diff --git a/gnu/usr.bin/binutils/gdb/Makefile b/gnu/usr.bin/binutils/gdb/Makefile new file mode 100644 index 00000000000..4ef28320d6f --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/Makefile @@ -0,0 +1,72 @@ +PROG = gdb +BINDIR= /usr/bin +SRCS = main.c blockframe.c breakpoint.c findvar.c stack.c thread.c \ + source.c values.c eval.c valops.c valarith.c valprint.c printcmd.c \ + symtab.c symfile.c symmisc.c infcmd.c infrun.c command.c utils.c \ + expprint.c environ.c gdbtypes.c copying.c i386-tdep.c i386-pinsn.c \ + freebsd-solib.c ser-unix.c exec.c fork-child.c infptrace.c inftarg.c \ + corelow.c coredep.c freebsd-nat.c remote.c dcache.c remote-utils.c \ + mem-break.c target.c putenv.c parse.c language.c buildsym.c \ + objfiles.c minsyms.c maint.c demangle.c dbxread.c coffread.c \ + elfread.c dwarfread.c mipsread.c stabsread.c core.c c-lang.c \ + ch-lang.c m2-lang.c complaints.c typeprint.c c-typeprint.c \ + ch-typeprint.c m2-typeprint.c c-valprint.c cp-valprint.c ch-valprint.c \ + m2-valprint.c nlmread.c serial.c inflow.c regex.c init.c \ + c-exp.tab.c ch-exp.tab.c m2-exp.tab.c version.c i386-dis.c dis-buf.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 y.tab.c + mv c-exp.new ./c-exp.tab.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 y.tab.c + mv 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 y.tab.c + mv m2-exp.new ./m2-exp.tab.c + + + +CFLAGS+= -I$(.CURDIR)/. -I/usr/include/readline -I$(.CURDIR)/../bfd +CFLAGS+= -DTRAD_CORE +LDADD+= -lreadline -ltermcap + +.if exists(${.CURDIR}/../libiberty/obj) +LDADD+= -L${.CURDIR}/../libiberty/obj -liberty +DPADD+= ${.CURDIR}/../libiberty/obj/libiberty.a +.else +LDADD+= -L${.CURDIR}/../libiberty/ -liberty +DPADD+= ${.CURDIR}/../libiberty/libiberty.a +.endif + +.if exists(${.CURDIR}/../bfd/obj) +LDADD+= -L${.CURDIR}/../bfd/obj -lbfd +DPADD+= ${.CURDIR}/../bfd/obj/libbfd.a +.else +LDADD+= -L${.CURDIR}/../bfd/ -lbfd +DPADD+= ${.CURDIR}/../bfd/libbfd.a +.endif + +.if exists(${.CURDIR}/../mmalloc/obj) +LDADD+= -L${.CURDIR}/../mmalloc/obj -lmmalloc +DPADD+= ${.CURDIR}/../mmalloc/obj/libmmalloc.a +.else +LDADD+= -L${.CURDIR}/../mmalloc/ -lmmalloc +DPADD+= ${.CURDIR}/../mmalloc/libmmalloc.a +.endif + + +.include diff --git a/gnu/usr.bin/binutils/gdb/gdb.1 b/gnu/usr.bin/binutils/gdb/gdb.1 new file mode 100644 index 00000000000..ccb216ee88f --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/gdb.1 @@ -0,0 +1,371 @@ +.\" Copyright (c) 1991 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.\" $Id: gdb.1,v 1.1.1.1 1993/10/30 21:59:13 jkh Exp $ +.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 "[\|" \-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 \-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 new file mode 100644 index 00000000000..deb68ebb945 --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c @@ -0,0 +1,323 @@ +/* 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. */ + +#include "defs.h" +#include + +/* this table must line up with REGISTER_NAMES in tm-i386.h */ +/* symbols like 'tEAX' come from */ +static int tregmap[] = +{ + tEAX, tECX, tEDX, tEBX, + tESP, tEBP, tESI, tEDI, + tEIP, tEFLAGS, tCS, tSS +}; +#ifdef sEAX +static int sregmap[] = +{ + sEAX, sECX, sEDX, sEBX, + sESP, sEBP, sESI, sEDI, + sEIP, sEFLAGS, sCS, sSS +}; +#endif +/* 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; +{ + /* The following condition is a kludge to get at the proper register map + depending upon the state of pcb_flag. + The proper condition would be + if (u.u_pcb.pcb_flag & FM_TRAP) + but that would require a ptrace call here and wouldn't work + for corefiles. */ + +#ifdef sEAX + if (blockend < 0x1fcc) + return (blockend + 4 * tregmap[regnum]); + else + return (blockend + 4 * sregmap[regnum]); +#else + return (blockend + 4 * tregmap[regnum]); +#endif +} + +#ifdef FLOAT_INFO +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ +#include +#undef curpcb +#include +#include +#include + +#define fpstate save87 +#define U_FPSTATE(u) u.u_pcb.pcb_savefpu + +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 */ +} + +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"); +} + +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]; +}; + +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); +} + +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 +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 ("last exception: "); + 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 `p->regs. + */ + st_regno = (fpreg + 8 - top) & 0x7; + + 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); + } +} + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in */ + 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 + { + printf("float info: can't do a core file (yet)\n"); + + return; +#if 0 + 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 + } + + print_387_status (0, (struct env387 *)buf); +} + +#endif diff --git a/gnu/usr.bin/binutils/gdb/i386/nm.h b/gnu/usr.bin/binutils/gdb/i386/nm.h new file mode 100644 index 00000000000..a7af00f33d8 --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/i386/nm.h @@ -0,0 +1,44 @@ +/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 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. */ + +#ifndef NM_FREEBSD_H +#define NM_FREEBSD_H + +/* Be shared lib aware */ +#include "solib.h" + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#include +#define KERNEL_U_ADDR USRSTACK + +/* #undef FLOAT_INFO /* No float info yet */ +#define FLOAT_INFO extern i386_float_info (); \ + i386_float_info () + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +#define PTRACE_ARG3_TYPE char* + +#endif /* NM_FREEBSD_H */ diff --git a/gnu/usr.bin/binutils/gdb/i386/tm.h b/gnu/usr.bin/binutils/gdb/i386/tm.h new file mode 100644 index 00000000000..25b66c709de --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/i386/tm.h @@ -0,0 +1,76 @@ +/* Macro definitions for i386 running under BSD Unix. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 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. */ + +/* Override number of expected traps from sysv. */ +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* Most definitions from sysv could be used. */ +#include "tm-i386v.h" + +/* 386BSD cannot handle the segment registers. */ +/* BSDI can't handle them either. */ +#undef NUM_REGS +#define NUM_REGS 10 + +/* 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 + +/* 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. */ + +/* 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 +#define FRAME_CHAIN(thisframe) \ + (thisframe->signal_handler_caller \ + ? thisframe->frame \ + : (!inside_entry_file ((thisframe)->pc) \ + ? 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 . */ +#define SIGCONTEXT_PC_OFFSET 20 + +#undef FRAME_SAVED_PC(FRAME) +#define FRAME_SAVED_PC(FRAME) \ + (((FRAME)->signal_handler_caller \ + ? sigtramp_saved_pc (FRAME) \ + : read_memory_integer ((FRAME)->frame + 4, 4)) \ + ) diff --git a/gnu/usr.bin/binutils/gdb/i386/version.c b/gnu/usr.bin/binutils/gdb/i386/version.c new file mode 100644 index 00000000000..d32e958a2dd --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/i386/version.c @@ -0,0 +1,3 @@ +char *version = "4.11"; +char *host_canonical = "i386-unknown-freebsd"; +char *target_canonical = "i386-unknown-freebsd"; diff --git a/gnu/usr.bin/binutils/gdb/i386/xm.h b/gnu/usr.bin/binutils/gdb/i386/xm.h new file mode 100644 index 00000000000..8d28df0b713 --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/i386/xm.h @@ -0,0 +1,31 @@ +/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 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. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#include /* for INT_MIN, to avoid "INT_MIN + redefined" warnings from defs.h */ + +/* psignal() is in . */ + +#define PSIGNAL_IN_SIGNAL_H + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE diff --git a/gnu/usr.bin/gdb/COPYING.LIB b/gnu/usr.bin/gdb/COPYING.LIB new file mode 100644 index 00000000000..eb685a5ec98 --- /dev/null +++ b/gnu/usr.bin/gdb/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/usr.bin/gdb/README.FreeBSD b/gnu/usr.bin/gdb/README.FreeBSD new file mode 100644 index 00000000000..75a30b2cb43 --- /dev/null +++ b/gnu/usr.bin/gdb/README.FreeBSD @@ -0,0 +1,15 @@ +This is a greatly pared down version of GDB-4.12 for FreeBSD 1.1.5 that +supports debugging of shared executables and the new a.out format. + +I've collapsed some of the directories and removed lots of files from others. +All that's included is those necessary to compile on FreeBSD 1.1.5, this was +to keep the replacement for GDB-3 compact since none of the multiple +architecture stuff is used. All the documentation has been put in the doc/ +directory. + +A full port of each library will probably be done for FreeBSD 2.0 and +included as system libraries so that other build tools can share them. +At that time a more complete port of GDB-4 will be done that allows +configuration for different systems and uses the full libraries. + +paul@freefall.cdrom.com diff --git a/gnu/usr.bin/gdb/VERSION b/gnu/usr.bin/gdb/VERSION new file mode 100644 index 00000000000..b849ff8ebf1 --- /dev/null +++ b/gnu/usr.bin/gdb/VERSION @@ -0,0 +1 @@ +4.11 diff --git a/gnu/usr.bin/gdb/bfd/COPYING b/gnu/usr.bin/gdb/bfd/COPYING new file mode 100644 index 00000000000..a43ea2126fb --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/gdb/bfd/Makefile b/gnu/usr.bin/gdb/bfd/Makefile new file mode 100644 index 00000000000..6e0e28dfa7f --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/Makefile @@ -0,0 +1,17 @@ +LIB = bfd +SRCS = archive.c archures.c bfd.c cache.c coffgen.c core.c ctor.c \ + format.c init.c libbfd.c opncls.c reloc.c seclet.c section.c syms.c \ + targets.c ecoff.c elf.c srec.c freebsd386.c aout32.c stab-syms.c \ + cpu-i386.c trad-core.c + +CFLAGS+= -I$(.CURDIR)/. -I$(.CURDIR)/../gdb/. +CFLAGS+= -DDEFAULT_VECTOR=freebsd386_vec -DSELECT_VECS='&freebsd386_vec' \ + -DSELECT_ARCHITECTURES='bfd_i386_arch' + +NOPROFILE=no +NOPIC=no + +install: + @echo -n + +.include diff --git a/gnu/usr.bin/gdb/bfd/README.FreeBSD b/gnu/usr.bin/gdb/bfd/README.FreeBSD new file mode 100644 index 00000000000..204119c1af7 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/README.FreeBSD @@ -0,0 +1,7 @@ +This is a greatly pared down libbfd directory. Only what's required to build +gdb-4.12 on FreeBSD was kept. + +This is temporary. In FreeBSD 2.0 a fully ported libbfd will likely appear +as a system library for use by all the build tools. + +paul@freefall.cdrom.com diff --git a/gnu/usr.bin/gdb/bfd/VERSION b/gnu/usr.bin/gdb/bfd/VERSION new file mode 100644 index 00000000000..8bbe6cf74a1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/VERSION @@ -0,0 +1 @@ +2.2 diff --git a/gnu/usr.bin/gdb/bfd/aout-target.h b/gnu/usr.bin/gdb/bfd/aout-target.h new file mode 100644 index 00000000000..65a22fff9b0 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/aout-target.h @@ -0,0 +1,429 @@ +/* Define a target vector and some small routines for a variant of a.out. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +/*#include "libaout.h"*/ + +extern CONST struct reloc_howto_struct * NAME(aout,reloc_type_lookup) (); + +/* Set parameters about this a.out file that are machine-dependent. + This routine is called from some_aout_object_p just before it returns. */ +#ifndef MY_callback +static bfd_target * +DEFUN(MY(callback),(abfd), + bfd *abfd) +{ + struct internal_exec *execp = exec_hdr (abfd); + + /* Calculate the file positions of the parts of a newly read aout header */ + obj_textsec (abfd)->_raw_size = N_TXTSIZE(*execp); + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR(*execp); + obj_datasec (abfd)->vma = N_DATADDR(*execp); + obj_bsssec (abfd)->vma = N_BSSADDR(*execp); + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF (*execp); + obj_datasec (abfd)->filepos = N_DATOFF (*execp); + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp); + + /* The file offsets of the string table and symbol table. */ + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + obj_str_filepos (abfd) = N_STROFF (*execp); + + /* Determine the architecture and machine type of the object file. */ +#ifdef SET_ARCH_MACH + SET_ARCH_MACH(abfd, *execp); +#else + bfd_default_set_arch_mach(abfd, DEFAULT_ARCH, 0); +#endif + + /* Don't set sizes now -- can't be sure until we know arch & mach. + Sizes get set in set_sizes callback, later. */ +#if 0 + adata(abfd).page_size = PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; +#endif + + return abfd->xvec; +} +#endif + +#ifndef MY_object_p +/* Finish up the reading of an a.out file header */ + +static bfd_target * +DEFUN(MY(object_p),(abfd), + bfd *abfd) +{ + struct external_exec exec_bytes; /* Raw exec header from file */ + struct internal_exec exec; /* Cleaned-up exec header */ + bfd_target *target; + + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + bfd_error = wrong_format; + return 0; + } + +#ifdef NO_SWAP_MAGIC + memcpy (&exec.a_info, exec_bytes.e_info, sizeof(exec.a_info)); +#else + exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info); +#endif /* NO_SWAP_MAGIC */ + + if (N_BADMAG (exec)) return 0; +#ifdef MACHTYPE_OK + if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0; +#endif + + NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec); + target = NAME(aout,some_aout_object_p) (abfd, &exec, MY(callback)); + +#ifdef ENTRY_CAN_BE_ZERO + /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage) + * means that it isn't obvious if EXEC_P should be set. + * All of the following must be true for an executable: + * There must be no relocations, the bfd can be neither an + * archive nor an archive element, and the file must be executable. */ + + if (exec.a_trsize + exec.a_drsize == 0 + && bfd_get_format(abfd) == bfd_object && abfd->my_archive == NULL) + { + struct stat buf; +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif + if (stat(abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR)) + abfd->flags |= EXEC_P; + } +#endif /* ENTRY_CAN_BE_ZERO */ + + return target; +} +#define MY_object_p MY(object_p) +#endif + + +#ifndef MY_mkobject +static boolean +DEFUN(MY(mkobject),(abfd), + bfd *abfd) +{ + if (NAME(aout,mkobject)(abfd) == false) + return false; +#if 0 /* Sizes get set in set_sizes callback, later, after we know + the architecture and machine. */ + adata(abfd).page_size = PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; +#endif + return true; +} +#define MY_mkobject MY(mkobject) +#endif + +/* Write an object file. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +#ifndef MY_write_object_contents +static boolean +DEFUN(MY(write_object_contents),(abfd), + bfd *abfd) +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE(abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + WRITE_HEADERS(abfd, execp); + + return true; +} +#define MY_write_object_contents MY(write_object_contents) +#endif + +#ifndef MY_set_sizes +static boolean +DEFUN(MY(set_sizes),(abfd), bfd *abfd) +{ + adata(abfd).page_size = PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; +} +#define MY_set_sizes MY(set_sizes) +#endif + +#ifndef MY_backend_data +static CONST struct aout_backend_data MY(backend_data) = { + 0, /* zmagic contiguous */ + 0, /* text incl header */ + 0, /* text vma? */ + MY_set_sizes, + 0, /* exec header is counted */ +}; +#define MY_backend_data &MY(backend_data) +#endif + +/* We assume BFD generic archive files. */ +#ifndef MY_openr_next_archived_file +#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file +#endif +#ifndef MY_generic_stat_arch_elt +#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt +#endif +#ifndef MY_slurp_armap +#define MY_slurp_armap bfd_slurp_bsd_armap +#endif +#ifndef MY_slurp_extended_name_table +#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table +#endif +#ifndef MY_write_armap +#define MY_write_armap bsd_write_armap +#endif +#ifndef MY_truncate_arname +#define MY_truncate_arname bfd_bsd_truncate_arname +#endif + +/* No core file defined here -- configure in trad-core.c separately. */ +#ifndef MY_core_file_failing_command +#define MY_core_file_failing_command _bfd_dummy_core_file_failing_command +#endif +#ifndef MY_core_file_failing_signal +#define MY_core_file_failing_signal _bfd_dummy_core_file_failing_signal +#endif +#ifndef MY_core_file_matches_executable_p +#define MY_core_file_matches_executable_p \ + _bfd_dummy_core_file_matches_executable_p +#endif +#ifndef MY_core_file_p +#define MY_core_file_p _bfd_dummy_target +#endif + +#ifndef MY_bfd_debug_info_start +#define MY_bfd_debug_info_start bfd_void +#endif +#ifndef MY_bfd_debug_info_end +#define MY_bfd_debug_info_end bfd_void +#endif +#ifndef MY_bfd_debug_info_accumulate +#define MY_bfd_debug_info_accumulate \ + (void (*) PARAMS ((bfd*, struct sec *))) bfd_void +#endif + +#ifndef MY_core_file_failing_command +#define MY_core_file_failing_command NAME(aout,core_file_failing_command) +#endif +#ifndef MY_core_file_failing_signal +#define MY_core_file_failing_signal NAME(aout,core_file_failing_signal) +#endif +#ifndef MY_core_file_matches_executable_p +#define MY_core_file_matches_executable_p NAME(aout,core_file_matches_executable_p) +#endif +#ifndef MY_slurp_armap +#define MY_slurp_armap NAME(aout,slurp_armap) +#endif +#ifndef MY_slurp_extended_name_table +#define MY_slurp_extended_name_table NAME(aout,slurp_extended_name_table) +#endif +#ifndef MY_truncate_arname +#define MY_truncate_arname NAME(aout,truncate_arname) +#endif +#ifndef MY_write_armap +#define MY_write_armap NAME(aout,write_armap) +#endif +#ifndef MY_close_and_cleanup +#define MY_close_and_cleanup NAME(aout,close_and_cleanup) +#endif +#ifndef MY_set_section_contents +#define MY_set_section_contents NAME(aout,set_section_contents) +#endif +#ifndef MY_get_section_contents +#define MY_get_section_contents NAME(aout,get_section_contents) +#endif +#ifndef MY_new_section_hook +#define MY_new_section_hook NAME(aout,new_section_hook) +#endif +#ifndef MY_get_symtab_upper_bound +#define MY_get_symtab_upper_bound NAME(aout,get_symtab_upper_bound) +#endif +#ifndef MY_get_symtab +#define MY_get_symtab NAME(aout,get_symtab) +#endif +#ifndef MY_get_reloc_upper_bound +#define MY_get_reloc_upper_bound NAME(aout,get_reloc_upper_bound) +#endif +#ifndef MY_canonicalize_reloc +#define MY_canonicalize_reloc NAME(aout,canonicalize_reloc) +#endif +#ifndef MY_make_empty_symbol +#define MY_make_empty_symbol NAME(aout,make_empty_symbol) +#endif +#ifndef MY_print_symbol +#define MY_print_symbol NAME(aout,print_symbol) +#endif +#ifndef MY_get_symbol_info +#define MY_get_symbol_info NAME(aout,get_symbol_info) +#endif +#ifndef MY_get_lineno +#define MY_get_lineno NAME(aout,get_lineno) +#endif +#ifndef MY_set_arch_mach +#define MY_set_arch_mach NAME(aout,set_arch_mach) +#endif +#ifndef MY_openr_next_archived_file +#define MY_openr_next_archived_file NAME(aout,openr_next_archived_file) +#endif +#ifndef MY_find_nearest_line +#define MY_find_nearest_line NAME(aout,find_nearest_line) +#endif +#ifndef MY_generic_stat_arch_elt +#define MY_generic_stat_arch_elt NAME(aout,generic_stat_arch_elt) +#endif +#ifndef MY_sizeof_headers +#define MY_sizeof_headers NAME(aout,sizeof_headers) +#endif +#ifndef MY_bfd_debug_info_start +#define MY_bfd_debug_info_start NAME(aout,bfd_debug_info_start) +#endif +#ifndef MY_bfd_debug_info_end +#define MY_bfd_debug_info_end NAME(aout,bfd_debug_info_end) +#endif +#ifndef MY_bfd_debug_info_accumulat +#define MY_bfd_debug_info_accumulat NAME(aout,bfd_debug_info_accumulat) +#endif +#ifndef MY_reloc_howto_type_lookup +#define MY_reloc_howto_type_lookup NAME(aout,reloc_type_lookup) +#endif +#ifndef MY_make_debug_symbol +#define MY_make_debug_symbol 0 +#endif + +/* Aout symbols normally have leading underscores */ +#ifndef MY_symbol_leading_char +#define MY_symbol_leading_char '_' +#endif + +/* Aout archives normally use spaces for padding */ +#ifndef AR_PAD_CHAR +#define AR_PAD_CHAR ' ' +#endif + +#ifndef MY_BFD_TARGET +bfd_target MY(vec) = +{ + TARGETNAME, /* name */ + bfd_target_aout_flavour, +#ifdef TARGET_IS_BIG_ENDIAN_P + true, /* target byte order (big) */ + true, /* target headers byte order (big) */ +#else + false, /* target byte order (little) */ + false, /* target headers byte order (little) */ +#endif + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + AR_PAD_CHAR, /* ar_pad_char */ + 15, /* ar_max_namelen */ + 3, /* minimum alignment */ +#ifdef TARGET_IS_BIG_ENDIAN_P + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ +#else + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ +#endif + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + MY_core_file_failing_command, + MY_core_file_failing_signal, + MY_core_file_matches_executable_p, + MY_slurp_armap, + MY_slurp_extended_name_table, + MY_truncate_arname, + MY_write_armap, + MY_close_and_cleanup, + MY_set_section_contents, + MY_get_section_contents, + MY_new_section_hook, + MY_get_symtab_upper_bound, + MY_get_symtab, + MY_get_reloc_upper_bound, + MY_canonicalize_reloc, + MY_make_empty_symbol, + MY_print_symbol, + MY_get_symbol_info, + MY_get_lineno, + MY_set_arch_mach, + MY_openr_next_archived_file, + MY_find_nearest_line, + MY_generic_stat_arch_elt, + MY_sizeof_headers, + MY_bfd_debug_info_start, + MY_bfd_debug_info_end, + MY_bfd_debug_info_accumulate, + bfd_generic_get_relocated_section_contents, + bfd_generic_relax_section, + bfd_generic_seclet_link, + MY_reloc_howto_type_lookup, + MY_make_debug_symbol, + (PTR) MY_backend_data, +}; +#endif /* MY_BFD_TARGET */ diff --git a/gnu/usr.bin/gdb/bfd/aout32.c b/gnu/usr.bin/gdb/bfd/aout32.c new file mode 100644 index 00000000000..84d20872fc9 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/aout32.c @@ -0,0 +1,23 @@ +/* BFD back-end for 32-bit a.out files. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#define ARCH_SIZE 32 + +#include "aoutx.h" diff --git a/gnu/usr.bin/gdb/bfd/aoutx.h b/gnu/usr.bin/gdb/bfd/aoutx.h new file mode 100644 index 00000000000..1ab442926ff --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/aoutx.h @@ -0,0 +1,2568 @@ +/* BFD semi-generic back-end for a.out binaries. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + a.out backends + + +DESCRIPTION + + BFD supports a number of different flavours of a.out format, + though the major differences are only the sizes of the + structures on disk, and the shape of the relocation + information. + + The support is split into a basic support file @code{aoutx.h} + and other files which derive functions from the base. One + derivation file is @code{aoutf1.h} (for a.out flavour 1), and + adds to the basic a.out functions support for sun3, sun4, 386 + and 29k a.out files, to create a target jump vector for a + specific target. + + This information is further split out into more specific files + for each machine, including @code{sunos.c} for sun3 and sun4, + @code{newsos3.c} for the Sony NEWS, and @code{demo64.c} for a + demonstration of a 64 bit a.out format. + + The base file @code{aoutx.h} defines general mechanisms for + reading and writing records to and from disk, and various + other methods which BFD requires. It is included by + @code{aout32.c} and @code{aout64.c} to form the names + aout_32_swap_exec_header_in, aout_64_swap_exec_header_in, etc. + + As an example, this is what goes on to make the back end for a + sun4, from aout32.c + +| #define ARCH_SIZE 32 +| #include "aoutx.h" + + Which exports names: + +| ... +| aout_32_canonicalize_reloc +| aout_32_find_nearest_line +| aout_32_get_lineno +| aout_32_get_reloc_upper_bound +| ... + + from sunos.c + +| #define ARCH 32 +| #define TARGET_NAME "a.out-sunos-big" +| #define VECNAME sunos_big_vec +| #include "aoutf1.h" + + requires all the names from aout32.c, and produces the jump vector + +| sunos_big_vec + + The file host-aout.c is a special case. It is for a large set + of hosts that use ``more or less standard'' a.out files, and + for which cross-debugging is not interesting. It uses the + standard 32-bit a.out support routines, but determines the + file offsets and addresses of the text, data, and BSS + sections, the machine architecture and machine type, and the + entry point address, in a host-dependent manner. Once these + values have been determined, generic code is used to handle + the object file. + + When porting it to run on a new system, you must supply: + +| HOST_PAGE_SIZE +| HOST_SEGMENT_SIZE +| HOST_MACHINE_ARCH (optional) +| HOST_MACHINE_MACHINE (optional) +| HOST_TEXT_START_ADDR +| HOST_STACK_END_ADDR + + in the file <<../include/sys/h-XXX.h>> (for your host). These + values, plus the structures and macros defined in <> on + your host system, will produce a BFD target that will access + ordinary a.out files on your host. To configure a new machine + to use <., specify: + +| TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec +| TDEPFILES= host-aout.o trad-core.o + + in the <> file, and modify configure.in to use the + <> file (by setting "<>") when your + configuration is selected. + +*/ + +/* Some assumptions: + * Any BFD with D_PAGED set is ZMAGIC, and vice versa. + Doesn't matter what the setting of WP_TEXT is on output, but it'll + get set on input. + * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC. + * Any BFD with both flags clear is OMAGIC. + (Just want to make these explicit, so the conditions tested in this + file make sense if you're more familiar with a.out than with BFD.) */ + +#define KEEPIT flags +#define KEEPITTYPE int + +#include +#include /* For strchr and friends */ +#include "bfd.h" +#include +#include + +struct external_exec; +#include "libaout.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" + +extern void (*bfd_error_trap)(); + +/* +SUBSECTION + relocations + +DESCRIPTION + The file @code{aoutx.h} caters for both the @emph{standard} + and @emph{extended} forms of a.out relocation records. + + The standard records are characterised by containing only an + address, a symbol index and a type field. The extended records + (used on 29ks and sparcs) also have a full integer for an + addend. + +*/ +#define CTOR_TABLE_RELOC_IDX 2 + +#define howto_table_ext NAME(aout,ext_howto_table) +#define howto_table_std NAME(aout,std_howto_table) + +reloc_howto_type howto_table_ext[] = +{ + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ + HOWTO(RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", false, 0,0x000000ff, false), + HOWTO(RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", false, 0,0x0000ffff, false), + HOWTO(RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", false, 0,0xffffffff, false), + HOWTO(RELOC_DISP8, 0, 0, 8, true, 0, complain_overflow_signed,0,"DISP8", false, 0,0x000000ff, false), + HOWTO(RELOC_DISP16, 0, 1, 16, true, 0, complain_overflow_signed,0,"DISP16", false, 0,0x0000ffff, false), + HOWTO(RELOC_DISP32, 0, 2, 32, true, 0, complain_overflow_signed,0,"DISP32", false, 0,0xffffffff, false), + HOWTO(RELOC_WDISP30,2, 2, 30, true, 0, complain_overflow_signed,0,"WDISP30", false, 0,0x3fffffff, false), + HOWTO(RELOC_WDISP22,2, 2, 22, true, 0, complain_overflow_signed,0,"WDISP22", false, 0,0x003fffff, false), + HOWTO(RELOC_HI22, 10, 2, 22, false, 0, complain_overflow_bitfield,0,"HI22", false, 0,0x003fffff, false), + HOWTO(RELOC_22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"22", false, 0,0x003fffff, false), + HOWTO(RELOC_13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"13", false, 0,0x00001fff, false), + HOWTO(RELOC_LO10, 0, 2, 10, false, 0, complain_overflow_dont,0,"LO10", false, 0,0x000003ff, false), + HOWTO(RELOC_SFA_BASE,0, 2, 32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false), + HOWTO(RELOC_SFA_OFF13,0,2, 32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false), + HOWTO(RELOC_BASE10, 0, 2, 16, false, 0, complain_overflow_bitfield,0,"BASE10", false, 0,0x0000ffff, false), + HOWTO(RELOC_BASE13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"BASE13", false, 0,0x00001fff, false), + HOWTO(RELOC_BASE22, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASE22", false, 0,0x00000000, false), + HOWTO(RELOC_PC10, 0, 2, 10, false, 0, complain_overflow_bitfield,0,"PC10", false, 0,0x000003ff, false), + HOWTO(RELOC_PC22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"PC22", false, 0,0x003fffff, false), + HOWTO(RELOC_JMP_TBL,0, 2, 32, false, 0, complain_overflow_bitfield,0,"JMP_TBL", false, 0,0xffffffff, false), + HOWTO(RELOC_SEGOFF16,0, 2, 0, false, 0, complain_overflow_bitfield,0,"SEGOFF16", false, 0,0x00000000, false), + HOWTO(RELOC_GLOB_DAT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"GLOB_DAT", false, 0,0x00000000, false), + HOWTO(RELOC_JMP_SLOT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_SLOT", false, 0,0x00000000, false), + HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false), +}; + +/* Convert standard reloc records to "arelent" format (incl byte swap). */ + +reloc_howto_type howto_table_std[] = { + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ +HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false), +HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false), +HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false), +HOWTO( 3, 0, 4, 64, false, 0, complain_overflow_bitfield,0,"64", true, 0xdeaddead,0xdeaddead, false), +HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, false), +HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, false), +HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, false), +HOWTO( 7, 0, 4, 64, true, 0, complain_overflow_signed, 0,"DISP64", true, 0xfeedface,0xfeedface, false), +{ -1 }, +HOWTO( 9, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"BASE16", false,0xffffffff,0xffffffff, false), +HOWTO(10, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"BASE32", false,0xffffffff,0xffffffff, false), +}; + +#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0])) + +CONST struct reloc_howto_struct * +DEFUN(NAME(aout,reloc_type_lookup),(abfd,code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ +#define EXT(i,j) case i: return &howto_table_ext[j] +#define STD(i,j) case i: return &howto_table_std[j] + int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE; + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + } + if (ext) + switch (code) + { + EXT (BFD_RELOC_32, 2); + EXT (BFD_RELOC_HI22, 8); + EXT (BFD_RELOC_LO10, 11); + EXT (BFD_RELOC_32_PCREL_S2, 6); + default: return (CONST struct reloc_howto_struct *) 0; + } + else + /* std relocs */ + switch (code) + { + STD (BFD_RELOC_16, 1); + STD (BFD_RELOC_32, 2); + STD (BFD_RELOC_8_PCREL, 4); + STD (BFD_RELOC_16_PCREL, 5); + STD (BFD_RELOC_32_PCREL, 6); + STD (BFD_RELOC_16_BASEREL, 9); + STD (BFD_RELOC_32_BASEREL, 10); + default: return (CONST struct reloc_howto_struct *) 0; + } +} + +extern bfd_error_vector_type bfd_error_vector; + +/* +SUBSECTION + Internal Entry Points + +DESCRIPTION + @code{aoutx.h} exports several routines for accessing the + contents of an a.out file, which are gathered and exported in + turn by various format specific files (eg sunos.c). + +*/ + +/* +FUNCTION + aout__swap_exec_header_in + +DESCRIPTION + Swaps the information in an executable header taken from a raw + byte stream memory image, into the internal exec_header + structure. + +SYNOPSIS + void aout__swap_exec_header_in, + (bfd *abfd, + struct external_exec *raw_bytes, + struct internal_exec *execp); +*/ + +#ifndef NAME_swap_exec_header_in +void +DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp), + bfd *abfd AND + struct external_exec *raw_bytes AND + struct internal_exec *execp) +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* The internal_exec structure has some fields that are unused in this + configuration (IE for i960), so ensure that all such uninitialized + fields are zero'd out. There are places where two of these structs + are memcmp'd, and thus the contents do matter. */ + memset (execp, 0, sizeof (struct internal_exec)); + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); +} +#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in) +#endif + +/* +FUNCTION + aout__swap_exec_header_out + +DESCRIPTION + Swaps the information in an internal exec header structure + into the supplied buffer ready for writing to disk. + +SYNOPSIS + void aout__swap_exec_header_out + (bfd *abfd, + struct internal_exec *execp, + struct external_exec *raw_bytes); +*/ +void +DEFUN(NAME(aout,swap_exec_header_out),(abfd, execp, raw_bytes), + bfd *abfd AND + struct internal_exec *execp AND + struct external_exec *raw_bytes) +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the raw data, from the fields in the exec struct. */ + bfd_h_put_32 (abfd, execp->a_info , bytes->e_info); + PUT_WORD (abfd, execp->a_text , bytes->e_text); + PUT_WORD (abfd, execp->a_data , bytes->e_data); + PUT_WORD (abfd, execp->a_bss , bytes->e_bss); + PUT_WORD (abfd, execp->a_syms , bytes->e_syms); + PUT_WORD (abfd, execp->a_entry , bytes->e_entry); + PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); + PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); +} + + + +/* +FUNCTION + aout__some_aout_object_p + +DESCRIPTION + Some A.OUT variant thinks that the file whose format we're + checking is an a.out file. Do some more checking, and set up + for access if it really is. Call back to the calling + environments "finish up" function just before returning, to + handle any last-minute setup. + +SYNOPSIS + bfd_target *aout__some_aout_object_p + (bfd *abfd, + bfd_target *(*callback_to_real_object_p)()); +*/ + +bfd_target * +DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p), + bfd *abfd AND + struct internal_exec *execp AND + bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *))) +{ + struct aout_data_struct *rawptr, *oldrawptr; + bfd_target *result; + + rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (struct aout_data_struct )); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + oldrawptr = abfd->tdata.aout_data; + abfd->tdata.aout_data = rawptr; + + /* Copy the contents of the old tdata struct. + In particular, we want the subformat, since for hpux it was set in + hp300hpux.c:swap_exec_header_in and will be used in + hp300hpux.c:callback. */ + if (oldrawptr != NULL) + *abfd->tdata.aout_data = *oldrawptr; + + abfd->tdata.aout_data->a.hdr = &rawptr->e; + *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec struct */ + execp = abfd->tdata.aout_data->a.hdr; + + /* Set the file flags */ + abfd->flags = NO_FLAGS; + if (execp->a_drsize || execp->a_trsize) + abfd->flags |= HAS_RELOC; + /* Setting of EXEC_P has been deferred to the bottom of this function */ + if (execp->a_syms) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + + if (N_MAGIC (*execp) == ZMAGIC) + { + abfd->flags |= D_PAGED|WP_TEXT; + adata(abfd).magic = z_magic; + } + else if (N_MAGIC (*execp) == NMAGIC) + { + abfd->flags |= WP_TEXT; + adata(abfd).magic = n_magic; + } + else + adata(abfd).magic = o_magic; + + bfd_get_start_address (abfd) = execp->a_entry; + + obj_aout_symbols (abfd) = (aout_symbol_type *)NULL; + bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist); + + /* The default relocation entry size is that of traditional V7 Unix. */ + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + + /* The default symbol entry size is that of traditional Unix. */ + obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE; + + /* Create the sections. This is raunchy, but bfd_close wants to reclaim + them. */ + + obj_textsec (abfd) = bfd_make_section_old_way (abfd, ".text"); + obj_datasec (abfd) = bfd_make_section_old_way (abfd, ".data"); + obj_bsssec (abfd) = bfd_make_section_old_way (abfd, ".bss"); + +#if 0 + (void)bfd_make_section (abfd, ".text"); + (void)bfd_make_section (abfd, ".data"); + (void)bfd_make_section (abfd, ".bss"); +#endif + + obj_datasec (abfd)->_raw_size = execp->a_data; + obj_bsssec (abfd)->_raw_size = execp->a_bss; + + obj_textsec (abfd)->flags = (execp->a_trsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC) : + (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)); + obj_datasec (abfd)->flags = (execp->a_drsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC) : + (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS)); + obj_bsssec (abfd)->flags = SEC_ALLOC; + +#ifdef THIS_IS_ONLY_DOCUMENTATION + /* The common code can't fill in these things because they depend + on either the start address of the text segment, the rounding + up of virtual addersses between segments, or the starting file + position of the text segment -- all of which varies among different + versions of a.out. */ + + /* Call back to the format-dependent code to fill in the rest of the + fields and do any further cleanup. Things that should be filled + in by the callback: */ + + struct exec *execp = exec_hdr (abfd); + + obj_textsec (abfd)->size = N_TXTSIZE(*execp); + obj_textsec (abfd)->raw_size = N_TXTSIZE(*execp); + /* data and bss are already filled in since they're so standard */ + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR(*execp); + obj_datasec (abfd)->vma = N_DATADDR(*execp); + obj_bsssec (abfd)->vma = N_BSSADDR(*execp); + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF(*execp); + obj_datasec (abfd)->filepos = N_DATOFF(*execp); + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp); + + /* The file offsets of the string table and symbol table. */ + obj_str_filepos (abfd) = N_STROFF (*execp); + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + + /* Determine the architecture and machine type of the object file. */ + switch (N_MACHTYPE (*exec_hdr (abfd))) { + default: + abfd->obj_arch = bfd_arch_obscure; + break; + } + + adata(abfd)->page_size = PAGE_SIZE; + adata(abfd)->segment_size = SEGMENT_SIZE; + adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE; + + return abfd->xvec; + + /* The architecture is encoded in various ways in various a.out variants, + or is not encoded at all in some of them. The relocation size depends + on the architecture and the a.out variant. Finally, the return value + is the bfd_target vector in use. If an error occurs, return zero and + set bfd_error to the appropriate error code. + + Formats such as b.out, which have additional fields in the a.out + header, should cope with them in this callback as well. */ +#endif /* DOCUMENTATION */ + + result = (*callback_to_real_object_p)(abfd); + + /* Now that the segment addresses have been worked out, take a better + guess at whether the file is executable. If the entry point + is within the text segment, assume it is. (This makes files + executable even if their entry point address is 0, as long as + their text starts at zero.) + + At some point we should probably break down and stat the file and + declare it executable if (one of) its 'x' bits are on... */ + if ((execp->a_entry >= obj_textsec(abfd)->vma) && + (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size)) + abfd->flags |= EXEC_P; + if (result) + { +#if 0 /* These should be set correctly anyways. */ + abfd->sections = obj_textsec (abfd); + obj_textsec (abfd)->next = obj_datasec (abfd); + obj_datasec (abfd)->next = obj_bsssec (abfd); +#endif + } + else + { + free (rawptr); + abfd->tdata.aout_data = oldrawptr; + } + return result; +} + +/* +FUNCTION + aout__mkobject + +DESCRIPTION + This routine initializes a BFD for use with a.out files. + +SYNOPSIS + boolean aout__mkobject, (bfd *); +*/ + +boolean +DEFUN(NAME(aout,mkobject),(abfd), + bfd *abfd) +{ + struct aout_data_struct *rawptr; + + bfd_error = system_call_error; + + /* Use an intermediate variable for clarity */ + rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct )); + + if (rawptr == NULL) { + bfd_error = no_memory; + return false; + } + + abfd->tdata.aout_data = rawptr; + exec_hdr (abfd) = &(rawptr->e); + + /* For simplicity's sake we just make all the sections right here. */ + + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + bfd_make_section (abfd, ".text"); + bfd_make_section (abfd, ".data"); + bfd_make_section (abfd, ".bss"); + bfd_make_section (abfd, BFD_ABS_SECTION_NAME); + bfd_make_section (abfd, BFD_UND_SECTION_NAME); + bfd_make_section (abfd, BFD_COM_SECTION_NAME); + + return true; +} + + +/* +FUNCTION + aout__machine_type + +DESCRIPTION + Keep track of machine architecture and machine type for + a.out's. Return the machine_type for a particular + arch&machine, or M_UNKNOWN if that exact arch&machine can't be + represented in a.out format. + + If the architecture is understood, machine type 0 (default) + should always be understood. + +SYNOPSIS + enum machine_type aout__machine_type + (enum bfd_architecture arch, + unsigned long machine)); +*/ + +enum machine_type +DEFUN(NAME(aout,machine_type),(arch, machine), + enum bfd_architecture arch AND + unsigned long machine) +{ + enum machine_type arch_flags; + + arch_flags = M_UNKNOWN; + + switch (arch) { + case bfd_arch_sparc: + if (machine == 0) arch_flags = M_SPARC; + break; + + case bfd_arch_m68k: + switch (machine) { + case 0: arch_flags = M_68010; break; + case 68000: arch_flags = M_UNKNOWN; break; + case 68010: arch_flags = M_68010; break; + case 68020: arch_flags = M_68020; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_i386: + if (machine == 0) arch_flags = M_386; + break; + + case bfd_arch_a29k: + if (machine == 0) arch_flags = M_29K; + break; + + case bfd_arch_mips: + switch (machine) { + case 0: + case 2000: + case 3000: arch_flags = M_MIPS1; break; + case 4000: + case 4400: + case 6000: arch_flags = M_MIPS2; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + default: + arch_flags = M_UNKNOWN; + } + return arch_flags; +} + + +/* +FUNCTION + aout__set_arch_mach + +DESCRIPTION + Sets the architecture and the machine of the BFD to those + values supplied. Verifies that the format can support the + architecture required. + +SYNOPSIS + boolean aout__set_arch_mach, + (bfd *, + enum bfd_architecture, + unsigned long machine)); +*/ + +boolean +DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine), + bfd *abfd AND + enum bfd_architecture arch AND + unsigned long machine) +{ + if (! bfd_default_set_arch_mach (abfd, arch, machine)) + return false; + + if (arch != bfd_arch_unknown && + NAME(aout,machine_type) (arch, machine) == M_UNKNOWN) + return false; /* We can't represent this type */ + + /* Determine the size of a relocation entry */ + switch (arch) { + case bfd_arch_sparc: + case bfd_arch_a29k: + case bfd_arch_mips: + obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; + break; + default: + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + break; + } + + return (*aout_backend_info(abfd)->set_sizes) (abfd); +} + +boolean +DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end), + bfd *abfd AND bfd_size_type *text_size AND file_ptr *text_end) +{ + struct internal_exec *execp = exec_hdr (abfd); + if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL)) + { + bfd_error = invalid_operation; + return false; + } + if (adata(abfd).magic != undecided_magic) return true; + obj_textsec(abfd)->_raw_size = + align_power(obj_textsec(abfd)->_raw_size, + obj_textsec(abfd)->alignment_power); + + *text_size = obj_textsec (abfd)->_raw_size; + /* Rule (heuristic) for when to pad to a new page. Note that there + * are (at least) two ways demand-paged (ZMAGIC) files have been + * handled. Most Berkeley-based systems start the text segment at + * (PAGE_SIZE). However, newer versions of SUNOS start the text + * segment right after the exec header; the latter is counted in the + * text segment size, and is paged in by the kernel with the rest of + * the text. */ + + /* This perhaps isn't the right way to do this, but made it simpler for me + to understand enough to implement it. Better would probably be to go + right from BFD flags to alignment/positioning characteristics. But the + old code was sloppy enough about handling the flags, and had enough + other magic, that it was a little hard for me to understand. I think + I understand it better now, but I haven't time to do the cleanup this + minute. */ + if (adata(abfd).magic == undecided_magic) + { + if (abfd->flags & D_PAGED) + /* Whether or not WP_TEXT is set -- let D_PAGED override. */ + /* @@ What about QMAGIC? */ + adata(abfd).magic = z_magic; + else if (abfd->flags & WP_TEXT) + adata(abfd).magic = n_magic; + else + adata(abfd).magic = o_magic; + } + +#ifdef BFD_AOUT_DEBUG /* requires gcc2 */ +#if __GNUC__ >= 2 + fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n", + ({ char *str; + switch (adata(abfd).magic) { + case n_magic: str = "NMAGIC"; break; + case o_magic: str = "OMAGIC"; break; + case z_magic: str = "ZMAGIC"; break; + default: abort (); + } + str; + }), + obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, obj_textsec(abfd)->alignment_power, + obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->alignment_power, + obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size, obj_bsssec(abfd)->alignment_power); +#endif +#endif + + switch (adata(abfd).magic) + { + case o_magic: + { + file_ptr pos = adata (abfd).exec_bytes_size; + bfd_vma vma = 0; + int pad = 0; + + obj_textsec(abfd)->filepos = pos; + pos += obj_textsec(abfd)->_raw_size; + vma += obj_textsec(abfd)->_raw_size; + if (!obj_datasec(abfd)->user_set_vma) + { +#if 0 /* ?? Does alignment in the file image really matter? */ + pad = align_power (vma, obj_datasec(abfd)->alignment_power) - vma; +#endif + obj_textsec(abfd)->_raw_size += pad; + pos += pad; + vma += pad; + obj_datasec(abfd)->vma = vma; + } + obj_datasec(abfd)->filepos = pos; + pos += obj_datasec(abfd)->_raw_size; + vma += obj_datasec(abfd)->_raw_size; + if (!obj_bsssec(abfd)->user_set_vma) + { +#if 0 + pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma; +#endif + obj_datasec(abfd)->_raw_size += pad; + pos += pad; + vma += pad; + obj_bsssec(abfd)->vma = vma; + } + obj_bsssec(abfd)->filepos = pos; + execp->a_text = obj_textsec(abfd)->_raw_size; + execp->a_data = obj_datasec(abfd)->_raw_size; + execp->a_bss = obj_bsssec(abfd)->_raw_size; + N_SET_MAGIC (*execp, OMAGIC); + } + break; + case z_magic: + { + bfd_size_type data_pad, text_pad; + file_ptr text_end; + CONST struct aout_backend_data *abdp; + int ztih; + bfd_vma data_vma; + + abdp = aout_backend_info (abfd); + ztih = abdp && abdp->text_includes_header; + obj_textsec(abfd)->filepos = (ztih + ? adata(abfd).exec_bytes_size + : adata(abfd).page_size); + if (! obj_textsec(abfd)->user_set_vma) + /* ?? Do we really need to check for relocs here? */ + obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC) + ? 0 + : (ztih + ? (abdp->default_text_vma + + adata(abfd).exec_bytes_size) + : abdp->default_text_vma)); + /* Could take strange alignment of text section into account here? */ + + /* Find start of data. */ + text_end = obj_textsec(abfd)->filepos + obj_textsec(abfd)->_raw_size; + text_pad = BFD_ALIGN (text_end, adata(abfd).page_size) - text_end; + obj_textsec(abfd)->_raw_size += text_pad; + text_end += text_pad; + + if (!obj_datasec(abfd)->user_set_vma) + { + bfd_vma vma; + vma = obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size; + obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size); + } + data_vma = obj_datasec(abfd)->vma; + if (abdp && abdp->zmagic_mapped_contiguous) + { + text_pad = (obj_datasec(abfd)->vma + - obj_textsec(abfd)->vma + - obj_textsec(abfd)->_raw_size); + obj_textsec(abfd)->_raw_size += text_pad; + } + obj_datasec(abfd)->filepos = (obj_textsec(abfd)->filepos + + obj_textsec(abfd)->_raw_size); + + /* Fix up exec header while we're at it. */ + execp->a_text = obj_textsec(abfd)->_raw_size; + if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted))) + execp->a_text += adata(abfd).exec_bytes_size; + N_SET_MAGIC (*execp, ZMAGIC); + /* Spec says data section should be rounded up to page boundary. */ + /* If extra space in page is left after data section, fudge data + in the header so that the bss section looks smaller by that + amount. We'll start the bss section there, and lie to the OS. */ + obj_datasec(abfd)->_raw_size + = align_power (obj_datasec(abfd)->_raw_size, + obj_bsssec(abfd)->alignment_power); + execp->a_data = BFD_ALIGN (obj_datasec(abfd)->_raw_size, + adata(abfd).page_size); + data_pad = execp->a_data - obj_datasec(abfd)->_raw_size; + + if (!obj_bsssec(abfd)->user_set_vma) + obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma + + obj_datasec(abfd)->_raw_size); + if (data_pad > obj_bsssec(abfd)->_raw_size) + execp->a_bss = 0; + else + execp->a_bss = obj_bsssec(abfd)->_raw_size - data_pad; + } + break; + case n_magic: + { + file_ptr pos = adata(abfd).exec_bytes_size; + bfd_vma vma = 0; + int pad; + + obj_textsec(abfd)->filepos = pos; + if (!obj_textsec(abfd)->user_set_vma) + obj_textsec(abfd)->vma = vma; + else + vma = obj_textsec(abfd)->vma; + pos += obj_textsec(abfd)->_raw_size; + vma += obj_textsec(abfd)->_raw_size; + obj_datasec(abfd)->filepos = pos; + if (!obj_datasec(abfd)->user_set_vma) + obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size); + vma = obj_datasec(abfd)->vma; + + /* Since BSS follows data immediately, see if it needs alignment. */ + vma += obj_datasec(abfd)->_raw_size; + pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma; + obj_datasec(abfd)->_raw_size += pad; + pos += obj_datasec(abfd)->_raw_size; + + if (!obj_bsssec(abfd)->user_set_vma) + obj_bsssec(abfd)->vma = vma; + else + vma = obj_bsssec(abfd)->vma; + } + execp->a_text = obj_textsec(abfd)->_raw_size; + execp->a_data = obj_datasec(abfd)->_raw_size; + execp->a_bss = obj_bsssec(abfd)->_raw_size; + N_SET_MAGIC (*execp, NMAGIC); + break; + default: + abort (); + } +#ifdef BFD_AOUT_DEBUG + fprintf (stderr, " text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n", + obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, obj_textsec(abfd)->filepos, + obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->filepos, + obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size); +#endif + return true; +} + +/* +FUNCTION + aout__new_section_hook + +DESCRIPTION + Called by the BFD in response to a @code{bfd_make_section} + request. + +SYNOPSIS + boolean aout__new_section_hook, + (bfd *abfd, + asection *newsect)); +*/ +boolean +DEFUN(NAME(aout,new_section_hook),(abfd, newsect), + bfd *abfd AND + asection *newsect) +{ + /* align to double at least */ + newsect->alignment_power = bfd_get_arch_info(abfd)->section_align_power; + + + if (bfd_get_format (abfd) == bfd_object) + { + if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) { + obj_textsec(abfd)= newsect; + newsect->target_index = N_TEXT | N_EXT; + return true; + } + + if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) { + obj_datasec(abfd) = newsect; + newsect->target_index = N_DATA | N_EXT; + return true; + } + + if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) { + obj_bsssec(abfd) = newsect; + newsect->target_index = N_BSS | N_EXT; + return true; + } + + } + + /* We allow more than three sections internally */ + return true; +} + +boolean +DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + file_ptr text_end; + bfd_size_type text_size; + + if (abfd->output_has_begun == false) + { + if (NAME(aout,adjust_sizes_and_vmas) (abfd, + &text_size, + &text_end) == false) + return false; + } + + /* regardless, once we know what we're doing, we might as well get going */ + if (section != obj_bsssec(abfd)) + { + bfd_seek (abfd, section->filepos + offset, SEEK_SET); + + if (count) { + return (bfd_write ((PTR)location, 1, count, abfd) == count) ? + true : false; + } + return true; + } + return true; +} + +/* Classify stabs symbols */ + +#define sym_in_text_section(sym) \ + (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT) + +#define sym_in_data_section(sym) \ + (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA) + +#define sym_in_bss_section(sym) \ + (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS) + +/* Symbol is undefined if type is N_UNDF|N_EXT and if it has + zero in the "value" field. Nonzeroes there are fortrancommon + symbols. */ +#define sym_is_undefined(sym) \ + ((sym)->type == (N_UNDF | N_EXT) && (sym)->symbol.value == 0) + +/* Symbol is a global definition if N_EXT is on and if it has + a nonzero type field. */ +#define sym_is_global_defn(sym) \ + (((sym)->type & N_EXT) && (sym)->type & N_TYPE) + +/* Symbol is debugger info if any bits outside N_TYPE or N_EXT + are on. */ +#define sym_is_debugger_info(sym) \ + (((sym)->type & ~(N_EXT | N_TYPE)) || (sym)->type == N_FN) + +#define sym_is_fortrancommon(sym) \ + (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0) + +/* Symbol is absolute if it has N_ABS set */ +#define sym_is_absolute(sym) \ + (((sym)->type & N_TYPE)== N_ABS) + + +#define sym_is_indirect(sym) \ + (((sym)->type & N_ABS)== N_ABS) + +/* Only in their own functions for ease of debugging; when sym flags have + stabilised these should be inlined into their (single) caller */ + +static void +DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd), + struct external_nlist *sym_pointer AND + aout_symbol_type * cache_ptr AND + bfd * abfd) +{ + cache_ptr->symbol.section = 0; + switch (cache_ptr->type & N_TYPE) + { + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1); + asection *section; + asection *into_section; + + arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + strcpy (copy, cache_ptr->symbol.name); + + /* Make sure that this bfd has a section with the right contructor + name */ + section = bfd_get_section_by_name (abfd, copy); + if (!section) + section = bfd_make_section (abfd, copy); + + /* Build a relocation entry for the constructor */ + switch ((cache_ptr->type & N_TYPE)) + { + case N_SETA: + into_section = &bfd_abs_section; + cache_ptr->type = N_ABS; + break; + case N_SETT: + into_section = (asection *) obj_textsec (abfd); + cache_ptr->type = N_TEXT; + break; + case N_SETD: + into_section = (asection *) obj_datasec (abfd); + cache_ptr->type = N_DATA; + break; + case N_SETB: + into_section = (asection *) obj_bsssec (abfd); + cache_ptr->type = N_BSS; + break; + default: + abort (); + } + + /* Build a relocation pointing into the constuctor section + pointing at the symbol in the set vector specified */ + + reloc->relent.addend = cache_ptr->symbol.value; + cache_ptr->symbol.section = into_section->symbol->section; + reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr; + + + /* We modify the symbol to belong to a section depending upon the + name of the symbol - probably __CTOR__ or __DTOR__ but we don't + really care, and add to the size of the section to contain a + pointer to the symbol. Build a reloc entry to relocate to this + symbol attached to this section. */ + + section->flags = SEC_CONSTRUCTOR; + + + section->reloc_count++; + section->alignment_power = 2; + + reloc->next = section->constructor_chain; + section->constructor_chain = reloc; + reloc->relent.address = section->_raw_size; + section->_raw_size += sizeof (int *); + + reloc->relent.howto + = (obj_reloc_entry_size(abfd) == RELOC_EXT_SIZE + ? howto_table_ext : howto_table_std) + + CTOR_TABLE_RELOC_IDX; + cache_ptr->symbol.flags |= BSF_CONSTRUCTOR; + } + break; + default: + if (cache_ptr->type == N_WARNING) + { + /* This symbol is the text of a warning message, the next symbol + is the symbol to associate the warning with */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING; + + /* @@ Stuffing pointers into integers is a no-no. + We can usually get away with it if the integer is + large enough though. */ + if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) + abort (); + cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1)); + + /* We furgle with the next symbol in place. + We don't want it to be undefined, we'll trample the type */ + (sym_pointer + 1)->e_type[0] = 0xff; + break; + } + if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT)) + { + /* Two symbols in a row for an INDR message. The first symbol + contains the name we will match, the second symbol contains + the name the first name is translated into. It is supplied to + us undefined. This is good, since we want to pull in any files + which define it */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT; + + /* @@ Stuffing pointers into integers is a no-no. + We can usually get away with it if the integer is + large enough though. */ + if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) + abort (); + + cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1)); + cache_ptr->symbol.section = &bfd_ind_section; + } + + else if (sym_is_debugger_info (cache_ptr)) + { + cache_ptr->symbol.flags = BSF_DEBUGGING; + /* Work out the section correct for this symbol */ + switch (cache_ptr->type & N_TYPE) + { + case N_TEXT: + case N_FN: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= obj_textsec (abfd)->vma; + break; + case N_DATA: + cache_ptr->symbol.value -= obj_datasec (abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + break; + case N_BSS: + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec (abfd)->vma; + break; + default: + case N_ABS: + + cache_ptr->symbol.section = &bfd_abs_section; + break; + } + } + else + { + + if (sym_is_fortrancommon (cache_ptr)) + { + cache_ptr->symbol.flags = 0; + cache_ptr->symbol.section = &bfd_com_section; + } + else + { + + + } + + /* In a.out, the value of a symbol is always relative to the + * start of the file, if this is a data symbol we'll subtract + * the size of the text section to get the section relative + * value. If this is a bss symbol (which would be strange) + * we'll subtract the size of the previous two sections + * to find the section relative address. + */ + + if (sym_in_text_section (cache_ptr)) + { + cache_ptr->symbol.value -= obj_textsec (abfd)->vma; + cache_ptr->symbol.section = obj_textsec (abfd); + } + else if (sym_in_data_section (cache_ptr)) + { + cache_ptr->symbol.value -= obj_datasec (abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + } + else if (sym_in_bss_section (cache_ptr)) + { + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec (abfd)->vma; + } + else if (sym_is_undefined (cache_ptr)) + { + cache_ptr->symbol.flags = 0; + cache_ptr->symbol.section = &bfd_und_section; + } + else if (sym_is_absolute (cache_ptr)) + { + cache_ptr->symbol.section = &bfd_abs_section; + } + + if (sym_is_global_defn (cache_ptr)) + { + cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT; + } + else + { + cache_ptr->symbol.flags = BSF_LOCAL; + } + } + } + if (cache_ptr->symbol.section == 0) + abort (); +} + + + +static void +DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd), + struct external_nlist *sym_pointer AND + asymbol *cache_ptr AND + bfd *abfd) +{ + bfd_vma value = cache_ptr->value; + + /* mask out any existing type bits in case copying from one section + to another */ + sym_pointer->e_type[0] &= ~N_TYPE; + + + /* We attempt to order these tests by decreasing frequency of success, + according to tcov when linking the linker. */ + if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) { + sym_pointer->e_type[0] |= N_ABS; + } + else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) { + sym_pointer->e_type[0] |= N_TEXT; + } + else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) { + sym_pointer->e_type[0] |= N_DATA; + } + else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) { + sym_pointer->e_type[0] |= N_BSS; + } + else if (bfd_get_output_section(cache_ptr) == &bfd_und_section) + { + sym_pointer->e_type[0] = (N_UNDF | N_EXT); + } + else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section) + { + sym_pointer->e_type[0] = N_INDR; + } + else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) { + sym_pointer->e_type[0] = (N_UNDF | N_EXT); + } + else { + if (cache_ptr->section->output_section) + { + + bfd_error_vector.nonrepresentable_section(abfd, + bfd_get_output_section(cache_ptr)->name); + } + else + { + bfd_error_vector.nonrepresentable_section(abfd, + cache_ptr->section->name); + + } + + } + /* Turn the symbol from section relative to absolute again */ + + value += cache_ptr->section->output_section->vma + cache_ptr->section->output_offset ; + + + if (cache_ptr->flags & (BSF_WARNING)) { + (sym_pointer+1)->e_type[0] = 1; + } + + if (cache_ptr->flags & BSF_DEBUGGING) { + sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type; + } + else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) { + sym_pointer->e_type[0] |= N_EXT; + } + if (cache_ptr->flags & BSF_CONSTRUCTOR) { + int type = ((aout_symbol_type *)cache_ptr)->type; + switch (type) + { + case N_ABS: type = N_SETA; break; + case N_TEXT: type = N_SETT; break; + case N_DATA: type = N_SETD; break; + case N_BSS: type = N_SETB; break; + } + sym_pointer->e_type[0] = type; + } + + PUT_WORD(abfd, value, sym_pointer->e_value); +} + +/* Native-level interface to symbols. */ + +/* We read the symbols into a buffer, which is discarded when this +function exits. We read the strings into a buffer large enough to +hold them all plus all the cached symbol entries. */ + +asymbol * +DEFUN(NAME(aout,make_empty_symbol),(abfd), + bfd *abfd) +{ + aout_symbol_type *new = + (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type)); + new->symbol.the_bfd = abfd; + + return &new->symbol; +} + +boolean +DEFUN(NAME(aout,slurp_symbol_table),(abfd), + bfd *abfd) +{ + bfd_size_type symbol_size; + bfd_size_type string_size; + unsigned char string_chars[BYTES_IN_WORD]; + struct external_nlist *syms; + char *strings; + aout_symbol_type *cached; + + /* If there's no work to be done, don't do any */ + if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true; + symbol_size = exec_hdr(abfd)->a_syms; + if (symbol_size == 0) + { + bfd_error = no_symbols; + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((PTR)string_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD) + return false; + string_size = GET_WORD (abfd, string_chars); + + strings =(char *) bfd_alloc(abfd, string_size + 1); + cached = (aout_symbol_type *) + bfd_zalloc(abfd, (bfd_size_type)(bfd_get_symcount (abfd) * sizeof(aout_symbol_type))); + + /* malloc this, so we can free it if simply. The symbol caching + might want to allocate onto the bfd's obstack */ + syms = (struct external_nlist *) bfd_xmalloc(symbol_size); + bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET); + if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size) + { + bailout: + if (syms) + free (syms); + if (cached) + bfd_release (abfd, cached); + if (strings) + bfd_release (abfd, strings); + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size) + { + goto bailout; + } + strings[string_size] = 0; /* Just in case. */ + + /* OK, now walk the new symtable, cacheing symbol properties */ + { + register struct external_nlist *sym_pointer; + register struct external_nlist *sym_end = syms + bfd_get_symcount (abfd); + register aout_symbol_type *cache_ptr = cached; + + /* Run through table and copy values */ + for (sym_pointer = syms, cache_ptr = cached; + sym_pointer < sym_end; sym_pointer ++, cache_ptr++) + { + long x = GET_WORD(abfd, sym_pointer->e_strx); + cache_ptr->symbol.the_bfd = abfd; + if (x == 0) + cache_ptr->symbol.name = ""; + else if (x >= 0 && x < string_size) + cache_ptr->symbol.name = x + strings; + else + goto bailout; + + cache_ptr->symbol.value = GET_SWORD(abfd, sym_pointer->e_value); + cache_ptr->desc = bfd_h_get_16(abfd, sym_pointer->e_desc); + cache_ptr->other = bfd_h_get_8(abfd, sym_pointer->e_other); + cache_ptr->type = bfd_h_get_8(abfd, sym_pointer->e_type); + cache_ptr->symbol.udata = 0; + translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd); + } + } + + obj_aout_symbols (abfd) = cached; + free((PTR)syms); + + return true; +} + + +/* Possible improvements: + + look for strings matching trailing substrings of other strings + + better data structures? balanced trees? + + smaller per-string or per-symbol data? re-use some of the symbol's + data fields? + + also look at reducing memory use elsewhere -- maybe if we didn't have to + construct the entire symbol table at once, we could get by with smaller + amounts of VM? (What effect does that have on the string table + reductions?) + + rip this out of here, put it into its own file in bfd or libiberty, so + coff and elf can use it too. I'll work on this soon, but have more + pressing tasks right now. + + A hash table might(?) be more efficient for handling exactly the cases that + are handled now, but for trailing substring matches, I think we want to + examine the `nearest' values (reverse-)lexically, not merely impose a strict + order, nor look only for exact-match or not-match. I don't think a hash + table would be very useful for that, and I don't feel like fleshing out two + completely different implementations. [raeburn:930419.0331EDT] */ + +struct stringtab_entry { + /* Hash value for this string. Only useful so long as we aren't doing + substring matches. */ + unsigned int hash; + + /* Next node to look at, depending on whether the hash value of the string + being searched for is less than or greater than the hash value of the + current node. For now, `equal to' is lumped in with `greater than', for + space efficiency. It's not a common enough case to warrant another field + to be used for all nodes. */ + struct stringtab_entry *less; + struct stringtab_entry *greater; + + /* The string itself. */ + CONST char *string; + + /* The index allocated for this string. */ + bfd_size_type index; + +#ifdef GATHER_STATISTICS + /* How many references have there been to this string? (Not currently used; + could be dumped out for anaylsis, if anyone's interested.) */ + unsigned long count; +#endif + + /* Next node in linked list, in suggested output order. */ + struct stringtab_entry *next_to_output; +}; + +struct stringtab_data { + /* Tree of string table entries. */ + struct stringtab_entry *strings; + + /* Fudge factor used to center top node of tree. */ + int hash_zero; + + /* Next index value to issue. */ + bfd_size_type index; + + /* Index used for empty strings. Cached here because checking for them + is really easy, and we can avoid searching the tree. */ + bfd_size_type empty_string_index; + + /* These fields indicate the two ends of a singly-linked list that indicates + the order strings should be written out in. Use this order, and no + seeking will need to be done, so output efficiency should be maximized. */ + struct stringtab_entry **end; + struct stringtab_entry *output_order; + +#ifdef GATHER_STATISTICS + /* Number of strings which duplicate strings already in the table. */ + unsigned long duplicates; + + /* Number of bytes saved by not having to write all the duplicate strings. */ + unsigned long bytes_saved; + + /* Number of zero-length strings. Currently, these all turn into + references to the null byte at the end of the first string. In some + cases (possibly not all? explore this...), it should be possible to + simply write out a zero index value. */ + unsigned long empty_strings; + + /* Number of times the hash values matched but the strings were different. + Note that this includes the number of times the other string(s) occurs, so + there may only be two strings hashing to the same value, even if this + number is very large. */ + unsigned long bad_hash_matches; + + /* Null strings aren't counted in this one. + This will probably only be nonzero if we've got an input file + which was produced by `ld -r' (i.e., it's already been processed + through this code). Under some operating systems, native tools + may make all empty strings have the same index; but the pointer + check won't catch those, because to get to that stage we'd already + have to compute the checksum, which requires reading the string, + so we short-circuit that case with empty_string_index above. */ + unsigned long pointer_matches; + + /* Number of comparisons done. I figure with the algorithms in use below, + the average number of comparisons done (per symbol) should be roughly + log-base-2 of the number of unique strings. */ + unsigned long n_compares; +#endif +}; + +/* Some utility functions for the string table code. */ + +/* For speed, only hash on the first this many bytes of strings. + This number was chosen by profiling ld linking itself, with -g. */ +#define HASHMAXLEN 25 + +#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c)) + +static INLINE unsigned int +hash (string, len) + unsigned char *string; + register unsigned int len; +{ + register unsigned int sum = 0; + + if (len > HASHMAXLEN) + { + HASH_CHAR (len); + len = HASHMAXLEN; + } + + while (len--) + { + HASH_CHAR (*string++); + } + return sum; +} + +static INLINE void +stringtab_init (tab) + struct stringtab_data *tab; +{ + tab->strings = 0; + tab->output_order = 0; + tab->end = &tab->output_order; + + /* Initial string table length includes size of length field. */ + tab->index = BYTES_IN_WORD; + tab->empty_string_index = -1; +#ifdef GATHER_STATISTICS + tab->duplicates = 0; + tab->empty_strings = 0; + tab->bad_hash_matches = 0; + tab->pointer_matches = 0; + tab->bytes_saved = 0; + tab->n_compares = 0; +#endif +} + +static INLINE int +compare (entry, str, hash) + struct stringtab_entry *entry; + CONST char *str; + unsigned int hash; +{ + return hash - entry->hash; +} + +#ifdef GATHER_STATISTICS +/* Don't want to have to link in math library with all bfd applications... */ +static INLINE double +log2 (num) + int num; +{ + double d = num; + int n = 0; + while (d >= 2.0) + n++, d /= 2.0; + return ((d > 1.41) ? 0.5 : 0) + n; +} +#endif + +/* Main string table routines. */ +/* Returns index in string table. Whether or not this actually adds an + entry into the string table should be irrelevant -- it just has to + return a valid index. */ +static bfd_size_type +add_to_stringtab (abfd, str, tab, check) + bfd *abfd; + CONST char *str; + struct stringtab_data *tab; + int check; +{ + struct stringtab_entry **ep; + register struct stringtab_entry *entry; + unsigned int hashval, len; + + if (str[0] == 0) + { + bfd_size_type index; + CONST bfd_size_type minus_one = -1; + +#ifdef GATHER_STATISTICS + tab->empty_strings++; +#endif + index = tab->empty_string_index; + if (index != minus_one) + { + got_empty: +#ifdef GATHER_STATISTICS + tab->bytes_saved++; + tab->duplicates++; +#endif + return index; + } + + /* Need to find it. */ + entry = tab->strings; + if (entry) + { + index = entry->index + strlen (entry->string); + tab->empty_string_index = index; + goto got_empty; + } + len = 0; + } + else + len = strlen (str); + + /* The hash_zero value is chosen such that the first symbol gets a value of + zero. With a balanced tree, this wouldn't be very useful, but without it, + we might get a more even split at the top level, instead of skewing it + badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */ + hashval = hash (str, len) ^ tab->hash_zero; + ep = &tab->strings; + if (!*ep) + { + tab->hash_zero = hashval; + hashval = 0; + goto add_it; + } + + while (*ep) + { + register int cmp; + + entry = *ep; +#ifdef GATHER_STATISTICS + tab->n_compares++; +#endif + cmp = compare (entry, str, hashval); + /* The not-equal cases are more frequent, so check them first. */ + if (cmp > 0) + ep = &entry->greater; + else if (cmp < 0) + ep = &entry->less; + else + { + if (entry->string == str) + { +#ifdef GATHER_STATISTICS + tab->pointer_matches++; +#endif + goto match; + } + /* Compare the first bytes to save a function call if they + don't match. */ + if (entry->string[0] == str[0] && !strcmp (entry->string, str)) + { + match: +#ifdef GATHER_STATISTICS + entry->count++; + tab->bytes_saved += len + 1; + tab->duplicates++; +#endif + /* If we're in the linker, and the new string is from a new + input file which might have already had these reductions + run over it, we want to keep the new string pointer. I + don't think we're likely to see any (or nearly as many, + at least) cases where a later string is in the same location + as an earlier one rather than this one. */ + entry->string = str; + return entry->index; + } +#ifdef GATHER_STATISTICS + tab->bad_hash_matches++; +#endif + ep = &entry->greater; + } + } + + /* If we get here, nothing that's in the table already matched. + EP points to the `next' field at the end of the chain; stick a + new entry on here. */ + add_it: + entry = (struct stringtab_entry *) + bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry)); + + entry->less = entry->greater = 0; + entry->hash = hashval; + entry->index = tab->index; + entry->string = str; + entry->next_to_output = 0; +#ifdef GATHER_STATISTICS + entry->count = 1; +#endif + + assert (*tab->end == 0); + *(tab->end) = entry; + tab->end = &entry->next_to_output; + assert (*tab->end == 0); + + { + tab->index += len + 1; + if (len == 0) + tab->empty_string_index = entry->index; + } + assert (*ep == 0); + *ep = entry; + return entry->index; +} + +static void +emit_strtab (abfd, tab) + bfd *abfd; + struct stringtab_data *tab; +{ + struct stringtab_entry *entry; +#ifdef GATHER_STATISTICS + int count = 0; +#endif + + /* Be sure to put string length into correct byte ordering before writing + it out. */ + char buffer[BYTES_IN_WORD]; + + PUT_WORD (abfd, tab->index, (unsigned char *) buffer); + bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd); + + for (entry = tab->output_order; entry; entry = entry->next_to_output) + { + bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd); +#ifdef GATHER_STATISTICS + count++; +#endif + } + +#ifdef GATHER_STATISTICS + /* Short form only, for now. + To do: Specify output file. Conditionalize on environment? Detailed + analysis if desired. */ + { + int n_syms = bfd_get_symcount (abfd); + + fprintf (stderr, "String table data for output file:\n"); + fprintf (stderr, " %8d symbols output\n", n_syms); + fprintf (stderr, " %8d duplicate strings\n", tab->duplicates); + fprintf (stderr, " %8d empty strings\n", tab->empty_strings); + fprintf (stderr, " %8d unique strings output\n", count); + fprintf (stderr, " %8d pointer matches\n", tab->pointer_matches); + fprintf (stderr, " %8d bytes saved\n", tab->bytes_saved); + fprintf (stderr, " %8d bad hash matches\n", tab->bad_hash_matches); + fprintf (stderr, " %8d hash-val comparisons\n", tab->n_compares); + if (n_syms) + { + double n_compares = tab->n_compares; + double avg_compares = n_compares / n_syms; + /* The second value here should usually be near one. */ + fprintf (stderr, + "\t average %f comparisons per symbol (%f * log2 nstrings)\n", + avg_compares, avg_compares / log2 (count)); + } + } +#endif + +/* Old code: + unsigned int count; + generic = bfd_get_outsymbols(abfd); + for (count = 0; count < bfd_get_symcount(abfd); count++) + { + asymbol *g = *(generic++); + + if (g->name) + { + size_t length = strlen(g->name)+1; + bfd_write((PTR)g->name, 1, length, abfd); + } + g->KEEPIT = (KEEPITTYPE) count; + } */ +} + +void +DEFUN(NAME(aout,write_syms),(abfd), + bfd *abfd) +{ + unsigned int count ; + asymbol **generic = bfd_get_outsymbols (abfd); + struct stringtab_data strtab; + + stringtab_init (&strtab); + + for (count = 0; count < bfd_get_symcount (abfd); count++) + { + asymbol *g = generic[count]; + struct external_nlist nsp; + + if (g->name) + PUT_WORD (abfd, add_to_stringtab (abfd, g->name, &strtab), + (unsigned char *) nsp.e_strx); + else + PUT_WORD (abfd, 0, (unsigned char *)nsp.e_strx); + + if (bfd_asymbol_flavour(g) == abfd->xvec->flavour) + { + bfd_h_put_16(abfd, aout_symbol(g)->desc, nsp.e_desc); + bfd_h_put_8(abfd, aout_symbol(g)->other, nsp.e_other); + bfd_h_put_8(abfd, aout_symbol(g)->type, nsp.e_type); + } + else + { + bfd_h_put_16(abfd,0, nsp.e_desc); + bfd_h_put_8(abfd, 0, nsp.e_other); + bfd_h_put_8(abfd, 0, nsp.e_type); + } + + translate_to_native_sym_flags (&nsp, g, abfd); + + bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd); + + /* NB: `KEEPIT' currently overlays `flags', so set this only + here, at the end. */ + g->KEEPIT = count; + } + + emit_strtab (abfd, &strtab); +} + + +unsigned int +DEFUN(NAME(aout,get_symtab),(abfd, location), + bfd *abfd AND + asymbol **location) +{ + unsigned int counter = 0; + aout_symbol_type *symbase; + + if (!NAME(aout,slurp_symbol_table)(abfd)) return 0; + + for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);) + *(location++) = (asymbol *)( symbase++); + *location++ =0; + return bfd_get_symcount (abfd); +} + + +/* Standard reloc stuff */ +/* Output standard relocation information to a file in target byte order. */ + +void +DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr), + bfd *abfd AND + arelent *g AND + struct reloc_std_external *natptr) +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + unsigned int r_addend; + asection *output_section = sym->section->output_section; + + PUT_WORD(abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two */ + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ + /* XXX This relies on relocs coming from a.out files. */ + r_baserel = (g->howto->type & 8) != 0; + /* r_jmptable, r_relative??? FIXME-soon */ + r_jmptable = 0; + r_relative = 0; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; + r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT); + + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_BIG: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_BIG: 0) + | (r_baserel? RELOC_STD_BITS_BASEREL_BIG: 0) + | (r_jmptable? RELOC_STD_BITS_JMPTABLE_BIG: 0) + | (r_relative? RELOC_STD_BITS_RELATIVE_BIG: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG); + } else { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0) + | (r_baserel? RELOC_STD_BITS_BASEREL_LITTLE: 0) + | (r_jmptable? RELOC_STD_BITS_JMPTABLE_LITTLE: 0) + | (r_relative? RELOC_STD_BITS_RELATIVE_LITTLE: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE); + } +} + + +/* Extended stuff */ +/* Output extended relocation information to a file in target byte order. */ + +void +DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr), + bfd *abfd AND + arelent *g AND + register struct reloc_ext_external *natptr) +{ + int r_index; + int r_extern; + unsigned int r_type; + unsigned int r_addend; + asymbol *sym = *(g->sym_ptr_ptr); + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_type = (unsigned int) g->howto->type; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here. */ + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + r_extern = 1; + r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT); + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + ((r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG)); + } else { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + PUT_WORD (abfd, r_addend, natptr->r_addend); +} + +/* BFD deals internally with all things based from the section they're + in. so, something in 10 bytes into a text section with a base of + 50 would have a symbol (.text+10) and know .text vma was 50. + + Aout keeps all it's symbols based from zero, so the symbol would + contain 60. This macro subs the base of each section from the value + to give the true offset from the section */ + + +#define MOVE_ADDRESS(ad) \ + if (r_extern) { \ + /* undefined symbol */ \ + cache_ptr->sym_ptr_ptr = symbols + r_index; \ + cache_ptr->addend = ad; \ + } else { \ + /* defined, section relative. replace symbol with pointer to \ + symbol which points to section */ \ + switch (r_index) { \ + case N_TEXT: \ + case N_TEXT | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->textsec->vma; \ + break; \ + case N_DATA: \ + case N_DATA | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->datasec->vma; \ + break; \ + case N_BSS: \ + case N_BSS | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->bsssec->vma; \ + break; \ + default: \ + case N_ABS: \ + case N_ABS | N_EXT: \ + cache_ptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; \ + cache_ptr->addend = ad; \ + break; \ + } \ + } \ + +void +DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols), + bfd *abfd AND + struct reloc_ext_external *bytes AND + arelent *cache_ptr AND + asymbol **symbols) +{ + int r_index; + int r_extern; + unsigned int r_type; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + r_index = (bytes->r_index[0] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[2]; + r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG)); + r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG; + } else { + r_index = (bytes->r_index[2] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[0]; + r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); + r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) + >> RELOC_EXT_BITS_TYPE_SH_LITTLE; + } + + cache_ptr->howto = howto_table_ext + r_type; + MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend)); +} + +void +DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols), + bfd *abfd AND + struct reloc_std_external *bytes AND + arelent *cache_ptr AND + asymbol **symbols) +{ + int r_index; + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + int howto_idx; + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + r_index = (bytes->r_index[0] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[2]; + r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); + r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); + r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); + r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); + r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG)); + r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) + >> RELOC_STD_BITS_LENGTH_SH_BIG; + } else { + r_index = (bytes->r_index[2] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[0]; + r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); + r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); + r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE)); + r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE)); + r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE)); + r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) + >> RELOC_STD_BITS_LENGTH_SH_LITTLE; + } + + howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel; + BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std)); + cache_ptr->howto = howto_table_std + howto_idx; + BFD_ASSERT (cache_ptr->howto->type != -1); + BFD_ASSERT (r_jmptable == 0); + BFD_ASSERT (r_relative == 0); + /* FIXME-soon: Roll jmptable, relative bits into howto setting */ + + MOVE_ADDRESS(0); +} + +/* Reloc hackery */ + +boolean +DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols), + bfd *abfd AND + sec_ptr asect AND + asymbol **symbols) +{ + unsigned int count; + bfd_size_type reloc_size; + PTR relocs; + arelent *reloc_cache; + size_t each_size; + + if (asect->relocation) return true; + + if (asect->flags & SEC_CONSTRUCTOR) return true; + + if (asect == obj_datasec (abfd)) { + reloc_size = exec_hdr(abfd)->a_drsize; + goto doit; + } + + if (asect == obj_textsec (abfd)) { + reloc_size = exec_hdr(abfd)->a_trsize; + goto doit; + } + + bfd_error = invalid_operation; + return false; + + doit: + bfd_seek (abfd, asect->rel_filepos, SEEK_SET); + each_size = obj_reloc_entry_size (abfd); + + count = reloc_size / each_size; + + + reloc_cache = (arelent *) bfd_zalloc (abfd, (size_t)(count * sizeof + (arelent))); + if (!reloc_cache) { +nomem: + bfd_error = no_memory; + return false; + } + + relocs = (PTR) bfd_alloc (abfd, reloc_size); + if (!relocs) { + bfd_release (abfd, reloc_cache); + goto nomem; + } + + if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) { + bfd_release (abfd, relocs); + bfd_release (abfd, reloc_cache); + bfd_error = system_call_error; + return false; + } + + if (each_size == RELOC_EXT_SIZE) { + register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) { + NAME(aout,swap_ext_reloc_in)(abfd, rptr, cache_ptr, symbols); + } + } else { + register struct reloc_std_external *rptr = (struct reloc_std_external*) relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) { + NAME(aout,swap_std_reloc_in)(abfd, rptr, cache_ptr, symbols); + } + + } + + bfd_release (abfd,relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + return true; +} + + + +/* Write out a relocation section into an object file. */ + +boolean +DEFUN(NAME(aout,squirt_out_relocs),(abfd, section), + bfd *abfd AND + asection *section) +{ + arelent **generic; + unsigned char *native, *natptr; + size_t each_size; + + unsigned int count = section->reloc_count; + size_t natsize; + + if (count == 0) return true; + + each_size = obj_reloc_entry_size (abfd); + natsize = each_size * count; + native = (unsigned char *) bfd_zalloc (abfd, natsize); + if (!native) { + bfd_error = no_memory; + return false; + } + + generic = section->orelocation; + + if (each_size == RELOC_EXT_SIZE) + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(aout,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *)natptr); + } + else + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(aout,swap_std_reloc_out)(abfd, *generic, (struct reloc_std_external *)natptr); + } + + if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) { + bfd_release(abfd, native); + return false; + } + bfd_release (abfd, native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +unsigned int +DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols), + bfd *abfd AND + sec_ptr section AND + arelent **relptr AND + asymbol **symbols) +{ + arelent *tblptr = section->relocation; + unsigned int count; + + if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols))) + return 0; + + if (section->flags & SEC_CONSTRUCTOR) { + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count ++) { + *relptr ++ = &chain->relent; + chain = chain->next; + } + } + else { + tblptr = section->relocation; + if (!tblptr) return 0; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + +unsigned int +DEFUN(NAME(aout,get_reloc_upper_bound),(abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (bfd_get_format (abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + if (asect->flags & SEC_CONSTRUCTOR) { + return (sizeof (arelent *) * (asect->reloc_count+1)); + } + + + if (asect == obj_datasec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd)) + +1)); + + if (asect == obj_textsec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd)) + +1)); + + bfd_error = invalid_operation; + return 0; +} + + + unsigned int +DEFUN(NAME(aout,get_symtab_upper_bound),(abfd), + bfd *abfd) +{ + if (!NAME(aout,slurp_symbol_table)(abfd)) return 0; + + return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *)); +} + alent * +DEFUN(NAME(aout,get_lineno),(ignore_abfd, ignore_symbol), + bfd *ignore_abfd AND + asymbol *ignore_symbol) +{ +return (alent *)NULL; +} + +void +DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret), + bfd *ignore_abfd AND + asymbol *symbol AND + symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); + + if (ret->type == '?') + { + int type_code = aout_symbol(symbol)->type & 0xff; + CONST char *stab_name = aout_stab_name(type_code); + static char buf[10]; + + if (stab_name == NULL) + { + sprintf(buf, "(%d)", type_code); + stab_name = buf; + } + ret->type = '-'; + ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff); + ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff); + ret->stab_name = stab_name; + } +} + +void +DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how), + bfd *ignore_abfd AND + PTR afile AND + asymbol *symbol AND + bfd_print_symbol_type how) +{ + FILE *file = (FILE *)afile; + + switch (how) { + case bfd_print_symbol_name: + if (symbol->name) + fprintf(file,"%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type)); + break; + case bfd_print_symbol_all: + { + CONST char *section_name = symbol->section->name; + + + bfd_print_symbol_vandf((PTR)file,symbol); + + fprintf(file," %-5s %04x %02x %02x", + section_name, + (unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type & 0xff)); + if (symbol->name) + fprintf(file," %s", symbol->name); + } + break; + } +} + +/* + provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. +*/ + +boolean +DEFUN(NAME(aout,find_nearest_line),(abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr), + bfd *abfd AND + asection *section AND + asymbol **symbols AND + bfd_vma offset AND + CONST char **filename_ptr AND + CONST char **functionname_ptr AND + unsigned int *line_ptr) +{ + /* Run down the file looking for the filename, function and linenumber */ + asymbol **p; + static char buffer[100]; + static char filename_buffer[200]; + CONST char *directory_name = NULL; + CONST char *main_file_name = NULL; + CONST char *current_file_name = NULL; + CONST char *line_file_name = NULL; /* Value of current_file_name at line number. */ + bfd_vma high_line_vma = ~0; + bfd_vma low_func_vma = 0; + asymbol *func = 0; + *filename_ptr = abfd->filename; + *functionname_ptr = 0; + *line_ptr = 0; + if (symbols != (asymbol **)NULL) { + for (p = symbols; *p; p++) { + aout_symbol_type *q = (aout_symbol_type *)(*p); + next: + switch (q->type){ + case N_SO: + main_file_name = current_file_name = q->symbol.name; + /* Look ahead to next symbol to check if that too is an N_SO. */ + p++; + if (*p == NULL) + break; + q = (aout_symbol_type *)(*p); + if (q->type != (int)N_SO) + goto next; + + /* Found a second N_SO First is directory; second is filename. */ + directory_name = current_file_name; + main_file_name = current_file_name = q->symbol.name; + if (obj_textsec(abfd) != section) + goto done; + break; + case N_SOL: + current_file_name = q->symbol.name; + break; + + case N_SLINE: + + case N_DSLINE: + case N_BSLINE: + /* We'll keep this if it resolves nearer than the one we have already */ + if (q->symbol.value >= offset && + q->symbol.value < high_line_vma) { + *line_ptr = q->desc; + high_line_vma = q->symbol.value; + line_file_name = current_file_name; + } + break; + case N_FUN: + { + /* We'll keep this if it is nearer than the one we have already */ + if (q->symbol.value >= low_func_vma && + q->symbol.value <= offset) { + low_func_vma = q->symbol.value; + func = (asymbol *)q; + } + if (*line_ptr && func) { + CONST char *function = func->name; + char *p; + strncpy(buffer, function, sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = 0; + /* Have to remove : stuff */ + p = strchr(buffer,':'); + if (p != NULL) { *p = '\0'; } + *functionname_ptr = buffer; + goto done; + + } + } + break; + } + } + } + + done: + if (*line_ptr) + main_file_name = line_file_name; + if (main_file_name) { + if (main_file_name[0] == '/' || directory_name == NULL) + *filename_ptr = main_file_name; + else { + sprintf(filename_buffer, "%.140s%.50s", + directory_name, main_file_name); + *filename_ptr = filename_buffer; + } + } + return true; + +} + +int +DEFUN(NAME(aout,sizeof_headers),(abfd, execable), + bfd *abfd AND + boolean execable) +{ + return adata(abfd).exec_bytes_size; +} diff --git a/gnu/usr.bin/gdb/bfd/archive.c b/gnu/usr.bin/gdb/bfd/archive.c new file mode 100644 index 00000000000..5edae9d3db0 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/archive.c @@ -0,0 +1,1770 @@ +/* BFD back-end for archive files (libraries). + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +@setfilename archive-info +SECTION + Archives + +DESCRIPTION + Archives are supported in BFD in <>. + + An archive (or library) is just another BFD. It has a symbol + table, although there's not much a user program will do with it. + + The big difference between an archive BFD and an ordinary BFD + is that the archive doesn't have sections. Instead it has a + chain of BFDs considered its contents. These BFDs can be + manipulated just like any other. The BFDs contained in an + archive opened for reading will all be opened for reading; you + may put either input or output BFDs into an archive opened for + output; it will be handled correctly when the archive is closed. + + Use <> to step through all + the contents of an archive opened for input. It's not + required that you read the entire archive if you don't want + to! Read it until you find what you want. + + Archive contents of output BFDs are chained through the + <> pointer in a BFD. The first one is findable through + the <> slot of the archive. Set it with + <> (q.v.). A given BFD may be in only one + open output archive at a time. + + As expected, the BFD archive code is more general than the + archive code of any given environment. BFD archives may + contain files of different formats (e.g., a.out and coff) and + even different architectures. You may even place archives + recursively into archives! + + This can cause unexpected confusion, since some archive + formats are more expressive than others. For instance, Intel + COFF archives can preserve long filenames; Sun a.out archives + cannot. If you move a file from the first to the second + format and back again, the filename may be truncated. + Likewise, different a.out environments have different + conventions as to how they truncate filenames, whether they + preserve directory names in filenames, etc. When + interoperating with native tools, be sure your files are + homogeneous. + + Beware: most of these formats do not react well to the + presence of spaces in filenames. We do the best we can, but + can't always handle this due to restrctions in the format of + archives. Many unix utilities are braindead in regards to + spaces and such in filenames anyway, so this shouldn't be much + of a restriction. +*/ + +/* Assumes: + o - all archive elements start on an even boundary, newline padded; + o - all arch headers are char *; + o - all arch headers are the same size (across architectures). +*/ + +/* Some formats provide a way to cram a long filename into the short + (16 chars) space provided by a bsd archive. The trick is: make a + special "file" in the front of the archive, sort of like the SYMDEF + entry. If the filename is too long to fit, put it in the extended + name table, and use its index as the filename. To prevent + confusion prepend the index with a space. This means you can't + have filenames that start with a space, but then again, many unix + utilities can't handle that anyway. + + This scheme unfortunately requires that you stand on your head in + order to write an archive since you need to put a magic file at the + front, and need to touch every entry to do so. C'est la vie. + + We support two variants of this idea: + The SVR4 format (extended name table is named "//"), + and an extended pseudo-BSD variant (extended name table is named + "ARFILENAMES/"). The origin of the latter format is uncertain. + + BSD 4.4 uses a third scheme: It writes a long filename + directly after the header. This allows 'ar q' to work. + We current can read BSD 4.4 archives, but not write them. +*/ + +/* Summary of archive member names: + + Symbol table (must be first): + "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib. + "/ " - Symbol table, system 5 style. + + Long name table (must be before regular file members): + "// " - Long name table, System 5 R4 style. + "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4). + + Regular file members with short names: + "filename.o/ " - Regular file, System 5 style (embedded spaces ok). + "filename.o " - Regular file, Berkeley style (no embedded spaces). + + Regular files with long names (or embedded spaces, for BSD variants): + "/18 " - SVR4 style, name at offset 18 in name table. + "#1/23 " - Long name (or embedded paces) 23 characters long, + BSD 4.4 style, full name follows header. + Implemented for reading, not writing. + " 18 " - Long name 18 characters long, extended pseudo-BSD. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/ar.h" +#include "aout/ranlib.h" +#include +#include /* For memchr, strrchr and friends */ +#include + +#ifndef errno +extern int errno; +#endif + +#ifdef GNU960 +#define BFD_GNU960_ARMAG(abfd) (BFD_COFF_FILE_P((abfd)) ? ARMAG : ARMAGB) +#endif + +/* Can't define this in hosts/*.h, because (e.g. in gprof) the hosts file + is included, then obstack.h, which thinks if offsetof is defined, it + doesn't need to include stddef.h. */ +/* Define offsetof for those systems which lack it */ + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* We keep a cache of archive filepointers to archive elements to + speed up searching the archive by filepos. We only add an entry to + the cache when we actually read one. We also don't sort the cache; + it's generally short enough to search linearly. + Note that the pointers here point to the front of the ar_hdr, not + to the front of the contents! +*/ +struct ar_cache { + file_ptr ptr; + bfd* arelt; + struct ar_cache *next; +}; + +#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char) +#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) + +#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data)) +#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header) + +/* Forward declarations of functions */ + +boolean +compute_and_write_armap PARAMS ((bfd *arch, unsigned int elength)); + +static boolean +bsd_update_armap_timestamp PARAMS ((bfd *arch)); + + + +boolean +_bfd_generic_mkarchive (abfd) + bfd *abfd; +{ + abfd->tdata.aout_ar_data = (struct artdata *)bfd_zalloc(abfd, + sizeof (struct artdata)); + + if (bfd_ardata (abfd) == NULL) { + bfd_error = no_memory; + return false; + } + bfd_ardata(abfd)->cache = 0; + return true; +} + +/* +FUNCTION + bfd_get_next_mapent + +SYNOPSIS + symindex bfd_get_next_mapent(bfd *, symindex previous, carsym ** sym); + +DESCRIPTION + This function steps through an archive's symbol table (if it + has one). Successively updates <> with the next symbol's + information, returning that symbol's (internal) index into the + symbol table. + + Supply BFD_NO_MORE_SYMBOLS as the <> entry to get + the first one; returns BFD_NO_MORE_SYMBOLS when you're already + got the last one. + + A <> is a canonical archive symbol. The only + user-visible element is its name, a null-terminated string. +*/ + +symindex +DEFUN(bfd_get_next_mapent,(abfd, prev, entry), + bfd *abfd AND + symindex prev AND + carsym **entry) +{ + if (!bfd_has_map (abfd)) { + bfd_error = invalid_operation; + return BFD_NO_MORE_SYMBOLS; + } + + if (prev == BFD_NO_MORE_SYMBOLS) prev = 0; + else if (++prev >= bfd_ardata (abfd)->symdef_count) + return BFD_NO_MORE_SYMBOLS; + + *entry = (bfd_ardata (abfd)->symdefs + prev); + return prev; +} + +/* To be called by backends only */ + +bfd * +_bfd_create_empty_archive_element_shell (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = new_bfd_contained_in(obfd); + if (nbfd == NULL) + { + bfd_error = no_memory; + return NULL; + } + return nbfd; +} + +/* +FUNCTION + bfd_set_archive_head + +SYNOPSIS + boolean bfd_set_archive_head(bfd *output, bfd *new_head); + +DESCRIPTION + Used whilst processing archives. Sets the head of the chain of + BFDs contained in an archive to @var{new_head}. +*/ + +boolean +DEFUN(bfd_set_archive_head,(output_archive, new_head), + bfd *output_archive AND + bfd *new_head) +{ + + output_archive->archive_head = new_head; + return true; +} + +bfd * +look_for_bfd_in_cache (arch_bfd, filepos) + bfd *arch_bfd; + file_ptr filepos; +{ + struct ar_cache *current; + + for (current = bfd_ardata (arch_bfd)->cache; current != NULL; + current = current->next) + if (current->ptr == filepos) return current->arelt; + + return NULL; +} + +/* Kind of stupid to call cons for each one, but we don't do too many */ +boolean +add_bfd_to_cache (arch_bfd, filepos, new_elt) + bfd *arch_bfd, *new_elt; + file_ptr filepos; +{ + struct ar_cache *new_cache = (struct ar_cache *) + bfd_zalloc(arch_bfd, sizeof (struct ar_cache)); + + if (new_cache == NULL) { + bfd_error = no_memory; + return false; + } + + new_cache->ptr = filepos; + new_cache->arelt = new_elt; + new_cache->next = (struct ar_cache *)NULL; + if (bfd_ardata (arch_bfd)->cache == NULL) + bfd_ardata (arch_bfd)->cache = new_cache; + else { + struct ar_cache *current = bfd_ardata (arch_bfd)->cache; + + for (; current->next != NULL; current = current->next); + current->next = new_cache; + } + + return true; +} + + + +/* The name begins with space. Hence the rest of the name is an index into + the string table. */ +char * +get_extended_arelt_filename (arch, name) + bfd *arch; + char *name; +{ + unsigned long index = 0; + + /* Should extract string so that I can guarantee not to overflow into + the next region, but I'm too lazy. */ + errno = 0; + /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ + index = strtol (name+1, NULL, 10); + if (errno != 0) { + bfd_error = malformed_archive; + return NULL; + } + + return bfd_ardata (arch)->extended_names + index; +} + +/* This functions reads an arch header and returns an areltdata pointer, or + NULL on error. + + Presumes the file pointer is already in the right place (ie pointing + to the ar_hdr in the file). Moves the file pointer; on success it + should be pointing to the front of the file contents; on failure it + could have been moved arbitrarily. +*/ + +struct areltdata * +snarf_ar_hdr (abfd) + bfd *abfd; +{ +#ifndef errno + extern int errno; +#endif + + struct ar_hdr hdr; + char *hdrp = (char *) &hdr; + unsigned int parsed_size; + struct areltdata *ared; + char *filename = NULL; + unsigned int namelen = 0; + unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); + char *allocptr = 0; + + if (bfd_read ((PTR)hdrp, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) { + bfd_error = no_more_archived_files; + return NULL; + } + if (strncmp ((hdr.ar_fmag), ARFMAG, 2)) { + bfd_error = malformed_archive; + return NULL; + } + + errno = 0; + parsed_size = strtol (hdr.ar_size, NULL, 10); + if (errno != 0) { + bfd_error = malformed_archive; + return NULL; + } + + /* extract the filename from the archive - there are two ways to + specify an extendend name table, either the first char of the + name is a space, or it's a slash. */ + if ((hdr.ar_name[0] == '/' + || (hdr.ar_name[0] == ' ' + && memchr (hdr.ar_name, '/', ar_maxnamelen(abfd)) == NULL)) + && bfd_ardata (abfd)->extended_names != NULL) { + filename = get_extended_arelt_filename (abfd, hdr.ar_name); + if (filename == NULL) { + bfd_error = malformed_archive; + return NULL; + } + } + /* BSD4.4-style long filename. + Only implemented for reading, so far! */ + else if (hdr.ar_name[0] == '#' && hdr.ar_name[1] == '1' + && hdr.ar_name[2] == '/' && isdigit(hdr.ar_name[3])) + { + /* BSD-4.4 extended name */ + namelen = atoi (&hdr.ar_name[3]); + allocsize += namelen + 1; + parsed_size -= namelen; + + allocptr = bfd_zalloc(abfd, allocsize); + if (allocptr == NULL) { + bfd_error = no_memory; + return NULL; + } + filename = allocptr + + (sizeof (struct areltdata) + sizeof (struct ar_hdr)); + if (bfd_read (filename, 1, namelen, abfd) != namelen) { + bfd_error = no_more_archived_files; + return NULL; + } + filename[namelen] = '\0'; + } + else + { + /* We judge the end of the name by looking for '/' or ' '. + Note: The SYSV format (terminated by '/') allows embedded + spaces, so only look for ' ' if we don't find '/'. */ + + namelen = 0; + while (hdr.ar_name[namelen] != '\0' && + hdr.ar_name[namelen] != '/') { + namelen++; + if (namelen == (unsigned)ar_maxnamelen(abfd)) { + namelen = 0; + while (hdr.ar_name[namelen] != ' ' + && namelen < (unsigned)ar_maxnamelen(abfd)) { + namelen++; + } + break; + } + } + + allocsize += namelen + 1; + } + + if (!allocptr) { + allocptr = bfd_zalloc(abfd, allocsize); + if (allocptr == NULL) { + bfd_error = no_memory; + return NULL; + } + } + + ared = (struct areltdata *) allocptr; + + ared->arch_header = allocptr + sizeof (struct areltdata); + memcpy ((char *) ared->arch_header, (char *) &hdr, sizeof (struct ar_hdr)); + ared->parsed_size = parsed_size; + + if (filename != NULL) ared->filename = filename; + else { + ared->filename = allocptr + (sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (namelen) + memcpy (ared->filename, hdr.ar_name, namelen); + ared->filename[namelen] = '\0'; + } + + return ared; +} + +/* This is an internal function; it's mainly used when indexing + through the archive symbol table, but also used to get the next + element, since it handles the bookkeeping so nicely for us. +*/ + +bfd * +get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + struct areltdata *new_areldata; + bfd *n_nfd; + + n_nfd = look_for_bfd_in_cache (archive, filepos); + if (n_nfd) + return n_nfd; + + if (0 > bfd_seek (archive, filepos, SEEK_SET)) + { + bfd_error = system_call_error; + return NULL; + } + + if ((new_areldata = snarf_ar_hdr (archive)) == NULL) + return NULL; + + n_nfd = _bfd_create_empty_archive_element_shell (archive); + if (n_nfd == NULL) + { + bfd_release (archive, (PTR)new_areldata); + return NULL; + } + + n_nfd->origin = bfd_tell (archive); + n_nfd->arelt_data = (PTR) new_areldata; + n_nfd->filename = new_areldata->filename; + + if (add_bfd_to_cache (archive, filepos, n_nfd)) + return n_nfd; + + /* huh? */ + bfd_release (archive, (PTR)n_nfd); + bfd_release (archive, (PTR)new_areldata); + return NULL; +} + +/* +FUNCTION + bfd_get_elt_at_index + +SYNOPSIS + bfd *bfd_get_elt_at_index(bfd * archive, int index); + +DESCRIPTION + Return the bfd which is referenced by the symbol indexed by <>. + <> should have been returned by <> (q.v.). + +*/ +bfd * +DEFUN(bfd_get_elt_at_index,(abfd, index), + bfd *abfd AND + int index) +{ + bfd *result = + get_elt_at_filepos + (abfd, (bfd_ardata (abfd)->symdefs + index)->file_offset); + return result; +} + +/* +FUNCTION + bfd_openr_next_archived_file + +SYNOPSIS + bfd* bfd_openr_next_archived_file(bfd *archive, bfd *previous); + +DESCRIPTION + Initially provided a BFD containing an archive and NULL, opens + an inpout BFD on the first contained element and returns that. + Subsequent calls to bfd_openr_next_archived_file should pass + the archive and the previous return value to return a created + BFD to the next contained element. NULL is returned when there + are no more. + +*/ + +bfd * +bfd_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + if ((bfd_get_format (archive) != bfd_archive) || + (archive->direction == write_direction)) + { + bfd_error = invalid_operation; + return NULL; + } + + return BFD_SEND (archive, + openr_next_archived_file, + (archive, + last_file)); +} + +bfd * +bfd_generic_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (!last_file) + filestart = bfd_ardata (archive)->first_file_filepos; + else { + unsigned int size = arelt_size(last_file); + /* Pad to an even boundary... + Note that last_file->origin can be odd in the case of + BSD-4.4-style element with a long odd size. */ + filestart = last_file->origin + size; + filestart += filestart % 2; + } + + return get_elt_at_filepos (archive, filestart); +} + + +bfd_target * +bfd_generic_archive_p (abfd) + bfd *abfd; +{ + char armag[SARMAG+1]; + + if (bfd_read ((PTR)armag, 1, SARMAG, abfd) != SARMAG) { + bfd_error = wrong_format; + return 0; + } + +#ifdef GNU960 + if (strncmp (armag, BFD_GNU960_ARMAG(abfd), SARMAG)) return 0; +#else + if (strncmp (armag, ARMAG, SARMAG) && + strncmp (armag, ARMAGB, SARMAG)) return 0; +#endif + + + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of assignment. */ + abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc(abfd,sizeof (struct artdata)); + + if (bfd_ardata (abfd) == NULL) { + bfd_error = no_memory; + return 0; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + + if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) { + bfd_release(abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = NULL; + return 0; + } + + if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) { + bfd_release(abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = NULL; + return 0; + } + + return abfd->xvec; +} + +/* Returns false on error, true otherwise */ +static boolean +DEFUN (do_slurp_bsd_armap, (abfd), + bfd *abfd) +{ + struct areltdata *mapdata; + unsigned int counter = 0; + int *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int parsed_size; + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */ + + raw_armap = (int *) bfd_zalloc(abfd, parsed_size); + if (raw_armap == NULL) { + bfd_error = no_memory; + return false; + } + + if (bfd_read ((PTR)raw_armap, 1, parsed_size, abfd) != parsed_size) { + bfd_error = malformed_archive; + byebye: + bfd_release (abfd, (PTR)raw_armap); + return false; + } + + ardata->symdef_count = + bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef); + + if (ardata->symdef_count * sizeof (struct symdef) + > parsed_size - sizeof (*raw_armap)) { + /* Probably we're using the wrong byte ordering. */ + bfd_error = wrong_format; + goto byebye; + } + + ardata->cache = 0; + rbase = raw_armap+1; + ardata->symdefs = (carsym *) rbase; + stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4; + + for (;counter < ardata->symdef_count; counter++) { + struct symdef *sym = ((struct symdef *) rbase) + counter; + sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase; + sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset))); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata-> first_file_filepos) %2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an obstack anyway... */ + bfd_has_map (abfd) = true; + return true; +} + +/* Returns false on error, true otherwise */ +static boolean +DEFUN (do_slurp_coff_armap, (abfd), + bfd *abfd) +{ + struct areltdata *mapdata; + int *raw_armap, *rawptr; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + unsigned int parsed_size; + carsym *carsyms; + unsigned int nsymz; /* Number of symbols in armap. */ + + bfd_vma (*swap) PARAMS ((bfd_byte*)); + char int_buf[sizeof(long)]; + unsigned int carsym_size, ptrsize, i; + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */ + + if (bfd_read ((PTR)int_buf, 1, 4, abfd) != 4) { + bfd_error = malformed_archive; + return false; + } + /* It seems that all numeric information in a coff archive is always + in big endian format, nomatter the host or target. */ + swap = bfd_getb32; + nsymz = bfd_getb32((PTR)int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + +#if 1 + /* ... except that some archive formats are broken, and it may be our + fault - the i960 little endian coff sometimes has big and sometimes + little, because our tools changed. Here's a horrible hack to clean + up the crap. */ + + if (stringsize > 0xfffff) { + /* This looks dangerous, let's do it the other way around */ + nsymz = bfd_getl32((PTR)int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + swap = bfd_getl32; + } +#endif + + /* The coff armap must be read sequentially. So we construct a bsd-style + one in core all at once, for simplicity. */ + + carsym_size = (nsymz * sizeof (carsym)); + ptrsize = (4 * nsymz); + + ardata->symdefs = (carsym *) bfd_zalloc(abfd, carsym_size + stringsize + 1); + if (ardata->symdefs == NULL) { + bfd_error = no_memory; + return false; + } + carsyms = ardata->symdefs; + stringbase = ((char *) ardata->symdefs) + carsym_size; + + /* Allocate and read in the raw offsets. */ + raw_armap = (int *) bfd_alloc(abfd, ptrsize); + if (raw_armap == NULL) { + bfd_error = no_memory; + goto release_symdefs; + } + if (bfd_read ((PTR)raw_armap, 1, ptrsize, abfd) != ptrsize + || bfd_read ((PTR)stringbase, 1, stringsize, abfd) != stringsize) { + bfd_error = malformed_archive; + goto release_raw_armap; + } + + /* OK, build the carsyms */ + for (i = 0; i < nsymz; i++) { + rawptr = raw_armap + i; + carsyms->file_offset = swap((PTR)rawptr); + carsyms->name = stringbase; + while (*stringbase++) ; + carsyms++; + } + *stringbase = 0; + + ardata->symdef_count = nsymz; + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata->first_file_filepos) %2; + + bfd_has_map (abfd) = true; + bfd_release (abfd, (PTR)raw_armap); + return true; + + release_raw_armap: + bfd_release (abfd, (PTR)raw_armap); + release_symdefs: + bfd_release (abfd, (PTR)(ardata)->symdefs); + return false; +} + +/* This routine can handle either coff-style or bsd-style armaps. + Returns false on error, true otherwise */ + +boolean +bfd_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + int i = bfd_read ((PTR)nextname, 1, 16, abfd); + + if (i == 0) + return true; + if (i != 16) + return false; + + bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + + if (!strncmp (nextname, "__.SYMDEF ", 16)) + return do_slurp_bsd_armap (abfd); + else if (!strncmp (nextname, "/ ", 16)) + return do_slurp_coff_armap (abfd); + + bfd_has_map (abfd) = false; + return true; +} + +/* Returns false on error, true otherwise */ +/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the + header is in a slightly different order and the map name is '/'. + This flavour is used by hp300hpux. */ +boolean +bfd_slurp_bsd_armap_f2 (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + char nextname[17]; + unsigned int counter = 0; + int *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + int i = bfd_read ((PTR)nextname, 1, 16, abfd); + + if (i == 0) + return true; + if (i != 16) + return false; + + /* The archive has at least 16 bytes in it */ + bfd_seek (abfd, -16L, SEEK_CUR); + + if (!strncmp (nextname, "__.SYMDEF ", 16)) + return do_slurp_bsd_armap (abfd); + + if (strncmp (nextname, "/ ", 16)) + { + bfd_has_map (abfd) = false; + return true; + } + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + + raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size); + if (raw_armap == NULL) + { + bfd_error = no_memory; + byebye: + bfd_release (abfd, (PTR)mapdata); + return false; + } + + if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) != + mapdata->parsed_size) + { + bfd_error = malformed_archive; + byebyebye: + bfd_release (abfd, (PTR)raw_armap); + goto byebye; + } + + ardata->symdef_count = bfd_h_get_16(abfd, (PTR)raw_armap); + + if (ardata->symdef_count * sizeof (struct symdef) + > mapdata->parsed_size - sizeof (*raw_armap)) + { + /* Probably we're using the wrong byte ordering. */ + bfd_error = wrong_format; + goto byebyebye; + } + + ardata->cache = 0; + + stringsize = bfd_h_get_32(abfd, (PTR)(((char*)raw_armap)+2)); + /* skip sym count and string sz */ + rbase = (int*)(((char*)raw_armap) + 6); + stringbase = (char *) rbase; + ardata->symdefs = (carsym *)(((char*) rbase) + stringsize); + + for (;counter < ardata->symdef_count; counter++) + { + struct symdef *sym = ((struct symdef *) ardata->symdefs) + counter; + sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase; + sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset))); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata-> first_file_filepos) %2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an obstack anyway... */ + bfd_has_map (abfd) = true; + return true; +} + +/** Extended name table. + + Normally archives support only 14-character filenames. + + Intel has extended the format: longer names are stored in a special + element (the first in the archive, or second if there is an armap); + the name in the ar_hdr is replaced by . Index is the P.R. of an int (decimal). Data General have + extended the format by using the prefix // for the special element */ + +/* Returns false on error, true otherwise */ +boolean +_bfd_slurp_extended_name_table (abfd) + bfd *abfd; +{ + char nextname[17]; + struct areltdata *namedata; + + /* FIXME: Formatting sucks here, and in case of failure of BFD_READ, + we probably don't want to return true. */ + if (bfd_read ((PTR)nextname, 1, 16, abfd) == 16) { + + bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + + if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 && + strncmp (nextname, "// ", 16) != 0) + { + bfd_ardata (abfd)->extended_names = NULL; + return true; + } + + namedata = snarf_ar_hdr (abfd); + if (namedata == NULL) return false; + + bfd_ardata (abfd)->extended_names = bfd_zalloc(abfd,namedata->parsed_size); + if (bfd_ardata (abfd)->extended_names == NULL) { + bfd_error = no_memory; + byebye: + bfd_release (abfd, (PTR)namedata); + return false; + } + + if (bfd_read ((PTR)bfd_ardata (abfd)->extended_names, 1, + namedata->parsed_size, abfd) != namedata->parsed_size) { + bfd_error = malformed_archive; + bfd_release (abfd, (PTR)(bfd_ardata (abfd)->extended_names)); + bfd_ardata (abfd)->extended_names = NULL; + goto byebye; + } + + /* Since the archive is supposed to be printable if it contains + text, the entries in the list are newline-padded, not null + padded. In SVR4-style archives, the names also have a + trailing '/'. We'll fix both problems here.. */ + { + char *temp = bfd_ardata (abfd)->extended_names; + char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) + if (*temp == '\n') + temp[temp[-1] == '/' ? -1 : 0] = '\0'; + } + + /* Pad to an even boundary if you have to */ + bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd); + bfd_ardata (abfd)->first_file_filepos += + (bfd_ardata (abfd)->first_file_filepos) %2; + + /* FIXME, we can't release namedata here because it was allocated + below extended_names on the obstack... */ + /* bfd_release (abfd, namedata); */ + } + return true; +} + +#ifdef VMS + +/* Return a copy of the stuff in the filename between any :]> and a + semicolon */ +static CONST char * +DEFUN(normalize,(file), + CONST char *file) +{ + CONST char *first; + CONST char *last; + char *copy; + + first = file + strlen(file)-1; + last = first+1; + + while (first != file) + { + if (*first == ';') + last = first; + if (*first == ':' || *first == ']' ||*first == '>') + { + first++; + break; + } + first --; + } + + + copy = bfd_xmalloc(last - first + 1); + memcpy(copy, first, last-first); + copy[last-first] = 0; + + return copy; +} + +#else +static CONST char * +DEFUN (normalize, (file), + CONST char *file) +{ + CONST char * filename = strrchr(file, '/'); + + if (filename != (char *)NULL) { + filename ++; + } + else { + filename = file; + } + return filename; +} +#endif +/* Follows archive_head and produces an extended name table if necessary. + Returns (in tabloc) a pointer to an extended name table, and in tablen + the length of the table. If it makes an entry it clobbers the filename + so that the element may be written without further massage. + Returns true if it ran successfully, false if something went wrong. + A successful return may still involve a zero-length tablen! + */ +boolean +DEFUN (bfd_construct_extended_name_table, (abfd, tabloc, tablen), + bfd *abfd AND + char **tabloc AND + unsigned int *tablen) +{ + unsigned int maxname = abfd->xvec->ar_max_namelen; + unsigned int total_namelen = 0; + bfd *current; + char *strptr; + + *tablen = 0; + + /* Figure out how long the table should be */ + for (current = abfd->archive_head; current != NULL; current = current->next){ + unsigned int thislen = strlen (normalize(current->filename)); + if (thislen > maxname) total_namelen += thislen + 1; /* leave room for \n */ + } + + if (total_namelen == 0) return true; + + *tabloc = bfd_zalloc (abfd,total_namelen); + if (*tabloc == NULL) { + bfd_error = no_memory; + return false; + } + + *tablen = total_namelen; + strptr = *tabloc; + + for (current = abfd->archive_head; current != NULL; current = + current->next) { + CONST char *normal =normalize( current->filename); + unsigned int thislen = strlen (normal); + if (thislen > maxname) { + /* Works for now; may need to be re-engineered if we encounter an oddball + archive format and want to generalise this hack. */ + struct ar_hdr *hdr = arch_hdr(current); + strcpy (strptr, normal); + strptr[thislen] = '\n'; + hdr->ar_name[0] = ' '; + /* We know there will always be enough room (one of the few cases + where you may safely use sprintf). */ + sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc)); + /* Kinda Kludgy. We should just use the returned value of sprintf + but not all implementations get this right */ + { + char *temp = hdr->ar_name +2; + for (; temp < hdr->ar_name + maxname; temp++) + if (*temp == '\0') *temp = ' '; + } + strptr += thislen + 1; + } + } + + return true; +} + +/** A couple of functions for creating ar_hdrs */ + +/* Takes a filename, returns an arelt_data for it, or NULL if it can't make one. + The filename must refer to a filename in the filesystem. + The filename field of the ar_hdr will NOT be initialized +*/ + +struct areltdata * +DEFUN(bfd_ar_hdr_from_filesystem, (abfd,filename), + bfd* abfd AND + CONST char *filename) +{ + struct stat status; + struct areltdata *ared; + struct ar_hdr *hdr; + char *temp, *temp1; + + + if (stat (filename, &status) != 0) { + bfd_error = system_call_error; + return NULL; + } + + ared = (struct areltdata *) bfd_zalloc(abfd, sizeof (struct ar_hdr) + + sizeof (struct areltdata)); + if (ared == NULL) { + bfd_error = no_memory; + return NULL; + } + hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); + + /* ar headers are space padded, not null padded! */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; *(temp++) = ' '); + strncpy (hdr->ar_fmag, ARFMAG, 2); + + /* Goddamned sprintf doesn't permit MAXIMUM field lengths */ + sprintf ((hdr->ar_date), "%-12ld", status.st_mtime); + sprintf ((hdr->ar_uid), "%d", status.st_uid); + sprintf ((hdr->ar_gid), "%d", status.st_gid); + sprintf ((hdr->ar_mode), "%-8o", (unsigned) status.st_mode); + sprintf ((hdr->ar_size), "%-10ld", status.st_size); + /* Correct for a lossage in sprintf whereby it null-terminates. I cannot + understand how these C losers could design such a ramshackle bunch of + IO operations */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; temp++) { + if (*temp == '\0') *temp = ' '; + } + strncpy (hdr->ar_fmag, ARFMAG, 2); + ared->parsed_size = status.st_size; + ared->arch_header = (char *) hdr; + + return ared; +} + +/* This is magic required by the "ar" program. Since it's + undocumented, it's undocumented. You may think that it would + take a strong stomach to write this, and it does, but it takes + even a stronger stomach to try to code around such a thing! +*/ + +struct ar_hdr * +DEFUN(bfd_special_undocumented_glue, (abfd, filename), + bfd *abfd AND + char *filename) +{ + struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename); + if (ar_elt == NULL) + return NULL; + return (struct ar_hdr *) ar_elt->arch_header; +} + + +/* Analogous to stat call */ +int +bfd_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + struct ar_hdr *hdr; + char *aloser; + + if (abfd->arelt_data == NULL) { + bfd_error = invalid_operation; + return -1; + } + + hdr = arch_hdr (abfd); + +#define foo(arelt, stelt, size) \ + buf->stelt = strtol (hdr->arelt, &aloser, size); \ + if (aloser == hdr->arelt) return -1; + + foo (ar_date, st_mtime, 10); + foo (ar_uid, st_uid, 10); + foo (ar_gid, st_gid, 10); + foo (ar_mode, st_mode, 8); + + buf->st_size = arch_eltdata (abfd)->parsed_size; + + return 0; +} + +void +bfd_dont_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + /* FIXME: This interacts unpleasantly with ar's quick-append option. + Fortunately ic960 users will never use that option. Fixing this + is very hard; fortunately I know how to do it and will do so once + intel's release is out the door. */ + + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = normalize(pathname); + int maxlen = ar_maxnamelen (abfd); + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + + if (length < maxlen) (hdr->ar_name)[length] = ar_padchar (abfd); + return; + +} + +void +bfd_bsd_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else { + /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + length = maxlen; + } + + if (length < maxlen) (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* Store name into ar header. Truncates the name to fit. + 1> strip pathname to be just the basename. + 2> if it's short enuf to fit, stuff it in. + 3> If it doesn't end with .o, truncate it to fit + 4> truncate it before the .o, append .o, stuff THAT in. +*/ + +/* This is what gnu ar does. It's better but incompatible with the bsd ar. */ +void +bfd_gnu_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else { /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) { + hdr->ar_name[maxlen - 2] = '.'; + hdr->ar_name[maxlen - 1] = 'o'; + } + length = maxlen; + } + + if (length < 16) (hdr->ar_name)[length] = ar_padchar (abfd); +} + + +/* The BFD is open for write and has its format set to bfd_archive */ +boolean +_bfd_write_archive_contents (arch) + bfd *arch; +{ + bfd *current; + char *etable = NULL; + unsigned int elength = 0; + boolean makemap = bfd_has_map (arch); + boolean hasobjects = false; /* if no .o's, don't bother to make a map */ + unsigned int i; + int tries; + + /* Verify the viability of all entries; if any of them live in the + filesystem (as opposed to living in an archive open for input) + then construct a fresh ar_hdr for them. + */ + for (current = arch->archive_head; current; current = current->next) { + if (bfd_write_p (current)) { + bfd_error = invalid_operation; + return false; + } + if (!current->arelt_data) { + current->arelt_data = + (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename); + if (!current->arelt_data) return false; + + /* Put in the file name */ + + BFD_SEND (arch, _bfd_truncate_arname,(arch, + current->filename, + (char *) arch_hdr(current))); + + + } + + if (makemap) { /* don't bother if we won't make a map! */ + if ((bfd_check_format (current, bfd_object)) +#if 0 /* FIXME -- these are not set correctly */ + && ((bfd_get_file_flags (current) & HAS_SYMS)) +#endif + ) + hasobjects = true; + } + } + + if (!bfd_construct_extended_name_table (arch, &etable, &elength)) + return false; + + bfd_seek (arch, (file_ptr) 0, SEEK_SET); +#ifdef GNU960 + bfd_write (BFD_GNU960_ARMAG(arch), 1, SARMAG, arch); +#else + bfd_write (ARMAG, 1, SARMAG, arch); +#endif + + if (makemap && hasobjects) { + + if (compute_and_write_armap (arch, elength) != true) { + return false; + } + } + + if (elength != 0) { + struct ar_hdr hdr; + + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + sprintf (&(hdr.ar_name[0]), "ARFILENAMES/"); + sprintf (&(hdr.ar_size[0]), "%-10d", (int) elength); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch); + bfd_write (etable, 1, elength, arch); + if ((elength % 2) == 1) bfd_write ("\n", 1, 1, arch); + + } + + for (current = arch->archive_head; current; current = current->next) { + char buffer[DEFAULT_BUFFERSIZE]; + unsigned int remaining = arelt_size (current); + struct ar_hdr *hdr = arch_hdr(current); + /* write ar header */ + + if (bfd_write ((char *)hdr, 1, sizeof(*hdr), arch) != sizeof(*hdr)) { + syserr: + bfd_error = system_call_error; + return false; + } + if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto syserr; + while (remaining) + { + unsigned int amt = DEFAULT_BUFFERSIZE; + if (amt > remaining) { + amt = remaining; + } + errno = 0; + if (bfd_read (buffer, amt, 1, current) != amt) { + if (errno) goto syserr; + /* Looks like a truncated archive. */ + bfd_error = malformed_archive; + return false; + } + if (bfd_write (buffer, amt, 1, arch) != amt) goto syserr; + remaining -= amt; + } + if ((arelt_size (current) % 2) == 1) bfd_write ("\n", 1, 1, arch); + } + + /* Verify the timestamp in the archive file. If it would + not be accepted by the linker, rewrite it until it would be. + If anything odd happens, break out and just return. + (The Berkeley linker checks the timestamp and refuses to read the + table-of-contents if it is >60 seconds less than the file's + modified-time. That painful hack requires this painful hack. */ + + tries = 1; + do { + /* FIXME! This kludge is to avoid adding a member to the xvec, + while generating a small patch for Adobe. FIXME! The + update_armap_timestamp function call should be in the xvec, + thus: + + if (bfd_update_armap_timestamp (arch) == true) break; + ^ + + Instead, we check whether in a BSD archive, and call directly. */ + + if (arch->xvec->write_armap != bsd_write_armap) + break; + if (bsd_update_armap_timestamp(arch) == true) /* FIXME!!! Vector it */ + break; + if (tries > 0) + fprintf (stderr, + "Warning: writing archive was slow: rewriting timestamp\n"); + } while (++tries < 6 ); + + return true; +} + +/* Note that the namidx for the first symbol is 0 */ + +boolean +compute_and_write_armap (arch, elength) + bfd *arch; + unsigned int elength; +{ + bfd *current; + file_ptr elt_no = 0; + struct orl *map; + int orl_max = 15000; /* fine initial default */ + int orl_count = 0; + int stridx = 0; /* string index */ + + /* Dunno if this is the best place for this info... */ + if (elength != 0) elength += sizeof (struct ar_hdr); + elength += elength %2 ; + + map = (struct orl *) bfd_zalloc (arch,orl_max * sizeof (struct orl)); + if (map == NULL) { + bfd_error = no_memory; + return false; + } + + /* Drop all the files called __.SYMDEF, we're going to make our + own */ + while (arch->archive_head && + strcmp(arch->archive_head->filename,"__.SYMDEF") == 0) + { + arch->archive_head = arch->archive_head->next; + } + /* Map over each element */ + for (current = arch->archive_head; + current != (bfd *)NULL; + current = current->next, elt_no++) + { + if ((bfd_check_format (current, bfd_object) == true) + && ((bfd_get_file_flags (current) & HAS_SYMS))) { + asymbol **syms; + unsigned int storage; + unsigned int symcount; + unsigned int src_count; + + storage = get_symtab_upper_bound (current); + if (storage != 0) { + + syms = (asymbol **) bfd_zalloc (arch,storage); + if (syms == NULL) { + bfd_error = no_memory; /* FIXME -- memory leak */ + return false; + } + symcount = bfd_canonicalize_symtab (current, syms); + + + /* Now map over all the symbols, picking out the ones we want */ + for (src_count = 0; src_count flags; + asection *sec = + syms[src_count]->section; + + if ((flags & BSF_GLOBAL || + flags & BSF_WEAK || + flags & BSF_INDIRECT || + bfd_is_com_section (sec)) + && (sec != &bfd_und_section)) { + + /* This symbol will go into the archive header */ + if (orl_count == orl_max) + { + orl_max *= 2; + map = (struct orl *) bfd_realloc (arch, (char *) map, + orl_max * sizeof (struct orl)); + } + + (map[orl_count]).name = (char **) &((syms[src_count])->name); + (map[orl_count]).pos = (file_ptr) current; + (map[orl_count]).namidx = stridx; + + stridx += strlen ((syms[src_count])->name) + 1; + ++orl_count; + } + } + } + } + } + /* OK, now we have collected all the data, let's write them out */ + if (!BFD_SEND (arch, write_armap, + (arch, elength, map, orl_count, stridx))) { + + return false; + } + + + return true; +} + +boolean +bsd_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + int padit = stridx & 1; + unsigned int ranlibsize = orl_count * sizeof (struct ranlib); + unsigned int stringsize = stridx + padit; + /* Include 8 bytes to store ranlibsize and stringsize in output. */ + unsigned int mapsize = ranlibsize + stringsize + 8; + file_ptr firstreal; + bfd *current = arch->archive_head; + bfd *last_elt = current; /* last element arch seen */ + int temp; + int count; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + + firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + stat (arch->filename, &statbuf); + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + sprintf (hdr.ar_name, RANLIBMAG); + /* Remember the timestamp, to keep it holy. But fudge it a little. */ + bfd_ardata(arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET; + bfd_ardata(arch)->armap_datepos = SARMAG + + offsetof(struct ar_hdr, ar_date[0]); + sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp); + sprintf (hdr.ar_uid, "%d", getuid()); + sprintf (hdr.ar_gid, "%d", getgid()); + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch); + bfd_h_put_32(arch, (bfd_vma) ranlibsize, (PTR)&temp); + bfd_write (&temp, 1, sizeof (temp), arch); + + for (count = 0; count < orl_count; count++) { + struct symdef outs; + struct symdef *outp = &outs; + + if (((bfd *)(map[count]).pos) != last_elt) { + do { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } while (current != (bfd *)(map[count]).pos); + } /* if new archive element */ + + last_elt = current; + bfd_h_put_32(arch, ((map[count]).namidx),(PTR) &outs.s.string_offset); + bfd_h_put_32(arch, firstreal,(PTR) &outs.file_offset); + bfd_write ((char *)outp, 1, sizeof (outs), arch); + } + + /* now write the strings themselves */ + bfd_h_put_32(arch, stringsize, (PTR)&temp); + bfd_write ((PTR)&temp, 1, sizeof (temp), arch); + for (count = 0; count < orl_count; count++) + bfd_write (*((map[count]).name), 1, strlen (*((map[count]).name))+1, arch); + + /* The spec sez this should be a newline. But in order to be + bug-compatible for sun's ar we use a null. */ + if (padit) + bfd_write("\0",1,1,arch); + + return true; +} + + +/* At the end of archive file handling, update the timestamp in the + file, so the linker will accept it. + + Return true if the timestamp was OK, or an unusual problem happened. + Return false if we updated the timestamp. */ + +static boolean +bsd_update_armap_timestamp (arch) + bfd *arch; +{ + struct stat archstat; + struct ar_hdr hdr; + int i; + + /* Flush writes, get last-write timestamp from file, and compare it + to the timestamp IN the file. */ + bfd_flush (arch); + if (bfd_stat (arch, &archstat) == -1) { + perror ("Reading archive file mod timestamp"); + return true; /* Can't read mod time for some reason */ + } + if (archstat.st_mtime <= bfd_ardata(arch)->armap_timestamp) + return true; /* OK by the linker's rules */ + + /* Update the timestamp. */ + bfd_ardata(arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET; + + /* Prepare an ASCII version suitable for writing. */ + memset (hdr.ar_date, 0, sizeof (hdr.ar_date)); + sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp); + for (i = 0; i < sizeof (hdr.ar_date); i++) + if (hdr.ar_date[i] == '\0') + (hdr.ar_date)[i] = ' '; + + /* Write it into the file. */ + bfd_seek (arch, bfd_ardata(arch)->armap_datepos, SEEK_SET); + if (bfd_write (hdr.ar_date, sizeof(hdr.ar_date), 1, arch) + != sizeof(hdr.ar_date)) { + perror ("Writing updated armap timestamp"); + return true; /* Some error while writing */ + } + + return false; /* We updated the timestamp successfully. */ +} + + +/* A coff armap looks like : + lARMAG + struct ar_hdr with name = '/' + number of symbols + offset of file for symbol 0 + offset of file for symbol 1 + + offset of file for symbol n-1 + symbol name 0 + symbol name 1 + + symbol name n-1 + +*/ + +boolean +coff_write_armap (arch, elength, map, symbol_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int symbol_count; + int stridx; +{ + /* The size of the ranlib is the number of exported symbols in the + archive * the number of bytes in a int, + an int for the count */ + + unsigned int ranlibsize = (symbol_count * 4) + 4; + unsigned int stringsize = stridx; + unsigned int mapsize = stringsize + ranlibsize; + file_ptr archive_member_file_ptr; + bfd *current = arch->archive_head; + int count; + struct ar_hdr hdr; + unsigned int i; + int padit = mapsize & 1; + + if (padit) mapsize ++; + + /* work out where the first object file will go in the archive */ + archive_member_file_ptr = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + hdr.ar_name[0] = '/'; + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", (long)time (NULL)); + /* This, at least, is what Intel coff sets the values to.: */ + sprintf ((hdr.ar_uid), "%d", 0); + sprintf ((hdr.ar_gid), "%d", 0); + sprintf ((hdr.ar_mode), "%-7o",(unsigned ) 0); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + + /* Write the ar header for this item and the number of symbols */ + + + bfd_write ((PTR)&hdr, 1, sizeof (struct ar_hdr), arch); + + bfd_write_bigendian_4byte_int(arch, symbol_count); + + /* Two passes, first write the file offsets for each symbol - + remembering that each offset is on a two byte boundary. */ + + /* Write out the file offset for the file associated with each + symbol, and remember to keep the offsets padded out. */ + + current = arch->archive_head; + count = 0; + while (current != (bfd *)NULL && count < symbol_count) { + /* For each symbol which is used defined in this object, write out + the object file's address in the archive */ + + while (((bfd *)(map[count]).pos) == current) { + bfd_write_bigendian_4byte_int(arch, archive_member_file_ptr); + count++; + } + /* Add size of this archive entry */ + archive_member_file_ptr += arelt_size (current) + sizeof (struct + ar_hdr); + /* remember aboout the even alignment */ + archive_member_file_ptr += archive_member_file_ptr % 2; + current = current->next; + } + + + + /* now write the strings themselves */ + for (count = 0; count < symbol_count; count++) { + bfd_write ((PTR)*((map[count]).name), + 1, + strlen (*((map[count]).name))+1, arch); + + } + /* The spec sez this should be a newline. But in order to be + bug-compatible for arc960 we use a null. */ + if (padit) + bfd_write("\0",1,1,arch); + + return true; +} diff --git a/gnu/usr.bin/gdb/bfd/archures.c b/gnu/usr.bin/gdb/bfd/archures.c new file mode 100644 index 00000000000..9697904bd73 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/archures.c @@ -0,0 +1,731 @@ +/* BFD library support routines for architectures. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Hacked by John Gilmore and Steve Chamberlain of Cygnus Support. + + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* + +SECTION + Architectures + + BFD's idea of an architecture is implimented in + <>. BFD keeps one atom in a BFD describing the + architecture of the data attached to the BFD; a pointer to a + <>. + + Pointers to structures can be requested independently of a bfd + so that an architecture's information can be interrogated + without access to an open bfd. + + The arch information is provided by each architecture package. + The set of default architectures is selected by the #define + <>. This is normally set up in the + <> file of your choice. If the name is not + defined, then all the architectures supported are included. + + When BFD starts up, all the architectures are called with an + initialize method. It is up to the architecture back end to + insert as many items into the list of architectures as it wants to; + generally this would be one for each machine and one for the + default case (an item with a machine field of 0). +*/ + +/* + +SUBSECTION + bfd_architecture + +DESCRIPTION + This enum gives the object file's CPU architecture, in a + global sense --- i.e., what processor family does it belong to? + There is another field, which indicates what processor within + the family is in use. The machine gives a number which + distingushes different versions of the architecture, + containing for example 2 and 3 for Intel i960 KA and i960 KB, + and 68020 and 68030 for Motorola 68020 and 68030. + +.enum bfd_architecture +.{ +. bfd_arch_unknown, {* File arch not known *} +. bfd_arch_obscure, {* Arch known, not one of these *} +. bfd_arch_m68k, {* Motorola 68xxx *} +. bfd_arch_vax, {* DEC Vax *} +. bfd_arch_i960, {* Intel 960 *} +. {* The order of the following is important. +. lower number indicates a machine type that +. only accepts a subset of the instructions +. available to machines with higher numbers. +. The exception is the "ca", which is +. incompatible with all other machines except +. "core". *} +. +.#define bfd_mach_i960_core 1 +.#define bfd_mach_i960_ka_sa 2 +.#define bfd_mach_i960_kb_sb 3 +.#define bfd_mach_i960_mc 4 +.#define bfd_mach_i960_xa 5 +.#define bfd_mach_i960_ca 6 +. +. bfd_arch_a29k, {* AMD 29000 *} +. bfd_arch_sparc, {* SPARC *} +. bfd_arch_mips, {* MIPS Rxxxx *} +. bfd_arch_i386, {* Intel 386 *} +. bfd_arch_we32k, {* AT&T WE32xxx *} +. bfd_arch_tahoe, {* CCI/Harris Tahoe *} +. bfd_arch_i860, {* Intel 860 *} +. bfd_arch_romp, {* IBM ROMP PC/RT *} +. bfd_arch_alliant, {* Alliant *} +. bfd_arch_convex, {* Convex *} +. bfd_arch_m88k, {* Motorola 88xxx *} +. bfd_arch_pyramid, {* Pyramid Technology *} +. bfd_arch_h8300, {* Hitachi H8/300 *} +.#define bfd_mach_h8300 1 +.#define bfd_mach_h8300h 2 +. bfd_arch_rs6000, {* IBM RS/6000 *} +. bfd_arch_hppa, {* HP PA RISC *} +. bfd_arch_z8k, {* Zilog Z8000 *} +.#define bfd_mach_z8001 1 +.#define bfd_mach_z8002 2 +. bfd_arch_h8500, {* Hitachi H8/500 *} +. bfd_arch_sh, {* Hitachi SH *} +. bfd_arch_alpha, {* Dec Alpha *} +. bfd_arch_last +. }; + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* + +SUBSECTION + bfd_arch_info + +DESCRIPTION + This structure contains information on architectures for use + within BFD. + +. +.typedef struct bfd_arch_info +.{ +. int bits_per_word; +. int bits_per_address; +. int bits_per_byte; +. enum bfd_architecture arch; +. long mach; +. char *arch_name; +. CONST char *printable_name; +. unsigned int section_align_power; +. {* true if this is the default machine for the architecture *} +. boolean the_default; +. CONST struct bfd_arch_info * (*compatible) +. PARAMS ((CONST struct bfd_arch_info *a, +. CONST struct bfd_arch_info *b)); +. +. boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *)); +. {* How to disassemble an instruction, producing a printable +. representation on a specified stdio stream. This isn't +. defined for most processors at present, because of the size +. of the additional tables it would drag in, and because gdb +. wants to use a different interface. *} +. unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data, +. PTR stream)); +. +. struct bfd_arch_info *next; +.} bfd_arch_info_type; +*/ + +bfd_arch_info_type *bfd_arch_info_list; + + +/* +FUNCTION + bfd_printable_name + +SYNOPSIS + CONST char *bfd_printable_name(bfd *abfd); + +DESCRIPTION + Return a printable string representing the architecture and machine + from the pointer to the arch info structure + +*/ + +CONST char * +DEFUN(bfd_printable_name, (abfd), + bfd *abfd) +{ + return abfd->arch_info->printable_name; +} + + + +/* +FUNCTION + bfd_scan_arch + +SYNOPSIS + bfd_arch_info_type *bfd_scan_arch(CONST char *); + +DESCRIPTION + This routine is provided with a string and tries to work out + if bfd supports any cpu which could be described with the name + provided. The routine returns a pointer to an arch_info + structure if a machine is found, otherwise NULL. + +*/ + +bfd_arch_info_type * +DEFUN(bfd_scan_arch,(string), + CONST char *string) +{ + struct bfd_arch_info *ap; + + /* Look through all the installed architectures */ + for (ap = bfd_arch_info_list; + ap != (bfd_arch_info_type *)NULL; + ap = ap->next) { + + if (ap->scan(ap, string)) + return ap; + } + return (bfd_arch_info_type *)NULL; +} + + + +/* +FUNCTION + bfd_arch_get_compatible + +SYNOPSIS + CONST bfd_arch_info_type *bfd_arch_get_compatible( + CONST bfd *abfd, + CONST bfd *bbfd); + +DESCRIPTION + This routine is used to determine whether two BFDs' + architectures and achine types are compatible. It calculates + the lowest common denominator between the two architectures + and machine types implied by the BFDs and returns a pointer to + an arch_info structure describing the compatible machine. +*/ + +CONST bfd_arch_info_type * +DEFUN(bfd_arch_get_compatible,(abfd, bbfd), +CONST bfd *abfd AND +CONST bfd *bbfd) + +{ + return abfd->arch_info->compatible(abfd->arch_info,bbfd->arch_info); +} + + +/* +INTERNAL_DEFINITION + bfd_default_arch_struct + +DESCRIPTION + The <> is an item of + <> which has been initialized to a fairly + generic state. A BFD starts life by pointing to this + structure, until the correct back end has determined the real + architecture of the file. + +.extern bfd_arch_info_type bfd_default_arch_struct; + +*/ + +bfd_arch_info_type bfd_default_arch_struct = +{ + 32,32,8,bfd_arch_unknown,0,"unknown","unknown",2,true, + bfd_default_compatible, + bfd_default_scan, + 0, +}; + +/* +FUNCTION + bfd_set_arch_info + +SYNOPSIS + void bfd_set_arch_info(bfd *, bfd_arch_info_type *); + +*/ + +void DEFUN(bfd_set_arch_info,(abfd, arg), +bfd *abfd AND +bfd_arch_info_type *arg) +{ + abfd->arch_info = arg; +} + +/* +INTERNAL_FUNCTION + bfd_default_set_arch_mach + +SYNOPSIS + boolean bfd_default_set_arch_mach(bfd *abfd, + enum bfd_architecture arch, + unsigned long mach); + +DESCRIPTION + Set the architecture and machine type in a bfd. This finds the + correct pointer to structure and inserts it into the arch_info + pointer. +*/ + +boolean DEFUN(bfd_default_set_arch_mach,(abfd, arch, mach), + bfd *abfd AND + enum bfd_architecture arch AND + unsigned long mach) +{ + static struct bfd_arch_info *old_ptr = &bfd_default_arch_struct; + boolean found = false; + /* run through the table to find the one we want, we keep a little + cache to speed things up */ + if (old_ptr == 0 || arch != old_ptr->arch || mach != old_ptr->mach) { + bfd_arch_info_type *ptr; + old_ptr = (bfd_arch_info_type *)NULL; + for (ptr = bfd_arch_info_list; + ptr != (bfd_arch_info_type *)NULL; + ptr= ptr->next) { + if (ptr->arch == arch && + ((ptr->mach == mach) || (ptr->the_default && mach == 0))) { + old_ptr = ptr; + found = true; + break; + } + } + if (found==false) { + /*looked for it and it wasn't there, so put in the default */ + old_ptr = &bfd_default_arch_struct; + bfd_error = bad_value; + } + } + else { + /* it was in the cache */ + found = true; + } + + abfd->arch_info = old_ptr; + + return found; +} + + + + + +/* +FUNCTION + bfd_get_arch + +SYNOPSIS + enum bfd_architecture bfd_get_arch(bfd *abfd); + +DESCRIPTION + Returns the enumerated type which describes the supplied bfd's + architecture + +*/ + +enum bfd_architecture DEFUN(bfd_get_arch, (abfd), bfd *abfd) +{ + return abfd->arch_info->arch; +} + +/* +FUNCTION + bfd_get_mach + +SYNOPSIS + unsigned long bfd_get_mach(bfd *abfd); + +DESCRIPTION + Returns the long type which describes the supplied bfd's + machine +*/ + +unsigned long +DEFUN(bfd_get_mach, (abfd), bfd *abfd) +{ + return abfd->arch_info->mach; +} + +/* +FUNCTION + bfd_arch_bits_per_byte + +SYNOPSIS + unsigned int bfd_arch_bits_per_byte(bfd *abfd); + +DESCRIPTION + Returns the number of bits in one of the architectures bytes + +*/ + +unsigned int DEFUN(bfd_arch_bits_per_byte, (abfd), bfd *abfd) + { + return abfd->arch_info->bits_per_byte; + } + +/* +FUNCTION + bfd_arch_bits_per_address + +SYNOPSIS + unsigned int bfd_arch_bits_per_address(bfd *abfd); + +DESCRIPTION + Returns the number of bits in one of the architectures addresses +*/ + +unsigned int DEFUN(bfd_arch_bits_per_address, (abfd), bfd *abfd) + { + return abfd->arch_info->bits_per_address; + } + + +extern void bfd_a29k_arch PARAMS ((void)); +extern void bfd_alpha_arch PARAMS ((void)); +extern void bfd_h8300_arch PARAMS ((void)); +extern void bfd_h8500_arch PARAMS ((void)); +extern void bfd_hppa_arch PARAMS ((void)); +extern void bfd_i386_arch PARAMS ((void)); +extern void bfd_i960_arch PARAMS ((void)); +extern void bfd_m68k_arch PARAMS ((void)); +extern void bfd_m88k_arch PARAMS ((void)); +extern void bfd_mips_arch PARAMS ((void)); +extern void bfd_rs6000_arch PARAMS ((void)); +extern void bfd_sh_arch PARAMS ((void)); +extern void bfd_sparc_arch PARAMS ((void)); +extern void bfd_vax_arch PARAMS ((void)); +extern void bfd_we32k_arch PARAMS ((void)); +extern void bfd_z8k_arch PARAMS ((void)); + +static void (*archures_init_table[]) PARAMS ((void)) = +{ +#ifdef SELECT_ARCHITECTURES + SELECT_ARCHITECTURES, +#else + bfd_a29k_arch, + bfd_alpha_arch, + bfd_h8300_arch, + bfd_h8500_arch, + bfd_hppa_arch, + bfd_i386_arch, + bfd_i960_arch, + bfd_m68k_arch, + bfd_m88k_arch, + bfd_mips_arch, + bfd_rs6000_arch, + bfd_sh_arch, + bfd_sparc_arch, + bfd_vax_arch, + bfd_we32k_arch, + bfd_z8k_arch, +#endif + 0 + }; + + + +/* +INTERNAL_FUNCTION + bfd_arch_init + +SYNOPSIS + void bfd_arch_init(void); + +DESCRIPTION + This routine initializes the architecture dispatch table by + calling all installed architecture packages and getting them + to poke around. +*/ + +void +DEFUN_VOID(bfd_arch_init) +{ + void (**ptable) PARAMS ((void)); + for (ptable = archures_init_table; + *ptable ; + ptable++) + { + (*ptable)(); + } +} + + +/* +INTERNAL_FUNCTION + bfd_arch_linkin + +SYNOPSIS + void bfd_arch_linkin(bfd_arch_info_type *); + +DESCRIPTION + Link the provided arch info structure into the list +*/ + +void DEFUN(bfd_arch_linkin,(ptr), + bfd_arch_info_type *ptr) +{ + ptr->next = bfd_arch_info_list; + bfd_arch_info_list = ptr; +} + + +/* +INTERNAL_FUNCTION + bfd_default_compatible + +SYNOPSIS + CONST bfd_arch_info_type *bfd_default_compatible + (CONST bfd_arch_info_type *a, + CONST bfd_arch_info_type *b); + +DESCRIPTION + The default function for testing for compatibility. +*/ + +CONST bfd_arch_info_type * +DEFUN(bfd_default_compatible,(a,b), + CONST bfd_arch_info_type *a AND + CONST bfd_arch_info_type *b) +{ + if(a->arch != b->arch) return NULL; + + if (a->mach > b->mach) { + return a; + } + if (b->mach > a->mach) { + return b; + } + return a; +} + + +/* +INTERNAL_FUNCTION + bfd_default_scan + +SYNOPSIS + boolean bfd_default_scan(CONST struct bfd_arch_info *, CONST char *); + +DESCRIPTION + The default function for working out whether this is an + architecture hit and a machine hit. +*/ + +boolean +DEFUN(bfd_default_scan,(info, string), +CONST struct bfd_arch_info *info AND +CONST char *string) +{ + CONST char *ptr_src; + CONST char *ptr_tst; + unsigned long number; + enum bfd_architecture arch; + /* First test for an exact match */ + if (strcmp(string, info->printable_name) == 0) return true; + + /* See how much of the supplied string matches with the + architecture, eg the string m68k:68020 would match the 68k entry + up to the :, then we get left with the machine number */ + + for (ptr_src = string, + ptr_tst = info->arch_name; + *ptr_src && *ptr_tst; + ptr_src++, + ptr_tst++) + { + if (*ptr_src != *ptr_tst) break; + } + + /* Chewed up as much of the architecture as will match, skip any + colons */ + if (*ptr_src == ':') ptr_src++; + + if (*ptr_src == 0) { + /* nothing more, then only keep this one if it is the default + machine for this architecture */ + return info->the_default; + } + number = 0; + while (isdigit(*ptr_src)) { + number = number * 10 + *ptr_src - '0'; + ptr_src++; + } + + switch (number) + { + case 300: + arch = bfd_arch_h8300; + break; + + case 500: + arch = bfd_arch_h8500; + break; + + case 68010: + case 68020: + case 68030: + case 68040: + case 68332: + case 68050: + case 68000: + arch = bfd_arch_m68k; + break; + case 386: + case 80386: + case 486: + case 80486: + arch = bfd_arch_i386; + break; + case 29000: + arch = bfd_arch_a29k; + break; + + case 8000: + arch = bfd_arch_z8k; + break; + + case 32000: + arch = bfd_arch_we32k; + break; + + case 860: + case 80860: + arch = bfd_arch_i860; + break; + case 960: + case 80960: + arch = bfd_arch_i960; + break; + + case 2000: + case 3000: + case 4000: + case 4400: + arch = bfd_arch_mips; + break; + + case 6000: + arch = bfd_arch_rs6000; + break; + + default: + return false; + } + if (arch != info->arch) + return false; + + if (number != info->mach) + return false; + + return true; +} + + + + +/* +FUNCTION + bfd_get_arch_info + + +SYNOPSIS + bfd_arch_info_type * bfd_get_arch_info(bfd *); + +*/ + +bfd_arch_info_type * +DEFUN(bfd_get_arch_info,(abfd), +bfd *abfd) +{ + return abfd->arch_info; +} + + +/* +FUNCTION + bfd_lookup_arch + +SYNOPSIS + bfd_arch_info_type *bfd_lookup_arch + (enum bfd_architecture + arch, + long machine); + +DESCRIPTION + Look for the architecure info struct which matches the + arguments given. A machine of 0 will match the + machine/architecture structure which marks itself as the + default. +*/ + +bfd_arch_info_type * +DEFUN(bfd_lookup_arch,(arch, machine), +enum bfd_architecture arch AND +long machine) +{ + bfd_arch_info_type *ap; + bfd_check_init(); + for (ap = bfd_arch_info_list; + ap != (bfd_arch_info_type *)NULL; + ap = ap->next) { + if (ap->arch == arch && + ((ap->mach == machine) + || (ap->the_default && machine == 0))) { + return ap; + } + } + return (bfd_arch_info_type *)NULL; +} + + + +/* +FUNCTION + bfd_printable_arch_mach + +SYNOPSIS + CONST char * bfd_printable_arch_mach + (enum bfd_architecture arch, unsigned long machine); + +DESCRIPTION + Return a printable string representing the architecture and + machine type. + + NB. The use of this routine is depreciated. +*/ + +CONST char * +DEFUN(bfd_printable_arch_mach,(arch, machine), + enum bfd_architecture arch AND + unsigned long machine) +{ + bfd_arch_info_type *ap = bfd_lookup_arch(arch, machine); + if(ap) return ap->printable_name; + return "UNKNOWN!"; +} diff --git a/gnu/usr.bin/gdb/bfd/bfd.c b/gnu/usr.bin/gdb/bfd/bfd.c new file mode 100644 index 00000000000..a994cd170a0 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/bfd.c @@ -0,0 +1,733 @@ +/* Generic BFD library interface and support routines. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + <> + + A BFD is has type <>; objects of this type are the + cornerstone of any application using <>. References + though the BFD and to data in the BFD give the entire BFD + functionality. + + Here is the struct used to define the type <>. This + contains the major data about the file, and contains pointers + to the rest of the data. + +CODE_FRAGMENT +. +.struct _bfd +.{ +. {* The filename the application opened the BFD with. *} +. CONST char *filename; +. +. {* A pointer to the target jump table. *} +. struct bfd_target *xvec; +. +. {* To avoid dragging too many header files into every file that +. includes `<>', IOSTREAM has been declared as a "char +. *", and MTIME as a "long". Their correct types, to which they +. are cast when used, are "FILE *" and "time_t". The iostream +. is the result of an fopen on the filename. *} +. char *iostream; +. +. {* Is the file being cached *} +. +. boolean cacheable; +. +. {* Marks whether there was a default target specified when the +. BFD was opened. This is used to select what matching algorithm +. to use to chose the back end. *} +. +. boolean target_defaulted; +. +. {* The caching routines use these to maintain a +. least-recently-used list of BFDs *} +. +. struct _bfd *lru_prev, *lru_next; +. +. {* When a file is closed by the caching routines, BFD retains +. state information on the file here: +. *} +. +. file_ptr where; +. +. {* and here:*} +. +. boolean opened_once; +. +. {* Set if we have a locally maintained mtime value, rather than +. getting it from the file each time: *} +. +. boolean mtime_set; +. +. {* File modified time, if mtime_set is true: *} +. +. long mtime; +. +. {* Reserved for an unimplemented file locking extension.*} +. +. int ifd; +. +. {* The format which belongs to the BFD.*} +. +. bfd_format format; +. +. {* The direction the BFD was opened with*} +. +. enum bfd_direction {no_direction = 0, +. read_direction = 1, +. write_direction = 2, +. both_direction = 3} direction; +. +. {* Format_specific flags*} +. +. flagword flags; +. +. {* Currently my_archive is tested before adding origin to +. anything. I believe that this can become always an add of +. origin, with origin set to 0 for non archive files. *} +. +. file_ptr origin; +. +. {* Remember when output has begun, to stop strange things +. happening. *} +. boolean output_has_begun; +. +. {* Pointer to linked list of sections*} +. struct sec *sections; +. +. {* The number of sections *} +. unsigned int section_count; +. +. {* Stuff only useful for object files: +. The start address. *} +. bfd_vma start_address; +. +. {* Used for input and output*} +. unsigned int symcount; +. +. {* Symbol table for output BFD*} +. struct symbol_cache_entry **outsymbols; +. +. {* Pointer to structure which contains architecture information*} +. struct bfd_arch_info *arch_info; +. +. {* Stuff only useful for archives:*} +. PTR arelt_data; +. struct _bfd *my_archive; +. struct _bfd *next; +. struct _bfd *archive_head; +. boolean has_armap; +. +. {* Used by the back end to hold private data. *} +. +. union +. { +. struct aout_data_struct *aout_data; +. struct artdata *aout_ar_data; +. struct _oasys_data *oasys_obj_data; +. struct _oasys_ar_data *oasys_ar_data; +. struct coff_tdata *coff_obj_data; +. struct ecoff_tdata *ecoff_obj_data; +. struct ieee_data_struct *ieee_data; +. struct ieee_ar_data_struct *ieee_ar_data; +. struct srec_data_struct *srec_data; +. struct tekhex_data_struct *tekhex_data; +. struct elf_obj_tdata *elf_obj_data; +. struct nlm_obj_tdata *nlm_obj_data; +. struct bout_data_struct *bout_data; +. struct sun_core_struct *sun_core_data; +. struct trad_core_struct *trad_core_data; +. struct hppa_data_struct *hppa_data; +. struct hpux_core_struct *hpux_core_data; +. struct sgi_core_struct *sgi_core_data; +. struct lynx_core_struct *lynx_core_data; +. struct osf_core_struct *osf_core_data; +. PTR any; +. } tdata; +. +. {* Used by the application to hold private data*} +. PTR usrdata; +. +. {* Where all the allocated stuff under this BFD goes *} +. struct obstack memory; +. +. {* Is this really needed in addition to usrdata? *} +. asymbol **ld_symbols; +.}; +. +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "libcoff.h" +#include "libecoff.h" +#undef obj_symbols +#include "libelf.h" + +#undef strerror +extern char *strerror(); + +/** Error handling + o - Most functions return nonzero on success (check doc for + precise semantics); 0 or NULL on error. + o - Internal errors are documented by the value of bfd_error. + If that is system_call_error then check errno. + o - The easiest way to report this to the user is to use bfd_perror. +*/ + +bfd_ec bfd_error = no_error; + +CONST char *CONST bfd_errmsgs[] = { + "No error", + "System call error", + "Invalid target", + "File in wrong format", + "Invalid operation", + "Memory exhausted", + "No symbols", + "No relocation info", + "No more archived files", + "Malformed archive", + "Symbol not found", + "File format not recognized", + "File format is ambiguous", + "Section has no contents", + "Nonrepresentable section on output", + "Symbol needs debug section which does not exist", + "Bad value", + "File truncated", + "#" + }; + +static +void +DEFUN(bfd_nonrepresentable_section,(abfd, name), + CONST bfd * CONST abfd AND + CONST char * CONST name) +{ + fprintf(stderr, + "bfd error writing file %s, format %s can't represent section %s\n", + abfd->filename, + abfd->xvec->name, + name); + exit(1); +} + +/*ARGSUSED*/ +static +void +DEFUN(bfd_undefined_symbol,(relent, seclet), + CONST arelent *relent AND + CONST struct bfd_seclet *seclet) +{ + asymbol *symbol = *(relent->sym_ptr_ptr); + fprintf(stderr, "bfd error relocating, symbol %s is undefined\n", + symbol->name); + exit(1); +} +/*ARGSUSED*/ +static +void +DEFUN(bfd_reloc_value_truncated,(relent, seclet), + CONST arelent *relent AND + struct bfd_seclet *seclet) +{ + fprintf(stderr, "bfd error relocating, value truncated\n"); + exit(1); +} +/*ARGSUSED*/ +static +void +DEFUN(bfd_reloc_is_dangerous,(relent, seclet), + CONST arelent *relent AND + CONST struct bfd_seclet *seclet) +{ + fprintf(stderr, "bfd error relocating, dangerous\n"); + exit(1); +} + +bfd_error_vector_type bfd_error_vector = + { + bfd_nonrepresentable_section , + bfd_undefined_symbol, + bfd_reloc_value_truncated, + bfd_reloc_is_dangerous, + }; + + +CONST char * +bfd_errmsg (error_tag) + bfd_ec error_tag; +{ +#ifndef errno + extern int errno; +#endif + if (error_tag == system_call_error) + return strerror (errno); + + if ((((int)error_tag <(int) no_error) || + ((int)error_tag > (int)invalid_error_code))) + error_tag = invalid_error_code;/* sanity check */ + + return bfd_errmsgs [(int)error_tag]; +} + +void +DEFUN (bfd_default_error_trap, (error_tag), + bfd_ec error_tag) +{ + fprintf(stderr, "bfd assert fail (%s)\n", bfd_errmsg(error_tag)); +} + +void (*bfd_error_trap) PARAMS ((bfd_ec)) = bfd_default_error_trap; +void (*bfd_error_nonrepresentabltrap) PARAMS ((bfd_ec)) = bfd_default_error_trap; + +void +DEFUN(bfd_perror,(message), + CONST char *message) +{ + if (bfd_error == system_call_error) + perror((char *)message); /* must be system error then... */ + else { + if (message == NULL || *message == '\0') + fprintf (stderr, "%s\n", bfd_errmsg (bfd_error)); + else + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_error)); + } +} + + +/** Symbols */ + + +/* +FUNCTION + bfd_get_reloc_upper_bound + +SYNOPSIS + unsigned int bfd_get_reloc_upper_bound(bfd *abfd, asection *sect); + +DESCRIPTION + This function return the number of bytes required to store the + relocation information associated with section <> + attached to bfd <> + +*/ + + +unsigned int +DEFUN(bfd_get_reloc_upper_bound,(abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (abfd->format != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + + return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); +} + +/* +FUNCTION + bfd_canonicalize_reloc + +SYNOPSIS + unsigned int bfd_canonicalize_reloc + (bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms); + +DESCRIPTION + This function calls the back end associated with the open + <> and translates the external form of the relocation + information attached to <> into the internal canonical + form. The table is placed into memory at <>, which has + been preallocated, usually by a call to + <>. + + The <> table is also needed for horrible internal magic + reasons. + + +*/ +unsigned int +DEFUN(bfd_canonicalize_reloc,(abfd, asect, location, symbols), + bfd *abfd AND + sec_ptr asect AND + arelent **location AND + asymbol **symbols) +{ + if (abfd->format != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + return BFD_SEND (abfd, _bfd_canonicalize_reloc, + (abfd, asect, location, symbols)); + } + + +/* +FUNCTION + bfd_set_file_flags + +SYNOPSIS + boolean bfd_set_file_flags(bfd *abfd, flagword flags); + +DESCRIPTION + This function attempts to set the flag word in the referenced + BFD structure to the value supplied. + + Possible errors are: + o wrong_format - The target bfd was not of object format. + o invalid_operation - The target bfd was open for reading. + o invalid_operation - + The flag word contained a bit which was not applicable to the + type of file. eg, an attempt was made to set the D_PAGED bit + on a bfd format which does not support demand paging + +*/ + +boolean +bfd_set_file_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + if (abfd->format != bfd_object) { + bfd_error = wrong_format; + return false; + } + + if (bfd_read_p (abfd)) { + bfd_error = invalid_operation; + return false; + } + + bfd_get_file_flags (abfd) = flags; + if ((flags & bfd_applicable_file_flags (abfd)) != flags) { + bfd_error = invalid_operation; + return false; + } + +return true; +} + +/* +FUNCTION + bfd_set_reloc + +SYNOPSIS + void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count) + +DESCRIPTION + This function sets the relocation pointer and count within a + section to the supplied values. + +*/ +/*ARGSUSED*/ +void +bfd_set_reloc (ignore_abfd, asect, location, count) + bfd *ignore_abfd; + sec_ptr asect; + arelent **location; + unsigned int count; +{ + asect->orelocation = location; + asect->reloc_count = count; +} + +void +bfd_assert(file, line) +char *file; +int line; +{ + fprintf(stderr, "bfd assertion fail %s:%d\n",file,line); +} + + +/* +FUNCTION + bfd_set_start_address + +DESCRIPTION + Marks the entry point of an output BFD. + +RETURNS + Returns <> on success, <> otherwise. + +SYNOPSIS + boolean bfd_set_start_address(bfd *, bfd_vma); +*/ + +boolean +bfd_set_start_address(abfd, vma) +bfd *abfd; +bfd_vma vma; +{ + abfd->start_address = vma; + return true; +} + + +/* +FUNCTION + The bfd_get_mtime function + +SYNOPSIS + long bfd_get_mtime(bfd *); + +DESCRIPTION + Return file modification time (as read from file system, or + from archive header for archive members). + +*/ + +long +bfd_get_mtime (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ + return buf.st_mtime; +} + +/* +FUNCTION + The bfd_get_size function + +SYNOPSIS + long bfd_get_size(bfd *); + +DESCRIPTION + Return file size (as read from file system) for the file + associated with a bfd. + + Note that the initial motivation for, and use of, this routine is not + so we can get the exact size of the object the bfd applies to, since + that might not be generally possible (archive members for example?). + Although it would be ideal if someone could eventually modify + it so that such results were guaranteed. + + Instead, we want to ask questions like "is this NNN byte sized + object I'm about to try read from file offset YYY reasonable?" + As as example of where we might want to do this, some object formats + use string tables for which the first sizeof(long) bytes of the table + contain the size of the table itself, including the size bytes. + If an application tries to read what it thinks is one of these + string tables, without some way to validate the size, and for + some reason the size is wrong (byte swapping error, wrong location + for the string table, etc), the only clue is likely to be a read + error when it tries to read the table, or a "virtual memory + exhausted" error when it tries to allocated 15 bazillon bytes + of space for the 15 bazillon byte table it is about to read. + This function at least allows us to answer the quesion, "is the + size reasonable?". +*/ + +long +bfd_get_size (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + return buf.st_size; +} + +/* +FUNCTION + The bfd_get_gp_size function + +SYNOPSIS + int bfd_get_gp_size(bfd *); + +DESCRIPTION + Get the maximum size of objects to be optimized using the GP + register under MIPS ECOFF. This is typically set by the -G + argument to the compiler, assembler or linker. +*/ + +int +bfd_get_gp_size (abfd) + bfd *abfd; +{ + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp_size; + return 0; +} + +/* +FUNCTION + The bfd_set_gp_size function + +SYNOPSIS + void bfd_set_gp_size(bfd *, int); + +DESCRIPTION + Set the maximum size of objects to be optimized using the GP + register under ECOFF or MIPS ELF. This is typically set by + the -G argument to the compiler, assembler or linker. +*/ + +void +bfd_set_gp_size (abfd, i) + bfd *abfd; + int i; +{ + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp_size = i; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp_size (abfd) = i; +} + +/* +FUNCTION + bfd_scan_vma + +DESCRIPTION + Converts, like strtoul, a numerical expression as a + string into a bfd_vma integer, and returns that integer. + (Though without as many bells and whistles as strtoul.) + The expression is assumed to be unsigned (i.e. positive). + If given a base, it is used as the base for conversion. + A base of 0 causes the function to interpret the string + in hex if a leading "0x" or "0X" is found, otherwise + in octal if a leading zero is found, otherwise in decimal. + + Overflow is not detected. + +SYNOPSIS + bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base); +*/ + +bfd_vma +DEFUN(bfd_scan_vma,(string, end, base), + CONST char *string AND + CONST char **end AND + int base) +{ + bfd_vma value; + int digit; + + /* Let the host do it if possible. */ + if (sizeof(bfd_vma) <= sizeof(unsigned long)) + return (bfd_vma) strtoul (string, 0, base); + + /* A negative base makes no sense, and we only need to go as high as hex. */ + if ((base < 0) || (base > 16)) + return (bfd_vma) 0; + + if (base == 0) + { + if (string[0] == '0') + { + if ((string[1] == 'x') || (string[1] == 'X')) + base = 16; + /* XXX should we also allow "0b" or "0B" to set base to 2? */ + else + base = 8; + } + else + base = 10; + } + if ((base == 16) && + (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + string += 2; + /* XXX should we also skip over "0b" or "0B" if base is 2? */ + +/* Speed could be improved with a table like hex_value[] in gas. */ +#define HEX_VALUE(c) \ + (isxdigit(c) ? \ + (isdigit(c) ? \ + (c - '0') : \ + (10 + c - (islower(c) ? 'a' : 'A'))) : \ + 42) + + for (value = 0; (digit = HEX_VALUE(*string)) < base; string++) + { + value = value * base + digit; + } + + if (end) + *end = string; + + return value; +} + +/* +FUNCTION + stuff + +DESCRIPTION + stuff which should be documented + +.#define bfd_sizeof_headers(abfd, reloc) \ +. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) +. +.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ +. BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) +. +. {* Do these three do anything useful at all, for any back end? *} +.#define bfd_debug_info_start(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) +. +.#define bfd_debug_info_end(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) +. +.#define bfd_debug_info_accumulate(abfd, section) \ +. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) +. +. +.#define bfd_stat_arch_elt(abfd, stat) \ +. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) +. +.#define bfd_set_arch_mach(abfd, arch, mach)\ +. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) +. +.#define bfd_get_relocated_section_contents(abfd, seclet, data, relocateable) \ +. BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable)) +. +.#define bfd_relax_section(abfd, section, symbols) \ +. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols)) +. +.#define bfd_seclet_link(abfd, data, relocateable) \ +. BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable)) + +*/ diff --git a/gnu/usr.bin/gdb/bfd/bfd.h b/gnu/usr.bin/gdb/bfd/bfd.h new file mode 100644 index 00000000000..fbe0f0f36ba --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/bfd.h @@ -0,0 +1,1803 @@ +/* Main header file for the bfd library -- portable access to object files. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them; +** instead, change bfd-in.h or the other BFD source files processed to +** generate these files. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* bfd.h -- The only header file required by users of the bfd library + +The bfd.h file is generated from bfd-in.h and various .c files; if you +change it, your changes will probably be lost. + +All the prototypes and definitions following the comment "THE FOLLOWING +IS EXTRACTED FROM THE SOURCE" are extracted from the source files for +BFD. If you change it, someone oneday will extract it from the source +again, and your changes will be lost. To save yourself from this bind, +change the definitions in the source in the bfd directory. Type "make +docs" and then "make headers" in that directory, and magically this file +will change to reflect your changes. + +If you don't have the tools to perform the extraction, then you are +safe from someone on your system trampling over your header files. +You should still maintain the equivalence between the source and this +file though; every change you make to the .c file should be reflected +here. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#include "ansidecl.h" +#include "obstack.h" + +#define BFD_VERSION "2.2" + +#define BFD_ARCH_SIZE 32 + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* 64-bit type definition (if any) from bfd's sysdep.h goes here */ + + +/* forward declaration */ +typedef struct _bfd bfd; + +/* To squelch erroneous compiler warnings ("illegal pointer + combination") from the SVR3 compiler, we would like to typedef + boolean to int (it doesn't like functions which return boolean. + Making sure they are never implicitly declared to return int + doesn't seem to help). But this file is not configured based on + the host. */ +/* General rules: functions which are boolean return true on success + and false on failure (unless they're a predicate). -- bfd.doc */ +/* I'm sure this is going to break something and someone is going to + force me to change it. */ +/* typedef enum boolean {false, true} boolean; */ +/* Yup, SVR4 has a "typedef enum boolean" in -fnf */ +typedef enum bfd_boolean {false, true} boolean; + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from . + For now, try to avoid breaking stuff by not including here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef long int file_ptr; + +/* Support for different sizes of target format ints and addresses. If the + host implements 64-bit values, it defines HOST_64_BIT to be the appropriate + type. Otherwise, this code will fall back on gcc's "long long" type if gcc + is being used. HOST_64_BIT must be defined in such a way as to be a valid + type name by itself or with "unsigned" prefixed. It should be a signed + type by itself. + + If neither is the case, then compilation will fail if 64-bit targets are + requested. If you don't request any 64-bit targets, you should be safe. */ + +#ifdef BFD64 + +#if defined (__GNUC__) && !defined (HOST_64_BIT) +#define HOST_64_BIT long long +typedef HOST_64_BIT int64_type; +typedef unsigned HOST_64_BIT uint64_type; +#endif + +#if !defined (uint64_type) && defined (__GNUC__) +#define uint64_type unsigned long long +#define int64_type long long +#define uint64_typeLOW(x) (unsigned long)(((x) & 0xffffffff)) +#define uint64_typeHIGH(x) (unsigned long)(((x) >> 32) & 0xffffffff) +#endif + +typedef unsigned HOST_64_BIT bfd_vma; +typedef HOST_64_BIT bfd_signed_vma; +typedef unsigned HOST_64_BIT bfd_size_type; +typedef unsigned HOST_64_BIT symvalue; +#define fprintf_vma(s,x) \ + fprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x)) +#define sprintf_vma(s,x) \ + sprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x)) +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf(s, "%08lx", x) +#define sprintf_vma(s,x) sprintf(s, "%08lx", x) +#endif /* not BFD64 */ +#define printf_vma(x) fprintf_vma(stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ + +/** File formats */ + +typedef enum bfd_format { + bfd_unknown = 0, /* file format is unknown */ + bfd_object, /* linker/assember/compiler output */ + bfd_archive, /* object archive file */ + bfd_core, /* core dump */ + bfd_type_end} /* marks the end; don't use it! */ + bfd_format; + +/* Object file flag values */ +#define NO_FLAGS 0x00 +#define HAS_RELOC 0x01 +#define EXEC_P 0x02 +#define HAS_LINENO 0x04 +#define HAS_DEBUG 0x08 +#define HAS_SYMS 0x10 +#define HAS_LOCALS 0x20 +#define DYNAMIC 0x40 +#define WP_TEXT 0x80 +#define D_PAGED 0x100 +#define BFD_IS_RELAXABLE 0x200 + +/* symbols and relocation */ + +typedef unsigned long symindex; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +typedef enum bfd_symclass { + bfd_symclass_unknown = 0, + bfd_symclass_fcommon, /* fortran common symbols */ + bfd_symclass_global, /* global symbol, what a surprise */ + bfd_symclass_debugger, /* some debugger symbol */ + bfd_symclass_undefined /* none known */ + } symclass; + + +/* general purpose part of a symbol; + target specific parts will be found in libcoff.h, liba.out.h etc */ + + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym { + char *name; + file_ptr file_offset; /* look here to find the file */ +} carsym; /* to make these you call a carsymogen */ + + +/* Used in generating armaps. Perhaps just a forward definition would do? */ +struct orl { /* output ranlib */ + char **name; /* symbol name */ + file_ptr pos; /* bfd* or file position */ + int namidx; /* index into string table */ +}; + + + +/* Linenumber stuff */ +typedef struct lineno_cache_entry { + unsigned int line_number; /* Linenumber from start of function*/ + union { + struct symbol_cache_entry *sym; /* Function name */ + unsigned long offset; /* Offset into section */ + } u; +} alent; + +/* object and core file sections */ + + +#define align_power(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + +typedef struct sec *sec_ptr; + +#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) +#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) +#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) +#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) +#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) + +#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) + +#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = true), true) +#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true) +#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true) + +typedef struct stat stat_type; + +/** Error handling */ + +typedef enum bfd_error { + no_error = 0, system_call_error, invalid_target, + wrong_format, invalid_operation, no_memory, + no_symbols, no_relocation_info, + no_more_archived_files, malformed_archive, + symbol_not_found, file_not_recognized, + file_ambiguously_recognized, no_contents, + bfd_error_nonrepresentable_section, + no_debug_section, bad_value, + + /* An input file is shorter than expected. */ + file_truncated, + + invalid_error_code} bfd_ec; + +extern bfd_ec bfd_error; +struct reloc_cache_entry; +struct bfd_seclet; + + +typedef struct bfd_error_vector { + void (* nonrepresentable_section ) PARAMS ((CONST bfd *CONST abfd, + CONST char *CONST name)); + void (* undefined_symbol) PARAMS ((CONST struct reloc_cache_entry *rel, + CONST struct bfd_seclet *sec)); + void (* reloc_value_truncated) PARAMS ((CONST struct + reloc_cache_entry *rel, + struct bfd_seclet *sec)); + + void (* reloc_dangerous) PARAMS ((CONST struct reloc_cache_entry *rel, + CONST struct bfd_seclet *sec)); + +} bfd_error_vector_type; + +CONST char *bfd_errmsg PARAMS ((bfd_ec error_tag)); +void bfd_perror PARAMS ((CONST char *message)); + + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; /* */ + CONST char *name; /* Symbol name. */ + char stab_other; /* Unused. */ + short stab_desc; /* Info for N_TYPE. */ + CONST char *stab_name; +} symbol_info; + +/* The code that implements targets can initialize a jump table with this + macro. It must name all its routines the same way (a prefix plus + the standard routine suffix), or it must #define the routines that + are not so named, before calling JUMP_TABLE in the initializer. */ + +/* Semi-portable string concatenation in cpp. + The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the + inner CAT macros to be evaluated first, producing still-valid pp-tokens. + Then the final concatenation can be done. (Sigh.) */ +#ifndef CAT +#ifdef SABER +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#else +#ifdef __STDC__ +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define XCAT2(a,b) CAT(a,b) +#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d)) +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#endif +#endif +#endif + +#define JUMP_TABLE(NAME)\ +CAT(NAME,_core_file_failing_command),\ +CAT(NAME,_core_file_failing_signal),\ +CAT(NAME,_core_file_matches_executable_p),\ +CAT(NAME,_slurp_armap),\ +CAT(NAME,_slurp_extended_name_table),\ +CAT(NAME,_truncate_arname),\ +CAT(NAME,_write_armap),\ +CAT(NAME,_close_and_cleanup),\ +CAT(NAME,_set_section_contents),\ +CAT(NAME,_get_section_contents),\ +CAT(NAME,_new_section_hook),\ +CAT(NAME,_get_symtab_upper_bound),\ +CAT(NAME,_get_symtab),\ +CAT(NAME,_get_reloc_upper_bound),\ +CAT(NAME,_canonicalize_reloc),\ +CAT(NAME,_make_empty_symbol),\ +CAT(NAME,_print_symbol),\ +CAT(NAME,_get_symbol_info),\ +CAT(NAME,_get_lineno),\ +CAT(NAME,_set_arch_mach),\ +CAT(NAME,_openr_next_archived_file),\ +CAT(NAME,_find_nearest_line),\ +CAT(NAME,_generic_stat_arch_elt),\ +CAT(NAME,_sizeof_headers),\ +CAT(NAME,_bfd_debug_info_start),\ +CAT(NAME,_bfd_debug_info_end),\ +CAT(NAME,_bfd_debug_info_accumulate),\ +CAT(NAME,_bfd_get_relocated_section_contents),\ +CAT(NAME,_bfd_relax_section),\ +CAT(NAME,_bfd_seclet_link),\ +CAT(NAME,_bfd_reloc_type_lookup),\ +CAT(NAME,_bfd_make_debug_symbol) + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + + +/* User program access to BFD facilities */ + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 PARAMS ((unsigned char *)); +bfd_vma bfd_getl64 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 PARAMS ((unsigned char *)); +bfd_vma bfd_getb32 PARAMS ((unsigned char *)); +bfd_vma bfd_getl32 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 PARAMS ((unsigned char *)); +bfd_vma bfd_getb16 PARAMS ((unsigned char *)); +bfd_vma bfd_getl16 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 PARAMS ((unsigned char *)); +void bfd_putb64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 PARAMS ((bfd_vma, unsigned char *)); + +/* And more from the source. */ +void +bfd_init PARAMS ((void)); + +bfd * +bfd_openr PARAMS ((CONST char *filename, CONST char*target)); + +bfd * +bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd)); + +bfd * +bfd_openw PARAMS ((CONST char *filename, CONST char *target)); + +boolean +bfd_close PARAMS ((bfd *)); + +boolean +bfd_close_all_done PARAMS ((bfd *)); + +bfd_size_type +bfd_alloc_size PARAMS ((bfd *abfd)); + +bfd * +bfd_create PARAMS ((CONST char *filename, bfd *templ)); + + + /* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + (*((unsigned char *)(ptr)) = (unsigned char)val) +#define bfd_put_signed_8 \ + bfd_put_8 +#define bfd_get_8(abfd, ptr) \ + (*(unsigned char *)(ptr)) +#define bfd_get_signed_8(abfd, ptr) \ + ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) + +#define bfd_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +#define bfd_put_signed_16 \ + bfd_put_16 +#define bfd_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx16, (ptr)) +#define bfd_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) + +#define bfd_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +#define bfd_put_signed_32 \ + bfd_put_32 +#define bfd_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx32, (ptr)) +#define bfd_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) + +#define bfd_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +#define bfd_put_signed_64 \ + bfd_put_64 +#define bfd_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx64, (ptr)) +#define bfd_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) + + + /* Byte swapping macros for file header data. */ + +#define bfd_h_put_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_put_signed_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_get_8(abfd, ptr) \ + bfd_get_8 (abfd, ptr) +#define bfd_h_get_signed_8(abfd, ptr) \ + bfd_get_signed_8 (abfd, ptr) + +#define bfd_h_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +#define bfd_h_put_signed_16 \ + bfd_h_put_16 +#define bfd_h_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx16,(ptr)) +#define bfd_h_get_signed_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) + +#define bfd_h_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +#define bfd_h_put_signed_32 \ + bfd_h_put_32 +#define bfd_h_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx32,(ptr)) +#define bfd_h_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) + +#define bfd_h_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +#define bfd_h_put_signed_64 \ + bfd_h_put_64 +#define bfd_h_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx64,(ptr)) +#define bfd_h_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) + +typedef struct sec +{ + /* The name of the section, the name isn't a copy, the pointer is + the same as that passed to bfd_make_section. */ + + CONST char *name; + + /* Which section is it 0.nth */ + + int index; + + /* The next section in the list belonging to the BFD, or NULL. */ + + struct sec *next; + + /* The field flags contains attributes of the section. Some of + flags are read in from the object file, and some are + synthesized from other information. */ + + flagword flags; + +#define SEC_NO_FLAGS 0x000 + + /* Tells the OS to allocate space for this section when loaded. + This would clear for a section containing debug information + only. */ +#define SEC_ALLOC 0x001 + + /* Tells the OS to load the section from the file when loading. + This would be clear for a .bss section */ +#define SEC_LOAD 0x002 + + /* The section contains data still to be relocated, so there will + be some relocation information too. */ +#define SEC_RELOC 0x004 + +#if 0 /* Obsolete ? */ +#define SEC_BALIGN 0x008 +#endif + + /* A signal to the OS that the section contains read only + data. */ +#define SEC_READONLY 0x010 + + /* The section contains code only. */ +#define SEC_CODE 0x020 + + /* The section contains data only. */ +#define SEC_DATA 0x040 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x080 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by <>. When a back end sees a symbol + which should be used in a constructor list, it creates a new + section for the type of name (eg <<__CTOR_LIST__>>), attaches + the symbol to it and builds a relocation. To build the lists + of constructors, all the linker has to do is catenate all the + sections called <<__CTOR_LIST__>> and relocte the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x100 + + /* The section is a constuctor, and should be placed at the + end of the text, data, or bss section(?). */ +#define SEC_CONSTRUCTOR_TEXT 0x1100 +#define SEC_CONSTRUCTOR_DATA 0x2100 +#define SEC_CONSTRUCTOR_BSS 0x3100 + + /* The section has contents - a data section could be + <> | <>, a debug section could be + <> */ +#define SEC_HAS_CONTENTS 0x200 + + /* An instruction to the linker not to output sections + containing this flag even if they have information which + would normally be written. */ +#define SEC_NEVER_LOAD 0x400 + + /* The section is a shared library section. The linker must leave + these completely alone, as the vma and size are used when + the executable is loaded. */ +#define SEC_SHARED_LIBRARY 0x800 + + /* The section is a common section (symbols may be defined + multiple times, the value of a symbol is the amount of + space it requires, and the largest symbol value is the one + used). Most targets have exactly one of these (which we + translate to bfd_com_section), but ECOFF has two. */ +#define SEC_IS_COMMON 0x8000 + + /* The section contains only debugging information. For + example, this is set for ELF .debug and .stab sections. + strip tests this flag to see if a section can be + discarded. */ +#define SEC_DEBUGGING 0x10000 + + /* End of section flags. */ + + /* The virtual memory address of the section - where it will be + at run time. The symbols are relocated against this. The + user_set_vma flag is maintained by bfd; if it's not set, the + backend can assign addresses (for example, in <>, where + the default address for <<.data>> is dependent on the specific + target and various flags). */ + + bfd_vma vma; + boolean user_set_vma; + + /* The load address of the section - where it would be in a + rom image, really only used for writing section header + information. */ + + bfd_vma lma; + + /* The size of the section in bytes, as it will be output. + contains a value even if the section has no contents (eg, the + size of <<.bss>>). This will be filled in after relocation */ + + bfd_size_type _cooked_size; + + /* The size on disk of the section in bytes originally. Normally this + value is the same as the size, but if some relaxing has + been done, then this value will be bigger. */ + + bfd_size_type _raw_size; + + /* If this section is going to be output, then this value is the + offset into the output section of the first byte in the input + section. Eg, if this was going to start at the 100th byte in + the output section, this value would be 100. */ + + bfd_vma output_offset; + + /* The output section through which to map on output. */ + + struct sec *output_section; + + /* The alignment requirement of the section, as an exponent - eg + 3 aligns to 2^3 (or 8) */ + + unsigned int alignment_power; + + /* If an input section, a pointer to a vector of relocation + records for the data in this section. */ + + struct reloc_cache_entry *relocation; + + /* If an output section, a pointer to a vector of pointers to + relocation records for the data in this section. */ + + struct reloc_cache_entry **orelocation; + + /* The number of relocation records in one of the above */ + + unsigned reloc_count; + + /* Information below is back end specific - and not always used + or updated. */ + + /* File position of section data */ + + file_ptr filepos; + + /* File position of relocation info */ + + file_ptr rel_filepos; + + /* File position of line data */ + + file_ptr line_filepos; + + /* Pointer to data for applications */ + + PTR userdata; + + struct lang_output_section *otheruserdata; + + /* Attached line number information */ + + alent *lineno; + + /* Number of line number records */ + + unsigned int lineno_count; + + /* When a section is being output, this value changes as more + linenumbers are written out */ + + file_ptr moving_line_filepos; + + /* what the section number is in the target world */ + + int target_index; + + PTR used_by_bfd; + + /* If this is a constructor section then here is a list of the + relocations created to relocate items within it. */ + + struct relent_chain *constructor_chain; + + /* The BFD which owns the section. */ + + bfd *owner; + + boolean reloc_done; + /* A symbol which points at this section only */ + struct symbol_cache_entry *symbol; + struct symbol_cache_entry **symbol_ptr_ptr; + + struct bfd_seclet *seclets_head; + struct bfd_seclet *seclets_tail; +} asection ; + + + /* These sections are global, and are managed by BFD. The application + and target back end are not permitted to change the values in + these sections. */ +#define BFD_ABS_SECTION_NAME "*ABS*" +#define BFD_UND_SECTION_NAME "*UND*" +#define BFD_COM_SECTION_NAME "*COM*" +#define BFD_IND_SECTION_NAME "*IND*" + + /* the absolute section */ +extern asection bfd_abs_section; + /* Pointer to the undefined section */ +extern asection bfd_und_section; + /* Pointer to the common section */ +extern asection bfd_com_section; + /* Pointer to the indirect section */ +extern asection bfd_ind_section; + +extern struct symbol_cache_entry *bfd_abs_symbol; +extern struct symbol_cache_entry *bfd_com_symbol; +extern struct symbol_cache_entry *bfd_und_symbol; +extern struct symbol_cache_entry *bfd_ind_symbol; +#define bfd_get_section_size_before_reloc(section) \ + (section->reloc_done ? (abort(),1): (section)->_raw_size) +#define bfd_get_section_size_after_reloc(section) \ + ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section_old_way PARAMS ((bfd *, CONST char *name)); + +asection * +bfd_make_section_anyway PARAMS ((bfd *, CONST char *name)); + +asection * +bfd_make_section PARAMS ((bfd *, CONST char *name)); + +boolean +bfd_set_section_flags PARAMS ((bfd *, asection *, flagword)); + +void +bfd_map_over_sections PARAMS ((bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj)); + +boolean +bfd_set_section_size PARAMS ((bfd *, asection *, bfd_size_type val)); + +boolean +bfd_set_section_contents + PARAMS ((bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count)); + +boolean +bfd_get_section_contents + PARAMS ((bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count)); + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ + bfd_arch_mips, /* MIPS Rxxxx */ + bfd_arch_i386, /* Intel 386 */ + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ + bfd_arch_alpha, /* Dec Alpha */ + bfd_arch_last + }; + +typedef struct bfd_arch_info +{ + int bits_per_word; + int bits_per_address; + int bits_per_byte; + enum bfd_architecture arch; + long mach; + char *arch_name; + CONST char *printable_name; + unsigned int section_align_power; + /* true if this is the default machine for the architecture */ + boolean the_default; + CONST struct bfd_arch_info * (*compatible) + PARAMS ((CONST struct bfd_arch_info *a, + CONST struct bfd_arch_info *b)); + + boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *)); + /* How to disassemble an instruction, producing a printable + representation on a specified stdio stream. This isn't + defined for most processors at present, because of the size + of the additional tables it would drag in, and because gdb + wants to use a different interface. */ + unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data, + PTR stream)); + + struct bfd_arch_info *next; +} bfd_arch_info_type; +CONST char * +bfd_printable_name PARAMS ((bfd *abfd)); + +bfd_arch_info_type * +bfd_scan_arch PARAMS ((CONST char *)); + +CONST bfd_arch_info_type * +bfd_arch_get_compatible PARAMS (( + CONST bfd *abfd, + CONST bfd *bbfd)); + +void +bfd_set_arch_info PARAMS ((bfd *, bfd_arch_info_type *)); + +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); + +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); + +bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *)); + +bfd_arch_info_type * +bfd_lookup_arch + PARAMS ((enum bfd_architecture + arch, + long machine)); + +CONST char * +bfd_printable_arch_mach + PARAMS ((enum bfd_architecture arch, unsigned long machine)); + +typedef enum bfd_reloc_status +{ + /* No errors detected */ + bfd_reloc_ok, + + /* The relocation was performed, but there was an overflow. */ + bfd_reloc_overflow, + + /* The address to relocate was not within the section supplied. */ + bfd_reloc_outofrange, + + /* Used by special functions */ + bfd_reloc_continue, + + /* Unused */ + bfd_reloc_notsupported, + + /* Unsupported relocation size requested. */ + bfd_reloc_other, + + /* The symbol to relocate against was undefined. */ + bfd_reloc_undefined, + + /* The relocation was performed, but may not be ok - presently + generated only when linking i960 coff files with i960 b.out + symbols. */ + bfd_reloc_dangerous + } + bfd_reloc_status_type; + + +typedef struct reloc_cache_entry +{ + /* A pointer into the canonical table of pointers */ + struct symbol_cache_entry **sym_ptr_ptr; + + /* offset in section */ + bfd_size_type address; + + /* addend for relocation value */ + bfd_vma addend; + + /* Pointer to how to perform the required relocation */ + CONST struct reloc_howto_struct *howto; + +} arelent; +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +typedef CONST struct reloc_howto_struct +{ + /* The type field has mainly a documetary use - the back end can + to what it wants with it, though the normally the back end's + external idea of what a reloc number would be would be stored + in this field. For example, the a PC relative word relocation + in a coff environment would have the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. + 0 : one byte + 1 : two bytes + 2 : four bytes + 3 : nothing done (unless special_function is nonzero) + 4 : eight bytes + -2 : two bytes, result should be subtracted from the + data instead of added + There is currently no trivial way to extract a "number of + bytes" from a howto pointer. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + boolean pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accomodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd)); + + /* The textual name of the relocation type. */ + char *name; + + /* When performing a partial link, some formats must modify the + relocations rather than the data - this flag signals this.*/ + boolean partial_inplace; + + /* The src_mask is used to select what parts of the read in data + are to be used in the relocation sum. E.g., if this was an 8 bit + bit of data which we read and relocated, this would be + 0x000000ff. When we have relocs which have an addend, such as + sun4 extended relocs, the value in the offset part of a + relocating field is garbage so we never use it. In this case + the mask would be 0x00000000. */ + bfd_vma src_mask; + + /* The dst_mask is what parts of the instruction are replaced + into the instruction. In most cases src_mask == dst_mask, + except in the above special case, where dst_mask would be + 0x000000ff, and src_mask would be 0x00000000. */ + bfd_vma dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs), this flag signals the fact.*/ + boolean pcrel_offset; + +} reloc_howto_type; +#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} +#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) + +#define HOWTO_PREPARE(relocation, symbol) \ + { \ + if (symbol != (asymbol *)NULL) { \ + if (bfd_is_com_section (symbol->section)) { \ + relocation = 0; \ + } \ + else { \ + relocation = symbol->value; \ + } \ + } \ +} +typedef unsigned char bfd_byte; + +typedef struct relent_chain { + arelent relent; + struct relent_chain *next; +} arelent_chain; +bfd_reloc_status_type + +bfd_perform_relocation + PARAMS ((bfd * abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd)); + +typedef enum bfd_reloc_code_real +{ + /* Basic absolute relocations */ + BFD_RELOC_64, + BFD_RELOC_32, + BFD_RELOC_16, + BFD_RELOC_8, + + /* PC-relative relocations */ + BFD_RELOC_64_PCREL, + BFD_RELOC_32_PCREL, + BFD_RELOC_24_PCREL, /* used by i960 */ + BFD_RELOC_16_PCREL, + BFD_RELOC_8_PCREL, + + /* Linkage-table relative */ + BFD_RELOC_32_BASEREL, + BFD_RELOC_16_BASEREL, + BFD_RELOC_8_BASEREL, + + /* The type of reloc used to build a contructor table - at the moment + probably a 32 bit wide abs address, but the cpu can choose. */ + BFD_RELOC_CTOR, + + /* 8 bits wide, but used to form an address like 0xffnn */ + BFD_RELOC_8_FFnn, + + /* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit + word displacement, e.g. for SPARC) */ + BFD_RELOC_32_PCREL_S2, + + /* High 22 bits of 32-bit value, placed into lower 22 bits of + target word; simple reloc. */ + BFD_RELOC_HI22, + /* Low 10 bits. */ + BFD_RELOC_LO10, + + /* Reloc types used for i960/b.out. */ + BFD_RELOC_I960_CALLJ, + + /* now for the sparc/elf codes */ + BFD_RELOC_NONE, /* actually used */ + BFD_RELOC_SPARC_WDISP22, + BFD_RELOC_SPARC22, + BFD_RELOC_SPARC13, + BFD_RELOC_SPARC_GOT10, + BFD_RELOC_SPARC_GOT13, + BFD_RELOC_SPARC_GOT22, + BFD_RELOC_SPARC_PC10, + BFD_RELOC_SPARC_PC22, + BFD_RELOC_SPARC_WPLT30, + BFD_RELOC_SPARC_COPY, + BFD_RELOC_SPARC_GLOB_DAT, + BFD_RELOC_SPARC_JMP_SLOT, + BFD_RELOC_SPARC_RELATIVE, + BFD_RELOC_SPARC_UA32, + + /* these are a.out specific? */ + BFD_RELOC_SPARC_BASE13, + BFD_RELOC_SPARC_BASE22, + + + /* Bits 27..2 of the relocation address shifted right 2 bits; + simple reloc otherwise. */ + BFD_RELOC_MIPS_JMP, + + /* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) */ + BFD_RELOC_16_PCREL_S2, + + /* High 16 bits of 32-bit value; simple reloc. */ + BFD_RELOC_HI16, + /* High 16 bits of 32-bit value but the low 16 bits will be sign + extended and added to form the final result. If the low 16 + bits form a negative number, we need to add one to the high value + to compensate for the borrow when the low bits are added. */ + BFD_RELOC_HI16_S, + /* Low 16 bits. */ + BFD_RELOC_LO16, + + /* 16 bit relocation relative to the global pointer. */ + BFD_RELOC_MIPS_GPREL, + + /* These are, so far, specific to HPPA processors. I'm not sure that some + don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL. + Also, many more were in the list I got that don't fit in well in the + model BFD uses, so I've omitted them for now. If we do make this reloc + type get used for code that really does implement the funky reloc types, + they'll have to be added to this list. */ + BFD_RELOC_HPPA_32, + BFD_RELOC_HPPA_11, + BFD_RELOC_HPPA_14, + BFD_RELOC_HPPA_17, + + BFD_RELOC_HPPA_L21, + BFD_RELOC_HPPA_R11, + BFD_RELOC_HPPA_R14, + BFD_RELOC_HPPA_R17, + BFD_RELOC_HPPA_LS21, + BFD_RELOC_HPPA_RS11, + BFD_RELOC_HPPA_RS14, + BFD_RELOC_HPPA_RS17, + BFD_RELOC_HPPA_LD21, + BFD_RELOC_HPPA_RD11, + BFD_RELOC_HPPA_RD14, + BFD_RELOC_HPPA_RD17, + BFD_RELOC_HPPA_LR21, + BFD_RELOC_HPPA_RR14, + BFD_RELOC_HPPA_RR17, + + BFD_RELOC_HPPA_GOTOFF_11, + BFD_RELOC_HPPA_GOTOFF_14, + BFD_RELOC_HPPA_GOTOFF_L21, + BFD_RELOC_HPPA_GOTOFF_R11, + BFD_RELOC_HPPA_GOTOFF_R14, + BFD_RELOC_HPPA_GOTOFF_LS21, + BFD_RELOC_HPPA_GOTOFF_RS11, + BFD_RELOC_HPPA_GOTOFF_RS14, + BFD_RELOC_HPPA_GOTOFF_LD21, + BFD_RELOC_HPPA_GOTOFF_RD11, + BFD_RELOC_HPPA_GOTOFF_RD14, + BFD_RELOC_HPPA_GOTOFF_LR21, + BFD_RELOC_HPPA_GOTOFF_RR14, + + BFD_RELOC_HPPA_DLT_32, + BFD_RELOC_HPPA_DLT_11, + BFD_RELOC_HPPA_DLT_14, + BFD_RELOC_HPPA_DLT_L21, + BFD_RELOC_HPPA_DLT_R11, + BFD_RELOC_HPPA_DLT_R14, + + BFD_RELOC_HPPA_ABS_CALL_11, + BFD_RELOC_HPPA_ABS_CALL_14, + BFD_RELOC_HPPA_ABS_CALL_17, + BFD_RELOC_HPPA_ABS_CALL_L21, + BFD_RELOC_HPPA_ABS_CALL_R11, + BFD_RELOC_HPPA_ABS_CALL_R14, + BFD_RELOC_HPPA_ABS_CALL_R17, + BFD_RELOC_HPPA_ABS_CALL_LS21, + BFD_RELOC_HPPA_ABS_CALL_RS11, + BFD_RELOC_HPPA_ABS_CALL_RS14, + BFD_RELOC_HPPA_ABS_CALL_RS17, + BFD_RELOC_HPPA_ABS_CALL_LD21, + BFD_RELOC_HPPA_ABS_CALL_RD11, + BFD_RELOC_HPPA_ABS_CALL_RD14, + BFD_RELOC_HPPA_ABS_CALL_RD17, + BFD_RELOC_HPPA_ABS_CALL_LR21, + BFD_RELOC_HPPA_ABS_CALL_RR14, + BFD_RELOC_HPPA_ABS_CALL_RR17, + + BFD_RELOC_HPPA_PCREL_CALL_11, + BFD_RELOC_HPPA_PCREL_CALL_12, + BFD_RELOC_HPPA_PCREL_CALL_14, + BFD_RELOC_HPPA_PCREL_CALL_17, + BFD_RELOC_HPPA_PCREL_CALL_L21, + BFD_RELOC_HPPA_PCREL_CALL_R11, + BFD_RELOC_HPPA_PCREL_CALL_R14, + BFD_RELOC_HPPA_PCREL_CALL_R17, + BFD_RELOC_HPPA_PCREL_CALL_LS21, + BFD_RELOC_HPPA_PCREL_CALL_RS11, + BFD_RELOC_HPPA_PCREL_CALL_RS14, + BFD_RELOC_HPPA_PCREL_CALL_RS17, + BFD_RELOC_HPPA_PCREL_CALL_LD21, + BFD_RELOC_HPPA_PCREL_CALL_RD11, + BFD_RELOC_HPPA_PCREL_CALL_RD14, + BFD_RELOC_HPPA_PCREL_CALL_RD17, + BFD_RELOC_HPPA_PCREL_CALL_LR21, + BFD_RELOC_HPPA_PCREL_CALL_RR14, + BFD_RELOC_HPPA_PCREL_CALL_RR17, + + BFD_RELOC_HPPA_PLABEL_32, + BFD_RELOC_HPPA_PLABEL_11, + BFD_RELOC_HPPA_PLABEL_14, + BFD_RELOC_HPPA_PLABEL_L21, + BFD_RELOC_HPPA_PLABEL_R11, + BFD_RELOC_HPPA_PLABEL_R14, + + BFD_RELOC_HPPA_UNWIND_ENTRY, + BFD_RELOC_HPPA_UNWIND_ENTRIES, + + /* i386/elf relocations */ + BFD_RELOC_386_GOT32, + BFD_RELOC_386_PLT32, + BFD_RELOC_386_COPY, + BFD_RELOC_386_GLOB_DAT, + BFD_RELOC_386_JUMP_SLOT, + BFD_RELOC_386_RELATIVE, + BFD_RELOC_386_GOTOFF, + BFD_RELOC_386_GOTPC, + + /* this must be the highest numeric value */ + BFD_RELOC_UNUSED + } bfd_reloc_code_real_type; +CONST struct reloc_howto_struct * + +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + + +typedef struct symbol_cache_entry +{ + /* A pointer to the BFD which owns the symbol. This information + is necessary so that a back end can work out what additional + information (invisible to the application writer) is carried + with the symbol. + + This field is *almost* redundant, since you can use section->owner + instead, except that some symbols point to the global sections + bfd_{abs,com,und}_section. This could be fixed by making + these globals be per-bfd (or per-target-flavor). FIXME. */ + + struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ + + /* The text of the symbol. The name is left alone, and not copied - the + application may not alter it. */ + CONST char *name; + + /* The value of the symbol. This really should be a union of a + numeric value with a pointer, since some flags indicate that + a pointer to another symbol is stored here. */ + symvalue value; + + /* Attributes of a symbol: */ + +#define BSF_NO_FLAGS 0x00 + + /* The symbol has local scope; <> in <>. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in <>. The + value is the offset into the section of the data. */ +#define BSF_GLOBAL 0x02 + + /* The symbol has global scope, and is exported. The value is + the offset into the section of the data. */ +#define BSF_EXPORT BSF_GLOBAL /* no real difference */ + + /* A normal C symbol would be one of: + <>, <>, <> or + <> */ + + /* The symbol is a debugging record. The value has an arbitary + meaning. */ +#define BSF_DEBUGGING 0x08 + + /* The symbol denotes a function entry point. Used in ELF, + perhaps others someday. */ +#define BSF_FUNCTION 0x10 + + /* Used by the linker. */ +#define BSF_KEEP 0x20 +#define BSF_KEEP_G 0x40 + + /* A weak global symbol, overridable without warnings by + a regular global symbol of the same name. */ +#define BSF_WEAK 0x80 + + /* This symbol was created to point to a section, e.g. ELF's + STT_SECTION symbols. */ +#define BSF_SECTION_SYM 0x100 + + /* The symbol used to be a common symbol, but now it is + allocated. */ +#define BSF_OLD_COMMON 0x200 + + /* The default value for common data. */ +#define BFD_FORT_COMM_DEFAULT_VALUE 0 + + /* In some files the type of a symbol sometimes alters its + location in an output file - ie in coff a <> symbol + which is also <> symbol appears where it was + declared and not at the end of a section. This bit is set + by the target BFD part to convey this information. */ + +#define BSF_NOT_AT_END 0x400 + + /* Signal that the symbol is the label of constructor section. */ +#define BSF_CONSTRUCTOR 0x800 + + /* Signal that the symbol is a warning symbol. If the symbol + is a warning symbol, then the value field (I know this is + tacky) will point to the asymbol which when referenced will + cause the warning. */ +#define BSF_WARNING 0x1000 + + /* Signal that the symbol is indirect. The value of the symbol + is a pointer to an undefined asymbol which contains the + name to use instead. */ +#define BSF_INDIRECT 0x2000 + + /* BSF_FILE marks symbols that contain a file name. This is used + for ELF STT_FILE symbols. */ +#define BSF_FILE 0x4000 + + flagword flags; + + /* A pointer to the section to which this symbol is + relative. This will always be non NULL, there are special + sections for undefined and absolute symbols */ + struct sec *section; + + /* Back end special data. This is being phased out in favour + of making this a union. */ + PTR udata; + +} asymbol; +#define get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _get_symtab_upper_bound, (abfd)) +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab,\ + (abfd, location)) +boolean +bfd_set_symtab PARAMS ((bfd *, asymbol **, unsigned int )); + +void +bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol)); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); + +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); + +struct _bfd +{ + /* The filename the application opened the BFD with. */ + CONST char *filename; + + /* A pointer to the target jump table. */ + struct bfd_target *xvec; + + /* To avoid dragging too many header files into every file that + includes `<>', IOSTREAM has been declared as a "char + *", and MTIME as a "long". Their correct types, to which they + are cast when used, are "FILE *" and "time_t". The iostream + is the result of an fopen on the filename. */ + char *iostream; + + /* Is the file being cached */ + + boolean cacheable; + + /* Marks whether there was a default target specified when the + BFD was opened. This is used to select what matching algorithm + to use to chose the back end. */ + + boolean target_defaulted; + + /* The caching routines use these to maintain a + least-recently-used list of BFDs */ + + struct _bfd *lru_prev, *lru_next; + + /* When a file is closed by the caching routines, BFD retains + state information on the file here: + */ + + file_ptr where; + + /* and here:*/ + + boolean opened_once; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time: */ + + boolean mtime_set; + + /* File modified time, if mtime_set is true: */ + + long mtime; + + /* Reserved for an unimplemented file locking extension.*/ + + int ifd; + + /* The format which belongs to the BFD.*/ + + bfd_format format; + + /* The direction the BFD was opened with*/ + + enum bfd_direction {no_direction = 0, + read_direction = 1, + write_direction = 2, + both_direction = 3} direction; + + /* Format_specific flags*/ + + flagword flags; + + /* Currently my_archive is tested before adding origin to + anything. I believe that this can become always an add of + origin, with origin set to 0 for non archive files. */ + + file_ptr origin; + + /* Remember when output has begun, to stop strange things + happening. */ + boolean output_has_begun; + + /* Pointer to linked list of sections*/ + struct sec *sections; + + /* The number of sections */ + unsigned int section_count; + + /* Stuff only useful for object files: + The start address. */ + bfd_vma start_address; + + /* Used for input and output*/ + unsigned int symcount; + + /* Symbol table for output BFD*/ + struct symbol_cache_entry **outsymbols; + + /* Pointer to structure which contains architecture information*/ + struct bfd_arch_info *arch_info; + + /* Stuff only useful for archives:*/ + PTR arelt_data; + struct _bfd *my_archive; + struct _bfd *next; + struct _bfd *archive_head; + boolean has_armap; + + /* Used by the back end to hold private data. */ + + union + { + struct aout_data_struct *aout_data; + struct artdata *aout_ar_data; + struct _oasys_data *oasys_obj_data; + struct _oasys_ar_data *oasys_ar_data; + struct coff_tdata *coff_obj_data; + struct ecoff_tdata *ecoff_obj_data; + struct ieee_data_struct *ieee_data; + struct ieee_ar_data_struct *ieee_ar_data; + struct srec_data_struct *srec_data; + struct tekhex_data_struct *tekhex_data; + struct elf_obj_tdata *elf_obj_data; + struct nlm_obj_tdata *nlm_obj_data; + struct bout_data_struct *bout_data; + struct sun_core_struct *sun_core_data; + struct trad_core_struct *trad_core_data; + struct hppa_data_struct *hppa_data; + struct hpux_core_struct *hpux_core_data; + struct sgi_core_struct *sgi_core_data; + struct lynx_core_struct *lynx_core_data; + struct osf_core_struct *osf_core_data; + PTR any; + } tdata; + + /* Used by the application to hold private data*/ + PTR usrdata; + + /* Where all the allocated stuff under this BFD goes */ + struct obstack memory; + + /* Is this really needed in addition to usrdata? */ + asymbol **ld_symbols; +}; + +unsigned int +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); + +unsigned int +bfd_canonicalize_reloc + PARAMS ((bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms)); + +boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); + +void +bfd_set_reloc + PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count) + + ); + +boolean +bfd_set_start_address PARAMS ((bfd *, bfd_vma)); + +long +bfd_get_mtime PARAMS ((bfd *)); + +long +bfd_get_size PARAMS ((bfd *)); + +int +bfd_get_gp_size PARAMS ((bfd *)); + +void +bfd_set_gp_size PARAMS ((bfd *, int)); + +bfd_vma +bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base)); + +#define bfd_sizeof_headers(abfd, reloc) \ + BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) + +#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ + BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) + + /* Do these three do anything useful at all, for any back end? */ +#define bfd_debug_info_start(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) + +#define bfd_debug_info_end(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) + +#define bfd_debug_info_accumulate(abfd, section) \ + BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) + + +#define bfd_stat_arch_elt(abfd, stat) \ + BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) + +#define bfd_set_arch_mach(abfd, arch, mach)\ + BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) + +#define bfd_get_relocated_section_contents(abfd, seclet, data, relocateable) \ + BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable)) + +#define bfd_relax_section(abfd, section, symbols) \ + BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols)) + +#define bfd_seclet_link(abfd, data, relocateable) \ + BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable)) +symindex +bfd_get_next_mapent PARAMS ((bfd *, symindex previous, carsym ** sym)); + +boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); + +bfd * +bfd_get_elt_at_index PARAMS ((bfd * archive, int index)); + +bfd* +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); + +CONST char * +bfd_core_file_failing_command PARAMS ((bfd *)); + +int +bfd_core_file_failing_signal PARAMS ((bfd *)); + +boolean +core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +#define BFD_SEND(bfd, message, arglist) \ + ((*((bfd)->xvec->message)) arglist) +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) +typedef struct bfd_target +{ + char *name; + enum target_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_hppa_flavour} flavour; + boolean byteorder_big_p; + boolean header_byteorder_big_p; + flagword object_flags; + flagword section_flags; + char symbol_leading_char; + char ar_pad_char; + unsigned short ar_max_namelen; + unsigned int align_power_min; + bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *)); + void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *)); + void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *)); + void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *)); + void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *)); + void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *)); + void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + struct bfd_target * (*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + char * (*_core_file_failing_command) PARAMS ((bfd *)); + int (*_core_file_failing_signal) PARAMS ((bfd *)); + boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); + boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); + void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); + boolean (*write_armap) PARAMS ((bfd *arch, + unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); + boolean (*_close_and_cleanup) PARAMS ((bfd *)); + boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *)); + unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *, + struct symbol_cache_entry **)); + unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); + unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, + struct symbol_cache_entry **)); + struct symbol_cache_entry * + (*_bfd_make_empty_symbol) PARAMS ((bfd *)); + void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, + struct symbol_cache_entry *, + bfd_print_symbol_type)); +#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) + void (*_bfd_get_symbol_info) PARAMS ((bfd *, + struct symbol_cache_entry *, + symbol_info *)); +#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); + + boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); + + bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); + + boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, + struct sec *section, struct symbol_cache_entry **symbols, + bfd_vma offset, CONST char **file, CONST char **func, + unsigned int *line)); + + int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); + + int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); + + void (*_bfd_debug_info_start) PARAMS ((bfd *)); + void (*_bfd_debug_info_end) PARAMS ((bfd *)); + void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *)); + + bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, + struct bfd_seclet *, bfd_byte *data, + boolean relocateable)); + + boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, + struct symbol_cache_entry **)); + + boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data, + boolean relocateable)); + /* See documentation on reloc types. */ + CONST struct reloc_howto_struct * + (*reloc_type_lookup) PARAMS ((bfd *abfd, + bfd_reloc_code_real_type code)); + + /* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + asymbol * (*_bfd_make_debug_symbol) PARAMS (( + bfd *abfd, + void *ptr, + unsigned long size)); + PTR backend_data; +} bfd_target; +bfd_target * +bfd_find_target PARAMS ((CONST char *, bfd *)); + +CONST char ** +bfd_target_list PARAMS ((void)); + +boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); + +boolean +bfd_set_format PARAMS ((bfd *, bfd_format)); + +CONST char * +bfd_format_string PARAMS ((bfd_format)); + +#endif diff --git a/gnu/usr.bin/gdb/bfd/cache.c b/gnu/usr.bin/gdb/bfd/cache.c new file mode 100644 index 00000000000..f8cfd19fed5 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/cache.c @@ -0,0 +1,311 @@ +/* BFD library -- caching of file descriptors. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + File Caching + + The file caching mechanism is embedded within BFD and allows + the application to open as many BFDs as it wants without + regard to the underlying operating system's file descriptor + limit (often as low as 20 open files). The module in + <> maintains a least recently used list of + <> files, and exports the name + <> which runs around and makes sure that + the required BFD is open. If not, then it chooses a file to + close, closes it and opens the one wanted, returning its file + handle. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +INTERNAL_FUNCTION + BFD_CACHE_MAX_OPEN macro + +DESCRIPTION + The maximum number of files which the cache will keep open at + one time. + +.#define BFD_CACHE_MAX_OPEN 10 + +*/ + + +static boolean +bfd_cache_delete PARAMS ((bfd *)); + +/* Number of bfds on the chain. All such bfds have their file open; + if it closed, they get snipd()d from the chain. */ + +static int open_files; + +static bfd *cache_sentinel; /* Chain of BFDs with active fds we've + opened */ + +/* +INTERNAL_FUNCTION + bfd_last_cache + +SYNOPSIS + extern bfd *bfd_last_cache; + +DESCRIPTION + Zero, or a pointer to the topmost BFD on the chain. This is + used by the <> macro in @file{libbfd.h} to + determine when it can avoid a function call. +*/ + +bfd *bfd_last_cache; + +/* + * INTERNAL_FUNCTION + * bfd_cache_lookup + * + * DESCRIPTION + * Checks to see if the required BFD is the same as the last one + * looked up. If so then it can use the iostream in the BFD with + * impunity, since it can't have changed since the last lookup, + * otherwise it has to perform the complicated lookup function + * + * .#define bfd_cache_lookup(x) \ + * . ((x)==bfd_last_cache? \ + * . (FILE*)(bfd_last_cache->iostream): \ + * . bfd_cache_lookup_worker(x)) + * + * + */ + +static void +DEFUN_VOID(close_one) +{ + bfd *kill = cache_sentinel; + if (kill == 0) /* Nothing in the cache */ + return ; + + /* We can only close files that want to play this game. */ + while (!kill->cacheable) { + kill = kill->lru_prev; + if (kill == cache_sentinel) /* Nobody wants to play */ + return ; + } + + kill->where = ftell((FILE *)(kill->iostream)); + (void) bfd_cache_delete(kill); +} + +/* Cuts the BFD abfd out of the chain in the cache */ +static void +DEFUN(snip,(abfd), + bfd *abfd) +{ + abfd->lru_prev->lru_next = abfd->lru_next; + abfd->lru_next->lru_prev = abfd->lru_prev; + if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL; +} + +static boolean +DEFUN(bfd_cache_delete,(abfd), + bfd *abfd) +{ + boolean ret; + + if (fclose ((FILE *)(abfd->iostream)) == 0) + ret = true; + else + { + ret = false; + bfd_error = system_call_error; + } + snip (abfd); + abfd->iostream = NULL; + open_files--; + bfd_last_cache = 0; + return ret; +} + +static bfd * +DEFUN(insert,(x,y), + bfd *x AND + bfd *y) +{ + if (y) { + x->lru_next = y; + x->lru_prev = y->lru_prev; + y->lru_prev->lru_next = x; + y->lru_prev = x; + + } + else { + x->lru_prev = x; + x->lru_next = x; + } + return x; +} + + +/* Initialize a BFD by putting it on the cache LRU. */ + +void +DEFUN(bfd_cache_init,(abfd), + bfd *abfd) +{ + if (open_files >= BFD_CACHE_MAX_OPEN) + close_one (); + cache_sentinel = insert(abfd, cache_sentinel); + ++open_files; +} + + +/* +INTERNAL_FUNCTION + bfd_cache_close + +DESCRIPTION + Remove the BFD from the cache. If the attached file is open, + then close it too. + +SYNOPSIS + boolean bfd_cache_close (bfd *); + +RETURNS + <> is returned if closing the file fails, <> is + returned if all is well. +*/ +boolean +DEFUN(bfd_cache_close,(abfd), + bfd *abfd) +{ + /* If this file is open then remove from the chain */ + if (abfd->iostream) + { + return bfd_cache_delete(abfd); + } + else + { + return true; + } +} + +/* +INTERNAL_FUNCTION + bfd_open_file + +DESCRIPTION + Call the OS to open a file for this BFD. Returns the FILE * + (possibly null) that results from this operation. Sets up the + BFD so that future accesses know the file is open. If the FILE + * returned is null, then there is won't have been put in the + cache, so it won't have to be removed from it. + +SYNOPSIS + FILE* bfd_open_file(bfd *); +*/ + +FILE * +DEFUN(bfd_open_file, (abfd), + bfd *abfd) +{ + abfd->cacheable = true; /* Allow it to be closed later. */ + + if(open_files >= BFD_CACHE_MAX_OPEN) { + close_one(); + } + + switch (abfd->direction) { + case read_direction: + case no_direction: + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RB); + break; + case both_direction: + case write_direction: + if (abfd->opened_once == true) { + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RUB); + if (!abfd->iostream) { + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WUB); + } + } else { + /*open for creat */ + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WB); + abfd->opened_once = true; + } + break; + } + + if (abfd->iostream) { + bfd_cache_init (abfd); + } + + return (FILE *)(abfd->iostream); +} + +/* +INTERNAL_FUNCTION + bfd_cache_lookup_worker + +DESCRIPTION + Called when the macro <> fails to find a + quick answer. Finds a file descriptor for this BFD. If + necessary, it open it. If there are already more than + BFD_CACHE_MAX_OPEN files open, it trys to close one first, to + avoid running out of file descriptors. + +SYNOPSIS + FILE *bfd_cache_lookup_worker(bfd *); + +*/ + +FILE * +DEFUN(bfd_cache_lookup_worker,(abfd), + bfd *abfd) +{ + if (abfd->my_archive) + { + abfd = abfd->my_archive; + } + /* Is this file already open .. if so then quick exit */ + if (abfd->iostream) + { + if (abfd != cache_sentinel) { + /* Place onto head of lru chain */ + snip (abfd); + cache_sentinel = insert(abfd, cache_sentinel); + } + } + /* This is a BFD without a stream - + so it must have been closed or never opened. + find an empty cache entry and use it. */ + else + { + + if (open_files >= BFD_CACHE_MAX_OPEN) + { + close_one(); + } + + BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ; + fseek((FILE *)(abfd->iostream), abfd->where, false); + } + bfd_last_cache = abfd; + return (FILE *)(abfd->iostream); +} diff --git a/gnu/usr.bin/gdb/bfd/coffgen.c b/gnu/usr.bin/gdb/bfd/coffgen.c new file mode 100644 index 00000000000..94cc225d098 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/coffgen.c @@ -0,0 +1,1519 @@ +/* Support for the generic parts of COFF, for BFD. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* Most of this hacked by Steve Chamberlain, sac@cygnus.com. + Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */ + +/* This file contains COFF code that is not dependent on any + particular COFF target. There is only one version of this file in + libbfd.a, so no target specific code may be put in here. Or, to + put it another way, + + ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE ********** + + If you need to add some target specific behaviour, add a new hook + function to bfd_coff_backend_data. + + Some of these functions are also called by the ECOFF routines. + Those functions may not use any COFF specific information, such as + coff_data (abfd). */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "seclet.h" +#include "libcoff.h" + +static asection bfd_debug_section = { "*DEBUG*" }; + +/* Take a section header read from a coff file (in HOST byte order), + and make a BFD "section" out of it. This is used by ECOFF. */ +static boolean +DEFUN(make_a_section_from_file,(abfd, hdr, target_index), + bfd *abfd AND + struct internal_scnhdr *hdr AND + unsigned int target_index) +{ + asection *return_section; + char *name; + + /* Assorted wastage to null-terminate the name, thanks AT&T! */ + name = bfd_alloc(abfd, sizeof (hdr->s_name)+1); + if (name == NULL) { + bfd_error = no_memory; + return false; + } + strncpy(name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); + name[sizeof (hdr->s_name)] = 0; + + return_section = bfd_make_section(abfd, name); + if (return_section == NULL) + return_section = bfd_coff_make_section_hook (abfd, name); + + /* Handle several sections of the same name. For example, if an executable + has two .bss sections, GDB better be able to find both of them + (PR 3562). */ + if (return_section == NULL) + return_section = bfd_make_section_anyway (abfd, name); + + if (return_section == NULL) + return false; + + /* s_paddr is presumed to be = to s_vaddr */ + + return_section->vma = hdr->s_vaddr; + return_section->_raw_size = hdr->s_size; + return_section->filepos = hdr->s_scnptr; + return_section->rel_filepos = hdr->s_relptr; + return_section->reloc_count = hdr->s_nreloc; + + bfd_coff_set_alignment_hook (abfd, return_section, hdr); + + return_section->line_filepos = hdr->s_lnnoptr; + + return_section->lineno_count = hdr->s_nlnno; + return_section->userdata = NULL; + return_section->next = (asection *) NULL; + return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr); + + return_section->target_index = target_index; + + /* At least on i386-coff, the line number count for a shared library + section must be ignored. */ + if ((return_section->flags & SEC_SHARED_LIBRARY) != 0) + return_section->lineno_count = 0; + + if (hdr->s_nreloc != 0) + return_section->flags |= SEC_RELOC; + /* FIXME: should this check 'hdr->s_size > 0' */ + if (hdr->s_scnptr != 0) + return_section->flags |= SEC_HAS_CONTENTS; + return true; +} + +/* Read in a COFF object and make it into a BFD. This is used by + ECOFF as well. */ + +static +bfd_target * +DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a), + bfd *abfd AND + unsigned nscns AND + struct internal_filehdr *internal_f AND + struct internal_aouthdr *internal_a) +{ + PTR tdata; + size_t readsize; /* length of file_info */ + unsigned int scnhsz; + char *external_sections; + + /* Build a play area */ + tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a); + if (tdata == NULL) + return 0; + + scnhsz = bfd_coff_scnhsz (abfd); + readsize = nscns * scnhsz; + external_sections = (char *)bfd_alloc(abfd, readsize); + + if (bfd_read((PTR)external_sections, 1, readsize, abfd) != readsize) { + goto fail; + } + + /* Now copy data as required; construct all asections etc */ + if (nscns != 0) { + unsigned int i; + for (i = 0; i < nscns; i++) { + struct internal_scnhdr tmp; + bfd_coff_swap_scnhdr_in(abfd, (PTR) (external_sections + i * scnhsz), + (PTR) &tmp); + make_a_section_from_file(abfd,&tmp, i+1); + } + } + +/* make_abs_section(abfd);*/ + + if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false) + goto fail; + + if (!(internal_f->f_flags & F_RELFLG)) + abfd->flags |= HAS_RELOC; + if ((internal_f->f_flags & F_EXEC)) + abfd->flags |= EXEC_P; + if (!(internal_f->f_flags & F_LNNO)) + abfd->flags |= HAS_LINENO; + if (!(internal_f->f_flags & F_LSYMS)) + abfd->flags |= HAS_LOCALS; + + + bfd_get_symcount(abfd) = internal_f->f_nsyms; + if (internal_f->f_nsyms) + abfd->flags |= HAS_SYMS; + + if (internal_a != (struct internal_aouthdr *) NULL) + bfd_get_start_address (abfd) = internal_a->entry; + else + bfd_get_start_address (abfd) = 0; + + return abfd->xvec; + fail: + bfd_release(abfd, tdata); + return (bfd_target *)NULL; +} + +/* Turn a COFF file into a BFD, but fail with wrong_format if it is + not a COFF file. This is also used by ECOFF. */ + +bfd_target * +DEFUN(coff_object_p,(abfd), + bfd *abfd) +{ + unsigned int filhsz; + unsigned int aoutsz; + int nscns; + PTR filehdr; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + bfd_error = system_call_error; + + /* figure out how much to read */ + filhsz = bfd_coff_filhsz (abfd); + aoutsz = bfd_coff_aoutsz (abfd); + + filehdr = bfd_alloc (abfd, filhsz); + if (filehdr == NULL) + return 0; + if (bfd_read(filehdr, 1, filhsz, abfd) != filhsz) + return 0; + bfd_coff_swap_filehdr_in(abfd, filehdr, &internal_f); + bfd_release (abfd, filehdr); + + if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) { + bfd_error = wrong_format; + return 0; + } + nscns =internal_f.f_nscns; + + if (internal_f.f_opthdr) { + PTR opthdr; + + opthdr = bfd_alloc (abfd, aoutsz); + if (opthdr == NULL) + return 0;; + if (bfd_read(opthdr, 1,aoutsz, abfd) != aoutsz) { + return 0; + } + bfd_coff_swap_aouthdr_in(abfd, opthdr, (PTR)&internal_a); + } + + /* Seek past the opt hdr stuff */ + bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET); + + return coff_real_object_p(abfd, nscns, &internal_f, + (internal_f.f_opthdr != 0 + ? &internal_a + : (struct internal_aouthdr *) NULL)); +} + +/* Get the BFD section from a COFF symbol section number. */ + +struct sec * +DEFUN(coff_section_from_bfd_index,(abfd, index), + bfd *abfd AND + int index) +{ + struct sec *answer = abfd->sections; + + if (index == N_ABS) + { + return &bfd_abs_section; + } + if (index == N_UNDEF) + { + return &bfd_und_section; + } + if(index == N_DEBUG) + { + return &bfd_debug_section; + + } + + while (answer) { + if (answer->target_index == index) + return answer; + answer = answer->next; + } + BFD_ASSERT(0); + return &bfd_und_section; /* For gcc -W and lint. Never executed. */ +} + +/* Get the upper bound of a COFF symbol table. */ + +unsigned int +coff_get_symtab_upper_bound(abfd) +bfd *abfd; +{ + if (!bfd_coff_slurp_symbol_table(abfd)) + return 0; + + return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *)); +} + + +/* Canonicalize a COFF symbol table. */ + +unsigned int +DEFUN(coff_get_symtab, (abfd, alocation), + bfd *abfd AND + asymbol **alocation) +{ + unsigned int counter = 0; + coff_symbol_type *symbase; + coff_symbol_type **location = (coff_symbol_type **) (alocation); + if (!bfd_coff_slurp_symbol_table(abfd)) + return 0; + + symbase = obj_symbols(abfd); + while (counter < bfd_get_symcount(abfd)) + { + /* This nasty code looks at the symbol to decide whether or + not it is descibes a constructor/destructor entry point. It + is structured this way to (hopefully) speed non matches */ +#if 0 + if (0 && symbase->symbol.name[9] == '$') + { + bfd_constructor_entry(abfd, + (asymbol **)location, + symbase->symbol.name[10] == 'I' ? + "CTOR" : "DTOR"); + } +#endif + *(location++) = symbase++; + counter++; + } + *location++ = 0; + return bfd_get_symcount(abfd); +} + +/* Set lineno_count for the output sections of a COFF file. */ + +int +DEFUN(coff_count_linenumbers,(abfd), + bfd *abfd) +{ + unsigned int limit = bfd_get_symcount(abfd); + unsigned int i; + int total = 0; + asymbol **p; + { + asection *s = abfd->sections->output_section; + while (s) { + BFD_ASSERT(s->lineno_count == 0); + s = s->next; + } + } + + + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { + asymbol *q_maybe = *p; + if (bfd_asymbol_flavour(q_maybe) == bfd_target_coff_flavour) { + coff_symbol_type *q = coffsymbol(q_maybe); + if (q->lineno) { + /* + This symbol has a linenumber, increment the owning + section's linenumber count + */ + alent *l = q->lineno; + q->symbol.section->output_section->lineno_count++; + total ++; + l++; + while (l->line_number) { + total ++; + q->symbol.section->output_section->lineno_count++; + l++; + } + } + } + } + return total; +} + +/* Takes a bfd and a symbol, returns a pointer to the coff specific + area of the symbol if there is one. */ + +coff_symbol_type * +DEFUN(coff_symbol_from,(ignore_abfd, symbol), + bfd *ignore_abfd AND + asymbol *symbol) +{ + if (bfd_asymbol_flavour(symbol) != bfd_target_coff_flavour) + return (coff_symbol_type *)NULL; + + if (bfd_asymbol_bfd(symbol)->tdata.coff_obj_data == (coff_data_type*)NULL) + return (coff_symbol_type *)NULL; + + return (coff_symbol_type *) symbol; +} + +static void +DEFUN(fixup_symbol_value,(coff_symbol_ptr, syment), +coff_symbol_type *coff_symbol_ptr AND +struct internal_syment *syment) +{ + + /* Normalize the symbol flags */ + if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) { + /* a common symbol is undefined with a value */ + syment->n_scnum = N_UNDEF; + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) { + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.section == & bfd_und_section) { + syment->n_scnum = N_UNDEF; + syment->n_value = 0; + } + else { + if (coff_symbol_ptr->symbol.section) { + syment->n_scnum = + coff_symbol_ptr->symbol.section->output_section->target_index; + + syment->n_value = + coff_symbol_ptr->symbol.value + + coff_symbol_ptr->symbol.section->output_offset + + coff_symbol_ptr->symbol.section->output_section->vma; + } + else { + BFD_ASSERT(0); + /* This can happen, but I don't know why yet (steve@cygnus.com) */ + syment->n_scnum = N_ABS; + syment->n_value = coff_symbol_ptr->symbol.value; + } + } +} + +/* run through all the symbols in the symbol table and work out what + their indexes into the symbol table will be when output + + Coff requires that each C_FILE symbol points to the next one in the + chain, and that the last one points to the first external symbol. We + do that here too. + +*/ +void +DEFUN(coff_renumber_symbols,(bfd_ptr), + bfd *bfd_ptr) +{ + unsigned int symbol_count = bfd_get_symcount(bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int native_index = 0; + struct internal_syment *last_file = (struct internal_syment *)NULL; + unsigned int symbol_index; + + /* COFF demands that undefined symbols come after all other symbols. + Since we don't need to impose this extra knowledge on all our client + programs, deal with that here. Sort the symbol table; just move the + undefined symbols to the end, leaving the rest alone. */ + /* @@ Do we have some condition we could test for, so we don't always + have to do this? I don't think relocatability is quite right, but + I'm not certain. [raeburn:19920508.1711EST] */ + { + asymbol **newsyms; + int i; + + newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr, + sizeof (asymbol *) + * (symbol_count + 1)); + bfd_ptr->outsymbols = newsyms; + for (i = 0; i < symbol_count; i++) + if (symbol_ptr_ptr[i]->section != &bfd_und_section) + *newsyms++ = symbol_ptr_ptr[i]; + for (i = 0; i < symbol_count; i++) + if (symbol_ptr_ptr[i]->section == &bfd_und_section) + *newsyms++ = symbol_ptr_ptr[i]; + *newsyms = (asymbol *) NULL; + symbol_ptr_ptr = bfd_ptr->outsymbols; + } + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]); + if (coff_symbol_ptr && coff_symbol_ptr->native) { + combined_entry_type *s = coff_symbol_ptr->native; + int i; + + if (s->u.syment.n_sclass == C_FILE) + { + if (last_file != (struct internal_syment *)NULL) { + last_file->n_value = native_index; + } + last_file = &(s->u.syment); + } + else { + + /* Modify the symbol values according to their section and + type */ + + fixup_symbol_value(coff_symbol_ptr, &(s->u.syment)); + } + for (i = 0; i < s->u.syment.n_numaux + 1; i++) { + s[i].offset = native_index ++; + } + } + else { + native_index++; + } + } + obj_conv_table_size (bfd_ptr) = native_index; +} + +/* + Run thorough the symbol table again, and fix it so that all pointers to + entries are changed to the entries' index in the output symbol table. + +*/ +void +DEFUN(coff_mangle_symbols,(bfd_ptr), + bfd *bfd_ptr) +{ + unsigned int symbol_count = bfd_get_symcount(bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int symbol_index; + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = + coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]); + + if (coff_symbol_ptr && coff_symbol_ptr->native) { + int i; + combined_entry_type *s = coff_symbol_ptr->native; + + for (i = 0; i < s->u.syment.n_numaux ; i++) { + combined_entry_type *a = s + i + 1; + if (a->fix_tag) { + a->u.auxent.x_sym.x_tagndx.l = + a->u.auxent.x_sym.x_tagndx.p->offset; + a->fix_tag = 0; + } + if (a->fix_end) { + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l = + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset; + a->fix_end = 0; + + } + + } + } + } +} + +static int string_size; + +static void +DEFUN(coff_fix_symbol_name,(abfd, symbol, native), + bfd *abfd AND + asymbol *symbol AND + combined_entry_type *native) +{ + unsigned int name_length; + union internal_auxent *auxent; + char * name = ( char *)(symbol->name); + + if (name == (char *) NULL) { + /* coff symbols always have names, so we'll make one up */ + symbol->name = "strange"; + name = (char *)symbol->name; + } + name_length = strlen(name); + + if (native->u.syment.n_sclass == C_FILE) { + strncpy(native->u.syment._n._n_name, ".file", SYMNMLEN); + auxent = &(native+1)->u.auxent; + + if (bfd_coff_long_filenames (abfd)) { + if (name_length <= FILNMLEN) { + strncpy(auxent->x_file.x_fname, name, FILNMLEN); + } + else { + auxent->x_file.x_n.x_offset = string_size + 4; + auxent->x_file.x_n.x_zeroes = 0; + string_size += name_length + 1; + } + } + else { + strncpy(auxent->x_file.x_fname, name, FILNMLEN); + if (name_length > FILNMLEN) { + name[FILNMLEN] = '\0'; + } + } + } + else + { /* NOT A C_FILE SYMBOL */ + if (name_length <= SYMNMLEN) { + /* This name will fit into the symbol neatly */ + strncpy(native->u.syment._n._n_name, symbol->name, SYMNMLEN); + } + else { + native->u.syment._n._n_n._n_offset = string_size + 4; + native->u.syment._n._n_n._n_zeroes = 0; + string_size += name_length + 1; + } + } +} + +#define set_index(symbol, idx) ((symbol)->udata =(PTR) (idx)) + +static unsigned int +DEFUN(coff_write_symbol,(abfd, symbol, native, written), +bfd *abfd AND +asymbol *symbol AND +combined_entry_type *native AND +unsigned int written) +{ + unsigned int numaux = native->u.syment.n_numaux; + int type = native->u.syment.n_type; + int class = native->u.syment.n_sclass; + PTR buf; + bfd_size_type symesz; + + /* @@ bfd_debug_section isn't accessible outside this file, but we know + that C_FILE symbols belong there. So move them. */ + if (native->u.syment.n_sclass == C_FILE) + symbol->section = &bfd_debug_section; + + if (symbol->section == &bfd_abs_section) + { + native->u.syment.n_scnum = N_ABS; + } + else if (symbol->section == &bfd_debug_section) + { + native->u.syment.n_scnum = N_DEBUG; + } + else if (symbol->section == &bfd_und_section) + { + native->u.syment.n_scnum = N_UNDEF; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + } + + + coff_fix_symbol_name(abfd, symbol, native); + + symesz = bfd_coff_symesz (abfd); + buf = bfd_alloc (abfd, symesz); + bfd_coff_swap_sym_out(abfd, &native->u.syment, buf); + bfd_write(buf, 1, symesz, abfd); + bfd_release (abfd, buf); + + if (native->u.syment.n_numaux > 0) + { + bfd_size_type auxesz; + unsigned int j; + + auxesz = bfd_coff_auxesz (abfd); + buf = bfd_alloc (abfd, auxesz); + for (j = 0; j < native->u.syment.n_numaux; j++) + { + bfd_coff_swap_aux_out(abfd, + &((native + j + 1)->u.auxent), + type, + class, + buf); + bfd_write(buf, 1, auxesz, abfd); + } + bfd_release (abfd, buf); + } + /* + Reuse somewhere in the symbol to keep the index + */ + set_index(symbol, written); + return written + 1 + numaux; +} + + +static unsigned int +DEFUN(coff_write_alien_symbol,(abfd, symbol, written), + bfd *abfd AND + asymbol *symbol AND + unsigned int written) +{ + /* + This symbol has been created by the loader, or come from a non + coff format. It has no native element to inherit, make our + own + */ + combined_entry_type *native; + combined_entry_type dummy; + native = &dummy; + native->u.syment.n_type = T_NULL; + native->u.syment.n_flags = 0; + if (symbol->section == &bfd_und_section) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (bfd_is_com_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + + } + + else if (symbol->flags & BSF_DEBUGGING) { + /* + remove name so it doesn't take up any space + */ + symbol->name = ""; + } + else { + native->u.syment.n_scnum = symbol->section->output_section->target_index; + native->u.syment.n_value = symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset; + /* Copy the any flags from the the file hdr into the symbol */ + { + coff_symbol_type *c = coff_symbol_from(abfd, symbol); + if (c != (coff_symbol_type *)NULL) { + native->u.syment.n_flags = bfd_asymbol_bfd(&c->symbol)->flags; + } + } + } + + native->u.syment.n_type = 0; + if (symbol->flags & BSF_LOCAL) + native->u.syment.n_sclass = C_STAT; + else + native->u.syment.n_sclass = C_EXT; + native->u.syment.n_numaux = 0; + + return coff_write_symbol(abfd, symbol, native, written); +} + +static unsigned int +DEFUN(coff_write_native_symbol,(abfd, symbol, written), +bfd *abfd AND +coff_symbol_type *symbol AND +unsigned int written) +{ + /* + Does this symbol have an ascociated line number - if so then + make it remember this symbol index. Also tag the auxent of + this symbol to point to the right place in the lineno table + */ + combined_entry_type *native = symbol->native; + + alent *lineno = symbol->lineno; + + if (lineno && !symbol->done_lineno) { + unsigned int count = 0; + lineno[count].u.offset = written; + if (native->u.syment.n_numaux) { + union internal_auxent *a = &((native+1)->u.auxent); + + a->x_sym.x_fcnary.x_fcn.x_lnnoptr = + symbol->symbol.section->output_section->moving_line_filepos; + } + /* + And count and relocate all other linenumbers + */ + + count++; + while (lineno[count].line_number) { +#if 0 +/* 13 april 92. sac +I've been told this, but still need proof: +> The second bug is also in `bfd/coffcode.h'. This bug causes the linker to screw +> up the pc-relocations for all the line numbers in COFF code. This bug isn't +> only specific to A29K implementations, but affects all systems using COFF +> format binaries. Note that in COFF object files, the line number core offsets +> output by the assembler are relative to the start of each procedure, not +> to the start of the .text section. This patch relocates the line numbers +> relative to the `native->u.syment.n_value' instead of the section virtual +> address. modular!olson@cs.arizona.edu (Jon Olson) +*/ + lineno[count].u.offset += native->u.syment.n_value; + +#else + lineno[count].u.offset += + symbol->symbol.section->output_section->vma + + symbol->symbol.section->output_offset; +#endif + count++; + } + symbol->done_lineno = true; + + symbol->symbol.section->output_section->moving_line_filepos += + count * bfd_coff_linesz (abfd); + } + return coff_write_symbol(abfd, &( symbol->symbol), native,written); +} + +void +DEFUN(coff_write_symbols,(abfd), + bfd *abfd) +{ + unsigned int i; + unsigned int limit = bfd_get_symcount(abfd); + unsigned int written = 0; + + asymbol **p; + + string_size = 0; + + + /* Seek to the right place */ + bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET); + + /* Output all the symbols we have */ + + written = 0; + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *symbol = *p; + coff_symbol_type *c_symbol = coff_symbol_from(abfd, symbol); + + if (c_symbol == (coff_symbol_type *) NULL || + c_symbol->native == (combined_entry_type *)NULL) + { + written = coff_write_alien_symbol(abfd, symbol, written); + } + else + { + written = coff_write_native_symbol(abfd, c_symbol, written); + } + + } + + bfd_get_symcount(abfd) = written; + + /* Now write out strings */ + + if (string_size != 0) + { + unsigned int size = string_size + 4; + bfd_byte buffer[4]; + + bfd_h_put_32(abfd, size, buffer); + bfd_write((PTR) buffer, 1, sizeof(buffer), abfd); + for (p = abfd->outsymbols, i = 0; + i < limit; + i++, p++) + { + asymbol *q = *p; + size_t name_length = strlen(q->name); + int maxlen; + coff_symbol_type* c_symbol = coff_symbol_from(abfd, q); + maxlen = ((c_symbol != NULL && c_symbol->native != NULL) && + (c_symbol->native->u.syment.n_sclass == C_FILE)) ? + FILNMLEN : SYMNMLEN; + + if (name_length > maxlen) { + bfd_write((PTR) (q->name), 1, name_length + 1, abfd); + } + } + } + else { + /* We would normally not write anything here, but we'll write + out 4 so that any stupid coff reader which tries to read + the string table even when there isn't one won't croak. */ + unsigned int size = 4; + bfd_byte buffer[4]; + + bfd_h_put_32 (abfd, size, buffer); + bfd_write((PTR) buffer, 1, sizeof (buffer), abfd); + } +} + +void +DEFUN(coff_write_linenumbers,(abfd), + bfd *abfd) +{ + asection *s; + bfd_size_type linesz; + PTR buff; + + linesz = bfd_coff_linesz (abfd); + buff = bfd_alloc (abfd, linesz); + for (s = abfd->sections; s != (asection *) NULL; s = s->next) { + if (s->lineno_count) { + asymbol **q = abfd->outsymbols; + bfd_seek(abfd, s->line_filepos, SEEK_SET); + /* Find all the linenumbers in this section */ + while (*q) { + asymbol *p = *q; + if (p->section->output_section == s) { + alent *l = + BFD_SEND(bfd_asymbol_bfd(p), _get_lineno, (bfd_asymbol_bfd(p), p)); + if (l) { + /* Found a linenumber entry, output */ + struct internal_lineno out; + memset( (PTR)&out, 0, sizeof(out)); + out.l_lnno = 0; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out(abfd, &out, buff); + bfd_write(buff, 1, linesz, abfd); + l++; + while (l->line_number) { + out.l_lnno = l->line_number; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out(abfd, &out, buff); + bfd_write(buff, 1, linesz, abfd); + l++; + } + } + } + q++; + } + } + } + bfd_release (abfd, buff); +} + +alent * +DEFUN(coff_get_lineno,(ignore_abfd, symbol), + bfd *ignore_abfd AND + asymbol *symbol) +{ + return coffsymbol(symbol)->lineno; +} + +asymbol * +coff_section_symbol (abfd, name) + bfd *abfd; + char *name; +{ + asection *sec = bfd_make_section_old_way (abfd, name); + asymbol *sym; + combined_entry_type *csym; + + sym = sec->symbol; + csym = coff_symbol_from (abfd, sym)->native; + /* Make sure back-end COFF stuff is there. */ + if (csym == 0) + { + struct foo { + coff_symbol_type sym; + /* @@FIXME This shouldn't use a fixed size!! */ + combined_entry_type e[10]; + }; + struct foo *f; + f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f)); + memset ((char *) f, 0, sizeof (*f)); + coff_symbol_from (abfd, sym)->native = csym = f->e; + } + csym[0].u.syment.n_sclass = C_STAT; + csym[0].u.syment.n_numaux = 1; +/* SF_SET_STATICS (sym); @@ ??? */ + csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size; + csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count; + csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count; + + if (sec->output_section == NULL) + { + sec->output_section = sec; + sec->output_offset = 0; + } + + return sym; +} + +/* This function transforms the offsets into the symbol table into + pointers to syments. */ + +static void +DEFUN(coff_pointerize_aux,(abfd, table_base, type, class, auxent), +bfd *abfd AND +combined_entry_type *table_base AND +int type AND +int class AND +combined_entry_type *auxent) +{ + /* Don't bother if this is a file or a section */ + if (class == C_STAT && type == T_NULL) return; + if (class == C_FILE) return; + + /* Otherwise patch up */ +#define N_TMASK coff_data (abfd)->local_n_tmask +#define N_BTSHFT coff_data (abfd)->local_n_btshft + if (ISFCN(type) || ISTAG(class) || class == C_BLOCK) { + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base + + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; + auxent->fix_end = 1; + } + /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can + generate one, so we must be careful to ignore it. */ + if (auxent->u.auxent.x_sym.x_tagndx.l > 0) { + auxent->u.auxent.x_sym.x_tagndx.p = + table_base + auxent->u.auxent.x_sym.x_tagndx.l; + auxent->fix_tag = 1; + } +} + +static char * +DEFUN(build_string_table,(abfd), +bfd *abfd) +{ + char string_table_size_buffer[4]; + unsigned int string_table_size; + char *string_table; + + /* At this point we should be "seek"'d to the end of the + symbols === the symbol table size. */ + if (bfd_read((char *) string_table_size_buffer, + sizeof(string_table_size_buffer), + 1, abfd) != sizeof(string_table_size)) { + bfd_error = system_call_error; + return (NULL); + } /* on error */ + + string_table_size = bfd_h_get_32(abfd, (bfd_byte *) string_table_size_buffer); + + if ((string_table = (PTR) bfd_alloc(abfd, string_table_size -= 4)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on mallocation error */ + if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) { + bfd_error = system_call_error; + return (NULL); + } + return string_table; +} + +/* Allocate space for the ".debug" section, and read it. + We did not read the debug section until now, because + we didn't want to go to the trouble until someone needed it. */ + +static char * +DEFUN(build_debug_section,(abfd), + bfd *abfd) +{ + char *debug_section; + long position; + + asection *sect = bfd_get_section_by_name (abfd, ".debug"); + + if (!sect) { + bfd_error = no_debug_section; + return NULL; + } + + debug_section = (PTR) bfd_alloc (abfd, + bfd_get_section_size_before_reloc (sect)); + if (debug_section == NULL) { + bfd_error = no_memory; + return NULL; + } + + /* Seek to the beginning of the `.debug' section and read it. + Save the current position first; it is needed by our caller. + Then read debug section and reset the file pointer. */ + + position = bfd_tell (abfd); + bfd_seek (abfd, sect->filepos, SEEK_SET); + if (bfd_read (debug_section, + bfd_get_section_size_before_reloc (sect), 1, abfd) + != bfd_get_section_size_before_reloc(sect)) { + bfd_error = system_call_error; + return NULL; + } + bfd_seek (abfd, position, SEEK_SET); + return debug_section; +} + + +/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be + \0-terminated, but will not exceed 'maxlen' characters. The copy *will* + be \0-terminated. */ +static char * +DEFUN(copy_name,(abfd, name, maxlen), + bfd *abfd AND + char *name AND + int maxlen) +{ + int len; + char *newname; + + for (len = 0; len < maxlen; ++len) { + if (name[len] == '\0') { + break; + } + } + + if ((newname = (PTR) bfd_alloc(abfd, len+1)) == NULL) { + bfd_error = no_memory; + return (NULL); + } + strncpy(newname, name, len); + newname[len] = '\0'; + return newname; +} + +/* Read a symbol table into freshly bfd_allocated memory, swap it, and + knit the symbol names into a normalized form. By normalized here I + mean that all symbols have an n_offset pointer that points to a null- + terminated string. */ + +combined_entry_type * +DEFUN(coff_get_normalized_symtab,(abfd), +bfd *abfd) +{ + combined_entry_type *internal; + combined_entry_type *internal_ptr; + combined_entry_type *symbol_ptr; + combined_entry_type *internal_end; + bfd_size_type symesz; + PTR raw; + char *raw_src; + char *raw_end; + char *string_table = NULL; + char *debug_section = NULL; + unsigned long size; + + unsigned int raw_size; + if (obj_raw_syments(abfd) != (combined_entry_type *)NULL) { + return obj_raw_syments(abfd); + } + if ((size = bfd_get_symcount(abfd) * sizeof(combined_entry_type)) == 0) { + bfd_error = no_symbols; + return (NULL); + } + + internal = (combined_entry_type *)bfd_alloc(abfd, size); + internal_end = internal + bfd_get_symcount(abfd); + + symesz = bfd_coff_symesz (abfd); + raw_size = bfd_get_symcount(abfd) * symesz; + raw = bfd_alloc(abfd,raw_size); + + if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1 + || bfd_read(raw, raw_size, 1, abfd) != raw_size) { + bfd_error = system_call_error; + return (NULL); + } + /* mark the end of the symbols */ + raw_end = (char *) raw + bfd_get_symcount(abfd) * symesz; + /* + FIXME SOMEDAY. A string table size of zero is very weird, but + probably possible. If one shows up, it will probably kill us. + */ + + /* Swap all the raw entries */ + for (raw_src = (char *) raw, internal_ptr = internal; + raw_src < raw_end; + raw_src += symesz, internal_ptr++) { + + unsigned int i; + bfd_coff_swap_sym_in(abfd, (PTR)raw_src, (PTR)&internal_ptr->u.syment); + internal_ptr->fix_tag = 0; + internal_ptr->fix_end = 0; + symbol_ptr = internal_ptr; + + for (i = 0; + i < symbol_ptr->u.syment.n_numaux; + i++) + { + internal_ptr++; + raw_src += symesz; + + internal_ptr->fix_tag = 0; + internal_ptr->fix_end = 0; + bfd_coff_swap_aux_in(abfd, (PTR) raw_src, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + &(internal_ptr->u.auxent)); + /* Remember that bal entries arn't pointerized */ + if (i != 1 || symbol_ptr->u.syment.n_sclass != C_LEAFPROC) + { + + coff_pointerize_aux(abfd, + internal, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + internal_ptr); + } + + } + } + + /* Free all the raw stuff */ + bfd_release(abfd, raw); + + for (internal_ptr = internal; internal_ptr < internal_end; + internal_ptr ++) + { + if (internal_ptr->u.syment.n_sclass == C_FILE) { + /* make a file symbol point to the name in the auxent, since + the text ".file" is redundant */ + if ((internal_ptr+1)->u.auxent.x_file.x_n.x_zeroes == 0) { + /* the filename is a long one, point into the string table */ + if (string_table == NULL) { + string_table = build_string_table(abfd); + } + + internal_ptr->u.syment._n._n_n._n_offset = + (long) (string_table - 4 + + (internal_ptr+1)->u.auxent.x_file.x_n.x_offset); + } + else { + /* ordinary short filename, put into memory anyway */ + internal_ptr->u.syment._n._n_n._n_offset = (long) + copy_name(abfd, (internal_ptr+1)->u.auxent.x_file.x_fname, + FILNMLEN); + } + } + else { + if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) { + /* This is a "short" name. Make it long. */ + unsigned long i = 0; + char *newstring = NULL; + + /* find the length of this string without walking into memory + that isn't ours. */ + for (i = 0; i < 8; ++i) { + if (internal_ptr->u.syment._n._n_name[i] == '\0') { + break; + } /* if end of string */ + } /* possible lengths of this string. */ + + if ((newstring = (PTR) bfd_alloc(abfd, ++i)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + memset(newstring, 0, i); + strncpy(newstring, internal_ptr->u.syment._n._n_name, i-1); + internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring; + internal_ptr->u.syment._n._n_n._n_zeroes = 0; + } + else if (!bfd_coff_symname_in_debug(abfd, &internal_ptr->u.syment)) { + /* Long name already. Point symbol at the string in the table. */ + if (string_table == NULL) { + string_table = build_string_table(abfd); + } + internal_ptr->u.syment._n._n_n._n_offset = (long int) + (string_table - 4 + internal_ptr->u.syment._n._n_n._n_offset); + } + else { + /* Long name in debug section. Very similar. */ + if (debug_section == NULL) { + debug_section = build_debug_section(abfd); + } + internal_ptr->u.syment._n._n_n._n_offset = (long int) + (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + } + } + internal_ptr += internal_ptr->u.syment.n_numaux; + } + + obj_raw_syments(abfd) = internal; + obj_raw_syment_count(abfd) = internal_ptr - internal; + + return (internal); +} /* coff_get_normalized_symtab() */ + +unsigned int +DEFUN (coff_get_reloc_upper_bound, (abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (bfd_get_format(abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + return (asect->reloc_count + 1) * sizeof(arelent *); +} + +asymbol * +DEFUN (coff_make_empty_symbol, (abfd), + bfd *abfd) +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + new->symbol.section = 0; + new->native = 0; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Make a debugging symbol. */ + +asymbol * +coff_bfd_make_debug_symbol (abfd, ptr, sz) + bfd *abfd; + PTR ptr; + unsigned long sz; +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + /* @@ This shouldn't be using a constant multiplier. */ + new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10); + new->symbol.section = &bfd_debug_section; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +void +coff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Print out information about COFF symbol. */ + +void +coff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + + case bfd_print_symbol_more: + fprintf (file, "coff %s %s", + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " "); + break; + + case bfd_print_symbol_all: + if (coffsymbol(symbol)->native) + { + unsigned int aux; + combined_entry_type *combined = coffsymbol (symbol)->native; + combined_entry_type *root = obj_raw_syments (abfd); + struct lineno_cache_entry *l = coffsymbol(symbol)->lineno; + + fprintf (file,"[%3d]", combined - root); + + fprintf (file, + "(sc %2d)(fl 0x%02x)(ty %3x)(sc %3d) (nx %d) 0x%08x %s", + combined->u.syment.n_scnum, + combined->u.syment.n_flags, + combined->u.syment.n_type, + combined->u.syment.n_sclass, + combined->u.syment.n_numaux, + combined->u.syment.n_value, + symbol->name); + + for (aux = 0; aux < combined->u.syment.n_numaux; aux++) + { + combined_entry_type *auxp = combined + aux + 1; + long tagndx; + + if (auxp->fix_tag) + tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; + else + tagndx = auxp->u.auxent.x_sym.x_tagndx.l; + + fprintf (file, "\n"); + switch (combined->u.syment.n_sclass) + { + case C_FILE: + fprintf (file, "File "); + break; + default: + + fprintf (file, "AUX lnno %d size 0x%x tagndx %d", + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno, + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size, + tagndx); + break; + } + } + + if (l) + { + fprintf (file, "\n%s :", l->u.sym->name); + l++; + while (l->line_number) + { + fprintf (file, "\n%4d : 0x%x", + l->line_number, + l->u.offset + symbol->section->vma); + l++; + } + } + } + else + { + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s %s %s", + symbol->section->name, + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " ", + symbol->name); + } + } +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +boolean +DEFUN(coff_find_nearest_line,(abfd, + section, + ignore_symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr), + bfd *abfd AND + asection *section AND + asymbol **ignore_symbols AND + bfd_vma offset AND + CONST char **filename_ptr AND + CONST char **functionname_ptr AND + unsigned int *line_ptr) +{ + static bfd *cache_abfd; + static asection *cache_section; + static bfd_vma cache_offset; + static unsigned int cache_i; + static CONST char *cache_function; + static unsigned int line_base = 0; + + unsigned int i = 0; + coff_data_type *cof = coff_data(abfd); + /* Run through the raw syments if available */ + combined_entry_type *p; + alent *l; + + + *filename_ptr = 0; + *functionname_ptr = 0; + *line_ptr = 0; + + /* Don't try and find line numbers in a non coff file */ + if (abfd->xvec->flavour != bfd_target_coff_flavour) + return false; + + if (cof == NULL) + return false; + + p = cof->raw_syments; + + for (i = 0; i < cof->raw_syment_count; i++) { + if (p->u.syment.n_sclass == C_FILE) { + /* File name has been moved into symbol */ + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + break; + } + p += 1 + p->u.syment.n_numaux; + } + /* Now wander though the raw linenumbers of the section */ + /* + If this is the same BFD as we were previously called with and this is + the same section, and the offset we want is further down then we can + prime the lookup loop + */ + if (abfd == cache_abfd && + section == cache_section && + offset >= cache_offset) { + i = cache_i; + *functionname_ptr = cache_function; + } + else { + i = 0; + } + l = §ion->lineno[i]; + + for (; i < section->lineno_count; i++) { + if (l->line_number == 0) { + /* Get the symbol this line number points at */ + coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); + if (coff->symbol.value > offset) + break; + *functionname_ptr = coff->symbol.name; + if (coff->native) { + combined_entry_type *s = coff->native; + s = s + 1 + s->u.syment.n_numaux; + /* + S should now point to the .bf of the function + */ + if (s->u.syment.n_numaux) { + /* + The linenumber is stored in the auxent + */ + union internal_auxent *a = &((s + 1)->u.auxent); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; + *line_ptr = line_base; + } + } + } + else { + if (l->u.offset > offset) + break; + *line_ptr = l->line_number + line_base - 1; + } + l++; + } + + cache_abfd = abfd; + cache_section = section; + cache_offset = offset; + cache_i = i; + cache_function = *functionname_ptr; + + return true; +} + +int +DEFUN(coff_sizeof_headers,(abfd, reloc), + bfd *abfd AND + boolean reloc) +{ + size_t size; + + if (reloc == false) { + size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); + } + else { + size = bfd_coff_filhsz (abfd); + } + + size += abfd->section_count * bfd_coff_scnhsz (abfd); + return size; +} diff --git a/gnu/usr.bin/gdb/bfd/core.c b/gnu/usr.bin/gdb/bfd/core.c new file mode 100644 index 00000000000..c428775fbf3 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/core.c @@ -0,0 +1,106 @@ +/* Core file generic interface routines for BFD. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + Core files + +DESCRIPTION + Buff output this facinating topic +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* +FUNCTION + bfd_core_file_failing_command + +SYNOPSIS + CONST char *bfd_core_file_failing_command(bfd *); + +DESCRIPTION + Returns a read-only string explaining what program was running + when it failed and produced the core file being read + +*/ + +CONST char * +DEFUN(bfd_core_file_failing_command,(abfd), + bfd *abfd) +{ + if (abfd->format != bfd_core) { + bfd_error = invalid_operation; + return NULL; + } + return BFD_SEND (abfd, _core_file_failing_command, (abfd)); +} + +/* +FUNCTION + bfd_core_file_failing_signal + +SYNOPSIS + int bfd_core_file_failing_signal(bfd *); + +DESCRIPTION + Returns the signal number which caused the core dump which + generated the file the BFD is attached to. +*/ + +int +bfd_core_file_failing_signal (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_error = invalid_operation; + return 0; + } + return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); +} + + +/* +FUNCTION + core_file_matches_executable_p + +SYNOPSIS + boolean core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + +DESCRIPTION + Returns <> if the core file attached to @var{core_bfd} + was generated by a run of the executable file attached to + @var{exec_bfd}, or else <>. +*/ +boolean +core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { + bfd_error = wrong_format; + return false; + } + + return BFD_SEND (core_bfd, _core_file_matches_executable_p, + (core_bfd, exec_bfd)); +} diff --git a/gnu/usr.bin/gdb/bfd/cpu-i386.c b/gnu/usr.bin/gdb/bfd/cpu-i386.c new file mode 100644 index 00000000000..b4afdb2392b --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/cpu-i386.c @@ -0,0 +1,43 @@ +/* BFD support for the Intel 386 architecture. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static bfd_arch_info_type arch_info_struct = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + 0, /* only 1 machine */ + "i386", + "i386", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; + +void DEFUN_VOID(bfd_i386_arch) +{ + bfd_arch_linkin(&arch_info_struct); +} diff --git a/gnu/usr.bin/gdb/bfd/ctor.c b/gnu/usr.bin/gdb/bfd/ctor.c new file mode 100644 index 00000000000..adc69195ff6 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/ctor.c @@ -0,0 +1,148 @@ +/* BFD library support routines for constructors + Copyright (C) 1990-1991 Free Software Foundation, Inc. + + Hacked by Steve Chamberlain of Cygnus Support. With some help from + Judy Chamberlain too. + + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + Constructors + + Classes in C++ have `constructors' and `destructors'. These + are functions which are called automatically by the language + whenever data of a class is created or destroyed. Class data + which is static data may also be have a type which requires + `construction', the contructor must be called before the data + can be referenced, so the contructor must be called before the + program begins. + + The common solution to this problem is for the compiler to + call a magic function as the first statement <
>. + This magic function, (often called <<__main>>) runs around + calling the constructors for all the things needing it. + + With COFF the compile has a bargain with the linker et al. + All constructors are given strange names, for example + <<__GLOBAL__$I$foo>> might be the label of a contructor for + the class @var{foo}. The solution on unfortunate systems + (most system V machines) is to perform a partial link on all + the <<.o>> files, do an <> on the result, run <> or some + such over the result looking for strange <<__GLOBAL__$>> + symbols, generate a C program from this, compile it and link + with the partially linked input. This process is usually + called <>. + + Some versions of <> use something called the + <> mechanism. The constructor symbols are output + from the compiler with a special stab code saying that they + are constructors, and the linker can deal with them directly. + + BFD allows applications (ie the linker) to deal with + constructor information independently of their external + implimentation by providing a set of entry points for the + indiviual object back ends to call which maintains a database + of the contructor information. The application can + interrogate the database to find out what it wants. The + construction data essential for the linker to be able to + perform its job are: + + o asymbol - + The asymbol of the contructor entry point contains all the + information necessary to call the function. + + o table id - + The type of symbol, i.e., is it a constructor, a destructor or + something else someone dreamed up to make our lives difficult. + + This module takes this information and then builds extra + sections attached to the bfds which own the entry points. It + creates these sections as if they were tables of pointers to + the entry points, and builds relocation entries to go with + them so that the tables can be relocated along with the data + they reference. + + These sections are marked with a special bit + (<>) which the linker notices and do with + what it wants. + +*/ + +#include +#include +#include + + + +/* +INTERNAL_FUNCTION + bfd_constructor_entry + +SYNOPSIS + void bfd_constructor_entry(bfd *abfd, + asymbol **symbol_ptr_ptr, + CONST char*type); + + +DESCRIPTION + This function is called with an a symbol describing the + function to be called, an string which descibes the xtor type, + e.g., something like "CTOR" or "DTOR" would be fine. And the bfd + which owns the function. Its duty is to create a section + called "CTOR" or "DTOR" or whatever if the bfd doesn't already + have one, and grow a relocation table for the entry points as + they accumulate. + +*/ + + +void DEFUN(bfd_constructor_entry,(abfd, symbol_ptr_ptr, type), + bfd *abfd AND + asymbol **symbol_ptr_ptr AND + CONST char *type) + +{ + /* Look up the section we're using to store the table in */ + asection *rel_section = bfd_get_section_by_name (abfd, type); + if (rel_section == (asection *)NULL) { + rel_section = bfd_make_section (abfd, type); + rel_section->flags = SEC_CONSTRUCTOR; + rel_section->alignment_power = 2; + } + + /* Create a relocation into the section which references the entry + point */ + { + arelent_chain *reloc = (arelent_chain *)bfd_alloc(abfd, + sizeof(arelent_chain)); + +/* reloc->relent.section = (asection *)NULL;*/ + reloc->relent.addend = 0; + + reloc->relent.sym_ptr_ptr = symbol_ptr_ptr; + reloc->next = rel_section->constructor_chain; + rel_section->constructor_chain = reloc; + reloc->relent.address = rel_section->_cooked_size; + /* ask the cpu which howto to use */ + reloc->relent.howto = bfd_reloc_type_lookup(abfd, BFD_RELOC_CTOR); + rel_section->_cooked_size += sizeof(int *); + rel_section->reloc_count++; + } + +} diff --git a/gnu/usr.bin/gdb/bfd/ecoff.c b/gnu/usr.bin/gdb/bfd/ecoff.c new file mode 100644 index 00000000000..e3b7c937aa0 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/ecoff.c @@ -0,0 +1,3994 @@ +/* Generic ECOFF (Extended-COFF) routines. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Original version by Per Bothner. + Full support added by Ian Lance Taylor, ian@cygnus.com. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +#include "aout/ar.h" +#include "aout/ranlib.h" + +/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines + some other stuff which we don't want and which conflicts with stuff + we do want. */ +#include "libaout.h" +#include "aout/aout64.h" +#undef N_ABS +#undef exec_hdr +#undef obj_sym_filepos + +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" +#include "libcoff.h" +#include "libecoff.h" + +/* Prototypes for static functions. */ + +static int ecoff_get_magic PARAMS ((bfd *abfd)); +static void ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym, + asymbol *asym, int ext, + asymbol **indirect_ptr_ptr)); +static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string, + RNDXR *rndx, long isym, + CONST char *which)); +static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr, + unsigned int indx, int bigendian)); +static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section, + asymbol **symbols)); +static void ecoff_clear_output_flags PARAMS ((bfd *abfd)); +static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet, + asection *output_section, PTR data, + boolean relocateable)); +static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet, + asection *section, PTR data, + boolean relocateable)); +static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr, + CONST char *string, boolean external)); +static boolean ecoff_get_debug PARAMS ((bfd *output_bfd, + bfd_seclet_type *seclet, + asection *section, + boolean relocateable)); +static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd)); +static unsigned int ecoff_armap_hash PARAMS ((CONST char *s, + unsigned int *rehash, + unsigned int size, + unsigned int hlog)); + +/* This stuff is somewhat copied from coffcode.h. */ + +static asection bfd_debug_section = { "*DEBUG*" }; + +/* Create an ECOFF object. */ + +boolean +ecoff_mkobject (abfd) + bfd *abfd; +{ + abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *) + bfd_zalloc (abfd, sizeof (ecoff_data_type))); + if (abfd->tdata.ecoff_obj_data == NULL) + { + bfd_error = no_memory; + return false; + } + + /* Always create a .scommon section for every BFD. This is a hack so + that the linker has something to attach scSCommon symbols to. */ + if (bfd_make_section (abfd, SCOMMON) == NULL) + return false; + + return true; +} + +/* This is a hook called by coff_real_object_p to create any backend + specific information. */ + +PTR +ecoff_mkobject_hook (abfd, filehdr, aouthdr) + bfd *abfd; + PTR filehdr; + PTR aouthdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr; + ecoff_data_type *ecoff; + asection *regsec; + + if (ecoff_mkobject (abfd) == false) + return NULL; + + ecoff = ecoff_data (abfd); + ecoff->gp_size = 8; + ecoff->sym_filepos = internal_f->f_symptr; + + /* Create the .reginfo section to give programs outside BFD a way to + see the information stored in the a.out header. See the comment + in coff/ecoff.h. */ + regsec = bfd_make_section (abfd, REGINFO); + if (regsec == NULL) + return NULL; + + if (internal_a != (struct internal_aouthdr *) NULL) + { + int i; + + ecoff->text_start = internal_a->text_start; + ecoff->text_end = internal_a->text_start + internal_a->tsize; + ecoff->gp = internal_a->gp_value; + ecoff->gprmask = internal_a->gprmask; + for (i = 0; i < 4; i++) + ecoff->cprmask[i] = internal_a->cprmask[i]; + ecoff->fprmask = internal_a->fprmask; + if (internal_a->magic == ECOFF_AOUT_ZMAGIC) + abfd->flags |= D_PAGED; + } + + /* It turns out that no special action is required by the MIPS or + Alpha ECOFF backends. They have different information in the + a.out header, but we just copy it all (e.g., gprmask, cprmask and + fprmask) and let the swapping routines ensure that only relevant + information is written out. */ + + return (PTR) ecoff; +} + +/* This is a hook needed by SCO COFF, but we have nothing to do. */ + +asection * +ecoff_make_section_hook (abfd, name) + bfd *abfd; + char *name; +{ + return (asection *) NULL; +} + +/* Initialize a new section. */ + +boolean +ecoff_new_section_hook (abfd, section) + bfd *abfd; + asection *section; +{ + section->alignment_power = abfd->xvec->align_power_min; + + if (strcmp (section->name, _TEXT) == 0) + section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + else if (strcmp (section->name, _DATA) == 0 + || strcmp (section->name, _SDATA) == 0) + section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + else if (strcmp (section->name, _RDATA) == 0 + || strcmp (section->name, _LIT8) == 0 + || strcmp (section->name, _LIT4) == 0) + section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + else if (strcmp (section->name, _BSS) == 0 + || strcmp (section->name, _SBSS) == 0) + section->flags |= SEC_ALLOC; + else if (strcmp (section->name, REGINFO) == 0) + { + section->flags |= SEC_HAS_CONTENTS | SEC_NEVER_LOAD; + section->_raw_size = sizeof (struct ecoff_reginfo); + } + + /* Probably any other section name is SEC_NEVER_LOAD, but I'm + uncertain about .init on some systems and I don't know how shared + libraries work. */ + + return true; +} + +/* Determine the machine architecture and type. This is called from + the generic COFF routines. It is the inverse of ecoff_get_magic, + below. This could be an ECOFF backend routine, with one version + for each target, but there aren't all that many ECOFF targets. */ + +boolean +ecoff_set_arch_mach_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + enum bfd_architecture arch; + unsigned long mach; + + switch (internal_f->f_magic) + { + case MIPS_MAGIC_1: + case MIPS_MAGIC_LITTLE: + case MIPS_MAGIC_BIG: + arch = bfd_arch_mips; + mach = 3000; + break; + + case MIPS_MAGIC_LITTLE2: + case MIPS_MAGIC_BIG2: + /* MIPS ISA level 2: the r6000 */ + arch = bfd_arch_mips; + mach = 6000; + break; + + case MIPS_MAGIC_LITTLE3: + case MIPS_MAGIC_BIG3: + /* MIPS ISA level 3: the r4000 */ + arch = bfd_arch_mips; + mach = 4000; + break; + + case ALPHA_MAGIC: + arch = bfd_arch_alpha; + mach = 0; + break; + + default: + arch = bfd_arch_obscure; + mach = 0; + break; + } + + return bfd_default_set_arch_mach (abfd, arch, mach); +} + +/* Get the magic number to use based on the architecture and machine. + This is the inverse of ecoff_set_arch_mach_hook, above. */ + +static int +ecoff_get_magic (abfd) + bfd *abfd; +{ + int big, little; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_mips: + switch (bfd_get_mach (abfd)) + { + default: + case 0: + case 3000: + big = MIPS_MAGIC_BIG; + little = MIPS_MAGIC_LITTLE; + break; + + case 6000: + big = MIPS_MAGIC_BIG2; + little = MIPS_MAGIC_LITTLE2; + break; + + case 4000: + big = MIPS_MAGIC_BIG3; + little = MIPS_MAGIC_LITTLE3; + break; + } + + return abfd->xvec->byteorder_big_p ? big : little; + + case bfd_arch_alpha: + return ALPHA_MAGIC; + + default: + abort (); + return 0; + } +} + +/* Get the section s_flags to use for a section. */ + +long +ecoff_sec_to_styp_flags (name, flags) + CONST char *name; + flagword flags; +{ + long styp; + + styp = 0; + + if (strcmp (name, _TEXT) == 0) + styp = STYP_TEXT; + else if (strcmp (name, _DATA) == 0) + styp = STYP_DATA; + else if (strcmp (name, _SDATA) == 0) + styp = STYP_SDATA; + else if (strcmp (name, _RDATA) == 0) + styp = STYP_RDATA; + else if (strcmp (name, _LIT8) == 0) + styp = STYP_LIT8; + else if (strcmp (name, _LIT4) == 0) + styp = STYP_LIT4; + else if (strcmp (name, _BSS) == 0) + styp = STYP_BSS; + else if (strcmp (name, _SBSS) == 0) + styp = STYP_SBSS; + else if (strcmp (name, _INIT) == 0) + styp = STYP_ECOFF_INIT; + else if (strcmp (name, _FINI) == 0) + styp = STYP_ECOFF_FINI; + else if (flags & SEC_CODE) + styp = STYP_TEXT; + else if (flags & SEC_DATA) + styp = STYP_DATA; + else if (flags & SEC_READONLY) + styp = STYP_RDATA; + else if (flags & SEC_LOAD) + styp = STYP_REG; + else + styp = STYP_BSS; + + if (flags & SEC_NEVER_LOAD) + styp |= STYP_NOLOAD; + + return styp; +} + +/* Get the BFD flags to use for a section. */ + +flagword +ecoff_styp_to_sec_flags (abfd, hdr) + bfd *abfd; + PTR hdr; +{ + struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; + long styp_flags = internal_s->s_flags; + flagword sec_flags=0; + + if (styp_flags & STYP_NOLOAD) + sec_flags |= SEC_NEVER_LOAD; + + /* For 386 COFF, at least, an unloadable text or data section is + actually a shared library section. */ + if ((styp_flags & STYP_TEXT) + || (styp_flags & STYP_ECOFF_INIT) + || (styp_flags & STYP_ECOFF_FINI)) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_CODE | SEC_SHARED_LIBRARY; + else + sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + } + else if ((styp_flags & STYP_DATA) + || (styp_flags & STYP_RDATA) + || (styp_flags & STYP_SDATA)) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY; + else + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + if (styp_flags & STYP_RDATA) + sec_flags |= SEC_READONLY; + } + else if ((styp_flags & STYP_BSS) + || (styp_flags & STYP_SBSS)) + { + sec_flags |= SEC_ALLOC; + } + else if (styp_flags & STYP_INFO) + { + sec_flags |= SEC_NEVER_LOAD; + } + else if ((styp_flags & STYP_LIT8) + || (styp_flags & STYP_LIT4)) + { + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + } + else + { + sec_flags |= SEC_ALLOC | SEC_LOAD; + } + + return sec_flags; +} + +/* Routines to swap auxiliary information in and out. I am assuming + that the auxiliary information format is always going to be target + independent. */ + +/* Swap in a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +ecoff_swap_tir_in (bigend, ext_copy, intern) + int bigend; + struct tir_ext *ext_copy; + TIR *intern; +{ + struct tir_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG) + >> TIR_BITS1_BT_SH_BIG; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG) + >> TIR_BITS_TQ4_SH_BIG; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG) + >> TIR_BITS_TQ5_SH_BIG; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG) + >> TIR_BITS_TQ0_SH_BIG; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG) + >> TIR_BITS_TQ1_SH_BIG; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG) + >> TIR_BITS_TQ2_SH_BIG; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG) + >> TIR_BITS_TQ3_SH_BIG; + } else { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE) + >> TIR_BITS1_BT_SH_LITTLE; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE) + >> TIR_BITS_TQ4_SH_LITTLE; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE) + >> TIR_BITS_TQ5_SH_LITTLE; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE) + >> TIR_BITS_TQ0_SH_LITTLE; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE) + >> TIR_BITS_TQ1_SH_LITTLE; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE) + >> TIR_BITS_TQ2_SH_LITTLE; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE) + >> TIR_BITS_TQ3_SH_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +ecoff_swap_tir_out (bigend, intern_copy, ext) + int bigend; + TIR *intern_copy; + struct tir_ext *ext; +{ + TIR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0) + | ((intern->bt << TIR_BITS1_BT_SH_BIG) + & TIR_BITS1_BT_BIG)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG) + & TIR_BITS_TQ4_BIG) + | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG) + & TIR_BITS_TQ5_BIG)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG) + & TIR_BITS_TQ0_BIG) + | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG) + & TIR_BITS_TQ1_BIG)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG) + & TIR_BITS_TQ2_BIG) + | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG) + & TIR_BITS_TQ3_BIG)); + } else { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0) + | ((intern->bt << TIR_BITS1_BT_SH_LITTLE) + & TIR_BITS1_BT_LITTLE)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE) + & TIR_BITS_TQ4_LITTLE) + | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE) + & TIR_BITS_TQ5_LITTLE)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE) + & TIR_BITS_TQ0_LITTLE) + | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE) + & TIR_BITS_TQ1_LITTLE)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE) + & TIR_BITS_TQ2_LITTLE) + | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE) + & TIR_BITS_TQ3_LITTLE)); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +ecoff_swap_rndx_in (bigend, ext_copy, intern) + int bigend; + struct rndx_ext *ext_copy; + RNDXR *intern; +{ + struct rndx_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG) + >> RNDX_BITS1_RFD_SH_BIG); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG) + << RNDX_BITS1_INDEX_SH_LEFT_BIG) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG); + } else { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE) + << RNDX_BITS1_RFD_SH_LEFT_LITTLE); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE) + >> RNDX_BITS1_INDEX_SH_LITTLE) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +ecoff_swap_rndx_out (bigend, intern_copy, ext) + int bigend; + RNDXR *intern_copy; + struct rndx_ext *ext; +{ + RNDXR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG; + ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG) + & RNDX_BITS1_RFD_BIG) + | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG) + & RNDX_BITS1_INDEX_BIG)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG; + } else { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE; + ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE) + & RNDX_BITS1_RFD_LITTLE) + | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE) + & RNDX_BITS1_INDEX_LITTLE)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Read in and swap the important symbolic information for an ECOFF + object file. This is called by gdb. */ + +boolean +ecoff_slurp_symbolic_info (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + bfd_size_type external_hdr_size; + HDRR *internal_symhdr; + bfd_size_type raw_base; + bfd_size_type raw_size; + PTR raw; + bfd_size_type external_fdr_size; + char *fraw_src; + char *fraw_end; + struct fdr *fdr_ptr; + bfd_size_type raw_end; + bfd_size_type cb_end; + + /* Check whether we've already gotten it, and whether there's any to + get. */ + if (ecoff_data (abfd)->raw_syments != (PTR) NULL) + return true; + if (ecoff_data (abfd)->sym_filepos == 0) + { + bfd_get_symcount (abfd) = 0; + return true; + } + + /* At this point bfd_get_symcount (abfd) holds the number of symbols + as read from the file header, but on ECOFF this is always the + size of the symbolic information header. It would be cleaner to + handle this when we first read the file in coffgen.c. */ + external_hdr_size = backend->external_hdr_size; + if (bfd_get_symcount (abfd) != external_hdr_size) + { + bfd_error = bad_value; + return false; + } + + /* Read the symbolic information header. */ + raw = (PTR) alloca (external_hdr_size); + if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1 + || (bfd_read (raw, external_hdr_size, 1, abfd) + != external_hdr_size)) + { + bfd_error = system_call_error; + return false; + } + internal_symhdr = &ecoff_data (abfd)->symbolic_header; + (*backend->swap_hdr_in) (abfd, raw, internal_symhdr); + + if (internal_symhdr->magic != backend->sym_magic) + { + bfd_error = bad_value; + return false; + } + + /* Now we can get the correct number of symbols. */ + bfd_get_symcount (abfd) = (internal_symhdr->isymMax + + internal_symhdr->iextMax); + + /* Read all the symbolic information at once. */ + raw_base = ecoff_data (abfd)->sym_filepos + external_hdr_size; + + /* Alpha ecoff makes the determination of raw_size difficult. It has + an undocumented debug data section between the symhdr and the first + documented section. And the ordering of the sections varies between + statically and dynamically linked executables. + If bfd supports SEEK_END someday, this code could be simplified. */ + + raw_end = 0; + +#define UPDATE_RAW_END(start, count, size) \ + cb_end = internal_symhdr->start + internal_symhdr->count * (size); \ + if (cb_end > raw_end) \ + raw_end = cb_end + + UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char)); + UPDATE_RAW_END (cbDnOffset, idnMax, backend->external_dnr_size); + UPDATE_RAW_END (cbPdOffset, ipdMax, backend->external_pdr_size); + UPDATE_RAW_END (cbSymOffset, isymMax, backend->external_sym_size); + UPDATE_RAW_END (cbOptOffset, ioptMax, backend->external_opt_size); + UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext)); + UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char)); + UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char)); + UPDATE_RAW_END (cbFdOffset, ifdMax, backend->external_fdr_size); + UPDATE_RAW_END (cbRfdOffset, crfd, backend->external_rfd_size); + UPDATE_RAW_END (cbExtOffset, iextMax, backend->external_ext_size); + +#undef UPDATE_RAW_END + + raw_size = raw_end - raw_base; + if (raw_size == 0) + { + ecoff_data (abfd)->sym_filepos = 0; + return true; + } + raw = (PTR) bfd_alloc (abfd, raw_size); + if (raw == NULL) + { + bfd_error = no_memory; + return false; + } + if (bfd_read (raw, raw_size, 1, abfd) != raw_size) + { + bfd_error = system_call_error; + bfd_release (abfd, raw); + return false; + } + + ecoff_data (abfd)->raw_size = raw_size; + ecoff_data (abfd)->raw_syments = raw; + + /* Get pointers for the numeric offsets in the HDRR structure. */ +#define FIX(off1, off2, type) \ + if (internal_symhdr->off1 == 0) \ + ecoff_data (abfd)->off2 = (type) NULL; \ + else \ + ecoff_data (abfd)->off2 = (type) ((char *) raw \ + + internal_symhdr->off1 \ + - raw_base) + FIX (cbLineOffset, line, unsigned char *); + FIX (cbDnOffset, external_dnr, PTR); + FIX (cbPdOffset, external_pdr, PTR); + FIX (cbSymOffset, external_sym, PTR); + FIX (cbOptOffset, external_opt, PTR); + FIX (cbAuxOffset, external_aux, union aux_ext *); + FIX (cbSsOffset, ss, char *); + FIX (cbSsExtOffset, ssext, char *); + FIX (cbFdOffset, external_fdr, PTR); + FIX (cbRfdOffset, external_rfd, PTR); + FIX (cbExtOffset, external_ext, PTR); +#undef FIX + + /* I don't want to always swap all the data, because it will just + waste time and most programs will never look at it. The only + time the linker needs most of the debugging information swapped + is when linking big-endian and little-endian MIPS object files + together, which is not a common occurrence. + + We need to look at the fdr to deal with a lot of information in + the symbols, so we swap them here. */ + ecoff_data (abfd)->fdr = + (struct fdr *) bfd_alloc (abfd, + (internal_symhdr->ifdMax * + sizeof (struct fdr))); + if (ecoff_data (abfd)->fdr == NULL) + { + bfd_error = no_memory; + return false; + } + external_fdr_size = backend->external_fdr_size; + fdr_ptr = ecoff_data (abfd)->fdr; + fraw_src = (char *) ecoff_data (abfd)->external_fdr; + fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size; + for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) + (*backend->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + + return true; +} + +/* ECOFF symbol table routines. The ECOFF symbol table is described + in gcc/mips-tfile.c. */ + +/* ECOFF uses two common sections. One is the usual one, and the + other is for small objects. All the small objects are kept + together, and then referenced via the gp pointer, which yields + faster assembler code. This is what we use for the small common + section. */ +static asection ecoff_scom_section; +static asymbol ecoff_scom_symbol; +static asymbol *ecoff_scom_symbol_ptr; + +/* Create an empty symbol. */ + +asymbol * +ecoff_make_empty_symbol (abfd) + bfd *abfd; +{ + ecoff_symbol_type *new; + + new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type)); + if (new == (ecoff_symbol_type *) NULL) + { + bfd_error = no_memory; + return (asymbol *) NULL; + } + memset (new, 0, sizeof *new); + new->symbol.section = (asection *) NULL; + new->fdr = (FDR *) NULL; + new->local = false; + new->native = NULL; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Set the BFD flags and section for an ECOFF symbol. */ + +static void +ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) + bfd *abfd; + SYMR *ecoff_sym; + asymbol *asym; + int ext; + asymbol **indirect_ptr_ptr; +{ + asym->the_bfd = abfd; + asym->value = ecoff_sym->value; + asym->section = &bfd_debug_section; + asym->udata = NULL; + + /* An indirect symbol requires two consecutive stabs symbols. */ + if (*indirect_ptr_ptr != (asymbol *) NULL) + { + BFD_ASSERT (ECOFF_IS_STAB (ecoff_sym)); + + /* @@ Stuffing pointers into integers is a no-no. + We can usually get away with it if the integer is + large enough though. */ + if (sizeof (asym) > sizeof (bfd_vma)) + abort (); + (*indirect_ptr_ptr)->value = (bfd_vma) asym; + + asym->flags = BSF_DEBUGGING; + asym->section = &bfd_und_section; + *indirect_ptr_ptr = NULL; + return; + } + + if (ECOFF_IS_STAB (ecoff_sym) + && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT)) + { + asym->flags = BSF_DEBUGGING | BSF_INDIRECT; + asym->section = &bfd_ind_section; + /* Pass this symbol on to the next call to this function. */ + *indirect_ptr_ptr = asym; + return; + } + + /* Most symbol types are just for debugging. */ + switch (ecoff_sym->st) + { + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + break; + case stNil: + if (ECOFF_IS_STAB (ecoff_sym)) + { + asym->flags = BSF_DEBUGGING; + return; + } + break; + default: + asym->flags = BSF_DEBUGGING; + return; + } + + if (ext) + asym->flags = BSF_EXPORT | BSF_GLOBAL; + else + asym->flags = BSF_LOCAL; + switch (ecoff_sym->sc) + { + case scNil: + /* Used for compiler generated labels. Leave them in the + debugging section, and mark them as local. If BSF_DEBUGGING + is set, then nm does not display them for some reason. If no + flags are set then the linker whines about them. */ + asym->flags = BSF_LOCAL; + break; + case scText: + asym->section = bfd_make_section_old_way (abfd, ".text"); + asym->value -= asym->section->vma; + break; + case scData: + asym->section = bfd_make_section_old_way (abfd, ".data"); + asym->value -= asym->section->vma; + break; + case scBss: + asym->section = bfd_make_section_old_way (abfd, ".bss"); + asym->value -= asym->section->vma; + break; + case scRegister: + asym->flags = BSF_DEBUGGING; + break; + case scAbs: + asym->section = &bfd_abs_section; + break; + case scUndefined: + asym->section = &bfd_und_section; + asym->flags = 0; + asym->value = 0; + break; + case scCdbLocal: + case scBits: + case scCdbSystem: + case scRegImage: + case scInfo: + case scUserStruct: + asym->flags = BSF_DEBUGGING; + break; + case scSData: + asym->section = bfd_make_section_old_way (abfd, ".sdata"); + asym->value -= asym->section->vma; + break; + case scSBss: + asym->section = bfd_make_section_old_way (abfd, ".sbss"); + asym->value -= asym->section->vma; + break; + case scRData: + asym->section = bfd_make_section_old_way (abfd, ".rdata"); + asym->value -= asym->section->vma; + break; + case scVar: + asym->flags = BSF_DEBUGGING; + break; + case scCommon: + if (asym->value > ecoff_data (abfd)->gp_size) + { + asym->section = &bfd_com_section; + asym->flags = 0; + break; + } + /* Fall through. */ + case scSCommon: + if (ecoff_scom_section.name == NULL) + { + /* Initialize the small common section. */ + ecoff_scom_section.name = SCOMMON; + ecoff_scom_section.flags = SEC_IS_COMMON; + ecoff_scom_section.output_section = &ecoff_scom_section; + ecoff_scom_section.symbol = &ecoff_scom_symbol; + ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; + ecoff_scom_symbol.name = SCOMMON; + ecoff_scom_symbol.flags = BSF_SECTION_SYM; + ecoff_scom_symbol.section = &ecoff_scom_section; + ecoff_scom_symbol_ptr = &ecoff_scom_symbol; + } + asym->section = &ecoff_scom_section; + asym->flags = 0; + break; + case scVarRegister: + case scVariant: + asym->flags = BSF_DEBUGGING; + break; + case scSUndefined: + asym->section = &bfd_und_section; + asym->flags = 0; + asym->value = 0; + break; + case scInit: + asym->section = bfd_make_section_old_way (abfd, ".init"); + asym->value -= asym->section->vma; + break; + case scBasedVar: + case scXData: + case scPData: + asym->flags = BSF_DEBUGGING; + break; + case scFini: + asym->section = bfd_make_section_old_way (abfd, ".fini"); + asym->value -= asym->section->vma; + break; + default: + break; + } + + /* Look for special constructors symbols and make relocation entries + in a special construction section. These are produced by the + -fgnu-linker argument to g++. */ + if (ECOFF_IS_STAB (ecoff_sym)) + { + switch (ECOFF_UNMARK_STAB (ecoff_sym->index)) + { + default: + break; + + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + const char *name; + asection *section; + arelent_chain *reloc_chain; + unsigned int bitsize; + + /* Get a section with the same name as the symbol (usually + __CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the + name ___CTOR_LIST (three underscores). We need + __CTOR_LIST (two underscores), since ECOFF doesn't use + a leading underscore. This should be handled by gcc, + but instead we do it here. Actually, this should all + be done differently anyhow. */ + name = bfd_asymbol_name (asym); + if (name[0] == '_' && name[1] == '_' && name[2] == '_') + { + ++name; + asym->name = name; + } + section = bfd_get_section_by_name (abfd, name); + if (section == (asection *) NULL) + { + char *copy; + + copy = (char *) bfd_alloc (abfd, strlen (name) + 1); + strcpy (copy, name); + section = bfd_make_section (abfd, copy); + } + + /* Build a reloc pointing to this constructor. */ + reloc_chain = + (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + reloc_chain->relent.sym_ptr_ptr = + bfd_get_section (asym)->symbol_ptr_ptr; + reloc_chain->relent.address = section->_raw_size; + reloc_chain->relent.addend = asym->value; + reloc_chain->relent.howto = + ecoff_backend (abfd)->constructor_reloc; + + /* Set up the constructor section to hold the reloc. */ + section->flags = SEC_CONSTRUCTOR; + ++section->reloc_count; + + /* Constructor sections must be rounded to a boundary + based on the bitsize. These are not real sections-- + they are handled specially by the linker--so the ECOFF + 16 byte alignment restriction does not apply. */ + bitsize = ecoff_backend (abfd)->constructor_bitsize; + section->alignment_power = 1; + while ((1 << section->alignment_power) < bitsize / 8) + ++section->alignment_power; + + reloc_chain->next = section->constructor_chain; + section->constructor_chain = reloc_chain; + section->_raw_size += bitsize / 8; + + /* Mark the symbol as a constructor. */ + asym->flags |= BSF_CONSTRUCTOR; + } + break; + } + } +} + +/* Read an ECOFF symbol table. */ + +boolean +ecoff_slurp_symbol_table (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_size_type external_ext_size = backend->external_ext_size; + const bfd_size_type external_sym_size = backend->external_sym_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->swap_ext_in; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = backend->swap_sym_in; + bfd_size_type internal_size; + ecoff_symbol_type *internal; + ecoff_symbol_type *internal_ptr; + asymbol *indirect_ptr; + char *eraw_src; + char *eraw_end; + FDR *fdr_ptr; + FDR *fdr_end; + + /* If we've already read in the symbol table, do nothing. */ + if (ecoff_data (abfd)->canonical_symbols != NULL) + return true; + + /* Get the symbolic information. */ + if (ecoff_slurp_symbolic_info (abfd) == false) + return false; + if (bfd_get_symcount (abfd) == 0) + return true; + + internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type); + internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size); + if (internal == NULL) + { + bfd_error = no_memory; + return false; + } + + internal_ptr = internal; + indirect_ptr = NULL; + eraw_src = (char *) ecoff_data (abfd)->external_ext; + eraw_end = (eraw_src + + (ecoff_data (abfd)->symbolic_header.iextMax + * external_ext_size)); + for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++) + { + EXTR internal_esym; + + (*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym); + internal_ptr->symbol.name = (ecoff_data (abfd)->ssext + + internal_esym.asym.iss); + ecoff_set_symbol_info (abfd, &internal_esym.asym, + &internal_ptr->symbol, 1, &indirect_ptr); + /* The alpha uses a negative ifd field for section symbols. */ + if (internal_esym.ifd >= 0) + internal_ptr->fdr = ecoff_data (abfd)->fdr + internal_esym.ifd; + else + internal_ptr->fdr = NULL; + internal_ptr->local = false; + internal_ptr->native = (PTR) eraw_src; + } + BFD_ASSERT (indirect_ptr == (asymbol *) NULL); + + /* The local symbols must be accessed via the fdr's, because the + string and aux indices are relative to the fdr information. */ + fdr_ptr = ecoff_data (abfd)->fdr; + fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax; + for (; fdr_ptr < fdr_end; fdr_ptr++) + { + char *lraw_src; + char *lraw_end; + + lraw_src = ((char *) ecoff_data (abfd)->external_sym + + fdr_ptr->isymBase * external_sym_size); + lraw_end = lraw_src + fdr_ptr->csym * external_sym_size; + for (; + lraw_src < lraw_end; + lraw_src += external_sym_size, internal_ptr++) + { + SYMR internal_sym; + + (*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym); + internal_ptr->symbol.name = (ecoff_data (abfd)->ss + + fdr_ptr->issBase + + internal_sym.iss); + ecoff_set_symbol_info (abfd, &internal_sym, + &internal_ptr->symbol, 0, &indirect_ptr); + internal_ptr->fdr = fdr_ptr; + internal_ptr->local = true; + internal_ptr->native = (PTR) lraw_src; + } + } + BFD_ASSERT (indirect_ptr == (asymbol *) NULL); + + ecoff_data (abfd)->canonical_symbols = internal; + + return true; +} + +/* Return the amount of space needed for the canonical symbols. */ + +unsigned int +ecoff_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (ecoff_slurp_symbolic_info (abfd) == false + || bfd_get_symcount (abfd) == 0) + return 0; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *)); +} + +/* Get the canonicals symbols. */ + +unsigned int +ecoff_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int counter = 0; + ecoff_symbol_type *symbase; + ecoff_symbol_type **location = (ecoff_symbol_type **) alocation; + + if (ecoff_slurp_symbol_table (abfd) == false + || bfd_get_symcount (abfd) == 0) + return 0; + + symbase = ecoff_data (abfd)->canonical_symbols; + while (counter < bfd_get_symcount (abfd)) + { + *(location++) = symbase++; + counter++; + } + *location++ = (ecoff_symbol_type *) NULL; + return bfd_get_symcount (abfd); +} + +/* Turn ECOFF type information into a printable string. + ecoff_emit_aggregate and ecoff_type_to_string are from + gcc/mips-tdump.c, with swapping added and used_ptr removed. */ + +/* Write aggregate information to a string. */ + +static void +ecoff_emit_aggregate (abfd, string, rndx, isym, which) + bfd *abfd; + char *string; + RNDXR *rndx; + long isym; + CONST char *which; +{ + int ifd = rndx->rfd; + int indx = rndx->index; + int sym_base, ss_base; + CONST char *name; + + if (ifd == 0xfff) + ifd = isym; + + sym_base = ecoff_data (abfd)->fdr[ifd].isymBase; + ss_base = ecoff_data (abfd)->fdr[ifd].issBase; + + if (indx == indexNil) + name = "/* no name */"; + else + { + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + SYMR sym; + + indx += sym_base; + (*backend->swap_sym_in) (abfd, + ((char *) ecoff_data (abfd)->external_sym + + indx * backend->external_sym_size), + &sym); + name = ecoff_data (abfd)->ss + ss_base + sym.iss; + } + + sprintf (string, + "%s %s { ifd = %d, index = %d }", + which, name, ifd, + indx + ecoff_data (abfd)->symbolic_header.iextMax); +} + +/* Convert the type information to string format. */ + +static char * +ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) + bfd *abfd; + union aux_ext *aux_ptr; + unsigned int indx; + int bigendian; +{ + AUXU u; + struct qual { + unsigned int type; + int low_bound; + int high_bound; + int stride; + } qualifiers[7]; + + unsigned int basic_type; + int i; + static char buffer1[1024]; + static char buffer2[1024]; + char *p1 = buffer1; + char *p2 = buffer2; + RNDXR rndx; + + for (i = 0; i < 7; i++) + { + qualifiers[i].low_bound = 0; + qualifiers[i].high_bound = 0; + qualifiers[i].stride = 0; + } + + if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1) + return "-1 (no type)"; + ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti); + + basic_type = u.ti.bt; + qualifiers[0].type = u.ti.tq0; + qualifiers[1].type = u.ti.tq1; + qualifiers[2].type = u.ti.tq2; + qualifiers[3].type = u.ti.tq3; + qualifiers[4].type = u.ti.tq4; + qualifiers[5].type = u.ti.tq5; + qualifiers[6].type = tqNil; + + /* + * Go get the basic type. + */ + switch (basic_type) + { + case btNil: /* undefined */ + strcpy (p1, "nil"); + break; + + case btAdr: /* address - integer same size as pointer */ + strcpy (p1, "address"); + break; + + case btChar: /* character */ + strcpy (p1, "char"); + break; + + case btUChar: /* unsigned character */ + strcpy (p1, "unsigned char"); + break; + + case btShort: /* short */ + strcpy (p1, "short"); + break; + + case btUShort: /* unsigned short */ + strcpy (p1, "unsigned short"); + break; + + case btInt: /* int */ + strcpy (p1, "int"); + break; + + case btUInt: /* unsigned int */ + strcpy (p1, "unsigned int"); + break; + + case btLong: /* long */ + strcpy (p1, "long"); + break; + + case btULong: /* unsigned long */ + strcpy (p1, "unsigned long"); + break; + + case btFloat: /* float (real) */ + strcpy (p1, "float"); + break; + + case btDouble: /* Double (real) */ + strcpy (p1, "double"); + break; + + /* Structures add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to struct def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btStruct: /* Structure (Record) */ + ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, p1, &rndx, + AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "struct"); + indx++; /* skip aux words */ + break; + + /* Unions add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to union def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btUnion: /* Union */ + ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, p1, &rndx, + AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "union"); + indx++; /* skip aux words */ + break; + + /* Enumerations add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to enum def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btEnum: /* Enumeration */ + ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, p1, &rndx, + AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "enum"); + indx++; /* skip aux words */ + break; + + case btTypedef: /* defined via a typedef, isymRef points */ + strcpy (p1, "typedef"); + break; + + case btRange: /* subrange of int */ + strcpy (p1, "subrange"); + break; + + case btSet: /* pascal sets */ + strcpy (p1, "set"); + break; + + case btComplex: /* fortran complex */ + strcpy (p1, "complex"); + break; + + case btDComplex: /* fortran double complex */ + strcpy (p1, "double complex"); + break; + + case btIndirect: /* forward or unnamed typedef */ + strcpy (p1, "forward/unamed typedef"); + break; + + case btFixedDec: /* Fixed Decimal */ + strcpy (p1, "fixed decimal"); + break; + + case btFloatDec: /* Float Decimal */ + strcpy (p1, "float decimal"); + break; + + case btString: /* Varying Length Character String */ + strcpy (p1, "string"); + break; + + case btBit: /* Aligned Bit String */ + strcpy (p1, "bit"); + break; + + case btPicture: /* Picture */ + strcpy (p1, "picture"); + break; + + case btVoid: /* Void */ + strcpy (p1, "void"); + break; + + default: + sprintf (p1, "Unknown basic type %d", (int) basic_type); + break; + } + + p1 += strlen (buffer1); + + /* + * If this is a bitfield, get the bitsize. + */ + if (u.ti.fBitfield) + { + int bitsize; + + bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]); + sprintf (p1, " : %d", bitsize); + p1 += strlen (buffer1); + } + + + /* + * Deal with any qualifiers. + */ + if (qualifiers[0].type != tqNil) + { + /* + * Snarf up any array bounds in the correct order. Arrays + * store 5 successive words in the aux. table: + * word 0 RNDXR to type of the bounds (ie, int) + * word 1 Current file descriptor index + * word 2 low bound + * word 3 high bound (or -1 if []) + * word 4 stride size in bits + */ + for (i = 0; i < 7; i++) + { + if (qualifiers[i].type == tqArray) + { + qualifiers[i].low_bound = + AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]); + qualifiers[i].high_bound = + AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]); + qualifiers[i].stride = + AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]); + indx += 5; + } + } + + /* + * Now print out the qualifiers. + */ + for (i = 0; i < 6; i++) + { + switch (qualifiers[i].type) + { + case tqNil: + case tqMax: + break; + + case tqPtr: + strcpy (p2, "ptr to "); + p2 += sizeof ("ptr to ")-1; + break; + + case tqVol: + strcpy (p2, "volatile "); + p2 += sizeof ("volatile ")-1; + break; + + case tqFar: + strcpy (p2, "far "); + p2 += sizeof ("far ")-1; + break; + + case tqProc: + strcpy (p2, "func. ret. "); + p2 += sizeof ("func. ret. "); + break; + + case tqArray: + { + int first_array = i; + int j; + + /* Print array bounds reversed (ie, in the order the C + programmer writes them). C is such a fun language.... */ + + while (i < 5 && qualifiers[i+1].type == tqArray) + i++; + + for (j = i; j >= first_array; j--) + { + strcpy (p2, "array ["); + p2 += sizeof ("array [")-1; + if (qualifiers[j].low_bound != 0) + sprintf (p2, + "%ld:%ld {%ld bits}", + (long) qualifiers[j].low_bound, + (long) qualifiers[j].high_bound, + (long) qualifiers[j].stride); + + else if (qualifiers[j].high_bound != -1) + sprintf (p2, + "%ld {%ld bits}", + (long) (qualifiers[j].high_bound + 1), + (long) (qualifiers[j].stride)); + + else + sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride)); + + p2 += strlen (p2); + strcpy (p2, "] of "); + p2 += sizeof ("] of ")-1; + } + } + break; + } + } + } + + strcpy (p2, buffer1); + return buffer2; +} + +/* Return information about ECOFF symbol SYMBOL in RET. */ + +void +ecoff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; /* Ignored. */ + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Print information about an ECOFF symbol. */ + +void +ecoff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + FILE *file = (FILE *)filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + if (ecoffsymbol (symbol)->local) + { + SYMR ecoff_sym; + + (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_sym); + fprintf (file, "ecoff local "); + fprintf_vma (file, (bfd_vma) ecoff_sym.value); + fprintf (file, " %x %x", (unsigned) ecoff_sym.st, + (unsigned) ecoff_sym.sc); + } + else + { + EXTR ecoff_ext; + + (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); + fprintf (file, "ecoff extern "); + fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); + fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st, + (unsigned) ecoff_ext.asym.sc); + } + break; + case bfd_print_symbol_all: + /* Print out the symbols in a reasonable way */ + { + char type; + int pos; + EXTR ecoff_ext; + char jmptbl; + char cobol_main; + char weakext; + + if (ecoffsymbol (symbol)->local) + { + (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext.asym); + type = 'l'; + pos = ((((char *) ecoffsymbol (symbol)->native + - (char *) ecoff_data (abfd)->external_sym) + / backend->external_sym_size) + + ecoff_data (abfd)->symbolic_header.iextMax); + jmptbl = ' '; + cobol_main = ' '; + weakext = ' '; + } + else + { + (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); + type = 'e'; + pos = (((char *) ecoffsymbol (symbol)->native + - (char *) ecoff_data (abfd)->external_ext) + / backend->external_ext_size); + jmptbl = ecoff_ext.jmptbl ? 'j' : ' '; + cobol_main = ecoff_ext.cobol_main ? 'c' : ' '; + weakext = ecoff_ext.weakext ? 'w' : ' '; + } + + fprintf (file, "[%3d] %c ", + pos, type); + fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); + fprintf (file, " st %x sc %x indx %x %c%c%c %s", + (unsigned) ecoff_ext.asym.st, + (unsigned) ecoff_ext.asym.sc, + (unsigned) ecoff_ext.asym.index, + jmptbl, cobol_main, weakext, + symbol->name); + + if (ecoffsymbol (symbol)->fdr != NULL + && ecoff_ext.asym.index != indexNil) + { + unsigned int indx; + int bigendian; + bfd_size_type sym_base; + union aux_ext *aux_base; + + indx = ecoff_ext.asym.index; + + /* sym_base is used to map the fdr relative indices which + appear in the file to the position number which we are + using. */ + sym_base = ecoffsymbol (symbol)->fdr->isymBase; + if (ecoffsymbol (symbol)->local) + sym_base += ecoff_data (abfd)->symbolic_header.iextMax; + + /* aux_base is the start of the aux entries for this file; + asym.index is an offset from this. */ + aux_base = (ecoff_data (abfd)->external_aux + + ecoffsymbol (symbol)->fdr->iauxBase); + + /* The aux entries are stored in host byte order; the + order is indicated by a bit in the fdr. */ + bigendian = ecoffsymbol (symbol)->fdr->fBigendian; + + /* This switch is basically from gcc/mips-tdump.c */ + switch (ecoff_ext.asym.st) + { + case stNil: + case stLabel: + break; + + case stFile: + case stBlock: + fprintf (file, "\n End+1 symbol: %ld", + (long) (indx + sym_base)); + break; + + case stEnd: + if (ecoff_ext.asym.sc == scText + || ecoff_ext.asym.sc == scInfo) + fprintf (file, "\n First symbol: %ld", + (long) (indx + sym_base)); + else + fprintf (file, "\n First symbol: %ld", + (long) (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base)); + break; + + case stProc: + case stStaticProc: + if (ECOFF_IS_STAB (&ecoff_ext.asym)) + ; + else if (ecoffsymbol (symbol)->local) + fprintf (file, "\n End+1 symbol: %-7ld Type: %s", + (long) (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base), + ecoff_type_to_string (abfd, aux_base, indx + 1, + bigendian)); + else + fprintf (file, "\n Local symbol: %d", + (indx + + sym_base + + ecoff_data (abfd)->symbolic_header.iextMax)); + break; + + default: + if (! ECOFF_IS_STAB (&ecoff_ext.asym)) + fprintf (file, "\n Type: %s", + ecoff_type_to_string (abfd, aux_base, indx, + bigendian)); + break; + } + } + } + break; + } +} + +/* Read in the relocs for a section. */ + +static boolean +ecoff_slurp_reloc_table (abfd, section, symbols) + bfd *abfd; + asection *section; + asymbol **symbols; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + arelent *internal_relocs; + bfd_size_type external_reloc_size; + bfd_size_type external_relocs_size; + char *external_relocs; + arelent *rptr; + unsigned int i; + + if (section->relocation != (arelent *) NULL + || section->reloc_count == 0 + || (section->flags & SEC_CONSTRUCTOR) != 0) + return true; + + if (ecoff_slurp_symbol_table (abfd) == false) + return false; + + internal_relocs = (arelent *) bfd_alloc (abfd, + (sizeof (arelent) + * section->reloc_count)); + external_reloc_size = backend->external_reloc_size; + external_relocs_size = external_reloc_size * section->reloc_count; + external_relocs = (char *) bfd_alloc (abfd, external_relocs_size); + if (internal_relocs == (arelent *) NULL + || external_relocs == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0) + return false; + if (bfd_read (external_relocs, 1, external_relocs_size, abfd) + != external_relocs_size) + { + bfd_error = system_call_error; + return false; + } + + for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++) + { + struct internal_reloc intern; + + (*backend->swap_reloc_in) (abfd, + external_relocs + i * external_reloc_size, + &intern); + + if (intern.r_extern) + { + /* r_symndx is an index into the external symbols. */ + BFD_ASSERT (intern.r_symndx >= 0 + && (intern.r_symndx + < ecoff_data (abfd)->symbolic_header.iextMax)); + rptr->sym_ptr_ptr = symbols + intern.r_symndx; + rptr->addend = 0; + } + else if (intern.r_symndx == RELOC_SECTION_NONE + || intern.r_symndx == RELOC_SECTION_ABS) + { + rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + rptr->addend = 0; + } + else + { + CONST char *sec_name; + asection *sec; + + /* r_symndx is a section key. */ + switch (intern.r_symndx) + { + case RELOC_SECTION_TEXT: sec_name = ".text"; break; + case RELOC_SECTION_RDATA: sec_name = ".rdata"; break; + case RELOC_SECTION_DATA: sec_name = ".data"; break; + case RELOC_SECTION_SDATA: sec_name = ".sdata"; break; + case RELOC_SECTION_SBSS: sec_name = ".sbss"; break; + case RELOC_SECTION_BSS: sec_name = ".bss"; break; + case RELOC_SECTION_INIT: sec_name = ".init"; break; + case RELOC_SECTION_LIT8: sec_name = ".lit8"; break; + case RELOC_SECTION_LIT4: sec_name = ".lit4"; break; + case RELOC_SECTION_XDATA: sec_name = ".xdata"; break; + case RELOC_SECTION_PDATA: sec_name = ".pdata"; break; + case RELOC_SECTION_LITA: sec_name = ".lita"; break; + default: abort (); + } + + sec = bfd_get_section_by_name (abfd, sec_name); + if (sec == (asection *) NULL) + abort (); + rptr->sym_ptr_ptr = sec->symbol_ptr_ptr; + + rptr->addend = - bfd_get_section_vma (abfd, sec); + } + + rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section); + + /* Let the backend select the howto field and do any other + required processing. */ + (*backend->finish_reloc) (abfd, &intern, rptr); + } + + bfd_release (abfd, external_relocs); + + section->relocation = internal_relocs; + + return true; +} + +/* Get a canonical list of relocs. */ + +unsigned int +ecoff_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + asection *section; + arelent **relptr; + asymbol **symbols; +{ + unsigned int count; + + if (section->flags & SEC_CONSTRUCTOR) + { + arelent_chain *chain; + + /* This section has relocs made up by us, not the file, so take + them out of their chain and place them into the data area + provided. */ + for (count = 0, chain = section->constructor_chain; + count < section->reloc_count; + count++, chain = chain->next) + *relptr++ = &chain->relent; + } + else + { + arelent *tblptr; + + if (ecoff_slurp_reloc_table (abfd, section, symbols) == false) + return 0; + + tblptr = section->relocation; + if (tblptr == (arelent *) NULL) + return 0; + + for (count = 0; count < section->reloc_count; count++) + *relptr++ = tblptr++; + } + + *relptr = (arelent *) NULL; + + return section->reloc_count; +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +boolean +ecoff_find_nearest_line (abfd, + section, + ignore_symbols, + offset, + filename_ptr, + functionname_ptr, + retline_ptr) + bfd *abfd; + asection *section; + asymbol **ignore_symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *retline_ptr; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + FDR *fdr_ptr; + FDR *fdr_start; + FDR *fdr_end; + FDR *fdr_hold; + bfd_size_type external_pdr_size; + char *pdr_ptr; + char *pdr_end; + PDR pdr; + unsigned char *line_ptr; + unsigned char *line_end; + int lineno; + + /* If we're not in the .text section, we don't have any line + numbers. */ + if (strcmp (section->name, _TEXT) != 0 + || offset < ecoff_data (abfd)->text_start + || offset >= ecoff_data (abfd)->text_end) + return false; + + /* Make sure we have the FDR's. */ + if (ecoff_slurp_symbolic_info (abfd) == false + || bfd_get_symcount (abfd) == 0) + return false; + + /* Each file descriptor (FDR) has a memory address. Here we track + down which FDR we want. The FDR's are stored in increasing + memory order. If speed is ever important, this can become a + binary search. We must ignore FDR's with no PDR entries; they + will have the adr of the FDR before or after them. */ + fdr_start = ecoff_data (abfd)->fdr; + fdr_end = fdr_start + ecoff_data (abfd)->symbolic_header.ifdMax; + fdr_hold = (FDR *) NULL; + for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) + continue; + if (offset < fdr_ptr->adr) + break; + fdr_hold = fdr_ptr; + } + if (fdr_hold == (FDR *) NULL) + return false; + fdr_ptr = fdr_hold; + + /* Each FDR has a list of procedure descriptors (PDR). PDR's also + have an address, which is relative to the FDR address, and are + also stored in increasing memory order. */ + offset -= fdr_ptr->adr; + external_pdr_size = backend->external_pdr_size; + pdr_ptr = ((char *) ecoff_data (abfd)->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; + (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + + /* The address of the first PDR is an offset which applies to the + addresses of all the PDR's. */ + offset += pdr.adr; + + for (pdr_ptr += external_pdr_size; + pdr_ptr < pdr_end; + pdr_ptr += external_pdr_size) + { + (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + if (offset < pdr.adr) + break; + } + + /* Now we can look for the actual line number. The line numbers are + stored in a very funky format, which I won't try to describe. + Note that right here pdr_ptr and pdr hold the PDR *after* the one + we want; we need this to compute line_end. */ + line_end = ecoff_data (abfd)->line; + if (pdr_ptr == pdr_end) + line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine; + else + line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset; + + /* Now change pdr and pdr_ptr to the one we want. */ + pdr_ptr -= external_pdr_size; + (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + + offset -= pdr.adr; + lineno = pdr.lnLow; + line_ptr = (ecoff_data (abfd)->line + + fdr_ptr->cbLineOffset + + pdr.cbLineOffset); + while (line_ptr < line_end) + { + int delta; + int count; + + delta = *line_ptr >> 4; + if (delta >= 0x8) + delta -= 0x10; + count = (*line_ptr & 0xf) + 1; + ++line_ptr; + if (delta == -8) + { + delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); + if (delta >= 0x8000) + delta -= 0x10000; + line_ptr += 2; + } + lineno += delta; + if (offset < count * 4) + break; + offset -= count * 4; + } + + /* If fdr_ptr->rss is -1, then this file does not have full symbols, + at least according to gdb/mipsread.c. */ + if (fdr_ptr->rss == -1) + { + *filename_ptr = NULL; + if (pdr.isym == -1) + *functionname_ptr = NULL; + else + { + EXTR proc_ext; + + (*backend->swap_ext_in) (abfd, + ((char *) ecoff_data (abfd)->external_ext + + pdr.isym * backend->external_ext_size), + &proc_ext); + *functionname_ptr = ecoff_data (abfd)->ssext + proc_ext.asym.iss; + } + } + else + { + SYMR proc_sym; + + *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss; + (*backend->swap_sym_in) (abfd, + ((char *) ecoff_data (abfd)->external_sym + + ((fdr_ptr->isymBase + pdr.isym) + * backend->external_sym_size)), + &proc_sym); + *functionname_ptr = (ecoff_data (abfd)->ss + + fdr_ptr->issBase + + proc_sym.iss); + } + if (lineno == ilineNil) + lineno = 0; + *retline_ptr = lineno; + return true; +} + +/* We can't use the generic linking routines for ECOFF, because we + have to handle all the debugging information. The generic link + routine just works out the section contents and attaches a list of + symbols. + + We link by looping over all the seclets. We make two passes. On + the first we set the actual section contents and determine the size + of the debugging information. On the second we accumulate the + debugging information and write it out. + + This currently always accumulates the debugging information, which + is incorrect, because it ignores the -s and -S options of the + linker. The linker needs to be modified to give us that + information in a more useful format (currently it just provides a + list of symbols which should appear in the output file). */ + +/* Clear the output_has_begun flag for all the input BFD's. We use it + to avoid linking in the debugging information for a BFD more than + once. */ + +static void +ecoff_clear_output_flags (abfd) + bfd *abfd; +{ + register asection *o; + register bfd_seclet_type *p; + + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + for (p = o->seclets_head; + p != (bfd_seclet_type *) NULL; + p = p->next) + if (p->type == bfd_indirect_seclet) + p->u.indirect.section->owner->output_has_begun = false; +} + +/* Handle an indirect seclet on the first pass. Set the contents of + the output section, and accumulate the debugging information if + any. */ + +static boolean +ecoff_rel (output_bfd, seclet, output_section, data, relocateable) + bfd *output_bfd; + bfd_seclet_type *seclet; + asection *output_section; + PTR data; + boolean relocateable; +{ + bfd *input_bfd; + HDRR *output_symhdr; + HDRR *input_symhdr; + + if ((output_section->flags & SEC_HAS_CONTENTS) + && !(output_section->flags & SEC_NEVER_LOAD) + && (output_section->flags & SEC_LOAD) + && seclet->size) + { + data = (PTR) bfd_get_relocated_section_contents (output_bfd, + seclet, + data, + relocateable); + if (bfd_set_section_contents (output_bfd, + output_section, + data, + seclet->offset, + seclet->size) + == false) + { + abort(); + } + } + + input_bfd = seclet->u.indirect.section->owner; + + /* We want to figure out how much space will be required to + incorporate all the debugging information from input_bfd. We use + the output_has_begun field to avoid adding it in more than once. + The actual incorporation is done in the second pass, in + ecoff_get_debug. The code has to parallel that code in its + manipulations of output_symhdr. */ + + if (input_bfd->output_has_begun) + return true; + input_bfd->output_has_begun = true; + + output_symhdr = &ecoff_data (output_bfd)->symbolic_header; + + if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour) + { + asymbol **symbols; + asymbol **sym_ptr; + asymbol **sym_end; + + /* We just accumulate local symbols from a non-ECOFF BFD. The + external symbols are handled separately. */ + + symbols = (asymbol **) bfd_alloc (output_bfd, + get_symtab_upper_bound (input_bfd)); + if (symbols == (asymbol **) NULL) + { + bfd_error = no_memory; + return false; + } + sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); + + for (sym_ptr = symbols; sym_ptr < sym_end; sym_ptr++) + { + size_t len; + + len = strlen ((*sym_ptr)->name); + if (((*sym_ptr)->flags & BSF_EXPORT) == 0) + { + ++output_symhdr->isymMax; + output_symhdr->issMax += len + 1; + } + } + + bfd_release (output_bfd, (PTR) symbols); + + ++output_symhdr->ifdMax; + + return true; + } + + /* We simply add in the information from another ECOFF BFD. First + we make sure we have the symbolic information. */ + if (ecoff_slurp_symbol_table (input_bfd) == false) + return false; + if (bfd_get_symcount (input_bfd) == 0) + return true; + + input_symhdr = &ecoff_data (input_bfd)->symbolic_header; + + /* Figure out how much information we are going to be putting in. + The external symbols are handled separately. */ + output_symhdr->ilineMax += input_symhdr->ilineMax; + output_symhdr->cbLine += input_symhdr->cbLine; + output_symhdr->idnMax += input_symhdr->idnMax; + output_symhdr->ipdMax += input_symhdr->ipdMax; + output_symhdr->isymMax += input_symhdr->isymMax; + output_symhdr->ioptMax += input_symhdr->ioptMax; + output_symhdr->iauxMax += input_symhdr->iauxMax; + output_symhdr->issMax += input_symhdr->issMax; + output_symhdr->ifdMax += input_symhdr->ifdMax; + + /* The RFD's are special, since we create them if needed. */ + if (input_symhdr->crfd > 0) + output_symhdr->crfd += input_symhdr->crfd; + else + output_symhdr->crfd += input_symhdr->ifdMax; + + return true; +} + +/* Handle an arbitrary seclet on the first pass. */ + +static boolean +ecoff_dump_seclet (abfd, seclet, section, data, relocateable) + bfd *abfd; + bfd_seclet_type *seclet; + asection *section; + PTR data; + boolean relocateable; +{ + switch (seclet->type) + { + case bfd_indirect_seclet: + /* The contents of this section come from another one somewhere + else. */ + return ecoff_rel (abfd, seclet, section, data, relocateable); + + case bfd_fill_seclet: + /* Fill in the section with fill.value. This is used to pad out + sections, but we must avoid padding the .bss section. */ + if ((section->flags & SEC_HAS_CONTENTS) == 0) + { + if (seclet->u.fill.value != 0) + abort (); + } + else + { + char *d = (char *) bfd_alloc (abfd, seclet->size); + unsigned int i; + boolean ret; + + for (i = 0; i < seclet->size; i+=2) + d[i] = seclet->u.fill.value >> 8; + for (i = 1; i < seclet->size; i+=2) + d[i] = seclet->u.fill.value; + ret = bfd_set_section_contents (abfd, section, d, seclet->offset, + seclet->size); + bfd_release (abfd, (PTR) d); + return ret; + } + break; + + default: + abort(); + } + + return true; +} + +/* Add a string to the debugging information we are accumulating for a + file. Return the offset from the fdr string base or from the + external string base. */ + +static long +ecoff_add_string (output_bfd, fdr, string, external) + bfd *output_bfd; + FDR *fdr; + CONST char *string; + boolean external; +{ + HDRR *symhdr; + size_t len; + long ret; + + symhdr = &ecoff_data (output_bfd)->symbolic_header; + len = strlen (string); + if (external) + { + strcpy (ecoff_data (output_bfd)->ssext + symhdr->issExtMax, string); + ret = symhdr->issExtMax; + symhdr->issExtMax += len + 1; + } + else + { + strcpy (ecoff_data (output_bfd)->ss + symhdr->issMax, string); + ret = fdr->cbSs; + symhdr->issMax += len + 1; + fdr->cbSs += len + 1; + } + return ret; +} + +/* Accumulate the debugging information from an input section. */ + +static boolean +ecoff_get_debug (output_bfd, seclet, section, relocateable) + bfd *output_bfd; + bfd_seclet_type *seclet; + asection *section; + boolean relocateable; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (output_bfd); + const bfd_size_type external_sym_size = backend->external_sym_size; + const bfd_size_type external_pdr_size = backend->external_pdr_size; + const bfd_size_type external_fdr_size = backend->external_fdr_size; + const bfd_size_type external_rfd_size = backend->external_rfd_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = backend->swap_sym_in; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = backend->swap_sym_out; + void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)) + = backend->swap_pdr_in; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = backend->swap_fdr_out; + void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) + = backend->swap_rfd_out; + bfd *input_bfd; + HDRR *output_symhdr; + HDRR *input_symhdr; + ecoff_data_type *output_ecoff; + ecoff_data_type *input_ecoff; + unsigned int count; + char *sym_out; + ecoff_symbol_type *esym_ptr; + ecoff_symbol_type *esym_end; + FDR *fdr_ptr; + FDR *fdr_end; + char *fdr_out; + + input_bfd = seclet->u.indirect.section->owner; + + /* Don't get the information more than once. */ + if (input_bfd->output_has_begun) + return true; + input_bfd->output_has_begun = true; + + output_ecoff = ecoff_data (output_bfd); + output_symhdr = &output_ecoff->symbolic_header; + + if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour) + { + FDR fdr; + asymbol **symbols; + asymbol **sym_ptr; + asymbol **sym_end; + + /* This is not an ECOFF BFD. Just gather the symbols. */ + + memset (&fdr, 0, sizeof fdr); + + fdr.adr = bfd_get_section_vma (output_bfd, section) + seclet->offset; + fdr.issBase = output_symhdr->issMax; + fdr.cbSs = 0; + fdr.rss = ecoff_add_string (output_bfd, + &fdr, + bfd_get_filename (input_bfd), + false); + fdr.isymBase = output_symhdr->isymMax; + + /* Get the local symbols from the input BFD. */ + symbols = (asymbol **) bfd_alloc (output_bfd, + get_symtab_upper_bound (input_bfd)); + if (symbols == (asymbol **) NULL) + { + bfd_error = no_memory; + return false; + } + sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); + + /* Handle the local symbols. Any external symbols are handled + separately. */ + fdr.csym = 0; + for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++) + { + SYMR internal_sym; + + if (((*sym_ptr)->flags & BSF_EXPORT) != 0) + continue; + memset (&internal_sym, 0, sizeof internal_sym); + internal_sym.iss = ecoff_add_string (output_bfd, + &fdr, + (*sym_ptr)->name, + false); + + if (bfd_is_com_section ((*sym_ptr)->section) + || (*sym_ptr)->section == &bfd_und_section) + internal_sym.value = (*sym_ptr)->value; + else + internal_sym.value = ((*sym_ptr)->value + + (*sym_ptr)->section->output_offset + + (*sym_ptr)->section->output_section->vma); + internal_sym.st = stNil; + internal_sym.sc = scUndefined; + internal_sym.index = indexNil; + (*swap_sym_out) (output_bfd, &internal_sym, + ((char *) output_ecoff->external_sym + + output_symhdr->isymMax * external_sym_size)); + ++fdr.csym; + ++output_symhdr->isymMax; + } + + bfd_release (output_bfd, (PTR) symbols); + + /* Leave everything else in the FDR zeroed out. This will cause + the lang field to be langC. The fBigendian field will + indicate little endian format, but it doesn't matter because + it only applies to aux fields and there are none. */ + + (*swap_fdr_out) (output_bfd, &fdr, + ((char *) output_ecoff->external_fdr + + output_symhdr->ifdMax * external_fdr_size)); + ++output_symhdr->ifdMax; + return true; + } + + /* This is an ECOFF BFD. We want to grab the information from + input_bfd and attach it to output_bfd. */ + count = bfd_get_symcount (input_bfd); + if (count == 0) + return true; + input_ecoff = ecoff_data (input_bfd); + input_symhdr = &input_ecoff->symbolic_header; + + /* I think that it is more efficient to simply copy the debugging + information from the input BFD to the output BFD. Because ECOFF + uses relative pointers for most of the debugging information, + only a little of it has to be changed at all. */ + + /* Swap in the local symbols, adjust their values, and swap them out + again. The external symbols are handled separately. */ + sym_out = ((char *) output_ecoff->external_sym + + output_symhdr->isymMax * external_sym_size); + + esym_ptr = ecoff_data (input_bfd)->canonical_symbols; + esym_end = esym_ptr + count; + for (; esym_ptr < esym_end; esym_ptr++) + { + if (esym_ptr->local) + { + SYMR sym; + + (*swap_sym_in) (input_bfd, esym_ptr->native, &sym); + + /* If we're producing an executable, move common symbols + into bss. */ + if (relocateable == false) + { + if (sym.sc == scCommon) + sym.sc = scBss; + else if (sym.sc == scSCommon) + sym.sc = scSBss; + } + + if (! bfd_is_com_section (esym_ptr->symbol.section) + && (esym_ptr->symbol.flags & BSF_DEBUGGING) == 0 + && esym_ptr->symbol.section != &bfd_und_section) + sym.value = (esym_ptr->symbol.value + + esym_ptr->symbol.section->output_offset + + esym_ptr->symbol.section->output_section->vma); + (*swap_sym_out) (output_bfd, &sym, sym_out); + sym_out += external_sym_size; + } + } + + /* That should have accounted for all the local symbols in + input_bfd. */ + + /* Copy the information that does not need swapping. */ + memcpy (output_ecoff->line + output_symhdr->cbLine, + input_ecoff->line, + input_symhdr->cbLine * sizeof (unsigned char)); + memcpy (output_ecoff->external_aux + output_symhdr->iauxMax, + input_ecoff->external_aux, + input_symhdr->iauxMax * sizeof (union aux_ext)); + memcpy (output_ecoff->ss + output_symhdr->issMax, + input_ecoff->ss, + input_symhdr->issMax * sizeof (char)); + + /* Some of the information may need to be swapped. */ + if (output_bfd->xvec->header_byteorder_big_p + == input_bfd->xvec->header_byteorder_big_p) + { + /* The two BFD's have the same endianness, so memcpy will + suffice. */ + if (input_symhdr->idnMax > 0) + memcpy (((char *) output_ecoff->external_dnr + + output_symhdr->idnMax * backend->external_dnr_size), + input_ecoff->external_dnr, + input_symhdr->idnMax * backend->external_dnr_size); + if (input_symhdr->ipdMax > 0) + memcpy (((char *) output_ecoff->external_pdr + + output_symhdr->ipdMax * external_pdr_size), + input_ecoff->external_pdr, + input_symhdr->ipdMax * external_pdr_size); + if (input_symhdr->ioptMax > 0) + memcpy (((char *) output_ecoff->external_opt + + output_symhdr->ioptMax * backend->external_opt_size), + input_ecoff->external_opt, + input_symhdr->ioptMax * backend->external_opt_size); + } + else + { + bfd_size_type sz; + char *in; + char *end; + char *out; + + /* The two BFD's have different endianness, so we must swap + everything in and out. This code would always work, but it + would be slow in the normal case. */ + sz = backend->external_dnr_size; + in = (char *) input_ecoff->external_dnr; + end = in + input_symhdr->idnMax * sz; + out = (char *) output_ecoff->external_dnr + output_symhdr->idnMax * sz; + for (; in < end; in += sz, out += sz) + { + DNR dnr; + + (*backend->swap_dnr_in) (input_bfd, in, &dnr); + (*backend->swap_dnr_out) (output_bfd, &dnr, out); + } + + sz = external_pdr_size; + in = (char *) input_ecoff->external_pdr; + end = in + input_symhdr->ipdMax * sz; + out = (char *) output_ecoff->external_pdr + output_symhdr->ipdMax * sz; + for (; in < end; in += sz, out += sz) + { + PDR pdr; + + (*swap_pdr_in) (input_bfd, in, &pdr); + (*backend->swap_pdr_out) (output_bfd, &pdr, out); + } + + sz = backend->external_opt_size; + in = (char *) input_ecoff->external_opt; + end = in + input_symhdr->ioptMax * sz; + out = (char *) output_ecoff->external_opt + output_symhdr->ioptMax * sz; + for (; in < end; in += sz, out += sz) + { + OPTR opt; + + (*backend->swap_opt_in) (input_bfd, in, &opt); + (*backend->swap_opt_out) (output_bfd, &opt, out); + } + } + + /* Set ifdbase so that the external symbols know how to adjust their + ifd values. */ + input_ecoff->ifdbase = output_symhdr->ifdMax; + + fdr_ptr = input_ecoff->fdr; + fdr_end = fdr_ptr + input_symhdr->ifdMax; + fdr_out = ((char *) output_ecoff->external_fdr + + output_symhdr->ifdMax * external_fdr_size); + for (; fdr_ptr < fdr_end; fdr_ptr++, fdr_out += external_fdr_size) + { + FDR fdr; + unsigned long pdr_off; + + fdr = *fdr_ptr; + + /* The memory address for this fdr is the address for the seclet + plus the offset to this fdr within input_bfd. For some + reason the offset of the first procedure pointer is also + added in. */ + if (fdr.cpd == 0) + pdr_off = 0; + else + { + PDR pdr; + + (*swap_pdr_in) (input_bfd, + ((char *) input_ecoff->external_pdr + + fdr.ipdFirst * external_pdr_size), + &pdr); + pdr_off = pdr.adr; + } + fdr.adr = (bfd_get_section_vma (output_bfd, section) + + seclet->offset + + (fdr_ptr->adr - input_ecoff->fdr->adr) + + pdr_off); + + fdr.issBase += output_symhdr->issMax; + fdr.isymBase += output_symhdr->isymMax; + fdr.ilineBase += output_symhdr->ilineMax; + fdr.ioptBase += output_symhdr->ioptMax; + fdr.ipdFirst += output_symhdr->ipdMax; + fdr.iauxBase += output_symhdr->iauxMax; + fdr.rfdBase += output_symhdr->crfd; + + /* If there are no RFD's, we are going to add some. We don't + want to adjust irfd for this, so that all the FDR's can share + the RFD's. */ + if (input_symhdr->crfd == 0) + fdr.crfd = input_symhdr->ifdMax; + + if (fdr.cbLine != 0) + fdr.cbLineOffset += output_symhdr->cbLine; + + (*swap_fdr_out) (output_bfd, &fdr, fdr_out); + } + + if (input_symhdr->crfd > 0) + { + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = backend->swap_rfd_in; + char *rfd_in; + char *rfd_end; + char *rfd_out; + + /* Swap and adjust the RFD's. RFD's are only created by the + linker, so this will only be necessary if one of the input + files is the result of a partial link. Presumably all + necessary RFD's are present. */ + rfd_in = (char *) input_ecoff->external_rfd; + rfd_end = rfd_in + input_symhdr->crfd * external_rfd_size; + rfd_out = ((char *) output_ecoff->external_rfd + + output_symhdr->crfd * external_rfd_size); + for (; + rfd_in < rfd_end; + rfd_in += external_rfd_size, rfd_out += external_rfd_size) + { + RFDT rfd; + + (*swap_rfd_in) (input_bfd, rfd_in, &rfd); + rfd += output_symhdr->ifdMax; + (*swap_rfd_out) (output_bfd, &rfd, rfd_out); + } + output_symhdr->crfd += input_symhdr->crfd; + } + else + { + char *rfd_out; + char *rfd_end; + RFDT rfd; + + /* Create RFD's. Some of the debugging information includes + relative file indices. These indices are taken as indices to + the RFD table if there is one, or to the global table if + there is not. If we did not create RFD's, we would have to + parse and adjust all the debugging information which contains + file indices. */ + rfd = output_symhdr->ifdMax; + rfd_out = ((char *) output_ecoff->external_rfd + + output_symhdr->crfd * external_rfd_size); + rfd_end = rfd_out + input_symhdr->ifdMax * external_rfd_size; + for (; rfd_out < rfd_end; rfd_out += external_rfd_size, rfd++) + (*swap_rfd_out) (output_bfd, &rfd, rfd_out); + output_symhdr->crfd += input_symhdr->ifdMax; + } + + /* Combine the register masks. Not all of these are used on all + targets, but that's OK because only the relevant ones will be + swapped in and out. */ + { + int i; + + output_ecoff->gprmask |= input_ecoff->gprmask; + output_ecoff->fprmask |= input_ecoff->fprmask; + for (i = 0; i < 4; i++) + output_ecoff->cprmask[i] |= input_ecoff->cprmask[i]; + } + + /* Update the counts. */ + output_symhdr->ilineMax += input_symhdr->ilineMax; + output_symhdr->cbLine += input_symhdr->cbLine; + output_symhdr->idnMax += input_symhdr->idnMax; + output_symhdr->ipdMax += input_symhdr->ipdMax; + output_symhdr->isymMax += input_symhdr->isymMax; + output_symhdr->ioptMax += input_symhdr->ioptMax; + output_symhdr->iauxMax += input_symhdr->iauxMax; + output_symhdr->issMax += input_symhdr->issMax; + output_symhdr->ifdMax += input_symhdr->ifdMax; + + return true; +} + +/* This is the actual link routine. It makes two passes over all the + seclets. */ + +boolean +ecoff_bfd_seclet_link (abfd, data, relocateable) + bfd *abfd; + PTR data; + boolean relocateable; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + HDRR *symhdr; + int ipass; + register asection *o; + register bfd_seclet_type *p; + asymbol **sym_ptr_ptr; + bfd_size_type debug_align; + bfd_size_type size; + char *raw; + + /* We accumulate the debugging information counts in the symbolic + header. */ + symhdr = &ecoff_data (abfd)->symbolic_header; + symhdr->magic = backend->sym_magic; + /* FIXME: What should the version stamp be? */ + symhdr->vstamp = 0; + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* We need to copy over the debugging symbols from each input BFD. + When we do this copying, we have to adjust the text address in + the FDR structures, so we have to know the text address used for + the input BFD. Since we only want to copy the symbols once per + input BFD, but we are going to look at each input BFD multiple + times (once for each section it provides), we arrange to always + look at the text section first. That means that when we copy the + debugging information, we always know the text address. So we + actually do each pass in two sub passes; first the text sections, + then the non-text sections. We use the output_has_begun flag to + determine whether we have copied over the debugging information + yet. */ + + /* Do the first pass: set the output section contents and count the + debugging information. */ + ecoff_clear_output_flags (abfd); + for (ipass = 0; ipass < 2; ipass++) + { + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + /* If this is a fake section, just forget it. The register + information is handled in another way. */ + if (strcmp (o->name, SCOMMON) == 0 + || strcmp (o->name, REGINFO) == 0) + continue; + + /* For SEC_CODE sections, (flags & SEC_CODE) == 0 is false, + so they are done on pass 0. For other sections the + expression is true, so they are done on pass 1. */ + if (((o->flags & SEC_CODE) == 0) != ipass) + continue; + + for (p = o->seclets_head; + p != (bfd_seclet_type *) NULL; + p = p->next) + { + if (ecoff_dump_seclet (abfd, p, o, data, relocateable) + == false) + return false; + } + } + } + + /* We handle the external symbols differently. We use the ones + attached to the output_bfd. The linker will have already + determined which symbols are to be attached. Here we just + determine how much space we will need for them. */ + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr != NULL) + { + asymbol **sym_end; + + sym_end = sym_ptr_ptr + bfd_get_symcount (abfd); + for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++) + { + if (((*sym_ptr_ptr)->flags & BSF_DEBUGGING) == 0 + && ((*sym_ptr_ptr)->flags & BSF_LOCAL) == 0) + { + ++symhdr->iextMax; + symhdr->issExtMax += strlen ((*sym_ptr_ptr)->name) + 1; + } + } + } + + /* Adjust the counts so that structures are longword aligned. */ + debug_align = backend->debug_align; + --debug_align; + symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align; + symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align; + symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align; + + /* Now the counts in symhdr are the correct size for the debugging + information. We allocate the right amount of space, and reset + the counts so that the second pass can use them as indices. It + would be possible to output the debugging information directly to + the file in pass 2, rather than to build it in memory and then + write it out. Outputting to the file would require a lot of + seeks and small writes, though, and I think this approach is + faster. */ + size = (symhdr->cbLine * sizeof (unsigned char) + + symhdr->idnMax * backend->external_dnr_size + + symhdr->ipdMax * backend->external_pdr_size + + symhdr->isymMax * backend->external_sym_size + + symhdr->ioptMax * backend->external_opt_size + + symhdr->iauxMax * sizeof (union aux_ext) + + symhdr->issMax * sizeof (char) + + symhdr->issExtMax * sizeof (char) + + symhdr->ifdMax * backend->external_fdr_size + + symhdr->crfd * backend->external_rfd_size + + symhdr->iextMax * backend->external_ext_size); + raw = (char *) bfd_alloc (abfd, size); + if (raw == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + ecoff_data (abfd)->raw_size = size; + ecoff_data (abfd)->raw_syments = (PTR) raw; + + /* Initialize the raw pointers. */ +#define SET(field, count, type, size) \ + ecoff_data (abfd)->field = (type) raw; \ + raw += symhdr->count * size + + SET (line, cbLine, unsigned char *, sizeof (unsigned char)); + SET (external_dnr, idnMax, PTR, backend->external_dnr_size); + SET (external_pdr, ipdMax, PTR, backend->external_pdr_size); + SET (external_sym, isymMax, PTR, backend->external_sym_size); + SET (external_opt, ioptMax, PTR, backend->external_opt_size); + SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext)); + SET (ss, issMax, char *, sizeof (char)); + SET (ssext, issExtMax, char *, sizeof (char)); + SET (external_fdr, ifdMax, PTR, backend->external_fdr_size); + SET (external_rfd, crfd, PTR, backend->external_rfd_size); + SET (external_ext, iextMax, PTR, backend->external_ext_size); +#undef SET + + /* Reset the counts so the second pass can use them to know how far + it has gotten. */ + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* Do the second pass: accumulate the debugging information. */ + ecoff_clear_output_flags (abfd); + for (ipass = 0; ipass < 2; ipass++) + { + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + if (strcmp (o->name, SCOMMON) == 0 + || strcmp (o->name, REGINFO) == 0) + continue; + if (((o->flags & SEC_CODE) == 0) != ipass) + continue; + for (p = o->seclets_head; + p != (bfd_seclet_type *) NULL; + p = p->next) + { + if (p->type == bfd_indirect_seclet) + { + if (ecoff_get_debug (abfd, p, o, relocateable) == false) + return false; + } + } + } + } + + /* Put in the external symbols. */ + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr != NULL) + { + const bfd_size_type external_ext_size = backend->external_ext_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->swap_ext_in; + void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)) + = backend->swap_ext_out; + char *ssext; + char *external_ext; + + ssext = ecoff_data (abfd)->ssext; + external_ext = (char *) ecoff_data (abfd)->external_ext; + for (; *sym_ptr_ptr != NULL; sym_ptr_ptr++) + { + asymbol *sym_ptr; + EXTR esym; + + sym_ptr = *sym_ptr_ptr; + + if ((sym_ptr->flags & BSF_DEBUGGING) != 0 + || (sym_ptr->flags & BSF_LOCAL) != 0) + continue; + + /* The native pointer can be NULL for a symbol created by + the linker via ecoff_make_empty_symbol. */ + if (bfd_asymbol_flavour (sym_ptr) != bfd_target_ecoff_flavour + || ecoffsymbol (sym_ptr)->native == NULL) + { + esym.jmptbl = 0; + esym.cobol_main = 0; + esym.weakext = 0; + esym.reserved = 0; + esym.ifd = ifdNil; + /* FIXME: we can do better than this for st and sc. */ + esym.asym.st = stGlobal; + esym.asym.sc = scAbs; + esym.asym.reserved = 0; + esym.asym.index = indexNil; + } + else + { + ecoff_symbol_type *ecoff_sym_ptr; + + ecoff_sym_ptr = ecoffsymbol (sym_ptr); + if (ecoff_sym_ptr->local) + abort (); + (*swap_ext_in) (abfd, ecoff_sym_ptr->native, &esym); + + /* If we're producing an executable, move common symbols + into bss. */ + if (relocateable == false) + { + if (esym.asym.sc == scCommon) + esym.asym.sc = scBss; + else if (esym.asym.sc == scSCommon) + esym.asym.sc = scSBss; + } + + /* Adjust the FDR index for the symbol by that used for + the input BFD. */ + esym.ifd += ecoff_data (bfd_asymbol_bfd (sym_ptr))->ifdbase; + } + + esym.asym.iss = symhdr->issExtMax; + + if (bfd_is_com_section (sym_ptr->section) + || sym_ptr->section == &bfd_und_section) + esym.asym.value = sym_ptr->value; + else + esym.asym.value = (sym_ptr->value + + sym_ptr->section->output_offset + + sym_ptr->section->output_section->vma); + + (*swap_ext_out) (abfd, &esym, external_ext); + + ecoff_set_sym_index (sym_ptr, symhdr->iextMax); + + external_ext += external_ext_size; + ++symhdr->iextMax; + + strcpy (ssext + symhdr->issExtMax, sym_ptr->name); + symhdr->issExtMax += strlen (sym_ptr->name) + 1; + } + } + + /* Adjust the counts so that structures are longword aligned. */ + symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align; + symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align; + symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align; + + return true; +} + +/* Set the architecture. The supported architecture is stored in the + backend pointer. We always set the architecture anyhow, since many + callers ignore the return value. */ + +boolean +ecoff_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + bfd_default_set_arch_mach (abfd, arch, machine); + return arch == ecoff_backend (abfd)->arch; +} + +/* Get the size of the section headers. We do not output the .scommon + section which we created in ecoff_mkobject, nor do we output any + .reginfo section. */ + +int +ecoff_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + asection *current; + int c; + + c = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + if (strcmp (current->name, SCOMMON) != 0 + && strcmp (current->name, REGINFO) != 0) + ++c; + + return (bfd_coff_filhsz (abfd) + + bfd_coff_aoutsz (abfd) + + c * bfd_coff_scnhsz (abfd)); +} + + +/* Get the contents of a section. This is where we handle reading the + .reginfo section, which implicitly holds the contents of an + ecoff_reginfo structure. */ + +boolean +ecoff_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + ecoff_data_type *tdata = ecoff_data (abfd); + struct ecoff_reginfo s; + int i; + + if (strcmp (section->name, REGINFO) != 0) + return bfd_generic_get_section_contents (abfd, section, location, + offset, count); + + s.gp_value = tdata->gp; + s.gprmask = tdata->gprmask; + for (i = 0; i < 4; i++) + s.cprmask[i] = tdata->cprmask[i]; + s.fprmask = tdata->fprmask; + + /* bfd_get_section_contents has already checked that the offset and + size is reasonable. We don't have to worry about swapping or any + such thing; the .reginfo section is defined such that the + contents are an ecoff_reginfo structure as seen on the host. */ + memcpy (location, ((char *) &s) + offset, count); + return true; +} + +/* Calculate the file position for each section, and set + reloc_filepos. */ + +static void +ecoff_compute_section_file_positions (abfd) + bfd *abfd; +{ + asection *current; + file_ptr sofar; + file_ptr old_sofar; + boolean first_data; + + if (bfd_get_start_address (abfd)) + abfd->flags |= EXEC_P; + + sofar = ecoff_sizeof_headers (abfd, false); + + first_data = true; + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + /* Only deal with sections which have contents */ + if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0 + || strcmp (current->name, SCOMMON) == 0 + || strcmp (current->name, REGINFO) == 0) + continue; + + /* On Ultrix, the data sections in an executable file must be + aligned to a page boundary within the file. This does not + affect the section size, though. FIXME: Does this work for + other platforms? */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0 + && first_data != false + && (current->flags & SEC_CODE) == 0) + { + const bfd_vma round = ecoff_backend (abfd)->round; + + sofar = (sofar + round - 1) &~ (round - 1); + first_data = false; + } + + /* Align the sections in the file to the same boundary on + which they are aligned in virtual memory. */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + + current->filepos = sofar; + + sofar += current->_raw_size; + + /* make sure that this section is of the right size too */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + current->_raw_size += sofar - old_sofar; + } + + ecoff_data (abfd)->reloc_filepos = sofar; +} + +/* Set the contents of a section. This is where we handle setting the + contents of the .reginfo section, which implicitly holds a + ecoff_reginfo structure. */ + +boolean +ecoff_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (abfd->output_has_begun == false) + ecoff_compute_section_file_positions (abfd); + + if (strcmp (section->name, REGINFO) == 0) + { + ecoff_data_type *tdata = ecoff_data (abfd); + struct ecoff_reginfo s; + int i; + + /* If the caller is only changing part of the structure, we must + retrieve the current information before the memcpy. */ + if (offset != 0 || count != sizeof (struct ecoff_reginfo)) + { + s.gp_value = tdata->gp; + s.gprmask = tdata->gprmask; + for (i = 0; i < 4; i++) + s.cprmask[i] = tdata->cprmask[i]; + s.fprmask = tdata->fprmask; + } + + /* bfd_set_section_contents has already checked that the offset + and size is reasonable. We don't have to worry about + swapping or any such thing; the .reginfo section is defined + such that the contents are an ecoff_reginfo structure as seen + on the host. */ + memcpy (((char *) &s) + offset, location, count); + + tdata->gp = s.gp_value; + tdata->gprmask = s.gprmask; + for (i = 0; i < 4; i++) + tdata->cprmask[i] = s.cprmask[i]; + tdata->fprmask = s.fprmask; + + return true; + + } + + bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET); + + if (count != 0) + return (bfd_write (location, 1, count, abfd) == count) ? true : false; + + return true; +} + +/* Write out an ECOFF file. */ + +boolean +ecoff_write_object_contents (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_vma round = backend->round; + const bfd_size_type filhsz = bfd_coff_filhsz (abfd); + const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd); + const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd); + const bfd_size_type external_hdr_size = backend->external_hdr_size; + const bfd_size_type external_reloc_size = backend->external_reloc_size; + void (* const swap_reloc_out) PARAMS ((bfd *, + const struct internal_reloc *, + PTR)) + = backend->swap_reloc_out; + asection *current; + unsigned int count; + file_ptr scn_base; + file_ptr reloc_base; + file_ptr sym_base; + unsigned long reloc_size; + unsigned long text_size; + unsigned long text_start; + unsigned long data_size; + unsigned long data_start; + unsigned long bss_size; + PTR buff; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + int i; + + bfd_error = system_call_error; + + if(abfd->output_has_begun == false) + ecoff_compute_section_file_positions(abfd); + + if (abfd->sections != (asection *) NULL) + scn_base = abfd->sections->filepos; + else + scn_base = 0; + reloc_base = ecoff_data (abfd)->reloc_filepos; + + count = 1; + reloc_size = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + { + if (strcmp (current->name, SCOMMON) == 0 + || strcmp (current->name, REGINFO) == 0) + continue; + current->target_index = count; + ++count; + if (current->reloc_count != 0) + { + bfd_size_type relsize; + + current->rel_filepos = reloc_base; + relsize = current->reloc_count * external_reloc_size; + reloc_size += relsize; + reloc_base += relsize; + } + else + current->rel_filepos = 0; + } + + sym_base = reloc_base + reloc_size; + + /* At least on Ultrix, the symbol table of an executable file must + be aligned to a page boundary. FIXME: Is this true on other + platforms? */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + sym_base = (sym_base + round - 1) &~ (round - 1); + + ecoff_data (abfd)->sym_filepos = sym_base; + + if ((abfd->flags & D_PAGED) != 0) + text_size = ecoff_sizeof_headers (abfd, false); + else + text_size = 0; + text_start = 0; + data_size = 0; + data_start = 0; + bss_size = 0; + + /* Write section headers to the file. */ + + buff = (PTR) alloca (scnhsz); + internal_f.f_nscns = 0; + if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0) + return false; + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + struct internal_scnhdr section; + bfd_vma vma; + + if (strcmp (current->name, SCOMMON) == 0) + { + BFD_ASSERT (bfd_get_section_size_before_reloc (current) == 0 + && current->reloc_count == 0); + continue; + } + if (strcmp (current->name, REGINFO) == 0) + { + BFD_ASSERT (current->reloc_count == 0); + continue; + } + + ++internal_f.f_nscns; + + strncpy (section.s_name, current->name, sizeof section.s_name); + + /* FIXME: is this correct for shared libraries? I think it is + but I have no platform to check. Ian Lance Taylor. */ + vma = bfd_get_section_vma (abfd, current); + if (strcmp (current->name, _LIB) == 0) + section.s_vaddr = 0; + else + section.s_vaddr = vma; + + section.s_paddr = vma; + section.s_size = bfd_get_section_size_before_reloc (current); + + /* If this section is unloadable then the scnptr will be 0. */ + if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + section.s_scnptr = 0; + else + section.s_scnptr = current->filepos; + section.s_relptr = current->rel_filepos; + + /* FIXME: the lnnoptr of the .sbss or .sdata section of an + object file produced by the assembler is supposed to point to + information about how much room is required by objects of + various different sizes. I think this only matters if we + want the linker to compute the best size to use, or + something. I don't know what happens if the information is + not present. */ + section.s_lnnoptr = 0; + + section.s_nreloc = current->reloc_count; + section.s_nlnno = 0; + section.s_flags = ecoff_sec_to_styp_flags (current->name, + current->flags); + + bfd_coff_swap_scnhdr_out (abfd, (PTR) §ion, buff); + if (bfd_write (buff, 1, scnhsz, abfd) != scnhsz) + return false; + + if ((section.s_flags & STYP_TEXT) != 0) + { + text_size += bfd_get_section_size_before_reloc (current); + if (text_start == 0 || text_start > vma) + text_start = vma; + } + else if ((section.s_flags & STYP_RDATA) != 0 + || (section.s_flags & STYP_DATA) != 0 + || (section.s_flags & STYP_LIT8) != 0 + || (section.s_flags & STYP_LIT4) != 0 + || (section.s_flags & STYP_SDATA) != 0) + { + data_size += bfd_get_section_size_before_reloc (current); + if (data_start == 0 || data_start > vma) + data_start = vma; + } + else if ((section.s_flags & STYP_BSS) != 0 + || (section.s_flags & STYP_SBSS) != 0) + bss_size += bfd_get_section_size_before_reloc (current); + } + + /* Set up the file header. */ + + internal_f.f_magic = ecoff_get_magic (abfd); + + /* We will NOT put a fucking timestamp in the header here. Every + time you put it back, I will come in and take it out again. I'm + sorry. This field does not belong here. We fill it with a 0 so + it compares the same but is not a reasonable time. -- + gnu@cygnus.com. */ + internal_f.f_timdat = 0; + + if (bfd_get_symcount (abfd) != 0) + { + /* The ECOFF f_nsyms field is not actually the number of + symbols, it's the size of symbolic information header. */ + internal_f.f_nsyms = external_hdr_size; + internal_f.f_symptr = sym_base; + } + else + { + internal_f.f_nsyms = 0; + internal_f.f_symptr = 0; + } + + internal_f.f_opthdr = aoutsz; + + internal_f.f_flags = F_LNNO; + if (reloc_size == 0) + internal_f.f_flags |= F_RELFLG; + if (bfd_get_symcount (abfd) == 0) + internal_f.f_flags |= F_LSYMS; + if (abfd->flags & EXEC_P) + internal_f.f_flags |= F_EXEC; + + if (! abfd->xvec->byteorder_big_p) + internal_f.f_flags |= F_AR32WR; + else + internal_f.f_flags |= F_AR32W; + + /* Set up the ``optional'' header. */ + if ((abfd->flags & D_PAGED) != 0) + internal_a.magic = ECOFF_AOUT_ZMAGIC; + else + internal_a.magic = ECOFF_AOUT_OMAGIC; + + /* FIXME: This is what Ultrix puts in, and it makes the Ultrix + linker happy. But, is it right? */ + internal_a.vstamp = 0x20a; + + /* At least on Ultrix, these have to be rounded to page boundaries. + FIXME: Is this true on other platforms? */ + if ((abfd->flags & D_PAGED) != 0) + { + internal_a.tsize = (text_size + round - 1) &~ (round - 1); + internal_a.text_start = text_start &~ (round - 1); + internal_a.dsize = (data_size + round - 1) &~ (round - 1); + internal_a.data_start = data_start &~ (round - 1); + } + else + { + internal_a.tsize = text_size; + internal_a.text_start = text_start; + internal_a.dsize = data_size; + internal_a.data_start = data_start; + } + + /* On Ultrix, the initial portions of the .sbss and .bss segments + are at the end of the data section. The bsize field in the + optional header records how many bss bytes are required beyond + those in the data section. The value is not rounded to a page + boundary. */ + if (bss_size < internal_a.dsize - data_size) + bss_size = 0; + else + bss_size -= internal_a.dsize - data_size; + internal_a.bsize = bss_size; + internal_a.bss_start = internal_a.data_start + internal_a.dsize; + + internal_a.entry = bfd_get_start_address (abfd); + + internal_a.gp_value = ecoff_data (abfd)->gp; + + internal_a.gprmask = ecoff_data (abfd)->gprmask; + internal_a.fprmask = ecoff_data (abfd)->fprmask; + for (i = 0; i < 4; i++) + internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i]; + + /* Write out the file header and the optional header. */ + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return false; + + buff = (PTR) alloca (filhsz); + bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff); + if (bfd_write (buff, 1, filhsz, abfd) != filhsz) + return false; + + buff = (PTR) alloca (aoutsz); + bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff); + if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz) + return false; + + /* Write out the relocs. */ + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + arelent **reloc_ptr_ptr; + arelent **reloc_end; + char *out_ptr; + + if (current->reloc_count == 0) + continue; + + buff = bfd_alloc (abfd, current->reloc_count * external_reloc_size); + if (buff == NULL) + { + bfd_error = no_memory; + return false; + } + + reloc_ptr_ptr = current->orelocation; + reloc_end = reloc_ptr_ptr + current->reloc_count; + out_ptr = (char *) buff; + for (; + reloc_ptr_ptr < reloc_end; + reloc_ptr_ptr++, out_ptr += external_reloc_size) + { + arelent *reloc; + asymbol *sym; + struct internal_reloc in; + + memset (&in, 0, sizeof in); + + reloc = *reloc_ptr_ptr; + sym = *reloc->sym_ptr_ptr; + + in.r_vaddr = reloc->address + bfd_get_section_vma (abfd, current); + in.r_type = reloc->howto->type; + + if ((sym->flags & BSF_SECTION_SYM) == 0) + { + in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr); + in.r_extern = 1; + } + else + { + CONST char *name; + + name = bfd_get_section_name (abfd, bfd_get_section (sym)); + if (strcmp (name, ".text") == 0) + in.r_symndx = RELOC_SECTION_TEXT; + else if (strcmp (name, ".rdata") == 0) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else + abort (); + in.r_extern = 0; + } + + (*swap_reloc_out) (abfd, &in, (PTR) out_ptr); + } + + if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0) + return false; + if (bfd_write (buff, external_reloc_size, current->reloc_count, abfd) + != external_reloc_size * current->reloc_count) + return false; + bfd_release (abfd, buff); + } + + /* Write out the symbolic debugging information. */ + if (bfd_get_symcount (abfd) > 0) + { + HDRR *symhdr; + unsigned long sym_offset; + + /* Set up the offsets in the symbolic header. */ + symhdr = &ecoff_data (abfd)->symbolic_header; + sym_offset = ecoff_data (abfd)->sym_filepos + external_hdr_size; + +#define SET(offset, size, ptr) \ + if (symhdr->size == 0) \ + symhdr->offset = 0; \ + else \ + symhdr->offset = (((char *) ecoff_data (abfd)->ptr \ + - (char *) ecoff_data (abfd)->raw_syments) \ + + sym_offset); + + SET (cbLineOffset, cbLine, line); + SET (cbDnOffset, idnMax, external_dnr); + SET (cbPdOffset, ipdMax, external_pdr); + SET (cbSymOffset, isymMax, external_sym); + SET (cbOptOffset, ioptMax, external_opt); + SET (cbAuxOffset, iauxMax, external_aux); + SET (cbSsOffset, issMax, ss); + SET (cbSsExtOffset, issExtMax, ssext); + SET (cbFdOffset, ifdMax, external_fdr); + SET (cbRfdOffset, crfd, external_rfd); + SET (cbExtOffset, iextMax, external_ext); +#undef SET + + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos, + SEEK_SET) != 0) + return false; + buff = (PTR) alloca (external_hdr_size); + (*backend->swap_hdr_out) (abfd, &ecoff_data (abfd)->symbolic_header, + buff); + if (bfd_write (buff, 1, external_hdr_size, abfd) != external_hdr_size) + return false; + if (bfd_write ((PTR) ecoff_data (abfd)->raw_syments, 1, + ecoff_data (abfd)->raw_size, abfd) + != ecoff_data (abfd)->raw_size) + return false; + } + else if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + { + char c; + + /* A demand paged executable must occupy an even number of + pages. */ + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, + SEEK_SET) != 0) + return false; + if (bfd_read (&c, 1, 1, abfd) == 0) + c = 0; + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, + SEEK_SET) != 0) + return false; + if (bfd_write (&c, 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/* Archive handling. ECOFF uses what appears to be a unique type of + archive header (which I call an armap). The byte ordering of the + armap and the contents are encoded in the name of the armap itself. + At least for now, we only support archives with the same byte + ordering in the armap and the contents. + + The first four bytes in the armap are the number of symbol + definitions. This is always a power of two. + + This is followed by the symbol definitions. Each symbol definition + occupies 8 bytes. The first four bytes are the offset from the + start of the armap strings to the null-terminated string naming + this symbol. The second four bytes are the file offset to the + archive member which defines this symbol. If the second four bytes + are 0, then this is not actually a symbol definition, and it should + be ignored. + + The symbols are hashed into the armap with a closed hashing scheme. + See the functions below for the details of the algorithm. + + We could use the hash table when looking up symbols in a library. + This would require a new BFD target entry point to replace the + bfd_get_next_mapent function used by the linker. + + After the symbol definitions comes four bytes holding the size of + the string table, followed by the string table itself. */ + +/* The name of an archive headers looks like this: + __________E[BL]E[BL]_ (with a trailing space). + The trailing space is changed to an X if the archive is changed to + indicate that the armap is out of date. + + The Alpha seems to use ________64E[BL]E[BL]_. */ + +#define ARMAP_BIG_ENDIAN 'B' +#define ARMAP_LITTLE_ENDIAN 'L' +#define ARMAP_MARKER 'E' +#define ARMAP_START_LENGTH 10 +#define ARMAP_HEADER_MARKER_INDEX 10 +#define ARMAP_HEADER_ENDIAN_INDEX 11 +#define ARMAP_OBJECT_MARKER_INDEX 12 +#define ARMAP_OBJECT_ENDIAN_INDEX 13 +#define ARMAP_END_INDEX 14 +#define ARMAP_END "_ " + +/* This is a magic number used in the hashing algorithm. */ +#define ARMAP_HASH_MAGIC 0x9dd68ab5 + +/* This returns the hash value to use for a string. It also sets + *REHASH to the rehash adjustment if the first slot is taken. SIZE + is the number of entries in the hash table, and HLOG is the log + base 2 of SIZE. */ + +static unsigned int +ecoff_armap_hash (s, rehash, size, hlog) + CONST char *s; + unsigned int *rehash; + unsigned int size; + unsigned int hlog; +{ + unsigned int hash; + + hash = *s++; + while (*s != '\0') + hash = ((hash >> 27) | (hash << 5)) + *s++; + hash *= ARMAP_HASH_MAGIC; + *rehash = (hash & (size - 1)) | 1; + return hash >> (32 - hlog); +} + +/* Read in the armap. */ + +boolean +ecoff_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + unsigned int i; + struct areltdata *mapdata; + bfd_size_type parsed_size; + char *raw_armap; + struct artdata *ardata; + unsigned int count; + char *raw_ptr; + struct symdef *symdef_ptr; + char *stringbase; + + /* Get the name of the first element. */ + i = bfd_read ((PTR) nextname, 1, 16, abfd); + if (i == 0) + return true; + if (i != 16) + return false; + + bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + + /* Irix 4.0.5F apparently can use either an ECOFF armap or a + standard COFF armap. We could move the ECOFF armap stuff into + bfd_slurp_armap, but that seems inappropriate since no other + target uses this format. Instead, we check directly for a COFF + armap. */ + if (strncmp (nextname, "/ ", 16) == 0) + return bfd_slurp_armap (abfd); + + /* See if the first element is an armap. */ + if (strncmp (nextname, ecoff_backend (abfd)->armap_start, + ARMAP_START_LENGTH) != 0 + || nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER + || (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN + && nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) + || nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER + || (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN + && nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) + || strncmp (nextname + ARMAP_END_INDEX, + ARMAP_END, sizeof ARMAP_END - 1) != 0) + { + bfd_has_map (abfd) = false; + return true; + } + + /* Make sure we have the right byte ordering. */ + if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) + ^ (abfd->xvec->header_byteorder_big_p != false)) + || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) + ^ (abfd->xvec->byteorder_big_p != false))) + { + bfd_error = wrong_format; + return false; + } + + /* Read in the armap. */ + ardata = bfd_ardata (abfd); + mapdata = snarf_ar_hdr (abfd); + if (mapdata == (struct areltdata *) NULL) + return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); + + raw_armap = (char *) bfd_alloc (abfd, parsed_size); + if (raw_armap == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + + if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size) + { + bfd_error = malformed_archive; + bfd_release (abfd, (PTR) raw_armap); + return false; + } + + count = bfd_h_get_32 (abfd, (PTR) raw_armap); + + ardata->symdef_count = 0; + ardata->cache = (struct ar_cache *) NULL; + + /* This code used to overlay the symdefs over the raw archive data, + but that doesn't work on a 64 bit host. */ + + stringbase = raw_armap + count * 8 + 8; + +#ifdef CHECK_ARMAP_HASH + { + unsigned int hlog; + + /* Double check that I have the hashing algorithm right by making + sure that every symbol can be looked up successfully. */ + hlog = 0; + for (i = 1; i < count; i <<= 1) + hlog++; + BFD_ASSERT (i == count); + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + { + unsigned int name_offset, file_offset; + unsigned int hash, rehash, srch; + + name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + if (file_offset == 0) + continue; + hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count, + hlog); + if (hash == i) + continue; + + /* See if we can rehash to this location. */ + for (srch = (hash + rehash) & (count - 1); + srch != hash && srch != i; + srch = (srch + rehash) & (count - 1)) + BFD_ASSERT (bfd_h_get_32 (abfd, (PTR) (raw_armap + 8 + srch * 8)) + != 0); + BFD_ASSERT (srch == i); + } + } + +#endif /* CHECK_ARMAP_HASH */ + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + if (bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)) != 0) + ++ardata->symdef_count; + + symdef_ptr = ((struct symdef *) + bfd_alloc (abfd, + ardata->symdef_count * sizeof (struct symdef))); + ardata->symdefs = (carsym *) symdef_ptr; + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + { + unsigned int name_offset, file_offset; + + file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + if (file_offset == 0) + continue; + name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + symdef_ptr->s.name = stringbase + name_offset; + symdef_ptr->file_offset = file_offset; + ++symdef_ptr; + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary. */ + ardata->first_file_filepos += ardata->first_file_filepos % 2; + + bfd_has_map (abfd) = true; + + return true; +} + +/* Write out an armap. */ + +boolean +ecoff_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + unsigned int hashsize, hashlog; + unsigned int symdefsize; + int padit; + unsigned int stringsize; + unsigned int mapsize; + file_ptr firstreal; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + bfd_byte temp[4]; + bfd_byte *hashtable; + bfd *current; + bfd *last_elt; + + /* Ultrix appears to use as a hash table size the least power of two + greater than twice the number of entries. */ + for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++) + ; + hashsize = 1 << hashlog; + + symdefsize = hashsize * 8; + padit = stridx % 2; + stringsize = stridx + padit; + + /* Include 8 bytes to store symdefsize and stringsize in output. */ + mapsize = symdefsize + stringsize + 8; + + firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength; + + memset ((PTR) &hdr, 0, sizeof hdr); + + /* Work out the ECOFF armap name. */ + strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start); + hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER; + hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] = + (abfd->xvec->header_byteorder_big_p + ? ARMAP_BIG_ENDIAN + : ARMAP_LITTLE_ENDIAN); + hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER; + hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] = + abfd->xvec->byteorder_big_p ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN; + memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1); + + /* Write the timestamp of the archive header to be just a little bit + later than the timestamp of the file, otherwise the linker will + complain that the index is out of date. Actually, the Ultrix + linker just checks the archive name; the GNU linker may check the + date. */ + stat (abfd->filename, &statbuf); + sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60)); + + /* The DECstation uses zeroes for the uid, gid and mode of the + armap. */ + hdr.ar_uid[0] = '0'; + hdr.ar_gid[0] = '0'; + hdr.ar_mode[0] = '0'; + + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + + hdr.ar_fmag[0] = '`'; + hdr.ar_fmag[1] = '\n'; + + /* Turn all null bytes in the header into spaces. */ + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') + (((char *)(&hdr))[i]) = ' '; + + if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + return false; + + bfd_h_put_32 (abfd, hashsize, temp); + if (bfd_write (temp, 1, 4, abfd) != 4) + return false; + + hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize); + + current = abfd->archive_head; + last_elt = current; + for (i = 0; i < orl_count; i++) + { + unsigned int hash, rehash; + + /* Advance firstreal to the file position of this archive + element. */ + if (((bfd *) map[i].pos) != last_elt) + { + do + { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } + while (current != (bfd *) map[i].pos); + } + + last_elt = current; + + hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog); + if (bfd_h_get_32 (abfd, (PTR) (hashtable + (hash * 8) + 4)) != 0) + { + unsigned int srch; + + /* The desired slot is already taken. */ + for (srch = (hash + rehash) & (hashsize - 1); + srch != hash; + srch = (srch + rehash) & (hashsize - 1)) + if (bfd_h_get_32 (abfd, (PTR) (hashtable + (srch * 8) + 4)) == 0) + break; + + BFD_ASSERT (srch != hash); + + hash = srch; + } + + bfd_h_put_32 (abfd, map[i].namidx, (PTR) (hashtable + hash * 8)); + bfd_h_put_32 (abfd, firstreal, (PTR) (hashtable + hash * 8 + 4)); + } + + if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize) + return false; + + bfd_release (abfd, hashtable); + + /* Now write the strings. */ + bfd_h_put_32 (abfd, stringsize, temp); + if (bfd_write (temp, 1, 4, abfd) != 4) + return false; + for (i = 0; i < orl_count; i++) + { + bfd_size_type len; + + len = strlen (*map[i].name) + 1; + if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len) + return false; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for DECstation ar we use a null. */ + if (padit) + { + if (bfd_write ("\0", 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/* See whether this BFD is an archive. If it is, read in the armap + and the extended name table. */ + +bfd_target * +ecoff_archive_p (abfd) + bfd *abfd; +{ + char armag[SARMAG + 1]; + + if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG + || strncmp (armag, ARMAG, SARMAG) != 0) + { + bfd_error = wrong_format; + return (bfd_target *) NULL; + } + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of + assignment. */ + abfd->tdata.aout_ar_data = + (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata)); + + if (bfd_ardata (abfd) == (struct artdata *) NULL) + { + bfd_error = no_memory; + return (bfd_target *) NULL; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + + if (ecoff_slurp_armap (abfd) == false + || ecoff_slurp_extended_name_table (abfd) == false) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = (struct artdata *) NULL; + return (bfd_target *) NULL; + } + + return abfd->xvec; +} diff --git a/gnu/usr.bin/gdb/bfd/elf.c b/gnu/usr.bin/gdb/bfd/elf.c new file mode 100644 index 00000000000..2fcf2f14343 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/elf.c @@ -0,0 +1,248 @@ +/* ELF executable support for BFD. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* + +SECTION + ELF backends + + BFD support for ELF formats is being worked on. + Currently, the best supported back ends are for sparc and i386 + (running svr4 or Solaris 2). + + Documentation of the internals of the support code still needs + to be written. The code is changing quickly enough that we + haven't bothered yet. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "libelf.h" + +/* Standard ELF hash function. Do not change this function; you will + cause invalid hash tables to be generated. (Well, you would if this + were being used yet.) */ +unsigned long +DEFUN (bfd_elf_hash, (name), + CONST unsigned char *name) +{ + unsigned long h = 0; + unsigned long g; + int ch; + + while ((ch = *name++) != '\0') + { + h = (h << 4) + ch; + if ((g = (h & 0xf0000000)) != 0) + { + h ^= g >> 24; + h &= ~g; + } + } + return h; +} + +/* Read a specified number of bytes at a specified offset in an ELF + file, into a newly allocated buffer, and return a pointer to the + buffer. */ + +static char * +DEFUN (elf_read, (abfd, offset, size), + bfd * abfd AND + long offset AND + int size) +{ + char *buf; + + if ((buf = bfd_alloc (abfd, size)) == NULL) + { + bfd_error = no_memory; + return NULL; + } + if (bfd_seek (abfd, offset, SEEK_SET) == -1) + { + bfd_error = system_call_error; + return NULL; + } + if (bfd_read ((PTR) buf, size, 1, abfd) != size) + { + bfd_error = system_call_error; + return NULL; + } + return buf; +} + +boolean +DEFUN (elf_mkobject, (abfd), bfd * abfd) +{ + /* this just does initialization */ + /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ + elf_tdata (abfd) = (struct elf_obj_tdata *) + bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (elf_tdata (abfd) == 0) + { + bfd_error = no_memory; + return false; + } + /* since everything is done at close time, do we need any + initialization? */ + + return true; +} + +char * +DEFUN (elf_get_str_section, (abfd, shindex), + bfd * abfd AND + unsigned int shindex) +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab = NULL; + unsigned int offset; + unsigned int shstrtabsize; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp == 0 || i_shdrp[shindex] == 0) + return 0; + + shstrtab = i_shdrp[shindex]->rawdata; + if (shstrtab == NULL) + { + /* No cached one, attempt to read, and cache what we read. */ + offset = i_shdrp[shindex]->sh_offset; + shstrtabsize = i_shdrp[shindex]->sh_size; + shstrtab = elf_read (abfd, offset, shstrtabsize); + i_shdrp[shindex]->rawdata = (void *) shstrtab; + } + return shstrtab; +} + +char * +DEFUN (elf_string_from_elf_section, (abfd, shindex, strindex), + bfd * abfd AND + unsigned int shindex AND + unsigned int strindex) +{ + Elf_Internal_Shdr *hdr; + + if (strindex == 0) + return ""; + + hdr = elf_elfsections (abfd)[shindex]; + + if (!hdr->rawdata + && elf_get_str_section (abfd, shindex) == NULL) + return NULL; + + return ((char *) hdr->rawdata) + strindex; +} + +/* +INTERNAL_FUNCTION + bfd_elf_find_section + +SYNOPSIS + struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); + +DESCRIPTION + Helper functions for GDB to locate the string tables. + Since BFD hides string tables from callers, GDB needs to use an + internal hook to find them. Sun's .stabstr, in particular, + isn't even pointed to by the .stab section, so ordinary + mechanisms wouldn't work to find it, even if we had some. +*/ + +struct elf_internal_shdr * +DEFUN (bfd_elf_find_section, (abfd, name), + bfd * abfd AND + char *name) +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab; + unsigned int max; + unsigned int i; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp != NULL) + { + shstrtab = elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx); + if (shstrtab != NULL) + { + max = elf_elfheader (abfd)->e_shnum; + for (i = 1; i < max; i++) + if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name)) + return i_shdrp[i]; + } + } + return 0; +} + +const struct bfd_elf_arch_map bfd_elf_arch_map[] = { + { bfd_arch_sparc, EM_SPARC }, + { bfd_arch_i386, EM_386 }, + { bfd_arch_m68k, EM_68K }, + { bfd_arch_m88k, EM_88K }, + { bfd_arch_i860, EM_860 }, + { bfd_arch_mips, EM_MIPS }, + { bfd_arch_hppa, EM_HPPA }, +}; + +const int bfd_elf_arch_map_size = sizeof (bfd_elf_arch_map) / sizeof (bfd_elf_arch_map[0]); + +const char *const bfd_elf_section_type_names[] = { + "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", + "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", + "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", +}; + +/* ELF relocs are against symbols. If we are producing relocateable + output, and the reloc is against an external symbol, and nothing + has given us any additional addend, the resulting reloc will also + be against the same symbol. In such a case, we don't want to + change anything about the way the reloc is handled, since it will + all be done at final link time. Rather than put special case code + into bfd_perform_relocation, all the reloc types use this howto + function. It just short circuits the reloc if producing + relocateable output against an external symbol. */ + +bfd_reloc_status_type +bfd_elf_generic_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; +{ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + return bfd_reloc_continue; +} diff --git a/gnu/usr.bin/gdb/bfd/format.c b/gnu/usr.bin/gdb/bfd/format.c new file mode 100644 index 00000000000..6a80ed7082a --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/format.c @@ -0,0 +1,258 @@ +/* Generic BFD support for file formats. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + File Formats + + A format is a BFD concept of high level file contents. The + formats supported by BFD are: + + o bfd_object + + The BFD may contain data, symbols, relocations and debug info. + + o bfd_archive + + The BFD contains other BFDs and an optional index. + + o bfd_core + + The BFD contains the result of an executable core dump. + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +extern bfd_target *target_vector[]; +extern bfd_target *default_vector[]; + + +/* +FUNCTION + bfd_check_format + +SYNOPSIS + boolean bfd_check_format(bfd *abfd, bfd_format format); + +DESCRIPTION + This routine is supplied a BFD and a format. It attempts to + verify if the file attached to the BFD is indeed compatible + with the format specified (ie, one of <>, + <> or <>). + + If the BFD has been set to a specific @var{target} before the + call, only the named target and format combination will be + checked. If the target has not been set, or has been set to + <> then all the known target backends will be + interrogated to determine a match. If the default target + matches, it is used. If not, exactly one target must recognize + the file, or an error results. + + The function returns <> on success, otherwise <> + with one of the following error codes: + + o invalid_operation - + if <> is not one of <>, <> or + <>. + + o system_call_error - + if an error occured during a read - even some file mismatches + can cause system_call_errors + + o file_not_recognised - + none of the backends recognised the file format + + o file_ambiguously_recognized - + more than one backend recognised the file format. + +*/ + +boolean +DEFUN(bfd_check_format,(abfd, format), + bfd *abfd AND + bfd_format format) +{ + bfd_target **target, *save_targ, *right_targ; + int match_count; + + if (!bfd_read_p (abfd) || + ((int)(abfd->format) < (int)bfd_unknown) || + ((int)(abfd->format) >= (int)bfd_type_end)) { + bfd_error = invalid_operation; + return false; + } + + if (abfd->format != bfd_unknown) + return (abfd->format == format)? true: false; + + + /* Since the target type was defaulted, check them + all in the hope that one will be uniquely recognized. */ + + save_targ = abfd->xvec; + match_count = 0; + right_targ = 0; + + + /* presume the answer is yes */ + abfd->format = format; + + /* If the target type was explicitly specified, just check that target. */ + + if (!abfd->target_defaulted) { + bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* rewind! */ + + right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (right_targ) { + abfd->xvec = right_targ; /* Set the target as returned */ + return true; /* File position has moved, BTW */ + } + } + + for (target = target_vector; *target != NULL; target++) { + bfd_target *temp; + + abfd->xvec = *target; /* Change BFD's target temporarily */ + bfd_seek (abfd, (file_ptr)0, SEEK_SET); + /* If _bfd_check_format neglects to set bfd_error, assume wrong_format. + We didn't used to even pay any attention to bfd_error, so I suspect + that some _bfd_check_format might have this problem. */ + bfd_error = wrong_format; + temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (temp) { /* This format checks out as ok! */ + right_targ = temp; + match_count++; + /* If this is the default target, accept it, even if other targets + might match. People who want those other targets have to set + the GNUTARGET variable. */ + if (temp == default_vector[0]) + { + match_count = 1; + break; + } +#ifdef GNU960 + /* Big- and little-endian b.out archives look the same, but it doesn't + * matter: there is no difference in their headers, and member file byte + * orders will (I hope) be handled appropriately by bfd. Ditto for big + * and little coff archives. And the 4 coff/b.out object formats are + * unambiguous. So accept the first match we find. + */ + break; +#endif + } else if (bfd_error != wrong_format) { + abfd->xvec = save_targ; + abfd->format = bfd_unknown; + return false; + } + } + + if (match_count == 1) { + abfd->xvec = right_targ; /* Change BFD's target permanently */ + return true; /* File position has moved, BTW */ + } + + abfd->xvec = save_targ; /* Restore original target type */ + abfd->format = bfd_unknown; /* Restore original format */ + bfd_error = ((match_count == 0) ? file_not_recognized : + file_ambiguously_recognized); + return false; +} + + +/* +FUNCTION + bfd_set_format + +SYNOPSIS + boolean bfd_set_format(bfd *, bfd_format); + +DESCRIPTION + This function sets the file format of the supplied BFD to the + format requested. If the target set in the BFD does not + support the format requested, the format is illegal or the BFD + is not open for writing than an error occurs. + +*/ + +boolean +DEFUN(bfd_set_format,(abfd, format), + bfd *abfd AND + bfd_format format) +{ + + if (bfd_read_p (abfd) || + ((int)abfd->format < (int)bfd_unknown) || + ((int)abfd->format >= (int)bfd_type_end)) { + bfd_error = invalid_operation; + return false; + } + + if (abfd->format != bfd_unknown) + return (abfd->format == format) ? true:false; + + /* presume the answer is yes */ + abfd->format = format; + + if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) { + abfd->format = bfd_unknown; + return false; + } + + return true; +} + + +/* +FUNCTION + bfd_format_string + +SYNOPSIS + CONST char *bfd_format_string(bfd_format); + +DESCRIPTION + This function takes one argument, and enumerated type + (bfd_format) and returns a pointer to a const string + <>, <>, <>, <> or <> + depending upon the value of the enumeration. +*/ + +CONST char * +DEFUN(bfd_format_string,(format), + bfd_format format) +{ + if (((int)format <(int) bfd_unknown) + || ((int)format >=(int) bfd_type_end)) + return "invalid"; + + switch (format) { + case bfd_object: + return "object"; /* linker/assember/compiler output */ + case bfd_archive: + return "archive"; /* object archive file */ + case bfd_core: + return "core"; /* core dump */ + default: + return "unknown"; + } +} diff --git a/gnu/usr.bin/gdb/bfd/freebsd386.c b/gnu/usr.bin/gdb/bfd/freebsd386.c new file mode 100644 index 00000000000..9c269097470 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/freebsd386.c @@ -0,0 +1,111 @@ +/* BFD back-end for i386 a.out binaries under BSD. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* This data should be correct for the format used under all the various + BSD ports for 386 machines. */ + +#define BYTES_IN_WORD 4 +#define ARCH 32 + +/* ZMAGIC files never have the header in the text. */ +#define N_HEADER_IN_TEXT(x) 0 + +/* ZMAGIC files start at address 0. This does not apply to QMAGIC. */ +#define TEXT_START_ADDR 0 + +#define PAGE_SIZE 4096 +#define SEGMENT_SIZE PAGE_SIZE + +#define DEFAULT_ARCH bfd_arch_i386 +#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_386_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(freebsd386_,OP) +#define TARGETNAME "a.out-freebsd-386" + +#define N_MAGIC(ex) \ + ((ex).a_info & 0xffff) +#define N_MACHTYPE(ex) \ + ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETMID_NET(ex) : \ + ((ex).a_info >> 16) & 0x03ff ) +#define N_FLAGS(ex) \ + ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETFLAG_NET(ex) : \ + ((ex).a_info >> 26) & 0x3f ) +#define N_SET_INFO(ex,mag,mid,flag) \ + ( (ex).a_info = (((flag) & 0x3f) <<26) | (((mid) & 0x03ff) << 16) | \ + ((mag) & 0xffff) ) + +#define N_GETMAGIC_NET(ex) \ + (ntohl((ex).a_info) & 0xffff) +#define N_GETMID_NET(ex) \ + ((ntohl((ex).a_info) >> 16) & 0x03ff) +#define N_GETFLAG_NET(ex) \ + ((ntohl((ex).a_info) >> 26) & 0x3f) +#define N_SETMAGIC_NET(ex,mag,mid,flag) \ + ( (ex).a_info = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \ + (((mag)&0xffff)) ) ) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#define N_ALIGN(ex,x) \ + (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC || \ + N_GETMAGIC_NET(ex) == ZMAGIC || N_GETMAGIC_NET(ex) == QMAGIC ? \ + ((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) : (x)) + +/* Valid magic number check. */ +#define N_BADMAG(ex) \ + (N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != NMAGIC && \ + N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC && \ + N_GETMAGIC_NET(ex) != OMAGIC && N_GETMAGIC_NET(ex) != NMAGIC && \ + N_GETMAGIC_NET(ex) != ZMAGIC && N_GETMAGIC_NET(ex) != QMAGIC) + +/* Address of the bottom of the text segment. */ +#define N_TXTADDR(ex) \ + ((N_MAGIC(ex) == OMAGIC || N_MAGIC(ex) == NMAGIC || \ + N_MAGIC(ex) == ZMAGIC) ? 0 : PAGE_SIZE) + +/* Address of the bottom of the data segment. */ +#define N_DATADDR(ex) \ + N_ALIGN(ex, N_TXTADDR(ex) + (ex).a_text) + +/* Text segment offset. */ +#define N_TXTOFF(ex) \ + (N_MAGIC(ex) == ZMAGIC ? PAGE_SIZE : (N_MAGIC(ex) == QMAGIC || \ + N_GETMAGIC_NET(ex) == ZMAGIC) ? 0 : EXEC_BYTES_SIZE) + +/* Data segment offset. */ +#define N_DATOFF(ex) \ + N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text) + +/* Relocation table offset. */ +#define N_RELOFF(ex) \ + N_ALIGN(ex, N_DATOFF(ex) + (ex).a_data) + +/* Symbol table offset. */ +#define N_SYMOFF(ex) \ + (N_RELOFF(ex) + (ex).a_trsize + (ex).a_drsize) + +/* String table offset. */ +#define N_STROFF(ex) (N_SYMOFF(ex) + (ex).a_syms) + +#define NO_SWAP_MAGIC /* magic number already in correct endian format */ + +#include "aout-target.h" diff --git a/gnu/usr.bin/gdb/bfd/init.c b/gnu/usr.bin/gdb/bfd/init.c new file mode 100644 index 00000000000..30a275935c1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/init.c @@ -0,0 +1,78 @@ +/* bfd initialization stuff + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +extern void DEFUN_VOID (bfd_section_init); + +static boolean initialized = false; + +/* +SECTION + Initialization + + This is the initialization section + +*/ + +/* +FUNCTION + bfd_init + +SYNOPSIS + void bfd_init(void); + +DESCRIPTION + This routine must be called before any other bfd function to + initialize magical internal data structures. +*/ + +void DEFUN_VOID(bfd_init) +{ + if (initialized == false) { + initialized = true; + + bfd_arch_init(); + } +} + + +/* +INTERNAL_FUNCTION + bfd_check_init + +DESCRIPTION + This routine is called before any other bfd function using + initialized data is used to ensure that the structures have + been initialized. Soon this function will go away, and the bfd + library will assume that bfd_init has been called. + +SYNOPSIS + void bfd_check_init(void); +*/ + +void DEFUN_VOID(bfd_check_init) +{ + if (initialized == false) { + bfd_init(); + } +} diff --git a/gnu/usr.bin/gdb/bfd/libaout.h b/gnu/usr.bin/gdb/bfd/libaout.h new file mode 100644 index 00000000000..0d99d0c43db --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libaout.h @@ -0,0 +1,393 @@ +/* BFD back-end data structures for a.out (and similar) files. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* We try to encapsulate the differences in the various a.out file + variants in a few routines, and otherwise share large masses of code. + This means we only have to fix bugs in one place, most of the time. */ + +/* Parameterize the a.out code based on whether it is being built + for a 32-bit architecture or a 64-bit architecture. */ +#if ARCH_SIZE==64 +#define GET_WORD bfd_h_get_64 +#define GET_SWORD bfd_h_get_signed_64 +#define PUT_WORD bfd_h_put_64 +#ifndef NAME +#define NAME(x,y) CAT3(x,_64_,y) +#endif +#define JNAME(x) CAT(x,_64) +#define BYTES_IN_WORD 8 +#else /* ARCH_SIZE == 32 */ +#define GET_WORD bfd_h_get_32 +#define GET_SWORD bfd_h_get_signed_32 +#define PUT_WORD bfd_h_put_32 +#ifndef NAME +#define NAME(x,y) CAT3(x,_32_,y) +#endif +#define JNAME(x) CAT(x,_32) +#define BYTES_IN_WORD 4 +#endif /* ARCH_SIZE==32 */ + +/* Declare these types at file level, since they are used in parameter + lists, which have wierd scope. */ +struct external_exec; +struct internal_exec; + +/* Back-end information for various a.out targets. */ +struct aout_backend_data +{ + /* Are ZMAGIC files mapped contiguously? If so, the text section may + need more padding, if the segment size (granularity for memory access + control) is larger than the page size. */ + unsigned char zmagic_mapped_contiguous; + /* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the + text section, which starts immediately after the file header. + If not, the text section starts on the next page. */ + unsigned char text_includes_header; + + /* If the text section VMA isn't specified, and we need an absolute + address, use this as the default. If we're producing a relocatable + file, zero is always used. */ + /* ?? Perhaps a callback would be a better choice? Will this do anything + reasonable for a format that handles multiple CPUs with different + load addresses for each? */ + bfd_vma default_text_vma; + + /* Callback for setting the page and segment sizes, if they can't be + trivially determined from the architecture. */ + boolean (*set_sizes) PARAMS ((bfd *)); + + /* zmagic files only. For go32, the length of the exec header contributes + to the size of the text section in the file for alignment purposes but + does *not* get counted in the length of the text section. */ + unsigned char exec_header_not_counted; +}; +#define aout_backend_info(abfd) \ + ((CONST struct aout_backend_data *)((abfd)->xvec->backend_data)) + +/* This is the layout in memory of a "struct exec" while we process it. + All 'lengths' are given as a number of bytes. + All 'alignments' are for relinkable files only; an alignment of + 'n' indicates the corresponding segment must begin at an + address that is a multiple of (2**n). */ + +struct internal_exec +{ + long a_info; /* Magic number and flags, packed */ + bfd_vma a_text; /* length of text, in bytes */ + bfd_vma a_data; /* length of data, in bytes */ + bfd_vma a_bss; /* length of uninitialized data area in mem */ + bfd_vma a_syms; /* length of symbol table data in file */ + bfd_vma a_entry; /* start address */ + bfd_vma a_trsize; /* length of text's relocation info, in bytes */ + bfd_vma a_drsize; /* length of data's relocation info, in bytes */ + /* Added for i960 */ + bfd_vma a_tload; /* Text runtime load address */ + bfd_vma a_dload; /* Data runtime load address */ + unsigned char a_talign; /* Alignment of text segment */ + unsigned char a_dalign; /* Alignment of data segment */ + unsigned char a_balign; /* Alignment of bss segment */ + char a_relaxable; /* Enough info for linker relax */ +}; + +/* Magic number is written +< MSB > +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > +*/ +/* Magic number for NetBSD is + +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< >< MAGIC NUMBER > +*/ + +enum machine_type { + M_UNKNOWN = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* skip a bunch so we don't run into any of suns numbers */ + M_386 = 100, + M_29K = 101, /* AMD 29000 */ + M_386_DYNIX = 102, /* Sequent running dynix */ + M_386_NETBSD = 134, /* NetBSD/386 binary */ + M_MIPS1 = 151, /* MIPS R2000/R3000 binary */ + M_MIPS2 = 152, /* MIPS R4000/R6000 binary */ + M_HP200 = 200, /* HP 200 (68010) BSD binary */ + M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */ + M_HPUX = (0x20c % 256)/* HP 200/300 HPUX binary */ +}; + +#define N_DYNAMIC(exec) ((exec).a_info & 0x8000000) + +#ifndef N_MAGIC +# define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif + +#ifndef N_MACHTYPE +# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#endif + +#ifndef N_FLAGS +# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#endif + +#ifndef N_SET_INFO +# define N_SET_INFO(exec, magic, type, flags) \ +((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#endif + +#ifndef N_SET_MAGIC +# define N_SET_MAGIC(exec, magic) \ +((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) +#endif + +#ifndef N_SET_MACHTYPE +# define N_SET_MACHTYPE(exec, machtype) \ +((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) +#endif + +#ifndef N_SET_FLAGS +# define N_SET_FLAGS(exec, flags) \ +((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) +#endif + +typedef struct aout_symbol { + asymbol symbol; + short desc; + char other; + unsigned char type; +} aout_symbol_type; + +/* The `tdata' struct for all a.out-like object file formats. + Various things depend on this struct being around any time an a.out + file is being handled. An example is dbxread.c in GDB. */ + +struct aoutdata { + struct internal_exec *hdr; /* exec file header */ + aout_symbol_type *symbols; /* symtab for input bfd */ + + /* For ease, we do this */ + asection *textsec; + asection *datasec; + asection *bsssec; + + /* We remember these offsets so that after check_file_format, we have + no dependencies on the particular format of the exec_hdr. */ + file_ptr sym_filepos; + file_ptr str_filepos; + + /* Size of a relocation entry in external form */ + unsigned reloc_entry_size; + + /* Size of a symbol table entry in external form */ + unsigned symbol_entry_size; + + /* Page size - needed for alignment of demand paged files. */ + unsigned long page_size; + + /* Segment size - needed for alignment of demand paged files. */ + unsigned long segment_size; + + unsigned exec_bytes_size; + unsigned vma_adjusted : 1; + + /* used when a bfd supports several highly similar formats */ + enum { + default_format = 0, + gnu_encap_format } subformat; + + enum { + undecided_magic = 0, + z_magic, + o_magic, + n_magic } magic; +}; + +struct aout_data_struct { + struct aoutdata a; + struct internal_exec e; +}; + +#define adata(bfd) ((bfd)->tdata.aout_data->a) +#define exec_hdr(bfd) (adata(bfd).hdr) +#define obj_aout_symbols(bfd) (adata(bfd).symbols) +#define obj_textsec(bfd) (adata(bfd).textsec) +#define obj_datasec(bfd) (adata(bfd).datasec) +#define obj_bsssec(bfd) (adata(bfd).bsssec) +#define obj_sym_filepos(bfd) (adata(bfd).sym_filepos) +#define obj_str_filepos(bfd) (adata(bfd).str_filepos) +#define obj_reloc_entry_size(bfd) (adata(bfd).reloc_entry_size) +#define obj_symbol_entry_size(bfd) (adata(bfd).symbol_entry_size) +#define obj_aout_subformat(bfd) (adata(bfd).subformat) + +/* We take the address of the first element of an asymbol to ensure that the + macro is only ever applied to an asymbol */ +#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd)) + +/* Prototype declarations for functions defined in aoutx.h */ + +boolean +NAME(aout,squirt_out_relocs) PARAMS ((bfd *abfd, asection *section)); + +bfd_target * +NAME(aout,some_aout_object_p) PARAMS ((bfd *abfd, + struct internal_exec *execp, + bfd_target * (*callback)(bfd *))); + +boolean +NAME(aout,mkobject) PARAMS ((bfd *abfd)); + +enum machine_type +NAME(aout,machine_type) PARAMS ((enum bfd_architecture arch, + unsigned long machine)); + +boolean +NAME(aout,set_arch_mach) PARAMS ((bfd *abfd, enum bfd_architecture arch, + unsigned long machine)); + +boolean +NAME(aout,new_section_hook) PARAMS ((bfd *abfd, asection *newsect)); + +boolean +NAME(aout,set_section_contents) PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, bfd_size_type count)); + +asymbol * +NAME(aout,make_empty_symbol) PARAMS ((bfd *abfd)); + +boolean +NAME(aout,slurp_symbol_table) PARAMS ((bfd *abfd)); + +void +NAME(aout,write_syms) PARAMS ((bfd *abfd)); + +void +NAME(aout,reclaim_symbol_table) PARAMS ((bfd *abfd)); + +unsigned int +NAME(aout,get_symtab_upper_bound) PARAMS ((bfd *abfd)); + +unsigned int +NAME(aout,get_symtab) PARAMS ((bfd *abfd, asymbol **location)); + +boolean +NAME(aout,slurp_reloc_table) PARAMS ((bfd *abfd, sec_ptr asect, + asymbol **symbols)); + +unsigned int +NAME(aout,canonicalize_reloc) PARAMS ((bfd *abfd, sec_ptr section, + arelent **relptr, asymbol **symbols)); + +unsigned int +NAME(aout,get_reloc_upper_bound) PARAMS ((bfd *abfd, sec_ptr asect)); + +void +NAME(aout,reclaim_reloc) PARAMS ((bfd *ignore_abfd, sec_ptr ignore)); + +alent * +NAME(aout,get_lineno) PARAMS ((bfd *ignore_abfd, asymbol *ignore_symbol)); + +void +NAME(aout,print_symbol) PARAMS ((bfd *ignore_abfd, PTR file, + asymbol *symbol, bfd_print_symbol_type how)); + +void +NAME(aout,get_symbol_info) PARAMS ((bfd *ignore_abfd, + asymbol *symbol, symbol_info *ret)); + +boolean +NAME(aout,close_and_cleanup) PARAMS ((bfd *abfd)); + +boolean +NAME(aout,find_nearest_line) PARAMS ((bfd *abfd, asection *section, + asymbol **symbols, bfd_vma offset, CONST char **filename_ptr, + CONST char **functionname_ptr, unsigned int *line_ptr)); + +int +NAME(aout,sizeof_headers) PARAMS ((bfd *abfd, boolean exec)); + +boolean +NAME(aout,adjust_sizes_and_vmas) PARAMS ((bfd *abfd, + bfd_size_type *text_size, file_ptr *text_end)); + +void +NAME(aout,swap_exec_header_in) PARAMS ((bfd *abfd, + struct external_exec *raw_bytes, struct internal_exec *execp)); + +void +NAME(aout,swap_exec_header_out) PARAMS ((bfd *abfd, + struct internal_exec *execp, struct external_exec *raw_bytes)); + +/* Prototypes for functions in stab-syms.c. */ + +CONST char * +aout_stab_name PARAMS ((int code)); + +/* A.out uses the generic versions of these routines... */ + +#define aout_32_get_section_contents bfd_generic_get_section_contents +#define aout_32_close_and_cleanup bfd_generic_close_and_cleanup + +#define aout_64_get_section_contents bfd_generic_get_section_contents +#define aout_64_close_and_cleanup bfd_generic_close_and_cleanup +#ifndef NO_WRITE_HEADER_KLUDGE +#define NO_WRITE_HEADER_KLUDGE 0 +#endif + +#ifndef WRITE_HEADERS +#define WRITE_HEADERS(abfd, execp) \ + { \ + bfd_size_type text_size; /* dummy vars */ \ + file_ptr text_end; \ + if (adata(abfd).magic == undecided_magic) \ + NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ + \ + execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ + execp->a_entry = bfd_get_start_address (abfd); \ + \ + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ + \ + bfd_seek (abfd, (file_ptr) 0, SEEK_SET); \ + bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd); \ + /* Now write out reloc info, followed by syms and strings */ \ + \ + if (bfd_get_symcount (abfd) != 0) \ + { \ + bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET); \ + \ + NAME(aout,write_syms)(abfd); \ + \ + bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET); \ + \ + if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) return false; \ + bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET); \ + \ + if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) return false; \ + } \ + } +#endif diff --git a/gnu/usr.bin/gdb/bfd/libbfd.c b/gnu/usr.bin/gdb/bfd/libbfd.c new file mode 100644 index 00000000000..1bf8f7fb8e0 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libbfd.c @@ -0,0 +1,850 @@ +/* Assorted BFD support routines, only used internally. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + libbfd + +DESCRIPTION + This file contains various routines which are used within BFD. + They are not intended for export, but are documented here for + completeness. +*/ + +boolean +DEFUN(_bfd_dummy_new_section_hook,(ignore, ignore_newsect), + bfd *ignore AND + asection *ignore_newsect) +{ + return true; +} + +boolean +DEFUN(bfd_false ,(ignore), + bfd *ignore) +{ + return false; +} + +boolean +DEFUN(bfd_true,(ignore), + bfd *ignore) +{ + return true; +} + +PTR +DEFUN(bfd_nullvoidptr,(ignore), + bfd *ignore) +{ + return (PTR)NULL; +} + +int +DEFUN(bfd_0,(ignore), + bfd *ignore) +{ + return 0; +} + +unsigned int +DEFUN(bfd_0u,(ignore), + bfd *ignore) +{ + return 0; +} + +void +DEFUN(bfd_void,(ignore), + bfd *ignore) +{ +} + +boolean +DEFUN(_bfd_dummy_core_file_matches_executable_p,(ignore_core_bfd, ignore_exec_bfd), + bfd *ignore_core_bfd AND + bfd *ignore_exec_bfd) +{ + bfd_error = invalid_operation; + return false; +} + +/* of course you can't initialize a function to be the same as another, grr */ + +char * +DEFUN(_bfd_dummy_core_file_failing_command,(ignore_abfd), + bfd *ignore_abfd) +{ + return (char *)NULL; +} + +int +DEFUN(_bfd_dummy_core_file_failing_signal,(ignore_abfd), + bfd *ignore_abfd) +{ + return 0; +} + +bfd_target * +DEFUN(_bfd_dummy_target,(ignore_abfd), + bfd *ignore_abfd) +{ + return 0; +} + +/** zalloc -- allocate and clear storage */ + + +#ifndef zalloc +char * +DEFUN(zalloc,(size), + bfd_size_type size) +{ + char *ptr = (char *) malloc ((size_t)size); + + if ((ptr != NULL) && (size != 0)) + memset(ptr,0, (size_t) size); + + return ptr; +} +#endif + +/* +INTERNAL_FUNCTION + bfd_xmalloc + +SYNOPSIS + PTR bfd_xmalloc( bfd_size_type size); + +DESCRIPTION + Like malloc, but exit if no more memory. + +*/ + +/** There is major inconsistency in how running out of memory is handled. + Some routines return a NULL, and set bfd_error to no_memory. + However, obstack routines can't do this ... */ + + +DEFUN(PTR bfd_xmalloc,(size), + bfd_size_type size) +{ + static CONST char no_memory_message[] = "Virtual memory exhausted!\n"; + PTR ptr; + if (size == 0) size = 1; + ptr = (PTR)malloc((size_t) size); + if (!ptr) + { + write (2, no_memory_message, sizeof(no_memory_message)-1); + exit (-1); + } + return ptr; +} + +/* +INTERNAL_FUNCTION + bfd_xmalloc_by_size_t + +SYNOPSIS + PTR bfd_xmalloc_by_size_t ( size_t size); + +DESCRIPTION + Like malloc, but exit if no more memory. + Uses size_t, so it's suitable for use as obstack_chunk_alloc. + */ +PTR +DEFUN(bfd_xmalloc_by_size_t, (size), + size_t size) +{ + return bfd_xmalloc ((bfd_size_type) size); +} + +/* Some IO code */ + + +/* Note that archive entries don't have streams; they share their parent's. + This allows someone to play with the iostream behind BFD's back. + + Also, note that the origin pointer points to the beginning of a file's + contents (0 for non-archive elements). For archive entries this is the + first octet in the file, NOT the beginning of the archive header. */ + +static +int DEFUN(real_read,(where, a,b, file), + PTR where AND + int a AND + int b AND + FILE *file) +{ + return fread(where, a,b,file); +} +bfd_size_type +DEFUN(bfd_read,(ptr, size, nitems, abfd), + PTR ptr AND + bfd_size_type size AND + bfd_size_type nitems AND + bfd *abfd) +{ + int nread; + nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (nread > 0) + abfd->where += nread; +#endif + return nread; +} + +bfd_size_type +DEFUN(bfd_write,(ptr, size, nitems, abfd), + CONST PTR ptr AND + bfd_size_type size AND + bfd_size_type nitems AND + bfd *abfd) +{ + int nwrote = fwrite (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (nwrote > 0) + abfd->where += nwrote; +#endif + return nwrote; +} + +/* +INTERNAL_FUNCTION + bfd_write_bigendian_4byte_int + +SYNOPSIS + void bfd_write_bigendian_4byte_int(bfd *abfd, int i); + +DESCRIPTION + Writes a 4 byte integer to the outputing bfd, in big endian + mode regardless of what else is going on. This is useful in + archives. + +*/ +void +DEFUN(bfd_write_bigendian_4byte_int,(abfd, i), + bfd *abfd AND + int i) +{ + bfd_byte buffer[4]; + bfd_putb32(i, buffer); + bfd_write((PTR)buffer, 4, 1, abfd); +} + +long +DEFUN(bfd_tell,(abfd), + bfd *abfd) +{ + file_ptr ptr; + + ptr = ftell (bfd_cache_lookup(abfd)); + + if (abfd->my_archive) + ptr -= abfd->origin; + abfd->where = ptr; + return ptr; +} + +int +DEFUN(bfd_flush,(abfd), + bfd *abfd) +{ + return fflush (bfd_cache_lookup(abfd)); +} + +int +DEFUN(bfd_stat,(abfd, statbuf), + bfd *abfd AND + struct stat *statbuf) +{ + return fstat (fileno(bfd_cache_lookup(abfd)), statbuf); +} + +int +DEFUN(bfd_seek,(abfd, position, direction), + bfd * CONST abfd AND + CONST file_ptr position AND + CONST int direction) +{ + int result; + FILE *f; + file_ptr file_position; + /* For the time being, a BFD may not seek to it's end. The problem + is that we don't easily have a way to recognize the end of an + element in an archive. */ + + BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); + + if (direction == SEEK_CUR && position == 0) + return 0; +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (abfd->format != bfd_archive && abfd->my_archive == 0) + { +#ifndef NDEBUG + /* Explanation for this code: I'm only about 95+% sure that the above + conditions are sufficient and that all i/o calls are properly + adjusting the `where' field. So this is sort of an `assert' + that the `where' field is correct. If we can go a while without + tripping the abort, we can probably safely disable this code, + so that the real optimizations happen. */ + file_ptr where_am_i_now; + where_am_i_now = ftell (bfd_cache_lookup (abfd)); + if (abfd->my_archive) + where_am_i_now -= abfd->origin; + if (where_am_i_now != abfd->where) + abort (); +#endif + if (direction == SEEK_SET && position == abfd->where) + return 0; + } + else + { + /* We need something smarter to optimize access to archives. + Currently, anything inside an archive is read via the file + handle for the archive. Which means that a bfd_seek on one + component affects the `current position' in the archive, as + well as in any other component. + + It might be sufficient to put a spike through the cache + abstraction, and look to the archive for the file position, + but I think we should try for something cleaner. + + In the meantime, no optimization for archives. */ + } +#endif + + f = bfd_cache_lookup (abfd); + file_position = position; + if (direction == SEEK_SET && abfd->my_archive != NULL) + file_position += abfd->origin; + + result = fseek (f, file_position, direction); + + if (result != 0) + /* Force redetermination of `where' field. */ + bfd_tell (abfd); + else + { +#ifdef FILE_OFFSET_IS_CHAR_INDEX + /* Adjust `where' field. */ + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; +#endif + } + return result; +} + +/** Make a string table */ + +/*>bfd.h< + Add string to table pointed to by table, at location starting with free_ptr. + resizes the table if necessary (if it's NULL, creates it, ignoring + table_length). Updates free_ptr, table, table_length */ + +boolean +DEFUN(bfd_add_to_string_table,(table, new_string, table_length, free_ptr), + char **table AND + char *new_string AND + unsigned int *table_length AND + char **free_ptr) +{ + size_t string_length = strlen (new_string) + 1; /* include null here */ + char *base = *table; + size_t space_length = *table_length; + unsigned int offset = (base ? *free_ptr - base : 0); + + if (base == NULL) { + /* Avoid a useless regrow if we can (but of course we still + take it next time */ + space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ? + DEFAULT_STRING_SPACE_SIZE : string_length+1); + base = zalloc ((bfd_size_type) space_length); + + if (base == NULL) { + bfd_error = no_memory; + return false; + } + } + + if ((size_t)(offset + string_length) >= space_length) { + /* Make sure we will have enough space */ + while ((size_t)(offset + string_length) >= space_length) + space_length += space_length/2; /* grow by 50% */ + + base = (char *) realloc (base, space_length); + if (base == NULL) { + bfd_error = no_memory; + return false; + } + + } + + memcpy (base + offset, new_string, string_length); + *table = base; + *table_length = space_length; + *free_ptr = base + offset + string_length; + + return true; +} + +/** The do-it-yourself (byte) sex-change kit */ + +/* The middle letter e.g. getshort indicates Big or Little endian + target machine. It doesn't matter what the byte order of the host + machine is; these routines work for either. */ + +/* FIXME: Should these take a count argument? + Answer (gnu@cygnus.com): No, but perhaps they should be inline + functions in swap.h #ifdef __GNUC__. + Gprof them later and find out. */ + +/* +FUNCTION + bfd_put_size +FUNCTION + bfd_get_size + +DESCRIPTION + These macros as used for reading and writing raw data in + sections; each access (except for bytes) is vectored through + the target format of the BFD and mangled accordingly. The + mangling performs any necessary endian translations and + removes alignment restrictions. Note that types accepted and + returned by these macros are identical so they can be swapped + around in macros--for example libaout.h defines GET_WORD to + either bfd_get_32 or bfd_get_64. + + In the put routines, val must be a bfd_vma. If we are on a + system without prototypes, the caller is responsible for making + sure that is true, with a cast if necessary. We don't cast + them in the macro definitions because that would prevent lint + or gcc -Wall from detecting sins such as passing a pointer. + To detect calling these with less than a bfd_vma, use gcc + -Wconversion on a host with 64 bit bfd_vma's. + +. +.{* Byte swapping macros for user section data. *} +. +.#define bfd_put_8(abfd, val, ptr) \ +. (*((unsigned char *)(ptr)) = (unsigned char)val) +.#define bfd_put_signed_8 \ +. bfd_put_8 +.#define bfd_get_8(abfd, ptr) \ +. (*(unsigned char *)(ptr)) +.#define bfd_get_signed_8(abfd, ptr) \ +. ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) +. +.#define bfd_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +.#define bfd_put_signed_16 \ +. bfd_put_16 +.#define bfd_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx16, (ptr)) +.#define bfd_get_signed_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) +. +.#define bfd_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +.#define bfd_put_signed_32 \ +. bfd_put_32 +.#define bfd_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx32, (ptr)) +.#define bfd_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) +. +.#define bfd_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +.#define bfd_put_signed_64 \ +. bfd_put_64 +.#define bfd_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx64, (ptr)) +.#define bfd_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) +. +*/ + +/* +FUNCTION + bfd_h_put_size +FUNCTION + bfd_h_get_size + +DESCRIPTION + These macros have the same function as their <> + bretherin, except that they are used for removing information + for the header records of object files. Believe it or not, + some object files keep their header records in big endian + order, and their data in little endian order. +. +.{* Byte swapping macros for file header data. *} +. +.#define bfd_h_put_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_put_signed_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_get_8(abfd, ptr) \ +. bfd_get_8 (abfd, ptr) +.#define bfd_h_get_signed_8(abfd, ptr) \ +. bfd_get_signed_8 (abfd, ptr) +. +.#define bfd_h_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +.#define bfd_h_put_signed_16 \ +. bfd_h_put_16 +.#define bfd_h_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx16,(ptr)) +.#define bfd_h_get_signed_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) +. +.#define bfd_h_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +.#define bfd_h_put_signed_32 \ +. bfd_h_put_32 +.#define bfd_h_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx32,(ptr)) +.#define bfd_h_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) +. +.#define bfd_h_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +.#define bfd_h_put_signed_64 \ +. bfd_h_put_64 +.#define bfd_h_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx64,(ptr)) +.#define bfd_h_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) +. +*/ + +/* Sign extension to bfd_signed_vma. */ +#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) +#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000) +#define EIGHT_GAZILLION (((HOST_64_BIT)0x80000000) << 32) +#define COERCE64(x) \ + (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + +bfd_vma +DEFUN(bfd_getb16,(addr), + register bfd_byte *addr) +{ + return (addr[0] << 8) | addr[1]; +} + +bfd_vma +DEFUN(bfd_getl16,(addr), + register bfd_byte *addr) +{ + return (addr[1] << 8) | addr[0]; +} + +bfd_signed_vma +DEFUN(bfd_getb_signed_16,(addr), + register bfd_byte *addr) +{ + return COERCE16((addr[0] << 8) | addr[1]); +} + +bfd_signed_vma +DEFUN(bfd_getl_signed_16,(addr), + register bfd_byte *addr) +{ + return COERCE16((addr[1] << 8) | addr[0]); +} + +void +DEFUN(bfd_putb16,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte)(data >> 8); + addr[1] = (bfd_byte )data; +} + +void +DEFUN(bfd_putl16,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte )data; + addr[1] = (bfd_byte)(data >> 8); +} + +bfd_vma +bfd_getb32 (addr) + register bfd_byte *addr; +{ + return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8) + | addr[2]) << 8 | addr[3]; +} + +bfd_vma +bfd_getl32 (addr) + register bfd_byte *addr; +{ + return (((((bfd_vma)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_32 (addr) + register bfd_byte *addr; +{ + return COERCE32((((((bfd_vma)addr[0] << 8) | addr[1]) << 8) + | addr[2]) << 8 | addr[3]); +} + +bfd_signed_vma +bfd_getl_signed_32 (addr) + register bfd_byte *addr; +{ + return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]); +} + +bfd_vma +DEFUN(bfd_getb64,(addr), + register bfd_byte *addr) +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_vma +DEFUN(bfd_getl64,(addr), + register bfd_byte *addr) +{ + +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_signed_vma +DEFUN(bfd_getb_signed_64,(addr), + register bfd_byte *addr) +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_signed_vma +DEFUN(bfd_getl_signed_64,(addr), + register bfd_byte *addr) +{ + +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif + +} + +void +DEFUN(bfd_putb32,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte)(data >> 24); + addr[1] = (bfd_byte)(data >> 16); + addr[2] = (bfd_byte)(data >> 8); + addr[3] = (bfd_byte)data; +} + +void +DEFUN(bfd_putl32,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte)data; + addr[1] = (bfd_byte)(data >> 8); + addr[2] = (bfd_byte)(data >> 16); + addr[3] = (bfd_byte)(data >> 24); +} +void +DEFUN(bfd_putb64,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ +#ifdef BFD64 + addr[0] = (bfd_byte)(data >> (7*8)); + addr[1] = (bfd_byte)(data >> (6*8)); + addr[2] = (bfd_byte)(data >> (5*8)); + addr[3] = (bfd_byte)(data >> (4*8)); + addr[4] = (bfd_byte)(data >> (3*8)); + addr[5] = (bfd_byte)(data >> (2*8)); + addr[6] = (bfd_byte)(data >> (1*8)); + addr[7] = (bfd_byte)(data >> (0*8)); +#else + BFD_FAIL(); +#endif + +} + +void +DEFUN(bfd_putl64,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ +#ifdef BFD64 + addr[7] = (bfd_byte)(data >> (7*8)); + addr[6] = (bfd_byte)(data >> (6*8)); + addr[5] = (bfd_byte)(data >> (5*8)); + addr[4] = (bfd_byte)(data >> (4*8)); + addr[3] = (bfd_byte)(data >> (3*8)); + addr[2] = (bfd_byte)(data >> (2*8)); + addr[1] = (bfd_byte)(data >> (1*8)); + addr[0] = (bfd_byte)(data >> (0*8)); +#else + BFD_FAIL(); +#endif + +} + + +/* Default implementation */ + +boolean +DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + if (count == 0) + return true; + if ((bfd_size_type)(offset+count) > section->_raw_size + || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 + || bfd_read(location, (bfd_size_type)1, count, abfd) != count) + return (false); /* on error */ + return (true); +} + +/* This generic function can only be used in implementations where creating + NEW sections is disallowed. It is useful in patching existing sections + in read-write files, though. See other set_section_contents functions + to see why it doesn't work for new sections. */ +boolean +DEFUN(bfd_generic_set_section_contents, (abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + if (count == 0) + return true; + if ((bfd_size_type)(offset+count) > bfd_get_section_size_after_reloc(section) + || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 + || bfd_write(location, (bfd_size_type)1, count, abfd) != count) + return (false); /* on error */ + return (true); +} + +/* +INTERNAL_FUNCTION + bfd_log2 + +DESCRIPTION + Return the log base 2 of the value supplied, rounded up. eg an + arg of 1025 would return 11. + +SYNOPSIS + unsigned int bfd_log2(bfd_vma x); +*/ + +unsigned +bfd_log2(x) + bfd_vma x; +{ + unsigned result = 0; + while ( (bfd_vma)(1<< result) < x) + result++; + return result; +} diff --git a/gnu/usr.bin/gdb/bfd/libbfd.h b/gnu/usr.bin/gdb/bfd/libbfd.h new file mode 100644 index 00000000000..fcd5bbca8de --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libbfd.h @@ -0,0 +1,273 @@ +/* libbfd.h -- Declarations used by bfd library *implementation*. + (This include file is not for users of the library.) + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + + +/* Align an address upward to a boundary, expressed as a number of bytes. + E.g. align to an 8-byte boundary with argument of 8. */ +#define BFD_ALIGN(this, boundary) \ + ((( (this) + ((boundary) -1)) & (~((boundary)-1)))) + +/* If you want to read and write large blocks, you might want to do it + in quanta of this amount */ +#define DEFAULT_BUFFERSIZE 8192 + +/* Set a tdata field. Can't use the other macros for this, since they + do casts, and casting to the left of assignment isn't portable. */ +#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v)) + +/* tdata for an archive. For an input archive, cache + needs to be free()'d. For an output archive, symdefs do. */ + +struct artdata { + file_ptr first_file_filepos; + /* Speed up searching the armap */ + struct ar_cache *cache; + bfd *archive_head; /* Only interesting in output routines */ + carsym *symdefs; /* the symdef entries */ + symindex symdef_count; /* how many there are */ + char *extended_names; /* clever intel extension */ + time_t armap_timestamp; /* Timestamp value written into armap. + This is used for BSD archives to check + that the timestamp is recent enough + for the BSD linker to not complain, + just before we finish writing an + archive. */ + file_ptr armap_datepos; /* Position within archive to seek to + rewrite the date field. */ +}; + +#define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data) + +/* Goes in bfd's arelt_data slot */ +struct areltdata { + char * arch_header; /* it's actually a string */ + unsigned int parsed_size; /* octets of filesize not including ar_hdr */ + char *filename; /* null-terminated */ +}; + +#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) + +char *zalloc PARAMS ((bfd_size_type size)); + +/* These routines allocate and free things on the BFD's obstack. Note + that realloc can never occur in place. */ + +PTR bfd_alloc PARAMS ((bfd *abfd, size_t size)); +PTR bfd_zalloc PARAMS ((bfd *abfd, size_t size)); +PTR bfd_realloc PARAMS ((bfd *abfd, PTR orig, size_t new)); +void bfd_alloc_grow PARAMS ((bfd *abfd, PTR thing, size_t size)); +PTR bfd_alloc_finish PARAMS ((bfd *abfd)); +PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t wanted)); + +#define bfd_release(x,y) (void) obstack_free(&(x->memory),y) + + +bfd_size_type bfd_read PARAMS ((PTR ptr, bfd_size_type size, + bfd_size_type nitems, bfd *abfd)); +bfd_size_type bfd_write PARAMS ((CONST PTR ptr, bfd_size_type size, + bfd_size_type nitems, bfd *abfd)); +int bfd_seek PARAMS ((bfd* CONST abfd, CONST file_ptr fp, + CONST int direction)); +long bfd_tell PARAMS ((bfd *abfd)); + +int bfd_flush PARAMS ((bfd *abfd)); +int bfd_stat PARAMS ((bfd *abfd, struct stat *)); + +bfd * _bfd_create_empty_archive_element_shell PARAMS ((bfd *obfd)); +bfd * look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index)); +boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd)); +struct areltdata * snarf_ar_hdr PARAMS ((bfd *abfd)); +bfd_target * bfd_generic_archive_p PARAMS ((bfd *abfd)); +boolean bfd_slurp_armap PARAMS ((bfd *abfd)); +boolean bfd_slurp_bsd_armap_f2 PARAMS ((bfd *abfd)); +#define bfd_slurp_bsd_armap bfd_slurp_armap +#define bfd_slurp_coff_armap bfd_slurp_armap +boolean _bfd_slurp_extended_name_table PARAMS ((bfd *abfd)); +boolean _bfd_write_archive_contents PARAMS ((bfd *abfd)); +bfd * new_bfd PARAMS (()); + +#define DEFAULT_STRING_SPACE_SIZE 0x2000 +boolean bfd_add_to_string_table PARAMS ((char **table, char *new_string, + unsigned int *table_length, + char **free_ptr)); + +boolean bfd_false PARAMS ((bfd *ignore)); +boolean bfd_true PARAMS ((bfd *ignore)); +PTR bfd_nullvoidptr PARAMS ((bfd *ignore)); +int bfd_0 PARAMS ((bfd *ignore)); +unsigned int bfd_0u PARAMS ((bfd *ignore)); +void bfd_void PARAMS ((bfd *ignore)); + +bfd * new_bfd_contained_in PARAMS ((bfd *)); +boolean _bfd_dummy_new_section_hook PARAMS ((bfd *ignore, asection *newsect)); +char * _bfd_dummy_core_file_failing_command PARAMS ((bfd *abfd)); +int _bfd_dummy_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean _bfd_dummy_core_file_matches_executable_p PARAMS ((bfd *core_bfd, + bfd *exec_bfd)); +bfd_target * _bfd_dummy_target PARAMS ((bfd *abfd)); + +void bfd_dont_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_bsd_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_gnu_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); + +boolean bsd_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +boolean coff_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +bfd * bfd_generic_openr_next_archived_file PARAMS ((bfd *archive, + bfd *last_file)); + +int bfd_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); + +boolean bfd_generic_get_section_contents PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, + bfd_size_type count)); + +boolean bfd_generic_set_section_contents PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, + bfd_size_type count)); + +/* Macros to tell if bfds are read or write enabled. + + Note that bfds open for read may be scribbled into if the fd passed + to bfd_fdopenr is actually open both for read and write + simultaneously. However an output bfd will never be open for + read. Therefore sometimes you want to check bfd_read_p or + !bfd_read_p, and only sometimes bfd_write_p. +*/ + +#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction) +#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction) + +void bfd_assert PARAMS ((char*,int)); + +#define BFD_ASSERT(x) \ +{ if (!(x)) bfd_assert(__FILE__,__LINE__); } + +#define BFD_FAIL() \ +{ bfd_assert(__FILE__,__LINE__); } + +FILE * bfd_cache_lookup_worker PARAMS ((bfd *)); + +extern bfd *bfd_last_cache; + +/* Now Steve, what's the story here? */ +#ifdef lint +#define itos(x) "l" +#define stoi(x) 1 +#else +#define itos(x) ((char*)(x)) +#define stoi(x) ((int)(x)) +#endif + +/* Generic routine for close_and_cleanup is really just bfd_true. */ +#define bfd_generic_close_and_cleanup bfd_true + +/* And more follows */ + +void +bfd_check_init PARAMS ((void)); + +PTR +bfd_xmalloc PARAMS (( bfd_size_type size)); + +PTR +bfd_xmalloc_by_size_t PARAMS (( size_t size)); + +void +bfd_write_bigendian_4byte_int PARAMS ((bfd *abfd, int i)); + +unsigned int +bfd_log2 PARAMS ((bfd_vma x)); + +#define BFD_CACHE_MAX_OPEN 10 +extern bfd *bfd_last_cache; + +#define bfd_cache_lookup(x) \ + ((x)==bfd_last_cache? \ + (FILE*)(bfd_last_cache->iostream): \ + bfd_cache_lookup_worker(x)) +boolean +bfd_cache_close PARAMS ((bfd *)); + +FILE* +bfd_open_file PARAMS ((bfd *)); + +FILE * +bfd_cache_lookup_worker PARAMS ((bfd *)); + +void +bfd_constructor_entry PARAMS ((bfd *abfd, + asymbol **symbol_ptr_ptr, + CONST char*type)); + +CONST struct reloc_howto_struct * +bfd_default_reloc_type_lookup + PARAMS ((bfd *abfd AND + bfd_reloc_code_real_type code)); + +boolean +bfd_generic_relax_section + PARAMS ((bfd *abfd, + asection *section, + asymbol **symbols)); + +bfd_byte * + +bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd, + struct bfd_seclet *seclet, + bfd_byte *data, + boolean relocateable)); + +boolean +bfd_generic_seclet_link + PARAMS ((bfd *abfd, + PTR data, + boolean relocateable)); + +extern bfd_arch_info_type bfd_default_arch_struct; +boolean +bfd_default_set_arch_mach PARAMS ((bfd *abfd, + enum bfd_architecture arch, + unsigned long mach)); + +void +bfd_arch_init PARAMS ((void)); + +void +bfd_arch_linkin PARAMS ((bfd_arch_info_type *)); + +CONST bfd_arch_info_type * +bfd_default_compatible + PARAMS ((CONST bfd_arch_info_type *a, + CONST bfd_arch_info_type *b)); + +boolean +bfd_default_scan PARAMS ((CONST struct bfd_arch_info *, CONST char *)); + +struct elf_internal_shdr * +bfd_elf_find_section PARAMS ((bfd *abfd, char *name)); + diff --git a/gnu/usr.bin/gdb/bfd/libcoff.h b/gnu/usr.bin/gdb/bfd/libcoff.h new file mode 100644 index 00000000000..2aa6ad4b161 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libcoff.h @@ -0,0 +1,352 @@ +/* BFD COFF object file private structure. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + + +/* Object file tdata; access macros */ + +#define coff_data(bfd) ((bfd)->tdata.coff_obj_data) +#define exec_hdr(bfd) (coff_data(bfd)->hdr) +#define obj_symbols(bfd) (coff_data(bfd)->symbols) +#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos) + +#define obj_relocbase(bfd) (coff_data(bfd)->relocbase) +#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments) +#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count) +#define obj_convert(bfd) (coff_data(bfd)->conversion_table) +#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size) +#if CFILE_STUFF +#define obj_symbol_slew(bfd) (coff_data(bfd)->symbol_index_slew) +#else +#define obj_symbol_slew(bfd) 0 +#endif + + +/* `Tdata' information kept for COFF files. */ + +typedef struct coff_tdata +{ + struct coff_symbol_struct *symbols; /* symtab for input bfd */ + unsigned int *conversion_table; + int conv_table_size; + file_ptr sym_filepos; + + long symbol_index_slew; /* used during read to mark whether a + C_FILE symbol as been added. */ + + struct coff_ptr_struct *raw_syments; + struct lineno *raw_linenos; + unsigned int raw_syment_count; + unsigned short flags; + + /* These are only valid once writing has begun */ + long int relocbase; + + /* These members communicate important constants about the symbol table + to GDB's symbol-reading code. These `constants' unfortunately vary + from coff implementation to implementation... */ + unsigned local_n_btmask; + unsigned local_n_btshft; + unsigned local_n_tmask; + unsigned local_n_tshift; + unsigned local_symesz; + unsigned local_auxesz; + unsigned local_linesz; +} coff_data_type; + +/* We take the address of the first element of a asymbol to ensure that the + * macro is only ever applied to an asymbol. */ +#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) + +/* Functions in coffgen.c. */ +extern bfd_target *coff_object_p PARAMS ((bfd *)); +extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int)); +extern unsigned int coff_get_symtab_upper_bound PARAMS ((bfd *)); +extern unsigned int coff_get_symtab PARAMS ((bfd *, asymbol **)); +extern int coff_count_linenumbers PARAMS ((bfd *)); +extern struct coff_symbol_struct *coff_symbol_from PARAMS ((bfd *, asymbol *)); +extern void coff_renumber_symbols PARAMS ((bfd *)); +extern void coff_mangle_symbols PARAMS ((bfd *)); +extern void coff_write_symbols PARAMS ((bfd *)); +extern void coff_write_linenumbers PARAMS ((bfd *)); +extern alent *coff_get_lineno PARAMS ((bfd *, asymbol *)); +extern asymbol *coff_section_symbol PARAMS ((bfd *, char *)); +extern struct coff_ptr_struct *coff_get_normalized_symtab PARAMS ((bfd *)); +extern unsigned int coff_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern asymbol *coff_make_empty_symbol PARAMS ((bfd *)); +extern void coff_print_symbol PARAMS ((bfd *, PTR filep, asymbol *, + bfd_print_symbol_type how)); +extern void coff_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *ret)); +extern asymbol *coff_bfd_make_debug_symbol PARAMS ((bfd *, PTR, + unsigned long)); +extern boolean coff_find_nearest_line PARAMS ((bfd *, + asection *, + asymbol **, + bfd_vma offset, + CONST char **filename_ptr, + CONST char **functionname_ptr, + unsigned int *line_ptr)); +extern int coff_sizeof_headers PARAMS ((bfd *, boolean reloc)); +extern boolean bfd_coff_reloc16_relax_section PARAMS ((bfd *, + asection *, + asymbol **)); +extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_seclet *, bfd_byte *, boolean relocateable)); +extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *, + struct bfd_seclet *)); + +/* And more taken from the source .. */ + +typedef struct coff_ptr_struct +{ + + /* Remembers the offset from the first symbol in the file for + this symbol. Generated by coff_renumber_symbols. */ +unsigned int offset; + + /* Should the tag field of this symbol be renumbered. + Created by coff_pointerize_aux. */ +char fix_tag; + + /* Should the endidx field of this symbol be renumbered. + Created by coff_pointerize_aux. */ +char fix_end; + + /* The container for the symbol structure as read and translated + from the file. */ + +union { + union internal_auxent auxent; + struct internal_syment syment; + } u; +} combined_entry_type; + + + /* Each canonical asymbol really looks like this: */ + +typedef struct coff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ +asymbol symbol; + + /* A pointer to the hidden information for this symbol */ +combined_entry_type *native; + + /* A pointer to the linenumber information for this symbol */ +struct lineno_cache_entry *lineno; + + /* Have the line numbers been relocated yet ? */ +boolean done_lineno; +} coff_symbol_type; +typedef struct +{ + void (*_bfd_coff_swap_aux_in) PARAMS (( + bfd *abfd , + PTR ext, + int type, + int class , + PTR in)); + + void (*_bfd_coff_swap_sym_in) PARAMS (( + bfd *abfd , + PTR ext, + PTR in)); + + void (*_bfd_coff_swap_lineno_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + + unsigned int (*_bfd_coff_swap_aux_out) PARAMS (( + bfd *abfd, + PTR in, + int type, + int class, + PTR ext)); + + unsigned int (*_bfd_coff_swap_sym_out) PARAMS (( + bfd *abfd, + PTR in, + PTR ext)); + + unsigned int (*_bfd_coff_swap_lineno_out) PARAMS (( + bfd *abfd, + PTR in, + PTR ext)); + + unsigned int (*_bfd_coff_swap_reloc_out) PARAMS (( + bfd *abfd, + PTR src, + PTR dst)); + + unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int _bfd_filhsz; + unsigned int _bfd_aoutsz; + unsigned int _bfd_scnhsz; + unsigned int _bfd_symesz; + unsigned int _bfd_auxesz; + unsigned int _bfd_linesz; + boolean _bfd_coff_long_filenames; + void (*_bfd_coff_swap_filehdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_aouthdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_scnhdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + boolean (*_bfd_coff_bad_format_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr)); + boolean (*_bfd_coff_set_arch_mach_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr)); + PTR (*_bfd_coff_mkobject_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr, + PTR internal_aouthdr)); + flagword (*_bfd_styp_to_sec_flags_hook) PARAMS (( + bfd *abfd, + PTR internal_scnhdr)); + asection *(*_bfd_make_section_hook) PARAMS (( + bfd *abfd, + char *name)); + void (*_bfd_set_alignment_hook) PARAMS (( + bfd *abfd, + asection *sec, + PTR internal_scnhdr)); + boolean (*_bfd_coff_slurp_symbol_table) PARAMS (( + bfd *abfd)); + boolean (*_bfd_coff_symname_in_debug) PARAMS (( + bfd *abfd, + struct internal_syment *sym)); + void (*_bfd_coff_reloc16_extra_cases) PARAMS (( + bfd *abfd, + struct bfd_seclet *seclet, + arelent *reloc, + bfd_byte *data, + unsigned int *src_ptr, + unsigned int *dst_ptr)); + int (*_bfd_coff_reloc16_estimate) PARAMS (( + asection *input_section, + asymbol **symbols, + arelent *r, + unsigned int shrink)); + +} bfd_coff_backend_data; + +#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) + +#define bfd_coff_swap_aux_in(a,e,t,c,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,i)) + +#define bfd_coff_swap_sym_in(a,e,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) + +#define bfd_coff_swap_lineno_in(a,e,i) \ + ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) + +#define bfd_coff_swap_reloc_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) + +#define bfd_coff_swap_lineno_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) + +#define bfd_coff_swap_aux_out(abfd, i, t,c,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aux_out) (abfd, i,t,c, o)) + +#define bfd_coff_swap_sym_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) + +#define bfd_coff_swap_filehdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) + +#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) +#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) +#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) +#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) +#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) +#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) +#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames) +#define bfd_coff_swap_filehdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) + +#define bfd_coff_bad_format_hook(abfd, filehdr) \ + ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) + +#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ + ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) +#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ + ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr)) + +#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr)\ + ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr)) + +#define bfd_coff_make_section_hook(abfd, name)\ + ((coff_backend_info (abfd)->_bfd_make_section_hook) (abfd, name)) + +#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ + ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) + +#define bfd_coff_slurp_symbol_table(abfd)\ + ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) + +#define bfd_coff_symname_in_debug(abfd, sym)\ + ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) + +#define bfd_coff_reloc16_extra_cases(abfd, seclet, reloc, data, src_ptr, dst_ptr)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ + (abfd, seclet, reloc, data, src_ptr, dst_ptr)) + +#define bfd_coff_reloc16_estimate(abfd, section, symbols, reloc, shrink)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ + (section, symbols, reloc, shrink)) + + diff --git a/gnu/usr.bin/gdb/bfd/libecoff.h b/gnu/usr.bin/gdb/bfd/libecoff.h new file mode 100644 index 00000000000..ad3e8f223aa --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libecoff.h @@ -0,0 +1,265 @@ +/* BFD ECOFF object file private structure. + Copyright (C) 1993 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* This is the backend information kept for ECOFF files. This + structure is constant for a particular backend. The first element + is the COFF backend data structure, so that ECOFF targets can use + the generic COFF code. */ + +#define ecoff_backend(abfd) \ + ((struct ecoff_backend_data *) (abfd)->xvec->backend_data) + +struct ecoff_backend_data +{ + /* COFF backend information. This must be the first field. */ + bfd_coff_backend_data coff; + /* Supported architecture. */ + enum bfd_architecture arch; + /* Symbol table magic number. */ + int sym_magic; + /* Initial portion of armap string. */ + const char *armap_start; + /* Alignment of debugging information. E.g., 4. */ + bfd_size_type debug_align; + /* The page boundary used to align sections in a demand-paged + executable file. E.g., 0x1000. */ + bfd_vma round; + /* Bitsize of constructor entries. */ + unsigned int constructor_bitsize; + /* Reloc to use for constructor entries. */ + CONST struct reloc_howto_struct *constructor_reloc; + /* Sizes of external symbolic information. */ + bfd_size_type external_hdr_size; + bfd_size_type external_dnr_size; + bfd_size_type external_pdr_size; + bfd_size_type external_sym_size; + bfd_size_type external_opt_size; + bfd_size_type external_fdr_size; + bfd_size_type external_rfd_size; + bfd_size_type external_ext_size; + /* Functions to swap in external symbolic data. */ + void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *)); + void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *)); + void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)); + void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)); + void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *)); + void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *)); + void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)); + void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)); + /* Functions to swap out external symbolic data. */ + void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR)); + void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR)); + void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR)); + void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)); + void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR)); + void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)); + void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)); + void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)); + /* It so happens that the auxiliary type information has the same + type and format for all known ECOFF targets. I don't see any + reason that that should change, so at least for now the auxiliary + swapping information is not in this table. */ + /* External reloc size. */ + bfd_size_type external_reloc_size; + /* Reloc swapping functions. */ + void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *)); + void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR)); + /* Backend reloc tweaking. */ + void (*finish_reloc) PARAMS ((bfd *, struct internal_reloc *, arelent *)); +}; + +/* This is the target specific information kept for ECOFF files. */ + +#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data) + +typedef struct ecoff_tdata +{ + /* The reloc file position, set by + ecoff_compute_section_file_positions. */ + file_ptr reloc_filepos; + + /* The symbol table file position, set by ecoff_mkobject_hook. */ + file_ptr sym_filepos; + + /* The start and end of the text segment. Only valid for an + existing file, not for one we are creating. */ + unsigned long text_start; + unsigned long text_end; + + /* The cached gp value. This is used when relocating. */ + bfd_vma gp; + + /* The maximum size of objects to optimize using gp. This is + typically set by the -G option to the compiler, assembler or + linker. */ + int gp_size; + + /* The register masks. When linking, all the masks found in the + input files are combined into the masks of the output file. + These are not all used for all targets, but that's OK, because + the relevant ones are the only ones swapped in and out. */ + unsigned long gprmask; + unsigned long fprmask; + unsigned long cprmask[4]; + + /* The size of the unswapped ECOFF symbolic information. */ + bfd_size_type raw_size; + + /* The unswapped ECOFF symbolic information. */ + PTR raw_syments; + + /* The swapped ECOFF symbolic header. */ + HDRR symbolic_header; + + /* Pointers to the unswapped symbolic information. */ + unsigned char *line; + PTR external_dnr; /* struct dnr_ext */ + PTR external_pdr; /* struct pdr_ext */ + PTR external_sym; /* struct sym_ext */ + PTR external_opt; /* struct opt_ext */ + union aux_ext *external_aux; + char *ss; + char *ssext; + PTR external_fdr; /* struct fdr_ext */ + PTR external_rfd; /* struct rfd_ext */ + PTR external_ext; /* struct ext_ext */ + + /* The swapped FDR information. */ + FDR *fdr; + + /* The FDR index. This is set for an input BFD to a link so that + the external symbols can set their FDR index correctly. */ + unsigned int ifdbase; + + /* The canonical BFD symbols. */ + struct ecoff_symbol_struct *canonical_symbols; + +} ecoff_data_type; + +/* Each canonical asymbol really looks like this. */ + +typedef struct ecoff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ + asymbol symbol; + + /* The fdr for this symbol. */ + FDR *fdr; + + /* true if this is a local symbol rather than an external one. */ + boolean local; + + /* A pointer to the unswapped hidden information for this symbol. + This is either a struct sym_ext or a struct ext_ext, depending on + the value of the local field above. */ + PTR native; +} ecoff_symbol_type; + +/* We take the address of the first element of a asymbol to ensure that the + macro is only ever applied to an asymbol. */ +#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd))) + +/* This is a hack borrowed from coffcode.h; we need to save the index + of an external symbol when we write it out so that can set the + symbol index correctly when we write out the relocs. */ +#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata) +#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx)) + +/* Make an ECOFF object. */ +extern boolean ecoff_mkobject PARAMS ((bfd *)); + +/* Read in the ECOFF symbolic debugging information. */ +extern boolean ecoff_slurp_symbolic_info PARAMS ((bfd *)); + +/* Generic ECOFF BFD backend vectors. */ +extern asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd)); +extern unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd)); +extern unsigned int ecoff_get_symtab PARAMS ((bfd *abfd, + asymbol **alocation)); +extern void ecoff_get_symbol_info PARAMS ((bfd *abfd, + asymbol *symbol, + symbol_info *ret)); +extern void ecoff_print_symbol PARAMS ((bfd *abfd, PTR filep, + asymbol *symbol, + bfd_print_symbol_type how)); +extern unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd, + asection *section, + arelent **relptr, + asymbol **symbols)); +extern boolean ecoff_find_nearest_line PARAMS ((bfd *abfd, + asection *section, + asymbol **symbols, + bfd_vma offset, + CONST char **filename_ptr, + CONST char **fnname_ptr, + unsigned int *retline_ptr)); +extern boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data, + boolean relocateable)); +extern boolean ecoff_set_arch_mach PARAMS ((bfd *abfd, + enum bfd_architecture arch, + unsigned long machine)); +extern int ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc)); +extern boolean ecoff_set_section_contents PARAMS ((bfd *abfd, + asection *section, + PTR location, + file_ptr offset, + bfd_size_type count)); +extern boolean ecoff_get_section_contents PARAMS ((bfd *abfd, + asection *section, + PTR location, + file_ptr offset, + bfd_size_type count)); +extern boolean ecoff_write_object_contents PARAMS ((bfd *abfd)); +extern boolean ecoff_slurp_armap PARAMS ((bfd *abfd)); +extern boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); +#define ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table +extern bfd_target *ecoff_archive_p PARAMS ((bfd *abfd)); +#define ecoff_get_lineno \ + ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr) +#define ecoff_truncate_arname bfd_dont_truncate_arname +#define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file +#define ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound +#define ecoff_close_and_cleanup bfd_generic_close_and_cleanup +#define ecoff_bfd_debug_info_start bfd_void +#define ecoff_bfd_debug_info_end bfd_void +#define ecoff_bfd_debug_info_accumulate \ + ((void (*) PARAMS ((bfd *, struct sec *))) bfd_void) +#define ecoff_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define ecoff_bfd_relax_section bfd_generic_relax_section +#define ecoff_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +/* Hook functions for the generic COFF section reading code. */ +extern PTR ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr)); +extern asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name)); +extern boolean ecoff_new_section_hook PARAMS ((bfd *abfd, + asection *section)); +#define ecoff_set_alignment_hook \ + ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void) +extern boolean ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr)); +extern long ecoff_sec_to_styp_flags PARAMS ((CONST char *name, + flagword flags)); +extern flagword ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr)); +extern boolean ecoff_slurp_symbol_table PARAMS ((bfd *abfd)); diff --git a/gnu/usr.bin/gdb/bfd/libelf.h b/gnu/usr.bin/gdb/bfd/libelf.h new file mode 100644 index 00000000000..187c51a29c0 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libelf.h @@ -0,0 +1,249 @@ +/* BFD back-end data structures for ELF files. + Copyright (C) 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#ifndef _LIBELF_H_ +#define _LIBELF_H_ 1 + +#include "elf/common.h" +#include "elf/internal.h" +#include "elf/external.h" + +/* If size isn't specified as 64 or 32, NAME macro should fail. */ +#ifndef NAME +#if ARCH_SIZE==64 +#define NAME(x,y) CAT4(x,64,_,y) +#endif +#if ARCH_SIZE==32 +#define NAME(x,y) CAT4(x,32,_,y) +#endif +#endif + +#ifndef NAME +#define NAME(x,y) CAT4(x,NOSIZE,_,y) +#endif + +#define ElfNAME(X) NAME(Elf,X) +#define elfNAME(X) NAME(elf,X) + +typedef struct +{ + asymbol symbol; + Elf_Internal_Sym internal_elf_sym; + union + { + unsigned int hppa_arg_reloc; + PTR any; + } + tc_data; +} elf_symbol_type; + +struct elf_backend_data +{ + int use_rela_p; + int elf_64_p; + enum bfd_architecture arch; + void (*elf_info_to_howto) PARAMS ((bfd *, arelent *, + Elf_Internal_Rela *)); + void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *, + Elf_Internal_Rel *)); + bfd_vma maxpagesize; + void (*write_relocs) PARAMS ((bfd *, asection *, PTR)); + + void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *)); + boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *, elf_symbol_type *, int)); + boolean (*elf_backend_section_processing) PARAMS ((bfd *, Elf32_Internal_Shdr *)); + boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *, Elf32_Internal_Shdr *, char *)); + boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); + boolean (*elf_backend_section_from_bfd_section) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *)); +}; + +struct elf_sym_extra +{ + int elf_sym_num; /* sym# after locals/globals are reordered */ +}; + +typedef struct elf_sym_extra Elf_Sym_Extra; + +struct bfd_elf_arch_map { + enum bfd_architecture bfd_arch; + int elf_arch; +}; + +extern const struct bfd_elf_arch_map bfd_elf_arch_map[]; +extern const int bfd_elf_arch_map_size; + +struct bfd_elf_section_data { + Elf_Internal_Shdr this_hdr; + Elf_Internal_Shdr rel_hdr; + int this_idx, rel_idx; +}; +#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) +#define shdr_name(abfd,shdr) (elf_shstrtab (abfd)->tab + (shdr)->sh_name) + +#define get_elf_backend_data(abfd) \ + ((struct elf_backend_data *) (abfd)->xvec->backend_data) + +struct strtab +{ + char *tab; + int nentries; + int length; +}; + +/* Some private data is stashed away for future use using the tdata pointer + in the bfd structure. */ + +struct elf_obj_tdata +{ + Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ + Elf_Internal_Shdr **elf_sect_ptr; + Elf_Internal_Phdr *phdr; + struct strtab *strtab_ptr; + int num_locals; + int num_globals; + Elf_Internal_Sym *internal_syms; + elf_symbol_type *symbols; /* elf_symbol_type */ + Elf_Sym_Extra *sym_extra; + asymbol **section_syms; /* STT_SECTION symbols for each section */ + int num_section_syms; /* number of section_syms allocated */ + Elf_Internal_Shdr symtab_hdr; + Elf_Internal_Shdr shstrtab_hdr; + Elf_Internal_Shdr strtab_hdr; + int symtab_section, shstrtab_section, strtab_section; + file_ptr next_file_pos; + void *prstatus; /* The raw /proc prstatus structure */ + void *prpsinfo; /* The raw /proc prpsinfo structure */ + bfd_vma gp; /* The gp value (MIPS only, for now) */ + int gp_size; /* The gp size (MIPS only, for now) */ +}; + +#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) +#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) +#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) +#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) +#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) +#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) +#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) +#define elf_sym_extra(bfd) (elf_tdata(bfd) -> sym_extra) +#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) +#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms) +#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) +#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) +#define obj_symbols(bfd) (elf_tdata(bfd) -> symbols) +#define obj_internal_syms(bfd) (elf_tdata(bfd) -> internal_syms) +#define elf_gp(bfd) (elf_tdata(bfd) -> gp) +#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) + +extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned)); +extern char * elf_get_str_section PARAMS ((bfd *, unsigned)); + +#define bfd_elf32_mkobject bfd_elf_mkobject +#define bfd_elf64_mkobject bfd_elf_mkobject +#define elf_mkobject bfd_elf_mkobject + +extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *)); + +extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *, + arelent *, + asymbol *, + PTR, + asection *, + bfd *)); +extern boolean bfd_elf_mkobject PARAMS ((bfd *)); +extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *)); + +extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *)); +extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *)); + +extern bfd_target *bfd_elf32_object_p PARAMS ((bfd *)); +extern bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf32_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf32_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); +extern boolean bfd_elf32_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, + bfd_size_type)); + +extern unsigned int bfd_elf32_get_symtab_upper_bound PARAMS ((bfd *)); +extern unsigned int bfd_elf32_get_symtab PARAMS ((bfd *, asymbol **)); +extern unsigned int bfd_elf32_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern unsigned int bfd_elf32_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, + asymbol **)); +extern asymbol *bfd_elf32_make_empty_symbol PARAMS ((bfd *)); +extern void bfd_elf32_print_symbol PARAMS ((bfd *, PTR, asymbol *, + bfd_print_symbol_type)); +extern void bfd_elf32_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *)); +extern alent *bfd_elf32_get_lineno PARAMS ((bfd *, asymbol *)); +extern boolean bfd_elf32_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +extern boolean bfd_elf32_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, + bfd_vma, CONST char **, + CONST char **, + unsigned int *)); +extern int bfd_elf32_sizeof_headers PARAMS ((bfd *, boolean)); +extern void bfd_elf32__write_relocs PARAMS ((bfd *, asection *, PTR)); +extern boolean bfd_elf32_new_section_hook PARAMS ((bfd *, asection *)); + +/* If the target doesn't have reloc handling written yet: */ +extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *, + Elf32_Internal_Rela *)); + +extern bfd_target *bfd_elf64_object_p PARAMS ((bfd *)); +extern bfd_target *bfd_elf64_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf64_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf64_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf64_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); +extern boolean bfd_elf64_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, + bfd_size_type)); + +extern unsigned int bfd_elf64_get_symtab_upper_bound PARAMS ((bfd *)); +extern unsigned int bfd_elf64_get_symtab PARAMS ((bfd *, asymbol **)); +extern unsigned int bfd_elf64_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern unsigned int bfd_elf64_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, + asymbol **)); +extern asymbol *bfd_elf64_make_empty_symbol PARAMS ((bfd *)); +extern void bfd_elf64_print_symbol PARAMS ((bfd *, PTR, asymbol *, + bfd_print_symbol_type)); +extern void bfd_elf64_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *)); +extern alent *bfd_elf64_get_lineno PARAMS ((bfd *, asymbol *)); +extern boolean bfd_elf64_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +extern boolean bfd_elf64_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, + bfd_vma, CONST char **, + CONST char **, + unsigned int *)); +extern int bfd_elf64_sizeof_headers PARAMS ((bfd *, boolean)); +extern void bfd_elf64__write_relocs PARAMS ((bfd *, asection *, PTR)); +extern boolean bfd_elf64_new_section_hook PARAMS ((bfd *, asection *)); + +/* If the target doesn't have reloc handling written yet: */ +extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *, + Elf64_Internal_Rela *)); + +#endif /* _LIBELF_H_ */ diff --git a/gnu/usr.bin/gdb/bfd/opncls.c b/gnu/usr.bin/gdb/bfd/opncls.c new file mode 100644 index 00000000000..42858c25919 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/opncls.c @@ -0,0 +1,534 @@ +/* opncls.c -- open and close a BFD. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +extern void bfd_cache_init PARAMS ((bfd *)); +FILE *bfd_open_file PARAMS ((bfd *)); + +/* fdopen is a loser -- we should use stdio exclusively. Unfortunately + if we do that we can't use fcntl. */ + + +#define obstack_chunk_alloc bfd_xmalloc_by_size_t +#define obstack_chunk_free free + +/* Return a new BFD. All BFD's are allocated through this routine. */ + +bfd * +new_bfd PARAMS ((void)) +{ + bfd *nbfd; + + nbfd = (bfd *)zalloc (sizeof (bfd)); + if (!nbfd) + return 0; + + bfd_check_init(); + obstack_begin((PTR)&nbfd->memory, 128); + + nbfd->arch_info = &bfd_default_arch_struct; + + nbfd->direction = no_direction; + nbfd->iostream = NULL; + nbfd->where = 0; + nbfd->sections = (asection *)NULL; + nbfd->format = bfd_unknown; + nbfd->my_archive = (bfd *)NULL; + nbfd->origin = 0; + nbfd->opened_once = false; + nbfd->output_has_begun = false; + nbfd->section_count = 0; + nbfd->usrdata = (PTR)NULL; + nbfd->cacheable = false; + nbfd->flags = NO_FLAGS; + nbfd->mtime_set = false; + + return nbfd; +} + +/* Allocate a new BFD as a member of archive OBFD. */ + +bfd * +new_bfd_contained_in (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = new_bfd(); + nbfd->xvec = obfd->xvec; + nbfd->my_archive = obfd; + nbfd->direction = read_direction; + nbfd->target_defaulted = obfd->target_defaulted; + return nbfd; +} + +/* +SECTION + Opening and Closing BFDs + +*/ + +/* +FUNCTION + bfd_openr + +SYNOPSIS + bfd *bfd_openr(CONST char *filename, CONST char*target); + +DESCRIPTION + This function opens the file supplied (using <>) with the target + supplied, it returns a pointer to the created BFD. + + If NULL is returned then an error has occured. Possible errors + are <>, <> or <> error. +*/ + +bfd * +DEFUN(bfd_openr, (filename, target), + CONST char *filename AND + CONST char *target) +{ + bfd *nbfd; + bfd_target *target_vec; + + nbfd = new_bfd(); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) { + bfd_error = invalid_target; + return NULL; + } + + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_error = system_call_error; /* File didn't exist, or some such */ + bfd_release(nbfd,0); + return NULL; + } + return nbfd; +} + + +/* Don't try to `optimize' this function: + + o - We lock using stack space so that interrupting the locking + won't cause a storage leak. + o - We open the file stream last, since we don't want to have to + close it if anything goes wrong. Closing the stream means closing + the file descriptor too, even though we didn't open it. + */ +/* +FUNCTION + bfd_fdopenr + +SYNOPSIS + bfd *bfd_fdopenr(CONST char *filename, CONST char *target, int fd); + +DESCRIPTION + bfd_fdopenr is to bfd_fopenr much like fdopen is to fopen. + It opens a BFD on a file already described by the @var{fd} + supplied. + + When the file is later bfd_closed, the file descriptor will be closed. + + If the caller desires that this file descriptor be cached by BFD + (opened as needed, closed as needed to free descriptors for + other opens), with the supplied @var{fd} used as an initial + file descriptor (but subject to closure at any time), set + bfd->cacheable nonzero in the returned BFD. The default is to + assume no cacheing; the file descriptor will remain open until + bfd_close, and will not be affected by BFD operations on other + files. + + Possible errors are no_memory, invalid_target and system_call + error. +*/ + +bfd * +DEFUN(bfd_fdopenr,(filename, target, fd), + CONST char *filename AND + CONST char *target AND + int fd) +{ + bfd *nbfd; + bfd_target *target_vec; + int fdflags; + + bfd_error = system_call_error; + +#ifdef NO_FCNTL + fdflags = O_RDWR; /* Assume full access */ +#else + fdflags = fcntl (fd, F_GETFL, NULL); +#endif + if (fdflags == -1) return NULL; + + nbfd = new_bfd(); + + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) { + bfd_error = invalid_target; + return NULL; + } +#if defined(VMS) || defined(__GO32__) + nbfd->iostream = (char *)fopen(filename, FOPEN_RB); +#else + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (fdflags & (O_ACCMODE)) { + case O_RDONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RB); break; + case O_WRONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break; + case O_RDWR: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break; + default: abort (); + } +#endif + if (nbfd->iostream == NULL) { + (void) obstack_free (&nbfd->memory, (PTR)0); + return NULL; + } + + /* OK, put everything where it belongs */ + + nbfd->filename = filename; + + /* As a special case we allow a FD open for read/write to + be written through, although doing so requires that we end + the previous clause with a preposition. */ + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (fdflags & (O_ACCMODE)) { + case O_RDONLY: nbfd->direction = read_direction; break; + case O_WRONLY: nbfd->direction = write_direction; break; + case O_RDWR: nbfd->direction = both_direction; break; + default: abort (); + } + + bfd_cache_init (nbfd); + + return nbfd; +} + +/** bfd_openw -- open for writing. + Returns a pointer to a freshly-allocated BFD on success, or NULL. + + See comment by bfd_fdopenr before you try to modify this function. */ + +/* +FUNCTION + bfd_openw + +SYNOPSIS + bfd *bfd_openw(CONST char *filename, CONST char *target); + +DESCRIPTION + Creates a BFD, associated with file @var{filename}, using the + file format @var{target}, and returns a pointer to it. + + Possible errors are system_call_error, no_memory, + invalid_target. +*/ + +bfd * +DEFUN(bfd_openw,(filename, target), + CONST char *filename AND + CONST char *target) +{ + bfd *nbfd; + bfd_target *target_vec; + + bfd_error = system_call_error; + + /* nbfd has to point to head of malloc'ed block so that bfd_close may + reclaim it correctly. */ + + nbfd = new_bfd(); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) return NULL; + + nbfd->filename = filename; + nbfd->direction = write_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_error = system_call_error; /* File not writeable, etc */ + (void) obstack_free (&nbfd->memory, (PTR)0); + return NULL; + } + return nbfd; +} + +/* + +FUNCTION + bfd_close + +SYNOPSIS + boolean bfd_close(bfd *); + +DESCRIPTION + + This function closes a BFD. If the BFD was open for writing, + then pending operations are completed and the file written out + and closed. If the created file is executable, then + <> is called to mark it as such. + + All memory attached to the BFD's obstacks is released. + + The file descriptor associated with the BFD is closed (even + if it was passed in to BFD by bfd_fdopenr). + +RETURNS + <> is returned if all is ok, otherwise <>. +*/ + + +boolean +DEFUN(bfd_close,(abfd), + bfd *abfd) +{ + boolean ret; + + if (!bfd_read_p(abfd)) + if (BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)) != true) + return false; + + if (BFD_SEND (abfd, _close_and_cleanup, (abfd)) != true) return false; + + ret = bfd_cache_close(abfd); + + /* If the file was open for writing and is now executable, + make it so */ + if (ret == true + && abfd->direction == write_direction + && abfd->flags & EXEC_P) { + struct stat buf; + stat(abfd->filename, &buf); +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + + chmod(abfd->filename, 0777 & (buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH)); + } + (void) obstack_free (&abfd->memory, (PTR)0); + (void) free(abfd); + return ret; +} + +/* +FUNCTION + bfd_close_all_done + +SYNOPSIS + boolean bfd_close_all_done(bfd *); + +DESCRIPTION + This function closes a BFD. It differs from <> + since it does not complete any pending operations. This + routine would be used if the application had just used BFD for + swapping and didn't want to use any of the writing code. + + If the created file is executable, then <> is called + to mark it as such. + + All memory attached to the BFD's obstacks is released. + +RETURNS + <> is returned if all is ok, otherwise <>. + +*/ + +boolean +DEFUN(bfd_close_all_done,(abfd), + bfd *abfd) +{ + boolean ret; + + ret = bfd_cache_close(abfd); + + /* If the file was open for writing and is now executable, + make it so */ + if (ret == true + && abfd->direction == write_direction + && abfd->flags & EXEC_P) { + struct stat buf; + stat(abfd->filename, &buf); +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + + chmod(abfd->filename, 0x777 &(buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH)); + } + (void) obstack_free (&abfd->memory, (PTR)0); + (void) free(abfd); + return ret; +} + + +/* +FUNCTION + bfd_alloc_size + +SYNOPSIS + bfd_size_type bfd_alloc_size(bfd *abfd); + +DESCRIPTION + Return the number of bytes in the obstacks connected to the + supplied BFD. + +*/ + +bfd_size_type +DEFUN(bfd_alloc_size,(abfd), + bfd *abfd) +{ + struct _obstack_chunk *chunk = abfd->memory.chunk; + size_t size = 0; + while (chunk) { + size += chunk->limit - &(chunk->contents[0]); + chunk = chunk->prev; + } + return size; +} + + + +/* +FUNCTION + bfd_create + +SYNOPSIS + bfd *bfd_create(CONST char *filename, bfd *templ); + +DESCRIPTION + This routine creates a new BFD in the manner of + <>, but without opening a file. The new BFD + takes the target from the target used by @var{template}. The + format is always set to <>. + +*/ + +bfd * +DEFUN(bfd_create,(filename, templ), + CONST char *filename AND + bfd *templ) +{ + bfd *nbfd = new_bfd(); + if (nbfd == (bfd *)NULL) { + bfd_error = no_memory; + return (bfd *)NULL; + } + nbfd->filename = filename; + if(templ) { + nbfd->xvec = templ->xvec; + } + nbfd->direction = no_direction; + bfd_set_format(nbfd, bfd_object); + return nbfd; +} + +/* +INTERNAL_FUNCTION + bfd_alloc_by_size_t + +SYNOPSIS + PTR bfd_alloc_by_size_t(bfd *abfd, size_t wanted); + +DESCRIPTION + This function allocates a block of memory in the obstack + attatched to <> and returns a pointer to it. +*/ + + +PTR +DEFUN(bfd_alloc_by_size_t,(abfd, size), + bfd *abfd AND + size_t size) +{ + PTR res = obstack_alloc(&(abfd->memory), size); + return res; +} + +DEFUN(void bfd_alloc_grow,(abfd, ptr, size), + bfd *abfd AND + PTR ptr AND + size_t size) +{ + (void) obstack_grow(&(abfd->memory), ptr, size); +} +DEFUN(PTR bfd_alloc_finish,(abfd), + bfd *abfd) +{ + return obstack_finish(&(abfd->memory)); +} + +DEFUN(PTR bfd_alloc, (abfd, size), + bfd *abfd AND + size_t size) +{ + return bfd_alloc_by_size_t(abfd, (size_t)size); +} + +DEFUN(PTR bfd_zalloc,(abfd, size), + bfd *abfd AND + size_t size) +{ + PTR res; + res = bfd_alloc(abfd, size); + memset(res, 0, (size_t)size); + return res; +} + +DEFUN(PTR bfd_realloc,(abfd, old, size), + bfd *abfd AND + PTR old AND + size_t size) +{ + PTR res = bfd_alloc(abfd, size); + memcpy(res, old, (size_t)size); + return res; +} diff --git a/gnu/usr.bin/gdb/bfd/reloc.c b/gnu/usr.bin/gdb/bfd/reloc.c new file mode 100644 index 00000000000..f2dd5201d44 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/reloc.c @@ -0,0 +1,1225 @@ +/* BFD support for handling relocation entries. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + Relocations + + BFD maintains relocations in much the same was as it maintains + symbols; they are left alone until required, then read in + en-mass and traslated into an internal form. There is a common + routine <> which acts upon the + canonical form to do the actual fixup. + + Note that relocations are maintained on a per section basis, + whilst symbols are maintained on a per BFD basis. + + All a back end has to do to fit the BFD interface is to create + as many <> as there are relocations + in a particular section, and fill in the right bits: + +@menu +@* typedef arelent:: +@* howto manager:: +@end menu + +*/ +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +/* +DOCDD +INODE + typedef arelent, howto manager, Relocations, Relocations + +SUBSECTION + typedef arelent + + This is the structure of a relocation entry: + +CODE_FRAGMENT +. +.typedef enum bfd_reloc_status +.{ +. {* No errors detected *} +. bfd_reloc_ok, +. +. {* The relocation was performed, but there was an overflow. *} +. bfd_reloc_overflow, +. +. {* The address to relocate was not within the section supplied. *} +. bfd_reloc_outofrange, +. +. {* Used by special functions *} +. bfd_reloc_continue, +. +. {* Unused *} +. bfd_reloc_notsupported, +. +. {* Unsupported relocation size requested. *} +. bfd_reloc_other, +. +. {* The symbol to relocate against was undefined. *} +. bfd_reloc_undefined, +. +. {* The relocation was performed, but may not be ok - presently +. generated only when linking i960 coff files with i960 b.out +. symbols. *} +. bfd_reloc_dangerous +. } +. bfd_reloc_status_type; +. +. +.typedef struct reloc_cache_entry +.{ +. {* A pointer into the canonical table of pointers *} +. struct symbol_cache_entry **sym_ptr_ptr; +. +. {* offset in section *} +. bfd_size_type address; +. +. {* addend for relocation value *} +. bfd_vma addend; +. +. {* Pointer to how to perform the required relocation *} +. CONST struct reloc_howto_struct *howto; +. +.} arelent; + +*/ + +/* +DESCRIPTION + + Here is a description of each of the fields within a relent: + + o sym_ptr_ptr + + The symbol table pointer points to a pointer to the symbol + associated with the relocation request. This would naturally + be the pointer into the table returned by the back end's + get_symtab action. @xref{Symbols}. The symbol is referenced + through a pointer to a pointer so that tools like the linker + can fix up all the symbols of the same name by modifying only + one pointer. The relocation routine looks in the symbol and + uses the base of the section the symbol is attached to and the + value of the symbol as the initial relocation offset. If the + symbol pointer is zero, then the section provided is looked up. + + o address + + The address field gives the offset in bytes from the base of + the section data which owns the relocation record to the first + byte of relocatable information. The actual data relocated + will be relative to this point - for example, a relocation + type which modifies the bottom two bytes of a four byte word + would not touch the first byte pointed to in a big endian + world. + + o addend + + The addend is a value provided by the back end to be added (!) + to the relocation offset. Its interpretation is dependent upon + the howto. For example, on the 68k the code: + + +| char foo[]; +| main() +| { +| return foo[0x12345678]; +| } + + Could be compiled into: + +| linkw fp,#-4 +| moveb @@#12345678,d0 +| extbl d0 +| unlk fp +| rts + + + This could create a reloc pointing to foo, but leave the + offset in the data (something like) + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000006 32 _foo +| +|00000000 4e56 fffc ; linkw fp,#-4 +|00000004 1039 1234 5678 ; moveb @@#12345678,d0 +|0000000a 49c0 ; extbl d0 +|0000000c 4e5e ; unlk fp +|0000000e 4e75 ; rts + + + Using coff and an 88k, some instructions don't have enough + space in them to represent the full address range, and + pointers have to be loaded in two parts. So you'd get something like: + + +| or.u r13,r0,hi16(_foo+0x12345678) +| ld.b r2,r13,lo16(_foo+0x12345678) +| jmp r1 + + + This should create two relocs, both pointing to _foo, and with + 0x12340000 in their addend field. The data would consist of: + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000002 HVRT16 _foo+0x12340000 +|00000006 LVRT16 _foo+0x12340000 + +|00000000 5da05678 ; or.u r13,r0,0x5678 +|00000004 1c4d5678 ; ld.b r2,r13,0x5678 +|00000008 f400c001 ; jmp r1 + + + The relocation routine digs out the value from the data, adds + it to the addend to get the original offset and then adds the + value of _foo. Note that all 32 bits have to be kept around + somewhere, to cope with carry from bit 15 to bit 16. + + One further example is the sparc and the a.out format. The + sparc has a similar problem to the 88k, in that some + instructions don't have room for an entire offset, but on the + sparc the parts are created odd sized lumps. The designers of + the a.out format chose not to use the data within the section + for storing part of the offset; all the offset is kept within + the reloc. Any thing in the data should be ignored. + +| save %sp,-112,%sp +| sethi %hi(_foo+0x12345678),%g2 +| ldsb [%g2+%lo(_foo+0x12345678)],%i0 +| ret +| restore + + Both relocs contains a pointer to foo, and the offsets would + contain junk. + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000004 HI22 _foo+0x12345678 +|00000008 LO10 _foo+0x12345678 + +|00000000 9de3bf90 ; save %sp,-112,%sp +|00000004 05000000 ; sethi %hi(_foo+0),%g2 +|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0 +|0000000c 81c7e008 ; ret +|00000010 81e80000 ; restore + + + o howto + + The howto field can be imagined as a + relocation instruction. It is a pointer to a struct which + contains information on what to do with all the other + information in the reloc record and data section. A back end + would normally have a relocation instruction set and turn + relocations into pointers to the correct structure on input - + but it would be possible to create each howto field on demand. + +*/ + +/* +SUBSUBSECTION + <> + + Indicates what sort of overflow checking should be done when + performing a relocation. + +CODE_FRAGMENT +. +.enum complain_overflow +.{ +. {* Do not complain on overflow. *} +. complain_overflow_dont, +. +. {* Complain if the bitfield overflows, whether it is considered +. as signed or unsigned. *} +. complain_overflow_bitfield, +. +. {* Complain if the value overflows when considered as signed +. number. *} +. complain_overflow_signed, +. +. {* Complain if the value overflows when considered as an +. unsigned number. *} +. complain_overflow_unsigned +.}; + +*/ + +/* +SUBSUBSECTION + <> + + The <> is a structure which contains all the + information that BFD needs to know to tie up a back end's data. + +CODE_FRAGMENT +.struct symbol_cache_entry; {* Forward declaration *} +. +.typedef CONST struct reloc_howto_struct +.{ +. {* The type field has mainly a documetary use - the back end can +. to what it wants with it, though the normally the back end's +. external idea of what a reloc number would be would be stored +. in this field. For example, the a PC relative word relocation +. in a coff environment would have the type 023 - because that's +. what the outside world calls a R_PCRWORD reloc. *} +. unsigned int type; +. +. {* The value the final relocation is shifted right by. This drops +. unwanted data from the relocation. *} +. unsigned int rightshift; +. +. {* The size of the item to be relocated. This is *not* a +. power-of-two measure. +. 0 : one byte +. 1 : two bytes +. 2 : four bytes +. 3 : nothing done (unless special_function is nonzero) +. 4 : eight bytes +. -2 : two bytes, result should be subtracted from the +. data instead of added +. There is currently no trivial way to extract a "number of +. bytes" from a howto pointer. *} +. int size; +. +. {* The number of bits in the item to be relocated. This is used +. when doing overflow checking. *} +. unsigned int bitsize; +. +. {* Notes that the relocation is relative to the location in the +. data section of the addend. The relocation function will +. subtract from the relocation value the address of the location +. being relocated. *} +. boolean pc_relative; +. +. {* The bit position of the reloc value in the destination. +. The relocated value is left shifted by this amount. *} +. unsigned int bitpos; +. +. {* What type of overflow error should be checked for when +. relocating. *} +. enum complain_overflow complain_on_overflow; +. +. {* If this field is non null, then the supplied function is +. called rather than the normal function. This allows really +. strange relocation methods to be accomodated (e.g., i960 callj +. instructions). *} +. bfd_reloc_status_type (*special_function) +. PARAMS ((bfd *abfd, +. arelent *reloc_entry, +. struct symbol_cache_entry *symbol, +. PTR data, +. asection *input_section, +. bfd *output_bfd)); +. +. {* The textual name of the relocation type. *} +. char *name; +. +. {* When performing a partial link, some formats must modify the +. relocations rather than the data - this flag signals this.*} +. boolean partial_inplace; +. +. {* The src_mask is used to select what parts of the read in data +. are to be used in the relocation sum. E.g., if this was an 8 bit +. bit of data which we read and relocated, this would be +. 0x000000ff. When we have relocs which have an addend, such as +. sun4 extended relocs, the value in the offset part of a +. relocating field is garbage so we never use it. In this case +. the mask would be 0x00000000. *} +. bfd_vma src_mask; +. +. {* The dst_mask is what parts of the instruction are replaced +. into the instruction. In most cases src_mask == dst_mask, +. except in the above special case, where dst_mask would be +. 0x000000ff, and src_mask would be 0x00000000. *} +. bfd_vma dst_mask; +. +. {* When some formats create PC relative instructions, they leave +. the value of the pc of the place being relocated in the offset +. slot of the instruction, so that a PC relative relocation can +. be made just by adding in an ordinary offset (e.g., sun3 a.out). +. Some formats leave the displacement part of an instruction +. empty (e.g., m88k bcs), this flag signals the fact.*} +. boolean pcrel_offset; +. +.} reloc_howto_type; + +*/ + +/* +FUNCTION + the HOWTO macro + +DESCRIPTION + The HOWTO define is horrible and will go away. + + +.#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ +. {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} + +DESCRIPTION + And will be replaced with the totally magic way. But for the + moment, we are compatible, so do it this way.. + + +.#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) +. +DESCRIPTION + Helper routine to turn a symbol into a relocation value. + +.#define HOWTO_PREPARE(relocation, symbol) \ +. { \ +. if (symbol != (asymbol *)NULL) { \ +. if (bfd_is_com_section (symbol->section)) { \ +. relocation = 0; \ +. } \ +. else { \ +. relocation = symbol->value; \ +. } \ +. } \ +.} + +*/ + +/* +TYPEDEF + reloc_chain + +DESCRIPTION + + How relocs are tied together + +.typedef unsigned char bfd_byte; +. +.typedef struct relent_chain { +. arelent relent; +. struct relent_chain *next; +.} arelent_chain; + +*/ + + + +/* +FUNCTION + bfd_perform_relocation + +SYNOPSIS + bfd_reloc_status_type + bfd_perform_relocation + (bfd * abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd); + +DESCRIPTION + If an output_bfd is supplied to this function the generated + image will be relocatable, the relocations are copied to the + output file after they have been changed to reflect the new + state of the world. There are two ways of reflecting the + results of partial linkage in an output file; by modifying the + output data in place, and by modifying the relocation record. + Some native formats (e.g., basic a.out and basic coff) have no + way of specifying an addend in the relocation type, so the + addend has to go in the output data. This is no big deal + since in these formats the output data slot will always be big + enough for the addend. Complex reloc types with addends were + invented to solve just this problem. + +*/ + + +bfd_reloc_status_type +DEFUN(bfd_perform_relocation,(abfd, + reloc_entry, + data, + input_section, + output_bfd), + bfd *abfd AND + arelent *reloc_entry AND + PTR data AND + asection *input_section AND + bfd *output_bfd) +{ + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type addr = reloc_entry->address ; + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section ; + + asymbol *symbol; + + symbol = *( reloc_entry->sym_ptr_ptr); + if ((symbol->section == &bfd_abs_section) + && output_bfd != (bfd *)NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we are not producing relocateable output, return an error if + the symbol is not defined. An undefined weak symbol is + considered to have a value of zero (SVR4 ABI, p. 4-27). */ + if (symbol->section == &bfd_und_section + && (symbol->flags & BSF_WEAK) == 0 + && output_bfd == (bfd *) NULL) + flag = bfd_reloc_undefined; + + /* If there is a function supplied to handle this relocation type, + call it. It'll return `bfd_reloc_continue' if further processing + can be done. */ + if (howto->special_function) + { + bfd_reloc_status_type cont; + cont = howto->special_function (abfd, reloc_entry, symbol, data, + input_section, output_bfd); + if (cont != bfd_reloc_continue) + return cont; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (output_bfd && howto->partial_inplace==false) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative == true) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is false. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is true. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is false we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is true + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset == true) + relocation -= reloc_entry->address; + } + + if (output_bfd!= (bfd *)NULL) + { + if ( howto->partial_inplace == false) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour) + { + relocation -= reloc_entry->addend; + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + } + else + { + reloc_entry->addend = 0; + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma check; + + /* Get the value that will be used for the relocation, but + starting at bit position zero. */ + if (howto->rightshift > howto->bitpos) + check = relocation >> (howto->rightshift - howto->bitpos); + else + check = relocation << (howto->bitpos - howto->rightshift); + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; + + /* The above right shift is incorrect for a signed value. + Fix it up by forcing on the upper bits. */ + if (howto->rightshift > howto->bitpos + && (bfd_signed_vma) relocation < 0) + check |= ((bfd_vma) -1 + &~ ((bfd_vma) -1 + >> (howto->rightshift - howto->bitpos))); + if ((bfd_signed_vma) check > reloc_signed_max + || (bfd_signed_vma) check < reloc_signed_min) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((bfd_vma) check > reloc_unsigned_max) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (((bfd_vma) check &~ reloc_bits) != 0 + && ((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits)) + { + /* The above right shift is incorrect for a signed + value. See if turning on the upper bits fixes the + overflow. */ + if (howto->rightshift > howto->bitpos + && (bfd_signed_vma) relocation < 0) + { + check |= ((bfd_vma) -1 + &~ ((bfd_vma) -1 + >> (howto->rightshift - howto->bitpos))); + if (((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits)) + flag = bfd_reloc_overflow; + } + else + flag = bfd_reloc_overflow; + } + } + break; + default: + abort (); + } + } + + /* + Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs) + */ + relocation >>= howto->rightshift; + + /* Shift everything up to where it's going to be used */ + + relocation <<= howto->bitpos; + + /* Wait for the day when all have the mask in them */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + i i i i i o o o o o from bfd_get + and S S S S S to get the size offset we want + + r r r r r r r r r r to get the final value to place + and D D D D D to chop to right size + ----------------------- + A A A A A + And this: + ... i i i i i o o o o o from bfd_get + and N N N N N get instruction + ----------------------- + ... B B B B B + + And then: + B B B B B + or A A A A A + ----------------------- + R R R R R R R R R R put into bfd_put + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8(abfd, (char *)data + addr); + DOIT(x); + bfd_put_8(abfd,x, (unsigned char *) data + addr); + } + break; + + case 1: + if (relocation) + { + short x = bfd_get_16(abfd, (bfd_byte *)data + addr); + DOIT(x); + bfd_put_16(abfd, x, (unsigned char *)data + addr); + } + break; + case 2: + if (relocation) + { + long x = bfd_get_32 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_32 (abfd, x, (bfd_byte *)data + addr); + } + break; + case -2: + { + long x = bfd_get_32(abfd, (bfd_byte *) data + addr); + relocation = -relocation; + DOIT(x); + bfd_put_32(abfd,x, (bfd_byte *)data + addr); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: +#ifdef BFD64 + if (relocation) + { + bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_64 (abfd, x, (bfd_byte *) data + addr); + } +#else + abort (); +#endif + break; + default: + return bfd_reloc_other; + } + + return flag; +} + + + +/* +DOCDD +INODE + howto manager, , typedef arelent, Relocations + +SECTION + The howto manager + + When an application wants to create a relocation, but doesn't + know what the target machine might call it, it can find out by + using this bit of code. + +*/ + +/* +TYPEDEF + bfd_reloc_code_type + +DESCRIPTION + The insides of a reloc code. The idea is that, eventually, there + will be one enumerator for every type of relocation we ever do. + Pass one of these values to <>, and it'll + return a howto pointer. + + This does mean that the application must determine the correct + enumerator value; you can't get a howto pointer from a random set + of attributes. + +CODE_FRAGMENT +. +.typedef enum bfd_reloc_code_real +.{ +. {* Basic absolute relocations *} +. BFD_RELOC_64, +. BFD_RELOC_32, +. BFD_RELOC_16, +. BFD_RELOC_8, +. +. {* PC-relative relocations *} +. BFD_RELOC_64_PCREL, +. BFD_RELOC_32_PCREL, +. BFD_RELOC_24_PCREL, {* used by i960 *} +. BFD_RELOC_16_PCREL, +. BFD_RELOC_8_PCREL, +. +. {* Linkage-table relative *} +. BFD_RELOC_32_BASEREL, +. BFD_RELOC_16_BASEREL, +. BFD_RELOC_8_BASEREL, +. +. {* The type of reloc used to build a contructor table - at the moment +. probably a 32 bit wide abs address, but the cpu can choose. *} +. BFD_RELOC_CTOR, +. +. {* 8 bits wide, but used to form an address like 0xffnn *} +. BFD_RELOC_8_FFnn, +. +. {* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit +. word displacement, e.g. for SPARC) *} +. BFD_RELOC_32_PCREL_S2, +. +. {* High 22 bits of 32-bit value, placed into lower 22 bits of +. target word; simple reloc. *} +. BFD_RELOC_HI22, +. {* Low 10 bits. *} +. BFD_RELOC_LO10, +. +. {* Reloc types used for i960/b.out. *} +. BFD_RELOC_I960_CALLJ, +. +. {* now for the sparc/elf codes *} +. BFD_RELOC_NONE, {* actually used *} +. BFD_RELOC_SPARC_WDISP22, +. BFD_RELOC_SPARC22, +. BFD_RELOC_SPARC13, +. BFD_RELOC_SPARC_GOT10, +. BFD_RELOC_SPARC_GOT13, +. BFD_RELOC_SPARC_GOT22, +. BFD_RELOC_SPARC_PC10, +. BFD_RELOC_SPARC_PC22, +. BFD_RELOC_SPARC_WPLT30, +. BFD_RELOC_SPARC_COPY, +. BFD_RELOC_SPARC_GLOB_DAT, +. BFD_RELOC_SPARC_JMP_SLOT, +. BFD_RELOC_SPARC_RELATIVE, +. BFD_RELOC_SPARC_UA32, +. +. {* these are a.out specific? *} +. BFD_RELOC_SPARC_BASE13, +. BFD_RELOC_SPARC_BASE22, +. +. +. {* Bits 27..2 of the relocation address shifted right 2 bits; +. simple reloc otherwise. *} +. BFD_RELOC_MIPS_JMP, +. +. {* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) *} +. BFD_RELOC_16_PCREL_S2, +. +. {* High 16 bits of 32-bit value; simple reloc. *} +. BFD_RELOC_HI16, +. {* High 16 bits of 32-bit value but the low 16 bits will be sign +. extended and added to form the final result. If the low 16 +. bits form a negative number, we need to add one to the high value +. to compensate for the borrow when the low bits are added. *} +. BFD_RELOC_HI16_S, +. {* Low 16 bits. *} +. BFD_RELOC_LO16, +. +. {* 16 bit relocation relative to the global pointer. *} +. BFD_RELOC_MIPS_GPREL, +. +. {* These are, so far, specific to HPPA processors. I'm not sure that some +. don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL. +. Also, many more were in the list I got that don't fit in well in the +. model BFD uses, so I've omitted them for now. If we do make this reloc +. type get used for code that really does implement the funky reloc types, +. they'll have to be added to this list. *} +. BFD_RELOC_HPPA_32, +. BFD_RELOC_HPPA_11, +. BFD_RELOC_HPPA_14, +. BFD_RELOC_HPPA_17, +. +. BFD_RELOC_HPPA_L21, +. BFD_RELOC_HPPA_R11, +. BFD_RELOC_HPPA_R14, +. BFD_RELOC_HPPA_R17, +. BFD_RELOC_HPPA_LS21, +. BFD_RELOC_HPPA_RS11, +. BFD_RELOC_HPPA_RS14, +. BFD_RELOC_HPPA_RS17, +. BFD_RELOC_HPPA_LD21, +. BFD_RELOC_HPPA_RD11, +. BFD_RELOC_HPPA_RD14, +. BFD_RELOC_HPPA_RD17, +. BFD_RELOC_HPPA_LR21, +. BFD_RELOC_HPPA_RR14, +. BFD_RELOC_HPPA_RR17, +. +. BFD_RELOC_HPPA_GOTOFF_11, +. BFD_RELOC_HPPA_GOTOFF_14, +. BFD_RELOC_HPPA_GOTOFF_L21, +. BFD_RELOC_HPPA_GOTOFF_R11, +. BFD_RELOC_HPPA_GOTOFF_R14, +. BFD_RELOC_HPPA_GOTOFF_LS21, +. BFD_RELOC_HPPA_GOTOFF_RS11, +. BFD_RELOC_HPPA_GOTOFF_RS14, +. BFD_RELOC_HPPA_GOTOFF_LD21, +. BFD_RELOC_HPPA_GOTOFF_RD11, +. BFD_RELOC_HPPA_GOTOFF_RD14, +. BFD_RELOC_HPPA_GOTOFF_LR21, +. BFD_RELOC_HPPA_GOTOFF_RR14, +. +. BFD_RELOC_HPPA_DLT_32, +. BFD_RELOC_HPPA_DLT_11, +. BFD_RELOC_HPPA_DLT_14, +. BFD_RELOC_HPPA_DLT_L21, +. BFD_RELOC_HPPA_DLT_R11, +. BFD_RELOC_HPPA_DLT_R14, +. +. BFD_RELOC_HPPA_ABS_CALL_11, +. BFD_RELOC_HPPA_ABS_CALL_14, +. BFD_RELOC_HPPA_ABS_CALL_17, +. BFD_RELOC_HPPA_ABS_CALL_L21, +. BFD_RELOC_HPPA_ABS_CALL_R11, +. BFD_RELOC_HPPA_ABS_CALL_R14, +. BFD_RELOC_HPPA_ABS_CALL_R17, +. BFD_RELOC_HPPA_ABS_CALL_LS21, +. BFD_RELOC_HPPA_ABS_CALL_RS11, +. BFD_RELOC_HPPA_ABS_CALL_RS14, +. BFD_RELOC_HPPA_ABS_CALL_RS17, +. BFD_RELOC_HPPA_ABS_CALL_LD21, +. BFD_RELOC_HPPA_ABS_CALL_RD11, +. BFD_RELOC_HPPA_ABS_CALL_RD14, +. BFD_RELOC_HPPA_ABS_CALL_RD17, +. BFD_RELOC_HPPA_ABS_CALL_LR21, +. BFD_RELOC_HPPA_ABS_CALL_RR14, +. BFD_RELOC_HPPA_ABS_CALL_RR17, +. +. BFD_RELOC_HPPA_PCREL_CALL_11, +. BFD_RELOC_HPPA_PCREL_CALL_12, +. BFD_RELOC_HPPA_PCREL_CALL_14, +. BFD_RELOC_HPPA_PCREL_CALL_17, +. BFD_RELOC_HPPA_PCREL_CALL_L21, +. BFD_RELOC_HPPA_PCREL_CALL_R11, +. BFD_RELOC_HPPA_PCREL_CALL_R14, +. BFD_RELOC_HPPA_PCREL_CALL_R17, +. BFD_RELOC_HPPA_PCREL_CALL_LS21, +. BFD_RELOC_HPPA_PCREL_CALL_RS11, +. BFD_RELOC_HPPA_PCREL_CALL_RS14, +. BFD_RELOC_HPPA_PCREL_CALL_RS17, +. BFD_RELOC_HPPA_PCREL_CALL_LD21, +. BFD_RELOC_HPPA_PCREL_CALL_RD11, +. BFD_RELOC_HPPA_PCREL_CALL_RD14, +. BFD_RELOC_HPPA_PCREL_CALL_RD17, +. BFD_RELOC_HPPA_PCREL_CALL_LR21, +. BFD_RELOC_HPPA_PCREL_CALL_RR14, +. BFD_RELOC_HPPA_PCREL_CALL_RR17, +. +. BFD_RELOC_HPPA_PLABEL_32, +. BFD_RELOC_HPPA_PLABEL_11, +. BFD_RELOC_HPPA_PLABEL_14, +. BFD_RELOC_HPPA_PLABEL_L21, +. BFD_RELOC_HPPA_PLABEL_R11, +. BFD_RELOC_HPPA_PLABEL_R14, +. +. BFD_RELOC_HPPA_UNWIND_ENTRY, +. BFD_RELOC_HPPA_UNWIND_ENTRIES, +. +. {* i386/elf relocations *} +. BFD_RELOC_386_GOT32, +. BFD_RELOC_386_PLT32, +. BFD_RELOC_386_COPY, +. BFD_RELOC_386_GLOB_DAT, +. BFD_RELOC_386_JUMP_SLOT, +. BFD_RELOC_386_RELATIVE, +. BFD_RELOC_386_GOTOFF, +. BFD_RELOC_386_GOTPC, +. +. {* this must be the highest numeric value *} +. BFD_RELOC_UNUSED +. } bfd_reloc_code_real_type; +*/ + + +/* +SECTION + bfd_reloc_type_lookup + +SYNOPSIS + CONST struct reloc_howto_struct * + bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code); + +DESCRIPTION + This routine returns a pointer to a howto struct which when + invoked, will perform the supplied relocation on data from the + architecture noted. + +*/ + + +CONST struct reloc_howto_struct * +DEFUN(bfd_reloc_type_lookup,(abfd, code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ + return BFD_SEND (abfd, reloc_type_lookup, (abfd, code)); +} + +static reloc_howto_type bfd_howto_32 = + HOWTO(0, 00,2,32,false,0,complain_overflow_bitfield,0,"VRT32", false,0xffffffff,0xffffffff,true); + + +/* +INTERNAL_FUNCTION + bfd_default_reloc_type_lookup + +SYNOPSIS + CONST struct reloc_howto_struct *bfd_default_reloc_type_lookup + (bfd *abfd AND + bfd_reloc_code_real_type code); + +DESCRIPTION + Provides a default relocation lookup routine for any architecture. + + +*/ + +CONST struct reloc_howto_struct * +DEFUN(bfd_default_reloc_type_lookup, (abfd, code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ + switch (code) + { + case BFD_RELOC_CTOR: + /* The type of reloc used in a ctor, which will be as wide as the + address - so either a 64, 32, or 16 bitter. */ + switch (bfd_get_arch_info (abfd)->bits_per_address) { + case 64: + BFD_FAIL(); + case 32: + return &bfd_howto_32; + case 16: + BFD_FAIL(); + default: + BFD_FAIL(); + } + default: + BFD_FAIL(); + } + return (CONST struct reloc_howto_struct *)NULL; +} + + +/* +INTERNAL_FUNCTION + bfd_generic_relax_section + +SYNOPSIS + boolean bfd_generic_relax_section + (bfd *abfd, + asection *section, + asymbol **symbols); + +DESCRIPTION + Provides default handling for relaxing for back ends which + don't do relaxing -- i.e., does nothing. +*/ + +boolean +DEFUN(bfd_generic_relax_section,(abfd, section, symbols), + bfd *abfd AND + asection *section AND + asymbol **symbols) +{ + + return false; + +} + + +/* +INTERNAL_FUNCTION + bfd_generic_get_relocated_section_contents + +SYNOPSIS + bfd_byte * + bfd_generic_get_relocated_section_contents (bfd *abfd, + struct bfd_seclet *seclet, + bfd_byte *data, + boolean relocateable); + +DESCRIPTION + Provides default handling of relocation effort for back ends + which can't be bothered to do it efficiently. + +*/ + +bfd_byte * +DEFUN(bfd_generic_get_relocated_section_contents,(abfd, + seclet, + data, + relocateable), + bfd *abfd AND + struct bfd_seclet *seclet AND + bfd_byte *data AND + boolean relocateable) +{ + extern bfd_error_vector_type bfd_error_vector; + + /* Get enough memory to hold the stuff */ + bfd *input_bfd = seclet->u.indirect.section->owner; + asection *input_section = seclet->u.indirect.section; + + + + size_t reloc_size = bfd_get_reloc_upper_bound(input_bfd, input_section); + arelent **reloc_vector = (arelent **) alloca(reloc_size); + + /* read in the section */ + bfd_get_section_contents(input_bfd, + input_section, + data, + 0, + input_section->_raw_size); + +/* We're not relaxing the section, so just copy the size info */ + input_section->_cooked_size = input_section->_raw_size; + input_section->reloc_done = true; + + + if (bfd_canonicalize_reloc(input_bfd, + input_section, + reloc_vector, + seclet->u.indirect.symbols) ) + { + arelent **parent; + for (parent = reloc_vector; * parent != (arelent *)NULL; + parent++) + { + bfd_reloc_status_type r= + bfd_perform_relocation(input_bfd, + *parent, + data, + input_section, + relocateable ? abfd : (bfd *) NULL); + + if (relocateable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + bfd_error_vector.undefined_symbol(*parent, seclet); + break; + case bfd_reloc_dangerous: + bfd_error_vector.reloc_dangerous(*parent, seclet); + break; + case bfd_reloc_outofrange: + case bfd_reloc_overflow: + bfd_error_vector.reloc_value_truncated(*parent, seclet); + break; + default: + abort(); + break; + } + + } + } + } + + + return data; + + +} diff --git a/gnu/usr.bin/gdb/bfd/seclet.c b/gnu/usr.bin/gdb/bfd/seclet.c new file mode 100644 index 00000000000..5dcc59ab0ef --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/seclet.c @@ -0,0 +1,185 @@ +/* seclet.c + Copyright (C) 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* This module is part of BFD */ + + +/* The intention is that one day, all the code which uses sections + will change and use seclets instead - maybe seglet would have been + a better name.. + + Anyway, a seclet contains enough info to be able to describe an + area of output memory in one go. + + The only description so far catered for is that of the + <>, which is a select which points to a + <
> and the <> associated with the section, so + that relocation can be done when needed. + + One day there will be more types - they will at least migrate from + the linker's data structures - also there could be extra stuff, + like a bss seclet, which descibes a lump of memory as containing + zeros compactly, without the horrible SEC_* flag cruft. + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +#include "coff/internal.h" + +/* Create a new seclet and attach it to a section. */ + +bfd_seclet_type * +DEFUN(bfd_new_seclet,(abfd, section), + bfd *abfd AND + asection *section) +{ + bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type)); + if (section->seclets_tail != (bfd_seclet_type *)NULL) { + section->seclets_tail->next = n; + } + else + { + section->seclets_head = n; + } + section->seclets_tail = n; + + return n; +} + +/* Given an indirect seclet which points to an input section, relocate + the contents of the seclet and put the data in its final + destination. */ + +static boolean +DEFUN(rel,(abfd, seclet, output_section, data, relocateable), + bfd *abfd AND + bfd_seclet_type *seclet AND + asection *output_section AND + PTR data AND + boolean relocateable) +{ + if ((output_section->flags & SEC_HAS_CONTENTS) != 0 + && seclet->size) + { + data = (PTR) bfd_get_relocated_section_contents(abfd, seclet, data, + relocateable); + if(bfd_set_section_contents(abfd, + output_section, + data, + seclet->offset, + seclet->size) == false) + { + abort(); + } + } + return true; +} + +/* Put the contents of a seclet in its final destination. */ + +static boolean +DEFUN(seclet_dump_seclet,(abfd, seclet, section, data, relocateable), + bfd *abfd AND + bfd_seclet_type *seclet AND + asection *section AND + PTR data AND + boolean relocateable) +{ + switch (seclet->type) + { + case bfd_indirect_seclet: + /* The contents of this section come from another one somewhere + else */ + return rel(abfd, seclet, section, data, relocateable); + + case bfd_fill_seclet: + /* Fill in the section with us */ + { + char *d = bfd_xmalloc(seclet->size); + unsigned int i; + for (i =0; i < seclet->size; i+=2) { + d[i] = seclet->u.fill.value >> 8; + } + for (i = 1; i < seclet->size; i+=2) { + d[i] = seclet->u.fill.value ; + } + /* Don't bother to fill in empty sections */ + if (!(bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS)) + { + return true; + } + return bfd_set_section_contents(abfd, section, d, seclet->offset, + seclet->size); + } + + default: + abort(); + } + + return true; +} + +/* +INTERNAL_FUNCTION + bfd_generic_seclet_link + +SYNOPSIS + boolean bfd_generic_seclet_link + (bfd *abfd, + PTR data, + boolean relocateable); + +DESCRIPTION + + The generic seclet linking routine. The caller should have + set up seclets for all the output sections. The DATA argument + should point to a memory area large enough to hold the largest + section. This function looks through the seclets and moves + the contents into the output sections. If RELOCATEABLE is + true, the orelocation fields of the output sections must + already be initialized. + +*/ + +boolean +DEFUN(bfd_generic_seclet_link,(abfd, data, relocateable), + bfd *abfd AND + PTR data AND + boolean relocateable) +{ + asection *o = abfd->sections; + while (o != (asection *)NULL) + { + bfd_seclet_type *p = o->seclets_head; + while (p != (bfd_seclet_type *)NULL) + { + if (seclet_dump_seclet(abfd, p, o, data, relocateable) == false) + return false; + p = p ->next; + } + o = o->next; + } + + return true; +} diff --git a/gnu/usr.bin/gdb/bfd/seclet.h b/gnu/usr.bin/gdb/bfd/seclet.h new file mode 100644 index 00000000000..de5fdff0bb1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/seclet.h @@ -0,0 +1,55 @@ +/* Definitions of little sections (seclets) for BFD. + Copyright 1992 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#ifndef _SECLET_H +#define _SECLET_H + +enum bfd_seclet_enum +{ + bfd_indirect_seclet, + bfd_fill_seclet +}; + +struct bfd_seclet +{ + struct bfd_seclet *next; + enum bfd_seclet_enum type; + unsigned int offset; + unsigned int size; + union + { + struct + { + asection *section; + asymbol **symbols; + } indirect; + struct { + int value; + } fill; + } + u; +}; + +typedef struct bfd_seclet bfd_seclet_type; + +bfd_seclet_type * +bfd_new_seclet PARAMS ((bfd *, asection *)); + +#endif diff --git a/gnu/usr.bin/gdb/bfd/section.c b/gnu/usr.bin/gdb/bfd/section.c new file mode 100644 index 00000000000..547c69e2cb8 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/section.c @@ -0,0 +1,899 @@ +/* Object file "section" support for the BFD library. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + Sections + + Sections are supported in BFD in <>. + + The raw data contained within a BFD is maintained through the + section abstraction. A single BFD may have any number of + sections, and keeps hold of them by pointing to the first, + each one points to the next in the list. + +@menu +@* Section Input:: +@* Section Output:: +@* typedef asection:: +@* section prototypes:: +@end menu + +INODE +Section Input, Section Output, Sections, Sections +SUBSECTION + Section Input + + When a BFD is opened for reading, the section structures are + created and attached to the BFD. + + Each section has a name which describes the section in the + outside world - for example, <> would contain at least + three sections, called <<.text>>, <<.data>> and <<.bss>>. + + Names need not be unique; for example a COFF file may have several + sections named .data. + + Sometimes a BFD will contain more than the 'natural' number of + sections. A back end may attach other sections containing + constructor data, or an application may add a section (using + bfd_make_section) to the sections attached to an already open + BFD. For example, the linker creates a supernumary section + <> for each input file's BFD to hold information about + common storage. + + The raw data is not necessarily read in at the same time as + the section descriptor is created. Some targets may leave the + data in place until a <> call is + made. Other back ends may read in all the data at once - For + example; an S-record file has to be read once to determine the + size of the data. An IEEE-695 file doesn't contain raw data in + sections, but data and relocation expressions intermixed, so + the data area has to be parsed to get out the data and + relocations. + +INODE +Section Output, typedef asection, Section Input, Sections + +SUBSECTION + Section Output + + To write a new object style BFD, the various sections to be + written have to be created. They are attached to the BFD in + the same way as input sections, data is written to the + sections using <>. + + Any program that creates or combines sections (e.g., the assembler + and linker) must use the fields <> and + <> to indicate the file sections to which each + section must be written. (If the section is being created from + scratch, <> should probably point to the section + itself, and <> should probably be zero.) + + The data to be written comes from input sections attached to + the output sections. The output section structure can be + considered a filter for the input section, the output section + determines the vma of the output data and the name, but the + input section determines the offset into the output section of + the data to be written. + + E.g., to create a section "O", starting at 0x100, 0x123 long, + containing two subsections, "A" at offset 0x0 (ie at vma + 0x100) and "B" at offset 0x20 (ie at vma 0x120) the structures + would look like: + +| section name "A" +| output_offset 0x00 +| size 0x20 +| output_section -----------> section name "O" +| | vma 0x100 +| section name "B" | size 0x123 +| output_offset 0x20 | +| size 0x103 | +| output_section --------| + + +SUBSECTION + Seglets + + The data within a section is stored in a <>. These + are much like the fixups in <>. The seglet abstraction + allows the a section to grow and shrink within itself. + + A seglet knows how big it is, and which is the next seglet and + where the raw data for it is, and also points to a list of + relocations which apply to it. + + The seglet is used by the linker to perform relaxing on final + code. The application creates code which is as big as + necessary to make it work without relaxing, and the user can + select whether to relax. Sometimes relaxing takes a lot of + time. The linker runs around the relocations to see if any + are attached to data which can be shrunk, if so it does it on + a seglet by seglet basis. + +*/ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* +DOCDD +INODE +typedef asection, section prototypes, Section Output, Sections +SUBSECTION + typedef asection + + The shape of a section struct: + +CODE_FRAGMENT +. +.typedef struct sec +.{ +. {* The name of the section, the name isn't a copy, the pointer is +. the same as that passed to bfd_make_section. *} +. +. CONST char *name; +. +. {* Which section is it 0.nth *} +. +. int index; +. +. {* The next section in the list belonging to the BFD, or NULL. *} +. +. struct sec *next; +. +. {* The field flags contains attributes of the section. Some of +. flags are read in from the object file, and some are +. synthesized from other information. *} +. +. flagword flags; +. +.#define SEC_NO_FLAGS 0x000 +. +. {* Tells the OS to allocate space for this section when loaded. +. This would clear for a section containing debug information +. only. *} +.#define SEC_ALLOC 0x001 +. +. {* Tells the OS to load the section from the file when loading. +. This would be clear for a .bss section *} +.#define SEC_LOAD 0x002 +. +. {* The section contains data still to be relocated, so there will +. be some relocation information too. *} +.#define SEC_RELOC 0x004 +. +.#if 0 {* Obsolete ? *} +.#define SEC_BALIGN 0x008 +.#endif +. +. {* A signal to the OS that the section contains read only +. data. *} +.#define SEC_READONLY 0x010 +. +. {* The section contains code only. *} +.#define SEC_CODE 0x020 +. +. {* The section contains data only. *} +.#define SEC_DATA 0x040 +. +. {* The section will reside in ROM. *} +.#define SEC_ROM 0x080 +. +. {* The section contains constructor information. This section +. type is used by the linker to create lists of constructors and +. destructors used by <>. When a back end sees a symbol +. which should be used in a constructor list, it creates a new +. section for the type of name (eg <<__CTOR_LIST__>>), attaches +. the symbol to it and builds a relocation. To build the lists +. of constructors, all the linker has to do is catenate all the +. sections called <<__CTOR_LIST__>> and relocte the data +. contained within - exactly the operations it would peform on +. standard data. *} +.#define SEC_CONSTRUCTOR 0x100 +. +. {* The section is a constuctor, and should be placed at the +. end of the text, data, or bss section(?). *} +.#define SEC_CONSTRUCTOR_TEXT 0x1100 +.#define SEC_CONSTRUCTOR_DATA 0x2100 +.#define SEC_CONSTRUCTOR_BSS 0x3100 +. +. {* The section has contents - a data section could be +. <> | <>, a debug section could be +. <> *} +.#define SEC_HAS_CONTENTS 0x200 +. +. {* An instruction to the linker not to output sections +. containing this flag even if they have information which +. would normally be written. *} +.#define SEC_NEVER_LOAD 0x400 +. +. {* The section is a shared library section. The linker must leave +. these completely alone, as the vma and size are used when +. the executable is loaded. *} +.#define SEC_SHARED_LIBRARY 0x800 +. +. {* The section is a common section (symbols may be defined +. multiple times, the value of a symbol is the amount of +. space it requires, and the largest symbol value is the one +. used). Most targets have exactly one of these (which we +. translate to bfd_com_section), but ECOFF has two. *} +.#define SEC_IS_COMMON 0x8000 +. +. {* The section contains only debugging information. For +. example, this is set for ELF .debug and .stab sections. +. strip tests this flag to see if a section can be +. discarded. *} +.#define SEC_DEBUGGING 0x10000 +. +. {* End of section flags. *} +. +. {* The virtual memory address of the section - where it will be +. at run time. The symbols are relocated against this. The +. user_set_vma flag is maintained by bfd; if it's not set, the +. backend can assign addresses (for example, in <>, where +. the default address for <<.data>> is dependent on the specific +. target and various flags). *} +. +. bfd_vma vma; +. boolean user_set_vma; +. +. {* The load address of the section - where it would be in a +. rom image, really only used for writing section header +. information. *} +. +. bfd_vma lma; +. +. {* The size of the section in bytes, as it will be output. +. contains a value even if the section has no contents (eg, the +. size of <<.bss>>). This will be filled in after relocation *} +. +. bfd_size_type _cooked_size; +. +. {* The size on disk of the section in bytes originally. Normally this +. value is the same as the size, but if some relaxing has +. been done, then this value will be bigger. *} +. +. bfd_size_type _raw_size; +. +. {* If this section is going to be output, then this value is the +. offset into the output section of the first byte in the input +. section. Eg, if this was going to start at the 100th byte in +. the output section, this value would be 100. *} +. +. bfd_vma output_offset; +. +. {* The output section through which to map on output. *} +. +. struct sec *output_section; +. +. {* The alignment requirement of the section, as an exponent - eg +. 3 aligns to 2^3 (or 8) *} +. +. unsigned int alignment_power; +. +. {* If an input section, a pointer to a vector of relocation +. records for the data in this section. *} +. +. struct reloc_cache_entry *relocation; +. +. {* If an output section, a pointer to a vector of pointers to +. relocation records for the data in this section. *} +. +. struct reloc_cache_entry **orelocation; +. +. {* The number of relocation records in one of the above *} +. +. unsigned reloc_count; +. +. {* Information below is back end specific - and not always used +. or updated. *} +. +. {* File position of section data *} +. +. file_ptr filepos; +. +. {* File position of relocation info *} +. +. file_ptr rel_filepos; +. +. {* File position of line data *} +. +. file_ptr line_filepos; +. +. {* Pointer to data for applications *} +. +. PTR userdata; +. +. struct lang_output_section *otheruserdata; +. +. {* Attached line number information *} +. +. alent *lineno; +. +. {* Number of line number records *} +. +. unsigned int lineno_count; +. +. {* When a section is being output, this value changes as more +. linenumbers are written out *} +. +. file_ptr moving_line_filepos; +. +. {* what the section number is in the target world *} +. +. int target_index; +. +. PTR used_by_bfd; +. +. {* If this is a constructor section then here is a list of the +. relocations created to relocate items within it. *} +. +. struct relent_chain *constructor_chain; +. +. {* The BFD which owns the section. *} +. +. bfd *owner; +. +. boolean reloc_done; +. {* A symbol which points at this section only *} +. struct symbol_cache_entry *symbol; +. struct symbol_cache_entry **symbol_ptr_ptr; +. +. struct bfd_seclet *seclets_head; +. struct bfd_seclet *seclets_tail; +.} asection ; +. +. +. {* These sections are global, and are managed by BFD. The application +. and target back end are not permitted to change the values in +. these sections. *} +.#define BFD_ABS_SECTION_NAME "*ABS*" +.#define BFD_UND_SECTION_NAME "*UND*" +.#define BFD_COM_SECTION_NAME "*COM*" +.#define BFD_IND_SECTION_NAME "*IND*" +. +. {* the absolute section *} +.extern asection bfd_abs_section; +. {* Pointer to the undefined section *} +.extern asection bfd_und_section; +. {* Pointer to the common section *} +.extern asection bfd_com_section; +. {* Pointer to the indirect section *} +.extern asection bfd_ind_section; +. +.extern struct symbol_cache_entry *bfd_abs_symbol; +.extern struct symbol_cache_entry *bfd_com_symbol; +.extern struct symbol_cache_entry *bfd_und_symbol; +.extern struct symbol_cache_entry *bfd_ind_symbol; +.#define bfd_get_section_size_before_reloc(section) \ +. (section->reloc_done ? (abort(),1): (section)->_raw_size) +.#define bfd_get_section_size_after_reloc(section) \ +. ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +*/ + +/* These symbols are global, not specific to any BFD. Therefore, anything + that tries to change them is broken, and should be repaired. */ +static CONST asymbol global_syms[] = { + /* the_bfd, name, value, attr, section [, udata] */ + { 0, BFD_COM_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_com_section }, + { 0, BFD_UND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_und_section }, + { 0, BFD_ABS_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_abs_section }, + { 0, BFD_IND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_ind_section }, +}; + +#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ + asymbol *SYM = (asymbol *) &global_syms[IDX]; \ + asection SEC = { NAME, 0, 0, FLAGS, 0, 0, (boolean) 0, 0, 0, 0, &SEC,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (boolean) 0, \ + (asymbol *) &global_syms[IDX], &SYM, } + +STD_SECTION (bfd_com_section, SEC_IS_COMMON, bfd_com_symbol, BFD_COM_SECTION_NAME, 0); +STD_SECTION (bfd_und_section, 0, bfd_und_symbol, BFD_UND_SECTION_NAME, 1); +STD_SECTION (bfd_abs_section, 0, bfd_abs_symbol, BFD_ABS_SECTION_NAME, 2); +STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3); +#undef STD_SECTION + +/* +DOCDD +INODE +section prototypes, , typedef asection, Sections +SUBSECTION + section prototypes + +These are the functions exported by the section handling part of +<. +*/ + +/* +FUNCTION + bfd_get_section_by_name + +SYNOPSIS + asection *bfd_get_section_by_name(bfd *abfd, CONST char *name); + +DESCRIPTION + Runs through the provided @var{abfd} and returns the one of the + <>s who's name matches that provided, otherwise NULL. + @xref{Sections}, for more information. + + This should only be used in special cases; the normal way to process + all sections of a given name is to use bfd_map_over_sections and + strcmp on the name (or better yet, base it on the section flags + or something else) for each section. +*/ + +asection * +DEFUN(bfd_get_section_by_name,(abfd, name), + bfd *abfd AND + CONST char *name) +{ + asection *sect; + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + if (!strcmp (sect->name, name)) return sect; + return NULL; +} + + +/* +FUNCTION + bfd_make_section_old_way + +SYNOPSIS + asection *bfd_make_section_old_way(bfd *, CONST char *name); + +DESCRIPTION + This function creates a new empty section called @var{name} + and attaches it to the end of the chain of sections for the + BFD supplied. An attempt to create a section with a name which + is already in use, returns its pointer without changing the + section chain. + + It has the funny name since this is the way it used to be + before is was rewritten... + + Possible errors are: + o invalid_operation - + If output has already started for this BFD. + o no_memory - + If obstack alloc fails. + +*/ + + +asection * +DEFUN(bfd_make_section_old_way,(abfd, name), + bfd *abfd AND + CONST char * name) +{ + asection *sec = bfd_get_section_by_name(abfd, name); + if (sec == (asection *)NULL) + { + sec = bfd_make_section(abfd, name); + } + return sec; +} + +/* +FUNCTION + bfd_make_section_anyway + +SYNOPSIS + asection *bfd_make_section_anyway(bfd *, CONST char *name); + +DESCRIPTION + Create a new empty section called @var{name} and attach it to the end of + the chain of sections for @var{abfd}. Create a new section even if there + is already a section with that name. + + Returns NULL and sets bfd_error on error; possible errors are: + o invalid_operation - If output has already started for @var{abfd}. + o no_memory - If obstack alloc fails. +*/ + +sec_ptr +bfd_make_section_anyway (abfd, name) + bfd *abfd; + CONST char *name; +{ + asection *newsect; + asection **prev = &abfd->sections; + asection * sect = abfd->sections; + + if (abfd->output_has_begun) + { + bfd_error = invalid_operation; + return NULL; + } + + while (sect) { + prev = §->next; + sect = sect->next; + } + + newsect = (asection *) bfd_zalloc(abfd, sizeof (asection)); + if (newsect == NULL) { + bfd_error = no_memory; + return NULL; + } + + newsect->name = name; + newsect->index = abfd->section_count++; + newsect->flags = SEC_NO_FLAGS; + + newsect->userdata = 0; + newsect->next = (asection *)NULL; + newsect->relocation = (arelent *)NULL; + newsect->reloc_count = 0; + newsect->line_filepos =0; + newsect->owner = abfd; + + /* Create a symbol whos only job is to point to this section. This is + useful for things like relocs which are relative to the base of a + section. */ + newsect->symbol = bfd_make_empty_symbol(abfd); + newsect->symbol->name = name; + newsect->symbol->value = 0; + newsect->symbol->section = newsect; + newsect->symbol->flags = BSF_SECTION_SYM; + + newsect->symbol_ptr_ptr = &newsect->symbol; + + if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) { + free (newsect); + return NULL; + } + + *prev = newsect; + return newsect; +} + +/* +FUNCTION + bfd_make_section + +SYNOPSIS + asection *bfd_make_section(bfd *, CONST char *name); + +DESCRIPTION + Like bfd_make_section_anyway, but return NULL (without setting + bfd_error) without changing the section chain if there is already a + section named @var{name}. If there is an error, return NULL and set + bfd_error. +*/ + +sec_ptr +DEFUN(bfd_make_section,(abfd, name), + bfd *abfd AND + CONST char * name) +{ + asection * sect = abfd->sections; + + if (strcmp(name, BFD_ABS_SECTION_NAME) == 0) + { + return &bfd_abs_section; + } + if (strcmp(name, BFD_COM_SECTION_NAME) == 0) + { + return &bfd_com_section; + } + if (strcmp(name, BFD_UND_SECTION_NAME) == 0) + { + return &bfd_und_section; + } + + if (strcmp(name, BFD_IND_SECTION_NAME) == 0) + { + return &bfd_ind_section; + } + + while (sect) { + if (!strcmp(sect->name, name)) return NULL; + sect = sect->next; + } + + /* The name is not already used; go ahead and make a new section. */ + return bfd_make_section_anyway (abfd, name); +} + + +/* +FUNCTION + bfd_set_section_flags + +SYNOPSIS + boolean bfd_set_section_flags(bfd *, asection *, flagword); + +DESCRIPTION + Attempts to set the attributes of the section named in the BFD + supplied to the value. Returns true on success, false on + error. Possible error returns are: + + o invalid operation - + The section cannot have one or more of the attributes + requested. For example, a .bss section in <> may not + have the <> field set. + +*/ + +boolean +DEFUN(bfd_set_section_flags,(abfd, section, flags), + bfd *abfd AND + sec_ptr section AND + flagword flags) +{ +#if 0 + /* If you try to copy a text section from an input file (where it + has the SEC_CODE flag set) to an output file, this loses big if + the bfd_applicable_section_flags (abfd) doesn't have the SEC_CODE + set - which it doesn't, at least not for a.out. FIXME */ + + if ((flags & bfd_applicable_section_flags (abfd)) != flags) { + bfd_error = invalid_operation; + return false; + } +#endif + + section->flags = flags; + return true; +} + + +/* +FUNCTION + bfd_map_over_sections + +SYNOPSIS + void bfd_map_over_sections(bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj); + +DESCRIPTION + Calls the provided function @var{func} for each section + attached to the BFD @var{abfd}, passing @var{obj} as an + argument. The function will be called as if by + +| func(abfd, the_section, obj); + + This is the prefered method for iterating over sections, an + alternative would be to use a loop: + +| section *p; +| for (p = abfd->sections; p != NULL; p = p->next) +| func(abfd, p, ...) + + +*/ + +/*VARARGS2*/ +void +DEFUN(bfd_map_over_sections,(abfd, operation, user_storage), + bfd *abfd AND + void (*operation) PARAMS ((bfd *abfd, asection *sect, PTR obj)) AND + PTR user_storage) +{ + asection *sect; + int i = 0; + + for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) + (*operation) (abfd, sect, user_storage); + + if (i != abfd->section_count) /* Debugging */ + abort(); +} + + +/* +FUNCTION + bfd_set_section_size + +SYNOPSIS + boolean bfd_set_section_size(bfd *, asection *, bfd_size_type val); + +DESCRIPTION + Sets @var{section} to the size @var{val}. If the operation is + ok, then <> is returned, else <>. + + Possible error returns: + o invalid_operation - + Writing has started to the BFD, so setting the size is invalid + +*/ + +boolean +DEFUN(bfd_set_section_size,(abfd, ptr, val), + bfd *abfd AND + sec_ptr ptr AND + bfd_size_type val) +{ + /* Once you've started writing to any section you cannot create or change + the size of any others. */ + + if (abfd->output_has_begun) { + bfd_error = invalid_operation; + return false; + } + + ptr->_cooked_size = val; + ptr->_raw_size = val; + + return true; +} + +/* +FUNCTION + bfd_set_section_contents + +SYNOPSIS + boolean bfd_set_section_contents + (bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count); + + +DESCRIPTION + Sets the contents of the section @var{section} in BFD + @var{abfd} to the data starting in memory at @var{data}. The + data is written to the output section starting at offset + @var{offset} for @var{count} bytes. + + + + Normally <> is returned, else <>. Possible error + returns are: + o no_contents - + The output section does not have the <> + attribute, so nothing can be written to it. + o and some more too + + This routine is front end to the back end function + <<_bfd_set_section_contents>>. + + +*/ + +#define bfd_get_section_size_now(abfd,sec) \ +(sec->reloc_done \ + ? bfd_get_section_size_after_reloc (sec) \ + : bfd_get_section_size_before_reloc (sec)) + +boolean +DEFUN(bfd_set_section_contents,(abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + bfd_size_type sz; + + if (!bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS) + { + bfd_error = no_contents; + return(false); + } + + if (offset < 0) + { + bad_val: + bfd_error = bad_value; + return false; + } + sz = bfd_get_section_size_now (abfd, section); + if (offset > sz + || count > sz + || offset + count > sz) + goto bad_val; + + switch (abfd->direction) + { + case read_direction: + case no_direction: + bfd_error = invalid_operation; + return false; + + case write_direction: + break; + + case both_direction: + /* File is opened for update. `output_has_begun' some time ago when + the file was created. Do not recompute sections sizes or alignments + in _bfd_set_section_content. */ + abfd->output_has_begun = true; + break; + } + + if (BFD_SEND (abfd, _bfd_set_section_contents, + (abfd, section, location, offset, count))) + { + abfd->output_has_begun = true; + return true; + } + + return false; +} + +/* +FUNCTION + bfd_get_section_contents + +SYNOPSIS + boolean bfd_get_section_contents + (bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count); + +DESCRIPTION + This function reads data from @var{section} in BFD @var{abfd} + into memory starting at @var{location}. The data is read at an + offset of @var{offset} from the start of the input section, + and is read for @var{count} bytes. + + If the contents of a constuctor with the <> + flag set are requested, then the @var{location} is filled with + zeroes. If no errors occur, <> is returned, else + <>. + + + +*/ +boolean +DEFUN(bfd_get_section_contents,(abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + bfd_size_type sz; + + if (section->flags & SEC_CONSTRUCTOR) + { + memset(location, 0, (unsigned)count); + return true; + } + + if (offset < 0) + { + bad_val: + bfd_error = bad_value; + return false; + } + sz = bfd_get_section_size_now (abfd, section); + if (offset > sz + || count > sz + || offset + count > sz) + goto bad_val; + + if (count == 0) + /* Don't bother. */ + return true; + + return BFD_SEND (abfd, _bfd_get_section_contents, + (abfd, section, location, offset, count)); +} diff --git a/gnu/usr.bin/gdb/bfd/srec.c b/gnu/usr.bin/gdb/bfd/srec.c new file mode 100644 index 00000000000..88ba9570e34 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/srec.c @@ -0,0 +1,1001 @@ +/* BFD back-end for s-record objects. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support . + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SUBSECTION + S-Record handling + +DESCRIPTION + + Ordinary S-Records cannot hold anything but addresses and + data, so that's all that we implement. + + The only interesting thing is that S-Records may come out of + order and there is no header, so an initial scan is required + to discover the minimum and maximum addresses used to create + the vma and size of the only section we create. We + arbitrarily call this section ".text". + + When bfd_get_section_contents is called the file is read + again, and this time the data is placed into a bfd_alloc'd + area. + + Any number of sections may be created for output, we save them + up and output them when it's time to close the bfd. + + An s record looks like: + +EXAMPLE + S
+ +DESCRIPTION + Where + o length + is the number of bytes following upto the checksum. Note that + this is not the number of chars following, since it takes two + chars to represent a byte. + o type + is one of: + 0) header record + 1) two byte address data record + 2) three byte address data record + 3) four byte address data record + 7) four byte address termination record + 8) three byte address termination record + 9) two byte address termination record + + o address + is the start address of the data following, or in the case of + a termination record, the start address of the image + o data + is the data. + o checksum + is the sum of all the raw byte data in the record, from the length + upwards, modulo 256 and subtracted from 255. + + +SUBSECTION + Symbol S-Record handling + +DESCRIPTION + Some ICE equipment understands an addition to the standard + S-Record format; symbols and their addresses can be sent + before the data. + + The format of this is: + ($$ + (
)*) + $$ + + so a short symbol table could look like: + +EXAMPLE + $$ flash.x + $$ flash.c + _port6 $0 + _delay $4 + _start $14 + _etext $8036 + _edata $8036 + _end $8036 + $$ + +DESCRIPTION + We allow symbols to be anywhere in the data stream - the module names + are always ignored. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* Macros for converting between hex and binary */ + +static CONST char digs[] = "0123456789ABCDEF"; + +static char hex_value[1 + (unsigned char)~0]; + +#define NOT_HEX 20 +#define NIBBLE(x) hex_value[(unsigned char)(x)] +#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) +#define TOHEX(d, x, ch) \ + d[1] = digs[(x) & 0xf]; \ + d[0] = digs[((x)>>4)&0xf]; \ + ch += ((x) & 0xff); +#define ISHEX(x) (hex_value[(unsigned char)(x)] != NOT_HEX) + + + +static void +DEFUN_VOID(srec_init) +{ + unsigned int i; + static boolean inited = false; + + if (inited == false) + { + + inited = true; + + for (i = 0; i < sizeof (hex_value); i++) + { + hex_value[i] = NOT_HEX; + } + + for (i = 0; i < 10; i++) + { + hex_value[i + '0'] = i; + + } + for (i = 0; i < 6; i++) + { + hex_value[i + 'a'] = i+10; + hex_value[i + 'A'] = i+10; + } + } +} + + +/* The maximum number of bytes on a line is FF */ +#define MAXCHUNK 0xff +/* The number of bytes we fit onto a line on output */ +#define CHUNK 21 + +/* We cannot output our srecords as we see them, we have to glue them + together, this is done in this structure : */ + +struct srec_data_list_struct +{ + unsigned char *data; + bfd_vma where; + bfd_size_type size; + struct srec_data_list_struct *next; + + +} ; +typedef struct srec_data_list_struct srec_data_list_type; + + +typedef struct srec_data_struct +{ + srec_data_list_type *head; + unsigned int type; + + int done_symbol_read; + int count; + asymbol *symbols; + char *strings; + int symbol_idx; + int string_size; + int string_idx; +} tdata_type; + + +/* + called once per input S-Record, used to work out vma and size of data. + */ + +static bfd_vma low,high; + +static void +size_symbols(abfd, buf, len, val) +bfd *abfd; +char *buf; +int len; +int val; +{ + abfd->symcount ++; + abfd->tdata.srec_data->string_size += len + 1; +} + +static void +fillup_symbols(abfd, buf, len, val) +bfd *abfd; +char *buf; +int len; +int val; +{ + if (!abfd->tdata.srec_data->done_symbol_read) + { + asymbol *p; + if (abfd->tdata.srec_data->symbols == 0) + { + abfd->tdata.srec_data->symbols = (asymbol *)bfd_alloc(abfd, abfd->symcount * sizeof(asymbol)); + abfd->tdata.srec_data->strings = (char*)bfd_alloc(abfd, abfd->tdata.srec_data->string_size); + abfd->tdata.srec_data->symbol_idx = 0; + abfd->tdata.srec_data->string_idx = 0; + } + + p = abfd->tdata.srec_data->symbols + abfd->tdata.srec_data->symbol_idx++; + p->the_bfd = abfd; + p->name = abfd->tdata.srec_data->strings + abfd->tdata.srec_data->string_idx; + memcpy((char *)(p->name), buf, len+1); + abfd->tdata.srec_data->string_idx += len + 1; + p->value = val; + p->flags = BSF_EXPORT | BSF_GLOBAL; + p->section = &bfd_abs_section; + p->udata = 0; + } +} +static void +DEFUN(size_srec,(abfd, section, address, raw, length), + bfd *abfd AND + asection *section AND + bfd_vma address AND + bfd_byte *raw AND + unsigned int length) +{ + if (address < low) + low = address; + if (address + length > high) + high = address + length -1; +} + + +/* + called once per input S-Record, copies data from input into bfd_alloc'd area + */ + +static void +DEFUN(fillup,(abfd, section, address, raw, length), +bfd *abfd AND +asection *section AND +bfd_vma address AND +bfd_byte *raw AND +unsigned int length) +{ + unsigned int i; + bfd_byte *dst = + (bfd_byte *)(section->used_by_bfd) + address - section->vma; + /* length -1 because we don't read in the checksum */ + for (i = 0; i < length -1 ; i++) { + *dst = HEX(raw); + dst++; + raw+=2; + } +} + +/* Pass over an S-Record file, calling one of the above functions on each + record. */ + +static int white(x) +char x; +{ +return (x== ' ' || x == '\t' || x == '\n' || x == '\r'); +} +static int +skipwhite(src,abfd) +char *src; +bfd *abfd; +{ + int eof = 0; + while (white(*src) && !eof) + { + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + return eof; +} + +static boolean +DEFUN(srec_mkobject, (abfd), + bfd *abfd) +{ + if (abfd->tdata.srec_data == 0) + { + tdata_type *tdata = (tdata_type *)bfd_alloc(abfd, sizeof(tdata_type)); + abfd->tdata.srec_data = tdata; + tdata->type = 1; + tdata->head = (srec_data_list_type *)NULL; + } + return true; + +} + +static void +DEFUN(pass_over,(abfd, func, symbolfunc, section), + bfd *abfd AND + void (*func)() AND + void (*symbolfunc)() AND + asection *section) +{ + unsigned int bytes_on_line; + boolean eof = false; + + srec_mkobject(abfd); + /* To the front of the file */ + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + while (eof == false) + { + char buffer[MAXCHUNK]; + char *src = buffer; + char type; + bfd_vma address = 0; + + /* Find first 'S' or $ */ + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + switch (*src) + { + default: + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + if (eof) return; + break; + + case '$': + /* Inside a symbol definition - just ignore the module name */ + while (*src != '\n' && !eof) + { + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + break; + + case ' ': + /* spaces - maybe just before a symbol */ + while (*src != '\n' && white(*src)) { + eof = skipwhite(src, abfd); + +{ + int val = 0; + int slen = 0; + char symbol[MAXCHUNK]; + + /* get the symbol part */ + while (!eof && !white(*src) && slen < MAXCHUNK) + { + symbol[slen++] = *src; + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + symbol[slen] = 0; + eof = skipwhite(src, abfd); + /* skip the $ for the hex value */ + if (*src == '$') + { + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + + /* Scan off the hex number */ + while (isxdigit(*src )) + { + val *= 16; + if (isdigit(*src)) + val += *src - '0'; + else if (isupper(*src)) { + val += *src - 'A' + 10; + } + else { + val += *src - 'a' + 10; + } + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + symbolfunc(abfd, symbol, slen, val); + } +} + break; + case 'S': + src++; + + /* Fetch the type and the length */ + bfd_read(src, 1, 3, abfd); + + type = *src++; + + if (!ISHEX (src[0]) || !ISHEX (src[1])) + break; + + bytes_on_line = HEX(src); + + if (bytes_on_line > MAXCHUNK/2) + break; + src+=2 ; + + bfd_read(src, 1 , bytes_on_line * 2, abfd); + + switch (type) { + case '0': + case '5': + /* Prologue - ignore */ + break; + case '3': + address = HEX(src); + src+=2; + bytes_on_line--; + + case '2': + address = HEX(src) | (address<<8) ; + src+=2; + bytes_on_line--; + case '1': + address = HEX(src) | (address<<8) ; + src+=2; + address = HEX(src) | (address<<8) ; + src+=2; + bytes_on_line-=2; + func(abfd,section, address, src, bytes_on_line); + break; + default: + return; + } + } + } + +} + +static bfd_target * +object_p(abfd) +bfd *abfd; +{ + asection *section; + /* We create one section called .text for all the contents, + and allocate enough room for the entire file. */ + + section = bfd_make_section(abfd, ".text"); + section->_raw_size = 0; + section->vma = 0xffffffff; + low = 0xffffffff; + high = 0; + pass_over(abfd, size_srec, size_symbols, section); + section->_raw_size = high - low; + section->vma = low; + section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + + if (abfd->symcount) + abfd->flags |= HAS_SYMS; + return abfd->xvec; +} + +static bfd_target * +DEFUN(srec_object_p, (abfd), + bfd *abfd) +{ + char b[4]; + + srec_init(); + + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + bfd_read(b, 1, 4, abfd); + + if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3])) + return (bfd_target*) NULL; + + /* We create one section called .text for all the contents, + and allocate enough room for the entire file. */ + + return object_p(abfd); +} + + +static bfd_target * +DEFUN(symbolsrec_object_p, (abfd), + bfd *abfd) +{ + char b[4]; + + srec_init(); + + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + bfd_read(b, 1, 4, abfd); + + if (b[0] != '$' || b[1] != '$') + return (bfd_target*) NULL; + + return object_p(abfd); +} + + +static boolean +DEFUN(srec_get_section_contents,(abfd, section, location, offset, count), + bfd *abfd AND + asection *section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + if (section->used_by_bfd == (PTR)NULL) + { + section->used_by_bfd = (PTR)bfd_alloc (abfd, section->_raw_size); + + pass_over(abfd, fillup, fillup_symbols, section); + } + (void) memcpy((PTR)location, + (PTR)((char *)(section->used_by_bfd) + offset), + count); + return true; +} + + + +boolean +DEFUN(srec_set_arch_mach,(abfd, arch, machine), + bfd *abfd AND + enum bfd_architecture arch AND + unsigned long machine) +{ + return bfd_default_set_arch_mach(abfd, arch, machine); +} + + +/* we have to save up all the Srecords for a splurge before output, + also remember */ + +static boolean +DEFUN(srec_set_section_contents,(abfd, section, location, offset, bytes_to_do), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type bytes_to_do) +{ + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *entry = (srec_data_list_type *) + bfd_alloc(abfd, sizeof(srec_data_list_type)); + + if ((section->flags & SEC_ALLOC) + && (section->flags & SEC_LOAD)) + { + unsigned char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do); + memcpy(data, location, bytes_to_do); + + if ((section->lma + offset + bytes_to_do) <= 0xffff) + { + + } + else if ((section->lma + offset + bytes_to_do) <= 0xffffff + && tdata->type < 2) + { + tdata->type = 2; + } + else + { + tdata->type = 3; + } + + entry->data = data; + entry->where = section->lma + offset; + entry->size = bytes_to_do; + entry->next = tdata->head; + tdata->head = entry; + } + return true; +} + +/* Write a record of type, of the supplied number of bytes. The + supplied bytes and length don't have a checksum. That's worked out + here +*/ +static +void DEFUN(srec_write_record,(abfd, type, address, data, end), + bfd *abfd AND + char type AND + bfd_vma address AND + CONST unsigned char *data AND + CONST unsigned char *end) + +{ + char buffer[MAXCHUNK]; + + unsigned int check_sum = 0; + unsigned CONST char *src = data; + char *dst =buffer; + char *length; + + + *dst++ = 'S'; + *dst++ = '0' + type; + + length = dst; + dst+=2; /* leave room for dst*/ + + switch (type) + { + case 3: + case 7: + TOHEX(dst, (address >> 24), check_sum); + dst+=2; + case 8: + case 2: + TOHEX(dst, (address >> 16), check_sum); + dst+=2; + case 9: + case 1: + case 0: + TOHEX(dst, (address >> 8), check_sum); + dst+=2; + TOHEX(dst, (address), check_sum); + dst+=2; + break; + + } + for (src = data; src < end; src++) + { + TOHEX(dst, *src, check_sum); + dst+=2; + } + + /* Fill in the length */ + TOHEX(length, (dst - length)/2, check_sum); + check_sum &= 0xff; + check_sum = 255 - check_sum; + TOHEX(dst, check_sum, check_sum); + dst+=2; + + *dst ++ = '\r'; + *dst ++ = '\n'; + bfd_write((PTR)buffer, 1, dst - buffer , abfd); +} + + + +static void +DEFUN(srec_write_header,(abfd), + bfd *abfd) +{ + unsigned char buffer[MAXCHUNK]; + unsigned char *dst = buffer; + unsigned int i; + + /* I'll put an arbitary 40 char limit on header size */ + for (i = 0; i < 40 && abfd->filename[i]; i++) + { + *dst++ = abfd->filename[i]; + } + srec_write_record(abfd,0, 0, buffer, dst); +} + +static void +DEFUN(srec_write_section,(abfd, tdata, list), + bfd *abfd AND + tdata_type *tdata AND + srec_data_list_type *list) +{ + unsigned int bytes_written = 0; + unsigned char *location = list->data; + + while (bytes_written < list->size) + { + bfd_vma address; + + unsigned int bytes_this_chunk = list->size - bytes_written; + + if (bytes_this_chunk > CHUNK) + { + bytes_this_chunk = CHUNK; + } + + address = list->where + bytes_written; + + srec_write_record(abfd, + tdata->type, + address, + location, + location + bytes_this_chunk); + + bytes_written += bytes_this_chunk; + location += bytes_this_chunk; + } + +} + +static void +DEFUN(srec_write_terminator,(abfd, tdata), + bfd *abfd AND + tdata_type *tdata) +{ + unsigned char buffer[2]; + + srec_write_record(abfd, 10 - tdata->type, + abfd->start_address, buffer, buffer); +} + + + +static void +srec_write_symbols(abfd) + bfd *abfd; +{ + char buffer[MAXCHUNK]; + /* Dump out the symbols of a bfd */ + int i; + int len = bfd_get_symcount(abfd); + + if (len) + { + asymbol **table = bfd_get_outsymbols(abfd); + sprintf(buffer, "$$ %s\r\n", abfd->filename); + + bfd_write(buffer, strlen(buffer), 1, abfd); + + for (i = 0; i < len; i++) + { + asymbol *s = table[i]; +#if 0 + int len = strlen(s->name); + + /* If this symbol has a .[ocs] in it, it's probably a file name + and we'll output that as the module name */ + + if (len > 3 && s->name[len-2] == '.') + { + int l; + sprintf(buffer, "$$ %s\r\n", s->name); + l = strlen(buffer); + bfd_write(buffer, l, 1, abfd); + } + else +#endif + if (s->flags & (BSF_GLOBAL | BSF_LOCAL) + && (s->flags & BSF_DEBUGGING) == 0 + && s->name[0] != '.' + && s->name[0] != 't') + { + /* Just dump out non debug symbols */ + + int l; + char buf2[40], *p; + + sprintf_vma (buf2, s->value + s->section->lma); + p = buf2; + while (p[0] == '0' && p[1] != 0) + p++; + sprintf (buffer, " %s $%s\r\n", s->name, p); + l = strlen(buffer); + bfd_write(buffer, l, 1,abfd); + } + } + sprintf(buffer, "$$ \r\n"); + bfd_write(buffer, strlen(buffer), 1, abfd); + } +} + +static boolean +internal_srec_write_object_contents(abfd, symbols) + bfd *abfd; + int symbols; +{ + int bytes_written; + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *list; + + bytes_written = 0; + + + if (symbols) + srec_write_symbols(abfd); + + srec_write_header(abfd); + + /* Now wander though all the sections provided and output them */ + list = tdata->head; + + while (list != (srec_data_list_type*)NULL) + { + srec_write_section(abfd, tdata, list); + list = list->next; + } + srec_write_terminator(abfd, tdata); + return true; +} + +static boolean +srec_write_object_contents(abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents(abfd, 0); +} + +static boolean +symbolsrec_write_object_contents(abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents(abfd, 1); +} + +static int +DEFUN(srec_sizeof_headers,(abfd, exec), + bfd *abfd AND + boolean exec) +{ +return 0; +} + +static asymbol * +DEFUN(srec_make_empty_symbol, (abfd), + bfd*abfd) +{ + asymbol *new= (asymbol *)bfd_zalloc (abfd, sizeof (asymbol)); + new->the_bfd = abfd; + return new; +} + +static unsigned int +srec_get_symtab_upper_bound(abfd) +bfd *abfd; +{ + /* Read in all the info */ + srec_get_section_contents(abfd,abfd->sections,0,0,0); + return (bfd_get_symcount(abfd) + 1) * (sizeof(asymbol *)); +} + +static unsigned int +DEFUN(srec_get_symtab, (abfd, alocation), + bfd *abfd AND + asymbol **alocation) +{ + int lim = abfd->symcount; + int i; + for (i = 0; i < lim; i++) { + alocation[i] = abfd->tdata.srec_data->symbols + i; + } + alocation[i] = 0; + return lim; +} + +void +DEFUN(srec_get_symbol_info,(ignore_abfd, symbol, ret), + bfd *ignore_abfd AND + asymbol *symbol AND + symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); +} + +void +DEFUN(srec_print_symbol,(ignore_abfd, afile, symbol, how), + bfd *ignore_abfd AND + PTR afile AND + asymbol *symbol AND + bfd_print_symbol_type how) +{ + FILE *file = (FILE *)afile; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + default: + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s", + symbol->section->name, + symbol->name); + + } +} + +#define FOO PROTO +#define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true + +#define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false +#define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0 + + + +#define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr +#define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false +#define srec_generic_stat_arch_elt (FOO(int, (*), (bfd *,struct stat *))) bfd_0 + + +#define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr) +#define srec_core_file_failing_signal (int (*)())bfd_0 +#define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false +#define srec_slurp_armap bfd_true +#define srec_slurp_extended_name_table bfd_true +#define srec_truncate_arname (void (*)())bfd_nullvoidptr +#define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr +#define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr +#define srec_close_and_cleanup bfd_generic_close_and_cleanup +#define srec_bfd_debug_info_start bfd_void +#define srec_bfd_debug_info_end bfd_void +#define srec_bfd_debug_info_accumulate (FOO(void, (*), (bfd *, asection *))) bfd_void +#define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define srec_bfd_relax_section bfd_generic_relax_section +#define srec_bfd_seclet_link bfd_generic_seclet_link +#define srec_bfd_reloc_type_lookup \ + ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) +#define srec_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +bfd_target srec_vec = +{ + "srec", /* name */ + bfd_target_srec_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS + |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 1, /* minimum alignment */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + srec_object_p, /* bfd_check_format */ + (struct bfd_target *(*)()) bfd_nullvoidptr, + (struct bfd_target *(*)()) bfd_nullvoidptr, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + srec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + JUMP_TABLE(srec) + }; + + + +bfd_target symbolsrec_vec = +{ + "symbolsrec", /* name */ + bfd_target_srec_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS + |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 1, /* minimum alignment */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + symbolsrec_object_p, /* bfd_check_format */ + (struct bfd_target *(*)()) bfd_nullvoidptr, + (struct bfd_target *(*)()) bfd_nullvoidptr, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + symbolsrec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + JUMP_TABLE(srec), + (PTR) 0 + }; + diff --git a/gnu/usr.bin/gdb/bfd/stab-syms.c b/gnu/usr.bin/gdb/bfd/stab-syms.c new file mode 100644 index 00000000000..88cf8506e47 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/stab-syms.c @@ -0,0 +1,59 @@ +/* Table of stab names for the BFD library. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" + +#define ARCH_SIZE 32 /* Value doesn't matter. */ +#include "libaout.h" +#include "aout/aout64.h" + +/* Create a table of debugging stab-codes and corresponding names. */ + +#define __define_name(CODE, STRING) {(int)CODE, STRING}, +#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING) +CONST struct {short code; char string[10];} aout_stab_names[] + = { +#include "aout/stab.def" + +/* These are not really stab symbols, but it is + convenient to have them here for the sake of nm. + For completeness, we could also add N_TEXT etc, but those + are never needed, since nm treats those specially. */ +__define_name (N_SETA, "SETA") /* Absolute set element symbol */ +__define_name (N_SETT, "SETT") /* Text set element symbol */ +__define_name (N_SETD, "SETD") /* Data set element symbol */ +__define_name (N_SETB, "SETB") /* Bss set element symbol */ +__define_name (N_SETV, "SETV") /* Pointer to set vector in data area. */ +__define_name (N_INDR, "INDR") +__define_name (N_WARNING, "WARNING") + }; +#undef __define_stab +#undef GNU_EXTRA_STABS + +CONST char * +DEFUN(aout_stab_name,(code), +int code) +{ + register int i = sizeof(aout_stab_names) / sizeof(aout_stab_names[0]); + while (--i >= 0) + if (aout_stab_names[i].code == code) + return aout_stab_names[i].string; + return 0; +} diff --git a/gnu/usr.bin/gdb/bfd/syms.c b/gnu/usr.bin/gdb/bfd/syms.c new file mode 100644 index 00000000000..89ac00124e3 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/syms.c @@ -0,0 +1,527 @@ +/* Generic symbol-table support for the BFD library. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* +SECTION + Symbols + + BFD trys to maintain as much symbol information as it can when + it moves information from file to file. BFD passes information + to applications though the <> structure. When the + application requests the symbol table, BFD reads the table in + the native form and translates parts of it into the internal + format. To maintain more than the infomation passed to + applications some targets keep some information `behind the + scenes', in a structure only the particular back end knows + about. For example, the coff back end keeps the original + symbol table structure as well as the canonical structure when + a BFD is read in. On output, the coff back end can reconstruct + the output symbol table so that no information is lost, even + information unique to coff which BFD doesn't know or + understand. If a coff symbol table was read, but was written + through an a.out back end, all the coff specific information + would be lost. The symbol table of a BFD + is not necessarily read in until a canonicalize request is + made. Then the BFD back end fills in a table provided by the + application with pointers to the canonical information. To + output symbols, the application provides BFD with a table of + pointers to pointers to <>s. This allows applications + like the linker to output a symbol as read, since the `behind + the scenes' information will be still available. +@menu +@* Reading Symbols:: +@* Writing Symbols:: +@* typedef asymbol:: +@* symbol handling functions:: +@end menu + +INODE +Reading Symbols, Writing Symbols, Symbols, Symbols +SUBSECTION + Reading Symbols + + There are two stages to reading a symbol table from a BFD; + allocating storage, and the actual reading process. This is an + excerpt from an appliction which reads the symbol table: + +| unsigned int storage_needed; +| asymbol **symbol_table; +| unsigned int number_of_symbols; +| unsigned int i; +| +| storage_needed = get_symtab_upper_bound (abfd); +| +| if (storage_needed == 0) { +| return ; +| } +| symbol_table = (asymbol **) bfd_xmalloc (storage_needed); +| ... +| number_of_symbols = +| bfd_canonicalize_symtab (abfd, symbol_table); +| +| for (i = 0; i < number_of_symbols; i++) { +| process_symbol (symbol_table[i]); +| } + + All storage for the symbols themselves is in an obstack + connected to the BFD, and is freed when the BFD is closed. + + +INODE +Writing Symbols, typedef asymbol, Reading Symbols, Symbols +SUBSECTION + Writing Symbols + + Writing of a symbol table is automatic when a BFD open for + writing is closed. The application attaches a vector of + pointers to pointers to symbols to the BFD being written, and + fills in the symbol count. The close and cleanup code reads + through the table provided and performs all the necessary + operations. The outputing code must always be provided with an + 'owned' symbol; one which has come from another BFD, or one + which has been created using <>. An + example showing the creation of a symbol table with only one element: + +| #include "bfd.h" +| main() +| { +| bfd *abfd; +| asymbol *ptrs[2]; +| asymbol *new; +| +| abfd = bfd_openw("foo","a.out-sunos-big"); +| bfd_set_format(abfd, bfd_object); +| new = bfd_make_empty_symbol(abfd); +| new->name = "dummy_symbol"; +| new->section = bfd_make_section_old_way(abfd, ".text"); +| new->flags = BSF_GLOBAL; +| new->value = 0x12345; +| +| ptrs[0] = new; +| ptrs[1] = (asymbol *)0; +| +| bfd_set_symtab(abfd, ptrs, 1); +| bfd_close(abfd); +| } +| +| ./makesym +| nm foo +| 00012345 A dummy_symbol + + Many formats cannot represent arbitary symbol information; for + instance the <> object format does not allow an + arbitary number of sections. A symbol pointing to a section + which is not one of <<.text>>, <<.data>> or <<.bss>> cannot + be described. + +*/ + + + +/* +DOCDD +INODE +typedef asymbol, symbol handling functions, Writing Symbols, Symbols + +*/ +/* +SUBSECTION + typedef asymbol + + An <> has the form: + +*/ + +/* +CODE_FRAGMENT + +. +.typedef struct symbol_cache_entry +.{ +. {* A pointer to the BFD which owns the symbol. This information +. is necessary so that a back end can work out what additional +. information (invisible to the application writer) is carried +. with the symbol. +. +. This field is *almost* redundant, since you can use section->owner +. instead, except that some symbols point to the global sections +. bfd_{abs,com,und}_section. This could be fixed by making +. these globals be per-bfd (or per-target-flavor). FIXME. *} +. +. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} +. +. {* The text of the symbol. The name is left alone, and not copied - the +. application may not alter it. *} +. CONST char *name; +. +. {* The value of the symbol. This really should be a union of a +. numeric value with a pointer, since some flags indicate that +. a pointer to another symbol is stored here. *} +. symvalue value; +. +. {* Attributes of a symbol: *} +. +.#define BSF_NO_FLAGS 0x00 +. +. {* The symbol has local scope; <> in <>. The value +. is the offset into the section of the data. *} +.#define BSF_LOCAL 0x01 +. +. {* The symbol has global scope; initialized data in <>. The +. value is the offset into the section of the data. *} +.#define BSF_GLOBAL 0x02 +. +. {* The symbol has global scope, and is exported. The value is +. the offset into the section of the data. *} +.#define BSF_EXPORT BSF_GLOBAL {* no real difference *} +. +. {* A normal C symbol would be one of: +. <>, <>, <> or +. <> *} +. +. {* The symbol is a debugging record. The value has an arbitary +. meaning. *} +.#define BSF_DEBUGGING 0x08 +. +. {* The symbol denotes a function entry point. Used in ELF, +. perhaps others someday. *} +.#define BSF_FUNCTION 0x10 +. +. {* Used by the linker. *} +.#define BSF_KEEP 0x20 +.#define BSF_KEEP_G 0x40 +. +. {* A weak global symbol, overridable without warnings by +. a regular global symbol of the same name. *} +.#define BSF_WEAK 0x80 +. +. {* This symbol was created to point to a section, e.g. ELF's +. STT_SECTION symbols. *} +.#define BSF_SECTION_SYM 0x100 +. +. {* The symbol used to be a common symbol, but now it is +. allocated. *} +.#define BSF_OLD_COMMON 0x200 +. +. {* The default value for common data. *} +.#define BFD_FORT_COMM_DEFAULT_VALUE 0 +. +. {* In some files the type of a symbol sometimes alters its +. location in an output file - ie in coff a <> symbol +. which is also <> symbol appears where it was +. declared and not at the end of a section. This bit is set +. by the target BFD part to convey this information. *} +. +.#define BSF_NOT_AT_END 0x400 +. +. {* Signal that the symbol is the label of constructor section. *} +.#define BSF_CONSTRUCTOR 0x800 +. +. {* Signal that the symbol is a warning symbol. If the symbol +. is a warning symbol, then the value field (I know this is +. tacky) will point to the asymbol which when referenced will +. cause the warning. *} +.#define BSF_WARNING 0x1000 +. +. {* Signal that the symbol is indirect. The value of the symbol +. is a pointer to an undefined asymbol which contains the +. name to use instead. *} +.#define BSF_INDIRECT 0x2000 +. +. {* BSF_FILE marks symbols that contain a file name. This is used +. for ELF STT_FILE symbols. *} +.#define BSF_FILE 0x4000 +. +. flagword flags; +. +. {* A pointer to the section to which this symbol is +. relative. This will always be non NULL, there are special +. sections for undefined and absolute symbols *} +. struct sec *section; +. +. {* Back end special data. This is being phased out in favour +. of making this a union. *} +. PTR udata; +. +.} asymbol; +*/ + +#include "bfd.h" +#include "sysdep.h" + +#include "libbfd.h" +#include "aout/stab_gnu.h" + +/* +DOCDD +INODE +symbol handling functions, , typedef asymbol, Symbols +SUBSECTION + Symbol Handling Functions +*/ + +/* +FUNCTION + get_symtab_upper_bound + +DESCRIPTION + Returns the number of bytes required in a vector of pointers + to <> for all the symbols in the supplied BFD, + including a terminal NULL pointer. If there are no symbols in + the BFD, then 0 is returned. + +.#define get_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _get_symtab_upper_bound, (abfd)) + +*/ + +/* +FUNCTION + bfd_canonicalize_symtab + +DESCRIPTION + Supplied a BFD and a pointer to an uninitialized vector of + pointers. This reads in the symbols from the BFD, and fills in + the table with pointers to the symbols, and a trailing NULL. + The routine returns the actual number of symbol pointers not + including the NULL. + + +.#define bfd_canonicalize_symtab(abfd, location) \ +. BFD_SEND (abfd, _bfd_canonicalize_symtab,\ +. (abfd, location)) + +*/ + + +/* +FUNCTION + bfd_set_symtab + +DESCRIPTION + Provided a table of pointers to symbols and a count, writes to + the output BFD the symbols when closed. + +SYNOPSIS + boolean bfd_set_symtab (bfd *, asymbol **, unsigned int ); +*/ + +boolean +bfd_set_symtab (abfd, location, symcount) + bfd *abfd; + asymbol **location; + unsigned int symcount; +{ + if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) { + bfd_error = invalid_operation; + return false; + } + + bfd_get_outsymbols (abfd) = location; + bfd_get_symcount (abfd) = symcount; + return true; +} + +/* +FUNCTION + bfd_print_symbol_vandf + +DESCRIPTION + Prints the value and flags of the symbol supplied to the stream file. + +SYNOPSIS + void bfd_print_symbol_vandf(PTR file, asymbol *symbol); +*/ +void +DEFUN(bfd_print_symbol_vandf,(file, symbol), +PTR file AND +asymbol *symbol) +{ + flagword type = symbol->flags; + if (symbol->section != (asection *)NULL) + { + fprintf_vma(file, symbol->value+symbol->section->vma); + } + else + { + fprintf_vma(file, symbol->value); + } + fprintf(file," %c%c%c%c%c%c%c", + (type & BSF_LOCAL) ? 'l':' ', + (type & BSF_GLOBAL) ? 'g' : ' ', + (type & BSF_WEAK) ? 'w' : ' ', + (type & BSF_CONSTRUCTOR) ? 'C' : ' ', + (type & BSF_WARNING) ? 'W' : ' ', + (type & BSF_INDIRECT) ? 'I' : ' ', + (type & BSF_DEBUGGING) ? 'd' :' '); + +} + + +/* +FUNCTION + bfd_make_empty_symbol + +DESCRIPTION + This function creates a new <> structure for the BFD, + and returns a pointer to it. + + This routine is necessary, since each back end has private + information surrounding the <>. Building your own + <> and pointing to it will not create the private + information, and will cause problems later on. + +.#define bfd_make_empty_symbol(abfd) \ +. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +*/ + +/* +FUNCTION + bfd_make_debug_symbol + +DESCRIPTION + This function creates a new <> structure for the BFD, + to be used as a debugging symbol. Further details of its use have + yet to be worked out. + +.#define bfd_make_debug_symbol(abfd,ptr,size) \ +. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +*/ + +struct section_to_type +{ + CONST char *section; + char type; +}; + +/* Map COFF section names to POSIX/BSD single-character symbol types. + This table is probably incomplete. It is sorted for convenience of + adding entries. Since it is so short, a linear search is used. */ +static CONST struct section_to_type stt[] = { + {"*DEBUG*", 'N'}, + {".bss", 'b'}, + {".data", 'd'}, + {".sbss", 's'}, /* Small BSS (uninitialized data) */ + {".scommon", 'c'}, /* Small common */ + {".sdata", 'g'}, /* Small initialized data */ + {".text", 't'}, + {0, 0} +}; + +/* Return the single-character symbol type corresponding to + COFF section S, or '?' for an unknown COFF section. */ + +static char +coff_section_type (s) + char *s; +{ + CONST struct section_to_type *t; + + for (t = &stt[0]; t->section; t++) + if (!strcmp (s, t->section)) + return t->type; + return '?'; +} + +#ifndef islower +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#endif +#ifndef toupper +#define toupper(c) (islower(c) ? ((c) & ~0x20) : (c)) +#endif + +/* +FUNCTION + bfd_decode_symclass + +DESCRIPTION + Return a character corresponding to the symbol + class of symbol, or '?' for an unknown class. + +SYNOPSIS + int bfd_decode_symclass(asymbol *symbol); +*/ +int +DEFUN(bfd_decode_symclass,(symbol), +asymbol *symbol) +{ + char c; + + if (bfd_is_com_section (symbol->section)) + return 'C'; + if (symbol->section == &bfd_und_section) + return 'U'; + if (symbol->section == &bfd_ind_section) + return 'I'; + if (!(symbol->flags & (BSF_GLOBAL|BSF_LOCAL))) + return '?'; + + if (symbol->section == &bfd_abs_section) + c = 'a'; + else if (symbol->section) + c = coff_section_type (symbol->section->name); + else + return '?'; + if (symbol->flags & BSF_GLOBAL) + c = toupper (c); + return c; + + /* We don't have to handle these cases just yet, but we will soon: + N_SETV: 'v'; + N_SETA: 'l'; + N_SETT: 'x'; + N_SETD: 'z'; + N_SETB: 's'; + N_INDR: 'i'; + */ +} + +/* +FUNCTION + bfd_symbol_info + +DESCRIPTION + Fill in the basic info about symbol that nm needs. + Additional info may be added by the back-ends after + calling this function. + +SYNOPSIS + void bfd_symbol_info(asymbol *symbol, symbol_info *ret); +*/ + +void +DEFUN(bfd_symbol_info,(symbol, ret), + asymbol *symbol AND + symbol_info *ret) +{ + ret->type = bfd_decode_symclass (symbol); + if (ret->type != 'U') + ret->value = symbol->value+symbol->section->vma; + else + ret->value = 0; + ret->name = symbol->name; +} + +void +bfd_symbol_is_absolute() +{ + abort(); +} + diff --git a/gnu/usr.bin/gdb/bfd/sysdep.h b/gnu/usr.bin/gdb/bfd/sysdep.h new file mode 100644 index 00000000000..68b107d7b67 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/sysdep.h @@ -0,0 +1,46 @@ +#ifndef hosts_i386bsd_H +/* Intel 386 running any BSD Unix */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +#define HOST_PAGE_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_i386 +#define HOST_TEXT_START_ADDR USRTEXT + +/* Jolitz suggested defining HOST_STACK_END_ADDR to + (u.u_kproc.kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ), which should work on + both BSDI and 386BSD, but that is believed not to work for BSD 4.4. */ + +#ifdef __bsdi__ +/* This seems to be the right thing for BSDI. */ +#define HOST_STACK_END_ADDR USRSTACK +#define HOST_DATA_START_ADDR ((bfd_vma)u.u_kproc.kp_eproc.e_vm.vm_daddr) +#else +/* This seems to be the right thing for 386BSD release 0.1. */ +#define HOST_STACK_END_ADDR (USRSTACK - MAXSSIZ) +#endif + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm + +#include "fopen-same.h" + +#define hosts_i386bsd_H +#endif diff --git a/gnu/usr.bin/gdb/bfd/targets.c b/gnu/usr.bin/gdb/bfd/targets.c new file mode 100644 index 00000000000..d6a966588c4 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/targets.c @@ -0,0 +1,635 @@ +/* Generic target-file-type support for the BFD library. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + Targets + +DESCRIPTION + Each port of BFD to a different machine requries the creation + of a target back end. All the back end provides to the root + part of BFD is a structure containing pointers to functions + which perform certain low level operations on files. BFD + translates the applications's requests through a pointer into + calls to the back end routines. + + When a file is opened with <>, its format and + target are unknown. BFD uses various mechanisms to determine + how to interpret the file. The operations performed are: + + o First a BFD is created by calling the internal routine + <>, then <> is called with the + target string supplied to <> and the new BFD pointer. + + o If a null target string was provided to <>, + it looks up the environment variable <> and uses + that as the target string. + + o If the target string is still NULL, or the target string is + <>, then the first item in the target vector is used + as the target type, and <> is set to + cause <> to loop through all the targets. + @xref{bfd_target}. @xref{Formats}. + + o Otherwise, the elements in the target vector are inspected + one by one, until a match on target name is found. When found, + that is used. + + o Otherwise the error <> is returned to + <>. + + o <> attempts to open the file using + <>, and returns the BFD. + + Once the BFD has been opened and the target selected, the file + format may be determined. This is done by calling + <> on the BFD with a suggested format. + If <> has been set, each possible target + type is tried to see if it recognizes the specified format. The + routine returns <> when the application guesses right. +@menu +@* bfd_target:: +@end menu +*/ + + +/* + +INODE + bfd_target, , Targets, Targets +DOCDD +SUBSECTION + bfd_target + +DESCRIPTION + This structure contains everything that BFD knows about a + target. It includes things like its byte order, name, what + routines to call to do various operations, etc. + + Every BFD points to a target structure with its <> + member. + + These macros are used to dispatch to functions through the + bfd_target vector. They are used in a number of macros further + down in @file{bfd.h}, and are also used when calling various + routines by hand inside the BFD implementation. The "arglist" + argument must be parenthesized; it contains all the arguments + to the called function. + + They make the documentation (more) unpleasant to read, so if + someone wants to fix this and not break the above, please do. + +.#define BFD_SEND(bfd, message, arglist) \ +. ((*((bfd)->xvec->message)) arglist) + + For operations which index on the BFD format + +.#define BFD_SEND_FMT(bfd, message, arglist) \ +. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) + + This is the struct which defines the type of BFD this is. The + <> member of the struct <> itself points here. Each + module that implements access to a different target under BFD, + defines one of these. + + + FIXME, these names should be rationalised with the names of + the entry points which call them. Too bad we can't have one + macro to define them both! + +.typedef struct bfd_target +.{ + +Identifies the kind of target, eg SunOS4, Ultrix, etc. + +. char *name; + +The "flavour" of a back end is a general indication about the contents +of a file. + +. enum target_flavour { +. bfd_target_unknown_flavour, +. bfd_target_aout_flavour, +. bfd_target_coff_flavour, +. bfd_target_ecoff_flavour, +. bfd_target_elf_flavour, +. bfd_target_ieee_flavour, +. bfd_target_nlm_flavour, +. bfd_target_oasys_flavour, +. bfd_target_tekhex_flavour, +. bfd_target_srec_flavour, +. bfd_target_hppa_flavour} flavour; + +The order of bytes within the data area of a file. + +. boolean byteorder_big_p; + +The order of bytes within the header parts of a file. + +. boolean header_byteorder_big_p; + +This is a mask of all the flags which an executable may have set - +from the set <>, <>, ...<>. + +. flagword object_flags; + +This is a mask of all the flags which a section may have set - from +the set <>, <>, ...<>. + +. flagword section_flags; + +The character normally found at the front of a symbol +(if any), perhaps _. + +. char symbol_leading_char; + +The pad character for filenames within an archive header. + +. char ar_pad_char; + +The maximum number of characters in an archive header. + +. unsigned short ar_max_namelen; + +The minimum alignment restriction for any section. + +. unsigned int align_power_min; + +Entries for byte swapping for data. These are different to the other +entry points, since they don't take BFD as first arg. Certain other handlers +could do the same. + +. bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *)); +. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *)); +. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *)); +. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + +Byte swapping for the headers + +. bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *)); +. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *)); +. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *)); +. void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + +Format dependent routines: these are vectors of entry points +within the target vector structure, one for each format to check. + +Check the format of a file being read. Return bfd_target * or zero. + +. struct bfd_target * (*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + +Set the format of a file being written. + +. boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + +Write cached information into a file being written, at bfd_close. + +. boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + +The following functions are defined in <>. The idea is +that the back end writer of <> names all the routines +<>@var{entry_point}, <> will built the entries +in this structure in the right order. + +Core file entry points + +. char * (*_core_file_failing_command) PARAMS ((bfd *)); +. int (*_core_file_failing_signal) PARAMS ((bfd *)); +. boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + +Archive entry points + +. boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); +. boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); +. void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); +. boolean (*write_armap) PARAMS ((bfd *arch, +. unsigned int elength, +. struct orl *map, +. unsigned int orl_count, +. int stridx)); + +Standard stuff. + +. boolean (*_close_and_cleanup) PARAMS ((bfd *)); +. boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, +. file_ptr, bfd_size_type)); +. boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, +. file_ptr, bfd_size_type)); +. boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + +Symbols and relocations + +. unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *)); +. unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *, +. struct symbol_cache_entry **)); +. unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); +. unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, +. struct symbol_cache_entry **)); +. struct symbol_cache_entry * +. (*_bfd_make_empty_symbol) PARAMS ((bfd *)); +. void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, +. struct symbol_cache_entry *, +. bfd_print_symbol_type)); +.#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) +. void (*_bfd_get_symbol_info) PARAMS ((bfd *, +. struct symbol_cache_entry *, +. symbol_info *)); +.#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + +. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); +. +. boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, +. unsigned long)); +. +. bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); +. +. boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, +. struct sec *section, struct symbol_cache_entry **symbols, +. bfd_vma offset, CONST char **file, CONST char **func, +. unsigned int *line)); +. +. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); +. +. int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); +. +. void (*_bfd_debug_info_start) PARAMS ((bfd *)); +. void (*_bfd_debug_info_end) PARAMS ((bfd *)); +. void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *)); +. +. bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, +. struct bfd_seclet *, bfd_byte *data, +. boolean relocateable)); +. +. boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, +. struct symbol_cache_entry **)); +. +. boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data, +. boolean relocateable)); + +. {* See documentation on reloc types. *} +. CONST struct reloc_howto_struct * +. (*reloc_type_lookup) PARAMS ((bfd *abfd, +. bfd_reloc_code_real_type code)); +. +. {* Back-door to allow format-aware applications to create debug symbols +. while using BFD for everything else. Currently used by the assembler +. when creating COFF files. *} +. asymbol * (*_bfd_make_debug_symbol) PARAMS (( +. bfd *abfd, +. void *ptr, +. unsigned long size)); + +Data for use by back-end routines, which isn't generic enough to belong +in this structure. + +. PTR backend_data; +.} bfd_target; + +*/ + +/* All known xvecs (even those that don't compile on all systems). + Alphabetized for easy reference. + They are listed a second time below, since + we can't intermix extern's and initializers. */ +extern bfd_target a29kcoff_big_vec; +extern bfd_target a_out_adobe_vec; +extern bfd_target aout_mips_big_vec; +extern bfd_target aout_mips_little_vec; +extern bfd_target apollocoff_vec; +extern bfd_target b_out_vec_big_host; +extern bfd_target b_out_vec_little_host; +extern bfd_target bfd_elf32_big_generic_vec; +extern bfd_target bfd_elf32_bigmips_vec; +extern bfd_target bfd_elf32_hppa_vec; +extern bfd_target bfd_elf32_i386_vec; +extern bfd_target bfd_elf32_i860_vec; +extern bfd_target bfd_elf32_little_generic_vec; +extern bfd_target bfd_elf32_littlemips_vec; +extern bfd_target bfd_elf32_m68k_vec; +extern bfd_target bfd_elf32_m88k_vec; +extern bfd_target bfd_elf32_sparc_vec; +extern bfd_target bfd_elf64_big_generic_vec; +extern bfd_target bfd_elf64_little_generic_vec; +extern bfd_target demo_64_vec; +extern bfd_target ecoff_big_vec; +extern bfd_target ecoff_little_vec; +extern bfd_target ecoffalpha_little_vec; +extern bfd_target h8300coff_vec; +extern bfd_target h8500coff_vec; +extern bfd_target host_aout_vec; +extern bfd_target hp300bsd_vec; +extern bfd_target hp300hpux_vec; +extern bfd_target hppa_vec; +extern bfd_target i386aout_vec; +extern bfd_target i386bsd_vec; +extern bfd_target netbsd386_vec; +extern bfd_target freebsd386_vec; +extern bfd_target i386coff_vec; +extern bfd_target i386linux_vec; +extern bfd_target i386lynx_aout_vec; +extern bfd_target i386lynx_coff_vec; +extern bfd_target icoff_big_vec; +extern bfd_target icoff_little_vec; +extern bfd_target ieee_vec; +extern bfd_target m68kcoff_vec; +extern bfd_target m68kcoffun_vec; +extern bfd_target m68klynx_aout_vec; +extern bfd_target m68klynx_coff_vec; +extern bfd_target m88kbcs_vec; +extern bfd_target newsos3_vec; +extern bfd_target nlm32_big_generic_vec; +extern bfd_target nlm32_i386_vec; +extern bfd_target nlm32_little_generic_vec; +extern bfd_target nlm64_big_generic_vec; +extern bfd_target nlm64_little_generic_vec; +extern bfd_target oasys_vec; +extern bfd_target rs6000coff_vec; +extern bfd_target shcoff_vec; +extern bfd_target sunos_big_vec; +extern bfd_target tekhex_vec; +extern bfd_target we32kcoff_vec; +extern bfd_target z8kcoff_vec; + +/* srec is always included. */ +extern bfd_target srec_vec; +extern bfd_target symbolsrec_vec; + +/* All of the xvecs for core files. */ +extern bfd_target aix386_core_vec; +extern bfd_target hpux_core_vec; +extern bfd_target osf_core_vec; +extern bfd_target sco_core_vec; +extern bfd_target trad_core_vec; + +bfd_target *target_vector[] = { + +#ifdef SELECT_VECS + + SELECT_VECS, + +#else /* not SELECT_VECS */ + +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + /* This list is alphabetized to make it easy to compare + with other vector lists -- the decls above and + the case statement in configure.in. + Vectors that don't compile on all systems, or aren't finished, + should have an entry here with #if 0 around it, to show that + it wasn't omitted by mistake. */ + &a29kcoff_big_vec, + &a_out_adobe_vec, +#if 0 /* No one seems to use this. */ + &aout_mips_big_vec, +#endif + &aout_mips_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, +#if 0 /* No one seems to use this. */ + &bfd_elf32_big_generic_vec, + &bfd_elf32_bigmips_vec, +#endif +#if 0 + &bfd_elf32_hppa_vec, +#endif + &bfd_elf32_i386_vec, + &bfd_elf32_i860_vec, +#if 0 /* No one seems to use this. */ + &bfd_elf32_little_generic_vec, + &bfd_elf32_littlemips_vec, +#endif + &bfd_elf32_m68k_vec, + &bfd_elf32_m88k_vec, + &bfd_elf32_sparc_vec, +#ifdef BFD64 /* No one seems to use this. */ + &bfd_elf64_big_generic_vec, + &bfd_elf64_little_generic_vec, +#endif +#ifdef BFD64 + &demo_64_vec, /* Only compiled if host has long-long support */ +#endif + &ecoff_big_vec, + &ecoff_little_vec, +#if 0 + &ecoffalpha_little_vec, +#endif + &h8300coff_vec, + &h8500coff_vec, +#if 0 + &host_aout_vec, +#endif +#if 0 /* Clashes with sunos_big_vec magic no. */ + &hp300bsd_vec, +#endif + &hp300hpux_vec, +#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) + &hppa_vec, +#endif + &i386aout_vec, + &i386bsd_vec, + &netbsd386_vec, + &freebsd386_vec, + &i386coff_vec, +#if 0 + &i386linux_vec, +#endif + &i386lynx_aout_vec, + &i386lynx_coff_vec, + &icoff_big_vec, + &icoff_little_vec, + &ieee_vec, + &m68kcoff_vec, + &m68kcoffun_vec, + &m68klynx_aout_vec, + &m68klynx_coff_vec, + &m88kbcs_vec, + &newsos3_vec, +#if 0 /* No one seems to use this. */ + &nlm32_big_generic_vec, +#endif + &nlm32_i386_vec, +#if 0 /* No one seems to use this. */ + &nlm32_little_generic_vec, +#endif +#ifdef BFD64 + &nlm64_big_generic_vec, + &nlm64_little_generic_vec, +#endif +#if 0 + /* We have no oasys tools anymore, so we can't test any of this + anymore. If you want to test the stuff yourself, go ahead... + steve@cygnus.com + Worse, since there is no magic number for archives, there + can be annoying target mis-matches. */ + &oasys_vec, +#endif + &rs6000coff_vec, + &shcoff_vec, + &sunos_big_vec, +#if 0 + &tekhex_vec, +#endif + &we32kcoff_vec, + &z8kcoff_vec, + +#endif /* not SELECT_VECS */ + +/* Always support S-records, for convenience. */ + &srec_vec, + &symbolsrec_vec, + +/* Add any required traditional-core-file-handler. */ + +#ifdef AIX386_CORE + &aix386_core_vec, +#endif +#ifdef HPUX_CORE + &hpux_core_vec, +#endif +#ifdef OSF_CORE + &osf_core_vec, +#endif +#ifdef SCO_CORE + &sco_core_vec, +#endif +#ifdef TRAD_CORE + &trad_core_vec, +#endif + + NULL /* end of list marker */ +}; + +/* default_vector[0] contains either the address of the default vector, + if there is one, or zero if there isn't. */ + +bfd_target *default_vector[] = { +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + NULL +}; + + + + +/* +FUNCTION + bfd_find_target + +DESCRIPTION + Returns a pointer to the transfer vector for the object target + named target_name. If target_name is NULL, chooses the one in + the environment variable GNUTARGET; if that is null or not + defined thenthe first entry in the target list is chosen. + Passing in the string "default" or setting the environment + variable to "default" will cause the first entry in the target + list to be returned, and "target_defaulted" will be set in the + BFD. This causes <> to loop over all the + targets to find the one that matches the file being read. + +SYNOPSIS + bfd_target *bfd_find_target(CONST char *, bfd *); +*/ + +bfd_target * +DEFUN(bfd_find_target,(target_name, abfd), + CONST char *target_name AND + bfd *abfd) +{ + bfd_target **target; + extern char *getenv (); + CONST char *targname = (target_name ? target_name : + (CONST char *) getenv ("GNUTARGET")); + + /* This is safe; the vector cannot be null */ + if (targname == NULL || !strcmp (targname, "default")) { + abfd->target_defaulted = true; + return abfd->xvec = target_vector[0]; + } + + abfd->target_defaulted = false; + + for (target = &target_vector[0]; *target != NULL; target++) { + if (!strcmp (targname, (*target)->name)) + return abfd->xvec = *target; + } + + bfd_error = invalid_target; + return NULL; +} + + +/* +FUNCTION + bfd_target_list + +DESCRIPTION + This function returns a freshly malloced NULL-terminated + vector of the names of all the valid BFD targets. Do not + modify the names + +SYNOPSIS + CONST char **bfd_target_list(void); + +*/ + +CONST char ** +DEFUN_VOID(bfd_target_list) +{ + int vec_length= 0; +#ifdef NATIVE_HPPAHPUX_COMPILER + /* The native compiler on the HP9000/700 has a bug which causes it + to loop endlessly when compiling this file. This avoids it. */ + volatile +#endif + bfd_target **target; + CONST char **name_list, **name_ptr; + + for (target = &target_vector[0]; *target != NULL; target++) + vec_length++; + + name_ptr = + name_list = (CONST char **) zalloc ((vec_length + 1) * sizeof (char **)); + + if (name_list == NULL) { + bfd_error = no_memory; + return NULL; + } + + for (target = &target_vector[0]; *target != NULL; target++) + *(name_ptr++) = (*target)->name; + + return name_list; +} diff --git a/gnu/usr.bin/gdb/bfd/trad-core.c b/gnu/usr.bin/gdb/bfd/trad-core.c new file mode 100644 index 00000000000..203c80e6a83 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/trad-core.c @@ -0,0 +1,384 @@ +/* BFD back end for traditional Unix core files (U-area and raw sections) + Copyright 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by John Gilmore of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + +/* To use this file on a particular host, configure the host with these + parameters in the config/h-HOST file: + + HDEFINES=-DTRAD_CORE + HDEPFILES=trad-core.o + + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include +#include +#include +#include +#include + +#include /* After a.out.h */ +#if 0 +/* file.h is included by std-host.h. So we better not try to include it + twice; on some systems (dpx2) it is not protected against multiple + inclusion. I have checked that all the hosts which use this file + include sys/file.h in the hosts file. */ +#include +#endif + +#include + + struct trad_core_struct + { + asection *data_section; + asection *stack_section; + asection *reg_section; + struct user u; + } *rawptr; + +#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u)) +#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section) +#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section) +#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section) + +/* forward declarations */ + +bfd_target * trad_unix_core_file_p PARAMS ((bfd *abfd)); +char * trad_unix_core_file_failing_command PARAMS ((bfd *abfd)); +int trad_unix_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean trad_unix_core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */ + +/* ARGSUSED */ +bfd_target * +trad_unix_core_file_p (abfd) + bfd *abfd; + +{ + int val; + struct user u; + +#ifdef TRAD_CORE_USER_OFFSET + /* If defined, this macro is the file position of the user struct. */ + if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) == 0) + return 0; +#endif + + val = bfd_read ((void *)&u, 1, sizeof u, abfd); + if (val != sizeof u) + { + /* Too small to be a core file */ + bfd_error = wrong_format; + return 0; + } + + /* Sanity check perhaps??? */ + if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */ + { + bfd_error = wrong_format; + return 0; + } + if (u.u_ssize > 0x1000000) + { + bfd_error = wrong_format; + return 0; + } + + /* Check that the size claimed is no greater than the file size. */ + { + FILE *stream = bfd_cache_lookup (abfd); + struct stat statbuf; + if (stream == NULL) + return 0; + if (fstat (fileno (stream), &statbuf) < 0) + { + bfd_error = system_call_error; + return 0; + } + if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) > statbuf.st_size) + { + bfd_error = file_truncated; + return 0; + } + if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) +#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED + /* Some systems write the file too big. */ + + TRAD_CORE_EXTRA_SIZE_ALLOWED +#endif + < statbuf.st_size) + { + /* The file is too big. Maybe it's not a core file + or we otherwise have bad values for u_dsize and u_ssize). */ + bfd_error = wrong_format; + return 0; + } + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + /* Allocate both the upage and the struct core_data at once, so + a single free() will free them both. */ + rawptr = (struct trad_core_struct *) + bfd_zalloc (abfd, sizeof (struct trad_core_struct)); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + abfd->tdata.trad_core_data = rawptr; + + rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */ + + /* Create the sections. This is raunchy, but bfd_close wants to free + them separately. */ + + core_stacksec(abfd) = (asection *) zalloc (sizeof (asection)); + if (core_stacksec (abfd) == NULL) { + loser: + bfd_error = no_memory; + free ((void *)rawptr); + return 0; + } + core_datasec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_datasec (abfd) == NULL) { + loser1: + free ((void *)core_stacksec (abfd)); + goto loser; + } + core_regsec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_regsec (abfd) == NULL) { + free ((void *)core_datasec (abfd)); + goto loser1; + } + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_regsec (abfd)->flags = SEC_ALLOC + SEC_HAS_CONTENTS; + + core_datasec (abfd)->_raw_size = NBPG * u.u_dsize; + core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize; + core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */ + + /* What a hack... we'd like to steal it from the exec file, + since the upage does not seem to provide it. FIXME. */ +#ifdef HOST_DATA_START_ADDR + core_datasec (abfd)->vma = HOST_DATA_START_ADDR; +#else + core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize); +#endif +/* a hack, but it works for FreeBSD !! */ +#include +/* this should really be in , but somebody forgot it */ +#ifndef vm_page_size +#define vm_page_size 4096 +#endif +#define HOST_STACK_START_ADDR trunc_page(u.u_kproc.kp_eproc.e_vm.vm_maxsaddr \ ++ MAXSSIZ - ctob(u.u_ssize)) +#ifdef HOST_STACK_START_ADDR + core_stacksec (abfd)->vma = HOST_STACK_START_ADDR; +#else + core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize); +#endif + + /* This is tricky. As the "register section", we give them the entire + upage and stack. u.u_ar0 points to where "register 0" is stored. + There are two tricks with this, though. One is that the rest of the + registers might be at positive or negative (or both) displacements + from *u_ar0. The other is that u_ar0 is sometimes an absolute address + in kernel memory, and on other systems it is an offset from the beginning + of the `struct user'. + + As a practical matter, we don't know where the registers actually are, + so we have to pass the whole area to GDB. We encode the value of u_ar0 + by setting the .regs section up so that its virtual memory address + 0 is at the place pointed to by u_ar0 (by setting the vma of the start + of the section to -u_ar0). GDB uses this info to locate the regs, + using minor trickery to get around the offset-or-absolute-addr problem. */ + core_regsec (abfd)->vma = 0 - (int) u.u_ar0; + + core_datasec (abfd)->filepos = NBPG * UPAGES; +#ifdef TRAD_CORE_STACK_FILEPOS + core_stacksec (abfd)->filepos = TRAD_CORE_STACK_FILEPOS; +#else + core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize; +#endif + core_regsec (abfd)->filepos = 0; /* Register segment is the upage */ + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + abfd->section_count = 3; + + return abfd->xvec; +} + +char * +trad_unix_core_file_failing_command (abfd) + bfd *abfd; +{ +#ifndef NO_CORE_COMMAND + char *com = abfd->tdata.trad_core_data->u.u_comm; + if (*com) + return com; + else +#endif + return 0; +} + +/* ARGSUSED */ +int +trad_unix_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd; +{ +#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL + return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd); +#else + return -1; /* FIXME, where is it? */ +#endif +} + +/* ARGSUSED */ +boolean +trad_unix_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +/* No archive file support via this BFD */ +#define trad_unix_openr_next_archived_file bfd_generic_openr_next_archived_file +#define trad_unix_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define trad_unix_slurp_armap bfd_false +#define trad_unix_slurp_extended_name_table bfd_true +#define trad_unix_write_armap (boolean (*) PARAMS \ + ((bfd *arch, unsigned int elength, struct orl *map, \ + unsigned int orl_count, int stridx))) bfd_false +#define trad_unix_truncate_arname bfd_dont_truncate_arname +#define aout_32_openr_next_archived_file bfd_generic_openr_next_archived_file + +#define trad_unix_close_and_cleanup bfd_generic_close_and_cleanup +#define trad_unix_set_section_contents (boolean (*) PARAMS \ + ((bfd *abfd, asection *section, PTR data, file_ptr offset, \ + bfd_size_type count))) bfd_false +#define trad_unix_get_section_contents bfd_generic_get_section_contents +#define trad_unix_new_section_hook (boolean (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_true +#define trad_unix_get_symtab_upper_bound bfd_0u +#define trad_unix_get_symtab (unsigned int (*) PARAMS \ + ((bfd *, struct symbol_cache_entry **))) bfd_0u +#define trad_unix_get_reloc_upper_bound (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_0u +#define trad_unix_canonicalize_reloc (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry**))) bfd_0u +#define trad_unix_make_empty_symbol (struct symbol_cache_entry * \ + (*) PARAMS ((bfd *))) bfd_false +#define trad_unix_print_symbol (void (*) PARAMS \ + ((bfd *, PTR, struct symbol_cache_entry *, \ + bfd_print_symbol_type))) bfd_false +#define trad_unix_get_symbol_info (void (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *, \ + symbol_info *))) bfd_false +#define trad_unix_get_lineno (alent * (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *))) bfd_nullvoidptr +#define trad_unix_set_arch_mach (boolean (*) PARAMS \ + ((bfd *, enum bfd_architecture, unsigned long))) bfd_false +#define trad_unix_find_nearest_line (boolean (*) PARAMS \ + ((bfd *abfd, struct sec *section, \ + struct symbol_cache_entry **symbols,bfd_vma offset, \ + CONST char **file, CONST char **func, unsigned int *line))) bfd_false +#define trad_unix_sizeof_headers (int (*) PARAMS \ + ((bfd *, boolean))) bfd_0 + +#define trad_unix_bfd_debug_info_start bfd_void +#define trad_unix_bfd_debug_info_end bfd_void +#define trad_unix_bfd_debug_info_accumulate (void (*) PARAMS \ + ((bfd *, struct sec *))) bfd_void +#define trad_unix_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define trad_unix_bfd_relax_section bfd_generic_relax_section +#define trad_unix_bfd_seclet_link \ + ((boolean (*) PARAMS ((bfd *, PTR, boolean))) bfd_false) +#define trad_unix_bfd_reloc_type_lookup \ + ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) +#define trad_unix_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET ((bfd_signed_vma (*) PARAMS ((bfd_byte *))) swap_abort ) + +bfd_target trad_core_vec = + { + "trad-core", + bfd_target_unknown_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 3, /* minimum alignment power */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + trad_unix_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + JUMP_TABLE(trad_unix), + (PTR) 0 /* backend_data */ +}; diff --git a/gnu/usr.bin/gdb/doc/ChangeLog b/gnu/usr.bin/gdb/doc/ChangeLog new file mode 100644 index 00000000000..fb867193a4a --- /dev/null +++ b/gnu/usr.bin/gdb/doc/ChangeLog @@ -0,0 +1,783 @@ +Tue Oct 19 14:21:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo (Sourc Path): index entries for $cwd, $pdir + + * a4rc.sed: update to work with Andreas Vogel papersize params + + * refcard.tex: use Andreas Vogel simplifications of papersize + params; remove useless version info; update copyright date. + +Tue Oct 19 10:46:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Symbols): Add class NAME to doc for ptype. + +Tue Oct 12 09:11:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Files): Say what address the load command loads it at. + + * stabs.texinfo (Common Blocks): Minor cleanups. + + * stabs.texinfo: Update ld stabs in elf relocation to reflect the fact + that Sun has backed away from the linker kludge and thus the relevant + issue is changes to the SunPRO tools, not the Solaris linker. + + * stabs.texinfo (Traditional Integer Types): Clean up description + of octal bounds a little bit. Document extra leading zeroes. + +Thu Oct 7 16:15:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Signaling): Update for symbolic symbol names + and add a section explaining the difference between the GDB + signal command and the shell kill utility. + +Wed Oct 6 13:23:01 1993 Tom Lord (lord@rtl.cygnus.com) + + * libgdb.texinfo: added `@' to braces that were unescaped. + +Mon Oct 4 10:42:18 1993 Tom Lord (lord@rtl.cygnus.com) + + * libgdb.texinfo: new file. Spec for the gdb library. + +Sun Oct 3 15:26:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Include Files): Fix typo (start -> end). + +Thu Sep 30 18:24:56 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, remote.texi: assorted small improvements, mostly + from Melissa at FSF's editing pass. + +Thu Sep 30 11:54:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo: Remove stuff about ar and 14 character filenames. + I believe this was fixed by the 13 Sep 89 change to print_frame_info. + Also, modern versions of ar like BSD 4.4 or SVR4 don't have this bug. + +Wed Sep 22 21:22:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.texi (Bootstrapping): Discuss 386 call gates. + +Sat Sep 18 17:10:44 1993 Jim Kingdon (kingdon@poseidon.cygnus.com) + + * stabs.texinfo (Based Variables): New node. + +Thu Sep 16 17:48:55 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Re-write discussions of + names, sizes, and formats to suggest how not to lose. + +Sat Sep 11 09:35:11 1993 Jim Kingdon (kingdon@poseidon.cygnus.com) + + * stabs.texinfo (Methods): Fix typo. + +Fri Sep 10 06:34:20 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * gdb.texinfo: Fix a few typos. + +Wed Sep 8 09:11:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo: Clarify how well it works with Fortran. + + * stabs.texinfo (Stabs In ELF, Statics, ELF Transformations): + More on relocating stabs in ELF files. + +Tue Sep 7 13:45:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs In ELF): Talk about N_FUN value. + +Mon Sep 6 19:23:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Local Variable Parameters): Talk about nameless + parameters on VAX. + +Fri Sep 3 17:06:08 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: @up/@down -> @raisesections/@lowersections + +Fri Sep 3 12:04:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Make info author notice match the TeX author notice. + +Tue Aug 31 13:21:06 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * stabs.texinfo: Initial-caps all words in node names and + non-trivial words in section names. + +Mon Aug 30 11:13:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Many minor cleanups. + + * stabs.texinfo: Remove @deffn except from Expanded Reference node. + +Sat Aug 28 12:08:09 1993 David J. MacKenzie (djm@edison.eng.umd.edu) + + * stabs.texinfo: Remove full description of big example. + It's not really helpful; just use pieces of it where appropriate. + Add more Texinfo formatting directives (@samp, etc.). + Use @deffn to define stab types. + Eliminate some wordiness. Break up some nodes. + Add an (alphabetized) index of symbol types. + Use consistent capitalization style in node and section names. + +Thu Aug 26 06:36:31 1993 Fred Fish (fnf@deneb.cygnus.com) + + * gdb.texinfo: Change typo "Two two" to "The two". + +Sun Aug 22 12:15:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (XCOFF-differences): Remove references to + non-existent types N_DECL and N_RPSYM. + + * stabs.texinfo (String Field): Say that type attributes bug is + fixed in GDB 4.10, since it is. + + * stabs.texinfo: Clean up djm cleanups, and more cleanups of my own. + +Sat Aug 21 04:32:28 1993 David MacKenzie (djm@cygnus.com) + + * stabs.texinfo: Formatting cleanups. + +Fri Aug 20 20:49:53 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: When explaining the n_type of a stab, standardize + how we do it ('#' as a comment indicator, "36 is N_FUN" as text, + no tabs, use @r). + (Global Variables): Clean up. + +Tue Aug 17 15:57:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stack Variables): Re-write. + +Mon Aug 16 21:20:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs-in-elf): Talk about getting the start + addresses of a source file. Also revise formatting. + Change "object module" or "object file" to "source file". + Various: Miscellaneous cleanups. + +Thu Aug 12 15:11:51 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Point to mangling info in gcc's gpcompare.texi. + +Tue Aug 10 16:57:49 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * gdbint.texinfo: Removed many nonsensical machine-collected + host and target conditionals, described some of the remainder. + +Tue Aug 10 13:28:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbint.texinfo (Getting Started): Use @itemize, not @table. + + * gdbint.texinfo (Top): Add name to @top line, and re-write the + paragraph which follows. + + * gdbint.texinfo (Host): Use @code not @samp for Makefile + variables. Looks better and avoids overful hbox. + +Fri Jul 30 18:26:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Procedures): Improve stuff on nested functions. + +Thu Jul 29 15:10:58 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * remote.texi: (MIPS Remote) clearer doc for set/show timeout, + retransmit-timeout + +Thu Jul 29 13:16:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbint.texinfo: Update statement about `some ancient Unix + systems, like Ultrix 4.0' to Ultrix 4.2. + +Wed Jul 28 15:26:53 1993 Roland H. Pesch (pesch@el_bosque.cygnus.com) + + * h8-cfg.texi, all-cfg.texi: new flag GDBSERVER + + * Makefile.in: depend on remote.texi rather than gdbinv-s.texi + + * remote.texi: (Server) New node on gdbserver. (Remote Serial, + ST2000 Remote, MIPS Remote): mention `host:port' syntax for TCP. + + * remote.texi: new name for former gdbinv-s.texi + + * gdb.texinfo: use remote.texi rather than gdbinv-s.texi + +Wed Jul 28 08:26:24 1993 Ian Lance Taylor (ian@cygnus.com) + + * gdbinv-s.texi: Documented timeout and retransmit-timeout + variables for MIPS remote debugging protocol. + +Mon Jul 26 13:00:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): FORTRAN LOGICAL fix. + +Tue Jul 20 16:30:41 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * Makefile.in (refcard.dvi): Use srcdir where necessary. + +Mon Jul 19 12:02:50 1993 Roland H. Pesch (pesch@cygnus.com) + + * gdb.texinfo: repair conditional bugs in text markup + +Fri Jul 16 18:57:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, all-cfg.texi, h8-cfg.texi: introduce MOD2 switch + to select Modula-2 material. + +Thu Jul 15 13:15:01 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Cleanups regarding statics. + + * gdbinv-s.texi (Bootstrapping): Document exceptionHandler. + (Debug Session): Mention exceptionHandler. Add xref to Bootstrapping. + +Mon Jul 12 13:37:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: N_MAIN is sometimes used for C. + +Fri Jul 9 09:47:02 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdbint.texinfo (Host, Target Conditionals): Remove TM_FILE_OVERRIDE. + +Tue Jul 6 12:41:28 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo (Target Conditionals): Remove NO_TYPEDEFS, + removed from the code by Kingdon. + +Tue Jul 6 12:24:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Break Commands): Remove stuff about flushing terminal + input when evaluating breakpoint conditions; the bug has been fixed. + + * gdb.texinfo (Continuing and Stepping): Argument to "continue" + sets the ignore count to N-1, not to N. + +Thu Jul 1 14:57:42 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * refcard.tex (\hoffset): correct longstanding error to match + intended offset; avoids cutting off edge on some printers + +Wed Jun 30 18:23:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Parameters): Say that order of stabs is significant. + +Fri Jun 25 21:34:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Common Blocks): Say what Sun FORTRAN does. + +Fri Jun 25 16:15:10 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * Makefile.in: (REFEDITS) new var to control whether PS or CM + fonts and whether US or A4 paper for GDB refcard; (refcard.dvi) + collect sed edits if any, apply to refcard before formatting; + (refcard.ps) stop implying PS fonts if PS output requested; + (lrefcard.ps) delete extra target for variant PS fonts + + * refcard.tex: parametrize papersize dependent info, collect + in easily replaced spot + + * a4rc.sed: new file, edits to refcard for A4 paper + +Fri Jun 25 14:21:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Type -16 is 4 bytes. + +Wed Jun 23 15:02:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Minor character cleanups. + +Tue Jun 22 16:31:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Express disapproval of 'D' symbol descriptor + politely rather than rudely. + +Fri Jun 18 19:42:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Document common blocks. + +Fri Jun 18 12:12:57 1993 Fred Fish (fnf@cygnus.com) + + * stabs.texinfo: Add some basic info about stabs-in-elf. + +Fri Jun 18 13:57:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Top): Minor cleanup. + +Mon Jun 14 16:16:51 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) + + * Makefile.in (install-info): remove parentdir support + +Tue Jun 15 18:11:39 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo (Copying): delete this node and references to it; + RMS says this manual need not carry GPL. (passim): Improvements + from last round at FSF, largely due to Ian Taylor review, and + minor formatting improvements. + + * gdbinv-s.texi (passim): Improvements from last round at FSF, + largely due to Ian Taylor review. (Debug Session): minor edits to + new text. + +Sun Jun 13 12:52:39 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (realclean): Remove info and dvi files too. + +Sat Jun 12 16:09:22 1993 Jim Kingdon (kingdon@cygnus.com) + + * {all,h8}-config.texi: Rename to *-cfg.texi for 14 char filenames. + * Makefile.in: Change accordingly. gdb-config.texi -> gdb-cfg.texi. + * gdb.texinfo: Change accordingly. + + * stabs.texinfo: Clean up N_{L,R}BRAC. Discuss what addresses of + N_{L,R}BRAC,N_SLINE are relative to. + +Fri Jun 11 15:15:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (GDBvn.texi): Update atomically. + +Wed Jun 9 10:58:16 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdbinv-s.texi (Debug Session): Document exceptionHook. + +Tue Jun 8 13:42:04 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdb.texinfo (Print Settings): Move all stuff relating to symbolic + addresses together. Also motivate the set print symbol-filename + command and suggest other solutions. + +Tue Jun 1 22:46:43 1993 Fred Fish (fnf@cygnus.com) + + * gdb.texinfo (set print elements): Note that the number of + elements is set to unlimited by "set print elements 0". + +Mon May 31 08:06:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Builtin Type Descriptors): Try to clarify what + NF_LDOUBLE means. + (Stab Types): Include Solaris stab types. + (Procedures): Document Solaris extensions. + +Thu May 27 06:20:42 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdb.texinfo: Add `set print symbol-filename' doc. + +Wed May 26 00:26:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Arrays): Talk about type definition vs. type + information. + + * stabs.texinfo (Builtin Type Descriptors): Talk about omitting + the trailing semicolon. + +Tue May 25 14:49:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Line Numbers, Source Files): Re-write these two nodes + and merge in other parts of the document addressing these subjects. + gdbint.texinfo (XCOFF): Remove info which is now in stabs.texinfo. + + * stabs.texinfo (Subranges, Arrays): Try to explain about the semicolon + at the end of a range type. + + * stabs.texinfo (Subranges): "A offset" and "T offset" are not + AIX extensions. + +Mon May 24 09:00:33 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs Format): Misc fixes. + +Sat May 22 10:40:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Constants): Allow an `e' constant to be non-enum. + (Traditional builtin types): Document convex convention for long long. + (Negative builtin types): Discuss type names, and misc fixes. + +Fri May 21 11:20:31 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Builtin Type Descriptors): Document the floating + point types used with @samp{R} type descriptor. + (Symbol Descriptors): Describe how to handle conflict between + different meanings of @samp{P} symbol descriptor. + +Thu May 20 13:35:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Remove node Quick Reference and put its children + directly under the main menu. + + * stabs.texinfo: Many more changes to bring it into line with + AIX documentation and reality. I think it now has all the + information from the AIX documentation, except that I burned + out when I got to variant records (Pascal and Modula-2) and + all the COBOL types. Oh well, we can add them later when we're + worrying more about those languages. + + * stabs.texinfo (Automatic variables): Talk about what it means + to omit the symbol descriptor. + +Tue May 18 17:59:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Parameters): Add "(sometimes)" when describing + gcc2 behavior with promoted args. + +Fri May 14 21:35:29 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: include readline appendices in info version of manual + +Fri May 7 11:56:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.texi (Remote Serial): describe new ^C behavior in + target remote. + + * gdb.texinfo (Machine Code): more index entries for disassemble + +Fri May 7 10:12:30 1993 Fred Fish (fnf@cygnus.com) + + * Clarify the intended use of the gdb-testers and gdb-patches + mailing lists, and shrink gzip comment. + +Thu May 6 16:39:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo (Shell Commands): do not mention SHELL env var in + DOSHOST configuration of manual. + + * gdb.texinfo (MIPS Stack): new node. + + * all-config.texi (MIPS) new switch. + + * gdbinv-s.texi (Nindy Options) Remove two instances of future + tense; (MIPS Remote) new node. + + * gdb.texinfo (passim) rephrases to work around makeinfo @value + bug; (Environment) less passive, other small cleanups in text about + .cshrc/.bashrc; (Invoking GDB) new MIPS Remote menu entry; + (Remote) new MIPS Remote menu entry. + +Thu Apr 29 09:36:25 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo: Many changes to include information from the + AIX documentation. + + * gdb.texinfo (Environment): Mention pitfall with .cshrc. + +Tue Apr 27 14:02:57 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdbint.texinfo (new node Debugging GDB, elsewhere): + Move a bunch of information from ../README. + (Getting Started): New node. + +Fri Apr 23 17:21:13 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.texi, gdb.texinfo: include Hitachi SH target + + * gdb.texinfo: advance manual revision dates to present + + * gdbinv-s.texi, gdb.texinfo, all-config.texi, h8-config.texi: + stop using silly Roman numerals in @set variable names + +Fri Apr 23 07:30:01 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Parameters): Keep trying to get this right. + +Wed Apr 21 15:18:47 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Parameters): More on "local parameters". + +Mon Apr 19 08:00:51 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Parameters): Re-do "local parameters" section. + +Sun Apr 18 09:47:45 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Symbol descriptors): Re-do using @table and @xref. + (Parameters): Rewrite. + (xcoff-differences, Sun-differences): Minor changes. + +Thu Apr 15 02:35:24 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * stabs.texinfo: Minor cleanup. + +Wed Apr 14 17:31:00 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdbint.texinfo: Minor xcoff stuff. + +Wed Apr 7 14:11:07 1993 Fred Fish (fnf@cygnus.com) + + * gdbint.texinfo: Update for new config directory structure. + Add info about internal type data structures. + +Mon Apr 5 09:06:30 1993 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in (SFILES_INCLUDED): gdb-config.texi is no longer in + $(srcdir). + (gdb-config.texi): Depend on file in $(srcdir). + +Fri Apr 2 16:55:13 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo: Fixes about N_SO. + +Fri Mar 26 18:00:35 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: include list of nonstandard init file names + + * *-config.texi: new switch GENERIC for text that applies *only* + to (usual) multiple-target version of manual + + * gdb.texinfo, gdbinv-s.texi: Update conditional markup to correct + h8 config + + * gdb.texinfo: depend on latest fixed makeinfo, use conditionals + in menus (rather than conditionally selected multiple alternative + menus). + + * Makefile.in: define and use DOC_CONFIG var to select + configuration for GDB user manual. + + * gdb-config.texi: delete from repository, generate from Makefile. + + * all-config.texi: normal `generic' configuration file, formerly + stored as gdb-config.texi + +Wed Mar 24 14:03:19 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) + + * Makefile.in: add dvi target to build all .dvi files + +Tue Mar 23 16:03:24 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, gdvinv-s.texinfo: formatting improvements. + +Fri Mar 19 21:46:50 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Doc NO_MMALLOC and NO_MMALLOC_CHECK as + host conditionals. + * stabs.texinfo: More array fixes inspired by Jim's. + +Fri Mar 19 10:23:34 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo: Fixes re arrays and continuations. + + * gdbint.texinfo: Add XCOFF node. + +Mon Mar 8 15:52:18 1993 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo: Add `set print max-symbolic-offset' doc. + +Sun Feb 21 17:09:38 1993 Per Bothner (bothner@rtl.cygnus.com) + + * stabs.texinfo: Fix for array types to mention lower bounds. + +Thu Feb 18 01:19:49 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Update PTRACE_ARG3_TYPE doc, pull PT_*. + +Wed Feb 17 08:15:24 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Remove SET_STACK_LIMIT_HUGE from target defines. + +Thu Feb 11 10:38:40 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Fix thinko (NM_FILE => NAT_FILE). Found + by Michael Ben-Gershon . + +Wed Feb 10 23:59:19 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Eliminate IBM6000_HOST, document IBM6000_TARGET. + +Tue Feb 9 18:26:21 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, gdbinv-s.texi: misc updates + +Sat Feb 6 10:25:47 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Brief documentation for longjmp support, + from an email msg by Stu. + +Fri Feb 5 14:10:15 1993 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Fix description of floating point "range" + types (which really define basic types). Reported by Jim Meehan, + . + + * gdbint.texinfo: Remove COFF_NO_LONG_FILE_NAMES define, now gone. + +Thu Feb 4 13:56:46 1993 Ian Lance Taylor (ian@cygnus.com) + + * gdbint.texinfo: Slightly expand section on supporting a new + object file format. + +Thu Feb 4 01:49:04 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (refcard.ps, lrefcard.ps): Remove psref.tex + intermediate file. + +Tue Feb 2 12:18:06 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, gdbinv-s.texi: miscellaneous stylistic cleanups + +Mon Feb 1 15:35:47 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.texi: z8000 simulator target name is just "sim" + + * gdbinv-s.texi: Mention that Z8000 simulator can simulate Z8001 + as well as Z8002. + +Sat Nov 28 06:51:35 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Add sections on clean design and on how to send + in changes. + +Mon Nov 9 23:57:02 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Add how to declare the result of make_cleanup. + +Mon Oct 26 11:09:47 1992 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo: Fix typo, reported by Karl Berry. + +Fri Oct 23 00:41:21 1992 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo: Add opcodes dir to GDB distribution description. + +Sat Oct 10 18:04:58 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * gdbint.texinfo: fixed a stray email address (needs @@), + added @table @code to node "Native Conditionals" + +Tue Sep 22 00:34:15 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Describe coding style of GDB. + +Mon Sep 21 19:32:16 1992 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Minor wording changes. + +Tue Sep 15 02:57:09 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Improve release doc slightly. + +Fri Sep 11 01:34:25 1992 John Gilmore (gnu@sphagnum.cygnus.com) + + * gdbint.texinfo: Improve doc of GDB config macros. + +Wed Sep 9 16:52:06 1992 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Remove Bothner's changes for C++ nested types. + These will be reinserted when examined. + +Mon Aug 24 01:17:55 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Make a start at documenting all the #if macros + in GDB. At least list them all, and start separating them into + host-specific and target-specific. + +Tue Aug 18 15:59:13 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.m4.in: refrain from using @cartouche for just a few + examples (not consistent w others). + gdb.texinfo: issue disclaimer paragraph on cmdline options only + for generic vn of doc + +Tue Aug 18 14:53:27 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: always create installation directories. + +Tue Aug 18 14:11:50 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: in h8 config, do not describe searching commands. + +Mon Aug 17 18:07:59 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, none.m4, h8.m4, gdbinv-s.m4.in: improve H8/300 + conditionals; introduce a few generic switches that may be + useful for other cross-dev or dos-hosted configs. + + * gdb.texinfo: fix typo in "info reg" description + +Sun Aug 16 01:16:18 1992 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Minor updates from running TeX over it. + * Makefile.in (stabs.dvi, stabs.ps): Add. + +Sat Aug 15 20:52:24 1992 Per Bothner (bothner@rtl.cygnus.com) + + * stabs.texinfo: Stabs documentation, written by Julia Menapace. + First pass at converting it to texinfo. + +Sat Aug 15 03:14:59 1992 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo, refcard.tex: Document mult args on `info reg'. + * Makefile.in (refcard.ps, lrefcard.ps): Add missing $(srdir). + +Fri Aug 14 21:08:47 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Add section on partial symbol tables. + +Sat Jun 20 16:31:10 1992 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: document `set remotedebug' and `set + rstack_high_address'. + +Thu May 14 17:09:48 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: slight expansion of new text on reading info files + * gdbinv-s.m4.in: correct and expand info on cross-debugging + H8/300 from DOS. + +Tue May 12 12:22:47 1992 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: `info user' => `show user'. Noticed by David Taylor. + +Mon May 11 19:06:27 1992 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: Say how to read the `info' files. + +Tue May 5 12:11:38 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in: gm4 -> m4. + +Fri Apr 10 17:50:43 1992 John Gilmore (gnu at rtl.cygnus.com) + + * gdb.texinfo: Update for GDB-4.5. Move `Formatting + Documentation' ahead of `Installing GDB' to match README. + Update shared library doc, -readnow and -mapped, and directory + structure (add glob and mmalloc). Update configure doc. + +Tue Mar 24 23:28:38 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in: remove $(srcdir) from gdb.info rule. + +Sat Mar 7 18:44:50 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * Makefile.in: commented out gdb-all.texinfo rule. This is + temporary. + +Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in, configure.in: removed traces of namesubdir, + -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced + copyrights to '92, changed some from Cygnus to FSF. + +Fri Dec 13 09:47:31 1991 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: Improve how we ask for bug reports. + +Tue Dec 10 04:07:21 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: infodir belongs in datadir. + +Fri Dec 6 23:57:34 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: remove spaces following hyphens, bsd make can't + cope. install using INSTALL_DATA. added clean-info. added + standards.text support. + +Thu Dec 5 22:46:12 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: idestdir and ddestdir go away. Added copyrights + and shift gpl to v2. Added ChangeLog if it didn't exist. docdir + and mandir now keyed off datadir by default. + + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/gnu/usr.bin/gdb/doc/Makefile b/gnu/usr.bin/gdb/doc/Makefile new file mode 100644 index 00000000000..8cde5d4b535 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/Makefile @@ -0,0 +1,340 @@ +# This file was generated automatically by configure. Do not edit. +VPATH = . +links = +host_alias = i386-unknown-freebsd +host_cpu = i386 +host_vendor = unknown +host_os = freebsd +host_canonical = i386-unknown-freebsd +target_alias = i386-unknown-freebsd +target_cpu = i386 +target_vendor = unknown +target_os = freebsd +target_canonical = i386-unknown-freebsd +##Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +# Makefile for GDB documentation. +# 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. + +srcdir = . + +prefix = /usr/gnu + +infodir = $(prefix)/info + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +# main GDB source directory +gdbdir = $(srcdir)/.. + +# where to find texinfo; GDB dist should include a recent one +TEXIDIR=${gdbdir}/../texinfo + +# where to find makeinfo, preferably one designed for texinfo-2 +MAKEINFO=makeinfo + +# where to find texi2roff, ditto +TEXI2ROFF=texi2roff + +# Where is the source dir for the READLINE library doc? +# Traditionally readline is in .. or . +READLINE_DIR = ${gdbdir}/../readline/doc + +SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS + +# There may be alternate predefined collections of switches to configure +# the GDB manual. Normally this is not done in synch with the software +# config system, since this choice tends to be independent; most people +# want a doc config of `all' for a generic manual, regardless of sw config. +DOC_CONFIG = all + +# This list of sed edits will edit the GDB reference card +# for what fonts and what papersize to use. +# By default (NO edits applied), the refcard uses: +# - Computer Modern (CM) fonts +# - US letter paper (8.5x11in) +# List some of the following files for alternative fonts and paper: +# a4rc.sed use A4 paper (297 x 210 mm) +# psrc.sed use PostScript fonts (Karl Berry short TeX names) +# lpsrc.sed use PostScript fonts (full PostScript names in TeX) +# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed +# for A4, CM fonts: REFEDITS = a4rc.sed +# for US, PS fonts: REFEDITS = psrc.sed +# for default: +REFEDITS = + +# Don Knuth's TeX formatter +TEX = tex + +# auxiliary program for sorting Texinfo indices +TEXINDEX = texindex + +# Main GDB manual's source files +SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi + +SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED) + +SFILES_DOC = $(SFILES_LOCAL) \ + $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi + +#### Host, target, and site specific Makefile fragments come in here. +### + +all install: + +info: gdb.info gdbint.info stabs.info +dvi: gdb.dvi refcard.dvi gdbint.dvi +all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi + +install-info: info + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +STAGESTUFF = *.info* gdb-all.texi GDBvn.texi + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) stage1 + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) stage2 + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) stage3 + +against=stage2 + +comparison: force + for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done + +de-stage1: force + -(cd stage1 ; mv -f * ..) + -rmdir stage1 + +de-stage2: force + -(cd stage2 ; mv -f * ..) + -rmdir stage2 + +de-stage3: force + -(cd stage3 ; mv -f * ..) + -rmdir stage3 + +clean-info: + rm -f gdb.info* gdbint.info* stabs.info* + +clean-dvi: + rm -f gdb.dvi refcard.dvi gdbint.dvi stabs.dvi sedref.dvi + +mostlyclean: clean-info clean-dvi + rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me + rm -f links2roff + rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~ + rm -f gdbint.?? gdbint.??? stabs.?? stabs.??? + +clean: mostlyclean + rm -f GDBvn.texi rluser.texinfo inc-hist.texi + +distclean: clean + rm -f Makefile config.status + +realclean: distclean clean-dvi clean-info + +# GDB QUICK REFERENCE (dvi output) +refcard.dvi : refcard.tex $(REFEDITS) + if [ -z "$(REFEDITS)" ]; then \ + cp $(srcdir)/refcard.tex sedref.tex ; \ + else \ + echo > tmp.sed ; \ + for f in "$(REFEDITS)" ; do \ + cat $(srcdir)/$$f >>tmp.sed ; done ; \ + sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \ + fi + $(SET_TEXINPUTS) $(TEX) sedref.tex + mv sedref.dvi refcard.dvi + rm -f sedref.log sedref.tex tmp.sed + +refcard.ps : refcard.dvi + dvips -t landscape refcard.dvi -o + +# File to record current GDB version number (copied from main dir Makefile.in) +GDBvn.texi : ${gdbdir}/Makefile.in + echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new + mv GDBvn.new GDBvn.texi + +# Updated atomically +.PRECIOUS: GDBvn.texi + +# Choose configuration for GDB manual (normally `all'; normally not tied into +# `configure' script because most users prefer generic version of manual, +# not one for their binary config---which may not be specifically +# defined anyways). +gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi + ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \ + ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \ + cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi + +# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear +# If your texinfo or makeinfo don't support these, get a new texinfo release +# +# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make. +# Note that we can *generate* GDBvn.texi, but since we distribute one in the +# source directory for the benefit of people who *don't* use this makefile, +# VPATH will often tell make not to bother building it, because the one +# in the srcdir is up to date. (if not, then make should build one here). + +# GDB MANUAL: TeX dvi file +gdb.dvi: ${SFILES_DOC} + if [ ! -f ./GDBvn.texi ]; then \ + ln -s $(srcdir)/GDBvn.texi . || \ + ln $(srcdir)/GDBvn.texi . || \ + cp $(srcdir)/GDBvn.texi . ; else true; fi + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + $(TEXINDEX) gdb.?? + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s + +# GDB MANUAL: info file +# We're using texinfo2, and older makeinfo's may not be able to +# cope with all the markup. +gdb.info: ${SFILES_DOC} + $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo + +# GDB MANUAL: roff translations +# Try to use a recent texi2roff. v2 was put on prep in jan91. +# If you want an index, see texi2roff doc for postprocessing +# and add -i to texi2roff invocations below. +# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete +# corresponding -e lines when later texi2roff's are current) +# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs. +# + @c's deleted explicitly because texi2roff sees texinfo commands in them +# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank +# + @alphaenumerate is ridiculously new, turned into @enumerate + +# texi2roff doesn't have a notion of include dirs, so we have to fake +# it out for gdb manual's include files---but only if not configured +# in main sourcedir. +links2roff: $(SFILES_INCLUDED) + if [ ! -f gdb.texinfo ]; then \ + ln -s $(SFILES_INCLUDED) . || \ + ln $(SFILES_INCLUDED) . || \ + cp $(SFILES_INCLUDED) . ; \ + fi + touch links2roff + +# "Readline" appendices. Get them also due to lack of includes, +# regardless of whether or not configuring in main sourcedir. +# @ftable removed due to bug in texi2roff-2; if your texi2roff +# is newer, try just ln or cp +rluser.texinfo: ${READLINE_DIR}/rluser.texinfo + sed -e 's/^@ftable/@table/g' \ + -e 's/^@end ftable/@end table/g' \ + ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo + +inc-hist.texi: ${READLINE_DIR}/inc-hist.texi + ln -s ${READLINE_DIR}/inc-hist.texi . || \ + ln ${READLINE_DIR}/inc-hist.texi . || \ + cp ${READLINE_DIR}/inc-hist.texi . + +# gdb manual suitable for [gtn]roff -me +gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -me | \ + sed -e 's/---/\\(em/g' \ + >gdb.me + +# gdb manual suitable for [gtn]roff -ms +gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -ms | \ + sed -e 's/---/\\(em/g' \ + >gdb.ms + +# gdb manual suitable for [tn]roff -mm +# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer, +# try leaving them in +gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e '/@noindent/d' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -mm | \ + sed -e 's/---/\\(em/g' \ + >gdb.mm + +# GDB INTERNALS MANUAL: TeX dvi file +gdbint.dvi : gdbint.texinfo + $(SET_TEXINPUTS) $(TEX) gdbint.texinfo + $(TEXINDEX) gdbint.?? + $(SET_TEXINPUTS) $(TEX) gdbint.texinfo + rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \ + gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs + +# GDB INTERNALS MANUAL: info file +gdb-internals: gdbint.info + +gdbint.info: gdbint.texinfo + $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo + +stabs.info: stabs.texinfo + $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo + +# STABS DOCUMENTATION: TeX dvi file +stabs.dvi : stabs.texinfo + $(SET_TEXINPUTS) $(TEX) stabs.texinfo + $(TEXINDEX) stabs.?? + $(SET_TEXINPUTS) $(TEX) stabs.texinfo + rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \ + stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs + +stabs.ps: stabs.dvi + dvips -o stabs.ps stabs + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status diff --git a/gnu/usr.bin/gdb/doc/Makefile.in b/gnu/usr.bin/gdb/doc/Makefile.in new file mode 100644 index 00000000000..d5ae2904f70 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/Makefile.in @@ -0,0 +1,327 @@ +##Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +# Makefile for GDB documentation. +# 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. + +srcdir = . + +prefix = /usr/local + +infodir = $(prefix)/info + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +# main GDB source directory +gdbdir = $(srcdir)/.. + +# where to find texinfo; GDB dist should include a recent one +TEXIDIR=${gdbdir}/../texinfo + +# where to find makeinfo, preferably one designed for texinfo-2 +MAKEINFO=makeinfo + +# where to find texi2roff, ditto +TEXI2ROFF=texi2roff + +# Where is the source dir for the READLINE library doc? +# Traditionally readline is in .. or . +READLINE_DIR = ${gdbdir}/../readline/doc + +SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS + +# There may be alternate predefined collections of switches to configure +# the GDB manual. Normally this is not done in synch with the software +# config system, since this choice tends to be independent; most people +# want a doc config of `all' for a generic manual, regardless of sw config. +DOC_CONFIG = all + +# This list of sed edits will edit the GDB reference card +# for what fonts and what papersize to use. +# By default (NO edits applied), the refcard uses: +# - Computer Modern (CM) fonts +# - US letter paper (8.5x11in) +# List some of the following files for alternative fonts and paper: +# a4rc.sed use A4 paper (297 x 210 mm) +# psrc.sed use PostScript fonts (Karl Berry short TeX names) +# lpsrc.sed use PostScript fonts (full PostScript names in TeX) +# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed +# for A4, CM fonts: REFEDITS = a4rc.sed +# for US, PS fonts: REFEDITS = psrc.sed +# for default: +REFEDITS = + +# Don Knuth's TeX formatter +TEX = tex + +# auxiliary program for sorting Texinfo indices +TEXINDEX = texindex + +# Main GDB manual's source files +SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi + +SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED) + +SFILES_DOC = $(SFILES_LOCAL) \ + $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi + +#### Host, target, and site specific Makefile fragments come in here. +### + +all install: + +info: gdb.info gdbint.info stabs.info +dvi: gdb.dvi refcard.dvi gdbint.dvi +all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi + +install-info: info + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +STAGESTUFF = *.info* gdb-all.texi GDBvn.texi + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) stage1 + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) stage2 + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) stage3 + +against=stage2 + +comparison: force + for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done + +de-stage1: force + -(cd stage1 ; mv -f * ..) + -rmdir stage1 + +de-stage2: force + -(cd stage2 ; mv -f * ..) + -rmdir stage2 + +de-stage3: force + -(cd stage3 ; mv -f * ..) + -rmdir stage3 + +clean-info: + rm -f gdb.info* gdbint.info* stabs.info* + +clean-dvi: + rm -f gdb.dvi refcard.dvi gdbint.dvi stabs.dvi sedref.dvi + +mostlyclean: clean-info clean-dvi + rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me + rm -f links2roff + rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~ + rm -f gdbint.?? gdbint.??? stabs.?? stabs.??? + +clean: mostlyclean + rm -f GDBvn.texi rluser.texinfo inc-hist.texi + +distclean: clean + rm -f Makefile config.status + +realclean: distclean clean-dvi clean-info + +# GDB QUICK REFERENCE (dvi output) +refcard.dvi : refcard.tex $(REFEDITS) + if [ -z "$(REFEDITS)" ]; then \ + cp $(srcdir)/refcard.tex sedref.tex ; \ + else \ + echo > tmp.sed ; \ + for f in "$(REFEDITS)" ; do \ + cat $(srcdir)/$$f >>tmp.sed ; done ; \ + sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \ + fi + $(SET_TEXINPUTS) $(TEX) sedref.tex + mv sedref.dvi refcard.dvi + rm -f sedref.log sedref.tex tmp.sed + +refcard.ps : refcard.dvi + dvips -t landscape refcard.dvi -o + +# File to record current GDB version number (copied from main dir Makefile.in) +GDBvn.texi : ${gdbdir}/Makefile.in + echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new + mv GDBvn.new GDBvn.texi + +# Updated atomically +.PRECIOUS: GDBvn.texi + +# Choose configuration for GDB manual (normally `all'; normally not tied into +# `configure' script because most users prefer generic version of manual, +# not one for their binary config---which may not be specifically +# defined anyways). +gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi + ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \ + ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \ + cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi + +# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear +# If your texinfo or makeinfo don't support these, get a new texinfo release +# +# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make. +# Note that we can *generate* GDBvn.texi, but since we distribute one in the +# source directory for the benefit of people who *don't* use this makefile, +# VPATH will often tell make not to bother building it, because the one +# in the srcdir is up to date. (if not, then make should build one here). + +# GDB MANUAL: TeX dvi file +gdb.dvi: ${SFILES_DOC} + if [ ! -f ./GDBvn.texi ]; then \ + ln -s $(srcdir)/GDBvn.texi . || \ + ln $(srcdir)/GDBvn.texi . || \ + cp $(srcdir)/GDBvn.texi . ; else true; fi + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + $(TEXINDEX) gdb.?? + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s + +# GDB MANUAL: info file +# We're using texinfo2, and older makeinfo's may not be able to +# cope with all the markup. +gdb.info: ${SFILES_DOC} + $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo + +# GDB MANUAL: roff translations +# Try to use a recent texi2roff. v2 was put on prep in jan91. +# If you want an index, see texi2roff doc for postprocessing +# and add -i to texi2roff invocations below. +# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete +# corresponding -e lines when later texi2roff's are current) +# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs. +# + @c's deleted explicitly because texi2roff sees texinfo commands in them +# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank +# + @alphaenumerate is ridiculously new, turned into @enumerate + +# texi2roff doesn't have a notion of include dirs, so we have to fake +# it out for gdb manual's include files---but only if not configured +# in main sourcedir. +links2roff: $(SFILES_INCLUDED) + if [ ! -f gdb.texinfo ]; then \ + ln -s $(SFILES_INCLUDED) . || \ + ln $(SFILES_INCLUDED) . || \ + cp $(SFILES_INCLUDED) . ; \ + fi + touch links2roff + +# "Readline" appendices. Get them also due to lack of includes, +# regardless of whether or not configuring in main sourcedir. +# @ftable removed due to bug in texi2roff-2; if your texi2roff +# is newer, try just ln or cp +rluser.texinfo: ${READLINE_DIR}/rluser.texinfo + sed -e 's/^@ftable/@table/g' \ + -e 's/^@end ftable/@end table/g' \ + ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo + +inc-hist.texi: ${READLINE_DIR}/inc-hist.texi + ln -s ${READLINE_DIR}/inc-hist.texi . || \ + ln ${READLINE_DIR}/inc-hist.texi . || \ + cp ${READLINE_DIR}/inc-hist.texi . + +# gdb manual suitable for [gtn]roff -me +gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -me | \ + sed -e 's/---/\\(em/g' \ + >gdb.me + +# gdb manual suitable for [gtn]roff -ms +gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -ms | \ + sed -e 's/---/\\(em/g' \ + >gdb.ms + +# gdb manual suitable for [tn]roff -mm +# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer, +# try leaving them in +gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e '/@noindent/d' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -mm | \ + sed -e 's/---/\\(em/g' \ + >gdb.mm + +# GDB INTERNALS MANUAL: TeX dvi file +gdbint.dvi : gdbint.texinfo + $(SET_TEXINPUTS) $(TEX) gdbint.texinfo + $(TEXINDEX) gdbint.?? + $(SET_TEXINPUTS) $(TEX) gdbint.texinfo + rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \ + gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs + +# GDB INTERNALS MANUAL: info file +gdb-internals: gdbint.info + +gdbint.info: gdbint.texinfo + $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo + +stabs.info: stabs.texinfo + $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo + +# STABS DOCUMENTATION: TeX dvi file +stabs.dvi : stabs.texinfo + $(SET_TEXINPUTS) $(TEX) stabs.texinfo + $(TEXINDEX) stabs.?? + $(SET_TEXINPUTS) $(TEX) stabs.texinfo + rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \ + stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs + +stabs.ps: stabs.dvi + dvips -o stabs.ps stabs + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status diff --git a/gnu/usr.bin/gdb/doc/a4rc.sed b/gnu/usr.bin/gdb/doc/a4rc.sed new file mode 100644 index 00000000000..22922904efc --- /dev/null +++ b/gnu/usr.bin/gdb/doc/a4rc.sed @@ -0,0 +1,11 @@ +/--- Papersize params:/,/--- end papersize params/c\ +%------- Papersize params:\ +%% A4 paper (297x210mm)\ +%%\ +\\totalwidth=297mm % total width of paper\ +\\totalheight=210mm % total height of paper\ +\\hmargin=5mm % horizontal margin width\ +\\vmargin=10mm % vertical margin width\ +\\secskip=.6pc % space between refcard secs\ +\\lskip=1pt % extra skip between \\sec entries\ +%------- end papersize params diff --git a/gnu/usr.bin/gdb/doc/all-cfg.texi b/gnu/usr.bin/gdb/doc/all-cfg.texi new file mode 100644 index 00000000000..ec64da105ed --- /dev/null +++ b/gnu/usr.bin/gdb/doc/all-cfg.texi @@ -0,0 +1,117 @@ +@c GDB MANUAL configuration file. +@c Copyright (c) 1993 Free Software Foundation, Inc. +@c +@c NOTE: While the GDB manual is configurable (by changing these +@c switches), its configuration is ***NOT*** automatically tied in to +@c source configuration---because the authors expect that, save in +@c unusual cases, the most inclusive form of the manual is appropriate +@c no matter how the program itself is configured. +@c +@c The only automatically-varying variable is the GDB version number, +@c which the Makefile rewrites based on the VERSION variable from +@c `../Makefile.in'. +@c +@c GDB version number is recorded in the variable GDBVN +@include GDBvn.texi +@c +@c ---------------------------------------------------------------------- +@c PLATFORM FLAGS: +@set GENERIC +@c +@c Hitachi H8/300 target: +@set H8 +@c Hitachi H8/300 target ONLY: +@clear H8EXCLUSIVE +@c +@c remote MIPS target: +@set MIPS +@c +@c SPARC target: +@set SPARC +@c +@c AMD 29000 target: +@set AMD29K +@c +@c Intel 960 target: +@set I960 +@c +@c Tandem ST2000 (phone switch) target: +@set ST2000 +@c +@c Zilog 8000 target: +@set Z8K +@c +@c Lucid "Energize" environment: +@clear LUCID +@c +@c Wind River Systems VxWorks environment: +@set VXWORKS +@c +@c ---------------------------------------------------------------------- +@c DOC FEATURE FLAGS: +@c +@c Include change-from-old? +@set NOVEL +@c +@c Bare-board target? +@clear BARETARGET +@c +@c Restrict languages discussed to C? +@c This is backward. As time permits, change this to language-specific +@c switches for what to include. +@clear CONLY +@c Discuss Fortran? +@set FORTRAN +@c +@c Discuss Modula 2? +@set MOD2 +@c +@c Specifically for host machine running DOS? +@clear DOSHOST +@c +@c Talk about CPU simulator targets? +@set SIMS +@c +@c Is manual stand-alone, or part of an agglomeration, with overall GPL? +@clear AGGLOMERATION +@c +@c Remote serial line settings of interest? +@set SERIAL +@c +@c Discuss features requiring Posix or similar OS environment? +@set POSIX +@c +@c Discuss remote serial debugging stub? +@set REMOTESTUB +@c +@c Discuss gdbserver? +@set GDBSERVER +@c +@c Refrain from discussing how to configure sw and format doc? +@clear PRECONFIGURED +@c +@c Refrain from referring to unfree publications? +@set FSFDOC +@c +@c ---------------------------------------------------------------------- +@c STRINGS: +@c +@c Name of GDB program. Used also for (gdb) prompt string. +@set GDBP gdb +@c +@c Name of GDB product. Used in running text. +@set GDBN GDB +@c +@c Name of GDB initialization file. +@set GDBINIT .gdbinit +@c +@c Name of host. Should not be used in generic configs, but generic +@c value may catch some flubs. +@set HOST machine specific +@c +@c Name of GCC product +@set NGCC GCC +@c +@c Name of GCC program +@set GCC gcc + diff --git a/gnu/usr.bin/gdb/doc/config.status b/gnu/usr.bin/gdb/doc/config.status new file mode 100755 index 00000000000..5d2c6dd679a --- /dev/null +++ b/gnu/usr.bin/gdb/doc/config.status @@ -0,0 +1,5 @@ +#!/bin/sh +# This file was generated automatically by configure. Do not edit. +# This directory was configured as follows: +../../configure --host=i386-unknown-freebsd --target=i386-unknown-freebsd -norecursion +# diff --git a/gnu/usr.bin/gdb/doc/configure.in b/gnu/usr.bin/gdb/doc/configure.in new file mode 100644 index 00000000000..1d2b47e78cc --- /dev/null +++ b/gnu/usr.bin/gdb/doc/configure.in @@ -0,0 +1,7 @@ +srcname="GDB doc" +srctrigger=gdb.texinfo +# per-host: +# per-target: + +files="" +links="" diff --git a/gnu/usr.bin/gdb/doc/gdb-cfg.texi b/gnu/usr.bin/gdb/doc/gdb-cfg.texi new file mode 100644 index 00000000000..ec64da105ed --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb-cfg.texi @@ -0,0 +1,117 @@ +@c GDB MANUAL configuration file. +@c Copyright (c) 1993 Free Software Foundation, Inc. +@c +@c NOTE: While the GDB manual is configurable (by changing these +@c switches), its configuration is ***NOT*** automatically tied in to +@c source configuration---because the authors expect that, save in +@c unusual cases, the most inclusive form of the manual is appropriate +@c no matter how the program itself is configured. +@c +@c The only automatically-varying variable is the GDB version number, +@c which the Makefile rewrites based on the VERSION variable from +@c `../Makefile.in'. +@c +@c GDB version number is recorded in the variable GDBVN +@include GDBvn.texi +@c +@c ---------------------------------------------------------------------- +@c PLATFORM FLAGS: +@set GENERIC +@c +@c Hitachi H8/300 target: +@set H8 +@c Hitachi H8/300 target ONLY: +@clear H8EXCLUSIVE +@c +@c remote MIPS target: +@set MIPS +@c +@c SPARC target: +@set SPARC +@c +@c AMD 29000 target: +@set AMD29K +@c +@c Intel 960 target: +@set I960 +@c +@c Tandem ST2000 (phone switch) target: +@set ST2000 +@c +@c Zilog 8000 target: +@set Z8K +@c +@c Lucid "Energize" environment: +@clear LUCID +@c +@c Wind River Systems VxWorks environment: +@set VXWORKS +@c +@c ---------------------------------------------------------------------- +@c DOC FEATURE FLAGS: +@c +@c Include change-from-old? +@set NOVEL +@c +@c Bare-board target? +@clear BARETARGET +@c +@c Restrict languages discussed to C? +@c This is backward. As time permits, change this to language-specific +@c switches for what to include. +@clear CONLY +@c Discuss Fortran? +@set FORTRAN +@c +@c Discuss Modula 2? +@set MOD2 +@c +@c Specifically for host machine running DOS? +@clear DOSHOST +@c +@c Talk about CPU simulator targets? +@set SIMS +@c +@c Is manual stand-alone, or part of an agglomeration, with overall GPL? +@clear AGGLOMERATION +@c +@c Remote serial line settings of interest? +@set SERIAL +@c +@c Discuss features requiring Posix or similar OS environment? +@set POSIX +@c +@c Discuss remote serial debugging stub? +@set REMOTESTUB +@c +@c Discuss gdbserver? +@set GDBSERVER +@c +@c Refrain from discussing how to configure sw and format doc? +@clear PRECONFIGURED +@c +@c Refrain from referring to unfree publications? +@set FSFDOC +@c +@c ---------------------------------------------------------------------- +@c STRINGS: +@c +@c Name of GDB program. Used also for (gdb) prompt string. +@set GDBP gdb +@c +@c Name of GDB product. Used in running text. +@set GDBN GDB +@c +@c Name of GDB initialization file. +@set GDBINIT .gdbinit +@c +@c Name of host. Should not be used in generic configs, but generic +@c value may catch some flubs. +@set HOST machine specific +@c +@c Name of GCC product +@set NGCC GCC +@c +@c Name of GCC program +@set GCC gcc + diff --git a/gnu/usr.bin/gdb/doc/gdb.info b/gnu/usr.bin/gdb/doc/gdb.info new file mode 100644 index 00000000000..c32646954b3 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info @@ -0,0 +1,213 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +Indirect: +gdb.info-1: 992 +gdb.info-2: 50863 +gdb.info-3: 98423 +gdb.info-4: 145674 +gdb.info-5: 194815 +gdb.info-6: 244253 +gdb.info-7: 290141 +gdb.info-8: 335234 + +Tag Table: +(Indirect) +Node: Top992 +Node: Summary2561 +Node: Free Software3754 +Node: Contributors4492 +Node: New Features8199 +Node: Sample Session12215 +Node: Invocation19094 +Node: Invoking GDB19559 +Node: File Options21298 +Node: Mode Options24476 +Node: Quitting GDB26641 +Node: Shell Commands27359 +Node: Commands28106 +Node: Command Syntax28739 +Node: Completion30598 +Node: Help34666 +Node: Running38442 +Node: Compilation39426 +Node: Starting41224 +Node: Arguments44411 +Node: Environment45412 +Node: Working Directory48518 +Node: Input/Output49258 +Node: Attach50863 +Node: Kill Process53122 +Node: Process Information54097 +Node: Stopping55350 +Node: Breakpoints56423 +Node: Set Breaks58622 +Node: Set Watchpoints65221 +Node: Exception Handling66051 +Node: Delete Breaks68610 +Node: Disabling70238 +Node: Conditions72881 +Node: Break Commands77378 +Node: Breakpoint Menus80225 +Node: Error in Breakpoints81935 +Node: Continuing and Stepping82839 +Node: Signals89318 +Node: Stack92940 +Node: Frames94414 +Node: Backtrace96691 +Node: Selection98423 +Node: Frame Info100917 +Node: MIPS Stack102984 +Node: Source103857 +Node: List104806 +Node: Search108286 +Node: Source Path109085 +Node: Machine Code111763 +Node: Data114236 +Node: Expressions116111 +Node: Variables117793 +Node: Arrays120314 +Node: Output Formats122397 +Node: Memory124456 +Node: Auto Display128727 +Node: Print Settings132474 +Node: Value History140630 +Node: Convenience Vars143017 +Node: Registers145674 +Node: Floating Point Hardware150276 +Node: Languages150781 +Node: Setting151949 +Node: Manually152483 +Node: Automatically153663 +Node: Show154980 +Node: Checks155888 +Node: Type Checking157244 +Node: Range Checking159924 +Node: Support162265 +Node: C163185 +Node: C Operators164016 +Node: C Constants168071 +Node: Cplus expressions169974 +Node: C Defaults172597 +Node: C Checks173215 +Node: Debugging C173926 +Node: Debugging C plus plus174404 +Node: Modula-2176416 +Node: M2 Operators177308 +Node: Built-In Func/Proc180308 +Node: M2 Constants183051 +Node: M2 Defaults184640 +Node: Deviations185239 +Node: M2 Checks186330 +Node: M2 Scope187130 +Node: GDB/M2188142 +Node: Symbols189081 +Node: Altering194815 +Node: Assignment195797 +Node: Jumping197907 +Node: Signaling199914 +Node: Returning201034 +Node: Calling202226 +Node: Patching202700 +Node: GDB Files203782 +Node: Files204247 +Node: Symbol Errors214466 +Node: Targets218064 +Node: Active Targets218954 +Node: Target Commands220530 +Node: Remote223904 +Node: Remote Serial225315 +Node: Stub Contents227768 +Node: Bootstrapping229877 +Node: Debug Session233057 +Node: Protocol236218 +Node: Server239069 +Node: i960-Nindy Remote242748 +Node: Nindy Startup243568 +Node: Nindy Options244253 +Node: Nindy Reset245867 +Node: UDI29K Remote246251 +Node: EB29K Remote247172 +Node: Comms (EB29K)248006 +Node: gdb-EB29K251189 +Node: Remote Log252555 +Node: ST2000 Remote253030 +Node: VxWorks Remote254499 +Node: VxWorks Connection256224 +Node: VxWorks Download257150 +Node: VxWorks Attach258886 +Node: Hitachi Remote259281 +Node: MIPS Remote260790 +Node: Simulator262861 +Node: Controlling GDB264351 +Node: Prompt264962 +Node: Editing265571 +Node: History266338 +Node: Screen Size269024 +Node: Numbers270420 +Node: Messages/Warnings271538 +Node: Sequences274587 +Node: Define275147 +Node: Hooks277144 +Node: Command Files278547 +Node: Output280302 +Node: Emacs282714 +Node: GDB Bugs288669 +Node: Bug Criteria289387 +Node: Bug Reporting290141 +Node: Command Line Editing297342 +Node: Introduction and Notation297763 +Node: Readline Interaction298780 +Node: Readline Bare Essentials299914 +Node: Readline Movement Commands301417 +Node: Readline Killing Commands302303 +Node: Readline Arguments303941 +Node: Readline Init File304887 +Node: Readline Init Syntax305708 +Node: Commands For Moving309640 +Node: Commands For History310260 +Node: Commands For Text311330 +Node: Commands For Killing313046 +Node: Numeric Arguments314168 +Node: Commands For Completion314606 +Node: Miscellaneous Commands315325 +Node: Readline Vi Mode316077 +Node: Using History Interactively316784 +Node: History Interaction317141 +Node: Event Designators318189 +Node: Word Designators318828 +Node: Modifiers319724 +Node: Renamed Commands320469 +Node: Formatting Documentation322131 +Node: Installing GDB325465 +Node: Separate Objdir328945 +Node: Config Names331490 +Node: configure Options332918 +Node: Index335234 + +End Tag Table diff --git a/gnu/usr.bin/gdb/doc/gdb.info-1 b/gnu/usr.bin/gdb/doc/gdb.info-1 new file mode 100644 index 00000000000..a1d71201a5c --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-1 @@ -0,0 +1,1304 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Top, Next: Summary, Prev: (DIR), Up: (DIR) + +Debugging with GDB +****************** + + This file describes GDB, the GNU symbolic debugger. + + This is Edition 4.09, August 1993, for GDB Version 4.11. + +* Menu: + +* Summary:: Summary of GDB + +* New Features:: New features since GDB version 3.5 + +* Sample Session:: A sample GDB session + +* Invocation:: Getting in and out of GDB +* Commands:: GDB commands +* Running:: Running programs under GDB +* Stopping:: Stopping and continuing +* Stack:: Examining the stack +* Source:: Examining source files +* Data:: Examining data + +* Languages:: Using GDB with different languages + + +* Symbols:: Examining the symbol table +* Altering:: Altering execution +* GDB Files:: GDB files +* Targets:: Specifying a debugging target +* Controlling GDB:: Controlling GDB +* Sequences:: Canned sequences of commands + +* Emacs:: Using GDB under GNU Emacs + +* GDB Bugs:: Reporting bugs in GDB +* Command Line Editing:: Facilities of the readline library +* Using History Interactively:: + +* Renamed Commands:: + +* Formatting Documentation:: How to format and print GDB documentation +* Installing GDB:: Installing GDB + +* Index:: Index + + +File: gdb.info, Node: Summary, Next: New Features, Prev: Top, Up: Top + +Summary of GDB +************** + + The purpose of a debugger such as GDB is to allow you to see what is +going on "inside" another program while it executes--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: + + * Start your program, specifying anything that might affect its + behavior. + + * Make your program stop on specified conditions. + + * Examine what has happened, when your program has stopped. + + * Change things in your program, so you can experiment with + correcting the effects of one bug and go on to learn about another. + + You can use GDB to debug programs written in C, C++, and Modula-2. +G{No Value For "DBN"} can be used to debug programs written in Fortran, +although it does not yet support entering expressions, printing values, +etc. using Fortran syntax. It may be necessary to refer to some +variables with a trailing underscore. + +* Menu: + +* Free Software:: Freely redistributable software +* Contributors:: Contributors to GDB + + +File: gdb.info, Node: Free Software, Next: Contributors, Up: Summary + +Free software +============= + + GDB is "free software", protected by the GNU General Public License +(GPL). The GPL gives you the freedom to copy or adapt a licensed +program--but every person getting a copy also gets with it the freedom +to modify that copy (which means that they must get access to the +source code), and the freedom to distribute further copies. Typical +software companies use copyrights to limit your freedoms; the Free +Software Foundation uses the GPL to preserve these freedoms. + + Fundamentally, the General Public License is a license which says +that you have these freedoms and that you cannot take these freedoms +away from anyone else. + + +File: gdb.info, Node: Contributors, Prev: Free Software, Up: Summary + +Contributors to GDB +=================== + + Richard Stallman was the original author of GDB, and of many other +GNU programs. Many others have contributed to its development. This +section attempts to credit major contributors. One of the virtues of +free software is that everyone is free to contribute to it; with +regret, we cannot actually acknowledge everyone here. The file +`ChangeLog' in the GDB distribution approximates a blow-by-blow account. + + Changes much prior to version 2.0 are lost in the mists of time. + + *Plea:* Additions to this section are particularly welcome. If you + or your friends (or enemies, to be evenhanded) have been unfairly + omitted from this list, we would like to add your names! + + So that they may not regard their long labor as thankless, we +particularly thank those who shepherded GDB through major releases: Fred +Fish (releases 4.11, 4.10, 4.9), Stu Grossman and John Gilmore (releases +4.8, 4.7, 4.6, 4.5, 4.4), John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and +3.9); Jim Kingdon (releases 3.5, 3.4, 3.3); and Randy Smith (releases +3.2, 3.1, 3.0). As major maintainer of GDB for some period, each +contributed significantly to the structure, stability, and capabilities +of the entire debugger. + + Richard Stallman, assisted at various times by Peter TerMaat, Chris +Hanson, and Richard Mlynarik, handled releases through 2.8. + + Michael Tiemann is the author of most of the GNU C++ support in GDB, +with significant additional contributions from Per Bothner. James +Clark wrote the GNU C++ demangler. Early work on C++ was by Peter +TerMaat (who also did much general update work leading to release 3.0). + + GDB 4 uses the BFD subroutine library to examine multiple +object-file formats; BFD was a joint project of David V. +Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore. + + David Johnson wrote the original COFF support; Pace Willison did the +original support for encapsulated COFF. + + Adam de Boor and Bradley Davis contributed the ISI Optimum V support. +Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS +support. Jean-Daniel Fekete contributed Sun 386i support. Chris +Hanson improved the HP9000 support. Noboyuki Hikichi and Tomoyuki +Hasei contributed Sony/News OS 3 support. David Johnson contributed +Encore Umax support. Jyrki Kuoppala contributed Altos 3068 support. +Keith Packard contributed NS32K support. Doug Rabson contributed Acorn +Risc Machine support. Chris Smith contributed Convex support (and +Fortran debugging). Jonathan Stone contributed Pyramid support. +Michael Tiemann contributed SPARC support. Tim Tucker contributed +support for the Gould NP1 and Gould Powernode. Pace Willison +contributed Intel 386 support. Jay Vosburgh contributed Symmetry +support. + + Rich Schaefer and Peter Schauer helped with support of SunOS shared +libraries. + + Jay Fenlason and Roland McGrath ensured that GDB and GAS agree about +several machine instruction sets. + + Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped +develop remote debugging. Intel Corporation and Wind River Systems +contributed remote debugging modules for their products. + + Brian Fox is the author of the readline libraries providing +command-line editing and command history. + + Andrew Beers of SUNY Buffalo wrote the language-switching code, the +Modula-2 support, and contributed the Languages chapter of this manual. + + Fred Fish wrote most of the support for Unix System Vr4. He also +enhanced the command-completion support to cover C++ overloaded symbols. + + Hitachi America, Ltd. sponsored the support for Hitachi +microprocessors. + + +File: gdb.info, Node: New Features, Next: Sample Session, Prev: Summary, Up: Top + +New Features since GDB Version 3.5 +********************************** + +*Targets* + Using the new command `target', you can select at runtime whether + you are debugging local files, local processes, standalone systems + over a serial port, realtime systems over a TCP/IP connection, + etc. The command `load' can download programs into a remote + system. Serial stubs are available for Motorola 680x0, Intel + 80386, and Sparc remote systems; GDB also supports debugging + realtime processes running under VxWorks, using SunRPC Remote + Procedure Calls over TCP/IP to talk to a debugger stub on the + target system. Internally, GDB now uses a function vector to + mediate access to different targets; if you need to add your own + support for a remote protocol, this makes it much easier. + +*Watchpoints* + GDB now sports watchpoints as well as breakpoints. You can use a + watchpoint to stop execution whenever the value of an expression + changes, without having to predict a particular place in your + program where this may happen. + +*Wide Output* + Commands that issue wide output now insert newlines at places + designed to make the output more readable. + +*Object Code Formats* + GDB uses a new library called the Binary File Descriptor (BFD) + Library to permit it to switch dynamically, without + reconfiguration or recompilation, between different object-file + formats. Formats currently supported are COFF, ELF, a.out, Intel + 960 b.out, MIPS ECOFF, HPPA SOM (with stabs debugging), and + S-records; files may be read as .o files, archive libraries, or + core dumps. BFD is available as a subroutine library so that + other programs may take advantage of it, and the other GNU binary + utilities are being converted to use it. + +*Configuration and Ports* + Compile-time configuration (to select a particular architecture and + operating system) is much easier. The script `configure' now + allows you to configure GDB as either a native debugger or a + cross-debugger. *Note Installing GDB::, for details on how to + configure. + +*Interaction* + The user interface to the GDB control variables is simpler, and is + consolidated in two commands, `set' and `show'. Output lines are + now broken at readable places, rather than overflowing onto the + next line. You can suppress output of machine-level addresses, + displaying only source language information. + +*C++* + GDB now supports C++ multiple inheritance (if used with a GCC + version 2 compiler), and also has limited support for C++ exception + handling, with the commands `catch' and `info catch': GDB can + break when an exception is raised, before the stack is peeled back + to the exception handler's context. + +*Modula-2* + GDB now has preliminary support for the GNU Modula-2 compiler, + currently under development at the State University of New York at + Buffalo. Coordinated development of both GDB and the GNU Modula-2 + compiler will continue. Other Modula-2 compilers are currently + not supported, and attempting to debug programs compiled with them + will likely result in an error as the symbol table of the + executable is read in. + +*Command Rationalization* + Many GDB commands have been renamed to make them easier to remember + and use. In particular, the subcommands of `info' and + `show'/`set' are grouped to make the former refer to the state of + your program, and the latter refer to the state of GDB itself. + *Note Renamed Commands::, for details on what commands were + renamed. + +*Shared Libraries* + GDB 4 can debug programs and core files that use SunOS, SVR4, or + IBM RS/6000 shared libraries. + +*Reference Card* + GDB 4 has a reference card. *Note Formatting the Documentation: + Formatting Documentation, for instructions about how to print it. + + +File: gdb.info, Node: Sample Session, Next: Invocation, Prev: New Features, Up: Top + +A Sample GDB Session +******************** + + You can use this manual at your leisure to read all about GDB. +However, a handful of commands are enough to get started using the +debugger. This chapter illustrates those commands. + + One of the preliminary versions of GNU `m4' (a generic macro +processor) exhibits the following bug: sometimes, when we change its +quote strings from the default, the commands used to capture one macro +definition within another stop working. In the following short `m4' +session, we define a macro `foo' which expands to `0000'; we then use +the `m4' built-in `defn' to define `bar' as the same thing. However, +when we change the open quote string to `' and the close quote +string to `', the same procedure fails to define a new synonym +`baz': + + $ cd gnu/m4 + $ ./m4 + define(foo,0000) + + foo + 0000 + define(bar,defn(`foo')) + + bar + 0000 + changequote(,) + + define(baz,defn(foo)) + baz + C-d + m4: End of input: 0: fatal error: EOF in string + +Let us use GDB to try to see what is going on. + + $ gdb m4 + GDB is free software and you are welcome to distribute copies + of it under certain conditions; type "show copying" to see + the conditions. + There is absolutely no warranty for GDB; type "show warranty" + for details. + GDB 4.11, Copyright 1993 Free Software Foundation, Inc... + (gdb) + +GDB reads only enough symbol data to know where to find the rest when +needed; as a result, the first prompt comes up very quickly. We now +tell GDB to use a narrower display width than usual, so that examples +will fit in this manual. + + (gdb) set width 70 + +We need to see how the `m4' built-in `changequote' works. Having +looked at the source, we know the relevant subroutine is +`m4_changequote', so we set a breakpoint there with the GDB `break' +command. + + (gdb) break m4_changequote + Breakpoint 1 at 0x62f4: file builtin.c, line 879. + +Using the `run' command, we start `m4' running under GDB control; as +long as control does not reach the `m4_changequote' subroutine, the +program runs as usual: + + (gdb) run + Starting program: /work/Editorial/gdb/gnu/m4/m4 + define(foo,0000) + + foo + 0000 + +To trigger the breakpoint, we call `changequote'. GDB suspends +execution of `m4', displaying information about the context where it +stops. + + changequote(,) + + Breakpoint 1, m4_changequote (argc=3, argv=0x33c70) + at builtin.c:879 + 879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3)) + +Now we use the command `n' (`next') to advance execution to the next +line of the current function. + + (gdb) n + 882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\ + : nil, + +`set_quotes' looks like a promising subroutine. We can go into it by +using the command `s' (`step') instead of `next'. `step' goes to the +next line to be executed in *any* subroutine, so it steps into +`set_quotes'. + + (gdb) s + set_quotes (lq=0x34c78 "", rq=0x34c88 "") + at input.c:530 + 530 if (lquote != def_lquote) + +The display that shows the subroutine where `m4' is now suspended (and +its arguments) is called a stack frame display. It shows a summary of +the stack. We can use the `backtrace' command (which can also be +spelled `bt'), to see where we are in the stack as a whole: the +`backtrace' command displays a stack frame for each active subroutine. + + (gdb) bt + #0 set_quotes (lq=0x34c78 "", rq=0x34c88 "") + at input.c:530 + #1 0x6344 in m4_changequote (argc=3, argv=0x33c70) + at builtin.c:882 + #2 0x8174 in expand_macro (sym=0x33320) at macro.c:242 + #3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30) + at macro.c:71 + #4 0x79dc in expand_input () at macro.c:40 + #5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195 + +We will step through a few more lines to see what happens. The first +two times, we can use `s'; the next two times we use `n' to avoid +falling into the `xstrdup' subroutine. + + (gdb) s + 0x3b5c 532 if (rquote != def_rquote) + (gdb) s + 0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \ + def_lquote : xstrdup(lq); + (gdb) n + 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ + : xstrdup(rq); + (gdb) n + 538 len_lquote = strlen(rquote); + +The last line displayed looks a little odd; we can examine the variables +`lquote' and `rquote' to see if they are in fact the new left and right +quotes we specified. We use the command `p' (`print') to see their +values. + + (gdb) p lquote + $1 = 0x35d40 "" + (gdb) p rquote + $2 = 0x35d50 "" + +`lquote' and `rquote' are indeed the new left and right quotes. To +look at some context, we can display ten lines of source surrounding +the current line with the `l' (`list') command. + + (gdb) l + 533 xfree(rquote); + 534 + 535 lquote = (lq == nil || *lq == '\0') ? def_lquote\ + : xstrdup (lq); + 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ + : xstrdup (rq); + 537 + 538 len_lquote = strlen(rquote); + 539 len_rquote = strlen(lquote); + 540 } + 541 + 542 void + +Let us step past the two lines that set `len_lquote' and `len_rquote', +and then examine the values of those variables. + + (gdb) n + 539 len_rquote = strlen(lquote); + (gdb) n + 540 } + (gdb) p len_lquote + $3 = 9 + (gdb) p len_rquote + $4 = 7 + +That certainly looks wrong, assuming `len_lquote' and `len_rquote' are +meant to be the lengths of `lquote' and `rquote' respectively. We can +set them to better values using the `p' command, since it can print the +value of any expression--and that expression can include subroutine +calls and assignments. + + (gdb) p len_lquote=strlen(lquote) + $5 = 7 + (gdb) p len_rquote=strlen(rquote) + $6 = 9 + +Is that enough to fix the problem of using the new quotes with the `m4' +built-in `defn'? We can allow `m4' to continue executing with the `c' +(`continue') command, and then try the example that caused trouble +initially: + + (gdb) c + Continuing. + + define(baz,defn(foo)) + + baz + 0000 + +Success! The new quotes now work just as well as the default ones. The +problem seems to have been just the two typos defining the wrong +lengths. We allow `m4' exit by giving it an EOF as input: + + C-d + Program exited normally. + +The message `Program exited normally.' is from GDB; it indicates `m4' +has finished executing. We can end our GDB session with the GDB `quit' +command. + + (gdb) quit + + +File: gdb.info, Node: Invocation, Next: Commands, Prev: Sample Session, Up: Top + +Getting In and Out of GDB +************************* + + This chapter discusses how to start GDB, and how to get out of it. +(The essentials: type `gdb' to start GDB, and type `quit' or `C-d' to +exit.) + +* Menu: + +* Invoking GDB:: How to start GDB +* Quitting GDB:: How to quit GDB +* Shell Commands:: How to use shell commands inside GDB + + +File: gdb.info, Node: Invoking GDB, Next: Quitting GDB, Up: Invocation + +Invoking GDB +============ + + Invoke GDB by running the program `gdb'. Once started, GDB reads +commands from the terminal until you tell it to exit. + + You can also run `gdb' with a variety of arguments and options, to +specify more of your debugging environment at the outset. + + The command-line options described here are designed to cover a +variety of situations; in some environments, some of these options may +effectively be unavailable. + + The most usual way to start GDB is with one argument, specifying an +executable program: + + gdb PROGRAM + +You can also start with both an executable program and a core file +specified: + + gdb PROGRAM CORE + + You can, instead, specify a process ID as a second argument, if you +want to debug a running process: + + gdb PROGRAM 1234 + +would attach GDB to process `1234' (unless you also have a file named +`1234'; GDB does check for a core file first). + + Taking advantage of the second command-line argument requires a +fairly complete operating system; when you use GDB as a remote debugger +attached to a bare board, there may not be any notion of "process", and +there is often no way to get a core dump. + +You can further control how GDB starts up by using command-line +options. GDB itself can remind you of the options available. + +Type + + gdb -help + +to display all available options and briefly describe their use (`gdb +-h' is a shorter equivalent). + + All options and command line arguments you give are processed in +sequential order. The order makes a difference when the `-x' option is +used. + +* Menu: + + + +* File Options:: Choosing files +* Mode Options:: Choosing modes + + +File: gdb.info, Node: File Options, Next: Mode Options, Up: Invoking GDB + +Choosing files +-------------- + + When GDB starts, it reads any arguments other than options as +specifying an executable file and core file (or process ID). This is +the same as if the arguments were specified by the `-se' and `-c' +options respectively. (GDB reads the first argument that does not have +an associated option flag as equivalent to the `-se' option followed by +that argument; and the second argument that does not have an associated +option flag, if any, as equivalent to the `-c' option followed by that +argument.) + + Many options have both long and short forms; both are shown in the +following list. GDB also recognizes the long forms 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 `--' rather than +`-', though we illustrate the more usual convention.) + +`-symbols FILE' +`-s FILE' + Read symbol table from file FILE. + +`-exec FILE' +`-e FILE' + Use file FILE as the executable file to execute when appropriate, + and for examining pure data in conjunction with a core dump. + +`-se FILE' + Read symbol table from file FILE and use it as the executable file. + +`-core FILE' +`-c FILE' + Use file FILE as a core dump to examine. + +`-c NUMBER' + Connect to process ID NUMBER, as with the `attach' command (unless + there is a file in core-dump format named NUMBER, in which case + `-c' specifies that file as a core dump to read). + +`-command FILE' +`-x FILE' + Execute GDB commands from file FILE. *Note Command files: Command + Files. + +`-directory DIRECTORY' +`-d DIRECTORY' + Add DIRECTORY to the path to search for source files. + +`-m' +`-mapped' + *Warning: this option depends on operating system facilities that + are not supported on all systems.* + If memory-mapped files are available on your system through the + `mmap' system call, you can use this option to have GDB write the + symbols from your program into a reusable file in the current + directory. If the program you are debugging is called + `/tmp/fred', the mapped symbol file will be `./fred.syms'. Future + GDB debugging sessions will notice the presence of this file, and + will quickly map in symbol information from it, rather than reading + the symbol table from the executable program. + + The `.syms' file is specific to the host machine where GDB is run. + It holds an exact image of the internal GDB symbol table. It + cannot be shared across multiple host platforms. + +`-r' +`-readnow' + Read each symbol file's entire symbol table immediately, rather + than the default, which is to read it incrementally as it is + needed. This makes startup slower, but makes future operations + faster. + + The `-mapped' and `-readnow' options are typically combined in order +to build a `.syms' file that contains complete symbol information. +(*Note Commands to specify files: Files, for information on `.syms' +files.) A simple GDB invocation to do nothing but build a `.syms' file +for future use is: + + gdb -batch -nx -mapped -readnow programname + + +File: gdb.info, Node: Mode Options, Prev: File Options, Up: Invoking GDB + +Choosing modes +-------------- + + You can run GDB in various alternative modes--for example, in batch +mode or quiet mode. + +`-nx' +`-n' + Do not execute commands from any initialization files (normally + called `.gdbinit'). Normally, the commands in these files are + executed after all the command options and arguments have been + processed. *Note Command files: Command Files. + +`-quiet' +`-q' + "Quiet". Do not print the introductory and copyright messages. + These messages are also suppressed in batch mode. + +`-batch' + Run in batch mode. Exit with status `0' after processing all the + command files specified with `-x' (and all commands from + initialization files, if not inhibited with `-n'). 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 + + Program exited normally. + + (which is ordinarily issued whenever a program running under GDB + control terminates) is not issued when running in batch mode. + +`-cd DIRECTORY' + Run GDB using DIRECTORY as its working directory, instead of the + current directory. + +`-fullname' +`-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 your program stops). This recognizable format + looks like two `\032' 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 `\032' characters + as a signal to display the source code for the frame. + +`-b BPS' + Set the line speed (baud rate or bits per second) of any serial + interface used by GDB for remote debugging. + +`-tty DEVICE' + Run using DEVICE for your program's standard input and output. + + +File: gdb.info, Node: Quitting GDB, Next: Shell Commands, Prev: Invoking GDB, Up: Invocation + +Quitting GDB +============ + +`quit' + To exit GDB, use the `quit' command (abbreviated `q'), or type an + end-of-file character (usually `C-d'). + + An interrupt (often `C-c') will not exit from GDB, but rather will +terminate the action of any GDB command that is in progress and return +to GDB command level. It is safe to type the interrupt character at +any time because GDB does not allow it to take effect until a time when +it is safe. + + If you have been using GDB to control an attached process or device, +you can release it with the `detach' command (*note Debugging an +already-running process: Attach.). + + +File: gdb.info, Node: Shell Commands, Prev: Quitting GDB, Up: Invocation + +Shell commands +============== + + If you need to execute occasional shell commands during your +debugging session, there is no need to leave or suspend GDB; you can +just use the `shell' command. + +`shell COMMAND STRING' + Invoke a the standard shell to execute COMMAND STRING. If it + exists, the environment variable `SHELL' determines which shell to + run. Otherwise GDB uses `/bin/sh'. + + The utility `make' is often needed in development environments. You +do not have to use the `shell' command for this purpose in GDB: + +`make MAKE-ARGS' + Execute the `make' program with the specified arguments. This is + equivalent to `shell make MAKE-ARGS'. + + +File: gdb.info, Node: Commands, Next: Running, Prev: Invocation, Up: Top + +GDB Commands +************ + + You can abbreviate a GDB command to the first few letters of the +command name, if that abbreviation is unambiguous; and you can repeat +certain GDB commands by typing just RET. You can also use the TAB key +to get GDB to fill out the rest of a word in a command (or to show you +the alternatives available, if there is more than one possibility). + +* Menu: + +* Command Syntax:: How to give commands to GDB +* Completion:: Command completion +* Help:: How to ask GDB for help + + +File: gdb.info, Node: Command Syntax, Next: Completion, Up: Commands + +Command syntax +============== + + A GDB command is a single line of input. There is no limit on how +long it can be. It starts with a command name, which is followed by +arguments whose meaning depends on the command name. For example, the +command `step' accepts an argument which is the number of times to +step, as in `step 5'. You can also use the `step' command with no +arguments. Some command names do not allow any arguments. + + GDB command names may always be truncated if that abbreviation is +unambiguous. Other possible command abbreviations are listed in the +documentation for individual commands. In some cases, even ambiguous +abbreviations are allowed; for example, `s' is specially defined as +equivalent to `step' even though there are other commands whose names +start with `s'. You can test abbreviations by using them as arguments +to the `help' command. + + A blank line as input to GDB (typing just RET) means to repeat the +previous command. Certain commands (for example, `run') will not repeat +this way; these are commands for which unintentional repetition might +cause trouble and which you are unlikely to want to repeat. + + The `list' and `x' commands, when you repeat them with RET, +construct new arguments rather than repeating exactly as typed. This +permits easy scanning of source or memory. + + GDB can also use RET in another way: to partition lengthy output, in +a way similar to the common utility `more' (*note Screen size: Screen +Size.). Since it is easy to press one RET too many in this situation, +GDB disables command repetition after any command that generates this +sort of display. + + Any text from a `#' to the end of the line is a comment; it does +nothing. This is useful mainly in command files (*note Command files: +Command Files.). + + +File: gdb.info, Node: Completion, Next: Help, Prev: Command Syntax, Up: Commands + +Command completion +================== + + GDB can fill in the rest of a word in a command for you, if there is +only one possibility; it can also show you what the valid possibilities +are for the next word in a command, at any time. This works for GDB +commands, GDB subcommands, and the names of symbols in your program. + + Press the TAB key whenever you want GDB to fill out the rest of a +word. If there is only one possibility, GDB will fill in the word, and +wait for you to finish the command (or press RET to enter it). For +example, if you type + + (gdb) info bre TAB + +GDB fills in the rest of the word `breakpoints', since that is the only +`info' subcommand beginning with `bre': + + (gdb) info breakpoints + +You can either press RET at this point, to run the `info breakpoints' +command, or backspace and enter something else, if `breakpoints' does +not look like the command you expected. (If you were sure you wanted +`info breakpoints' in the first place, you might as well just type RET +immediately after `info bre', to exploit command abbreviations rather +than command completion). + + If there is more than one possibility for the next word when you +press TAB, GDB will sound a bell. You can either supply more +characters and try again, or just press TAB a second time, and GDB will +display all the possible completions for that word. For example, you +might want to set a breakpoint on a subroutine whose name begins with +`make_', but when you type `b make_TAB' GDB just sounds the bell. +Typing TAB again will display all the function names in your program +that begin with those characters, for example: + + (gdb) b make_ TAB +GDB sounds bell; press TAB again, to see: + make_a_section_from_file make_environ + make_abs_section make_function_type + make_blockvector make_pointer_type + make_cleanup make_reference_type + make_command make_symbol_completion_list + (gdb) b make_ + +After displaying the available possibilities, GDB copies your partial +input (`b make_' in the example) so you can finish the command. + + If you just want to see the list of alternatives in the first place, +you can press `M-?' rather than pressing TAB twice. `M-?' means `META +?'. You can type this either by holding down a key designated as the +META shift on your keyboard (if there is one) while typing `?', or as +ESC followed by `?'. + + Sometimes the string you need, while logically a "word", may contain +parentheses or other characters that GDB normally excludes from its +notion of a word. To permit word completion to work in this situation, +you may enclose words in `'' (single quote marks) in GDB commands. + + The most likely situation where you might need this is in typing the +name of a C++ function. This is because C++ allows function overloading +(multiple definitions of the same function, distinguished by argument +type). For example, when you want to set a breakpoint you may need to +distinguish whether you mean the version of `name' that takes an `int' +parameter, `name(int)', or the version that takes a `float' parameter, +`name(float)'. To use the word-completion facilities in this +situation, type a single quote `'' at the beginning of the function +name. This alerts GDB that it may need to consider more information +than usual when you press TAB or `M-?' to request word completion: + + (gdb) b 'bubble( M-? + bubble(double,double) bubble(int,int) + (gdb) b 'bubble( + + In some cases, GDB can tell that completing a name will require +quotes. When this happens, GDB will insert the quote for you (while +completing as much as it can) if you do not type the quote in the first +place: + + (gdb) b bub TAB +GDB alters your input line to the following, and rings a bell: + (gdb) b 'bubble( + +In general, GDB can tell that a quote is needed (and inserts it) if you +have not yet started typing the argument list when you ask for +completion on an overloaded symbol. + + +File: gdb.info, Node: Help, Prev: Completion, Up: Commands + +Getting help +============ + + You can always ask GDB itself for information on its commands, using +the command `help'. + +`help' +`h' + You can use `help' (abbreviated `h') with no arguments to display + a short list of named classes of commands: + + (gdb) help + List of classes of commands: + + running -- Running the program + stack -- Examining the stack + data -- Examining data + breakpoints -- Making program stop at certain points + files -- Specifying and examining files + status -- Status inquiries + support -- Support facilities + user-defined -- User-defined commands + aliases -- Aliases of other commands + obscure -- Obscure features + + Type "help" followed by a class name for a list of + commands in that class. + Type "help" followed by command name for full + documentation. + Command name abbreviations are allowed if unambiguous. + (gdb) + +`help CLASS' + Using one of the general help classes as an argument, you can get a + list of the individual commands in that class. For example, here + is the help display for the class `status': + + (gdb) help status + Status inquiries. + + List of commands: + + show -- Generic command for showing things set + with "set" + info -- Generic command for printing status + + Type "help" followed by command name for full + documentation. + Command name abbreviations are allowed if unambiguous. + (gdb) + +`help COMMAND' + With a command name as `help' argument, GDB will display a short + paragraph on how to use that command. + + In addition to `help', you can use the GDB commands `info' and +`show' to inquire about the state of your program, or the state of GDB +itself. Each command supports many topics of inquiry; this manual +introduces each of them in the appropriate context. The listings under +`info' and under `show' in the Index point to all the sub-commands. +*Note Index::. + +`info' + This command (abbreviated `i') is for describing the state of your + program. For example, you can list the arguments given to your + program with `info args', list the registers currently in use with + `info registers', or list the breakpoints you have set with `info + breakpoints'. You can get a complete list of the `info' + sub-commands with `help info'. + +`show' + In contrast, `show' is for describing the state of GDB itself. + You can change most of the things you can `show', by using the + related command `set'; for example, you can control what number + system is used for displays with `set radix', or simply inquire + which is currently in use with `show radix'. + + To display all the settable parameters and their current values, + you can use `show' with no arguments; you may also use `info set'. + Both commands produce the same display. + + Here are three miscellaneous `show' subcommands, all of which are +exceptional in lacking corresponding `set' commands: + +`show version' + Show what version of GDB is running. You should include this + information in GDB bug-reports. If multiple versions of GDB are in + use at your site, you may occasionally want to determine which + version of GDB you are running; as GDB evolves, new commands are + introduced, and old ones may wither away. The version number is + also announced when you start GDB. + +`show copying' + Display information about permission for copying GDB. + +`show warranty' + Display the GNU "NO WARRANTY" statement. + + +File: gdb.info, Node: Running, Next: Stopping, Prev: Commands, Up: Top + +Running Programs Under GDB +************************** + + When you run a program under GDB, you must first generate debugging +information when you compile it. You may start it with its arguments, +if any, in an environment of your choice. You may redirect your +program's input and output, debug an already running process, or kill a +child process. + +* Menu: + +* Compilation:: Compiling for debugging +* Starting:: Starting your program + +* Arguments:: Your program's arguments +* Environment:: Your program's environment +* Working Directory:: Your program's working directory +* Input/Output:: Your program's input and output +* Attach:: Debugging an already-running process +* Kill Process:: Killing the child process +* Process Information:: Additional process information + + +File: gdb.info, Node: Compilation, Next: Starting, Up: Running + +Compiling for debugging +======================= + + In order to debug a program effectively, you need to generate +debugging information when you compile it. This debugging information +is stored in the object file; it describes the data type of each +variable or function and the correspondence between source line numbers +and addresses in the executable code. + + To request debugging information, specify the `-g' option when you +run the compiler. + + Many C compilers are unable to handle the `-g' and `-O' options +together. Using those compilers, you cannot generate optimized +executables containing debugging information. + + GCC, the GNU C compiler, supports `-g' with or without `-O', making +it possible to debug optimized code. We recommend that you *always* +use `-g' whenever you compile a program. You may think your program is +correct, but there is no sense in pushing your luck. + + When you debug a program compiled with `-g -O', remember that the +optimizer is rearranging your code; the debugger will show you what is +really there. Do not be too surprised when the execution path does not +exactly match your source file! An extreme example: if you define a +variable, but never use it, GDB will never see that variable--because +the compiler optimizes it out of existence. + + Some things do not work as well with `-g -O' as with just `-g', +particularly on machines with instruction scheduling. If in doubt, +recompile with `-g' alone, and if this fixes the problem, please report +it as a bug (including a test case!). + + Older versions of the GNU C compiler permitted a variant option +`-gg' for debugging information. GDB no longer supports this format; +if your GNU C compiler has this option, do not use it. + + +File: gdb.info, Node: Starting, Next: Arguments, Prev: Compilation, Up: Running + +Starting your program +===================== + +`run' +`r' + Use the `run' command to start your program under GDB. You must + first specify the program name (except on VxWorks) with an + argument to GDB (*note Getting In and Out of GDB: Invocation.), or + by using the `file' or `exec-file' command (*note Commands to + specify files: Files.). + + If you are running your program in an execution environment that +supports processes, `run' creates an inferior process and makes that +process run your program. (In environments without processes, `run' +jumps to the start of your program.) + + The execution of a program is affected by certain information it +receives from its superior. GDB provides ways to specify this +information, which you must do *before* starting your program. (You +can change it after starting your program, but such changes will only +affect your program the next time you start it.) This information may +be divided into four categories: + +The *arguments.* + Specify the arguments to give your program as the arguments of the + `run' command. If a shell is available on your target, the shell + is used to pass the arguments, so that you may use normal + conventions (such as wildcard expansion or variable substitution) + in describing the arguments. In Unix systems, you can control + which shell is used with the `SHELL' environment variable. *Note + Your program's arguments: Arguments. + +The *environment.* + Your program normally inherits its environment from GDB, but you + can use the GDB commands `set environment' and `unset environment' + to change parts of the environment that will be given to your + program. *Note Your program's environment: Environment. + +The *working directory.* + Your program inherits its working directory from GDB. You can set + the GDB working directory with the `cd' command in GDB. *Note + Your program's working directory: Working Directory. + +The *standard input and output.* + Your program normally uses the same device for standard input and + standard output as GDB is using. You can redirect input and output + in the `run' command line, or you can use the `tty' command to set + a different device for your program. *Note Your program's input + and output: Input/Output. + + *Warning:* While input and output redirection work, you cannot use + pipes to pass the output of the program you are debugging to + another program; if you attempt this, GDB is likely to wind up + debugging the wrong program. + + When you issue the `run' command, your program begins to execute +immediately. *Note Stopping and continuing: Stopping, for discussion +of how to arrange for your program to stop. Once your program has +stopped, you may call functions in your program, using the `print' or +`call' commands. *Note Examining Data: Data. + + If the modification time of your symbol file has changed since the +last time GDB read its symbols, GDB will discard its symbol table and +re-read it. When it does this, GDB tries to retain your current +breakpoints. + + +File: gdb.info, Node: Arguments, Next: Environment, Prev: Starting, Up: Running + +Your program's arguments +======================== + + The arguments to your program can be specified by the arguments of +the `run' command. They are passed to a shell, which expands wildcard +characters and performs redirection of I/O, and thence to your program. +Your `SHELL' environment variable (if it exists) specifies what shell +GDB if you do not define `SHELL', GDB uses `/bin/sh'. + + `run' with no arguments uses the same arguments used by the previous +`run', or those set by the `set args' command. + +`set args' + Specify the arguments to be used the next time your program is + run. If `set args' has no arguments, `run' will execute your + program with no arguments. Once you have run your program with + arguments, using `set args' before the next `run' is the only way + to run it again without arguments. + +`show args' + Show the arguments to give your program when it is started. + + +File: gdb.info, Node: Environment, Next: Working Directory, Prev: Arguments, Up: Running + +Your program's environment +========================== + + The "environment" consists of a set of environment variables and +their values. Environment variables conventionally record such things +as your user name, your home directory, your terminal type, and your +search path for programs to run. Usually you set up environment +variables with the shell and they are inherited by all the other +programs you run. When debugging, it can be useful to try running your +program with a modified environment without having to start GDB over +again. + +`path DIRECTORY' + Add DIRECTORY to the front of the `PATH' environment variable (the + search path for executables), for both GDB and your program. You + may specify several directory names, separated by `:' or + whitespace. If DIRECTORY is already in the path, it is moved to + the front, so it will be searched sooner. + + You can use the string `$cwd' to refer to whatever is the current + working directory at the time GDB searches the path. If you use + `.' instead, it refers to the directory where you executed the + `path' command. GDB replaces `.' in the DIRECTORY argument (with + the current path) before adding DIRECTORY to the search path. + +`show paths' + Display the list of search paths for executables (the `PATH' + environment variable). + +`show environment [VARNAME]' + Print the value of environment variable VARNAME to be given to + your program when it starts. If you do not supply VARNAME, print + the names and values of all environment variables to be given to + your program. You can abbreviate `environment' as `env'. + +`set environment VARNAME [=] VALUE' + Set environment variable VARNAME to VALUE. The value changes for + your program only, not for GDB itself. VALUE may be any string; + the values of environment variables are just strings, and any + interpretation is supplied by your program itself. The VALUE + parameter is optional; if it is eliminated, the variable is set to + a null value. + + For example, this command: + + set env USER = foo + + tells a Unix program, when subsequently run, that its user is named + `foo'. (The spaces around `=' are used for clarity here; they are + not actually required.) + +`unset environment VARNAME' + Remove variable VARNAME from the environment to be passed to your + program. This is different from `set env VARNAME ='; `unset + environment' removes the variable from the environment, rather + than assigning it an empty value. + + *Warning:* GDB runs your program using the shell indicated by your +`SHELL' environment variable if it exists (or `/bin/sh' if not). If +your `SHELL' variable names a shell that runs an initialization +file--such as `.cshrc' for C-shell, or `.bashrc' for BASH--any +variables you set in that file will affect your program. You may wish +to move setting of environment variables to files that are only run +when you sign on, such as `.login' or `.profile'. + + +File: gdb.info, Node: Working Directory, Next: Input/Output, Prev: Environment, Up: Running + +Your program's working directory +================================ + + Each time you start your program with `run', it inherits its working +directory from the current working directory of GDB. The GDB working +directory is initially whatever it inherited from its parent process +(typically the shell), but you can specify a new working directory in +GDB with the `cd' command. + + The GDB working directory also serves as a default for the commands +that specify files for GDB to operate on. *Note Commands to specify +files: Files. + +`cd DIRECTORY' + Set the GDB working directory to DIRECTORY. + +`pwd' + Print the GDB working directory. + + +File: gdb.info, Node: Input/Output, Next: Attach, Prev: Working Directory, Up: Running + +Your program's input and output +=============================== + + By default, the program you run under GDB does input and output to +the same terminal that GDB uses. GDB switches the terminal to its own +terminal modes to interact with you, but it records the terminal modes +your program was using and switches back to them when you continue +running your program. + +`info terminal' + Displays information recorded by GDB about the terminal modes your + program is using. + + You can redirect your program's input and/or output using shell +redirection with the `run' command. For example, + + run > outfile + +starts your program, diverting its output to the file `outfile'. + + Another way to specify where your program should do input and output +is with the `tty' command. This command accepts a file name as +argument, and causes this file to be the default for future `run' +commands. It also resets the controlling terminal for the child +process, for future `run' commands. For example, + + tty /dev/ttyb + +directs that processes started with subsequent `run' commands default +to do input and output on the terminal `/dev/ttyb' and have that as +their controlling terminal. + + An explicit redirection in `run' overrides the `tty' command's +effect on the input/output device, but not its effect on the controlling +terminal. + + When you use the `tty' command or redirect input in the `run' +command, only the input *for your program* is affected. The input for +GDB still comes from your terminal. + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-2 b/gnu/usr.bin/gdb/doc/gdb.info-2 new file mode 100644 index 00000000000..e8be2fa7d90 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-2 @@ -0,0 +1,1165 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Attach, Next: Kill Process, Prev: Input/Output, Up: Running + +Debugging an already-running process +==================================== + +`attach PROCESS-ID' + This command attaches to a running process--one that was started + outside GDB. (`info files' will show your active targets.) The + command takes as argument a process ID. The usual way to find out + the process-id of a Unix process is with the `ps' utility, or with + the `jobs -l' shell command. + + `attach' will not repeat if you press RET a second time after + executing the command. + + To use `attach', your program must be running in an environment +which supports processes; for example, `attach' does not work for +programs on bare-board targets that lack an operating system. You must +also have permission to send the process a signal. + + When using `attach', you should first use the `file' command to +specify the program running in the process and load its symbol table. +*Note Commands to Specify Files: Files. + + The first thing GDB does after arranging to debug the specified +process is to stop it. You can examine and modify an attached process +with all the GDB commands that are ordinarily available when you start +processes with `run'. You can insert breakpoints; you can step and +continue; you can modify storage. If you would rather the process +continue running, you may use the `continue' command after attaching +GDB to the process. + +`detach' + When you have finished debugging the attached process, you can use + the `detach' command to release it from GDB control. Detaching + the process continues its execution. After the `detach' command, + that process and GDB become completely independent once more, and + you are ready to `attach' another process or start one with `run'. + `detach' will not repeat if you press RET again after executing + the command. + + If you exit GDB or use the `run' command while you have an attached +process, you kill that process. By default, you will be asked for +confirmation if you try to do either of these things; you can control +whether or not you need to confirm by using the `set confirm' command +(*note Optional warnings and messages: Messages/Warnings.). + + +File: gdb.info, Node: Kill Process, Next: Process Information, Prev: Attach, Up: Running + +Killing the child process +========================= + +`kill' + Kill the child process in which your program is running under GDB. + + This command is useful if you wish to debug a core dump instead of a +running process. GDB ignores any core dump file while your program is +running. + + On some operating systems, a program cannot be executed outside GDB +while you have breakpoints set on it inside GDB. You can use the +`kill' command in this situation to permit running your program outside +the debugger. + + The `kill' command is also useful if you wish to recompile and +relink your program, since on many systems it is impossible to modify an +executable file while it is running in a process. In this case, when +you next type `run', GDB will notice that the file has changed, and +will re-read the symbol table (while trying to preserve your current +breakpoint settings). + + +File: gdb.info, Node: Process Information, Prev: Kill Process, Up: Running + +Additional process information +============================== + + Some operating systems provide a facility called `/proc' that can be +used to examine the image of a running process using file-system +subroutines. If GDB is configured for an operating system with this +facility, the command `info proc' is available to report on several +kinds of information about the process running your program. + +`info proc' + Summarize available information about the process. + +`info proc mappings' + Report on the address ranges accessible in the program, with + information on whether your program may read, write, or execute + each range. + +`info proc times' + Starting time, user CPU time, and system CPU time for your program + and its children. + +`info proc id' + Report on the process IDs related to your program: its own process + ID, the ID of its parent, the process group ID, and the session ID. + +`info proc status' + General information on the state of the process. If the process is + stopped, this report includes the reason for stopping, and any + signal received. + +`info proc all' + Show all the above information about the process. + + +File: gdb.info, Node: Stopping, Next: Stack, Prev: Running, Up: Top + +Stopping and Continuing +*********************** + + The principal purposes of using a debugger are so that you can stop +your program before it terminates; or so that, if your program runs into +trouble, you can investigate and find out why. + + Inside GDB, your program may stop for any of several reasons, such as +a signal, a breakpoint, or reaching a new line after a GDB command such +as `step'. You may then examine and change variables, set new +breakpoints or remove old ones, and then continue execution. Usually, +the messages shown by GDB provide ample explanation of the status of +your program--but you can also explicitly request this information at +any time. + +`info program' + Display information about the status of your program: whether it is + running or not, what process it is, and why it stopped. + +* Menu: + + +* Breakpoints:: Breakpoints, watchpoints, and exceptions + + +* Continuing and Stepping:: Resuming execution + +* Signals:: Signals + + +File: gdb.info, Node: Breakpoints, Next: Continuing and Stepping, Up: Stopping + +Breakpoints, watchpoints, and exceptions +======================================== + + A "breakpoint" makes your program stop whenever a certain point in +the program is reached. For each breakpoint, you can add various +conditions to control in finer detail whether your program will stop. +You can set breakpoints with the `break' command and its variants +(*note Setting breakpoints: Set Breaks.), to specify the place where +your program should stop by line number, function name or exact address +in the program. In languages with exception handling (such as GNU +C++), you can also set breakpoints where an exception is raised (*note +Breakpoints and exceptions: Exception Handling.). + + A "watchpoint" is a special breakpoint that stops your program when +the value of an expression changes. You must use a different command +to set watchpoints (*note Setting watchpoints: Set Watchpoints.), but +aside from that, you can manage a watchpoint like any other breakpoint: +you enable, disable, and delete both breakpoints and watchpoints using +the same commands. + + You can arrange to have values from your program displayed +automatically whenever GDB stops at a breakpoint. *Note Automatic +display: Auto Display. + + GDB assigns a number to each breakpoint or watchpoint when you +create it; these numbers are successive integers starting with one. In +many of the commands for controlling various features of breakpoints you +use the breakpoint number to say which breakpoint you want to change. +Each breakpoint may be "enabled" or "disabled"; if disabled, it has no +effect on your program until you enable it again. + +* Menu: + +* Set Breaks:: Setting breakpoints +* Set Watchpoints:: Setting watchpoints + +* Exception Handling:: Breakpoints and exceptions + +* Delete Breaks:: Deleting breakpoints +* Disabling:: Disabling breakpoints +* Conditions:: Break conditions +* Break Commands:: Breakpoint command lists + +* Breakpoint Menus:: Breakpoint menus + +* Error in Breakpoints:: "Cannot insert breakpoints" + + +File: gdb.info, Node: Set Breaks, Next: Set Watchpoints, Up: Breakpoints + +Setting breakpoints +------------------- + + Breakpoints are set with the `break' command (abbreviated `b'). The +debugger convenience variable `$bpnum' records the number of the +beakpoint you've set most recently; see *Note Convenience variables: +Convenience Vars, for a discussion of what you can do with convenience +variables. + + You have several ways to say where the breakpoint should go. + +`break FUNCTION' + Set a breakpoint at entry to function FUNCTION. When using source + languages that permit overloading of symbols, such as C++, + FUNCTION may refer to more than one possible place to break. + *Note Breakpoint menus: Breakpoint Menus, for a discussion of that + situation. + +`break +OFFSET' +`break -OFFSET' + Set a breakpoint some number of lines forward or back from the + position at which execution stopped in the currently selected + frame. + +`break LINENUM' + Set a breakpoint at line LINENUM in the current source file. That + file is the last file whose source text was printed. This + breakpoint will stop your program just before it executes any of + the code on that line. + +`break FILENAME:LINENUM' + Set a breakpoint at line LINENUM in source file FILENAME. + +`break FILENAME:FUNCTION' + Set a breakpoint at entry to function FUNCTION found in file + FILENAME. Specifying a file name as well as a function name is + superfluous except when multiple files contain similarly named + functions. + +`break *ADDRESS' + Set a breakpoint at address ADDRESS. You can use this to set + breakpoints in parts of your program which do not have debugging + information or source files. + +`break' + When called without any arguments, `break' sets a breakpoint at + the next instruction to be executed in the selected stack frame + (*note Examining the Stack: Stack.). In any selected frame but the + innermost, this will cause your program to stop as soon as control + returns to that frame. This is similar to the effect of a + `finish' command in the frame inside the selected frame--except + that `finish' does not leave an active breakpoint. If you use + `break' without an argument in the innermost frame, GDB will stop + the next time it reaches the current location; this may be useful + inside loops. + + GDB normally ignores breakpoints when it resumes execution, until + at least one instruction has been executed. If it did not do + this, you would be unable to proceed past a breakpoint without + first disabling the breakpoint. This rule applies whether or not + the breakpoint already existed when your program stopped. + +`break ... if COND' + Set a breakpoint with condition COND; evaluate the expression COND + each time the breakpoint is reached, and stop only if the value is + nonzero--that is, if COND evaluates as true. `...' stands for one + of the possible arguments described above (or no argument) + specifying where to break. *Note Break conditions: Conditions, + for more information on breakpoint conditions. + +`tbreak ARGS' + Set a breakpoint enabled only for one stop. ARGS are the same as + for the `break' command, and the breakpoint is set in the same + way, but the breakpoint is automatically disabled after the first + time your program stops there. *Note Disabling breakpoints: + Disabling. + +`rbreak REGEX' + Set breakpoints on all functions matching the regular expression + REGEX. This command sets an unconditional breakpoint on all + matches, printing a list of all breakpoints it set. Once these + breakpoints are set, they are treated just like the breakpoints + set with the `break' command. They can be deleted, disabled, made + conditional, etc., in the standard ways. + + When debugging C++ programs, `rbreak' is useful for setting + breakpoints on overloaded functions that are not members of any + special classes. + +`info breakpoints [N]' +`info break [N]' +`info watchpoints [N]' + Print a table of all breakpoints and watchpoints set and not + deleted, with the following columns for each breakpoint: + + *Breakpoint Numbers* + *Type* + Breakpoint or watchpoint. + + *Disposition* + Whether the breakpoint is marked to be disabled or deleted + when hit. + + *Enabled or Disabled* + Enabled breakpoints are marked with `y'. `n' marks + breakpoints that are not enabled. + + *Address* + Where the breakpoint is in your program, as a memory address + + *What* + Where the breakpoint is in the source for your program, as a + file and line number. + + If a breakpoint is conditional, `info break' shows the condition on + the line following the affected breakpoint; breakpoint commands, + if any, are listed after that. + + `info break' with a breakpoint number N as argument lists only + that breakpoint. The convenience variable `$_' and the default + examining-address for the `x' command are set to the address of + the last breakpoint listed (*note Examining memory: Memory.). + + GDB allows you to set any number of breakpoints at the same place in +your program. There is nothing silly or meaningless about this. When +the breakpoints are conditional, this is even useful (*note Break +conditions: Conditions.). + + GDB itself sometimes sets breakpoints in your program for special +purposes, such as proper handling of `longjmp' (in C programs). These +internal breakpoints are assigned negative numbers, starting with `-1'; +`info breakpoints' does not display them. + + You can see these breakpoints with the GDB maintenance command +`maint info breakpoints'. + +`maint info breakpoints' + Using the same format as `info breakpoints', display both the + breakpoints you've set explicitly, and those GDB is using for + internal purposes. Internal breakpoints are shown with negative + breakpoint numbers. The type column identifies what kind of + breakpoint is shown: + + `breakpoint' + Normal, explicitly set breakpoint. + + `watchpoint' + Normal, explicitly set watchpoint. + + `longjmp' + Internal breakpoint, used to handle correctly stepping through + `longjmp' calls. + + `longjmp resume' + Internal breakpoint at the target of a `longjmp'. + + `until' + Temporary internal breakpoint used by the GDB `until' command. + + `finish' + Temporary internal breakpoint used by the GDB `finish' + command. + + +File: gdb.info, Node: Set Watchpoints, Next: Exception Handling, Prev: Set Breaks, Up: Breakpoints + +Setting watchpoints +------------------- + + You can use a watchpoint to stop execution whenever the value of an +expression changes, without having to predict a particular place where +this may happen. + + Watchpoints currently execute two orders of magnitude more slowly +than other breakpoints, but this can be well worth it to catch errors +where you have no clue what part of your program is the culprit. Some +processors provide special hardware to support watchpoint evaluation; +future releases of GDB will use such hardware if it is available. + +`watch EXPR' + Set a watchpoint for an expression. + +`info watchpoints' + This command prints a list of watchpoints and breakpoints; it is + the same as `info break'. + + +File: gdb.info, Node: Exception Handling, Next: Delete Breaks, Prev: Set Watchpoints, Up: Breakpoints + +Breakpoints and exceptions +-------------------------- + + Some languages, such as GNU C++, implement exception handling. You +can use GDB to examine what caused your program to raise an exception, +and to list the exceptions your program is prepared to handle at a +given point in time. + +`catch EXCEPTIONS' + You can set breakpoints at active exception handlers by using the + `catch' command. EXCEPTIONS is a list of names of exceptions to + catch. + + You can use `info catch' to list active exception handlers. *Note +Information about a frame: Frame Info. + + There are currently some limitations to exception handling in GDB. +These will be corrected in a future release. + + * If you call a function interactively, GDB normally returns control + to you when the function has finished executing. If the call + raises an exception, however, the call may bypass the mechanism + that returns control to you and cause your program to simply + continue running until it hits a breakpoint, catches a signal that + GDB is listening for, or exits. + + * You cannot raise an exception interactively. + + * You cannot interactively install an exception handler. + + Sometimes `catch' is not the best way to debug exception handling: +if you need to know exactly where an exception is raised, it is better +to stop *before* the exception handler is called, since that way you +can see the stack before any unwinding takes place. If you set a +breakpoint in an exception handler instead, it may not be easy to find +out where the exception was raised. + + To stop just before an exception handler is called, you need some +knowledge of the implementation. In the case of GNU C++, exceptions are +raised by calling a library function named `__raise_exception' which +has the following ANSI C interface: + + /* ADDR is where the exception identifier is stored. + ID is the exception identifier. */ + void __raise_exception (void **ADDR, void *ID); + +To make the debugger catch all exceptions before any stack unwinding +takes place, set a breakpoint on `__raise_exception' (*note +Breakpoints; watchpoints; and exceptions: Breakpoints.). + + With a conditional breakpoint (*note Break conditions: Conditions.) +that depends on the value of ID, you can stop your program when a +specific exception is raised. You can use multiple conditional +breakpoints to stop your program when any of a number of exceptions are +raised. + + +File: gdb.info, Node: Delete Breaks, Next: Disabling, Prev: Exception Handling, Up: Breakpoints + +Deleting breakpoints +-------------------- + + It is often necessary to eliminate a breakpoint or watchpoint once it +has done its job and you no longer want your program to stop there. +This is called "deleting" the breakpoint. A breakpoint that has been +deleted no longer exists; it is forgotten. + + With the `clear' command you can delete breakpoints according to +where they are in your program. With the `delete' command you can +delete individual breakpoints or watchpoints by specifying their +breakpoint numbers. + + It is not necessary to delete a breakpoint to proceed past it. GDB +automatically ignores breakpoints on the first instruction to be +executed when you continue execution without changing the execution +address. + +`clear' + Delete any breakpoints at the next instruction to be executed in + the selected stack frame (*note Selecting a frame: Selection.). + When the innermost frame is selected, this is a good way to delete + a breakpoint where your program just stopped. + +`clear FUNCTION' +`clear FILENAME:FUNCTION' + Delete any breakpoints set at entry to the function FUNCTION. + +`clear LINENUM' +`clear FILENAME:LINENUM' + Delete any breakpoints set at or within the code of the specified + line. + +`delete [breakpoints] [BNUMS...]' + Delete the breakpoints or watchpoints of the numbers specified as + arguments. If no argument is specified, delete all breakpoints + (GDB asks confirmation, unless you have `set confirm off'). You + can abbreviate this command as `d'. + + +File: gdb.info, Node: Disabling, Next: Conditions, Prev: Delete Breaks, Up: Breakpoints + +Disabling breakpoints +--------------------- + + Rather than deleting a breakpoint or watchpoint, you might prefer to +"disable" it. This makes the breakpoint inoperative as if it had been +deleted, but remembers the information on the breakpoint so that you +can "enable" it again later. + + You disable and enable breakpoints and watchpoints with the `enable' +and `disable' commands, optionally specifying one or more breakpoint +numbers as arguments. Use `info break' or `info watch' to print a list +of breakpoints or watchpoints if you do not know which numbers to use. + + A breakpoint or watchpoint can have any of four different states of +enablement: + + * Enabled. The breakpoint will stop your program. A breakpoint set + with the `break' command starts out in this state. + + * Disabled. The breakpoint has no effect on your program. + + * Enabled once. The breakpoint will stop your program, but when it + does so it will become disabled. A breakpoint set with the + `tbreak' command starts out in this state. + + * Enabled for deletion. The breakpoint will stop your program, but + immediately after it does so it will be deleted permanently. + + You can use the following commands to enable or disable breakpoints +and watchpoints: + +`disable [breakpoints] [BNUMS...]' + Disable the specified breakpoints--or all breakpoints, if none are + listed. A disabled breakpoint has no effect but is not forgotten. + All options such as ignore-counts, conditions and commands are + remembered in case the breakpoint is enabled again later. You may + abbreviate `disable' as `dis'. + +`enable [breakpoints] [BNUMS...]' + Enable the specified breakpoints (or all defined breakpoints). + They become effective once again in stopping your program. + +`enable [breakpoints] once BNUMS...' + Enable the specified breakpoints temporarily. Each will be + disabled again the next time it stops your program. + +`enable [breakpoints] delete BNUMS...' + Enable the specified breakpoints to work once and then die. Each + of the breakpoints will be deleted the next time it stops your + program. + + Save for a breakpoint set with `tbreak' (*note Setting breakpoints: +Set Breaks.), breakpoints that you set are initially enabled; +subsequently, they become disabled or enabled only when you use one of +the commands above. (The command `until' can set and delete a +breakpoint of its own, but it will not change the state of your other +breakpoints; see *Note Continuing and stepping: Continuing and +Stepping.) + + +File: gdb.info, Node: Conditions, Next: Break Commands, Prev: Disabling, Up: Breakpoints + +Break conditions +---------------- + + The simplest sort of breakpoint breaks every time your program +reaches a specified place. You can also specify a "condition" for a +breakpoint. A condition is just a Boolean expression in your +programming language (*note Expressions: Expressions.). A breakpoint +with a condition evaluates the expression each time your program +reaches it, and your program stops only if the condition is *true*. + + This is the converse of using assertions for program validation; in +that situation, you want to stop when the assertion is violated--that +is, when the condition is false. In C, if you want to test an +assertion expressed by the condition ASSERT, you should set the +condition `! ASSERT' on the appropriate breakpoint. + + Conditions are also accepted for watchpoints; you may not need them, +since a watchpoint is inspecting the value of an expression anyhow--but +it might be simpler, say, to just set a watchpoint on a variable name, +and specify a condition that tests whether the new value is an +interesting one. + + Break conditions can have side effects, and may even call functions +in your program. This can be useful, for example, to activate functions +that log program progress, or to use your own print functions to format +special data structures. The effects are completely predictable unless +there is another enabled breakpoint at the same address. (In that +case, GDB might see the other breakpoint first and stop your program +without checking the condition of this one.) Note that breakpoint +commands are usually more convenient and flexible for the purpose of +performing side effects when a breakpoint is reached (*note Breakpoint +command lists: Break Commands.). + + Break conditions can be specified when a breakpoint is set, by using +`if' in the arguments to the `break' command. *Note Setting +breakpoints: Set Breaks. They can also be changed at any time with the +`condition' command. The `watch' command does not recognize the `if' +keyword; `condition' is the only way to impose a further condition on a +watchpoint. + +`condition BNUM EXPRESSION' + Specify EXPRESSION as the break condition for breakpoint or + watchpoint number BNUM. From now on, this breakpoint will stop + your program only if the value of EXPRESSION is true (nonzero, in + C). When you use `condition', GDB checks EXPRESSION immediately + for syntactic correctness, and to determine whether symbols in it + have referents in the context of your breakpoint. GDB does not + actually evaluate EXPRESSION at the time the `condition' command + is given, however. *Note Expressions: Expressions. + +`condition BNUM' + Remove the condition from breakpoint number BNUM. It becomes an + ordinary unconditional breakpoint. + + A special case of a breakpoint condition is to stop only when the +breakpoint has been reached a certain number of times. This is so +useful that there is a special way to do it, using the "ignore count" +of the breakpoint. Every breakpoint has an ignore count, which is an +integer. Most of the time, the ignore count is zero, and therefore has +no effect. But if your program reaches a breakpoint whose ignore count +is positive, then instead of stopping, it just decrements the ignore +count by one and continues. As a result, if the ignore count value is +N, the breakpoint will not stop the next N times it is reached. + +`ignore BNUM COUNT' + Set the ignore count of breakpoint number BNUM to COUNT. The next + COUNT times the breakpoint is reached, your program's execution + will not stop; other than to decrement the ignore count, GDB takes + no action. + + To make the breakpoint stop the next time it is reached, specify a + count of zero. + + When you use `continue' to resume execution of your program from a + breakpoint, you can specify an ignore count directly as an + argument to `continue', rather than using `ignore'. *Note + Continuing and stepping: Continuing and Stepping. + + If a breakpoint has a positive ignore count and a condition, the + condition is not checked. Once the ignore count reaches zero, the + condition will be checked. + + You could achieve the effect of the ignore count with a condition + such as `$foo-- <= 0' using a debugger convenience variable that + is decremented each time. *Note Convenience variables: + Convenience Vars. + + +File: gdb.info, Node: Break Commands, Next: Breakpoint Menus, Prev: Conditions, Up: Breakpoints + +Breakpoint command lists +------------------------ + + You can give any breakpoint (or watchpoint) a series of commands to +execute when your program stops due to that breakpoint. For example, +you might want to print the values of certain expressions, or enable +other breakpoints. + +`commands [BNUM]' +`... COMMAND-LIST ...' +`end' + Specify a list of commands for breakpoint number BNUM. The + commands themselves appear on the following lines. Type a line + containing just `end' to terminate the commands. + + To remove all commands from a breakpoint, type `commands' and + follow it immediately with `end'; that is, give no commands. + + With no BNUM argument, `commands' refers to the last breakpoint or + watchpoint set (not to the breakpoint most recently encountered). + + Pressing RET as a means of repeating the last GDB command is +disabled within a COMMAND-LIST. + + You can use breakpoint commands to start your program up again. +Simply use the `continue' command, or `step', or any other command that +resumes execution. + + Any other commands in the command list, after a command that resumes +execution, are ignored. This is because any time you resume execution +(even with a simple `next' or `step'), you may encounter another +breakpoint--which could have its own command list, leading to +ambiguities about which list to execute. + + If the first command you specify in a command list is `silent', the +usual message about stopping at a breakpoint is not printed. This may +be desirable for breakpoints that are to print a specific message and +then continue. If none of the remaining commands print anything, you +will see no sign that the breakpoint was reached. `silent' is +meaningful only at the beginning of a breakpoint command list. + + The commands `echo', `output', and `printf' allow you to print +precisely controlled output, and are often useful in silent +breakpoints. *Note Commands for controlled output: Output. + + For example, here is how you could use breakpoint commands to print +the value of `x' at entry to `foo' whenever `x' is positive. + + break foo if x>0 + commands + silent + printf "x is %d\n",x + cont + end + + One application for breakpoint commands is to compensate for one bug +so you can test for another. Put a breakpoint just after the erroneous +line of code, give it a condition to detect the case in which something +erroneous has been done, and give it commands to assign correct values +to any variables that need them. End with the `continue' command so +that your program does not stop, and start with the `silent' command so +that no output is produced. Here is an example: + + break 403 + commands + silent + set x = y + 4 + cont + end + + +File: gdb.info, Node: Breakpoint Menus, Next: Error in Breakpoints, Prev: Break Commands, Up: Breakpoints + +Breakpoint menus +---------------- + + Some programming languages (notably C++) permit a single function +name to be defined several times, for application in different contexts. +This is called "overloading". When a function name is overloaded, +`break FUNCTION' is not enough to tell GDB where you want a breakpoint. +If you realize this will be a problem, you can use something like +`break FUNCTION(TYPES)' to specify which particular version of the +function you want. Otherwise, GDB offers you a menu of numbered +choices for different possible breakpoints, and waits for your +selection with the prompt `>'. The first two options are always `[0] +cancel' and `[1] all'. Typing `1' sets a breakpoint at each definition +of FUNCTION, and typing `0' aborts the `break' command without setting +any new breakpoints. + + For example, the following session excerpt shows an attempt to set a +breakpoint at the overloaded symbol `String::after'. We choose three +particular definitions of that function name: + + (gdb) b String::after + [0] cancel + [1] all + [2] file:String.cc; line number:867 + [3] file:String.cc; line number:860 + [4] file:String.cc; line number:875 + [5] file:String.cc; line number:853 + [6] file:String.cc; line number:846 + [7] file:String.cc; line number:735 + > 2 4 6 + Breakpoint 1 at 0xb26c: file String.cc, line 867. + Breakpoint 2 at 0xb344: file String.cc, line 875. + Breakpoint 3 at 0xafcc: file String.cc, line 846. + Multiple breakpoints were set. + Use the "delete" command to delete unwanted + breakpoints. + (gdb) + + +File: gdb.info, Node: Error in Breakpoints, Prev: Breakpoint Menus, Up: Breakpoints + +"Cannot insert breakpoints" +--------------------------- + + Under some operating systems, breakpoints cannot be used in a +program if any other process is running that program. In this +situation, attempting to run or continue a program with a breakpoint +causes GDB to stop the other process. + + When this happens, you have three ways to proceed: + + 1. Remove or disable the breakpoints, then continue. + + 2. Suspend GDB, and copy the file containing your program to a new + name. Resume GDB and use the `exec-file' command to specify that + GDB should run your program under that name. Then start your + program again. + + 3. Relink your program so that the text segment is nonsharable, using + the linker option `-N'. The operating system limitation may not + apply to nonsharable executables. + + +File: gdb.info, Node: Continuing and Stepping, Next: Signals, Prev: Breakpoints, Up: Stopping + +Continuing and stepping +======================= + + "Continuing" means resuming program execution until your program +completes normally. In contrast, "stepping" means executing just one +more "step" of your program, where "step" may mean either one line of +source code, or one machine instruction (depending on what particular +command you use). Either when continuing or when stepping, your +program may stop even sooner, due to a breakpoint or a signal. (If due +to a signal, you may want to use `handle', or use `signal 0' to resume +execution. *Note Signals: Signals.) + +`continue [IGNORE-COUNT]' +`c [IGNORE-COUNT]' +`fg [IGNORE-COUNT]' + Resume program execution, at the address where your program last + stopped; any breakpoints set at that address are bypassed. The + optional argument IGNORE-COUNT allows you to specify a further + number of times to ignore a breakpoint at this location; its + effect is like that of `ignore' (*note Break conditions: + Conditions.). + + The argument IGNORE-COUNT is meaningful only when your program + stopped due to a breakpoint. At other times, the argument to + `continue' is ignored. + + The synonyms `c' and `fg' are provided purely for convenience, and + have exactly the same behavior as `continue'. + + To resume execution at a different place, you can use `return' +(*note Returning from a function: Returning.) to go back to the calling +function; or `jump' (*note Continuing at a different address: Jumping.) +to go to an arbitrary location in your program. + + A typical technique for using stepping is to set a breakpoint (*note +Breakpoints; watchpoints; and exceptions: Breakpoints.) at the +beginning of the function or the section of your program where a +problem is believed to lie, run your program until it stops at that +breakpoint, and then step through the suspect area, examining the +variables that are interesting, until you see the problem happen. + +`step' + Continue running your program until control reaches a different + source line, then stop it and return control to GDB. This command + is abbreviated `s'. + + *Warning:* If you use the `step' command while control is + within a function that was compiled without debugging + information, execution proceeds until control reaches a + function that does have debugging information. + +`step COUNT' + Continue running as in `step', but do so COUNT times. If a + breakpoint is reached, or a signal not related to stepping occurs + before COUNT steps, stepping stops right away. + +`next [COUNT]' + Continue to the next source line in the current (innermost) stack + frame. Similar to `step', but any function calls appearing within + the line of code are executed without stopping. Execution stops + when control reaches a different line of code at the stack level + which was executing when the `next' command was given. This + command is abbreviated `n'. + + An argument COUNT is a repeat count, as for `step'. + + `next' within a function that lacks debugging information acts like + `step', but any function calls appearing within the code of the + function are executed without stopping. + +`finish' + Continue running until just after function in the selected stack + frame returns. Print the returned value (if any). + + Contrast this with the `return' command (*note Returning from a + function: Returning.). + +`until' +`u' + Continue running until a source line past the current line, in the + current stack frame, is reached. This command is used to avoid + single stepping through a loop more than once. It is like the + `next' command, except that when `until' encounters a jump, it + automatically continues execution until the program counter is + greater than the address of the jump. + + This means that when you reach the end of a loop after single + stepping though it, `until' will cause your program to continue + execution until the loop is exited. In contrast, a `next' command + at the end of a loop will simply step back to the beginning of the + loop, which would force you to step through the next iteration. + + `until' always stops your program if it attempts to exit the + current stack frame. + + `until' may produce somewhat counterintuitive results if the order + of machine code does not match the order of the source lines. For + example, in the following excerpt from a debugging session, the `f' + (`frame') command shows that execution is stopped at line `206'; + yet when we use `until', we get to line `195': + + (gdb) f + #0 main (argc=4, argv=0xf7fffae8) at m4.c:206 + 206 expand_input(); + (gdb) until + 195 for ( ; argc > 0; NEXTARG) { + + This happened because, for execution efficiency, the compiler had + generated code for the loop closure test at the end, rather than + the start, of the loop--even though the test in a C `for'-loop is + written before the body of the loop. The `until' command appeared + to step back to the beginning of the loop when it advanced to this + expression; however, it has not really gone to an earlier + statement--not in terms of the actual machine code. + + `until' with no argument works by means of single instruction + stepping, and hence is slower than `until' with an argument. + +`until LOCATION' +`u LOCATION' + Continue running your program until either the specified location + is reached, or the current stack frame returns. LOCATION is any of + the forms of argument acceptable to `break' (*note Setting + breakpoints: Set Breaks.). This form of the command uses + breakpoints, and hence is quicker than `until' without an argument. + +`stepi' +`si' + Execute one machine instruction, then stop and return to the + debugger. + + It is often useful to do `display/i $pc' when stepping by machine + instructions. This will cause the next instruction to be executed + to be displayed automatically at each stop. *Note Automatic + display: Auto Display. + + An argument is a repeat count, as in `step'. + +`nexti' +`ni' + Execute one machine instruction, but if it is a function call, + proceed until the function returns. + + An argument is a repeat count, as in `next'. + + +File: gdb.info, Node: Signals, Prev: Continuing and Stepping, Up: Stopping + +Signals +======= + + A signal is an asynchronous event that can happen in a program. The +operating system defines the possible kinds of signals, and gives each +kind a name and a number. For example, in Unix `SIGINT' is the signal +a program gets when you type an interrupt (often `C-c'); `SIGSEGV' is +the signal a program gets from referencing a place in memory far away +from all the areas in use; `SIGALRM' occurs when the alarm clock timer +goes off (which happens only if your program has requested an alarm). + + Some signals, including `SIGALRM', are a normal part of the +functioning of your program. Others, such as `SIGSEGV', indicate +errors; these signals are "fatal" (kill your program immediately) if the +program has not specified in advance some other way to handle the +signal. `SIGINT' does not indicate an error in your program, but it is +normally fatal so it can carry out the purpose of the interrupt: to +kill the program. + + GDB has the ability to detect any occurrence of a signal in your +program. You can tell GDB in advance what to do for each kind of +signal. + + Normally, GDB is set up to ignore non-erroneous signals like +`SIGALRM' (so as not to interfere with their role in the functioning of +your program) but to stop your program immediately whenever an error +signal happens. You can change these settings with the `handle' +command. + +`info signals' + Print a table of all the kinds of signals and how GDB has been + told to handle each one. You can use this to see the signal + numbers of all the defined types of signals. + +`handle SIGNAL KEYWORDS...' + Change the way GDB handles signal SIGNAL. SIGNAL can be the + number of a signal or its name (with or without the `SIG' at the + beginning). The KEYWORDS say what change to make. + + The keywords allowed by the `handle' command can be abbreviated. +Their full names are: + +`nostop' + GDB should not stop your program when this signal happens. It may + still print a message telling you that the signal has come in. + +`stop' + GDB should stop your program when this signal happens. This + implies the `print' keyword as well. + +`print' + GDB should print a message when this signal happens. + +`noprint' + GDB should not mention the occurrence of the signal at all. This + implies the `nostop' keyword as well. + +`pass' + GDB should allow your program to see this signal; your program + will be able to handle the signal, or may be terminated if the + signal is fatal and not handled. + +`nopass' + GDB should not allow your program to see this signal. + + When a signal stops your program, the signal is not visible until you +continue. Your program will see the signal then, if `pass' is in +effect for the signal in question *at that time*. In other words, +after GDB reports a signal, you can use the `handle' command with +`pass' or `nopass' to control whether that signal will be seen by your +program when you later continue it. + + You can also use the `signal' command to prevent your program from +seeing a signal, or cause it to see a signal it normally would not see, +or to give it any signal at any time. For example, if your program +stopped due to some sort of memory reference error, you might store +correct values into the erroneous variables and continue, hoping to see +more execution; but your program would probably terminate immediately as +a result of the fatal signal once it saw the signal. To prevent this, +you can continue with `signal 0'. *Note Giving your program a signal: +Signaling. + + +File: gdb.info, Node: Stack, Next: Source, Prev: Stopping, Up: Top + +Examining the Stack +******************* + + When your program has stopped, the first thing you need to know is +where it stopped and how it got there. + + Each time your program performs a function call, the information +about where in your program the call was made from is saved in a block +of data called a "stack frame". The frame also contains the arguments +of the call and the local variables of the function that was called. +All the stack frames are allocated in a region of memory called the +"call stack". + + When your program stops, the GDB commands for examining the stack +allow you to see all of this information. + + One of the stack frames is "selected" by GDB and many GDB commands +refer implicitly to the selected frame. In particular, whenever you +ask GDB for the value of a variable in your program, the value is found +in the selected frame. There are special GDB commands to select +whichever frame you are interested in. + + When your program stops, GDB automatically selects the currently +executing frame and describes it briefly as the `frame' command does +(*note Information about a frame: Frame Info.). + +* Menu: + +* Frames:: Stack frames +* Backtrace:: Backtraces +* Selection:: Selecting a frame +* Frame Info:: Information on a frame + +* MIPS Stack:: MIPS machines and the function stack + + +File: gdb.info, Node: Frames, Next: Backtrace, Up: Stack + +Stack frames +============ + + The call stack is divided up into contiguous pieces called "stack +frames", or "frames" for short; each frame is the data associated with +one call to one function. The frame contains the arguments given to +the function, the function's local variables, and the address at which +the function is executing. + + When your program is started, the stack has only one frame, that of +the function `main'. This is called the "initial" frame or the +"outermost" frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function +invocation is eliminated. If a function is recursive, there can be +many frames for the same function. The frame for the function in which +execution is actually occurring is called the "innermost" frame. This +is the most recently created of all the stack frames that still exist. + + Inside your program, stack frames are identified by their addresses. +A stack frame consists of many bytes, each of which has its own +address; each kind of computer has a convention for choosing one of +those bytes whose address serves as the address of the frame. Usually +this address is kept in a register called the "frame pointer register" +while execution is going on in that frame. + + GDB assigns numbers to all existing stack frames, starting with zero +for the innermost frame, one for the frame that called it, and so on +upward. These numbers do not really exist in your program; they are +assigned by GDB to give you a way of designating stack frames in GDB +commands. + + Some compilers provide a way to compile functions so that they +operate without stack frames. (For example, the `gcc' option +`-fomit-frame-pointer' will generate functions without a frame.) This +is occasionally done with heavily used library functions to save the +frame setup time. GDB has limited facilities for dealing with these +function invocations. If the innermost function invocation has no +stack frame, GDB will nevertheless regard it as though it had a +separate frame, which is numbered zero as usual, allowing correct +tracing of the function call chain. However, GDB has no provision for +frameless functions elsewhere in the stack. + + +File: gdb.info, Node: Backtrace, Next: Selection, Prev: Frames, Up: Stack + +Backtraces +========== + + A backtrace is a summary of how your program got where it is. It +shows one line per frame, for many frames, starting with the currently +executing frame (frame zero), followed by its caller (frame one), and +on up the stack. + +`backtrace' +`bt' + Print a backtrace of the entire stack: one line per frame for all + frames in the stack. + + You can stop the backtrace at any time by typing the system + interrupt character, normally `C-c'. + +`backtrace N' +`bt N' + Similar, but print only the innermost N frames. + +`backtrace -N' +`bt -N' + Similar, but print only the outermost N frames. + + The names `where' and `info stack' (abbreviated `info s') are +additional aliases for `backtrace'. + + Each line in the backtrace shows the frame number and the function +name. The program counter value is also shown--unless you use `set +print address off'. The backtrace also shows the source file name and +line number, as well as the arguments to the function. The program +counter value is omitted if it is at the beginning of the code for that +line number. + + Here is an example of a backtrace. It was made with the command `bt +3', so it shows the innermost three frames. + + #0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) + at builtin.c:993 + #1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242 + #2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08) + at macro.c:71 + (More stack frames follow...) + +The display for frame zero does not begin with a program counter value, +indicating that your program has stopped at the beginning of the code +for line `993' of `builtin.c'. + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-3 b/gnu/usr.bin/gdb/doc/gdb.info-3 new file mode 100644 index 00000000000..aea5862a305 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-3 @@ -0,0 +1,1264 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Selection, Next: Frame Info, Prev: Backtrace, Up: Stack + +Selecting a frame +================= + + Most commands for examining the stack and other data in your program +work on whichever stack frame is selected at the moment. Here are the +commands for selecting a stack frame; all of them finish by printing a +brief description of the stack frame just selected. + +`frame N' +`f N' + Select frame number N. Recall that frame zero is the innermost + (currently executing) frame, frame one is the frame that called the + innermost one, and so on. The highest-numbered frame is the one + for `main'. + +`frame ADDR' +`f ADDR' + Select the frame at address ADDR. This is useful mainly if the + chaining of stack frames has been damaged by a bug, making it + impossible for GDB to assign numbers properly to all frames. In + addition, this can be useful when your program has multiple stacks + and switches between them. + + On the SPARC architecture, `frame' needs two addresses to select + an arbitrary frame: a frame pointer and a stack pointer. + +`up N' + Move N frames up the stack. For positive numbers N, this advances + toward the outermost frame, to higher frame numbers, to frames + that have existed longer. N defaults to one. + +`down N' + Move N frames down the stack. For positive numbers N, this + advances toward the innermost frame, to lower frame numbers, to + frames that were created more recently. N defaults to one. You + may abbreviate `down' as `do'. + + All of these commands end by printing two lines of output describing +the frame. The first line shows the frame number, the function name, +the arguments, and the source file and line number of execution in that +frame. The second line shows the text of that source line. + + For example: + (gdb) up + #1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc) + at env.c:10 + 10 read_input_file (argv[i]); + + After such a printout, the `list' command with no arguments will +print ten lines centered on the point of execution in the frame. *Note +Printing source lines: List. + +`up-silently N' +`down-silently N' + These two commands are variants of `up' and `down', respectively; + they differ in that they do their work silently, without causing + display of the new frame. They are intended primarily for use in + GDB command scripts, where the output might be unnecessary and + distracting. + + +File: gdb.info, Node: Frame Info, Next: MIPS Stack, Prev: Selection, Up: Stack + +Information about a frame +========================= + + There are several other commands to print information about the +selected stack frame. + +`frame' +`f' + When used without any argument, this command does not change which + frame is selected, but prints a brief description of the currently + selected stack frame. It can be abbreviated `f'. With an + argument, this command is used to select a stack frame. *Note + Selecting a frame: Selection. + +`info frame' +`info f' + This command prints a verbose description of the selected stack + frame, including the address of the frame, the addresses of the + next frame down (called by this frame) and the next frame up + (caller of this frame), the language that the source code + corresponding to this frame was written in, the address of the + frame's arguments, the program counter saved in it (the address of + execution in the caller frame), and which registers were saved in + the frame. The verbose description is useful when something has + gone wrong that has made the stack format fail to fit the usual + conventions. + +`info frame ADDR' +`info f ADDR' + Print a verbose description of the frame at address ADDR, without + selecting that frame. The selected frame remains unchanged by + this command. + +`info args' + Print the arguments of the selected frame, each on a separate line. + +`info locals' + Print the local variables of the selected frame, each on a separate + line. These are all variables (declared either static or + automatic) accessible at the point of execution of the selected + frame. + +`info catch' + Print a list of all the exception handlers that are active in the + current stack frame at the current point of execution. To see + other exception handlers, visit the associated frame (using the + `up', `down', or `frame' commands); then type `info catch'. *Note + Breakpoints and exceptions: Exception Handling. + + +File: gdb.info, Node: MIPS Stack, Prev: Frame Info, Up: Stack + +MIPS machines and the function stack +==================================== + + MIPS based computers use an unusual stack frame, which sometimes +requires GDB to search backward in the object code to find the +beginning of a function. + + To improve response time (especially for embedded applications, where +GDB may be restricted to a slow serial line for this search) you may +want to limit the size of this search, using one of these commands: + +`set heuristic-fence-post LIMIT' + Restrict GDBN to examining at most LIMIT bytes in its search for + the beginning of a function. A value of `0' (the default) means + there is no limit. + +`show heuristic-fence-post' + Display the current limit. + +These commands are available *only* when GDB is configured for +debugging programs on MIPS processors. + + +File: gdb.info, Node: Source, Next: Data, Prev: Stack, Up: Top + +Examining Source Files +********************** + + GDB can print parts of your program's source, since the debugging +information recorded in the program tells GDB what source files were +used to build it. When your program stops, GDB spontaneously prints +the line where it stopped. Likewise, when you select a stack frame +(*note Selecting a frame: Selection.), GDB prints the line where +execution in that frame has stopped. You can print other portions of +source files by explicit command. + + If you use GDB through its GNU Emacs interface, you may prefer to use +Emacs facilities to view source; *note Using GDB under GNU Emacs: +Emacs.. + +* Menu: + +* List:: Printing source lines + +* Search:: Searching source files + +* Source Path:: Specifying source directories +* Machine Code:: Source and machine code + + +File: gdb.info, Node: List, Next: Search, Up: Source + +Printing source lines +===================== + + To print lines from a source file, use the `list' command +(abbreviated `l'). There are several ways to specify what part of the +file you want to print. + + Here are the forms of the `list' command most commonly used: + +`list LINENUM' + Print lines centered around line number LINENUM in the current + source file. + +`list FUNCTION' + Print lines centered around the beginning of function FUNCTION. + +`list' + Print more lines. If the last lines printed were printed with a + `list' command, this prints lines following the last lines + printed; however, if the last line printed was a solitary line + printed as part of displaying a stack frame (*note Examining the + Stack: Stack.), this prints lines centered around that line. + +`list -' + Print lines just before the lines last printed. + + By default, GDB prints ten source lines with any of these forms of +the `list' command. You can change this using `set listsize': + +`set listsize COUNT' + Make the `list' command display COUNT source lines (unless the + `list' argument explicitly specifies some other number). + +`show listsize' + Display the number of lines that `list' will currently display by + default. + + Repeating a `list' command with RET discards the argument, so it is +equivalent to typing just `list'. This is more useful than listing the +same lines again. An exception is made for an argument of `-'; that +argument is preserved in repetition so that each repetition moves up in +the source file. + + In general, the `list' command expects you to supply zero, one or two +"linespecs". Linespecs specify source lines; there are several ways of +writing them but the effect is always to specify some source line. +Here is a complete description of the possible arguments for `list': + +`list LINESPEC' + Print lines centered around the line specified by LINESPEC. + +`list FIRST,LAST' + Print lines from FIRST to LAST. Both arguments are linespecs. + +`list ,LAST' + Print lines ending with LAST. + +`list FIRST,' + Print lines starting with FIRST. + +`list +' + Print lines just after the lines last printed. + +`list -' + Print lines just before the lines last printed. + +`list' + As described in the preceding table. + + Here are the ways of specifying a single source line--all the kinds +of linespec. + +`NUMBER' + Specifies line NUMBER of the current source file. When a `list' + command has two linespecs, this refers to the same source file as + the first linespec. + +`+OFFSET' + Specifies the line OFFSET lines after the last line printed. When + used as the second linespec in a `list' command that has two, this + specifies the line OFFSET lines down from the first linespec. + +`-OFFSET' + Specifies the line OFFSET lines before the last line printed. + +`FILENAME:NUMBER' + Specifies line NUMBER in the source file FILENAME. + +`FUNCTION' + Specifies the line of the open-brace that begins the body of the + function FUNCTION. + +`FILENAME:FUNCTION' + Specifies the line of the open-brace that begins the body of the + function FUNCTION in the file FILENAME. You only need the file + name with a function name to avoid ambiguity when there are + identically named functions in different source files. + +`*ADDRESS' + Specifies the line containing the program address ADDRESS. + ADDRESS may be any expression. + + +File: gdb.info, Node: Search, Next: Source Path, Prev: List, Up: Source + +Searching source files +====================== + + There are two commands for searching through the current source file +for a regular expression. + +`forward-search REGEXP' +`search REGEXP' + The command `forward-search REGEXP' checks each line, starting + with the one following the last line listed, for a match for + REGEXP. It lists the line that is found. You can use synonym + `search REGEXP' or abbreviate the command name as `fo'. + +`reverse-search REGEXP' + The command `reverse-search REGEXP' checks each line, starting + with the one before the last line listed and going backward, for a + match for REGEXP. It lists the line that is found. You can + abbreviate this command as `rev'. + + +File: gdb.info, Node: Source Path, Next: Machine Code, Prev: Search, Up: Source + +Specifying source directories +============================= + + Executable programs sometimes do not record the directories of the +source files from which they were compiled, just the names. Even when +they do, the directories could be moved between the compilation and +your debugging session. GDB has a list of directories to search for +source files; this is called the "source path". Each time GDB wants a +source file, it tries all the directories in the list, in the order +they are present in the list, until it finds a file with the desired +name. Note that the executable search path is *not* used for this +purpose. Neither is the current working directory, unless it happens +to be in the source path. + + If GDB cannot find a source file in the source path, and the object +program records a directory, GDB tries that directory too. If the +source path is empty, and there is no record of the compilation +directory, GDB will, as a last resort, look in the current directory. + + Whenever you reset or rearrange the source path, GDB will clear out +any information it has cached about where source files are found, where +each line is in the file, etc. + + When you start GDB, its source path is empty. To add other +directories, use the `directory' command. + +`directory DIRNAME ...' + Add directory DIRNAME to the front of the source path. Several + directory names may be given to this command, separated by `:' or + whitespace. You may specify a directory that is already in the + source path; this moves it forward, so it will be searched sooner. + + You can use the string `$cdir' to refer to the compilation + directory (if one is recorded), and `$cwd' to refer to the current + working directory. `$cwd' is not the same as `.'--the former + tracks the current working directory as it changes during your GDB + session, while the latter is immediately expanded to the current + directory at the time you add an entry to the source path. + +`directory' + Reset the source path to empty again. This requires confirmation. + +`show directories' + Print the source path: show which directories it contains. + + If your source path is cluttered with directories that are no longer +of interest, GDB may sometimes cause confusion by finding the wrong +versions of source. You can correct the situation as follows: + + 1. Use `directory' with no argument to reset the source path to empty. + + 2. Use `directory' with suitable arguments to reinstall the + directories you want in the source path. You can add all the + directories in one command. + + +File: gdb.info, Node: Machine Code, Prev: Source Path, Up: Source + +Source and machine code +======================= + + You can use the command `info line' to map source lines to program +addresses (and vice versa), and the command `disassemble' to display a +range of addresses as machine instructions. + +`info line LINESPEC' + Print the starting and ending addresses of the compiled code for + source line LINESPEC. You can specify source lines in any of the + ways understood by the `list' command (*note Printing source + lines: List.). + + For example, we can use `info line' to discover the location of the +object code for the first line of function `m4_changequote': + + (gdb) info line m4_changecom + Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350. + +We can also inquire (using `*ADDR' as the form for LINESPEC) what +source line covers a particular address: + (gdb) info line *0x63ff + Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404. + + After `info line', the default address for the `x' command is +changed to the starting address of the line, so that `x/i' is +sufficient to begin examining the machine code (*note Examining memory: +Memory.). Also, this address is saved as the value of the convenience +variable `$_' (*note Convenience variables: Convenience Vars.). + +`disassemble' + This specialized command dumps a range of memory as machine + instructions. The default memory range is the function + surrounding the program counter of the selected frame. A single + argument to this command is a program counter value; the function + surrounding this value will be dumped. Two arguments specify a + range of addresses (first inclusive, second exclusive) to dump. + + We can use `disassemble' to inspect the object code range shown in +the last `info line' example (the example shows SPARC machine +instructions): + + (gdb) disas 0x63e4 0x6404 + Dump of assembler code from 0x63e4 to 0x6404: + 0x63e4 : ble 0x63f8 + 0x63e8 : sethi %hi(0x4c00), %o0 + 0x63ec : ld [%i1+4], %o0 + 0x63f0 : b 0x63fc + 0x63f4 : ld [%o0+4], %o0 + 0x63f8 : or %o0, 0x1a4, %o0 + 0x63fc : call 0x9288 + 0x6400 : nop + End of assembler dump. + + +File: gdb.info, Node: Data, Next: Languages, Prev: Source, Up: Top + +Examining Data +************** + + The usual way to examine data in your program is with the `print' +command (abbreviated `p'), or its synonym `inspect'. It evaluates and +prints the value of an expression of the language your program is +written in (*note Using GDB with Different Languages: Languages.). + +`print EXP' +`print /F EXP' + EXP is an expression (in the source language). By default the + value of EXP is printed in a format appropriate to its data type; + you can choose a different format by specifying `/F', where F is a + letter specifying the format; *note Output formats: Output + Formats.. + +`print' +`print /F' + If you omit EXP, GDB displays the last value again (from the + "value history"; *note Value history: Value History.). This + allows you to conveniently inspect the same value in an + alternative format. + + A more low-level way of examining data is with the `x' command. It +examines data in memory at a specified address and prints it in a +specified format. *Note Examining memory: Memory. + + If you are interested in information about types, or about how the +fields of a struct or class are declared, use the `ptype EXP' command +rather than `print'. *Note Examining the Symbol Table: Symbols. + +* Menu: + +* Expressions:: Expressions +* Variables:: Program variables +* Arrays:: Artificial arrays +* Output Formats:: Output formats +* Memory:: Examining memory +* Auto Display:: Automatic display +* Print Settings:: Print settings +* Value History:: Value history +* Convenience Vars:: Convenience variables +* Registers:: Registers + +* Floating Point Hardware:: Floating point hardware + + +File: gdb.info, Node: Expressions, Next: Variables, Up: Data + +Expressions +=========== + + `print' and many other GDB commands accept an expression and compute +its value. Any kind of constant, variable or operator defined by the +programming language you are using is valid in an expression in GDB. +This includes conditional expressions, function calls, casts and string +constants. It unfortunately does not include symbols defined by +preprocessor `#define' commands. + + Because C is so widespread, most of the expressions shown in +examples in this manual are in C. *Note Using GDB with Different +Languages: Languages, for information on how to use expressions in other +languages. + + In this section, we discuss operators that you can use in GDB +expressions regardless of your programming language. + + Casts are supported in all languages, not just in C, because it is so +useful to cast a number into a pointer so as to examine a structure at +that address in memory. + + GDB supports these operators in addition to those of programming +languages: + +`@' + `@' is a binary operator for treating parts of memory as arrays. + *Note Artificial arrays: Arrays, for more information. + +`::' + `::' allows you to specify a variable in terms of the file or + function where it is defined. *Note Program variables: Variables. + +`{TYPE} ADDR' + Refers to an object of type TYPE stored at address ADDR in memory. + ADDR may be any expression whose value is an integer or pointer + (but parentheses are required around binary operators, just as in + a cast). This construct is allowed regardless of what kind of + data is normally supposed to reside at ADDR. + + +File: gdb.info, Node: Variables, Next: Arrays, Prev: Expressions, Up: Data + +Program variables +================= + + The most common kind of expression to use is the name of a variable +in your program. + + Variables in expressions are understood in the selected stack frame +(*note Selecting a frame: Selection.); they must either be global (or +static) or be visible according to the scope rules of the programming +language from the point of execution in that frame. This means that in +the function + + foo (a) + int a; + { + bar (a); + { + int b = test (); + bar (b); + } + } + +you can examine and use the variable `a' whenever your program is +executing within the function `foo', but you can only use or examine +the variable `b' while your program is executing inside the block where +`b' is declared. + + There is an exception: you can refer to a variable or function whose +scope is a single source file even if the current execution point is not +in this file. But it is possible to have more than one such variable or +function with the same name (in different source files). If that +happens, referring to that name has unpredictable effects. If you wish, +you can specify a static variable in a particular function or file, +using the colon-colon notation: + + FILE::VARIABLE + FUNCTION::VARIABLE + +Here FILE or FUNCTION is the name of the context for the static +VARIABLE. In the case of file names, you can use quotes to make sure +GDB parses the file name as a single word--for example, to print a +global value of `x' defined in `f2.c': + + (gdb) p 'f2.c'::x + + This use of `::' is very rarely in conflict with the very similar +use of the same notation in C++. GDB also supports use of the C++ +scope resolution operator in GDB expressions. + + *Warning:* Occasionally, a local variable may appear to have the + wrong value at certain points in a function--just after entry to a + new scope, and just before exit. + You may see this problem when you are stepping by machine +instructions. This is because on most machines, it takes more than one +instruction to set up a stack frame (including local variable +definitions); if you are stepping by machine instructions, variables +may appear to have the wrong values until the stack frame is completely +built. On exit, it usually also takes more than one machine +instruction to destroy a stack frame; after you begin stepping through +that group of instructions, local variable definitions may be gone. + + +File: gdb.info, Node: Arrays, Next: Output Formats, Prev: Variables, Up: Data + +Artificial arrays +================= + + It is often useful to print out several successive objects of the +same type in memory; a section of an array, or an array of dynamically +determined size for which only a pointer exists in the program. + + You can do this by referring to a contiguous span of memory as an +"artificial array", using the binary operator `@'. The left operand of +`@' should be the first element of the desired array, as an individual +object. The right operand should be the desired length of the array. +The result is an array value whose elements are all of the type of the +left argument. The first element is actually the left argument; the +second element comes from bytes of memory immediately following those +that hold the first element, and so on. Here is an example. If a +program says + + int *array = (int *) malloc (len * sizeof (int)); + +you can print the contents of `array' with + + p *array@len + + The left operand of `@' must reside in memory. Array values made +with `@' in this way behave just like other arrays in terms of +subscripting, and are coerced to pointers when used in expressions. +Artificial arrays most often appear in expressions via the value history +(*note Value history: Value History.), after printing one out. + + Sometimes the artificial array mechanism is not quite enough; in +moderately complex data structures, the elements of interest may not +actually be adjacent--for example, if you are interested in the values +of pointers in an array. One useful work-around in this situation is +to use a convenience variable (*note Convenience variables: Convenience +Vars.) as a counter in an expression that prints the first interesting +value, and then repeat that expression via RET. For instance, suppose +you have an array `dtab' of pointers to structures, and you are +interested in the values of a field `fv' in each structure. Here is an +example of what you might type: + + set $i = 0 + p dtab[$i++]->fv + RET + RET + ... + + +File: gdb.info, Node: Output Formats, Next: Memory, Prev: Arrays, Up: Data + +Output formats +============== + + By default, GDB prints a value according to its data type. Sometimes +this is not what you want. For example, you might want to print a +number in hex, or a pointer in decimal. Or you might want to view data +in memory at a certain address as a character string or as an +instruction. To do these things, specify an "output format" when you +print a value. + + The simplest use of output formats is to say how to print a value +already computed. This is done by starting the arguments of the +`print' command with a slash and a format letter. The format letters +supported are: + +`x' + Regard the bits of the value as an integer, and print the integer + in hexadecimal. + +`d' + Print as integer in signed decimal. + +`u' + Print as integer in unsigned decimal. + +`o' + Print as integer in octal. + +`t' + Print as integer in binary. The letter `t' stands for "two". (1) + +`a' + Print as an address, both absolute in hex and as an offset from the + nearest preceding symbol. This format can be used to discover + where (in what function) an unknown address is located: + + (gdb) p/a 0x54320 + $3 = 0x54320 <_initialize_vx+396> + +`c' + Regard as an integer and print it as a character constant. + +`f' + Regard the bits of the value as a floating point number and print + using typical floating point syntax. + + For example, to print the program counter in hex (*note +Registers::.), type + + p/x $pc + +Note that no space is required before the slash; this is because command +names in GDB cannot contain a slash. + + To reprint the last value in the value history with a different +format, you can use the `print' command with just a format and no +expression. For example, `p/x' reprints the last value in hex. + + ---------- Footnotes ---------- + + (1) `b' cannot be used because these format letters are also used +with the `x' command, where `b' stands for "byte"; *note Examining +memory: Memory.. + + +File: gdb.info, Node: Memory, Next: Auto Display, Prev: Output Formats, Up: Data + +Examining memory +================ + + You can use the command `x' (for "examine") to examine memory in any +of several formats, independently of your program's data types. + +`x/NFU ADDR' +`x ADDR' +`x' + Use the `x' command to examine memory. + + N, F, and U are all optional parameters that specify how much memory +to display and how to format it; ADDR is an expression giving the +address where you want to start displaying memory. If you use defaults +for NFU, you need not type the slash `/'. Several commands set +convenient defaults for ADDR. + +N, the repeat count + The repeat count is a decimal integer; the default is 1. It + specifies how much memory (counting by units U) to display. + +F, the display format + The display format is one of the formats used by `print', or `s' + (null-terminated string) or `i' (machine instruction). The + default is `x' (hexadecimal) initially, or the format from the + last time you used either `x' or `print'. + +U, the unit size + The unit size is any of + + `b' + Bytes. + + `h' + Halfwords (two bytes). + + `w' + Words (four bytes). This is the initial default. + + `g' + Giant words (eight bytes). + + Each time you specify a unit size with `x', that size becomes the + default unit the next time you use `x'. (For the `s' and `i' + formats, the unit size is ignored and is normally not written.) + +ADDR, starting display address + ADDR is the address where you want GDB to begin displaying memory. + The expression need not have a pointer value (though it may); it + is always interpreted as an integer address of a byte of memory. + *Note Expressions: Expressions, for more information on + expressions. The default for ADDR is usually just after the last + address examined--but several other commands also set the default + address: `info breakpoints' (to the address of the last breakpoint + listed), `info line' (to the starting address of a line), and + `print' (if you use it to display a value from memory). + + For example, `x/3uh 0x54320' is a request to display three halfwords +(`h') of memory, formatted as unsigned decimal integers (`u'), starting +at address `0x54320'. `x/4xw $sp' prints the four words (`w') of +memory above the stack pointer (here, `$sp'; *note Registers::.) in +hexadecimal (`x'). + + Since the letters indicating unit sizes are all distinct from the +letters specifying output formats, you do not have to remember whether +unit size or format comes first; either order will work. The output +specifications `4xw' and `4wx' mean exactly the same thing. (However, +the count N must come first; `wx4' will not work.) + + Even though the unit size U is ignored for the formats `s' and `i', +you might still want to use a count N; for example, `3i' specifies that +you want to see three machine instructions, including any operands. +The command `disassemble' gives an alternative way of inspecting +machine instructions; *note Source and machine code: Machine Code.. + + All the defaults for the arguments to `x' are designed to make it +easy to continue scanning memory with minimal specifications each time +you use `x'. For example, after you have inspected three machine +instructions with `x/3i ADDR', you can inspect the next seven with just +`x/7'. If you use RET to repeat the `x' command, the repeat count N is +used again; the other arguments default as for successive uses of `x'. + + The addresses and contents printed by the `x' command are not saved +in the value history because there is often too much of them and they +would get in the way. Instead, GDB makes these values available for +subsequent use in expressions as values of the convenience variables +`$_' and `$__'. After an `x' command, the last address examined is +available for use in expressions in the convenience variable `$_'. The +contents of that address, as examined, are available in the convenience +variable `$__'. + + If the `x' command has a repeat count, the address and contents saved +are from the last memory unit printed; this is not the same as the last +address printed if several units were printed on the last line of +output. + + +File: gdb.info, Node: Auto Display, Next: Print Settings, Prev: Memory, Up: Data + +Automatic display +================= + + If you find that you want to print the value of an expression +frequently (to see how it changes), you might want to add it to the +"automatic display list" so that GDB will print its value each time +your program stops. Each expression added to the list is given a +number to identify it; to remove an expression from the list, you +specify that number. The automatic display looks like this: + + 2: foo = 38 + 3: bar[5] = (struct hack *) 0x3804 + +This display shows item numbers, expressions and their current values. +As with displays you request manually using `x' or `print', you can +specify the output format you prefer; in fact, `display' decides +whether to use `print' or `x' depending on how elaborate your format +specification is--it uses `x' if you specify a unit size, or one of the +two formats (`i' and `s') that are only supported by `x'; otherwise it +uses `print'. + +`display EXP' + Add the expression EXP to the list of expressions to display each + time your program stops. *Note Expressions: Expressions. + + `display' will not repeat if you press RET again after using it. + +`display/FMT EXP' + For FMT specifying only a display format and not a size or count, + add the expression EXP to the auto-display list but arrange to + display it each time in the specified format FMT. *Note Output + formats: Output Formats. + +`display/FMT ADDR' + For FMT `i' or `s', or including a unit-size or a number of units, + add the expression ADDR as a memory address to be examined each + time your program stops. Examining means in effect doing `x/FMT + ADDR'. *Note Examining memory: Memory. + + For example, `display/i $pc' can be helpful, to see the machine +instruction about to be executed each time execution stops (`$pc' is a +common name for the program counter; *note Registers::.). + +`undisplay DNUMS...' +`delete display DNUMS...' + Remove item numbers DNUMS from the list of expressions to display. + + `undisplay' will not repeat if you press RET after using it. + (Otherwise you would just get the error `No display number ...'.) + +`disable display DNUMS...' + Disable the display of item numbers DNUMS. A disabled display + item is not printed automatically, but is not forgotten. It may be + enabled again later. + +`enable display DNUMS...' + Enable display of item numbers DNUMS. It becomes effective once + again in auto display of its expression, until you specify + otherwise. + +`display' + Display the current values of the expressions on the list, just as + is done when your program stops. + +`info display' + Print the list of expressions previously set up to display + automatically, each one with its item number, but without showing + the values. This includes disabled expressions, which are marked + as such. It also includes expressions which would not be + displayed right now because they refer to automatic variables not + currently available. + + If a display expression refers to local variables, then it does not +make sense outside the lexical context for which it was set up. Such an +expression is disabled when execution enters a context where one of its +variables is not defined. For example, if you give the command +`display last_char' while inside a function with an argument +`last_char', then this argument will be displayed while your program +continues to stop inside that function. When it stops elsewhere--where +there is no variable `last_char'--display is disabled. The next time +your program stops where `last_char' is meaningful, you can enable the +display expression once again. + + +File: gdb.info, Node: Print Settings, Next: Value History, Prev: Auto Display, Up: Data + +Print settings +============== + + GDB provides the following ways to control how arrays, structures, +and symbols are printed. + +These settings are useful for debugging programs in any language: + +`set print address' +`set print address on' + GDB will print memory addresses showing the location of stack + traces, structure values, pointer values, breakpoints, and so + forth, even when it also displays the contents of those addresses. + The default is on. For example, this is what a stack frame + display looks like, with `set print address on': + + (gdb) f + #0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>") + at input.c:530 + 530 if (lquote != def_lquote) + +`set print address off' + Do not print addresses when displaying their contents. For + example, this is the same stack frame displayed with `set print + address off': + + (gdb) set print addr off + (gdb) f + #0 set_quotes (lq="<<", rq=">>") at input.c:530 + 530 if (lquote != def_lquote) + + You can use `set print address off' to eliminate all machine + dependent displays from the GDB interface. For example, with + `print address off', you should get the same text for backtraces on + all machines--whether or not they involve pointer arguments. + +`show print address' + Show whether or not addresses are to be printed. + + When GDB prints a symbolic address, it normally prints the closest +earlier symbol plus an offset. If that symbol does not uniquely +identify the address (for example, it is a name whose scope is a single +source file), you may need to disambiguate. One way to do this is with +`info line', for example `info line *0x4537'. Alternately, you can set +GDB to print the source file and line number when it prints a symbolic +address: + +`set print symbol-filename on' + Tell GDB to print the source file name and line number of a symbol + in the symbolic form of an address. + +`set print symbol-filename off' + Do not print source file name and line number of a symbol. This + is the default. + +`show print symbol-filename' + Show whether or not GDB will print the source file name and line + number of a symbol in the symbolic form of an address. + + Also, you may wish to see the symbolic form only if the address being +printed is reasonably close to the closest earlier symbol: + +`set print max-symbolic-offset MAX-OFFSET' + Tell GDB to only display the symbolic form of an address if the + offset between the closest earlier symbol and the address is less + than MAX-OFFSET. The default is 0, which means to always print the + symbolic form of an address, if any symbol precedes it. + +`show print max-symbolic-offset' + Ask how large the maximum offset is that GDB will print in a + symbolic address. + +`set print array' +`set print array on' + GDB will pretty-print arrays. This format is more convenient to + read, but uses more space. The default is off. + +`set print array off' + Return to compressed format for arrays. + +`show print array' + Show whether compressed or pretty format is selected for displaying + arrays. + +`set print elements NUMBER-OF-ELEMENTS' + If GDB is printing a large array, it will stop printing after it + has printed the number of elements set by the `set print elements' + command. This limit also applies to the display of strings. + Setting the number of elements to zero means that the printing is + unlimited. + +`show print elements' + Display the number of elements of a large array that GDB will print + before losing patience. + +`set print pretty on' + Cause GDB to print structures in an indented format with one + member per line, like this: + + $1 = { + next = 0x0, + flags = { + sweet = 1, + sour = 1 + }, + meat = 0x54 "Pork" + } + +`set print pretty off' + Cause GDB to print structures in a compact format, like this: + + $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, \ + meat = 0x54 "Pork"} + + This is the default format. + +`show print pretty' + Show which format GDB will use to print structures. + +`set print sevenbit-strings on' + Print using only seven-bit characters; if this option is set, GDB + will display any eight-bit characters (in strings or character + values) using the notation `\'NNN. For example, `M-a' is + displayed as `\341'. + +`set print sevenbit-strings off' + Print using either seven-bit or eight-bit characters, as required. + This is the default. + +`show print sevenbit-strings' + Show whether or not GDB will print only seven-bit characters. + +`set print union on' + Tell GDB to print unions which are contained in structures. This + is the default setting. + +`set print union off' + Tell GDB not to print unions which are contained in structures. + +`show print union' + Ask GDB whether or not it will print unions which are contained in + structures. + + For example, given the declarations + + typedef enum {Tree, Bug} Species; + typedef enum {Big_tree, Acorn, Seedling} Tree_forms; + typedef enum {Caterpillar, Cocoon, Butterfly} + Bug_forms; + + struct thing { + Species it; + union { + Tree_forms tree; + Bug_forms bug; + } form; + }; + + struct thing foo = {Tree, {Acorn}}; + + with `set print union on' in effect `p foo' would print + + $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}} + + and with `set print union off' in effect it would print + + $1 = {it = Tree, form = {...}} + +These settings are of interest when debugging C++ programs: + +`set print demangle' +`set print demangle on' + Print C++ names in their source form rather than in the encoded + ("mangled") form passed to the assembler and linker for type-safe + linkage. The default is `on'. + +`show print demangle' + Show whether C++ names will be printed in mangled or demangled + form. + +`set print asm-demangle' +`set print asm-demangle on' + Print C++ names in their source form rather than their mangled + form, even in assembler code printouts such as instruction + disassemblies. The default is off. + +`show print asm-demangle' + Show whether C++ names in assembly listings will be printed in + mangled or demangled form. + +`set demangle-style STYLE' + Choose among several encoding schemes used by different compilers + to represent C++ names. The choices for STYLE are currently: + + `auto' + Allow GDB to choose a decoding style by inspecting your + program. + + `gnu' + Decode based on the GNU C++ compiler (`g++') encoding + algorithm. + + `lucid' + Decode based on the Lucid C++ compiler (`lcc') encoding + algorithm. + + `arm' + Decode using the algorithm in the `C++ Annotated Reference + Manual'. *Warning:* this setting alone is not sufficient to + allow debugging `cfront'-generated executables. GDB would + require further enhancement to permit that. + +`show demangle-style' + Display the encoding style currently in use for decoding C++ + symbols. + +`set print object' +`set print object on' + When displaying a pointer to an object, identify the *actual* + (derived) type of the object rather than the *declared* type, using + the virtual function table. + +`set print object off' + Display only the declared type of objects, without reference to the + virtual function table. This is the default setting. + +`show print object' + Show whether actual, or declared, object types will be displayed. + +`set print vtbl' +`set print vtbl on' + Pretty print C++ virtual function tables. The default is off. + +`set print vtbl off' + Do not pretty print C++ virtual function tables. + +`show print vtbl' + Show whether C++ virtual function tables are pretty printed, or + not. + + +File: gdb.info, Node: Value History, Next: Convenience Vars, Prev: Print Settings, Up: Data + +Value history +============= + + Values printed by the `print' command are saved in the GDB "value +history" so that you can refer to them in other expressions. Values are +kept until the symbol table is re-read or discarded (for example with +the `file' or `symbol-file' commands). When the symbol table changes, +the value history is discarded, since the values may contain pointers +back to the types defined in the symbol table. + + The values printed are given "history numbers" by which you can +refer to them. These are successive integers starting with one. +`print' shows you the history number assigned to a value by printing +`$NUM = ' before the value; here NUM is the history number. + + To refer to any previous value, use `$' followed by the value's +history number. The way `print' labels its output is designed to +remind you of this. Just `$' refers to the most recent value in the +history, and `$$' refers to the value before that. `$$N' refers to the +Nth value from the end; `$$2' is the value just prior to `$$', `$$1' is +equivalent to `$$', and `$$0' is equivalent to `$'. + + For example, suppose you have just printed a pointer to a structure +and want to see the contents of the structure. It suffices to type + + p *$ + + If you have a chain of structures where the component `next' points +to the next one, you can print the contents of the next one with this: + + p *$.next + +You can print successive links in the chain by repeating this +command--which you can do by just typing RET. + + Note that the history records values, not expressions. If the value +of `x' is 4 and you type these commands: + + print x + set x=5 + +then the value recorded in the value history by the `print' command +remains 4 even though the value of `x' has changed. + +`show values' + Print the last ten values in the value history, with their item + numbers. This is like `p $$9' repeated ten times, except that + `show values' does not change the history. + +`show values N' + Print ten history values centered on history item number N. + +`show values +' + Print ten history values just after the values last printed. If + no more values are available, produces no display. + + Pressing RET to repeat `show values N' has exactly the same effect +as `show values +'. + + +File: gdb.info, Node: Convenience Vars, Next: Registers, Prev: Value History, Up: Data + +Convenience variables +===================== + + GDB provides "convenience variables" that you can use within GDB to +hold on to a value and refer to it later. These variables exist +entirely within GDB; they are not part of your program, and setting a +convenience variable has no direct effect on further execution of your +program. That is why you can use them freely. + + Convenience variables are prefixed with `$'. Any name preceded by +`$' can be used for a convenience variable, unless it is one of the +predefined machine-specific register names (*note Registers::.). +(Value history references, in contrast, are *numbers* preceded by `$'. +*Note Value history: Value History.) + + You can save a value in a convenience variable with an assignment +expression, just as you would set a variable in your program. For +example: + + set $foo = *object_ptr + +would save in `$foo' the value contained in the object pointed to by +`object_ptr'. + + Using a convenience variable for the first time creates it, but its +value is `void' until you assign a new value. You can alter the value +with another assignment at any time. + + Convenience variables have no fixed types. You can assign a +convenience variable any type of value, including structures and +arrays, even if that variable already has a value of a different type. +The convenience variable, when used as an expression, has the type of +its current value. + +`show convenience' + Print a list of convenience variables used so far, and their + values. Abbreviated `show con'. + + One of the ways to use a convenience variable is as a counter to be +incremented or a pointer to be advanced. For example, to print a field +from successive elements of an array of structures: + + set $i = 0 + print bar[$i++]->contents + ... repeat that command by typing RET. + + Some convenience variables are created automatically by GDB and given +values likely to be useful. + +`$_' + The variable `$_' is automatically set by the `x' command to the + last address examined (*note Examining memory: Memory.). Other + commands which provide a default address for `x' to examine also + set `$_' to that address; these commands include `info line' and + `info breakpoint'. The type of `$_' is `void *' except when set + by the `x' command, in which case it is a pointer to the type of + `$__'. + +`$__' + The variable `$__' is automatically set by the `x' command to the + value found in the last address examined. Its type is chosen to + match the format in which the data was printed. + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-4 b/gnu/usr.bin/gdb/doc/gdb.info-4 new file mode 100644 index 00000000000..b0758fa5ef6 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-4 @@ -0,0 +1,1349 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Registers, Next: Floating Point Hardware, Prev: Convenience Vars, Up: Data + +Registers +========= + + You can refer to machine register contents, in expressions, as +variables with names starting with `$'. The names of registers are +different for each machine; use `info registers' to see the names used +on your machine. + +`info registers' + Print the names and values of all registers except floating-point + registers (in the selected stack frame). + +`info all-registers' + Print the names and values of all registers, including + floating-point registers. + +`info registers REGNAME ...' + Print the relativized value of each specified register REGNAME. + rEGNAME may be any register name valid on the machine you are + using, with or without the initial `$'. + + GDB has four "standard" register names that are available (in +expressions) on most machines--whenever they do not conflict with an +architecture's canonical mnemonics for registers. The register names +`$pc' and `$sp' are used for the program counter register and the stack +pointer. `$fp' is used for a register that contains a pointer to the +current stack frame, and `$ps' is used for a register that contains the +processor status. For example, you could print the program counter in +hex with + + p/x $pc + +or print the instruction to be executed next with + + x/i $pc + +or add four to the stack pointer(1) with + + set $sp += 4 + + Whenever possible, these four standard register names are available +on your machine even though the machine has different canonical +mnemonics, so long as there is no conflict. The `info registers' +command shows the canonical names. For example, on the SPARC, `info +registers' displays the processor status register as `$psr' but you can +also refer to it as `$ps'. + + GDB always considers the contents of an ordinary register as an +integer when the register is examined in this way. Some machines have +special registers which can hold nothing but floating point; these +registers are considered to have floating point values. There is no way +to refer to the contents of an ordinary register as floating point value +(although you can *print* it as a floating point value with `print/f +$REGNAME'). + + Some registers have distinct "raw" and "virtual" data formats. This +means that the data format in which the register contents are saved by +the operating system is not the same one that your program normally +sees. For example, the registers of the 68881 floating point +coprocessor are always saved in "extended" (raw) format, but all C +programs expect to work with "double" (virtual) format. In such cases, +GDB normally works with the virtual format only (the format that makes +sense for your program), but the `info registers' command prints the +data in both formats. + + Normally, register values are relative to the selected stack frame +(*note Selecting a frame: Selection.). This means that you get the +value that the register would contain if all stack frames farther in +were exited and their saved registers restored. In order to see the +true contents of hardware registers, you must select the innermost +frame (with `frame 0'). + + However, GDB must deduce where registers are saved, from the machine +code generated by your compiler. If some registers are not saved, or if +GDB is unable to locate the saved registers, the selected stack frame +will make no difference. + +`set rstack_high_address ADDRESS' + On AMD 29000 family processors, registers are saved in a separate + "register stack". There is no way for GDB to determine the extent + of this stack. Normally, GDB just assumes that the stack is "large + enough". This may result in GDB referencing memory locations that + do not exist. If necessary, you can get around this problem by + specifying the ending address of the register stack with the `set + rstack_high_address' command. The argument should be an address, + which you will probably want to precede with `0x' to specify in + hexadecimal. + +`show rstack_high_address' + Display the current limit of the register stack, on AMD 29000 + family processors. + + ---------- Footnotes ---------- + + (1) This is a way of removing one word from the stack, on machines +where stacks grow downward in memory (most machines, nowadays). This +assumes that the innermost stack frame is selected; setting `$sp' is +not allowed when other stack frames are selected. To pop entire frames +off the stack, regardless of machine architecture, use `return'; *note +Returning from a function: Returning.. + + +File: gdb.info, Node: Floating Point Hardware, Prev: Registers, Up: Data + +Floating point hardware +======================= + + Depending on the host machine architecture, GDB may be able to give +you more information about the status of the floating point hardware. + +`info float' + Display hardware-dependent information about the floating point + unit. The exact contents and layout vary depending on the + floating point chip; on some platforms, `info float' is not + available at all. + + +File: gdb.info, Node: Languages, Next: Symbols, Prev: Data, Up: Top + +Using GDB with Different Languages +********************************** + + Although programming languages generally have common aspects, they +are rarely expressed in the same manner. For instance, in ANSI C, +dereferencing a pointer `p' is accomplished by `*p', but in Modula-2, +it is accomplished by `p^'. Values can also be represented (and +displayed) differently. Hex numbers in C are written like `0x1ae', +while in Modula-2 they appear as `1AEH'. + + Language-specific information is built into GDB for some languages, +allowing you to express operations like the above in your program's +native language, and allowing GDB to output values in a manner +consistent with the syntax of your program's native language. The +language you use to build expressions, called the "working language", +can be selected manually, or GDB can set it automatically. + +* Menu: + +* Setting:: Switching between source languages +* Show:: Displaying the language + +* Checks:: Type and range checks + +* Support:: Supported languages + + +File: gdb.info, Node: Setting, Next: Show, Up: Languages + +Switching between source languages +================================== + + There are two ways to control the working language--either have GDB +set it automatically, or select it manually yourself. You can use the +`set language' command for either purpose. On startup, GDB defaults to +setting the language automatically. + +* Menu: + +* Manually:: Setting the working language manually +* Automatically:: Having GDB infer the source language + + +File: gdb.info, Node: Manually, Next: Automatically, Up: Setting + +Setting the working language +---------------------------- + + If you allow GDB to set the language automatically, expressions are +interpreted the same way in your debugging session and your program. + + If you wish, you may set the language manually. To do this, issue +the command `set language LANG', where LANG is the name of a language, +such as `c' or `modula-2'. For a list of the supported languages, type +`set language'. + + Setting the language manually prevents GDB from updating the working +language automatically. This can lead to confusion if you try to debug +a program when the working language is not the same as the source +language, when an expression is acceptable to both languages--but means +different things. For instance, if the current source file were +written in C, and GDB was parsing Modula-2, a command such as: + + print a = b + c + +might not have the effect you intended. In C, this means to add `b' +and `c' and place the result in `a'. The result printed would be the +value of `a'. In Modula-2, this means to compare `a' to the result of +`b+c', yielding a `BOOLEAN' value. + + +File: gdb.info, Node: Automatically, Prev: Manually, Up: Setting + +Having GDB infer the source language +------------------------------------ + + To have GDB set the working language automatically, use `set +language local' or `set language auto'. GDB then infers the language +that a program was written in by looking at the name of its source +files, and examining their extensions: + +`*.mod' + Modula-2 source file + +`*.c' + C source file + +`*.C' +`*.cc' + C++ source file + + This information is recorded for each function or procedure in a +source file. When your program stops in a frame (usually by +encountering a breakpoint), GDB sets the working language to the +language recorded for the function in that frame. If the language for +a frame is unknown (that is, if the function or block corresponding to +the frame was defined in a source file that does not have a recognized +extension), the current working language is not changed, and GDB issues +a warning. + + This may not seem necessary for most programs, which are written +entirely in one source language. However, program modules and libraries +written in one source language can be used by a main program written in +a different source language. Using `set language auto' in this case +frees you from having to set the working language manually. + + +File: gdb.info, Node: Show, Next: Checks, Prev: Setting, Up: Languages + +Displaying the language +======================= + + The following commands will help you find out which language is the +working language, and also what language source files were written in. + +`show language' + Display the current working language. This is the language you + can use with commands such as `print' to build and compute + expressions that may involve variables in your program. + +`info frame' + Among the other information listed here (*note Information about a + frame: Frame Info.) is the source language for this frame. This + is the language that will become the working language if you ever + use an identifier that is in this frame. + +`info source' + Among the other information listed here (*note Examining the + Symbol Table: Symbols.) is the source language of this source file. + + +File: gdb.info, Node: Checks, Next: Support, Prev: Show, Up: Languages + +Type and range checking +======================= + + *Warning:* In this release, the GDB commands for type and range + checking are included, but they do not yet have any effect. This + section documents the intended facilities. + + Some languages are designed to guard you against making seemingly +common errors through a series of compile- and run-time checks. These +include checking the type of arguments to functions and operators, and +making sure mathematical overflows are caught at run time. Checks such +as these help to ensure a program's correctness once it has been +compiled by eliminating type mismatches, and providing active checks +for range errors when your program is running. + + GDB can check for conditions like the above if you wish. Although +GDB will not check the statements in your program, it can check +expressions entered directly into GDB for evaluation via the `print' +command, for example. As with the working language, GDB can also +decide whether or not to check automatically based on your program's +source language. *Note Supported languages: Support, for the default +settings of supported languages. + +* Menu: + +* Type Checking:: An overview of type checking +* Range Checking:: An overview of range checking + + +File: gdb.info, Node: Type Checking, Next: Range Checking, Up: Checks + +An overview of type checking +---------------------------- + + Some languages, such as Modula-2, are strongly typed, meaning that +the arguments to operators and functions have to be of the correct type, +otherwise an error occurs. These checks prevent type mismatch errors +from ever causing any run-time problems. For example, + + 1 + 2 => 3 +but + error--> 1 + 2.3 + + The second example fails because the `CARDINAL' 1 is not +type-compatible with the `REAL' 2.3. + + For expressions you use in GDB commands, you can tell the GDB type +checker to skip checking; to treat any mismatches as errors and abandon +the expression; or only issue warnings when type mismatches occur, but +evaluate the expression anyway. When you choose the last of these, GDB +evaluates expressions like the second example above, but also issues a +warning. + + Even though you may turn type checking off, other type-based reasons +may prevent GDB from evaluating an expression. For instance, GDB does +not know how to add an `int' and a `struct foo'. These particular type +errors have nothing to do with the language in use, and usually arise +from expressions, such as the one described above, which make little +sense to evaluate anyway. + + Each language defines to what degree it is strict about type. For +instance, both Modula-2 and C require the arguments to arithmetical +operators to be numbers. In C, enumerated types and pointers can be +represented as numbers, so that they are valid arguments to mathematical +operators. *Note Supported languages: Support, for further details on +specific languages. + + GDB provides some additional commands for controlling the type +checker: + +`set check type auto' + Set type checking on or off based on the current working language. + *Note Supported languages: Support, for the default settings for + each language. + +`set check type on' +`set check type off' + Set type checking on or off, overriding the default setting for the + current working language. Issue a warning if the setting does not + match the language default. If any type mismatches occur in + evaluating an expression while typechecking is on, GDB prints a + message and aborts evaluation of the expression. + +`set check type warn' + Cause the type checker to issue warnings, but to always attempt to + evaluate the expression. Evaluating the expression may still be + impossible for other reasons. For example, GDB cannot add numbers + and structures. + +`show type' + Show the current setting of the type checker, and whether or not + GDB is setting it automatically. + + +File: gdb.info, Node: Range Checking, Prev: Type Checking, Up: Checks + +An overview of range checking +----------------------------- + + In some languages (such as Modula-2), it is an error to exceed the +bounds of a type; this is enforced with run-time checks. Such range +checking is meant to ensure program correctness by making sure +computations do not overflow, or indices on an array element access do +not exceed the bounds of the array. + + For expressions you use in GDB commands, you can tell GDB to treat +range errors in one of three ways: ignore them, always treat them as +errors and abandon the expression, or issue warnings but evaluate the +expression anyway. + + A range error can result from numerical overflow, from exceeding an +array index bound, or when you type a constant that is not a member of +any type. Some languages, however, do not treat overflows as an error. +In many implementations of C, mathematical overflow causes the result +to "wrap around" to lower values--for example, if M is the largest +integer value, and S is the smallest, then + + M + 1 => S + + This, too, is specific to individual languages, and in some cases +specific to individual compilers or machines. *Note Supported +languages: Support, for further details on specific languages. + + GDB provides some additional commands for controlling the range +checker: + +`set check range auto' + Set range checking on or off based on the current working language. + *Note Supported languages: Support, for the default settings for + each language. + +`set check range on' +`set check range off' + Set range checking on or off, overriding the default setting for + the current working language. A warning is issued if the setting + does not match the language default. If a range error occurs, + then a message is printed and evaluation of the expression is + aborted. + +`set check range warn' + Output messages when the GDB range checker detects a range error, + but attempt to evaluate the expression anyway. Evaluating the + expression may still be impossible for other reasons, such as + accessing memory that the process does not own (a typical example + from many Unix systems). + +`show range' + Show the current setting of the range checker, and whether or not + it is being set automatically by GDB. + + +File: gdb.info, Node: Support, Prev: Checks, Up: Languages + +Supported languages +=================== + + GDB 4 supports C, C++, and Modula-2. Some GDB features may be used +in expressions regardless of the language you use: the GDB `@' and `::' +operators, and the `{type}addr' construct (*note Expressions: +Expressions.) can be used with the constructs of any supported language. + + The following sections detail to what degree each source language is +supported by GDB. These sections are not meant to be language +tutorials or references, but serve only as a reference guide to what the +GDB expression parser will accept, and what input and output formats +should look like for different languages. There are many good books +written on each of these languages; please look to these for a language +reference or tutorial. + +* Menu: + +* C:: C and C++ +* Modula-2:: Modula-2 + + +File: gdb.info, Node: C, Next: Modula-2, Up: Support + +C and C++ +--------- + + Since C and C++ are so closely related, many features of GDB apply +to both languages. Whenever this is the case, we discuss both languages +together. + + The C++ debugging facilities are jointly implemented by the GNU C++ +compiler and GDB. Therefore, to debug your C++ code effectively, you +must compile your C++ programs with the GNU C++ compiler, `g++'. + +* Menu: + +* C Operators:: C and C++ operators +* C Constants:: C and C++ constants +* Cplus expressions:: C++ expressions +* C Defaults:: Default settings for C and C++ + +* C Checks:: C and C++ type and range checks + +* Debugging C:: GDB and C +* Debugging C plus plus:: Special features for C++ + + +File: gdb.info, Node: C Operators, Next: C Constants, Up: C + +C and C++ operators +------------------- + + Operators must be defined on values of specific types. For instance, +`+' is defined on numbers, but not on structures. Operators are often +defined on groups of types. + + For the purposes of C and C++, the following definitions hold: + + * *Integral types* include `int' with any of its storage-class + specifiers; `char'; and `enum'. + + * *Floating-point types* include `float' and `double'. + + * *Pointer types* include all types defined as `(TYPE *)'. + + * *Scalar types* include all of the above. + +The following operators are supported. They are listed here in order +of increasing precedence: + +`,' + The comma or sequencing operator. Expressions in a + comma-separated list are evaluated from left to right, with the + result of the entire expression being the last expression + evaluated. + +`=' + Assignment. The value of an assignment expression is the value + assigned. Defined on scalar types. + +`OP=' + Used in an expression of the form `A OP= B', and translated to + `A = A OP B'. `OP=' and `=' have the same precendence. OP is any + one of the operators `|', `^', `&', `<<', `>>', `+', `-', `*', + `/', `%'. + +`?:' + The ternary operator. `A ? B : C' can be thought of as: if A + then B else C. A should be of an integral type. + +`||' + Logical OR. Defined on integral types. + +`&&' + Logical AND. Defined on integral types. + +`|' + Bitwise OR. Defined on integral types. + +`^' + Bitwise exclusive-OR. Defined on integral types. + +`&' + Bitwise AND. Defined on integral types. + +`==, !=' + Equality and inequality. Defined on scalar types. The value of + these expressions is 0 for false and non-zero for true. + +`<, >, <=, >=' + Less than, greater than, less than or equal, greater than or equal. + Defined on scalar types. The value of these expressions is 0 for + false and non-zero for true. + +`<<, >>' + left shift, and right shift. Defined on integral types. + +`@' + The GDB "artificial array" operator (*note Expressions: + Expressions.). + +`+, -' + Addition and subtraction. Defined on integral types, + floating-point types and pointer types. + +`*, /, %' + Multiplication, division, and modulus. Multiplication and + division are defined on integral and floating-point types. + Modulus is defined on integral types. + +`++, --' + Increment and decrement. When appearing before a variable, the + operation is performed before the variable is used in an + expression; when appearing after it, the variable's value is used + before the operation takes place. + +`*' + Pointer dereferencing. Defined on pointer types. Same precedence + as `++'. + +`&' + Address operator. Defined on variables. Same precedence as `++'. + + For debugging C++, GDB implements a use of `&' beyond what is + allowed in the C++ language itself: you can use `&(&REF)' (or, if + you prefer, simply `&&REF') to examine the address where a C++ + reference variable (declared with `&REF') is stored. + +`-' + Negative. Defined on integral and floating-point types. Same + precedence as `++'. + +`!' + Logical negation. Defined on integral types. Same precedence as + `++'. + +`~' + Bitwise complement operator. Defined on integral types. Same + precedence as `++'. + +`., ->' + Structure member, and pointer-to-structure member. For + convenience, GDB regards the two as equivalent, choosing whether + to dereference a pointer based on the stored type information. + Defined on `struct' and `union' data. + +`[]' + Array indexing. `A[I]' is defined as `*(A+I)'. Same precedence + as `->'. + +`()' + Function parameter list. Same precedence as `->'. + +`::' + C++ scope resolution operator. Defined on `struct', `union', and + `class' types. + +`::' + Doubled colons also represent the GDB scope operator (*note + Expressions: Expressions.). Same precedence as `::', above. + + +File: gdb.info, Node: C Constants, Next: Cplus expressions, Prev: C Operators, Up: C + +C and C++ constants +------------------- + + GDB allows you to express the constants of C and C++ in the +following ways: + + * Integer constants are a sequence of digits. Octal constants are + specified by a leading `0' (ie. zero), and hexadecimal constants by + a leading `0x' or `0X'. Constants may also end with a letter `l', + specifying that the constant should be treated as a `long' value. + + * Floating point constants are a sequence of digits, followed by a + decimal point, followed by a sequence of digits, and optionally + followed by an exponent. An exponent is of the form: + `e[[+]|-]NNN', where NNN is another sequence of digits. The `+' + is optional for positive exponents. + + * Enumerated constants consist of enumerated identifiers, or their + integral equivalents. + + * Character constants are a single character surrounded by single + quotes (`''), or a number--the ordinal value of the corresponding + character (usually its ASCII value). Within quotes, the single + character may be represented by a letter or by "escape sequences", + which are of the form `\NNN', where NNN is the octal representation + of the character's ordinal value; or of the form `\X', where `X' + is a predefined special character--for example, `\n' for newline. + + * String constants are a sequence of character constants surrounded + by double quotes (`"'). + + * Pointer constants are an integral value. You can also write + pointers to constants using the C operator `&'. + + * Array constants are comma-separated lists surrounded by braces `{' + and `}'; for example, `{1,2,3}' is a three-element array of + integers, `{{1,2}, {3,4}, {5,6}}' is a three-by-two array, and + `{&"hi", &"there", &"fred"}' is a three-element array of pointers. + + +File: gdb.info, Node: Cplus expressions, Next: C Defaults, Prev: C Constants, Up: C + +C++ expressions +--------------- + + GDB expression handling has a number of extensions to interpret a +significant subset of C++ expressions. + + *Warning:* Most of these extensions depend on the use of additional + debugging information in the symbol table, and thus require a rich, + extendable object code format. In particular, if your system uses + a.out, MIPS ECOFF, RS/6000 XCOFF, or Sun ELF with stabs extensions + to the symbol table, these facilities are all available. Where + the object code format is standard COFF, on the other hand, most + of the C++ support in GDB will *not* work, nor can it. For the + standard SVr4 debugging format, DWARF in ELF, the standard is + still evolving, so the C++ support in GDB is still fragile; when + this debugging format stabilizes, however, C++ support will also + be available on systems that use it. + + 1. Member function calls are allowed; you can use expressions like + + count = aml->GetOriginal(x, y) + + 2. While a member function is active (in the selected stack frame), + your expressions have the same namespace available as the member + function; that is, GDB allows implicit references to the class + instance pointer `this' following the same rules as C++. + + 3. You can call overloaded functions; GDB will resolve the function + call to the right definition, with one restriction--you must use + arguments of the type required by the function that you want to + call. GDB will not perform conversions requiring constructors or + user-defined type operators. + + 4. GDB understands variables declared as C++ references; you can use + them in expressions just as you do in C++ source--they are + automatically dereferenced. + + In the parameter list shown when GDB displays a frame, the values + of reference variables are not displayed (unlike other variables); + this avoids clutter, since references are often used for large + structures. The *address* of a reference variable is always + shown, unless you have specified `set print address off'. + + 5. GDB supports the C++ name resolution operator `::'--your + expressions can use it just as expressions in your program do. + Since one scope may be defined in another, you can use `::' + repeatedly if necessary, for example in an expression like + `SCOPE1::SCOPE2::NAME'. GDB also allows resolving name scope by + reference to source files, in both C and C++ debugging (*note + Program variables: Variables.). + + +File: gdb.info, Node: C Defaults, Next: C Checks, Prev: Cplus expressions, Up: C + +C and C++ defaults +------------------ + + If you allow GDB to set type and range checking automatically, they +both default to `off' whenever the working language changes to C or +C++. This happens regardless of whether you, or GDB, selected the +working language. + + If you allow GDB to set the language automatically, it sets the +working language to C or C++ on entering code compiled from a source +file whose name ends with `.c', `.C', or `.cc'. *Note Having GDB infer +the source language: Automatically, for further details. + + +File: gdb.info, Node: C Checks, Next: Debugging C, Prev: C Defaults, Up: C + +C and C++ type and range checks +------------------------------- + + By default, when GDB parses C or C++ expressions, type checking is +not used. However, if you turn type checking on, GDB will consider two +variables type equivalent if: + + * The two variables are structured and have the same structure, + union, or enumerated tag. + + * Two two variables have the same type name, or types that have been + declared equivalent through `typedef'. + + Range checking, if turned on, is done on mathematical operations. +Array indices are not checked, since they are often used to index a +pointer that is not itself an array. + + +File: gdb.info, Node: Debugging C, Next: Debugging C plus plus, Prev: C Checks, Up: C + +GDB and C +--------- + + The `set print union' and `show print union' commands apply to the +`union' type. When set to `on', any `union' that is inside a `struct' +or `class' will also be printed. Otherwise, it will appear as `{...}'. + + The `@' operator aids in the debugging of dynamic arrays, formed +with pointers and a memory allocation function. *Note Expressions: +Expressions. + + +File: gdb.info, Node: Debugging C plus plus, Prev: Debugging C, Up: C + +GDB features for C++ +-------------------- + + Some GDB commands are particularly useful with C++, and some are +designed specifically for use with C++. Here is a summary: + +`breakpoint menus' + When you want a breakpoint in a function whose name is overloaded, + GDB breakpoint menus help you specify which function definition + you want. *Note Breakpoint menus: Breakpoint Menus. + +`rbreak REGEX' + Setting breakpoints using regular expressions is helpful for + setting breakpoints on overloaded functions that are not members + of any special classes. *Note Setting breakpoints: Set Breaks. + +`catch EXCEPTIONS' +`info catch' + Debug C++ exception handling using these commands. *Note + Breakpoints and exceptions: Exception Handling. + +`ptype TYPENAME' + Print inheritance relationships as well as other information for + type TYPENAME. *Note Examining the Symbol Table: Symbols. + +`set print demangle' +`show print demangle' +`set print asm-demangle' +`show print asm-demangle' + Control whether C++ symbols display in their source form, both when + displaying code as C++ source and when displaying disassemblies. + *Note Print settings: Print Settings. + +`set print object' +`show print object' + Choose whether to print derived (actual) or declared types of + objects. *Note Print settings: Print Settings. + +`set print vtbl' +`show print vtbl' + Control the format for printing virtual function tables. *Note + Print settings: Print Settings. + +`Overloaded symbol names' + You can specify a particular definition of an overloaded symbol, + using the same notation that is used to declare such symbols in + C++: type `SYMBOL(TYPES)' rather than just SYMBOL. You can also + use the GDB command-line word completion facilities to list the + available choices, or to finish the type list for you. *Note + Command completion: Completion, for details on how to do this. + + +File: gdb.info, Node: Modula-2, Prev: C, Up: Support + +Modula-2 +-------- + + The extensions made to GDB to support Modula-2 only support output +from the GNU Modula-2 compiler (which is currently being developed). +Other Modula-2 compilers are not currently supported, and attempting to +debug executables produced by them will most likely result in an error +as GDB reads in the executable's symbol table. + +* Menu: + +* M2 Operators:: Built-in operators +* Built-In Func/Proc:: Built-in functions and procedures +* M2 Constants:: Modula-2 constants +* M2 Defaults:: Default settings for Modula-2 +* Deviations:: Deviations from standard Modula-2 +* M2 Checks:: Modula-2 type and range checks +* M2 Scope:: The scope operators `::' and `.' +* GDB/M2:: GDB and Modula-2 + + +File: gdb.info, Node: M2 Operators, Next: Built-In Func/Proc, Up: Modula-2 + +Operators +--------- + + Operators must be defined on values of specific types. For instance, +`+' is defined on numbers, but not on structures. Operators are often +defined on groups of types. For the purposes of Modula-2, the +following definitions hold: + + * *Integral types* consist of `INTEGER', `CARDINAL', and their + subranges. + + * *Character types* consist of `CHAR' and its subranges. + + * *Floating-point types* consist of `REAL'. + + * *Pointer types* consist of anything declared as `POINTER TO TYPE'. + + * *Scalar types* consist of all of the above. + + * *Set types* consist of `SET' and `BITSET' types. + + * *Boolean types* consist of `BOOLEAN'. + +The following operators are supported, and appear in order of +increasing precedence: + +`,' + Function argument or array index separator. + +`:=' + Assignment. The value of VAR `:=' VALUE is VALUE. + +`<, >' + Less than, greater than on integral, floating-point, or enumerated + types. + +`<=, >=' + Less than, greater than, less than or equal to, greater than or + equal to on integral, floating-point and enumerated types, or set + inclusion on set types. Same precedence as `<'. + +`=, <>, #' + Equality and two ways of expressing inequality, valid on scalar + types. Same precedence as `<'. In GDB scripts, only `<>' is + available for inequality, since `#' conflicts with the script + comment character. + +`IN' + Set membership. Defined on set types and the types of their + members. Same precedence as `<'. + +`OR' + Boolean disjunction. Defined on boolean types. + +`AND, &' + Boolean conjuction. Defined on boolean types. + +`@' + The GDB "artificial array" operator (*note Expressions: + Expressions.). + +`+, -' + Addition and subtraction on integral and floating-point types, or + union and difference on set types. + +`*' + Multiplication on integral and floating-point types, or set + intersection on set types. + +`/' + Division on floating-point types, or symmetric set difference on + set types. Same precedence as `*'. + +`DIV, MOD' + Integer division and remainder. Defined on integral types. Same + precedence as `*'. + +`-' + Negative. Defined on `INTEGER' and `REAL' data. + +`^' + Pointer dereferencing. Defined on pointer types. + +`NOT' + Boolean negation. Defined on boolean types. Same precedence as + `^'. + +`.' + `RECORD' field selector. Defined on `RECORD' data. Same + precedence as `^'. + +`[]' + Array indexing. Defined on `ARRAY' data. Same precedence as `^'. + +`()' + Procedure argument list. Defined on `PROCEDURE' objects. Same + precedence as `^'. + +`::, .' + GDB and Modula-2 scope operators. + + *Warning:* Sets and their operations are not yet supported, so GDB + will treat the use of the operator `IN', or the use of operators + `+', `-', `*', `/', `=', , `<>', `#', `<=', and `>=' on sets as an + error. + + +File: gdb.info, Node: Built-In Func/Proc, Next: M2 Constants, Prev: M2 Operators, Up: Modula-2 + +Built-in functions and procedures +--------------------------------- + + Modula-2 also makes available several built-in procedures and +functions. In describing these, the following metavariables are used: + +A + represents an `ARRAY' variable. + +C + represents a `CHAR' constant or variable. + +I + represents a variable or constant of integral type. + +M + represents an identifier that belongs to a set. Generally used in + the same function with the metavariable S. The type of S should + be `SET OF MTYPE' (where MTYPE is the type of M). + +N + represents a variable or constant of integral or floating-point + type. + +R + represents a variable or constant of floating-point type. + +T + represents a type. + +V + represents a variable. + +X + represents a variable or constant of one of many types. See the + explanation of the function for details. + + All Modula-2 built-in procedures also return a result, described +below. + +`ABS(N)' + Returns the absolute value of N. + +`CAP(C)' + If C is a lower case letter, it returns its upper case equivalent, + otherwise it returns its argument + +`CHR(I)' + Returns the character whose ordinal value is I. + +`DEC(V)' + Decrements the value in the variable V. Returns the new value. + +`DEC(V,I)' + Decrements the value in the variable V by I. Returns the new + value. + +`EXCL(M,S)' + Removes the element M from the set S. Returns the new set. + +`FLOAT(I)' + Returns the floating point equivalent of the integer I. + +`HIGH(A)' + Returns the index of the last member of A. + +`INC(V)' + Increments the value in the variable V. Returns the new value. + +`INC(V,I)' + Increments the value in the variable V by I. Returns the new + value. + +`INCL(M,S)' + Adds the element M to the set S if it is not already there. + Returns the new set. + +`MAX(T)' + Returns the maximum value of the type T. + +`MIN(T)' + Returns the minimum value of the type T. + +`ODD(I)' + Returns boolean TRUE if I is an odd number. + +`ORD(X)' + Returns the ordinal value of its argument. For example, the + ordinal value of a character is its ASCII value (on machines + supporting the ASCII character set). X must be of an ordered + type, which include integral, character and enumerated types. + +`SIZE(X)' + Returns the size of its argument. X can be a variable or a type. + +`TRUNC(R)' + Returns the integral part of R. + +`VAL(T,I)' + Returns the member of the type T whose ordinal value is I. + + *Warning:* Sets and their operations are not yet supported, so + GDB will treat the use of procedures `INCL' and `EXCL' as an error. + + +File: gdb.info, Node: M2 Constants, Next: M2 Defaults, Prev: Built-In Func/Proc, Up: Modula-2 + +Constants +--------- + + GDB allows you to express the constants of Modula-2 in the following +ways: + + * Integer constants are simply a sequence of digits. When used in an + expression, a constant is interpreted to be type-compatible with + the rest of the expression. Hexadecimal integers are specified by + a trailing `H', and octal integers by a trailing `B'. + + * Floating point constants appear as a sequence of digits, followed + by a decimal point and another sequence of digits. An optional + exponent can then be specified, in the form `E[+|-]NNN', where + `[+|-]NNN' is the desired exponent. All of the digits of the + floating point constant must be valid decimal (base 10) digits. + + * Character constants consist of a single character enclosed by a + pair of like quotes, either single (`'') or double (`"'). They may + also be expressed by their ordinal value (their ASCII value, + usually) followed by a `C'. + + * String constants consist of a sequence of characters enclosed by a + pair of like quotes, either single (`'') or double (`"'). Escape + sequences in the style of C are also allowed. *Note C and C++ + constants: C Constants, for a brief explanation of escape + sequences. + + * Enumerated constants consist of an enumerated identifier. + + * Boolean constants consist of the identifiers `TRUE' and `FALSE'. + + * Pointer constants consist of integral values only. + + * Set constants are not yet supported. + + +File: gdb.info, Node: M2 Defaults, Next: Deviations, Prev: M2 Constants, Up: Modula-2 + +Modula-2 defaults +----------------- + + If type and range checking are set automatically by GDB, they both +default to `on' whenever the working language changes to Modula-2. +This happens regardless of whether you, or GDB, selected the working +language. + + If you allow GDB to set the language automatically, then entering +code compiled from a file whose name ends with `.mod' will set the +working language to Modula-2. *Note Having GDB set the language +automatically: Automatically, for further details. + + +File: gdb.info, Node: Deviations, Next: M2 Checks, Prev: M2 Defaults, Up: Modula-2 + +Deviations from standard Modula-2 +--------------------------------- + + A few changes have been made to make Modula-2 programs easier to +debug. This is done primarily via loosening its type strictness: + + * Unlike in standard Modula-2, pointer constants can be formed by + integers. This allows you to modify pointer variables during + debugging. (In standard Modula-2, the actual address contained in + a pointer variable is hidden from you; it can only be modified + through direct assignment to another pointer variable or + expression that returned a pointer.) + + * C escape sequences can be used in strings and characters to + represent non-printable characters. GDB will print out strings + with these escape sequences embedded. Single non-printable + characters are printed using the `CHR(NNN)' format. + + * The assignment operator (`:=') returns the value of its right-hand + argument. + + * All built-in procedures both modify *and* return their argument. + + +File: gdb.info, Node: M2 Checks, Next: M2 Scope, Prev: Deviations, Up: Modula-2 + +Modula-2 type and range checks +------------------------------ + + *Warning:* in this release, GDB does not yet perform type or range + checking. + + GDB considers two Modula-2 variables type equivalent if: + + * They are of types that have been declared equivalent via a `TYPE + T1 = T2' statement + + * They have been declared on the same line. (Note: This is true of + the GNU Modula-2 compiler, but it may not be true of other + compilers.) + + As long as type checking is enabled, any attempt to combine variables +whose types are not equivalent is an error. + + Range checking is done on all mathematical operations, assignment, +array index bounds, and all built-in functions and procedures. + + +File: gdb.info, Node: M2 Scope, Next: GDB/M2, Prev: M2 Checks, Up: Modula-2 + +The scope operators `::' and `.' +-------------------------------- + + There are a few subtle differences between the Modula-2 scope +operator (`.') and the GDB scope operator (`::'). The two have similar +syntax: + + + MODULE . ID + SCOPE :: ID + +where SCOPE is the name of a module or a procedure, MODULE the name of +a module, and ID is any declared identifier within your program, except +another module. + + Using the `::' operator makes GDB search the scope specified by +SCOPE for the identifier ID. If it is not found in the specified +scope, then GDB will search all scopes enclosing the one specified by +SCOPE. + + Using the `.' operator makes GDB search the current scope for the +identifier specified by ID that was imported from the definition module +specified by MODULE. With this operator, it is an error if the +identifier ID was not imported from definition module MODULE, or if ID +is not an identifier in MODULE. + + +File: gdb.info, Node: GDB/M2, Prev: M2 Scope, Up: Modula-2 + +GDB and Modula-2 +---------------- + + Some GDB commands have little use when debugging Modula-2 programs. +Five subcommands of `set print' and `show print' apply specifically to +C and C++: `vtbl', `demangle', `asm-demangle', `object', and `union'. +The first four apply to C++, and the last to the C `union' type, which +has no direct analogue in Modula-2. + + The `@' operator (*note Expressions: Expressions.), while available +while using any language, is not useful with Modula-2. Its intent is +to aid the debugging of "dynamic arrays", which cannot be created in +Modula-2 as they can in C or C++. However, because an address can be +specified by an integral constant, the construct `{TYPE}ADREXP' is +still useful. (*note Expressions: Expressions.) + + In GDB scripts, the Modula-2 inequality operator `#' is interpreted +as the beginning of a comment. Use `<>' instead. + + +File: gdb.info, Node: Symbols, Next: Altering, Prev: Languages, Up: Top + +Examining the Symbol Table +************************** + + The commands described in this section allow you to inquire about the +symbols (names of variables, functions and types) defined in your +program. This information is inherent in the text of your program and +does not change as your program executes. GDB finds it in your +program's symbol table, in the file indicated when you started GDB +(*note Choosing files: File Options.), or by one of the file-management +commands (*note Commands to specify files: Files.). + + Occasionally, you may need to refer to symbols that contain unusual +characters, which GDB ordinarily treats as word delimiters. The most +frequent case is in referring to static variables in other source files +(*note Program variables: Variables.). File names are recorded in +object files as debugging symbols, but GDB would ordinarily parse a +typical file name, like `foo.c', as the three words `foo' `.' `c'. To +allow GDB to recognize `foo.c' as a single symbol, enclose it in single +quotes; for example, + + p 'foo.c'::x + +looks up the value of `x' in the scope of the file `foo.c'. + +`info address SYMBOL' + Describe where the data for SYMBOL is stored. For a register + variable, this says which register it is kept in. For a + non-register local variable, this prints the stack-frame offset at + which the variable is always stored. + + Note the contrast with `print &SYMBOL', which does not work at all + for a register variable, and for a stack local variable prints the + exact address of the current instantiation of the variable. + +`whatis EXP' + Print the data type of expression EXP. EXP is not actually + evaluated, and any side-effecting operations (such as assignments + or function calls) inside it do not take place. *Note + Expressions: Expressions. + +`whatis' + Print the data type of `$', the last value in the value history. + +`ptype TYPENAME' + Print a description of data type TYPENAME. TYPENAME may be the + name of a type, or for C code it may have the form `class + CLASS-NAME', `struct STRUCT-TAG', `union UNION-TAG' or `enum + ENUM-TAG'. + +`ptype EXP' +`ptype' + Print a description of the type of expression EXP. `ptype' + differs from `whatis' by printing a detailed description, instead + of just the name of the type. + + For example, for this variable declaration: + + struct complex {double real; double imag;} v; + + the two commands give this output: + + (gdb) whatis v + type = struct complex + (gdb) ptype v + type = struct complex { + double real; + double imag; + } + + As with `whatis', using `ptype' without an argument refers to the + type of `$', the last value in the value history. + +`info types REGEXP' +`info types' + Print a brief description of all types whose name matches REGEXP + (or all types in your program, if you supply no argument). Each + complete typename is matched as though it were a complete line; + thus, `i type value' gives information on all types in your + program whose name includes the string `value', but `i type + ^value$' gives information only on types whose complete name is + `value'. + + This command differs from `ptype' in two ways: first, like + `whatis', it does not print a detailed description; second, it + lists all source files where a type is defined. + +`info source' + Show the name of the current source file--that is, the source file + for the function containing the current point of execution--and + the language it was written in. + +`info sources' + Print the names of all source files in your program for which + there is debugging information, organized into two lists: files + whose symbols have already been read, and files whose symbols will + be read when needed. + +`info functions' + Print the names and data types of all defined functions. + +`info functions REGEXP' + Print the names and data types of all defined functions whose + names contain a match for regular expression REGEXP. Thus, `info + fun step' finds all functions whose names include `step'; `info + fun ^step' finds those whose names start with `step'. + +`info variables' + Print the names and data types of all variables that are declared + outside of functions (i.e., excluding local variables). + +`info variables REGEXP' + Print the names and data types of all variables (except for local + variables) whose names contain a match for regular expression + REGEXP. + +`maint print symbols FILENAME' +`maint print psymbols FILENAME' +`maint print msymbols FILENAME' + Write a dump of debugging symbol data into the file FILENAME. + These commands are used to debug the GDB symbol-reading code. Only + symbols with debugging data are included. If you use `maint print + symbols', GDB includes all the symbols for which it has already + collected full details: that is, FILENAME reflects symbols for + only those files whose symbols GDB has read. You can use the + command `info sources' to find out which files these are. If you + use `maint print psymbols' instead, the dump shows information + about symbols that GDB only knows partially--that is, symbols + defined in files that GDB has skimmed, but not yet read + completely. Finally, `maint print msymbols' dumps just the + minimal symbol information required for each object file from + which GDB has read some symbols. *Note Commands to specify files: + Files, for a discussion of how GDB reads symbols (in the + description of `symbol-file'). + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-5 b/gnu/usr.bin/gdb/doc/gdb.info-5 new file mode 100644 index 00000000000..ecf3d18b96f --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-5 @@ -0,0 +1,1215 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Altering, Next: GDB Files, Prev: Symbols, Up: Top + +Altering Execution +****************** + + Once you think you have found an error in your program, you might +want to find out for certain whether correcting the apparent error +would lead to correct results in the rest of the run. You can find the +answer by experiment, using the GDB features for altering execution of +the program. + + For example, you can store new values into variables or memory +locations, give your program a signal, restart it at a different +address, or even return prematurely from a function to its caller. + +* Menu: + +* Assignment:: Assignment to variables +* Jumping:: Continuing at a different address + +* Signaling:: Giving your program a signal + +* Returning:: Returning from a function +* Calling:: Calling your program's functions +* Patching:: Patching your program + + +File: gdb.info, Node: Assignment, Next: Jumping, Up: Altering + +Assignment to variables +======================= + + To alter the value of a variable, evaluate an assignment expression. +*Note Expressions: Expressions. For example, + + print x=4 + +stores the value 4 into the variable `x', and then prints the value of +the assignment expression (which is 4). *Note Using GDB with Different +Languages: Languages, for more information on operators in supported +languages. + + If you are not interested in seeing the value of the assignment, use +the `set' command instead of the `print' command. `set' is really the +same as `print' except that the expression's value is not printed and +is not put in the value history (*note Value history: Value History.). +The expression is evaluated only for its effects. + + If the beginning of the argument string of the `set' command appears +identical to a `set' subcommand, use the `set variable' command instead +of just `set'. This command is identical to `set' except for its lack +of subcommands. For example, if your program has a variable `width', +you get an error if you try to set a new value with just `set width=13', +because GDB has the command `set width': + + (gdb) whatis width + type = double + (gdb) p width + $4 = 13 + (gdb) set width=47 + Invalid syntax in expression. + +The invalid expression, of course, is `=47'. In order to actually set +the program's variable `width', use + + (gdb) set var width=47 + + GDB allows more implicit conversions in assignments than C; you can +freely store an integer value into a pointer variable or vice versa, +and you can convert any structure to any other structure that is the +same length or shorter. + + To store values into arbitrary places in memory, use the `{...}' +construct to generate a value of specified type at a specified address +(*note Expressions: Expressions.). For example, `{int}0x83040' refers +to memory location `0x83040' as an integer (which implies a certain size +and representation in memory), and + + set {int}0x83040 = 4 + +stores the value 4 into that memory location. + + +File: gdb.info, Node: Jumping, Next: Signaling, Prev: Assignment, Up: Altering + +Continuing at a different address +================================= + + Ordinarily, when you continue your program, you do so at the place +where it stopped, with the `continue' command. You can instead +continue at an address of your own choosing, with the following +commands: + +`jump LINESPEC' + Resume execution at line LINESPEC. Execution will stop + immediately if there is a breakpoint there. *Note Printing source + lines: List, for a description of the different forms of LINESPEC. + + The `jump' command does not change the current stack frame, or the + stack pointer, or the contents of any memory location or any + register other than the program counter. If line LINESPEC is in a + different function from the one currently executing, the results + may be bizarre if the two functions expect different patterns of + arguments or of local variables. For this reason, the `jump' + command requests confirmation if the specified line is not in the + function currently executing. However, even bizarre results are + predictable if you are well acquainted with the machine-language + code of your program. + +`jump *ADDRESS' + Resume execution at the instruction at address ADDRESS. + + You can get much the same effect as the `jump' command by storing a +new value into the register `$pc'. The difference is that this does +not start your program running; it only changes the address where it +*will* run when it is continued. For example, + + set $pc = 0x485 + +causes the next `continue' command or stepping command to execute at +address `0x485', rather than at the address where your program stopped. +*Note Continuing and stepping: Continuing and Stepping. + + The most common occasion to use the `jump' command is to back up, +perhaps with more breakpoints set, over a portion of a program that has +already executed, in order to examine its execution in more detail. + + +File: gdb.info, Node: Signaling, Next: Returning, Prev: Jumping, Up: Altering + +Giving your program a signal +============================ + +`signal SIGNAL' + Resume execution where your program stopped, but immediately give + it the signal SIGNAL. SIGNAL can be the name or the number of a + signal. For example, on many systems `signal 2' and `signal + SIGINT' are both ways of sending an interrupt signal. + + Alternatively, if SIGNAL is zero, continue execution without + giving a signal. This is useful when your program stopped on + account of a signal and would ordinary see the signal when resumed + with the `continue' command; `signal 0' causes it to resume + without a signal. + + `signal' does not repeat when you press RET a second time after + executing the command. + + Invoking the `signal' command is not the same as invoking the `kill' +utility from the shell. Sending a signal with `kill' causes GDB to +decide what to do with the signal depending on the signal handling +tables (*note Signals::.). The `signal' command passes the signal +directly to your program. + + +File: gdb.info, Node: Returning, Next: Calling, Prev: Signaling, Up: Altering + +Returning from a function +========================= + +`return' +`return EXPRESSION' + You can cancel execution of a function call with the `return' + command. If you give an EXPRESSION argument, its value is used as + the function's return value. + + When you use `return', GDB discards the selected stack frame (and +all frames within it). You can think of this as making the discarded +frame return prematurely. If you wish to specify a value to be +returned, give that value as the argument to `return'. + + This pops the selected stack frame (*note Selecting a frame: +Selection.), and any other frames inside of it, leaving its caller as +the innermost remaining frame. That frame becomes selected. The +specified value is stored in the registers used for returning values of +functions. + + The `return' command does not resume execution; it leaves the +program stopped in the state that would exist if the function had just +returned. In contrast, the `finish' command (*note Continuing and +stepping: Continuing and Stepping.) resumes execution until the +selected stack frame returns naturally. + + +File: gdb.info, Node: Calling, Next: Patching, Prev: Returning, Up: Altering + +Calling program functions +========================= + +`call EXPR' + Evaluate the expression EXPR without displaying `void' returned + values. + + You can use this variant of the `print' command if you want to +execute a function from your program, but without cluttering the output +with `void' returned values. The result is printed and saved in the +value history, if it is not void. + + +File: gdb.info, Node: Patching, Prev: Calling, Up: Altering + +Patching programs +================= + + By default, GDB opens the file containing your program's executable +code (or the corefile) read-only. This prevents accidental alterations +to machine code; but it also prevents you from intentionally patching +your program's binary. + + If you'd like to be able to patch the binary, you can specify that +explicitly with the `set write' command. For example, you might want +to turn on internal debugging flags, or even to make emergency repairs. + +`set write on' +`set write off' + If you specify `set write on', GDB will open executable and core + files for both reading and writing; if you specify `set write off' + (the default), GDB will open them read-only. + + If you have already loaded a file, you must load it again (using + the `exec-file' or `core-file' command) after changing `set + write', for your new setting to take effect. + +`show write' + Display whether executable files and core files will be opened for + writing as well as reading. + + +File: gdb.info, Node: GDB Files, Next: Targets, Prev: Altering, Up: Top + +GDB Files +********* + + GDB needs to know the file name of the program to be debugged, both +in order to read its symbol table and in order to start your program. +To debug a core dump of a previous run, you must also tell GDB the name +of the core dump file. + +* Menu: + +* Files:: Commands to specify files +* Symbol Errors:: Errors reading symbol files + + +File: gdb.info, Node: Files, Next: Symbol Errors, Up: GDB Files + +Commands to specify files +========================= + + The usual way to specify executable and core dump file names is with +the command arguments given when you start GDB (*note Getting In and +Out of GDB: Invocation.. + + Occasionally it is necessary to change to a different file during a +GDB session. Or you may run GDB and forget to specify a file you want +to use. In these situations the GDB commands to specify new files are +useful. + +`file FILENAME' + Use FILENAME as the program to be debugged. It is read for its + symbols and for the contents of pure memory. It is also the + program executed when you use the `run' command. If you do not + specify a directory and the file is not found in the GDB working + directory, GDB uses the environment variable `PATH' as a list of + directories to search, just as the shell does when looking for a + program to run. You can change the value of this variable, for + both GDB and your program, using the `path' command. + + On systems with memory-mapped files, an auxiliary symbol table file + `FILENAME.syms' may be available for FILENAME. If it is, GDB will + map in the symbol table from `FILENAME.syms', starting up more + quickly. See the descriptions of the options `-mapped' and + `-readnow' (available on the command line, and with the commands + `file', `symbol-file', or `add-symbol-file'), for more information. + +`file' + `file' with no argument makes GDB discard any information it has + on both executable file and the symbol table. + +`exec-file [ FILENAME ]' + Specify that the program to be run (but not the symbol table) is + found in FILENAME. GDB will search the environment variable `PATH' + if necessary to locate your program. Omitting FILENAME means to + discard information on the executable file. + +`symbol-file [ FILENAME ]' + Read symbol table information from file FILENAME. `PATH' is + searched when necessary. Use the `file' command to get both symbol + table and program to run from the same file. + + `symbol-file' with no argument clears out GDB information on your + program's symbol table. + + The `symbol-file' command causes GDB to forget the contents of its + convenience variables, the value history, and all breakpoints and + auto-display expressions. This is because they may contain + pointers to the internal data recording symbols and data types, + which are part of the old symbol table data being discarded inside + GDB. + + `symbol-file' will not repeat if you press RET again after + executing it once. + + When GDB is configured for a particular environment, it will + understand debugging information in whatever format is the standard + generated for that environment; you may use either a GNU compiler, + or other compilers that adhere to the local conventions. Best + results are usually obtained from GNU compilers; for example, + using `gcc' you can generate debugging information for optimized + code. + + On some kinds of object files, the `symbol-file' command does not + normally read the symbol table in full right away. Instead, it + scans the symbol table quickly to find which source files and + which symbols are present. The details are read later, one source + file at a time, as they are needed. + + The purpose of this two-stage reading strategy is to make GDB + start up faster. For the most part, it is invisible except for + occasional pauses while the symbol table details for a particular + source file are being read. (The `set verbose' command can turn + these pauses into messages if desired. *Note Optional warnings + and messages: Messages/Warnings.) + + We have not implemented the two-stage strategy for COFF yet. When + the symbol table is stored in COFF format, `symbol-file' reads the + symbol table data in full right away. + +`symbol-file FILENAME [ -readnow ] [ -mapped ]' +`file FILENAME [ -readnow ] [ -mapped ]' + You can override the GDB two-stage strategy for reading symbol + tables by using the `-readnow' option with any of the commands that + load symbol table information, if you want to be sure GDB has the + entire symbol table available. + + If memory-mapped files are available on your system through the + `mmap' system call, you can use another option, `-mapped', to + cause GDB to write the symbols for your program into a reusable + file. Future GDB debugging sessions will map in symbol information + from this auxiliary symbol file (if the program has not changed), + rather than spending time reading the symbol table from the + executable program. Using the `-mapped' option has the same + effect as starting GDB with the `-mapped' command-line option. + + You can use both options together, to make sure the auxiliary + symbol file has all the symbol information for your program. + + The auxiliary symbol file for a program called MYPROG is called + `MYPROG.syms'. Once this file exists (so long as it is newer than + the corresponding executable), GDB will always attempt to use it + when you debug MYPROG; no special options or commands are needed. + + The `.syms' file is specific to the host machine where you run + GDB. It holds an exact image of the internal GDB symbol table. + It cannot be shared across multiple host platforms. + +`core-file [ FILENAME ]' + Specify the whereabouts of a core dump file to be used as the + "contents of memory". Traditionally, core files contain only some + parts of the address space of the process that generated them; GDB + can access the executable file itself for other parts. + + `core-file' with no argument specifies that no core file is to be + used. + + Note that the core file is ignored when your program is actually + running under GDB. So, if you have been running your program and + you wish to debug a core file instead, you must kill the + subprocess in which the program is running. To do this, use the + `kill' command (*note Killing the child process: Kill Process.). + +`load FILENAME' + Depending on what remote debugging facilities are configured into + GDB, the `load' command may be available. Where it exists, it is + meant to make FILENAME (an executable) available for debugging on + the remote system--by downloading, or dynamic linking, for example. + `load' also records the FILENAME symbol table in GDB, like the + `add-symbol-file' command. + + If your GDB does not have a `load' command, attempting to execute + it gets the error message "`You can't do that when your target is + ...'" + + The file is loaded at whatever address is specified in the + executable. For some object file formats, like a.out, the object + file format fixes the address and so it won't necessarily match + the address you gave to the linker. + + On VxWorks, `load' will dynamically link FILENAME on the current + target system as well as adding its symbols in GDB. + + With the Nindy interface to an Intel 960 board, `load' will + download FILENAME to the 960 as well as adding its symbols in GDB. + + When you select remote debugging to a Hitachi SH, H8/300, or + H8/500 board (*note GDB and Hitachi Microprocessors: Hitachi + Remote.), the `load' command downloads your program to the Hitachi + board and also opens it as the current executable target for GDB + on your host (like the `file' command). + + `load' will not repeat if you press RET again after using it. + +`add-symbol-file FILENAME ADDRESS' +`add-symbol-file FILENAME ADDRESS [ -readnow ] [ -mapped ]' + The `add-symbol-file' command reads additional symbol table + information from the file FILENAME. You would use this command + when FILENAME has been dynamically loaded (by some other means) + into the program that is running. ADDRESS should be the memory + address at which the file has been loaded; GDB cannot figure this + out for itself. You can specify ADDRESS as an expression. + + The symbol table of the file FILENAME is added to the symbol table + originally read with the `symbol-file' command. You can use the + `add-symbol-file' command any number of times; the new symbol data + thus read keeps adding to the old. To discard all old symbol data + instead, use the `symbol-file' command. + + `add-symbol-file' will not repeat if you press RET after using it. + + You can use the `-mapped' and `-readnow' options just as with the + `symbol-file' command, to change how GDB manages the symbol table + information for FILENAME. + +`info files' +`info target' + `info files' and `info target' are synonymous; both print the + current target (*note Specifying a Debugging Target: Targets.), + including the names of the executable and core dump files + currently in use by GDB, and the files from which symbols were + loaded. The command `help targets' lists all possible targets + rather than current ones. + + All file-specifying commands allow both absolute and relative file +names as arguments. GDB always converts the file name to an absolute +path name and remembers it that way. + + GDB supports SunOS, SVR4, and IBM RS/6000 shared libraries. GDB +automatically loads symbol definitions from shared libraries when you +use the `run' command, or when you examine a core file. (Before you +issue the `run' command, GDB will not understand references to a +function in a shared library, however--unless you are debugging a core +file). + +`info share' +`info sharedlibrary' + Print the names of the shared libraries which are currently loaded. + +`sharedlibrary REGEX' +`share REGEX' + This is an obsolescent command; you can use it to explicitly load + shared object library symbols for files matching a Unix regular + expression, but as with files loaded automatically, it will only + load shared libraries required by your program for a core file or + after typing `run'. If REGEX is omitted all shared libraries + required by your program are loaded. + + +File: gdb.info, Node: Symbol Errors, Prev: Files, Up: GDB Files + +Errors reading symbol files +=========================== + + While reading a symbol file, GDB will occasionally encounter +problems, such as symbol types it does not recognize, or known bugs in +compiler output. By default, GDB does not notify you of such problems, +since they are relatively common and primarily of interest to people +debugging compilers. If you are interested in seeing information about +ill-constructed symbol tables, you can either ask GDB to print only one +message about each such type of problem, no matter how many times the +problem occurs; or you can ask GDB to print more messages, to see how +many times the problems occur, with the `set complaints' command (*note +Optional warnings and messages: Messages/Warnings.). + + The messages currently printed, and their meanings, include: + +`inner block not inside outer block in SYMBOL' + The symbol information shows where symbol scopes begin and end + (such as at the start of a function or a block of statements). + This error indicates that an inner scope block is not fully + contained in its outer scope blocks. + + GDB circumvents the problem by treating the inner block as if it + had the same scope as the outer block. In the error message, + SYMBOL may be shown as "`(don't know)'" if the outer block is not a + function. + +`block at ADDRESS out of order' + The symbol information for symbol scope blocks should occur in + order of increasing addresses. This error indicates that it does + not do so. + + GDB does not circumvent this problem, and will have trouble + locating symbols in the source file whose symbols it is reading. + (You can often determine what source file is affected by specifying + `set verbose on'. *Note Optional warnings and messages: + Messages/Warnings.) + +`bad block start address patched' + The symbol information for a symbol scope block has a start address + smaller than the address of the preceding source line. This is + known to occur in the SunOS 4.1.1 (and earlier) C compiler. + + GDB circumvents the problem by treating the symbol scope block as + starting on the previous source line. + +`bad string table offset in symbol N' + Symbol number N contains a pointer into the string table which is + larger than the size of the string table. + + GDB circumvents the problem by considering the symbol to have the + name `foo', which may cause other problems if many symbols end up + with this name. + +`unknown symbol type `0xNN'' + The symbol information contains new data types that GDB does not + yet know how to read. `0xNN' is the symbol type of the + misunderstood information, in hexadecimal. + + GDB circumvents the error by ignoring this symbol information. + This will usually allow your program to be debugged, though + certain symbols will not be accessible. If you encounter such a + problem and feel like debugging it, you can debug `gdb' with + itself, breakpoint on `complain', then go up to the function + `read_dbx_symtab' and examine `*bufp' to see the symbol. + +`stub type has NULL name' + GDB could not find the full definition for a struct or class. + +`const/volatile indicator missing (ok if using g++ v1.x), got...' + The symbol information for a C++ member function is missing some + information that recent versions of the compiler should have output + for it. + +`info mismatch between compiler and debugger' + GDB could not parse a type specification output by the compiler. + + +File: gdb.info, Node: Targets, Next: Controlling GDB, Prev: GDB Files, Up: Top + +Specifying a Debugging Target +***************************** + + A "target" is the execution environment occupied by your program. +Often, GDB runs in the same host environment as your program; in that +case, the debugging target is specified as a side effect when you use +the `file' or `core' commands. When you need more flexibility--for +example, running GDB on a physically separate host, or controlling a +standalone system over a serial port or a realtime system over a TCP/IP +connection--you can use the `target' command to specify one of the +target types configured for GDB (*note Commands for managing targets: +Target Commands.). + +* Menu: + +* Active Targets:: Active targets +* Target Commands:: Commands for managing targets +* Remote:: Remote debugging + + +File: gdb.info, Node: Active Targets, Next: Target Commands, Up: Targets + +Active targets +============== + + There are three classes of targets: processes, core files, and +executable files. GDB can work concurrently on up to three active +targets, one in each class. This allows you to (for example) start a +process and inspect its activity without abandoning your work on a core +file. + + For example, if you execute `gdb a.out', then the executable file +`a.out' is the only active target. If you designate a core file as +well--presumably from a prior run that crashed and coredumped--then GDB +has two active targets and will use them in tandem, looking first in +the corefile target, then in the executable file, to satisfy requests +for memory addresses. (Typically, these two classes of target are +complementary, since core files contain only a program's read-write +memory--variables and so on--plus machine status, while executable +files contain only the program text and initialized data.) + + When you type `run', your executable file becomes an active process +target as well. When a process target is active, all GDB commands +requesting memory addresses refer to that target; addresses in an +active core file or executable file target are obscured while the +process target is active. + + Use the `core-file' and `exec-file' commands to select a new core +file or executable target (*note Commands to specify files: Files.). +To specify as a target a process that is already running, use the +`attach' command (*note Debugging an already-running process: Attach.). + + +File: gdb.info, Node: Target Commands, Next: Remote, Prev: Active Targets, Up: Targets + +Commands for managing targets +============================= + +`target TYPE PARAMETERS' + Connects the GDB host environment to a target machine or process. + A target is typically a protocol for talking to debugging + facilities. You use the argument TYPE to specify the type or + protocol of the target machine. + + Further PARAMETERS are interpreted by the target protocol, but + typically include things like device names or host names to connect + with, process numbers, and baud rates. + + The `target' command will not repeat if you press RET again after + executing the command. + +`help target' + Displays the names of all targets available. To display targets + currently selected, use either `info target' or `info files' + (*note Commands to specify files: Files.). + +`help target NAME' + Describe a particular target, including any parameters necessary to + select it. + + Here are some common targets (available, or not, depending on the GDB +configuration): + +`target exec PROGRAM' + An executable file. `target exec PROGRAM' is the same as + `exec-file PROGRAM'. + +`target core FILENAME' + A core dump file. `target core FILENAME' is the same as + `core-file FILENAME'. + +`target remote DEV' + Remote serial target in GDB-specific protocol. The argument DEV + specifies what serial device to use for the connection (e.g. + `/dev/ttya'). *Note Remote debugging: Remote. + +`target sim' + CPU simulator. *Note Simulated CPU Target: Simulator. + +`target udi KEYWORD' + Remote AMD29K target, using the AMD UDI protocol. The KEYWORD + argument specifies which 29K board or simulator to use. *Note GDB + and the UDI protocol for AMD29K: UDI29K Remote. + +`target amd-eb DEV SPEED PROG' + Remote PC-resident AMD EB29K board, attached over serial lines. + dEV is the serial device, as for `target remote'; SPEED allows you + to specify the linespeed; and PROG is the name of the program to + be debugged, as it appears to DOS on the PC. *Note GDB with a + remote EB29K: EB29K Remote. + +`target hms' + A Hitachi SH, H8/300, or H8/500 board, attached via serial line to + your host. Use special commands `device' and `speed' to control + the serial line and the communications speed used. *Note GDB and + Hitachi Microprocessors: Hitachi Remote. + +`target nindy DEVICENAME' + An Intel 960 board controlled by a Nindy Monitor. DEVICENAME is + the name of the serial device to use for the connection, e.g. + `/dev/ttya'. *Note GDB with a remote i960 (Nindy): i960-Nindy + Remote. + +`target st2000 DEV SPEED' + A Tandem ST2000 phone switch, running Tandem's STDBUG protocol. + dEV is the name of the device attached to the ST2000 serial line; + SPEED is the communication line speed. The arguments are not used + if GDB is configured to connect to the ST2000 using TCP or Telnet. + *Note GDB with a Tandem ST2000: ST2000 Remote. + +`target vxworks MACHINENAME' + A VxWorks system, attached via TCP/IP. The argument MACHINENAME + is the target system's machine name or IP address. *Note GDB and + VxWorks: VxWorks Remote. + + Different targets are available on different configurations of GDB; +your configuration may have more or fewer targets. + + +File: gdb.info, Node: Remote, Prev: Target Commands, Up: Targets + +Remote debugging +================ + + If you are trying to debug a program running on a machine that +cannot run GDB in the usual way, it is often useful to use remote +debugging. For example, you might use remote debugging on an operating +system kernel, or on a small system which does not have a general +purpose operating system powerful enough to run a full-featured +debugger. + + Some configurations of GDB have special serial or TCP/IP interfaces +to make this work with particular debugging targets. In addition, GDB +comes with a generic serial protocol (specific to GDB, but not specific +to any particular target system) which you can use if you write the +remote stubs--the code that will run on the remote system to +communicate with GDB. + + Other remote targets may be available in your configuration of GDB; +use `help targets' to list them. + +* Menu: + + +* Remote Serial:: GDB remote serial protocol + +* i960-Nindy Remote:: GDB with a remote i960 (Nindy) + +* UDI29K Remote:: GDB and the UDI protocol for AMD29K +* EB29K Remote:: GDB with a remote EB29K + +* VxWorks Remote:: GDB and VxWorks + +* ST2000 Remote:: GDB with a Tandem ST2000 + +* Hitachi Remote:: GDB and Hitachi Microprocessors + +* MIPS Remote:: GDB and MIPS boards + +* Simulator:: Simulated CPU target + + +File: gdb.info, Node: Remote Serial, Next: i960-Nindy Remote, Up: Remote + +The GDB remote serial protocol +------------------------------ + + To debug a program running on another machine (the debugging +"target" machine), you must first arrange for all the usual +prerequisites for the program to run by itself. For example, for a C +program, you need + + 1. A startup routine to set up the C runtime environment; these + usually have a name like `crt0'. The startup routine may be + supplied by your hardware supplier, or you may have to write your + own. + + 2. You probably need a C subroutine library to support your program's + subroutine calls, notably managing input and output. + + 3. A way of getting your program to the other machine--for example, a + download program. These are often supplied by the hardware + manufacturer, but you may have to write your own from hardware + documentation. + + The next step is to arrange for your program to use a serial port to +communicate with the machine where GDB is running (the "host" machine). +In general terms, the scheme looks like this: + +*On the host,* + GDB already understands how to use this protocol; when everything + else is set up, you can simply use the `target remote' command + (*note Specifying a Debugging Target: Targets.). + +*On the target,* + you must link with your program a few special-purpose subroutines + that implement the GDB remote serial protocol. The file + containing these subroutines is called a "debugging stub". + + On certain remote targets, you can use an auxiliary program + `gdbserver' instead of linking a stub into your program. *Note + Using the `gdbserver' program: Server, for details. + + The debugging stub is specific to the architecture of the remote +machine; for example, use `sparc-stub.c' to debug programs on SPARC +boards. + + These working remote stubs are distributed with GDB: + +`sparc-stub.c' + For SPARC architectures. + +`m68k-stub.c' + For Motorola 680x0 architectures. + +`i386-stub.c' + For Intel 386 and compatible architectures. + + The `README' file in the GDB distribution may list other recently +added stubs. + +* Menu: + +* Stub Contents:: What the stub can do for you +* Bootstrapping:: What you must do for the stub +* Debug Session:: Putting it all together +* Protocol:: Outline of the communication protocol + +* Server:: Using the `gdbserver' program + + +File: gdb.info, Node: Stub Contents, Next: Bootstrapping, Up: Remote Serial + +What the stub can do for you +---------------------------- + + The debugging stub for your architecture supplies these three +subroutines: + +`set_debug_traps' + This routine arranges for `handle_exception' to run when your + program stops. You must call this subroutine explicitly near the + beginning of your program. + +`handle_exception' + This is the central workhorse, but your program never calls it + explicitly--the setup code arranges for `handle_exception' to run + when a trap is triggered. + + `handle_exception' takes control when your program stops during + execution (for example, on a breakpoint), and mediates + communications with GDB on the host machine. This is where the + communications protocol is implemented; `handle_exception' acts as + the GDB representative on the target machine; it begins by sending + summary information on the state of your program, then continues + to execute, retrieving and transmitting any information GDB needs, + until you execute a GDB command that makes your program resume; at + that point, `handle_exception' returns control to your own code on + the target machine. + +`breakpoint' + Use this auxiliary subroutine to make your program contain a + breakpoint. Depending on the particular situation, this may be + the only way for GDB to get control. For instance, if your target + machine has some sort of interrupt button, you won't need to call + this; pressing the interrupt button will transfer control to + `handle_exception'--in effect, to GDB. On some machines, simply + receiving characters on the serial port may also trigger a trap; + again, in that situation, you don't need to call `breakpoint' from + your own program--simply running `target remote' from the host GDB + session will get control. + + Call `breakpoint' if none of these is true, or if you simply want + to make certain your program stops at a predetermined point for the + start of your debugging session. + + +File: gdb.info, Node: Bootstrapping, Next: Debug Session, Prev: Stub Contents, Up: Remote Serial + +What you must do for the stub +----------------------------- + + The debugging stubs that come with GDB are set up for a particular +chip architecture, but they have no information about the rest of your +debugging target machine. To allow the stub to work, you must supply +these special low-level subroutines: + +`int getDebugChar()' + Write this subroutine to read a single character from the serial + port. It may be identical to `getchar' for your target system; a + different name is used to allow you to distinguish the two if you + wish. + +`void putDebugChar(int)' + Write this subroutine to write a single character to the serial + port. It may be identical to `putchar' for your target system; a + different name is used to allow you to distinguish the two if you + wish. + +`void exceptionHandler (int EXCEPTION_NUMBER, void *EXCEPTION_ADDRESS)' + Write this function to install EXCEPTION_ADDRESS in the exception + handling tables. You need to do this because the stub does not + have any way of knowing what the exception handling tables on your + target system are like (for example, the processor's table might + be in ROM, containing entries which point to a table in RAM). + eXCEPTION_NUMBER is the exception number which should be changed; + its meaning is architecture-dependent (for example, different + numbers might represent divide by zero, misaligned access, etc). + When this exception occurs, control should be transferred directly + to EXCEPTION_ADDRESS, and the processor state (stack, registers, + etc.) should be just as it is when a processor exception occurs. + So if you want to use a jump instruction to reach + EXCEPTION_ADDRESS, it should be a simple jump, not a jump to + subroutine. + + For the 386, EXCEPTION_ADDRESS should be installed as an interrupt + gate so that interrupts are masked while the handler runs. The + gate should be at privilege level 0 (the most privileged level). + The SPARC and 68k stubs are able to mask interrupts themself + without help from `exceptionHandler'. + +`void flush_i_cache()' + Write this subroutine to flush the instruction cache, if any, on + your target machine. If there is no instruction cache, this + subroutine may be a no-op. + + On target machines that have instruction caches, GDB requires this + function to make certain that the state of your program is stable. + +You must also make sure this library routine is available: + +`void *memset(void *, int, int)' + This is the standard library function `memset' that sets an area of + memory to a known value. If you have one of the free versions of + `libc.a', `memset' can be found there; otherwise, you must either + obtain it from your hardware manufacturer, or write your own. + + If you do not use the GNU C compiler, you may need other standard +library subroutines as well; this will vary from one stub to another, +but in general the stubs are likely to use any of the common library +subroutines which `gcc' generates as inline code. + + +File: gdb.info, Node: Debug Session, Next: Protocol, Prev: Bootstrapping, Up: Remote Serial + +Putting it all together +----------------------- + + In summary, when your program is ready to debug, you must follow +these steps. + + 1. Make sure you have the supporting low-level routines (*note What + you must do for the stub: Bootstrapping.): + `getDebugChar', `putDebugChar', + `flush_i_cache', `memset', `exceptionHandler'. + + 2. Insert these lines near the top of your program: + + set_debug_traps(); + breakpoint(); + + 3. For the 680x0 stub only, you need to provide a variable called + `exceptionHook'. Normally you just use + + void (*exceptionHook)() = 0; + + but if before calling `set_debug_traps', you set it to point to a + function in your program, that function is called when `GDB' + continues after stopping on a trap (for example, bus error). The + function indicated by `exceptionHook' is called with one + parameter: an `int' which is the exception number. + + 4. Compile and link together: your program, the GDB debugging stub for + your target architecture, and the supporting subroutines. + + 5. Make sure you have a serial connection between your target machine + and the GDB host, and identify the serial port used for this on + the host. + + 6. Download your program to your target machine (or get it there by + whatever means the manufacturer provides), and start it. + + 7. To start remote debugging, run GDB on the host machine, and specify + as an executable file the program that is running in the remote + machine. This tells GDB how to find your program's symbols and + the contents of its pure text. + + Then establish communication using the `target remote' command. + Its argument specifies how to communicate with the target + machine--either via a devicename attached to a direct serial line, + or a TCP port (usually to a terminal server which in turn has a + serial line to the target). For example, to use a serial line + connected to the device named `/dev/ttyb': + + target remote /dev/ttyb + + To use a TCP connection, use an argument of the form `HOST:port'. + For example, to connect to port 2828 on a terminal server named + `manyfarms': + + target remote manyfarms:2828 + + Now you can use all the usual commands to examine and change data +and to step and continue the remote program. + + To resume the remote program and stop debugging it, use the `detach' +command. + + Whenever GDB is waiting for the remote program, if you type the +interrupt character (often C-C), GDB attempts to stop the program. +This may or may not succeed, depending in part on the hardware and the +serial drivers the remote system uses. If you type the interrupt +character once again, GDB displays this prompt: + + Interrupted while waiting for the program. + Give up (and stop debugging it)? (y or n) + + If you type `y', GDB abandons the remote debugging session. (If you +decide you want to try again later, you can use `target remote' again +to connect once more.) If you type `n', GDB goes back to waiting. + + +File: gdb.info, Node: Protocol, Next: Server, Prev: Debug Session, Up: Remote Serial + +Outline of the communication protocol +------------------------------------- + + The stub files provided with GDB implement the target side of the +communication protocol, and the GDB side is implemented in the GDB +source file `remote.c'. Normally, you can simply allow these +subroutines to communicate, and ignore the details. (If you're +implementing your own stub file, you can still ignore the details: start +with one of the existing stub files. `sparc-stub.c' is the best +organized, and therefore the easiest to read.) + + However, there may be occasions when you need to know something about +the protocol--for example, if there is only one serial port to your +target machine, you might want your program to do something special if +it recognizes a packet meant for GDB. + + All GDB commands and responses (other than acknowledgements, which +are single characters) are sent as a packet which includes a checksum. +A packet is introduced with the character `$', and ends with the +character `#' followed by a two-digit checksum: + + $PACKET INFO#CHECKSUM + +CHECKSUM is computed as the modulo 256 sum of the PACKET INFO +characters. + + When either the host or the target machine receives a packet, the +first response expected is an acknowledgement: a single character, +either `+' (to indicate the package was received correctly) or `-' (to +request retransmission). + + The host (GDB) sends commands, and the target (the debugging stub +incorporated in your program) sends data in response. The target also +sends data when your program stops. + + Command packets are distinguished by their first character, which +identifies the kind of command. + + These are the commands currently supported: + +`g' + Requests the values of CPU registers. + +`G' + Sets the values of CPU registers. + +`mADDR,COUNT' + Read COUNT bytes at location ADDR. + +`MADDR,COUNT:...' + Write COUNT bytes at location ADDR. + +`c' +`cADDR' + Resume execution at the current address (or at ADDR if supplied). + +`s' +`sADDR' + Step the target program for one instruction, from either the + current program counter or from ADDR if supplied. + +`k' + Kill the target program. + +`?' + Report the most recent signal. To allow you to take advantage of + the GDB signal handling commands, one of the functions of the + debugging stub is to report CPU traps as the corresponding POSIX + signal values. + + If you have trouble with the serial connection, you can use the +command `set remotedebug'. This makes GDB report on all packets sent +back and forth across the serial line to the remote machine. The +packet-debugging information is printed on the GDB standard output +stream. `set remotedebug off' turns it off, and `show remotedebug' +will show you its current state. + + +File: gdb.info, Node: Server, Prev: Protocol, Up: Remote Serial + +Using the `gdbserver' program +----------------------------- + + `gdbserver' is a control program for Unix-like systems, which allows +you to connect your program with a remote GDB via `target remote'--but +without linking in the usual debugging stub. + + `gdbserver' is not a complete replacement for the debugging stubs, +because it requires essentially the same operating-system facilities +that GDB itself does. In fact, a system that can run `gdbserver' to +connect to a remote GDB could also run GDBN locally! `gdbserver' is +sometimes useful nevertheless, because it is a much smaller program +than GDB itself. It is also easier to port than all of GDBN, so you +may be able to get started more quickly on a new system by using +`gdbserver'. + + GDB and `gdbserver' communicate via either a serial line or a TCP +connection, using the standard GDB remote serial protocol. + +*On the target,* + you need to have a copy of the program you want to debug. + `gdbserver' does not need your program's symbol table, so you can + strip the program if necessary to save space. GDB on the host + system does all the symbol handling. + + To use the server, you must tell it how to communicate with {No + Value For "GDB"}; the name of your program; and the arguments for + your program. The syntax is: + + target> gdbserver COMM PROGRAM [ ARGS ... ] + + COMM is either a device name (to use a serial line) or a TCP + hostname and portnumber. For example, to debug emacs with the + argument `foo.txt' and communicate with GDB over the serial port + `/dev/com1': + + target> gdbserver /dev/com1 emacs foo.txt + + `gdbserver' waits passively for the host GDB to communicate with + it. + + To use a TCP connection instead of a serial line: + + target> gdbserver host:2345 emacs foo.txt + + The only difference from the previous example is the first + argument, specifying that you are communicating with the host GDB + via TCP. The `host:2345' argument means that `gdbserver' is to + expect a TCP connection from machine `host' to local TCP port 2345. + (Currently, the `host' part is ignored.) You can choose any number + you want for the port number as long as it does not conflict with + any TCP ports already in use on the target system.(1) You must use + the same port number with the host GDB `target remote' command. + +*On the host,* + you need an unstripped copy of your program, since GDB needs + symbols and debugging information. Start up GDB as usual, using + the name of the local copy of your program as the first argument. + (You may also need the `--baud' option if the serial line is + running at anything other than 9600 bps.) After that, use `target + remote' to establish communications with `gdbserver'. Its + argument is either a device name (usually a serial device, like + `/dev/ttyb'), or a TCP port descriptof in the form `HOST:PORT'. + For example: + + (gdb) target remote /dev/ttyb + + communicates with the server via serial line `/dev/ttyb', and + + (gdb) target remote the-target:2345 + + communicates via a TCP connection to port 2345 on host + `the-target'. For TCP connections, you must start up `gdbserver' + prior to using the `target remote' command. Otherwise you may get + an error whose text depends on the host system, but which usually + looks something like `Connection refused'. + + ---------- Footnotes ---------- + + (1) If you choose a port number that conflicts with another +service, `gdbserver' prints an error message and exits. + + +File: gdb.info, Node: i960-Nindy Remote, Next: UDI29K Remote, Prev: Remote Serial, Up: Remote + +GDB with a remote i960 (Nindy) +------------------------------ + + "Nindy" is a ROM Monitor program for Intel 960 target systems. When +GDB is configured to control a remote Intel 960 using Nindy, you can +tell GDB how to connect to the 960 in several ways: + + * Through command line options specifying serial port, version of the + Nindy protocol, and communications speed; + + * By responding to a prompt on startup; + + * By using the `target' command at any point during your GDB + session. *Note Commands for managing targets: Target Commands. + +* Menu: + +* Nindy Startup:: Startup with Nindy +* Nindy Options:: Options for Nindy +* Nindy Reset:: Nindy reset command + + +File: gdb.info, Node: Nindy Startup, Next: Nindy Options, Up: i960-Nindy Remote + +Startup with Nindy +------------------ + + If you simply start `gdb' without using any command-line options, +you are prompted for what serial port to use, *before* you reach the +ordinary GDB prompt: + + Attach /dev/ttyNN -- specify NN, or "quit" to quit: + +Respond to the prompt with whatever suffix (after `/dev/tty') +identifies the serial port you want to use. You can, if you choose, +simply start up with no Nindy connection by responding to the prompt +with an empty line. If you do this and later wish to attach to Nindy, +use `target' (*note Commands for managing targets: Target Commands.). + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-6 b/gnu/usr.bin/gdb/doc/gdb.info-6 new file mode 100644 index 00000000000..8a746fd77b6 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-6 @@ -0,0 +1,1220 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Nindy Options, Next: Nindy Reset, Prev: Nindy Startup, Up: i960-Nindy Remote + +Options for Nindy +----------------- + + These are the startup options for beginning your GDB session with a +Nindy-960 board attached: + +`-r PORT' + Specify the serial port name of a serial interface to be used to + connect to the target system. This option is only available when + GDB is configured for the Intel 960 target architecture. You may + specify PORT as any of: a full pathname (e.g. `-r /dev/ttya'), a + device name in `/dev' (e.g. `-r ttya'), or simply the unique + suffix for a specific `tty' (e.g. `-r a'). + +`-O' + (An uppercase letter "O", not a zero.) Specify that GDB should use + the "old" Nindy monitor protocol to connect to the target system. + This option is only available when GDB is configured for the Intel + 960 target architecture. + + *Warning:* if you specify `-O', but are actually trying to + connect to a target system that expects the newer protocol, + the connection fails, appearing to be a speed mismatch. GDB + repeatedly attempts to reconnect at several different line + speeds. You can abort this process with an interrupt. + +`-brk' + Specify that GDB should first send a `BREAK' signal to the target + system, in an attempt to reset it, before connecting to a Nindy + target. + + *Warning:* Many target systems do not have the hardware that + this requires; it only works with a few boards. + + The standard `-b' option controls the line speed used on the serial +port. + + +File: gdb.info, Node: Nindy Reset, Prev: Nindy Options, Up: i960-Nindy Remote + +Nindy reset command +------------------- + +`reset' + For a Nindy target, this command sends a "break" to the remote + target system; this is only useful if the target has been equipped + with a circuit to perform a hard reset (or some other interesting + action) when a break is detected. + + +File: gdb.info, Node: UDI29K Remote, Next: EB29K Remote, Prev: i960-Nindy Remote, Up: Remote + +GDB and the UDI protocol for AMD29K +----------------------------------- + + GDB supports AMD's UDI ("Universal Debugger Interface") protocol for +debugging the a29k processor family. To use this configuration with +AMD targets running the MiniMON monitor, you need the program `MONTIP', +available from AMD at no charge. You can also use GDB with the UDI +conformant a29k simulator program `ISSTIP', also available from AMD. + +`target udi KEYWORD' + Select the UDI interface to a remote a29k board or simulator, where + KEYWORD is an entry in the AMD configuration file `udi_soc'. This + file contains keyword entries which specify parameters used to + connect to a29k targets. If the `udi_soc' file is not in your + working directory, you must set the environment variable `UDICONF' + to its pathname. + + +File: gdb.info, Node: EB29K Remote, Next: VxWorks Remote, Prev: UDI29K Remote, Up: Remote + +GDB and the EBMON protocol for AMD29K +------------------------------------- + + AMD distributes a 29K development board meant to fit in a PC, +together with a DOS-hosted monitor program called `EBMON'. As a +shorthand term, this development system is called the "EB29K". To use +GDB from a Unix system to run programs on the EB29K board, you must +first connect a serial cable between the PC (which hosts the EB29K +board) and a serial port on the Unix system. In the following, we +assume you've hooked the cable between the PC's `COM1' port and +`/dev/ttya' on the Unix system. + +* Menu: + +* Comms (EB29K):: Communications setup +* gdb-EB29K:: EB29K cross-debugging +* Remote Log:: Remote log + + +File: gdb.info, Node: Comms (EB29K), Next: gdb-EB29K, Up: EB29K Remote + +Communications setup +-------------------- + + The next step is to set up the PC's port, by doing something like +this in DOS on the PC: + + C:\> MODE com1:9600,n,8,1,none + +This example--run on an MS DOS 4.0 system--sets the PC port to 9600 +bps, no parity, eight data bits, one stop bit, and no "retry" action; +you must match the communications parameters when establishing the Unix +end of the connection as well. + + To give control of the PC to the Unix side of the serial line, type +the following at the DOS console: + + C:\> CTTY com1 + +(Later, if you wish to return control to the DOS console, you can use +the command `CTTY con'--but you must send it over the device that had +control, in our example over the `COM1' serial line). + + From the Unix host, use a communications program such as `tip' or +`cu' to communicate with the PC; for example, + + cu -s 9600 -l /dev/ttya + +The `cu' options shown specify, respectively, the linespeed and the +serial port to use. If you use `tip' instead, your command line may +look something like the following: + + tip -9600 /dev/ttya + +Your system may require a different name where we show `/dev/ttya' as +the argument to `tip'. The communications parameters, including which +port to use, are associated with the `tip' argument in the "remote" +descriptions file--normally the system table `/etc/remote'. + + Using the `tip' or `cu' connection, change the DOS working directory +to the directory containing a copy of your 29K program, then start the +PC program `EBMON' (an EB29K control program supplied with your board +by AMD). You should see an initial display from `EBMON' similar to the +one that follows, ending with the `EBMON' prompt `#'-- + + C:\> G: + + G:\> CD \usr\joe\work29k + + G:\USR\JOE\WORK29K> EBMON + Am29000 PC Coprocessor Board Monitor, version 3.0-18 + Copyright 1990 Advanced Micro Devices, Inc. + Written by Gibbons and Associates, Inc. + + Enter '?' or 'H' for help + + PC Coprocessor Type = EB29K + I/O Base = 0x208 + Memory Base = 0xd0000 + + Data Memory Size = 2048KB + Available I-RAM Range = 0x8000 to 0x1fffff + Available D-RAM Range = 0x80002000 to 0x801fffff + + PageSize = 0x400 + Register Stack Size = 0x800 + Memory Stack Size = 0x1800 + + CPU PRL = 0x3 + Am29027 Available = No + Byte Write Available = Yes + + # ~. + + Then exit the `cu' or `tip' program (done in the example by typing +`~.' at the `EBMON' prompt). `EBMON' will keep running, ready for GDB +to take over. + + For this example, we've assumed what is probably the most convenient +way to make sure the same 29K program is on both the PC and the Unix +system: a PC/NFS connection that establishes "drive `G:'" on the PC as +a file system on the Unix host. If you do not have PC/NFS or something +similar connecting the two systems, you must arrange some other +way--perhaps floppy-disk transfer--of getting the 29K program from the +Unix system to the PC; GDB will *not* download it over the serial line. + + +File: gdb.info, Node: gdb-EB29K, Next: Remote Log, Prev: Comms (EB29K), Up: EB29K Remote + +EB29K cross-debugging +--------------------- + + Finally, `cd' to the directory containing an image of your 29K +program on the Unix system, and start GDB--specifying as argument the +name of your 29K program: + + cd /usr/joe/work29k + gdb myfoo + + Now you can use the `target' command: + + target amd-eb /dev/ttya 9600 MYFOO + +In this example, we've assumed your program is in a file called +`myfoo'. Note that the filename given as the last argument to `target +amd-eb' should be the name of the program as it appears to DOS. In our +example this is simply `MYFOO', but in general it can include a DOS +path, and depending on your transfer mechanism may not resemble the +name on the Unix side. + + At this point, you can set any breakpoints you wish; when you are +ready to see your program run on the 29K board, use the GDB command +`run'. + + To stop debugging the remote program, use the GDB `detach' command. + + To return control of the PC to its console, use `tip' or `cu' once +again, after your GDB session has concluded, to attach to `EBMON'. You +can then type the command `q' to shut down `EBMON', returning control +to the DOS command-line interpreter. Type `CTTY con' to return command +input to the main DOS console, and type `~.' to leave `tip' or `cu'. + + +File: gdb.info, Node: Remote Log, Prev: gdb-EB29K, Up: EB29K Remote + +Remote log +---------- + + The `target amd-eb' command creates a file `eb.log' in the current +working directory, to help debug problems with the connection. +`eb.log' records all the output from `EBMON', including echoes of the +commands sent to it. Running `tail -f' on this file in another window +often helps to understand trouble with `EBMON', or unexpected events on +the PC side of the connection. + + +File: gdb.info, Node: ST2000 Remote, Next: Hitachi Remote, Prev: VxWorks Remote, Up: Remote + +GDB with a Tandem ST2000 +------------------------ + + To connect your ST2000 to the host system, see the manufacturer's +manual. Once the ST2000 is physically attached, you can run + + target st2000 DEV SPEED + +to establish it as your debugging environment. DEV is normally the +name of a serial device, such as `/dev/ttya', connected to the ST2000 +via a serial line. You can instead specify DEV as a TCP connection +(for example, to a serial line attached via a terminal concentrator) +using the syntax `HOSTNAME:PORTNUMBER'. + + The `load' and `attach' commands are *not* defined for this target; +you must load your program into the ST2000 as you normally would for +standalone operation. GDB will read debugging information (such as +symbols) from a separate, debugging version of the program available on +your host computer. + + These auxiliary GDB commands are available to help you with the +ST2000 environment: + +`st2000 COMMAND' + Send a COMMAND to the STDBUG monitor. See the manufacturer's + manual for available commands. + +`connect' + Connect the controlling terminal to the STDBUG command monitor. + When you are done interacting with STDBUG, typing either of two + character sequences will get you back to the GDB command prompt: + `RET~.' (Return, followed by tilde and period) or `RET~C-d' + (Return, followed by tilde and control-D). + + +File: gdb.info, Node: VxWorks Remote, Next: ST2000 Remote, Prev: EB29K Remote, Up: Remote + +GDB and VxWorks +--------------- + + GDB enables developers to spawn and debug tasks running on networked +VxWorks targets from a Unix host. Already-running tasks spawned from +the VxWorks shell can also be debugged. GDB uses code that runs on +both the Unix host and on the VxWorks target. The program `gdb' is +installed and executed on the Unix host. (It may be installed with the +name `vxgdb', to distinguish it from a GDB for debugging programs on +the host itself.) + + The following information on connecting to VxWorks was current when +this manual was produced; newer releases of VxWorks may use revised +procedures. + + The remote debugging interface (RDB) routines are installed and +executed on the VxWorks target. These routines are included in the +VxWorks library `rdb.a' and are incorporated into the system image when +source-level debugging is enabled in the VxWorks configuration. + + If you wish, you can define `INCLUDE_RDB' in the VxWorks +configuration file `configAll.h' to include the RDB interface routines +and spawn the source debugging task `tRdbTask' when VxWorks is booted. +For more information on configuring and remaking VxWorks, see the +manufacturer's manual. + + Once you have included the RDB interface in your VxWorks system image +and set your Unix execution search path to find GDB, you are ready to +run GDB. From your Unix host, run `gdb' (or `vxgdb', depending on your +installation). + + GDB comes up showing the prompt: + + (vxgdb) + +* Menu: + +* VxWorks Connection:: Connecting to VxWorks +* VxWorks Download:: VxWorks download +* VxWorks Attach:: Running tasks + + +File: gdb.info, Node: VxWorks Connection, Next: VxWorks Download, Up: VxWorks Remote + +Connecting to VxWorks +--------------------- + + The GDB command `target' lets you connect to a VxWorks target on the +network. To connect to a target whose host name is "`tt'", type: + + (vxgdb) target vxworks tt + + GDB displays messages like these: + + Attaching remote machine across net... + Connected to tt. + + GDB then attempts to read the symbol tables of any object modules +loaded into the VxWorks target since it was last booted. GDB locates +these files by searching the directories listed in the command search +path (*note Your program's environment: Environment.); if it fails to +find an object file, it displays a message such as: + + prog.o: No such file or directory. + + When this happens, add the appropriate directory to the search path +with the GDB command `path', and execute the `target' command again. + + +File: gdb.info, Node: VxWorks Download, Next: VxWorks Attach, Prev: VxWorks Connection, Up: VxWorks Remote + +VxWorks download +---------------- + + If you have connected to the VxWorks target and you want to debug an +object that has not yet been loaded, you can use the GDB `load' command +to download a file from Unix to VxWorks incrementally. The object file +given as an argument to the `load' command is actually opened twice: +first by the VxWorks target in order to download the code, then by GDB +in order to read the symbol table. This can lead to problems if the +current working directories on the two systems differ. If both systems +have NFS mounted the same filesystems, you can avoid these problems by +using absolute paths. Otherwise, it is simplest to set the working +directory on both systems to the directory in which the object file +resides, and then to reference the file by its name, without any path. +For instance, a program `prog.o' may reside in `VXPATH/vw/demo/rdb' in +VxWorks and in `HOSTPATH/vw/demo/rdb' on the host. To load this +program, type this on VxWorks: + + -> cd "VXPATH/vw/demo/rdb" + + Then, in GDB, type: + + (vxgdb) cd HOSTPATH/vw/demo/rdb + (vxgdb) load prog.o + + GDB displays a response similar to this: + + Reading symbol data from wherever/vw/demo/rdb/prog.o... done. + + You can also use the `load' command to reload an object module after +editing and recompiling the corresponding source file. Note that this +will cause GDB to delete all currently-defined breakpoints, +auto-displays, and convenience variables, and to clear the value +history. (This is necessary in order to preserve the integrity of +debugger data structures that reference the target system's symbol +table.) + + +File: gdb.info, Node: VxWorks Attach, Prev: VxWorks Download, Up: VxWorks Remote + +Running tasks +------------- + + You can also attach to an existing task using the `attach' command as +follows: + + (vxgdb) attach TASK + +where TASK is the VxWorks hexadecimal task ID. The task can be running +or suspended when you attach to it. If running, it will be suspended at +the time of attachment. + + +File: gdb.info, Node: Hitachi Remote, Next: MIPS Remote, Prev: ST2000 Remote, Up: Remote + +GDB and Hitachi Microprocessors +------------------------------- + + GDB needs to know these things to talk to your Hitachi SH, H8/300, +or H8/500: + + 1. that you want to use `target hms', the remote debugging interface + for Hitachi microprocessors (this is the default when GDB is + configured specifically for the Hitachi SH, H8/300, or H8/500); + + 2. what serial device connects your host to your Hitachi board (the + first serial device available on your host is the default); + + + Use the special `gdb' command `device PORT' if you need to +explicitly set the serial device. The default PORT is the first +available port on your host. This is only necessary on Unix hosts, +where it is typically something like `/dev/ttya'. + + `gdb' has another special command to set the communications speed: +`speed BPS'. This command also is only used from Unix hosts; on DOS +hosts, set the line speed as usual from outside GDB with the DOS `mode' +command (for instance, `mode com2:9600,n,8,1,p' for a 9600 bps +connection). + + The `device' and `speed' commands are available only when you use a +Unix host to debug your Hitachi microprocessor programs. If you use a +DOS host, GDB depends on an auxiliary terminate-and-stay-resident +program called `asynctsr' to communicate with the development board +through a PC serial port. You must also use the DOS `mode' command to +set up the serial port on the DOS side. + + +File: gdb.info, Node: MIPS Remote, Next: Simulator, Prev: Hitachi Remote, Up: Remote + +GDB and remote MIPS boards +-------------------------- + + GDB can use the MIPS remote debugging protocol to talk to a MIPS +board attached to a serial line. This is available when you configure +GDB with `--target=mips-idt-ecoff'. + + To run a program on the board, start up `gdb' with the name of your +program as the argument. To connect to the board, use the command +`target mips PORT', where PORT is the name of the serial port connected +to the board. If the program has not already been downloaded to the +board, you may use the `load' command to download it. You can then use +all the usual GDB commands. + + You can also specify PORT as a TCP connection (for instance, to a +serial line managed by a terminal concentrator), using the syntax +`HOSTNAME:PORTNUMBER'. + + You can see some debugging information about communications with the +board by setting the `remotedebug' variable. If you set it to 1 using +`set remotedebug 1' every packet will be displayed. If you set it to 2 +every character will be displayed. You can check the current value at +any time with the command `show remotedebug'. + + You can control the timeout used while waiting for a packet, in the +MIPS remote protocol, with the `set timeout SECONDS' command. The +default is 5 seconds. Similarly, you can control the timeout used while +waiting for an acknowledgement of a packet with the `set +retransmit-timeout SECONDS' command. The default is 3 seconds. You +can inspect both values with `show timeout' and `show +retransmit-timeout'. (These commands are *only* available when GDB is +configured for `--target=mips-idt-ecoff'.) + + If your target board does not support the MIPS floating point +coprocessor, you should use the command `set mipsfpu off' (you may wish +to put this in your .gdbinit file). This tells GDB how to find the +return value of functions which return floating point values. It also +allows GDB to avoid saving the floating point registers when calling +functions on the board. + + +File: gdb.info, Node: Simulator, Prev: MIPS Remote, Up: Remote + +Simulated CPU target +-------------------- + + For some configurations, GDB includes a CPU simulator that you can +use instead of a hardware CPU to debug your programs. Currently, a +simulator is available when GDB is configured to debug Zilog Z8000 or +Hitachi microprocessor targets. + + For the Z8000 family, `target sim' simulates either the Z8002 (the +unsegmented variant of the Z8000 architecture) or the Z8001 (the +segmented variant). The simulator recognizes which architecture is +appropriate by inspecting the object code. + +`target sim' + Debug programs on a simulated CPU (which CPU depends on the GDB + configuration) + +After specifying this target, you can debug programs for the simulated +CPU in the same style as programs for your host computer; use the +`file' command to load a new program image, the `run' command to run +your program, and so on. + + As well as making available all the usual machine registers (see +`info reg'), this debugging target provides three additional items of +information as specially named registers: + +`cycles' + Counts clock-ticks in the simulator. + +`insts' + Counts instructions run in the simulator. + +`time' + Execution time in 60ths of a second. + + You can refer to these values in GDB expressions with the usual +conventions; for example, `b fputc if $cycles>5000' sets a conditional +breakpoint that will suspend only after at least 5000 simulated clock +ticks. + + +File: gdb.info, Node: Controlling GDB, Next: Sequences, Prev: Targets, Up: Top + +Controlling GDB +*************** + + You can alter the way GDB interacts with you by using the `set' +command. For commands controlling how GDB displays data, *note Print +settings: Print Settings.; other settings are described here. + +* Menu: + +* Prompt:: Prompt +* Editing:: Command editing +* History:: Command history +* Screen Size:: Screen size +* Numbers:: Numbers +* Messages/Warnings:: Optional warnings and messages + + +File: gdb.info, Node: Prompt, Next: Editing, Up: Controlling GDB + +Prompt +====== + + GDB indicates its readiness to read a command by printing a string +called the "prompt". This string is normally `(gdb)'. You can change +the prompt string with the `set prompt' command. For instance, when +debugging GDB with GDB, it is useful to change the prompt in one of the +GDB sessions so that you can always tell which one you are talking to. + +`set prompt NEWPROMPT' + Directs GDB to use NEWPROMPT as its prompt string henceforth. + +`show prompt' + Prints a line of the form: `Gdb's prompt is: YOUR-PROMPT' + + +File: gdb.info, Node: Editing, Next: History, Prev: Prompt, Up: Controlling GDB + +Command editing +=============== + + GDB reads its input commands via the "readline" interface. This GNU +library provides consistent behavior for programs which provide a +command line interface to the user. Advantages are `emacs'-style or +`vi'-style inline editing of commands, `csh'-like history substitution, +and a storage and recall of command history across debugging sessions. + + You may control the behavior of command line editing in GDB with the +command `set'. + +`set editing' +`set editing on' + Enable command line editing (enabled by default). + +`set editing off' + Disable command line editing. + +`show editing' + Show whether command line editing is enabled. + + +File: gdb.info, Node: History, Next: Screen Size, Prev: Editing, Up: Controlling GDB + +Command history +=============== + + GDB can keep track of the commands you type during your debugging +sessions, so that you can be certain of precisely what happened. Use +these commands to manage the GDB command history facility. + +`set history filename FNAME' + Set the name of the GDB command history file to FNAME. This is + the file from which GDB will read an initial command history list + or to which it will write this list when it exits. This list is + accessed through history expansion or through the history command + editing characters listed below. This file defaults to the value + of the environment variable `GDBHISTFILE', or to `./.gdb_history' + if this variable is not set. + +`set history save' +`set history save on' + Record command history in a file, whose name may be specified with + the `set history filename' command. By default, this option is + disabled. + +`set history save off' + Stop recording command history in a file. + +`set history size SIZE' + Set the number of commands which GDB will keep in its history list. + This defaults to the value of the environment variable `HISTSIZE', + or to 256 if this variable is not set. + + History expansion assigns special meaning to the character `!'. + + Since `!' is also the logical not operator in C, history expansion +is off by default. If you decide to enable history expansion with the +`set history expansion on' command, you may sometimes need to follow +`!' (when it is used as logical not, in an expression) with a space or +a tab to prevent it from being expanded. The readline history +facilities will not attempt substitution on the strings `!=' and `!(', +even when history expansion is enabled. + + The commands to control history expansion are: + +`set history expansion on' +`set history expansion' + Enable history expansion. History expansion is off by default. + +`set history expansion off' + Disable history expansion. + + The readline code comes with more complete documentation of + editing and history expansion features. Users unfamiliar with + `emacs' or `vi' may wish to read it. + +`show history' +`show history filename' +`show history save' +`show history size' +`show history expansion' + These commands display the state of the GDB history parameters. + `show history' by itself displays all four states. + +`show commands' + Display the last ten commands in the command history. + +`show commands N' + Print ten commands centered on command number N. + +`show commands +' + Print ten commands just after the commands last printed. + + +File: gdb.info, Node: Screen Size, Next: Numbers, Prev: History, Up: Controlling GDB + +Screen size +=========== + + Certain commands to GDB may produce large amounts of information +output to the screen. To help you read all of it, GDB pauses and asks +you for input at the end of each page of output. Type RET when you +want to continue the output, or `q' to discard the remaining output. +Also, the screen width setting determines when to wrap lines of output. +Depending on what is being printed, GDB tries to break the line at a +readable place, rather than simply letting it overflow onto the +following line. + + Normally GDB knows the size of the screen from the termcap data base +together with the value of the `TERM' environment variable and the +`stty rows' and `stty cols' settings. If this is not correct, you can +override it with the `set height' and `set width' commands: + +`set height LPP' +`show height' +`set width CPL' +`show width' + These `set' commands specify a screen height of LPP lines and a + screen width of CPL characters. The associated `show' commands + display the current settings. + + If you specify a height of zero lines, GDB will not pause during + output no matter how long the output is. This is useful if output + is to a file or to an editor buffer. + + Likewise, you can specify `set width 0' to prevent GDB from + wrapping its output. + + +File: gdb.info, Node: Numbers, Next: Messages/Warnings, Prev: Screen Size, Up: Controlling GDB + +Numbers +======= + + You can always enter numbers in octal, decimal, or hexadecimal in +GDB by the usual conventions: octal numbers begin with `0', decimal +numbers end with `.', and hexadecimal numbers begin with `0x'. Numbers +that begin with none of these are, by default, entered in base 10; +likewise, the default display for numbers--when no particular format is +specified--is base 10. You can change the default base for both input +and output with the `set radix' command. + +`set radix BASE' + Set the default base for numeric input and display. Supported + choices for BASE are decimal 8, 10, or 16. BASE must itself be + specified either unambiguously or using the current default radix; + for example, any of + + set radix 012 + set radix 10. + set radix 0xa + + will set the base to decimal. On the other hand, `set radix 10' + will leave the radix unchanged no matter what it was. + +`show radix' + Display the current default base for numeric input and display. + + +File: gdb.info, Node: Messages/Warnings, Prev: Numbers, Up: Controlling GDB + +Optional warnings and messages +============================== + + By default, GDB is silent about its inner workings. If you are +running on a slow machine, you may want to use the `set verbose' +command. It will make GDB tell you when it does a lengthy internal +operation, so you will not think it has crashed. + + Currently, the messages controlled by `set verbose' are those which +announce that the symbol table for a source file is being read; see +`symbol-file' in *Note Commands to specify files: Files. + +`set verbose on' + Enables GDB output of certain informational messages. + +`set verbose off' + Disables GDB output of certain informational messages. + +`show verbose' + Displays whether `set verbose' is on or off. + + By default, if GDB encounters bugs in the symbol table of an object +file, it is silent; but if you are debugging a compiler, you may find +this information useful (*note Errors reading symbol files: Symbol +Errors.). + +`set complaints LIMIT' + Permits GDB to output LIMIT complaints about each type of unusual + symbols before becoming silent about the problem. Set LIMIT to + zero to suppress all complaints; set it to a large number to + prevent complaints from being suppressed. + +`show complaints' + Displays how many symbol complaints GDB is permitted to produce. + + By default, GDB is cautious, and asks what sometimes seems to be a +lot of stupid questions to confirm certain commands. For example, if +you try to run a program which is already running: + + (gdb) run + The program being debugged has been started already. + Start it from the beginning? (y or n) + + If you are willing to unflinchingly face the consequences of your own +commands, you can disable this "feature": + +`set confirm off' + Disables confirmation requests. + +`set confirm on' + Enables confirmation requests (the default). + +`show confirm' + Displays state of confirmation requests. + + Some systems allow individual object files that make up your program +to be replaced without stopping and restarting your program. For +example, in VxWorks you can simply recompile a defective object file +and keep on running. If you are running on one of these systems, you +can allow GDB to reload the symbols for automatically relinked modules: + +`set symbol-reloading on' + Replace symbol definitions for the corresponding source file when + an object file with a particular name is seen again. + +`set symbol-reloading off' + Do not replace symbol definitions when re-encountering object + files of the same name. This is the default state; if you are not + running on a system that permits automatically relinking modules, + you should leave `symbol-reloading' off, since otherwise GDB may + discard symbols when linking large programs, that may contain + several modules (from different directories or libraries) with the + same name. + +`show symbol-reloading' + Show the current `on' or `off' setting. + + +File: gdb.info, Node: Sequences, Next: Emacs, Prev: Controlling GDB, Up: Top + +Canned Sequences of Commands +**************************** + + Aside from breakpoint commands (*note Breakpoint command lists: +Break Commands.), GDB provides two ways to store sequences of commands +for execution as a unit: user-defined commands and command files. + +* Menu: + +* Define:: User-defined commands +* Hooks:: User-defined command hooks +* Command Files:: Command files +* Output:: Commands for controlled output + + +File: gdb.info, Node: Define, Next: Hooks, Up: Sequences + +User-defined commands +===================== + + A "user-defined command" is a sequence of GDB commands to which you +assign a new name as a command. This is done with the `define' command. + +`define COMMANDNAME' + Define a command named COMMANDNAME. If there is already a command + by that name, you are asked to confirm that you want to redefine + it. + + The definition of the command is made up of other GDB command + lines, which are given following the `define' command. The end of + these commands is marked by a line containing `end'. + +`document COMMANDNAME' + Give documentation to the user-defined command COMMANDNAME. The + command COMMANDNAME must already be defined. This command reads + lines of documentation just as `define' reads the lines of the + command definition, ending with `end'. After the `document' + command is finished, `help' on command COMMANDNAME will print the + documentation you have specified. + + You may use the `document' command again to change the + documentation of a command. Redefining the command with `define' + does not change the documentation. + +`help user-defined' + List all user-defined commands, with the first line of the + documentation (if any) for each. + +`show user' +`show user COMMANDNAME' + Display the GDB commands used to define COMMANDNAME (but not its + documentation). If no COMMANDNAME is given, display the + definitions for all user-defined commands. + + User-defined commands do not take arguments. When they are +executed, the commands of the definition are not printed. An error in +any command stops execution of the user-defined command. + + Commands that would ask for confirmation if used interactively +proceed without asking when used inside a user-defined command. Many +GDB commands that normally print messages to say what they are doing +omit the messages when used in a user-defined command. + + +File: gdb.info, Node: Hooks, Next: Command Files, Prev: Define, Up: Sequences + +User-defined command hooks +========================== + + You may define *hooks*, which are a special kind of user-defined +command. Whenever you run the command `foo', if the user-defined +command `hook-foo' exists, it is executed (with no arguments) before +that command. + + In addition, a pseudo-command, `stop' exists. Defining +(`hook-stop') makes the associated commands execute every time +execution stops in your program: before breakpoint commands are run, +displays are printed, or the stack frame is printed. + + For example, to ignore `SIGALRM' signals while single-stepping, but +treat them normally during normal execution, you could define: + + define hook-stop + handle SIGALRM nopass + end + + define hook-run + handle SIGALRM pass + end + + define hook-continue + handle SIGLARM pass + end + + You can define a hook for any single-word command in GDB, but not +for command aliases; you should define a hook for the basic command +name, e.g. `backtrace' rather than `bt'. If an error occurs during +the execution of your hook, execution of GDB commands stops and GDB +issues a prompt (before the command that you actually typed had a +chance to run). + + If you try to define a hook which does not match any known command, +you will get a warning from the `define' command. + + +File: gdb.info, Node: Command Files, Next: Output, Prev: Hooks, Up: Sequences + +Command files +============= + + A command file for GDB is a file of lines that are GDB commands. +Comments (lines starting with `#') may also be included. An empty line +in a command file does nothing; it does not mean to repeat the last +command, as it would from the terminal. + + When you start GDB, it automatically executes commands from its +"init files". These are files named `.gdbinit'. GDB reads the init +file (if any) in your home directory and then the init file (if any) in +the current working directory. (The init files are not executed if you +use the `-nx' option; *note Choosing modes: Mode Options..) + + On some configurations of GDB, the init file is known by a different +name (these are typically environments where a specialized form of GDB +may need to coexist with other forms, hence a different name for the +specialized version's init file). These are the environments with +special init file names: + + * VxWorks (Wind River Systems real-time OS): `.vxgdbinit' + + * OS68K (Enea Data Systems real-time OS): `.os68gdbinit' + + * ES-1800 (Ericsson Telecom AB M68000 emulator): `.esgdbinit' + + You can also request the execution of a command file with the +`source' command: + +`source FILENAME' + Execute the command file FILENAME. + + The lines in a command file are executed sequentially. They are not +printed as they are executed. An error in any command terminates +execution of the command file. + + Commands that would ask for confirmation if used interactively +proceed without asking when used in a command file. Many GDB commands +that normally print messages to say what they are doing omit the +messages when called from command files. + + +File: gdb.info, Node: Output, Prev: Command Files, Up: Sequences + +Commands for controlled output +============================== + + During the execution of a command file or a user-defined command, +normal GDB output is suppressed; the only output that appears is what is +explicitly printed by the commands in the definition. This section +describes three commands useful for generating exactly the output you +want. + +`echo TEXT' + Print TEXT. Nonprinting characters can be included in TEXT using + C escape sequences, such as `\n' to print a newline. *No newline + will be printed unless you specify one.* In addition to the + standard C escape sequences, a backslash followed by a space + stands for a space. This is useful for displaying a string with + spaces at the beginning or the end, since leading and trailing + spaces are otherwise trimmed from all arguments. To print ` and + foo = ', use the command `echo \ and foo = \ '. + + A backslash at the end of TEXT can be used, as in C, to continue + the command onto subsequent lines. For example, + + echo This is some text\n\ + which is continued\n\ + onto several lines.\n + + produces the same output as + + echo This is some text\n + echo which is continued\n + echo onto several lines.\n + +`output EXPRESSION' + Print the value of EXPRESSION and nothing but that value: no + newlines, no `$NN = '. The value is not entered in the value + history either. *Note Expressions: Expressions, for more + information on expressions. + +`output/FMT EXPRESSION' + Print the value of EXPRESSION in format FMT. You can use the same + formats as for `print'. *Note Output formats: Output Formats, for + more information. + +`printf STRING, EXPRESSIONS...' + Print the values of the EXPRESSIONS under the control of STRING. + The EXPRESSIONS are separated by commas and may be either numbers + or pointers. Their values are printed as specified by STRING, + exactly as if your program were to execute the C subroutine + + printf (STRING, EXPRESSIONS...); + + For example, you can print two values in hex like this: + + printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo + + The only backslash-escape sequences that you can use in the format + string are the simple ones that consist of backslash followed by a + letter. + + +File: gdb.info, Node: Emacs, Next: GDB Bugs, Prev: Sequences, Up: Top + +Using GDB under GNU Emacs +************************* + + A special interface allows you to use GNU Emacs to view (and edit) +the source files for the program you are debugging with GDB. + + To use this interface, use the command `M-x gdb' in Emacs. Give the +executable file you want to debug as an argument. This command starts +GDB as a subprocess of Emacs, with input and output through a newly +created Emacs buffer. + + Using GDB under Emacs is just like using GDB normally except for two +things: + + * All "terminal" input and output goes through the Emacs buffer. + + This applies both to GDB commands and their output, and to the input +and output done by the program you are debugging. + + This is useful because it means that you can copy the text of +previous commands and input them again; you can even use parts of the +output in this way. + + All the facilities of Emacs' Shell mode are available for interacting +with your program. In particular, you can send signals the usual +way--for example, `C-c C-c' for an interrupt, `C-c C-z' for a stop. + + * GDB displays source code through Emacs. + + Each time GDB displays a stack frame, Emacs automatically finds the +source file for that frame and puts an arrow (`=>') at the left margin +of the current line. Emacs uses a separate buffer for source display, +and splits the screen to show both your GDB session and the source. + + Explicit GDB `list' or search commands still produce output as +usual, but you probably will have no reason to use them. + + *Warning:* If the directory where your program resides is not your + current directory, it can be easy to confuse Emacs about the + location of the source files, in which case the auxiliary display + buffer will not appear to show your source. GDB can find programs + by searching your environment's `PATH' variable, so the GDB input + and output session will proceed normally; but Emacs does not get + enough information back from GDB to locate the source files in + this situation. To avoid this problem, either start GDB mode from + the directory where your program resides, or specify a full path + name when prompted for the `M-x gdb' argument. + + A similar confusion can result if you use the GDB `file' command to + switch to debugging a program in some other location, from an + existing GDB buffer in Emacs. + + By default, `M-x gdb' calls the program called `gdb'. If you need +to call GDB by a different name (for example, if you keep several +configurations around, with different names) you can set the Emacs +variable `gdb-command-name'; for example, + + (setq gdb-command-name "mygdb") + +(preceded by `ESC ESC', or typed in the `*scratch*' buffer, or in your +`.emacs' file) will make Emacs call the program named "`mygdb'" instead. + + In the GDB I/O buffer, you can use these special Emacs commands in +addition to the standard Shell mode commands: + +`C-h m' + Describe the features of Emacs' GDB Mode. + +`M-s' + Execute to another source line, like the GDB `step' command; also + update the display window to show the current file and location. + +`M-n' + Execute to next source line in this function, skipping all function + calls, like the GDB `next' command. Then update the display window + to show the current file and location. + +`M-i' + Execute one instruction, like the GDB `stepi' command; update + display window accordingly. + +`M-x gdb-nexti' + Execute to next instruction, using the GDB `nexti' command; update + display window accordingly. + +`C-c C-f' + Execute until exit from the selected stack frame, like the GDB + `finish' command. + +`M-c' + Continue execution of your program, like the GDB `continue' + command. + + *Warning:* In Emacs v19, this command is `C-c C-p'. + +`M-u' + Go up the number of frames indicated by the numeric argument + (*note Numeric Arguments: (emacs)Arguments.), like the GDB `up' + command. + + *Warning:* In Emacs v19, this command is `C-c C-u'. + +`M-d' + Go down the number of frames indicated by the numeric argument, + like the GDB `down' command. + + *Warning:* In Emacs v19, this command is `C-c C-d'. + +`C-x &' + Read the number where the cursor is positioned, and insert it at + the end of the GDB I/O buffer. For example, if you wish to + disassemble code around an address that was displayed earlier, + type `disassemble'; then move the cursor to the address display, + and pick up the argument for `disassemble' by typing `C-x &'. + + You can customize this further by defining elements of the list + `gdb-print-command'; once it is defined, you can format or + otherwise process numbers picked up by `C-x &' before they are + inserted. A numeric argument to `C-x &' will both indicate that + you wish special formatting, and act as an index to pick an + element of the list. If the list element is a string, the number + to be inserted is formatted using the Emacs function `format'; + otherwise the number is passed as an argument to the corresponding + list element. + + In any source file, the Emacs command `C-x SPC' (`gdb-break') tells +GDB to set a breakpoint on the source line point is on. + + If you accidentally delete the source-display buffer, an easy way to +get it back is to type the command `f' in the GDB buffer, to request a +frame display; when you run under Emacs, this will recreate the source +buffer if necessary to show you the context of the current frame. + + The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit the +files with these buffers if you wish; but keep in mind that GDB +communicates with Emacs in terms of line numbers. If you add or delete +lines from the text, the line numbers that GDB knows will cease to +correspond properly with the code. + + +File: gdb.info, Node: GDB Bugs, Next: Command Line Editing, Prev: Emacs, Up: Top + +Reporting Bugs in GDB +********************* + + Your bug reports play an essential role in making GDB reliable. + + Reporting a bug may help you by bringing a solution to your problem, +or it may not. But in any case the principal function of a bug report +is to help the entire community by making the next version of GDB work +better. Bug reports are your contribution to the maintenance of GDB. + + In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +* Menu: + +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs + + +File: gdb.info, Node: Bug Criteria, Next: Bug Reporting, Up: GDB Bugs + +Have you found a bug? +===================== + + If you are not sure whether you have found a bug, here are some +guidelines: + + * If the debugger gets a fatal signal, for any input whatever, that + is a GDB bug. Reliable debuggers never crash. + + * If GDB produces an error message for valid input, that is a bug. + + * If GDB does not produce an error message for invalid input, that + is a bug. However, you should note that your idea of "invalid + input" might be our idea of "an extension" or "support for + traditional practice". + + * If you are an experienced user of debugging tools, your suggestions + for improvement of GDB are welcome in any case. + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-7 b/gnu/usr.bin/gdb/doc/gdb.info-7 new file mode 100644 index 00000000000..963527ef774 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-7 @@ -0,0 +1,1233 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Bug Reporting, Prev: Bug Criteria, Up: GDB Bugs + +How to report bugs +================== + + A number of companies and individuals offer support for GNU products. +If you obtained GDB from a support organization, we recommend you +contact that organization first. + + You can find contact information for many support companies and +individuals in the file `etc/SERVICE' in the GNU Emacs distribution. + + In any event, we also recommend that you send bug reports for GDB to +one of these addresses: + + bug-gdb@prep.ai.mit.edu + {ucbvax|mit-eddie|uunet}!prep.ai.mit.edu!bug-gdb + + *Do not send bug reports to `info-gdb', or to `help-gdb', or to any +newsgroups.* Most users of GDB do not want to receive bug reports. +Those that do, have arranged to receive `bug-gdb'. + + The mailing list `bug-gdb' has a newsgroup `gnu.gdb.bug' which +serves as a repeater. The mailing list and the newsgroup carry exactly +the same messages. Often people think of posting bug reports to the +newsgroup instead of mailing them. This appears to work, but it has one +problem which can be crucial: a newsgroup posting often lacks a mail +path back to the sender. Thus, if we need to ask for more information, +we may be unable to reach you. For this reason, it is better to send +bug reports to the mailing list. + + As a last resort, send bug reports on paper to: + + GNU Debugger Bugs + Free Software Foundation + 545 Tech Square + Cambridge, MA 02139 + + The fundamental principle of reporting bugs usefully is this: +*report all the facts*. If you are not sure whether to state a fact or +leave it out, state it! + + Often people omit facts because they think they know what causes the +problem and assume that some details do not matter. Thus, you might +assume that the name of the variable you use in an example does not +matter. Well, probably it does not, but one cannot be sure. Perhaps +the bug is a stray memory reference which happens to fetch from the +location where that name is stored in memory; perhaps, if the name were +different, the contents of that location would fool the debugger into +doing the right thing despite the bug. Play it safe and give a +specific, complete example. That is the easiest thing for you to do, +and the most helpful. + + Keep in mind that the purpose of a bug report is to enable us to fix +the bug if it is new to us. It is not as important as what happens if +the bug is already known. Therefore, always write your bug reports on +the assumption that the bug has not been reported previously. + + Sometimes people give a few sketchy facts and ask, "Does this ring a +bell?" Those bug reports are useless, and we urge everyone to *refuse +to respond to them* except to chide the sender to report bugs properly. + + To enable us to fix the bug, you should include all these things: + + * The version of GDB. GDB announces it if you start with no + arguments; you can also print it at any time using `show version'. + + Without this, we will not know whether there is any point in + looking for the bug in the current version of GDB. + + * The type of machine you are using, and the operating system name + and version number. + + * What compiler (and its version) was used to compile GDB--e.g. + "gcc-2.0". + + * What compiler (and its version) was used to compile the program you + are debugging--e.g. "gcc-2.0". + + * The command arguments you gave the compiler to compile your + example and observe the bug. For example, did you use `-O'? To + guarantee you will not omit something important, list them all. A + copy of the Makefile (or the output from make) is sufficient. + + If we were to try to guess the arguments, we would probably guess + wrong and then we might not encounter the bug. + + * A complete input script, and all necessary source files, that will + reproduce the bug. + + * A description of what behavior you observe that you believe is + incorrect. For example, "It gets a fatal signal." + + Of course, if the bug is that GDB gets a fatal signal, then we will + certainly notice it. But if the bug is incorrect output, we might + not notice unless it is glaringly wrong. We are human, after all. + You might as well not give us a chance to make a mistake. + + Even if the problem you experience is a fatal signal, you should + still say so explicitly. Suppose something strange is going on, + such as, your copy of GDB is out of synch, or you have encountered + a bug in the C library on your system. (This has happened!) Your + copy might crash and ours would not. If you told us to expect a + crash, then when ours fails to crash, we would know that the bug + was not happening for us. If you had not told us to expect a + crash, then we would not be able to draw any conclusion from our + observations. + + * If you wish to suggest changes to the GDB source, send us context + diffs. If you even discuss something in the GDB source, refer to + it by context, not by line number. + + The line numbers in our development sources will not match those + in your sources. Your line numbers would convey no useful + information to us. + + Here are some things that are not necessary: + + * A description of the envelope of the bug. + + Often people who encounter a bug spend a lot of time investigating + which changes to the input file will make the bug go away and which + changes will not affect it. + + This is often time consuming and not very useful, because the way + we will find the bug is by running a single example under the + debugger with breakpoints, not by pure deduction from a series of + examples. We recommend that you save your time for something else. + + Of course, if you can find a simpler example to report *instead* + of the original one, that is a convenience for us. Errors in the + output will be easier to spot, running under the debugger will take + less time, etc. + + However, simplification is not vital; if you do not want to do + this, report the bug anyway and send us the entire test case you + used. + + * A patch for the bug. + + A patch for the bug does help us if it is a good one. But do not + omit the necessary information, such as the test case, on the + assumption that a patch is all we need. We might see problems + with your patch and decide to fix the problem another way, or we + might not understand it at all. + + Sometimes with a program as complicated as GDB it is very hard to + construct an example that will make the program follow a certain + path through the code. If you do not send us the example, we will + not be able to construct one, so we will not be able to verify + that the bug is fixed. + + And if we cannot understand what bug you are trying to fix, or why + your patch should be an improvement, we will not install it. A + test case will help us to understand. + + * A guess about what the bug is or what it depends on. + + Such guesses are usually wrong. Even we cannot guess right about + such things without first using the debugger to find the facts. + + +File: gdb.info, Node: Command Line Editing, Next: Using History Interactively, Prev: GDB Bugs, Up: Top + +Command Line Editing +******************** + + This text describes GNU's command line editing interface. + +* Menu: + +* Introduction and Notation:: Notation used in this text. +* Readline Interaction:: The minimum set of commands for editing a line. +* Readline Init File:: Customizing Readline from a user's view. + + +File: gdb.info, Node: Introduction and Notation, Next: Readline Interaction, Up: Command Line Editing + +Introduction to Line Editing +============================ + + The following paragraphs describe the notation we use to represent +keystrokes. + + The text C-k is read as `Control-K' and describes the character +produced when the Control key is depressed and the k key is struck. + + The text M-k is read as `Meta-K' and describes the character +produced when the meta key (if you have one) is depressed, and the k +key is struck. If you do not have a meta key, the identical keystroke +can be generated by typing ESC first, and then typing k. Either +process is known as "metafying" the k key. + + The text M-C-k is read as `Meta-Control-k' and describes the +character produced by "metafying" C-k. + + In addition, several keys have their own names. Specifically, DEL, +ESC, LFD, SPC, RET, and TAB all stand for themselves when seen in this +text, or in an init file (*note Readline Init File::., for more info). + + +File: gdb.info, Node: Readline Interaction, Next: Readline Init File, Prev: Introduction and Notation, Up: Command Line Editing + +Readline Interaction +==================== + + Often during an interactive session you type in a long line of text, +only to notice that the first word on the line is misspelled. The +Readline library gives you a set of commands for manipulating the text +as you type it in, allowing you to just fix your typo, and not forcing +you to retype the majority of the line. Using these editing commands, +you move the cursor to the place that needs correction, and delete or +insert the text of the corrections. Then, when you are satisfied with +the line, you simply press RETURN. You do not have to be at the end of +the line to press RETURN; the entire line is accepted regardless of the +location of the cursor within the line. + +* Menu: + +* Readline Bare Essentials:: The least you need to know about Readline. +* Readline Movement Commands:: Moving about the input line. +* Readline Killing Commands:: How to delete text, and how to get it back! +* Readline Arguments:: Giving numeric arguments to commands. + + +File: gdb.info, Node: Readline Bare Essentials, Next: Readline Movement Commands, Up: Readline Interaction + +Readline Bare Essentials +------------------------ + + In order to enter characters into the line, simply type them. The +typed character appears where the cursor was, and then the cursor moves +one space to the right. If you mistype a character, you can use DEL to +back up, and delete the mistyped character. + + Sometimes you may miss typing a character that you wanted to type, +and not notice your error until you have typed several other +characters. In that case, you can type C-b to move the cursor to the +left, and then correct your mistake. Aftwerwards, you can move the +cursor to the right with C-f. + + When you add text in the middle of a line, you will notice that +characters to the right of the cursor get `pushed over' to make room +for the text that you have inserted. Likewise, when you delete text +behind the cursor, characters to the right of the cursor get `pulled +back' to fill in the blank space created by the removal of the text. A +list of the basic bare essentials for editing the text of an input line +follows. + +C-b + Move back one character. + +C-f + Move forward one character. + +DEL + Delete the character to the left of the cursor. + +C-d + Delete the character underneath the cursor. + +Printing characters + Insert itself into the line at the cursor. + +C-_ + Undo the last thing that you did. You can undo all the way back + to an empty line. + + +File: gdb.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction + +Readline Movement Commands +-------------------------- + + The above table describes the most basic possible keystrokes that +you need in order to do editing of the input line. For your +convenience, many other commands have been added in addition to C-b, +C-f, C-d, and DEL. Here are some commands for moving more rapidly +about the line. + +C-a + Move to the start of the line. + +C-e + Move to the end of the line. + +M-f + Move forward a word. + +M-b + Move backward a word. + +C-l + Clear the screen, reprinting the current line at the top. + + Notice how C-f moves forward a character, while M-f moves forward a +word. It is a loose convention that control keystrokes operate on +characters while meta keystrokes operate on words. + + +File: gdb.info, Node: Readline Killing Commands, Next: Readline Arguments, Prev: Readline Movement Commands, Up: Readline Interaction + +Readline Killing Commands +------------------------- + + "Killing" text means to delete the text from the line, but to save +it away for later use, usually by "yanking" it back into the line. If +the description for a command says that it `kills' text, then you can +be sure that you can get the text back in a different (or the same) +place later. + + Here is the list of commands for killing text. + +C-k + Kill the text from the current cursor position to the end of the + line. + +M-d + Kill from the cursor to the end of the current word, or if between + words, to the end of the next word. + +M-DEL + Kill from the cursor to the start of the previous word, or if + between words, to the start of the previous word. + +C-w + Kill from the cursor to the previous whitespace. This is + different than M-DEL because the word boundaries differ. + + And, here is how to "yank" the text back into the line. Yanking is + +C-y + Yank the most recently killed text back into the buffer at the + cursor. + +M-y + Rotate the kill-ring, and yank the new top. You can only do this + if the prior command is C-y or M-y. + + When you use a kill command, the text is saved in a "kill-ring". +Any number of consecutive kills save all of the killed text together, so +that when you yank it back, you get it in one clean sweep. The kill +ring is not line specific; the text that you killed on a previously +typed line is available to be yanked back later, when you are typing +another line. + + +File: gdb.info, Node: Readline Arguments, Prev: Readline Killing Commands, Up: Readline Interaction + +Readline Arguments +------------------ + + You can pass numeric arguments to Readline commands. Sometimes the +argument acts as a repeat count, other times it is the sign of the +argument that is significant. If you pass a negative argument to a +command which normally acts in a forward direction, that command will +act in a backward direction. For example, to kill text back to the +start of the line, you might type M- C-k. + + The general way to pass numeric arguments to a command is to type +meta digits before the command. If the first `digit' you type is a +minus sign (-), then the sign of the argument will be negative. Once +you have typed one meta digit to get the argument started, you can type +the remainder of the digits, and then the command. For example, to give +the C-d command an argument of 10, you could type M-1 0 C-d. + + +File: gdb.info, Node: Readline Init File, Prev: Readline Interaction, Up: Command Line Editing + +Readline Init File +================== + + Although the Readline library comes with a set of Emacs-like +keybindings, it is possible that you would like to use a different set +of keybindings. You can customize programs that use Readline by putting +commands in an "init" file in your home directory. The name of this +file is `~/.inputrc'. + + When a program which uses the Readline library starts up, the +`~/.inputrc' file is read, and the keybindings are set. + + In addition, the C-x C-r command re-reads this init file, thus +incorporating any changes that you might have made to it. + +* Menu: + +* Readline Init Syntax:: Syntax for the commands in `~/.inputrc'. +* Readline Vi Mode:: Switching to `vi' mode in Readline. + + +File: gdb.info, Node: Readline Init Syntax, Next: Readline Vi Mode, Up: Readline Init File + +Readline Init Syntax +-------------------- + + There are only four constructs allowed in the `~/.inputrc' file: + +Variable Settings + You can change the state of a few variables in Readline. You do + this by using the `set' command within the init file. Here is how + you would specify that you wish to use Vi line editing commands: + + set editing-mode vi + + Right now, there are only a few variables which can be set; so few + in fact, that we just iterate them here: + + `editing-mode' + The `editing-mode' variable controls which editing mode you + are using. By default, GNU Readline starts up in Emacs + editing mode, where the keystrokes are most similar to Emacs. + This variable can either be set to `emacs' or `vi'. + + `horizontal-scroll-mode' + This variable can either be set to `On' or `Off'. Setting it + to `On' means that the text of the lines that you edit will + scroll horizontally on a single screen line when they are + larger than the width of the screen, instead of wrapping onto + a new screen line. By default, this variable is set to `Off'. + + `mark-modified-lines' + This variable when set to `On', says to display an asterisk + (`*') at the starts of history lines which have been modified. + This variable is off by default. + + `prefer-visible-bell' + If this variable is set to `On' it means to use a visible + bell if one is available, rather than simply ringing the + terminal bell. By default, the value is `Off'. + +Key Bindings + The syntax for controlling keybindings in the `~/.inputrc' file is + simple. First you have to know the name of the command that you + want to change. The following pages contain tables of the command + name, the default keybinding, and a short description of what the + command does. + + Once you know the name of the command, simply place the name of + the key you wish to bind the command to, a colon, and then the + name of the command on a line in the `~/.inputrc' file. The name + of the key can be expressed in different ways, depending on which + is most comfortable for you. + + KEYNAME: FUNCTION-NAME or MACRO + KEYNAME is the name of a key spelled out in English. For + example: + Control-u: universal-argument + Meta-Rubout: backward-kill-word + Control-o: ">&output" + + In the above example, C-u is bound to the function + `universal-argument', and C-o is bound to run the macro + expressed on the right hand side (that is, to insert the text + `>&output' into the line). + + "KEYSEQ": FUNCTION-NAME or MACRO + KEYSEQ differs from KEYNAME above in that strings denoting an + entire key sequence can be specified. Simply place the key + sequence in double quotes. GNU Emacs style key escapes can + be used, as in the following example: + + "\C-u": universal-argument + "\C-x\C-r": re-read-init-file + "\e[11~": "Function Key 1" + + In the above example, C-u is bound to the function + `universal-argument' (just as it was in the first example), + C-x C-r is bound to the function `re-read-init-file', and ESC + [ 1 1 ~ is bound to insert the text `Function Key 1'. + +* Menu: + +* Commands For Moving:: Moving about the line. +* Commands For History:: Getting at previous lines. +* Commands For Text:: Commands for changing text. +* Commands For Killing:: Commands for killing and yanking. +* Numeric Arguments:: Specifying numeric arguments, repeat counts. +* Commands For Completion:: Getting Readline to do the typing for you. +* Miscellaneous Commands:: Other miscillaneous commands. + + +File: gdb.info, Node: Commands For Moving, Next: Commands For History, Up: Readline Init Syntax + +Commands For Moving +------------------- + +`beginning-of-line (C-a)' + Move to the start of the current line. + +`end-of-line (C-e)' + Move to the end of the line. + +`forward-char (C-f)' + Move forward a character. + +`backward-char (C-b)' + Move back a character. + +`forward-word (M-f)' + Move forward to the end of the next word. + +`backward-word (M-b)' + Move back to the start of this, or the previous, word. + +`clear-screen (C-l)' + Clear the screen leaving the current line at the top of the screen. + + +File: gdb.info, Node: Commands For History, Next: Commands For Text, Prev: Commands For Moving, Up: Readline Init Syntax + +Commands For Manipulating The History +------------------------------------- + +`accept-line (Newline, Return)' + Accept the line regardless of where the cursor is. If this line is + non-empty, add it to the history list. If this line was a history + line, then restore the history line to its original state. + +`previous-history (C-p)' + Move `up' through the history list. + +`next-history (C-n)' + Move `down' through the history list. + +`beginning-of-history (M-<)' + Move to the first line in the history. + +`end-of-history (M->)' + Move to the end of the input history, i.e., the line you are + entering! + +`reverse-search-history (C-r)' + Search backward starting at the current line and moving `up' + through the history as necessary. This is an incremental search. + +`forward-search-history (C-s)' + Search forward starting at the current line and moving `down' + through the the history as neccessary. + + +File: gdb.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Readline Init Syntax + +Commands For Changing Text +-------------------------- + +`delete-char (C-d)' + Delete the character under the cursor. If the cursor is at the + beginning of the line, and there are no characters in the line, and + the last character typed was not C-d, then return EOF. + +`backward-delete-char (Rubout)' + Delete the character behind the cursor. A numeric arg says to kill + the characters instead of deleting them. + +`quoted-insert (C-q, C-v)' + Add the next character that you type to the line verbatim. This is + how to insert things like C-q for example. + +`tab-insert (M-TAB)' + Insert a tab character. + +`self-insert (a, b, A, 1, !, ...)' + Insert yourself. + +`transpose-chars (C-t)' + Drag the character before point forward over the character at + point. Point moves forward as well. If point is at the end of + the line, then transpose the two characters before point. + Negative args don't work. + +`transpose-words (M-t)' + Drag the word behind the cursor past the word in front of the + cursor moving the cursor over that word as well. + +`upcase-word (M-u)' + Uppercase all letters in the current (or following) word. With a + negative argument, do the previous word, but do not move point. + +`downcase-word (M-l)' + Lowercase all letters in the current (or following) word. With a + negative argument, do the previous word, but do not move point. + +`capitalize-word (M-c)' + Uppercase the first letter in the current (or following) word. + With a negative argument, do the previous word, but do not move + point. + + +File: gdb.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Readline Init Syntax + +Killing And Yanking +------------------- + +`kill-line (C-k)' + Kill the text from the current cursor position to the end of the + line. + +`backward-kill-line ()' + Kill backward to the beginning of the line. This is normally + unbound. + +`kill-word (M-d)' + Kill from the cursor to the end of the current word, or if between + words, to the end of the next word. + +`backward-kill-word (M-DEL)' + Kill the word behind the cursor. + +`unix-line-discard (C-u)' + Do what C-u used to do in Unix line input. We save the killed + text on the kill-ring, though. + +`unix-word-rubout (C-w)' + Do what C-w used to do in Unix line input. The killed text is + saved on the kill-ring. This is different than backward-kill-word + because the word boundaries differ. + +`yank (C-y)' + Yank the top of the kill ring into the buffer at point. + +`yank-pop (M-y)' + Rotate the kill-ring, and yank the new top. You can only do this + if the prior command is yank or yank-pop. + + +File: gdb.info, Node: Numeric Arguments, Next: Commands For Completion, Prev: Commands For Killing, Up: Readline Init Syntax + +Specifying Numeric Arguments +---------------------------- + +`digit-argument (M-0, M-1, ... M--)' + Add this digit to the argument already accumulating, or start a new + argument. M- starts a negative argument. + +`universal-argument ()' + Do what C-u does in emacs. By default, this is not bound. + + +File: gdb.info, Node: Commands For Completion, Next: Miscellaneous Commands, Prev: Numeric Arguments, Up: Readline Init Syntax + +Letting Readline Type For You +----------------------------- + +`complete (TAB)' + Attempt to do completion on the text before point. This is + implementation defined. Generally, if you are typing a filename + argument, you can do filename completion; if you are typing a + command, you can do command completion, if you are typing in a + symbol to GDB, you can do symbol name completion, if you are + typing in a variable to Bash, you can do variable name + completion... + +`possible-completions (M-?)' + List the possible completions of the text before point. + + +File: gdb.info, Node: Miscellaneous Commands, Prev: Commands For Completion, Up: Readline Init Syntax + +Some Miscellaneous Commands +--------------------------- + +`re-read-init-file (C-x C-r)' + Read in the contents of your `~/.inputrc' file, and incorporate + any bindings found there. + +`abort (C-g)' + Stop running the current editing command. + +`prefix-meta (ESC)' + Make the next character that you type be metafied. This is for + people without a meta key. Typing ESC f is equivalent to typing + M-f. + +`undo (C-_)' + Incremental undo, separately remembered for each line. + +`revert-line (M-r)' + Undo all changes made to this line. This is like typing the `undo' + command enough times to get back to the beginning. + + +File: gdb.info, Node: Readline Vi Mode, Prev: Readline Init Syntax, Up: Readline Init File + +Readline Vi Mode +---------------- + + While the Readline library does not have a full set of Vi editing +functions, it does contain enough to allow simple editing of the line. + + In order to switch interactively between Emacs and Vi editing modes, +use the command M-C-j (toggle-editing-mode). + + When you enter a line in Vi mode, you are already placed in +`insertion' mode, as if you had typed an `i'. Pressing ESC switches +you into `edit' mode, where you can edit the text of the line with the +standard Vi movement keys, move to previous history lines with `k', and +following lines with `j', and so forth. + + +File: gdb.info, Node: Using History Interactively, Next: Renamed Commands, Prev: Command Line Editing, Up: Top + +Using History Interactively +*************************** + + This chapter describes how to use the GNU History Library +interactively, from a user's standpoint. + +* Menu: + +* History Interaction:: What it feels like using History as a user. + + +File: gdb.info, Node: History Interaction, Up: Using History Interactively + +History Interaction +=================== + + The History library provides a history expansion feature that is +similar to the history expansion in Csh. The following text describes +the sytax that you use to manipulate the history information. + + History expansion takes place in two parts. The first is to +determine which line from the previous history should be used during +substitution. The second is to select portions of that line for +inclusion into the current one. The line selected from the previous +history is called the "event", and the portions of that line that are +acted upon are called "words". The line is broken into words in the +same fashion that the Bash shell does, so that several English (or +Unix) words surrounded by quotes are considered as one word. + +* Menu: + +* Event Designators:: How to specify which history line to use. +* Word Designators:: Specifying which words are of interest. +* Modifiers:: Modifying the results of susbstitution. + + +File: gdb.info, Node: Event Designators, Next: Word Designators, Up: History Interaction + +Event Designators +----------------- + + An event designator is a reference to a command line entry in the +history list. + +`!' + Start a history subsititution, except when followed by a space, + tab, or the end of the line... = or (. + +`!!' + Refer to the previous command. This is a synonym for `!-1'. + +`!n' + Refer to command line N. + +`!-n' + Refer to the command line N lines back. + +`!string' + Refer to the most recent command starting with STRING. + +`!?string'[`?'] + Refer to the most recent command containing STRING. + + +File: gdb.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction + +Word Designators +---------------- + + A : separates the event specification from the word designator. It +can be omitted if the word designator begins with a ^, $, * or %. +Words are numbered from the beginning of the line, with the first word +being denoted by a 0 (zero). + +`0 (zero)' + The zero'th word. For many applications, this is the command word. + +`n' + The N'th word. + +`^' + The first argument. that is, word 1. + +`$' + The last argument. + +`%' + The word matched by the most recent `?string?' search. + +`x-y' + A range of words; `-Y' Abbreviates `0-Y'. + +`*' + All of the words, excepting the zero'th. This is a synonym for + `1-$'. It is not an error to use * if there is just one word in + the event. The empty string is returned in that case. + + +File: gdb.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction + +Modifiers +--------- + + After the optional word designator, you can add a sequence of one or +more of the following modifiers, each preceded by a :. + +`#' + The entire command line typed so far. This means the current + command, not the previous command, so it really isn't a word + designator, and doesn't belong in this section. + +`h' + Remove a trailing pathname component, leaving only the head. + +`r' + Remove a trailing suffix of the form `.'SUFFIX, leaving the + basename. + +`e' + Remove all but the suffix. + +`t' + Remove all leading pathname components, leaving the tail. + +`p' + Print the new command but do not execute it. + + +File: gdb.info, Node: Renamed Commands, Next: Formatting Documentation, Prev: Using History Interactively, Up: Top + +Renamed Commands +**************** + + The following commands were renamed in GDB 4, in order to make the +command set as a whole more consistent and easier to use and remember: + + OLD COMMAND NEW COMMAND + --------------- ------------------------------- + add-syms add-symbol-file + delete environment unset environment + info convenience show convenience + info copying show copying + info directories show directories + info editing show commands + info history show values + info targets help target + info values show values + info version show version + info warranty show warranty + set/show addressprint set/show print address + set/show array-max set/show print elements + set/show arrayprint set/show print array + set/show asm-demangle set/show print asm-demangle + set/show caution set/show confirm + set/show demangle set/show print demangle + set/show history write set/show history save + set/show prettyprint set/show print pretty + set/show screen-height set/show height + set/show screen-width set/show width + set/show sevenbit-strings set/show print sevenbit-strings + set/show unionprint set/show print union + set/show vtblprint set/show print vtbl + + unset [No longer an alias for delete] + + +File: gdb.info, Node: Formatting Documentation, Next: Installing GDB, Prev: Renamed Commands, Up: Top + +Formatting Documentation +************************ + + The GDB 4 release includes an already-formatted reference card, ready +for printing with PostScript or GhostScript, in the `gdb' subdirectory +of the main source directory(1). If you can use PostScript or +GhostScript with your printer, you can print the reference card +immediately with `refcard.ps'. + + The release also includes the source for the reference card. You +can format it, using TeX, by typing: + + make refcard.dvi + + The GDB reference card is designed to print in landscape mode on US +"letter" size paper; that is, on a sheet 11 inches wide by 8.5 inches +high. You will need to specify this form of printing as an option to +your DVI output program. + + All the documentation for GDB comes as part of the machine-readable +distribution. The documentation is written in Texinfo format, which is +a documentation system that uses a single source file to produce both +on-line information and a printed manual. You can use one of the Info +formatting commands to create the on-line version of the documentation +and TeX (or `texi2roff') to typeset the printed version. + + GDB includes an already formatted copy of the on-line Info version of +this manual in the `gdb' subdirectory. The main Info file is +`gdb-VERSION-NUMBER/gdb/gdb.info', and it refers to subordinate files +matching `gdb.info*' in the same directory. If necessary, you can +print out these files, or read them with any editor; but they are +easier to read using the `info' subsystem in GNU Emacs or the +standalone `info' program, available as part of the GNU Texinfo +distribution. + + If you want to format these Info files yourself, you need one of the +Info formatting programs, such as `texinfo-format-buffer' or `makeinfo'. + + If you have `makeinfo' installed, and are in the top level GDB +source directory (`gdb-4.11', in the case of version 4.11), you can +make the Info file by typing: + + cd gdb + make gdb.info + + If you want to typeset and print copies of this manual, you need TeX, +a program to print its DVI output files, and `texinfo.tex', the Texinfo +definitions file. + + TeX is a typesetting program; it does not print files directly, but +produces output files called DVI files. To print a typeset document, +you need a program to print DVI files. If your system has TeX +installed, chances are it has such a program. The precise command to +use depends on your system; `lpr -d' is common; another (for PostScript +devices) is `dvips'. The DVI print command may require a file name +without any extension or a `.dvi' extension. + + TeX also requires a macro definitions file called `texinfo.tex'. +This file tells TeX how to typeset a document written in Texinfo +format. On its own, TeX cannot read, much less typeset a Texinfo file. +`texinfo.tex' is distributed with GDB and is located in the +`gdb-VERSION-NUMBER/texinfo' directory. + + If you have TeX and a DVI printer program installed, you can typeset +and print this manual. First switch to the the `gdb' subdirectory of +the main source directory (for example, to `gdb-4.11/gdb') and then +type: + + make gdb.dvi + + ---------- Footnotes ---------- + + (1) In `gdb-4.11/gdb/refcard.ps' of the version 4.11 release. + + +File: gdb.info, Node: Installing GDB, Next: Index, Prev: Formatting Documentation, Up: Top + +Installing GDB +************** + + GDB comes with a `configure' script that automates the process of +preparing GDB for installation; you can then use `make' to build the +`gdb' program. + + The GDB distribution includes all the source code you need for GDB in +a single directory, whose name is usually composed by appending the +version number to `gdb'. + + For example, the GDB version 4.11 distribution is in the `gdb-4.11' +directory. That directory contains: + +`gdb-4.11/configure (and supporting files)' + script for configuring GDB and all its supporting libraries. + +`gdb-4.11/gdb' + the source specific to GDB itself + +`gdb-4.11/bfd' + source for the Binary File Descriptor library + +`gdb-4.11/include' + GNU include files + +`gdb-4.11/libiberty' + source for the `-liberty' free software library + +`gdb-4.11/opcodes' + source for the library of opcode tables and disassemblers + +`gdb-4.11/readline' + source for the GNU command-line interface + +`gdb-4.11/glob' + source for the GNU filename pattern-matching subroutine + +`gdb-4.11/mmalloc' + source for the GNU memory-mapped malloc package + + The simplest way to configure and build GDB is to run `configure' +from the `gdb-VERSION-NUMBER' source directory, which in this example +is the `gdb-4.11' directory. + + First switch to the `gdb-VERSION-NUMBER' source directory if you are +not already in it; then run `configure'. Pass the identifier for the +platform on which GDB will run as an argument. + + For example: + + cd gdb-4.11 + ./configure HOST + make + +where HOST is an identifier such as `sun4' or `decstation', that +identifies the platform where GDB will run. (You can often leave off +HOST; `configure' tries to guess the correct value by examining your +system.) + + Running `configure HOST' and then running `make' builds the `bfd', +`readline', `mmalloc', and `libiberty' libraries, then `gdb' itself. +The configured source files, and the binaries, are left in the +corresponding source directories. + + `configure' is a Bourne-shell (`/bin/sh') script; if your system +does not recognize this automatically when you run a different shell, +you may need to run `sh' on it explicitly: + + sh configure HOST + + If you run `configure' from a directory that contains source +directories for multiple libraries or programs, such as the `gdb-4.11' +source directory for version 4.11, `configure' creates configuration +files for every directory level underneath (unless you tell it not to, +with the `--norecursion' option). + + You can run the `configure' script from any of the subordinate +directories in the GDB distribution if you only want to configure that +subdirectory, but be sure to specify a path to it. + + For example, with version 4.11, type the following to configure only +the `bfd' subdirectory: + + cd gdb-4.11/bfd + ../configure HOST + + You can install `gdb' anywhere; it has no hardwired paths. However, +you should make sure that the shell on your path (named by the `SHELL' +environment variable) is publicly readable. Remember that GDB uses the +shell to start your program--some systems refuse to let GDB debug child +processes whose programs are not readable. + +* Menu: + +* Separate Objdir:: Compiling GDB in another directory +* Config Names:: Specifying names for hosts and targets +* configure Options:: Summary of options for configure + + +File: gdb.info, Node: Separate Objdir, Next: Config Names, Up: Installing GDB + +Compiling GDB in another directory +================================== + + If you want to run GDB versions for several host or target machines, +you need a different `gdb' compiled for each combination of host and +target. `configure' is designed to make this easy by allowing you to +generate each configuration in a separate subdirectory, rather than in +the source directory. If your `make' program handles the `VPATH' +feature (GNU `make' does), running `make' in each of these directories +builds the `gdb' program specified there. + + To build `gdb' in a separate directory, run `configure' with the +`--srcdir' option to specify where to find the source. (You also need +to specify a path to find `configure' itself from your working +directory. If the path to `configure' would be the same as the +argument to `--srcdir', you can leave out the `--srcdir' option; it +will be assumed.) + + For example, with version 4.11, you can build GDB in a separate +directory for a Sun 4 like this: + + cd gdb-4.11 + mkdir ../gdb-sun4 + cd ../gdb-sun4 + ../gdb-4.11/configure sun4 + make + + When `configure' builds a configuration using a remote source +directory, it creates a tree for the binaries with the same structure +(and using the same names) as the tree under the source directory. In +the example, you'd find the Sun 4 library `libiberty.a' in the +directory `gdb-sun4/libiberty', and GDB itself in `gdb-sun4/gdb'. + + One popular reason to build several GDB configurations in separate +directories is to configure GDB for cross-compiling (where GDB runs on +one machine--the host--while debugging programs that run on another +machine--the target). You specify a cross-debugging target by giving +the `--target=TARGET' option to `configure'. + + When you run `make' to build a program or library, you must run it +in a configured directory--whatever directory you were in when you +called `configure' (or one of its subdirectories). + + The `Makefile' that `configure' generates in each source directory +also runs recursively. If you type `make' in a source directory such +as `gdb-4.11' (or in a separate configured directory configured with +`--srcdir=PATH/gdb-4.11'), you will build all the required libraries, +and then build GDB. + + When you have multiple hosts or targets configured in separate +directories, you can run `make' on them in parallel (for example, if +they are NFS-mounted on each of the hosts); they will not interfere +with each other. + + +File: gdb.info, Node: Config Names, Next: configure Options, Prev: Separate Objdir, Up: Installing GDB + +Specifying names for hosts and targets +====================================== + + The specifications used for hosts and targets in the `configure' +script are based on a three-part naming scheme, but some short +predefined aliases are also supported. The full naming scheme encodes +three pieces of information in the following pattern: + + ARCHITECTURE-VENDOR-OS + + For example, you can use the alias `sun4' as a HOST argument, or as +the value for TARGET in a `--target=TARGET' option. The equivalent +full name is `sparc-sun-sunos4'. + + The `configure' script accompanying GDB does not provide any query +facility to list all supported host and target names or aliases. +`configure' calls the Bourne shell script `config.sub' to map +abbreviations to full names; you can read the script, if you wish, or +you can use it to test your guesses on abbreviations--for example: + + % sh config.sub sun4 + sparc-sun-sunos4.1.1 + % sh config.sub sun3 + m68k-sun-sunos4.1.1 + % sh config.sub decstation + mips-dec-ultrix4.2 + % sh config.sub hp300bsd + m68k-hp-bsd + % sh config.sub i386v + i386-unknown-sysv + % sh config.sub i786v + Invalid configuration `i786v': machine `i786v' not recognized + +`config.sub' is also distributed in the GDB source directory +(`gdb-4.11', for version 4.11). + + +File: gdb.info, Node: configure Options, Prev: Config Names, Up: Installing GDB + +`configure' options +=================== + + Here is a summary of the `configure' options and arguments that are +most often useful for building GDB. `configure' also has several other +options not listed here. *note : (configure.info)What Configure Does, +for a full explanation of `configure'. + + configure [--help] + [--prefix=DIR] + [--srcdir=PATH] + [--norecursion] [--rm] + [--target=TARGET] HOST + +You may introduce options with a single `-' rather than `--' if you +prefer; but you may abbreviate option names if you use `--'. + +`--help' + Display a quick summary of how to invoke `configure'. + +`-prefix=DIR' + Configure the source to install programs and files under directory + `DIR'. + +`--srcdir=PATH' + *Warning: using this option requires GNU `make', or another `make' + that implements the `VPATH' feature.* + Use this option to make configurations in directories separate + from the GDB source directories. Among other things, you can use + this to build (or maintain) several configurations simultaneously, + in separate directories. `configure' writes configuration + specific files in the current directory, but arranges for them to + use the source in the directory PATH. `configure' will create + directories under the working directory in parallel to the source + directories below PATH. + +`--norecursion' + Configure only the directory level where `configure' is executed; + do not propagate configuration to subdirectories. + +`--rm' + *Remove* files otherwise built during configuration. + +`--target=TARGET' + Configure GDB for cross-debugging programs running on the specified + TARGET. Without this option, GDB is configured to debug programs + that run on the same machine (HOST) as GDB itself. + + There is no convenient way to generate a list of all available + targets. + +`HOST ...' + Configure GDB to run on the specified HOST. + + There is no convenient way to generate a list of all available + hosts. + +`configure' accepts other options, for compatibility with configuring +other GNU tools recursively; but these are the only options that affect +GDB or its supporting libraries. + diff --git a/gnu/usr.bin/gdb/doc/gdb.info-8 b/gnu/usr.bin/gdb/doc/gdb.info-8 new file mode 100644 index 00000000000..1d259e04323 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.info-8 @@ -0,0 +1,657 @@ +This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input +file gdb.texinfo. + +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY + This file documents the GNU debugger GDB. + + This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU +Source-Level Debugger' for GDB Version 4.11. + + Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. + + 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. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the entire resulting derived work is distributed under the terms +of a permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions. + + +File: gdb.info, Node: Index, Prev: Installing GDB, Up: Top + +Index +***** + +* Menu: + +* #: Command Syntax. +* $bpnum: Set Breaks. +* $cdir: Source Path. +* $cwd: Source Path. +* $_: Convenience Vars. +* $__: Convenience Vars. +* .: M2 Scope. +* .esgdbinit: Command Files. +* .os68gdbinit: Command Files. +* .vxgdbinit: Command Files. +* /proc: Process Information. +* 386: Remote Serial. +* 680x0: Remote Serial. +* @: Arrays. +* # in Modula-2: GDB/M2. +* $$: Value History. +* $_ and info breakpoints: Set Breaks. +* $_ and info line: Machine Code. +* $_, $__, and value history: Memory. +* $: Value History. +* breakpoint subroutine, remote: Stub Contents. +* heuristic-fence-post (MIPS): MIPS Stack. +* remotedebug, MIPS protocol: MIPS Remote. +* retransmit-timeout, MIPS protocol: MIPS Remote. +* timeout, MIPS protocol: MIPS Remote. +* vi style command editing: Readline Vi Mode. +* .gdbinit: Command Files. +* COFF versus C++: Cplus expressions. +* ECOFF and C++: Cplus expressions. +* ELF/DWARF and C++: Cplus expressions. +* ELF/stabs and C++: Cplus expressions. +* XCOFF and C++: Cplus expressions. +* GDB bugs, reporting: Bug Reporting. +* {TYPE}: Expressions. +* a.out and C++: Cplus expressions. +* abbreviation: Command Syntax. +* active targets: Active Targets. +* add-symbol-file: Files. +* add-syms: Renamed Commands. +* AMD 29K register stack: Registers. +* AMD EB29K: Target Commands. +* AMD29K via UDI: UDI29K Remote. +* arguments (to your program): Arguments. +* artificial array: Arrays. +* assembly instructions: Machine Code. +* assignment: Assignment. +* attach: Attach. +* attach: Attach. +* automatic display: Auto Display. +* b: Set Breaks. +* backtrace: Backtrace. +* break: Set Breaks. +* break in overloaded functions: Debugging C plus plus. +* breakpoint commands: Break Commands. +* breakpoint conditions: Conditions. +* breakpoint numbers: Breakpoints. +* breakpoint on memory address: Breakpoints. +* breakpoint on variable modification: Breakpoints. +* breakpoints: Breakpoints. +* bt: Backtrace. +* bug criteria: Bug Criteria. +* bug reports: Bug Reporting. +* bugs in GDB: GDB Bugs. +* c: Continuing and Stepping. +* C and C++: C. +* C and C++ checks: C Checks. +* C and C++ constants: C Operators. +* C and C++ defaults: C Defaults. +* C and C++ operators: C. +* C++: C. +* C++ and object formats: Cplus expressions. +* C++ exception handling: Debugging C plus plus. +* C++ scope resolution: Variables. +* C++ support, not in COFF: Cplus expressions. +* C++ symbol decoding style: Print Settings. +* C++ symbol display: Debugging C plus plus. +* call: Calling. +* call overloaded functions: Cplus expressions. +* call stack: Stack. +* calling functions: Calling. +* calling make: Shell Commands. +* casts, to view memory: Expressions. +* catch: Exception Handling. +* catch exceptions: Frame Info. +* cd: Working Directory. +* cdir: Source Path. +* checks, range: Type Checking. +* checks, type: Checks. +* checksum, for GDB remote: Protocol. +* clear: Delete Breaks. +* clearing breakpoints, watchpoints: Delete Breaks. +* colon, doubled as scope operator: M2 Scope. +* colon-colon: M2 Scope. +* colon-colon: Variables. +* command files: Hooks. +* command files: Command Files. +* command line editing: Editing. +* commands: Break Commands. +* commands for C++: Debugging C plus plus. +* commands to STDBUG (ST2000): ST2000 Remote. +* comment: Command Syntax. +* compilation directory: Source Path. +* completion: Completion. +* completion of quoted strings: Completion. +* condition: Conditions. +* conditional breakpoints: Conditions. +* configuring GDB: Installing GDB. +* confirmation: Messages/Warnings. +* connect (to STDBUG): ST2000 Remote. +* continue: Continuing and Stepping. +* continuing: Continuing and Stepping. +* controlling terminal: Input/Output. +* convenience variables: Convenience Vars. +* core: Files. +* core dump file: Files. +* core-file: Files. +* CPU simulator: Simulator. +* crash of debugger: Bug Criteria. +* current directory: Source Path. +* cwd: Source Path. +* d: Delete Breaks. +* debugger crash: Bug Criteria. +* debugging optimized code: Compilation. +* debugging stub, example: Protocol. +* debugging target: Targets. +* define: Define. +* delete: Delete Breaks. +* delete breakpoints: Delete Breaks. +* delete display: Auto Display. +* delete environment: Renamed Commands. +* deleting breakpoints, watchpoints: Delete Breaks. +* detach: Attach. +* device: Hitachi Remote. +* directories for source files: Source Path. +* directory: Source Path. +* directory, compilation: Source Path. +* directory, current: Source Path. +* dis: Disabling. +* disable: Disabling. +* disable breakpoints: Disabling. +* disable display: Auto Display. +* disabled breakpoints: Disabling. +* disassemble: Machine Code. +* display: Auto Display. +* display of expressions: Auto Display. +* do: Selection. +* document: Define. +* documentation: Formatting Documentation. +* down: Selection. +* down-silently: Selection. +* download to H8/300 or H8/500: Files. +* download to Hitachi SH: Files. +* download to Nindy-960: Files. +* download to VxWorks: VxWorks Download. +* dynamic linking: Files. +* eb.log: Remote Log. +* EB29K board: EB29K Remote. +* EBMON: Comms (EB29K). +* echo: Output. +* editing: Editing. +* editing-mode: Readline Init Syntax. +* emacs: Emacs. +* enable: Disabling. +* enable breakpoints: Disabling. +* enable display: Auto Display. +* enabled breakpoints: Disabling. +* end: Break Commands. +* entering numbers: Numbers. +* environment (of your program): Environment. +* error on valid input: Bug Criteria. +* event designators: Event Designators. +* examining data: Data. +* examining memory: Memory. +* exception handlers: Exception Handling. +* exception handlers: Frame Info. +* exceptionHandler: Bootstrapping. +* exec-file: Files. +* executable file: Files. +* exiting GDB: Quitting GDB. +* expansion: History Interaction. +* expressions: Expressions. +* expressions in C or C++: C. +* expressions in C++: Cplus expressions. +* expressions in Modula-2: Modula-2. +* f: Selection. +* fatal signal: Bug Criteria. +* fatal signals: Signals. +* fg: Continuing and Stepping. +* file: Files. +* finish: Continuing and Stepping. +* flinching: Messages/Warnings. +* floating point: Floating Point Hardware. +* floating point registers: Registers. +* floating point, MIPS remote: MIPS Remote. +* flush_i_cache: Bootstrapping. +* foo: Symbol Errors. +* format options: Print Settings. +* formatted output: Output Formats. +* Fortran: Summary. +* forward-search: Search. +* frame: Selection. +* frame: Frames. +* frame number: Frames. +* frame pointer: Frames. +* frameless execution: Frames. +* g++: C. +* GDB reference card: Formatting Documentation. +* gdbserver: Server. +* getDebugChar: Bootstrapping. +* GNU C++: C. +* h: Help. +* H8/300 or H8/500 download: Files. +* H8/300 or H8/500 simulator: Simulator. +* handle: Signals. +* handle_exception: Stub Contents. +* handling signals: Signals. +* help: Help. +* help target: Target Commands. +* help user-defined: Define. +* history expansion: History. +* history file: History. +* history number: Value History. +* history save: History. +* history size: History. +* history substitution: History. +* Hitachi SH download: Files. +* Hitachi SH simulator: Simulator. +* horizontal-scroll-mode: Readline Init Syntax. +* i: Help. +* i/o: Input/Output. +* i386-stub.c: Remote Serial. +* i960: i960-Nindy Remote. +* ignore: Conditions. +* ignore count (of breakpoint): Conditions. +* INCLUDE_RDB: VxWorks Remote. +* info: Help. +* info address: Symbols. +* info all-registers: Registers. +* info args: Frame Info. +* info breakpoints: Set Breaks. +* info catch: Frame Info. +* info convenience: Renamed Commands. +* info copying: Renamed Commands. +* info directories: Renamed Commands. +* info display: Auto Display. +* info editing: Renamed Commands. +* info f: Frame Info. +* info files: Files. +* info float: Floating Point Hardware. +* info frame: Frame Info. +* info frame: Show. +* info functions: Symbols. +* info history: Renamed Commands. +* info line: Machine Code. +* info locals: Frame Info. +* info proc: Process Information. +* info proc id: Process Information. +* info proc mappings: Process Information. +* info proc status: Process Information. +* info proc times: Process Information. +* info program: Stopping. +* info registers: Registers. +* info s: Backtrace. +* info set: Help. +* info share: Files. +* info sharedlibrary: Files. +* info signals: Signals. +* info source: Symbols. +* info source: Show. +* info sources: Symbols. +* info stack: Backtrace. +* info target: Files. +* info targets: Renamed Commands. +* info terminal: Input/Output. +* info types: Symbols. +* info values: Renamed Commands. +* info variables: Symbols. +* info version: Renamed Commands. +* info warranty: Renamed Commands. +* info watchpoints: Set Watchpoints. +* inheritance: Debugging C plus plus. +* init file: Command Files. +* init file name: Command Files. +* initial frame: Frames. +* innermost frame: Frames. +* inspect: Data. +* installation: Installing GDB. +* instructions, assembly: Machine Code. +* Intel: Remote Serial. +* interaction, readline: Readline Interaction. +* internal GDB breakpoints: Set Breaks. +* interrupt: Quitting GDB. +* interrupting remote programs: Debug Session. +* invalid input: Bug Criteria. +* jump: Jumping. +* kill: Kill Process. +* l: List. +* languages: Languages. +* latest breakpoint: Set Breaks. +* leaving GDB: Quitting GDB. +* linespec: List. +* list: List. +* listing machine instructions: Machine Code. +* load: Files. +* log file for EB29K: Remote Log. +* m68k-stub.c: Remote Serial. +* machine instructions: Machine Code. +* maint info breakpoints: Set Breaks. +* maint print psymbols: Symbols. +* maint print symbols: Symbols. +* make: Shell Commands. +* mapped: Files. +* mark-modified-lines: Readline Init Syntax. +* member functions: Cplus expressions. +* memory tracing: Breakpoints. +* memory, viewing as typed object: Expressions. +* memory-mapped symbol file: Files. +* memset: Bootstrapping. +* MIPS boards: MIPS Remote. +* MIPS remote floating point: MIPS Remote. +* MIPS stack: MIPS Stack. +* Modula-2: Modula-2. +* Modula-2 built-ins: M2 Operators. +* Modula-2 checks: M2 Checks. +* Modula-2 constants: Built-In Func/Proc. +* Modula-2 defaults: M2 Defaults. +* Modula-2 operators: M2 Operators. +* Modula-2, deviations from: Deviations. +* Motorola 680x0: Remote Serial. +* multiple targets: Active Targets. +* n: Continuing and Stepping. +* names of symbols: Symbols. +* namespace in C++: Cplus expressions. +* negative breakpoint numbers: Set Breaks. +* next: Continuing and Stepping. +* nexti: Continuing and Stepping. +* ni: Continuing and Stepping. +* Nindy: i960-Nindy Remote. +* number representation: Numbers. +* numbers for breakpoints: Breakpoints. +* object formats and C++: Cplus expressions. +* online documentation: Help. +* optimized code, debugging: Compilation. +* outermost frame: Frames. +* output: Output. +* output formats: Output Formats. +* overloading: Breakpoint Menus. +* overloading in C++: Debugging C plus plus. +* packets, reporting on stdout: Protocol. +* partial symbol dump: Symbols. +* patching binaries: Patching. +* path: Environment. +* pauses in output: Screen Size. +* pipes: Starting. +* prefer-visible-bell: Readline Init Syntax. +* print: Data. +* print settings: Print Settings. +* printf: Output. +* printing data: Data. +* process image: Process Information. +* prompt: Prompt. +* protocol, GDB remote serial: Protocol. +* ptype: Symbols. +* putDebugChar: Bootstrapping. +* pwd: Working Directory. +* q: Quitting GDB. +* quit: Quitting GDB. +* quotes in commands: Completion. +* quoting names: Symbols. +* raise exceptions: Exception Handling. +* range checking: Type Checking. +* rbreak: Set Breaks. +* reading symbols immediately: Files. +* readline: Editing. +* readnow: Files. +* redirection: Input/Output. +* reference card: Formatting Documentation. +* reference declarations: Cplus expressions. +* register stack, AMD29K: Registers. +* registers: Registers. +* regular expression: Set Breaks. +* reloading symbols: Messages/Warnings. +* remote connection without stubs: Server. +* remote debugging: Remote. +* remote programs, interrupting: Debug Session. +* remote serial debugging summary: Debug Session. +* remote serial debugging, overview: Remote Serial. +* remote serial protocol: Protocol. +* remote serial stub: Stub Contents. +* remote serial stub list: Remote Serial. +* remote serial stub, initialization: Stub Contents. +* remote serial stub, main routine: Stub Contents. +* remote stub, example: Protocol. +* remote stub, support routines: Bootstrapping. +* repeating commands: Command Syntax. +* reporting bugs in GDB: GDB Bugs. +* reset: Nindy Reset. +* response time, MIPS debugging: MIPS Stack. +* resuming execution: Continuing and Stepping. +* RET: Command Syntax. +* return: Returning. +* returning from a function: Returning. +* reverse-search: Search. +* run: Starting. +* running: Starting. +* running 29K programs: EB29K Remote. +* running VxWorks tasks: VxWorks Attach. +* s: Continuing and Stepping. +* saving symbol table: Files. +* scope: M2 Scope. +* search: Search. +* searching: Search. +* selected frame: Stack. +* serial connections, debugging: Protocol. +* serial device, Hitachi micros: Hitachi Remote. +* serial line speed, Hitachi micros: Hitachi Remote. +* serial line, target remote: Debug Session. +* serial protocol, GDB remote: Protocol. +* set addressprint: Renamed Commands. +* set args: Arguments. +* set array-max: Renamed Commands. +* set arrayprint: Renamed Commands. +* set asm-demangle: Renamed Commands. +* set caution: Renamed Commands. +* set check: Range Checking. +* set check: Type Checking. +* set check range: Range Checking. +* set check type: Type Checking. +* set complaints: Messages/Warnings. +* set confirm: Messages/Warnings. +* set demangle: Renamed Commands. +* set demangle-style: Print Settings. +* set editing: Editing. +* set environment: Environment. +* set height: Screen Size. +* set history expansion: History. +* set history filename: History. +* set history save: History. +* set history size: History. +* set history write: Renamed Commands. +* set language: Manually. +* set listsize: List. +* set mipsfpu off: MIPS Remote. +* set prettyprint: Renamed Commands. +* set print address: Print Settings. +* set print array: Print Settings. +* set print asm-demangle: Print Settings. +* set print demangle: Print Settings. +* set print elements: Print Settings. +* set print max-symbolic-offset: Print Settings. +* set print object: Print Settings. +* set print pretty: Print Settings. +* set print sevenbit-strings: Print Settings. +* set print symbol-filename: Print Settings. +* set print union: Print Settings. +* set print vtbl: Print Settings. +* set prompt: Prompt. +* set radix: Numbers. +* set remotedebug: Protocol. +* set retransmit-timeout: MIPS Remote. +* set rstack_high_address: Registers. +* set screen-height: Renamed Commands. +* set screen-width: Renamed Commands. +* set sevenbit-strings: Renamed Commands. +* set symbol-reloading: Messages/Warnings. +* set timeout: MIPS Remote. +* set unionprint: Renamed Commands. +* set variable: Assignment. +* set verbose: Messages/Warnings. +* set vtblprint: Renamed Commands. +* set width: Screen Size. +* set write: Patching. +* setting variables: Assignment. +* setting watchpoints: Set Watchpoints. +* set_debug_traps: Stub Contents. +* share: Files. +* shared libraries: Files. +* sharedlibrary: Files. +* shell: Shell Commands. +* shell escape: Shell Commands. +* show: Help. +* show addressprint: Renamed Commands. +* show args: Arguments. +* show array-max: Renamed Commands. +* show arrayprint: Renamed Commands. +* show asm-demangle: Renamed Commands. +* show caution: Renamed Commands. +* show check range: Range Checking. +* show check type: Type Checking. +* show commands: History. +* show complaints: Messages/Warnings. +* show confirm: Messages/Warnings. +* show convenience: Convenience Vars. +* show copying: Help. +* show demangle: Renamed Commands. +* show demangle-style: Print Settings. +* show directories: Source Path. +* show editing: Editing. +* show environment: Environment. +* show height: Screen Size. +* show history: History. +* show history write: Renamed Commands. +* show language: Show. +* show listsize: List. +* show paths: Environment. +* show prettyprint: Renamed Commands. +* show print address: Print Settings. +* show print array: Print Settings. +* show print asm-demangle: Print Settings. +* show print demangle: Print Settings. +* show print elements: Print Settings. +* show print max-symbolic-offset: Print Settings. +* show print object: Print Settings. +* show print pretty: Print Settings. +* show print sevenbit-strings: Print Settings. +* show print symbol-filename: Print Settings. +* show print union: Print Settings. +* show print vtbl: Print Settings. +* show prompt: Prompt. +* show radix: Numbers. +* show remotedebug: Protocol. +* show retransmit-timeout: MIPS Remote. +* show rstack_high_address: Registers. +* show screen-height: Renamed Commands. +* show screen-width: Renamed Commands. +* show sevenbit-strings: Renamed Commands. +* show timeout: MIPS Remote. +* show unionprint: Renamed Commands. +* show user: Define. +* show values: Value History. +* show verbose: Messages/Warnings. +* show version: Help. +* show vtblprint: Renamed Commands. +* show warranty: Help. +* show width: Screen Size. +* show write: Patching. +* si: Continuing and Stepping. +* signal: Signaling. +* signals: Signals. +* silent: Break Commands. +* sim: Simulator. +* simulator: Simulator. +* simulator, H8/300 or H8/500: Simulator. +* simulator, Hitachi SH: Simulator. +* simulator, Z8000: Simulator. +* size of screen: Screen Size. +* source: Command Files. +* source path: Source Path. +* sparc-stub.c: Remote Serial. +* speed: Hitachi Remote. +* st2000 CMD: ST2000 Remote. +* ST2000 auxiliary commands: ST2000 Remote. +* stack frame: Frames. +* stack on MIPS: MIPS Stack. +* stacking targets: Active Targets. +* starting: Starting. +* STDBUG commands (ST2000): ST2000 Remote. +* step: Continuing and Stepping. +* stepi: Continuing and Stepping. +* stepping: Continuing and Stepping. +* stub example, remote debugging: Protocol. +* stupid questions: Messages/Warnings. +* symbol decoding style, C++: Print Settings. +* symbol dump: Symbols. +* symbol names: Symbols. +* symbol overloading: Breakpoint Menus. +* symbol table: Files. +* symbol-file: Files. +* symbols, reading immediately: Files. +* target: Targets. +* target amd-eb: Target Commands. +* target core: Target Commands. +* target exec: Target Commands. +* target hms: Target Commands. +* target mips PORT: MIPS Remote. +* target nindy: Target Commands. +* target remote: Target Commands. +* target sim: Target Commands. +* target sim: Simulator. +* target st2000: Target Commands. +* target udi: Target Commands. +* target vxworks: Target Commands. +* tbreak: Set Breaks. +* TCP port, target remote: Debug Session. +* terminal: Input/Output. +* this: Cplus expressions. +* toggle-editing-mode: Readline Vi Mode. +* tty: Input/Output. +* type casting memory: Expressions. +* type checking: Checks. +* type conversions in C++: Cplus expressions. +* u: Continuing and Stepping. +* udi: UDI29K Remote. +* UDI: UDI29K Remote. +* undisplay: Auto Display. +* unset: Renamed Commands. +* unset environment: Environment. +* until: Continuing and Stepping. +* up: Selection. +* up-silently: Selection. +* user-defined command: Define. +* value history: Value History. +* variable name conflict: Variables. +* variable values, wrong: Variables. +* variables, setting: Assignment. +* version number: Help. +* VxWorks: VxWorks Remote. +* watch: Set Watchpoints. +* watchpoints: Breakpoints. +* whatis: Symbols. +* where: Backtrace. +* word completion: Completion. +* working directory: Source Path. +* working directory (of your program): Working Directory. +* working language: Languages. +* writing into corefiles: Patching. +* writing into executables: Patching. +* wrong values: Variables. +* x: Memory. +* Z8000 simulator: Simulator. + + diff --git a/gnu/usr.bin/gdb/doc/gdb.texinfo b/gnu/usr.bin/gdb/doc/gdb.texinfo new file mode 100644 index 00000000000..a2f293deb2a --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdb.texinfo @@ -0,0 +1,8591 @@ +\input texinfo @c -*-texinfo-*- +@c Copyright (c) 1988 1989 1990 1991 1992 1993 Free Software Foundation, Inc. +@c +@c %**start of header +@c makeinfo ignores cmds prev to setfilename, so its arg cannot make use +@c of @set vars. However, you can override filename with makeinfo -o. +@setfilename gdb.info +@c +@include gdb-cfg.texi +@c +@ifset GENERIC +@settitle Debugging with @value{GDBN} +@end ifset +@ifclear GENERIC +@settitle Debugging with @value{GDBN} (@value{TARGET}) +@end ifclear +@setchapternewpage odd +@c %**end of header + +@iftex +@c @smallbook +@c @cropmarks +@end iftex + +@finalout +@syncodeindex ky cp + +@c readline appendices use @vindex +@syncodeindex vr cp + +@c ===> NOTE! <== +@c Determine the edition number in *three* places by hand: +@c 1. First ifinfo section 2. title page 3. top node +@c To find the locations, search for !!set + +@c GDB CHANGELOG CONSULTED BETWEEN: +@c Fri Oct 11 23:27:06 1991 John Gilmore (gnu at cygnus.com) +@c Sat Dec 22 02:51:40 1990 John Gilmore (gnu at cygint) + +@c THIS MANUAL REQUIRES TEXINFO-2 macros and info-makers to format properly. + +@ifinfo +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. zoo@cygnus.com is developing this facility. +@format +START-INFO-DIR-ENTRY +* Gdb:: The GNU debugger. +END-INFO-DIR-ENTRY +@end format +@end ifinfo +@c +@c +@ifinfo +This file documents the GNU debugger @value{GDBN}. + +@c !!set edition, date, version +This is Edition 4.09, August 1993, +of @cite{Debugging with @value{GDBN}: the GNU Source-Level Debugger} +for GDB Version @value{GDBVN}. + +Copyright (C) 1988, '89, '90, '91, '92, '93 Free Software Foundation, Inc. + +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. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@titlepage +@title Debugging with @value{GDBN} +@subtitle The GNU Source-Level Debugger +@ifclear GENERIC +@subtitle (@value{TARGET}) +@end ifclear +@sp 1 +@c !!set edition, date, version +@subtitle Edition 4.09, for @value{GDBN} version @value{GDBVN} +@subtitle August 1993 +@author Richard M. Stallman and Roland H. Pesch +@page +@tex +{\parskip=0pt +\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@prep.ai.mit.edu.)\par +\hfill {\it Debugging with @value{GDBN}}\par +\hfill \TeX{}info \texinfoversion\par +\hfill pesch\@cygnus.com\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1988, '89, '90, '91, '92, '93 Free Software +Foundation, Inc. +@sp 2 +Published by the Free Software Foundation @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA @* +Printed copies are available for $20 each. @* +ISBN 1-882114-11-6 @* + +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. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage +@page + +@ifinfo +@node Top +@top Debugging with @value{GDBN} + +This file describes @value{GDBN}, the GNU symbolic debugger. + +@c !!set edition, date, version +This is Edition 4.09, August 1993, for GDB Version @value{GDBVN}. + +@menu +* Summary:: Summary of @value{GDBN} +@ifset NOVEL +* New Features:: New features since GDB version 3.5 +@end ifset +@ifclear BARETARGET +* Sample Session:: A sample @value{GDBN} session +@end ifclear + +* Invocation:: Getting in and out of @value{GDBN} +* Commands:: @value{GDBN} commands +* Running:: Running programs under @value{GDBN} +* Stopping:: Stopping and continuing +* Stack:: Examining the stack +* Source:: Examining source files +* Data:: Examining data +@ifclear CONLY +* Languages:: Using @value{GDBN} with different languages +@end ifclear +@ifset CONLY +* C:: C language support +@end ifset +@c remnant makeinfo bug, blank line needed after two end-ifs? + +* Symbols:: Examining the symbol table +* Altering:: Altering execution +* GDB Files:: @value{GDBN} files +* Targets:: Specifying a debugging target +* Controlling GDB:: Controlling @value{GDBN} +* Sequences:: Canned sequences of commands +@ifclear DOSHOST +* Emacs:: Using @value{GDBN} under GNU Emacs +@end ifclear + +* GDB Bugs:: Reporting bugs in @value{GDBN} +* Command Line Editing:: Facilities of the readline library +* Using History Interactively:: +@ifset NOVEL +* Renamed Commands:: +@end ifset +@ifclear PRECONFIGURED +* Formatting Documentation:: How to format and print GDB documentation +* Installing GDB:: Installing GDB +@end ifclear + +* Index:: Index +@end menu +@end ifinfo + +@node Summary +@unnumbered Summary of @value{GDBN} + +The purpose of a debugger such as @value{GDBN} is to allow you to see what is +going on ``inside'' another program while it executes---or what another +program was doing at the moment it crashed. + +@value{GDBN} can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +@itemize @bullet +@item +Start your program, specifying anything that might affect its behavior. + +@item +Make your program stop on specified conditions. + +@item +Examine what has happened, when your program has stopped. + +@item +Change things in your program, so you can experiment with correcting the +effects of one bug and go on to learn about another. +@end itemize + +@ifclear CONLY +@ifclear MOD2 +You can use @value{GDBN} to debug programs written in C or C++. +@end ifclear +@ifset MOD2 +You can use @value{GDBN} to debug programs written in C, C++, and +Modula-2. +@end ifset +@ifset FORTRAN +@cindex Fortran +@value{GDBN} can be used to debug programs written in Fortran, although +it does not yet support entering expressions, printing values, etc. +using Fortran syntax. It may be necessary to refer to some variables +with a trailing underscore. +@end ifset +@end ifclear + +@menu +* Free Software:: Freely redistributable software +* Contributors:: Contributors to GDB +@end menu + +@node Free Software +@unnumberedsec Free software + +@value{GDBN} is @dfn{free software}, protected by the GNU General Public License +(GPL). The GPL gives you the freedom to copy or adapt a licensed +program---but every person getting a copy also gets with it the +freedom to modify that copy (which means that they must get access to +the source code), and the freedom to distribute further copies. +Typical software companies use copyrights to limit your freedoms; the +Free Software Foundation uses the GPL to preserve these freedoms. + +Fundamentally, the General Public License is a license which says that +you have these freedoms and that you cannot take these freedoms away +from anyone else. + +@node Contributors +@unnumberedsec Contributors to GDB + +Richard Stallman was the original author of GDB, and of many other GNU +programs. Many others have contributed to its development. This +section attempts to credit major contributors. One of the virtues of +free software is that everyone is free to contribute to it; with +regret, we cannot actually acknowledge everyone here. The file +@file{ChangeLog} in the GDB distribution approximates a blow-by-blow +account. + +Changes much prior to version 2.0 are lost in the mists of time. + +@quotation +@emph{Plea:} Additions to this section are particularly welcome. If you +or your friends (or enemies, to be evenhanded) have been unfairly +omitted from this list, we would like to add your names! +@end quotation + +So that they may not regard their long labor as thankless, we +particularly thank those who shepherded GDB through major releases: Fred +Fish (releases 4.11, 4.10, 4.9), Stu Grossman and John Gilmore (releases +4.8, 4.7, 4.6, 4.5, 4.4), John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and +3.9); Jim Kingdon (releases 3.5, 3.4, 3.3); and Randy Smith (releases +3.2, 3.1, 3.0). As major maintainer of GDB for some period, each +contributed significantly to the structure, stability, and capabilities +of the entire debugger. + +Richard Stallman, assisted at various times by Peter TerMaat, Chris +Hanson, and Richard Mlynarik, handled releases through 2.8. + +@ifclear CONLY +Michael Tiemann is the author of most of the GNU C++ support in GDB, +with significant additional contributions from Per Bothner. James +Clark wrote the GNU C++ demangler. Early work on C++ was by Peter +TerMaat (who also did much general update work leading to release 3.0). +@end ifclear + +GDB 4 uses the BFD subroutine library to examine multiple +object-file formats; BFD was a joint project of David V. +Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore. + +David Johnson wrote the original COFF support; Pace Willison did +the original support for encapsulated COFF. + +Adam de Boor and Bradley Davis contributed the ISI Optimum V support. +Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS +support. Jean-Daniel Fekete contributed Sun 386i support. Chris +Hanson improved the HP9000 support. Noboyuki Hikichi and Tomoyuki +Hasei contributed Sony/News OS 3 support. David Johnson contributed +Encore Umax support. Jyrki Kuoppala contributed Altos 3068 support. +Keith Packard contributed NS32K support. Doug Rabson contributed +Acorn Risc Machine support. Chris Smith contributed Convex support +(and Fortran debugging). Jonathan Stone contributed Pyramid support. +Michael Tiemann contributed SPARC support. Tim Tucker contributed +support for the Gould NP1 and Gould Powernode. Pace Willison +contributed Intel 386 support. Jay Vosburgh contributed Symmetry +support. + +Rich Schaefer and Peter Schauer helped with support of SunOS shared +libraries. + +Jay Fenlason and Roland McGrath ensured that GDB and GAS agree about +several machine instruction sets. + +Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped +develop remote debugging. Intel Corporation and Wind River Systems +contributed remote debugging modules for their products. + +Brian Fox is the author of the readline libraries providing +command-line editing and command history. + +Andrew Beers of SUNY Buffalo wrote the language-switching code, +@ifset MOD2 +the Modula-2 support, +@end ifset +and contributed the Languages chapter of this manual. + +Fred Fish wrote most of the support for Unix System Vr4. +@ifclear CONLY +He also enhanced the command-completion support to cover C++ overloaded +symbols. +@end ifclear + +Hitachi America, Ltd. sponsored the support for Hitachi microprocessors. + +@ifset NOVEL +@node New Features +@unnumbered New Features since GDB Version 3.5 + +@table @emph +@item Targets +Using the new command @code{target}, you can select at runtime whether +you are debugging local files, local processes, standalone systems over +a serial port, realtime systems over a TCP/IP connection, etc. The +command @code{load} can download programs into a remote system. Serial +stubs are available for Motorola 680x0, Intel 80386, and Sparc remote +systems; GDB also supports debugging realtime processes running under +VxWorks, using SunRPC Remote Procedure Calls over TCP/IP to talk to a +debugger stub on the target system. Internally, GDB now uses a function +vector to mediate access to different targets; if you need to add your +own support for a remote protocol, this makes it much easier. + +@item Watchpoints +GDB now sports watchpoints as well as breakpoints. You can use a +watchpoint to stop execution whenever the value of an expression +changes, without having to predict a particular place in your program +where this may happen. + +@item Wide Output +Commands that issue wide output now insert newlines at places designed +to make the output more readable. + +@item Object Code Formats +GDB uses a new library called the Binary File Descriptor (BFD) Library +to permit it to switch dynamically, without reconfiguration or +recompilation, between different object-file formats. Formats currently +supported are COFF, ELF, a.out, Intel 960 b.out, MIPS ECOFF, HPPA SOM +(with stabs debugging), and S-records; files may be read as .o files, +archive libraries, or core dumps. BFD is available as a subroutine +library so that other programs may take advantage of it, and the other +GNU binary utilities are being converted to use it. + +@item Configuration and Ports +Compile-time configuration (to select a particular architecture and +operating system) is much easier. The script @code{configure} now +allows you to configure GDB as either a native debugger or a +cross-debugger. @xref{Installing GDB}, for details on how to +configure. + +@item Interaction +The user interface to the GDB control variables is simpler, +and is consolidated in two commands, @code{set} and @code{show}. Output +lines are now broken at readable places, rather than overflowing onto +the next line. You can suppress output of machine-level addresses, +displaying only source language information. + +@item C++ +GDB now supports C++ multiple inheritance (if used with a GCC +version 2 compiler), and also has limited support for C++ exception +handling, with the commands @code{catch} and @code{info catch}: GDB +can break when an exception is raised, before the stack is peeled back +to the exception handler's context. + +@ifset MOD2 +@item Modula-2 +GDB now has preliminary support for the GNU Modula-2 compiler, currently +under development at the State University of New York at Buffalo. +Coordinated development of both GDB and the GNU Modula-2 compiler will +continue. Other Modula-2 compilers are currently not supported, and +attempting to debug programs compiled with them will likely result in an +error as the symbol table of the executable is read in. +@end ifset + +@item Command Rationalization +Many GDB commands have been renamed to make them easier to remember +and use. In particular, the subcommands of @code{info} and +@code{show}/@code{set} are grouped to make the former refer to the state +of your program, and the latter refer to the state of GDB itself. +@xref{Renamed Commands}, for details on what commands were renamed. + +@item Shared Libraries +GDB 4 can debug programs and core files that use SunOS, SVR4, or IBM RS/6000 +shared libraries. + +@item Reference Card +GDB 4 has a reference card. @xref{Formatting Documentation,,Formatting +the Documentation}, for instructions about how to print it. +@end table +@end ifset + +@ifclear BARETARGET +@node Sample Session +@chapter A Sample @value{GDBN} Session + +You can use this manual at your leisure to read all about @value{GDBN}. +However, a handful of commands are enough to get started using the +debugger. This chapter illustrates those commands. + +@iftex +In this sample session, we emphasize user input like this: @b{input}, +to make it easier to pick out from the surrounding output. +@end iftex + +@c FIXME: this example may not be appropriate for some configs, where +@c FIXME...primary interest is in remote use. + +One of the preliminary versions of GNU @code{m4} (a generic macro +processor) exhibits the following bug: sometimes, when we change its +quote strings from the default, the commands used to capture one macro +definition within another stop working. In the following short @code{m4} +session, we define a macro @code{foo} which expands to @code{0000}; we +then use the @code{m4} built-in @code{defn} to define @code{bar} as the +same thing. However, when we change the open quote string to +@code{} and the close quote string to @code{}, the same +procedure fails to define a new synonym @code{baz}: + +@smallexample +$ @b{cd gnu/m4} +$ @b{./m4} +@b{define(foo,0000)} + +@b{foo} +0000 +@b{define(bar,defn(`foo'))} + +@b{bar} +0000 +@b{changequote(,)} + +@b{define(baz,defn(foo))} +@b{baz} +@b{C-d} +m4: End of input: 0: fatal error: EOF in string +@end smallexample + +@noindent +Let us use @value{GDBN} to try to see what is going on. + +@smallexample +$ @b{@value{GDBP} m4} +@c FIXME: this falsifies the exact text played out, to permit smallbook +@c FIXME... format to come out better. +GDB is free software and you are welcome to distribute copies + of it under certain conditions; type "show copying" to see + the conditions. +There is absolutely no warranty for GDB; type "show warranty" + for details. +GDB @value{GDBVN}, Copyright 1993 Free Software Foundation, Inc... +(@value{GDBP}) +@end smallexample + +@noindent +@value{GDBN} reads only enough symbol data to know where to find the rest when +needed; as a result, the first prompt comes up very quickly. We now +tell @value{GDBN} to use a narrower display width than usual, so that examples +will fit in this manual. + +@smallexample +(@value{GDBP}) @b{set width 70} +@end smallexample + +@noindent +We need to see how the @code{m4} built-in @code{changequote} works. +Having looked at the source, we know the relevant subroutine is +@code{m4_changequote}, so we set a breakpoint there with the @value{GDBN} +@code{break} command. + +@smallexample +(@value{GDBP}) @b{break m4_changequote} +Breakpoint 1 at 0x62f4: file builtin.c, line 879. +@end smallexample + +@noindent +Using the @code{run} command, we start @code{m4} running under @value{GDBN} +control; as long as control does not reach the @code{m4_changequote} +subroutine, the program runs as usual: + +@smallexample +(@value{GDBP}) @b{run} +Starting program: /work/Editorial/gdb/gnu/m4/m4 +@b{define(foo,0000)} + +@b{foo} +0000 +@end smallexample + +@noindent +To trigger the breakpoint, we call @code{changequote}. @value{GDBN} +suspends execution of @code{m4}, displaying information about the +context where it stops. + +@smallexample +@b{changequote(,)} + +Breakpoint 1, m4_changequote (argc=3, argv=0x33c70) + at builtin.c:879 +879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3)) +@end smallexample + +@noindent +Now we use the command @code{n} (@code{next}) to advance execution to +the next line of the current function. + +@smallexample +(@value{GDBP}) @b{n} +882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\ + : nil, +@end smallexample + +@noindent +@code{set_quotes} looks like a promising subroutine. We can go into it +by using the command @code{s} (@code{step}) instead of @code{next}. +@code{step} goes to the next line to be executed in @emph{any} +subroutine, so it steps into @code{set_quotes}. + +@smallexample +(@value{GDBP}) @b{s} +set_quotes (lq=0x34c78 "", rq=0x34c88 "") + at input.c:530 +530 if (lquote != def_lquote) +@end smallexample + +@noindent +The display that shows the subroutine where @code{m4} is now +suspended (and its arguments) is called a stack frame display. It +shows a summary of the stack. We can use the @code{backtrace} +command (which can also be spelled @code{bt}), to see where we are +in the stack as a whole: the @code{backtrace} command displays a +stack frame for each active subroutine. + +@smallexample +(@value{GDBP}) @b{bt} +#0 set_quotes (lq=0x34c78 "", rq=0x34c88 "") + at input.c:530 +#1 0x6344 in m4_changequote (argc=3, argv=0x33c70) + at builtin.c:882 +#2 0x8174 in expand_macro (sym=0x33320) at macro.c:242 +#3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30) + at macro.c:71 +#4 0x79dc in expand_input () at macro.c:40 +#5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195 +@end smallexample + +@noindent +We will step through a few more lines to see what happens. The first two +times, we can use @samp{s}; the next two times we use @code{n} to avoid +falling into the @code{xstrdup} subroutine. + +@smallexample +(@value{GDBP}) @b{s} +0x3b5c 532 if (rquote != def_rquote) +(@value{GDBP}) @b{s} +0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \ +def_lquote : xstrdup(lq); +(@value{GDBP}) @b{n} +536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ + : xstrdup(rq); +(@value{GDBP}) @b{n} +538 len_lquote = strlen(rquote); +@end smallexample + +@noindent +The last line displayed looks a little odd; we can examine the variables +@code{lquote} and @code{rquote} to see if they are in fact the new left +and right quotes we specified. We use the command @code{p} +(@code{print}) to see their values. + +@smallexample +(@value{GDBP}) @b{p lquote} +$1 = 0x35d40 "" +(@value{GDBP}) @b{p rquote} +$2 = 0x35d50 "" +@end smallexample + +@noindent +@code{lquote} and @code{rquote} are indeed the new left and right quotes. +To look at some context, we can display ten lines of source +surrounding the current line with the @code{l} (@code{list}) command. + +@smallexample +(@value{GDBP}) @b{l} +533 xfree(rquote); +534 +535 lquote = (lq == nil || *lq == '\0') ? def_lquote\ + : xstrdup (lq); +536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ + : xstrdup (rq); +537 +538 len_lquote = strlen(rquote); +539 len_rquote = strlen(lquote); +540 @} +541 +542 void +@end smallexample + +@noindent +Let us step past the two lines that set @code{len_lquote} and +@code{len_rquote}, and then examine the values of those variables. + +@smallexample +(@value{GDBP}) @b{n} +539 len_rquote = strlen(lquote); +(@value{GDBP}) @b{n} +540 @} +(@value{GDBP}) @b{p len_lquote} +$3 = 9 +(@value{GDBP}) @b{p len_rquote} +$4 = 7 +@end smallexample + +@noindent +That certainly looks wrong, assuming @code{len_lquote} and +@code{len_rquote} are meant to be the lengths of @code{lquote} and +@code{rquote} respectively. We can set them to better values using +the @code{p} command, since it can print the value of +any expression---and that expression can include subroutine calls and +assignments. + +@smallexample +(@value{GDBP}) @b{p len_lquote=strlen(lquote)} +$5 = 7 +(@value{GDBP}) @b{p len_rquote=strlen(rquote)} +$6 = 9 +@end smallexample + +@noindent +Is that enough to fix the problem of using the new quotes with the +@code{m4} built-in @code{defn}? We can allow @code{m4} to continue +executing with the @code{c} (@code{continue}) command, and then try the +example that caused trouble initially: + +@smallexample +(@value{GDBP}) @b{c} +Continuing. + +@b{define(baz,defn(foo))} + +baz +0000 +@end smallexample + +@noindent +Success! The new quotes now work just as well as the default ones. The +problem seems to have been just the two typos defining the wrong +lengths. We allow @code{m4} exit by giving it an EOF as input: + +@smallexample +@b{C-d} +Program exited normally. +@end smallexample + +@noindent +The message @samp{Program exited normally.} is from @value{GDBN}; it +indicates @code{m4} has finished executing. We can end our @value{GDBN} +session with the @value{GDBN} @code{quit} command. + +@smallexample +(@value{GDBP}) @b{quit} +@end smallexample +@end ifclear + +@node Invocation +@chapter Getting In and Out of @value{GDBN} + +This chapter discusses how to start @value{GDBN}, and how to get out of it. +(The essentials: type @samp{@value{GDBP}} to start GDB, and type @kbd{quit} +or @kbd{C-d} to exit.) + +@menu +* Invoking GDB:: How to start @value{GDBN} +* Quitting GDB:: How to quit @value{GDBN} +* Shell Commands:: How to use shell commands inside @value{GDBN} +@end menu + +@node Invoking GDB +@section Invoking @value{GDBN} + +@ifset H8EXCLUSIVE +For details on starting up @value{GDBP} as a +remote debugger attached to a Hitachi microprocessor, see @ref{Hitachi +Remote,,@value{GDBN} and Hitachi Microprocessors}. +@end ifset + +Invoke @value{GDBN} by running the program @code{@value{GDBP}}. Once started, +@value{GDBN} reads commands from the terminal until you tell it to exit. + +You can also run @code{@value{GDBP}} with a variety of arguments and options, +to specify more of your debugging environment at the outset. + +@ifset GENERIC +The command-line options described here are designed +to cover a variety of situations; in some environments, some of these +options may effectively be unavailable. +@end ifset + +The most usual way to start @value{GDBN} is with one argument, +specifying an executable program: + +@example +@value{GDBP} @var{program} +@end example + +@ifclear BARETARGET +@noindent +You can also start with both an executable program and a core file +specified: + +@example +@value{GDBP} @var{program} @var{core} +@end example + +You can, instead, specify a process ID as a second argument, if you want +to debug a running process: + +@example +@value{GDBP} @var{program} 1234 +@end example + +@noindent +would attach @value{GDBN} to process @code{1234} (unless you also have a file +named @file{1234}; @value{GDBN} does check for a core file first). + +Taking advantage of the second command-line argument requires a fairly +complete operating system; when you use @value{GDBN} as a remote debugger +attached to a bare board, there may not be any notion of ``process'', +and there is often no way to get a core dump. +@end ifclear + +@noindent +You can further control how @value{GDBN} starts up by using command-line +options. @value{GDBN} itself can remind you of the options available. + +@noindent +Type + +@example +@value{GDBP} -help +@end example + +@noindent +to display all available options and briefly describe their use +(@samp{@value{GDBP} -h} is a shorter equivalent). + +All options and command line arguments you give are processed +in sequential order. The order makes a difference when the +@samp{-x} option is used. + + +@menu +@ifclear GENERIC +@ifset REMOTESTUB +* Remote Serial:: @value{GDBN} remote serial protocol +@end ifset +@ifset I960 +* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) +@end ifset +@ifset AMD29K +* UDI29K Remote:: @value{GDBN} and the UDI protocol for AMD29K +* EB29K Remote:: @value{GDBN} with a remote EB29K +@end ifset +@ifset VXWORKS +* VxWorks Remote:: @value{GDBN} and VxWorks +@end ifset +@ifset ST2000 +* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 +@end ifset +@ifset H8 +* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors +@end ifset +@ifset MIPS +* MIPS Remote:: @value{GDBN} and MIPS boards +@end ifset +@ifset SIMS +* Simulator:: Simulated CPU target +@end ifset +@end ifclear +@c remnant makeinfo bug requires this blank line after *two* end-ifblahs: + +* File Options:: Choosing files +* Mode Options:: Choosing modes +@end menu + +@ifclear GENERIC +@include remote.texi +@end ifclear + +@node File Options +@subsection Choosing files + +@ifclear BARETARGET +When @value{GDBN} starts, it reads any arguments other than options as +specifying an executable file and core file (or process ID). This is +the same as if the arguments were specified by the @samp{-se} and +@samp{-c} options respectively. (@value{GDBN} reads the first argument +that does not have an associated option flag as equivalent to the +@samp{-se} option followed by that argument; and the second argument +that does not have an associated option flag, if any, as equivalent to +the @samp{-c} option followed by that argument.) +@end ifclear +@ifset BARETARGET +When @value{GDBN} starts, it reads any argument other than options as +specifying an executable file. This is the same as if the argument was +specified by the @samp{-se} option. +@end ifset + +Many options have both long and short forms; both are shown in the +following list. @value{GDBN} also recognizes the long forms 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 @samp{--} rather +than @samp{-}, though we illustrate the more usual convention.) + +@table @code +@item -symbols @var{file} +@itemx -s @var{file} +Read symbol table from file @var{file}. + +@item -exec @var{file} +@itemx -e @var{file} +Use file @var{file} as the executable file to execute when +@ifset BARETARGET +appropriate. +@end ifset +@ifclear BARETARGET +appropriate, and for examining pure data in conjunction with a core +dump. +@end ifclear + +@item -se @var{file} +Read symbol table from file @var{file} and use it as the executable +file. + +@ifclear BARETARGET +@item -core @var{file} +@itemx -c @var{file} +Use file @var{file} as a core dump to examine. + +@item -c @var{number} +Connect to process ID @var{number}, as with the @code{attach} command +(unless there is a file in core-dump format named @var{number}, in which +case @samp{-c} specifies that file as a core dump to read). +@end ifclear + +@item -command @var{file} +@itemx -x @var{file} +Execute @value{GDBN} commands from file @var{file}. @xref{Command +Files,, Command files}. + +@item -directory @var{directory} +@itemx -d @var{directory} +Add @var{directory} to the path to search for source files. + +@ifclear BARETARGET +@item -m +@itemx -mapped +@emph{Warning: this option depends on operating system facilities that are not +supported on all systems.}@* +If memory-mapped files are available on your system through the @code{mmap} +system call, you can use this option +to have @value{GDBN} write the symbols from your +program into a reusable file in the current directory. If the program you are debugging is +called @file{/tmp/fred}, the mapped symbol file will be @file{./fred.syms}. +Future @value{GDBN} debugging sessions will notice the presence of this file, +and will quickly map in symbol information from it, rather than reading +the symbol table from the executable program. + +@c FIXME! Really host, not target? +The @file{.syms} file is specific to the host machine where @value{GDBN} +is run. It holds an exact image of the internal @value{GDBN} symbol +table. It cannot be shared across multiple host platforms. +@end ifclear + +@item -r +@itemx -readnow +Read each symbol file's entire symbol table immediately, rather than +the default, which is to read it incrementally as it is needed. +This makes startup slower, but makes future operations faster. +@end table + +@ifclear BARETARGET +The @code{-mapped} and @code{-readnow} options are typically combined in +order to build a @file{.syms} file that contains complete symbol +information. (@xref{Files,,Commands to specify files}, for information +on @file{.syms} files.) A simple GDB invocation to do nothing but build +a @file{.syms} file for future use is: + +@example + gdb -batch -nx -mapped -readnow programname +@end example +@end ifclear + +@node Mode Options +@subsection Choosing modes + +You can run @value{GDBN} in various alternative modes---for example, in +batch mode or quiet mode. + +@table @code +@item -nx +@itemx -n +Do not execute commands from any initialization files (normally called +@file{@value{GDBINIT}}). Normally, the commands in these files are +executed after all the command options and arguments have been +processed. @xref{Command Files,,Command files}. + +@item -quiet +@itemx -q +``Quiet''. Do not print the introductory and copyright messages. These +messages are also suppressed in batch mode. + +@item -batch +Run in batch mode. Exit with status @code{0} after processing all the +command files specified with @samp{-x} (and all commands from +initialization files, if not inhibited with @samp{-n}). Exit with +nonzero status if an error occurs in executing the @value{GDBN} commands +in the command files. + +Batch mode may be useful for running @value{GDBN} as a filter, for example to +download and run a program on another computer; in order to make this +more useful, the message + +@example +Program exited normally. +@end example + +@noindent +(which is ordinarily issued whenever a program running under @value{GDBN} control +terminates) is not issued when running in batch mode. + +@item -cd @var{directory} +Run @value{GDBN} using @var{directory} as its working directory, +instead of the current directory. + +@ifset LUCID +@item -context @var{authentication} +When the Energize programming system starts up @value{GDBN}, it uses this +option to trigger an alternate mode of interaction. +@var{authentication} is a pair of numeric codes that identify @value{GDBN} +as a client in the Energize environment. Avoid this option when you run +@value{GDBN} directly from the command line. See @ref{Energize,,Using +@value{GDBN} with Energize} for more discussion of using @value{GDBN} with Energize. +@end ifset + +@ifclear DOSHOST +@item -fullname +@itemx -f +Emacs sets this option when it runs @value{GDBN} as a subprocess. It tells @value{GDBN} +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 your program stops). This recognizable format looks +like two @samp{\032} characters, followed by the file name, line number +and character position separated by colons, and a newline. The +Emacs-to-@value{GDBN} interface program uses the two @samp{\032} characters as +a signal to display the source code for the frame. +@end ifclear + +@ifset SERIAL +@item -b @var{bps} +Set the line speed (baud rate or bits per second) of any serial +interface used by @value{GDBN} for remote debugging. + +@item -tty @var{device} +Run using @var{device} for your program's standard input and output. +@c FIXME: kingdon thinks there is more to -tty. Investigate. +@end ifset +@end table + +@node Quitting GDB +@section Quitting @value{GDBN} +@cindex exiting @value{GDBN} +@cindex leaving @value{GDBN} + +@table @code +@item quit +@kindex quit +@kindex q +To exit @value{GDBN}, use the @code{quit} command (abbreviated @code{q}), or type +an end-of-file character (usually @kbd{C-d}). +@end table + +@cindex interrupt +An interrupt (often @kbd{C-c}) will not exit from @value{GDBN}, but rather +will terminate the action of any @value{GDBN} command that is in progress and +return to @value{GDBN} command level. It is safe to type the interrupt +character at any time because @value{GDBN} does not allow it to take effect +until a time when it is safe. + +@ifclear BARETARGET +If you have been using @value{GDBN} to control an attached process or +device, you can release it with the @code{detach} command +(@pxref{Attach, ,Debugging an already-running process}). +@end ifclear + +@node Shell Commands +@section Shell commands + +If you need to execute occasional shell commands during your +debugging session, there is no need to leave or suspend @value{GDBN}; you can +just use the @code{shell} command. + +@table @code +@item shell @var{command string} +@kindex shell +@cindex shell escape +Invoke a the standard shell to execute @var{command string}. +@ifclear DOSHOST +If it exists, the environment variable @code{SHELL} determines which +shell to run. Otherwise @value{GDBN} uses @code{/bin/sh}. +@end ifclear +@end table + +The utility @code{make} is often needed in development environments. +You do not have to use the @code{shell} command for this purpose in +@value{GDBN}: + +@table @code +@item make @var{make-args} +@kindex make +@cindex calling make +Execute the @code{make} program with the specified +arguments. This is equivalent to @samp{shell make @var{make-args}}. +@end table + +@node Commands +@chapter @value{GDBN} Commands + +You can abbreviate a @value{GDBN} command to the first few letters of the command +name, if that abbreviation is unambiguous; and you can repeat certain +@value{GDBN} commands by typing just @key{RET}. You can also use the @key{TAB} +key to get @value{GDBN} to fill out the rest of a word in a command (or to +show you the alternatives available, if there is more than one possibility). + +@menu +* Command Syntax:: How to give commands to @value{GDBN} +* Completion:: Command completion +* Help:: How to ask @value{GDBN} for help +@end menu + +@node Command Syntax +@section Command syntax + +A @value{GDBN} command is a single line of input. There is no limit on +how long it can be. It starts with a command name, which is followed by +arguments whose meaning depends on the command name. For example, the +command @code{step} accepts an argument which is the number of times to +step, as in @samp{step 5}. You can also use the @code{step} command +with no arguments. Some command names do not allow any arguments. + +@cindex abbreviation +@value{GDBN} command names may always be truncated if that abbreviation is +unambiguous. Other possible command abbreviations are listed in the +documentation for individual commands. In some cases, even ambiguous +abbreviations are allowed; for example, @code{s} is specially defined as +equivalent to @code{step} even though there are other commands whose +names start with @code{s}. You can test abbreviations by using them as +arguments to the @code{help} command. + +@cindex repeating commands +@kindex RET +A blank line as input to @value{GDBN} (typing just @key{RET}) means to +repeat the previous command. Certain commands (for example, @code{run}) +will not repeat this way; these are commands for which unintentional +repetition might cause trouble and which you are unlikely to want to +repeat. + +The @code{list} and @code{x} commands, when you repeat them with +@key{RET}, construct new arguments rather than repeating +exactly as typed. This permits easy scanning of source or memory. + +@value{GDBN} can also use @key{RET} in another way: to partition lengthy +output, in a way similar to the common utility @code{more} +(@pxref{Screen Size,,Screen size}). Since it is easy to press one +@key{RET} too many in this situation, @value{GDBN} disables command +repetition after any command that generates this sort of display. + +@kindex # +@cindex comment +Any text from a @kbd{#} to the end of the line is a comment; it does +nothing. This is useful mainly in command files (@pxref{Command +Files,,Command files}). + +@node Completion +@section Command completion + +@cindex completion +@cindex word completion +@value{GDBN} can fill in the rest of a word in a command for you, if there is +only one possibility; it can also show you what the valid possibilities +are for the next word in a command, at any time. This works for @value{GDBN} +commands, @value{GDBN} subcommands, and the names of symbols in your program. + +Press the @key{TAB} key whenever you want @value{GDBN} to fill out the rest +of a word. If there is only one possibility, @value{GDBN} will fill in the +word, and wait for you to finish the command (or press @key{RET} to +enter it). For example, if you type + +@c FIXME "@key" does not distinguish its argument sufficiently to permit +@c complete accuracy in these examples; space introduced for clarity. +@c If texinfo enhancements make it unnecessary, it would be nice to +@c replace " @key" by "@key" in the following... +@example +(@value{GDBP}) info bre @key{TAB} +@end example + +@noindent +@value{GDBN} fills in the rest of the word @samp{breakpoints}, since that is +the only @code{info} subcommand beginning with @samp{bre}: + +@example +(@value{GDBP}) info breakpoints +@end example + +@noindent +You can either press @key{RET} at this point, to run the @code{info +breakpoints} command, or backspace and enter something else, if +@samp{breakpoints} does not look like the command you expected. (If you +were sure you wanted @code{info breakpoints} in the first place, you +might as well just type @key{RET} immediately after @samp{info bre}, +to exploit command abbreviations rather than command completion). + +If there is more than one possibility for the next word when you press +@key{TAB}, @value{GDBN} will sound a bell. You can either supply more +characters and try again, or just press @key{TAB} a second time, and +@value{GDBN} will display all the possible completions for that word. For +example, you might want to set a breakpoint on a subroutine whose name +begins with @samp{make_}, but when you type @kbd{b make_@key{TAB}} @value{GDBN} +just sounds the bell. Typing @key{TAB} again will display all the +function names in your program that begin with those characters, for +example: + +@example +(@value{GDBP}) b make_ @key{TAB} +@exdent @value{GDBN} sounds bell; press @key{TAB} again, to see: +make_a_section_from_file make_environ +make_abs_section make_function_type +make_blockvector make_pointer_type +make_cleanup make_reference_type +make_command make_symbol_completion_list +(@value{GDBP}) b make_ +@end example + +@noindent +After displaying the available possibilities, @value{GDBN} copies your +partial input (@samp{b make_} in the example) so you can finish the +command. + +If you just want to see the list of alternatives in the first place, you +can press @kbd{M-?} rather than pressing @key{TAB} twice. @kbd{M-?} +means @kbd{@key{META} ?}. You can type this +@ifclear DOSHOST +either by holding down a +key designated as the @key{META} shift on your keyboard (if there is +one) while typing @kbd{?}, or +@end ifclear +as @key{ESC} followed by @kbd{?}. + +@cindex quotes in commands +@cindex completion of quoted strings +Sometimes the string you need, while logically a ``word'', may contain +parentheses or other characters that @value{GDBN} normally excludes from its +notion of a word. To permit word completion to work in this situation, +you may enclose words in @code{'} (single quote marks) in @value{GDBN} commands. + +@ifclear CONLY +The most likely situation where you might need this is in typing the +name of a C++ function. This is because C++ allows function overloading +(multiple definitions of the same function, distinguished by argument +type). For example, when you want to set a breakpoint you may need to +distinguish whether you mean the version of @code{name} that takes an +@code{int} parameter, @code{name(int)}, or the version that takes a +@code{float} parameter, @code{name(float)}. To use the word-completion +facilities in this situation, type a single quote @code{'} at the +beginning of the function name. This alerts @value{GDBN} that it may need to +consider more information than usual when you press @key{TAB} or +@kbd{M-?} to request word completion: + +@example +(@value{GDBP}) b 'bubble( @key{M-?} +bubble(double,double) bubble(int,int) +(@value{GDBP}) b 'bubble( +@end example + +In some cases, @value{GDBN} can tell that completing a name will require +quotes. When this happens, @value{GDBN} will insert the quote for you (while +completing as much as it can) if you do not type the quote in the first +place: + +@example +(@value{GDBP}) b bub @key{TAB} +@exdent @value{GDBN} alters your input line to the following, and rings a bell: +(@value{GDBP}) b 'bubble( +@end example + +@noindent +In general, @value{GDBN} can tell that a quote is needed (and inserts it) if +you have not yet started typing the argument list when you ask for +completion on an overloaded symbol. +@end ifclear + + +@node Help +@section Getting help +@cindex online documentation +@kindex help + +You can always ask @value{GDBN} itself for information on its commands, using the +command @code{help}. + +@table @code +@item help +@itemx h +@kindex h +You can use @code{help} (abbreviated @code{h}) with no arguments to +display a short list of named classes of commands: + +@smallexample +(@value{GDBP}) help +List of classes of commands: + +running -- Running the program +stack -- Examining the stack +data -- Examining data +breakpoints -- Making program stop at certain points +files -- Specifying and examining files +status -- Status inquiries +support -- Support facilities +user-defined -- User-defined commands +aliases -- Aliases of other commands +obscure -- Obscure features + +Type "help" followed by a class name for a list of +commands in that class. +Type "help" followed by command name for full +documentation. +Command name abbreviations are allowed if unambiguous. +(@value{GDBP}) +@end smallexample + +@item help @var{class} +Using one of the general help classes as an argument, you can get a +list of the individual commands in that class. For example, here is the +help display for the class @code{status}: + +@smallexample +(@value{GDBP}) help status +Status inquiries. + +List of commands: + +@c Line break in "show" line falsifies real output, but needed +@c to fit in smallbook page size. +show -- Generic command for showing things set + with "set" +info -- Generic command for printing status + +Type "help" followed by command name for full +documentation. +Command name abbreviations are allowed if unambiguous. +(@value{GDBP}) +@end smallexample + +@item help @var{command} +With a command name as @code{help} argument, @value{GDBN} will display a +short paragraph on how to use that command. +@end table + +In addition to @code{help}, you can use the @value{GDBN} commands @code{info} +and @code{show} to inquire about the state of your program, or the state +of @value{GDBN} itself. Each command supports many topics of inquiry; this +manual introduces each of them in the appropriate context. The listings +under @code{info} and under @code{show} in the Index point to +all the sub-commands. @xref{Index}. + +@c @group +@table @code +@item info +@kindex info +@kindex i +This command (abbreviated @code{i}) is for describing the state of your +program. For example, you can list the arguments given to your program +with @code{info args}, list the registers currently in use with @code{info +registers}, or list the breakpoints you have set with @code{info breakpoints}. +You can get a complete list of the @code{info} sub-commands with +@w{@code{help info}}. + +@kindex show +@item show +In contrast, @code{show} is for describing the state of @value{GDBN} itself. +You can change most of the things you can @code{show}, by using the +related command @code{set}; for example, you can control what number +system is used for displays with @code{set radix}, or simply inquire +which is currently in use with @code{show radix}. + +@kindex info set +To display all the settable parameters and their current +values, you can use @code{show} with no arguments; you may also use +@code{info set}. Both commands produce the same display. +@c FIXME: "info set" violates the rule that "info" is for state of +@c FIXME...program. Ck w/ GNU: "info set" to be called something else, +@c FIXME...or change desc of rule---eg "state of prog and debugging session"? +@end table +@c @end group + +Here are three miscellaneous @code{show} subcommands, all of which are +exceptional in lacking corresponding @code{set} commands: + +@table @code +@kindex show version +@cindex version number +@item show version +Show what version of @value{GDBN} is running. You should include this +information in @value{GDBN} bug-reports. If multiple versions of @value{GDBN} are in +use at your site, you may occasionally want to determine which version +of @value{GDBN} you are running; as @value{GDBN} evolves, new commands are introduced, +and old ones may wither away. The version number is also announced +when you start @value{GDBN}. + +@kindex show copying +@item show copying +Display information about permission for copying @value{GDBN}. + +@kindex show warranty +@item show warranty +Display the GNU ``NO WARRANTY'' statement. +@end table + +@node Running +@chapter Running Programs Under @value{GDBN} + +When you run a program under @value{GDBN}, you must first generate +debugging information when you compile it. +@ifclear BARETARGET +You may start it with its arguments, if any, in an environment of your +choice. You may redirect your program's input and output, debug an +already running process, or kill a child process. +@end ifclear + +@menu +* Compilation:: Compiling for debugging +* Starting:: Starting your program +@ifclear BARETARGET +* Arguments:: Your program's arguments +* Environment:: Your program's environment +* Working Directory:: Your program's working directory +* Input/Output:: Your program's input and output +* Attach:: Debugging an already-running process +* Kill Process:: Killing the child process +* Process Information:: Additional process information +@end ifclear +@end menu + +@node Compilation +@section Compiling for debugging + +In order to debug a program effectively, you need to generate +debugging information when you compile it. This debugging information +is stored in the object file; it describes the data type of each +variable or function and the correspondence between source line numbers +and addresses in the executable code. + +To request debugging information, specify the @samp{-g} option when you run +the compiler. + +Many C compilers are unable to handle the @samp{-g} and @samp{-O} +options together. Using those compilers, you cannot generate optimized +executables containing debugging information. + +@value{NGCC}, the GNU C compiler, supports @samp{-g} with or without +@samp{-O}, making it possible to debug optimized code. We recommend +that you @emph{always} use @samp{-g} whenever you compile a program. +You may think your program is correct, but there is no sense in pushing +your luck. + +@cindex optimized code, debugging +@cindex debugging optimized code +When you debug a program compiled with @samp{-g -O}, remember that the +optimizer is rearranging your code; the debugger will show you what is +really there. Do not be too surprised when the execution path does not +exactly match your source file! An extreme example: if you define a +variable, but never use it, @value{GDBN} will never see that +variable---because the compiler optimizes it out of existence. + +Some things do not work as well with @samp{-g -O} as with just +@samp{-g}, particularly on machines with instruction scheduling. If in +doubt, recompile with @samp{-g} alone, and if this fixes the problem, +please report it as a bug (including a test case!). + +Older versions of the GNU C compiler permitted a variant option +@w{@samp{-gg}} for debugging information. @value{GDBN} no longer supports this +format; if your GNU C compiler has this option, do not use it. + +@need 2000 +@node Starting +@section Starting your program +@cindex starting +@cindex running + +@table @code +@item run +@itemx r +@kindex run +Use the @code{run} command to start your program under @value{GDBN}. You must +first specify the program name +@ifset VXWORKS +(except on VxWorks) +@end ifset +with an argument to @value{GDBN} (@pxref{Invocation, ,Getting In and +Out of @value{GDBN}}), or by using the @code{file} or @code{exec-file} +command (@pxref{Files, ,Commands to specify files}). + +@end table + +@ifclear BARETARGET +If you are running your program in an execution environment that +supports processes, @code{run} creates an inferior process and makes +that process run your program. (In environments without processes, +@code{run} jumps to the start of your program.) + +The execution of a program is affected by certain information it +receives from its superior. @value{GDBN} provides ways to specify this +information, which you must do @emph{before} starting your program. (You +can change it after starting your program, but such changes will only affect +your program the next time you start it.) This information may be +divided into four categories: + +@table @asis +@item The @emph{arguments.} +Specify the arguments to give your program as the arguments of the +@code{run} command. If a shell is available on your target, the shell +is used to pass the arguments, so that you may use normal conventions +(such as wildcard expansion or variable substitution) in describing +the arguments. In Unix systems, you can control which shell is used +with the @code{SHELL} environment variable. @xref{Arguments, ,Your +program's arguments}. + +@item The @emph{environment.} +Your program normally inherits its environment from @value{GDBN}, but you can +use the @value{GDBN} commands @code{set environment} and @code{unset +environment} to change parts of the environment that will be given to +your program. @xref{Environment, ,Your program's environment}. + +@item The @emph{working directory.} +Your program inherits its working directory from @value{GDBN}. You can set +the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}. +@xref{Working Directory, ,Your program's working directory}. + +@item The @emph{standard input and output.} +Your program normally uses the same device for standard input and +standard output as @value{GDBN} is using. You can redirect input and output +in the @code{run} command line, or you can use the @code{tty} command to +set a different device for your program. +@xref{Input/Output, ,Your program's input and output}. + +@cindex pipes +@emph{Warning:} While input and output redirection work, you cannot use +pipes to pass the output of the program you are debugging to another +program; if you attempt this, @value{GDBN} is likely to wind up debugging the +wrong program. +@end table +@end ifclear + +When you issue the @code{run} command, your program begins to execute +immediately. @xref{Stopping, ,Stopping and continuing}, for discussion +of how to arrange for your program to stop. Once your program has +stopped, you may call functions in your program, using the @code{print} +or @code{call} commands. @xref{Data, ,Examining Data}. + +If the modification time of your symbol file has changed since the +last time @value{GDBN} read its symbols, @value{GDBN} will discard its symbol table and +re-read it. When it does this, @value{GDBN} tries to retain your current +breakpoints. + +@ifclear BARETARGET +@node Arguments +@section Your program's arguments + +@cindex arguments (to your program) +The arguments to your program can be specified by the arguments of the +@code{run} command. They are passed to a shell, which expands wildcard +characters and performs redirection of I/O, and thence to your program. +Your @code{SHELL} environment variable (if it exists) specifies what +shell @value{GDBN} if you do not define @code{SHELL}, @value{GDBN} uses +@code{/bin/sh}. + +@code{run} with no arguments uses the same arguments used by the previous +@code{run}, or those set by the @code{set args} command. + +@kindex set args +@table @code +@item set args +Specify the arguments to be used the next time your program is run. If +@code{set args} has no arguments, @code{run} will execute your program +with no arguments. Once you have run your program with arguments, +using @code{set args} before the next @code{run} is the only way to run +it again without arguments. + +@item show args +@kindex show args +Show the arguments to give your program when it is started. +@end table + +@node Environment +@section Your program's environment + +@cindex environment (of your program) +The @dfn{environment} consists of a set of environment variables and +their values. Environment variables conventionally record such things as +your user name, your home directory, your terminal type, and your search +path for programs to run. Usually you set up environment variables with +the shell and they are inherited by all the other programs you run. When +debugging, it can be useful to try running your program with a modified +environment without having to start @value{GDBN} over again. + +@table @code +@item path @var{directory} +@kindex path +Add @var{directory} to the front of the @code{PATH} environment variable +(the search path for executables), for both @value{GDBN} and your program. +You may specify several directory names, separated by @samp{:} or +whitespace. If @var{directory} is already in the path, it is moved to +the front, so it will be searched sooner. + +You can use the string @samp{$cwd} to refer to whatever is the current +working directory at the time @value{GDBN} searches the path. If you +use @samp{.} instead, it refers to the directory where you executed the +@code{path} command. @value{GDBN} replaces @samp{.} in the +@var{directory} argument (with the current path) before adding +@var{directory} to the search path. +@c 'path' is explicitly nonrepeatable, but RMS points out it is silly to +@c document that, since repeating it would be a no-op. + +@item show paths +@kindex show paths +Display the list of search paths for executables (the @code{PATH} +environment variable). + +@item show environment @r{[}@var{varname}@r{]} +@kindex show environment +Print the value of environment variable @var{varname} to be given to +your program when it starts. If you do not supply @var{varname}, +print the names and values of all environment variables to be given to +your program. You can abbreviate @code{environment} as @code{env}. + +@item set environment @var{varname} @r{[}=@r{]} @var{value} +@kindex set environment +Set environment variable @var{varname} to @var{value}. The value +changes for your program only, not for @value{GDBN} itself. @var{value} may +be any string; the values of environment variables are just strings, and +any interpretation is supplied by your program itself. The @var{value} +parameter is optional; if it is eliminated, the variable is set to a +null value. +@c "any string" here does not include leading, trailing +@c blanks. Gnu asks: does anyone care? + +For example, this command: + +@example +set env USER = foo +@end example + +@noindent +tells a Unix program, when subsequently run, that its user is named +@samp{foo}. (The spaces around @samp{=} are used for clarity here; they +are not actually required.) + +@item unset environment @var{varname} +@kindex unset environment +Remove variable @var{varname} from the environment to be passed to your +program. This is different from @samp{set env @var{varname} =}; +@code{unset environment} removes the variable from the environment, +rather than assigning it an empty value. +@end table + +@emph{Warning:} @value{GDBN} runs your program using the shell indicated +by your @code{SHELL} environment variable if it exists (or +@code{/bin/sh} if not). If your @code{SHELL} variable names a shell +that runs an initialization file---such as @file{.cshrc} for C-shell, or +@file{.bashrc} for BASH---any variables you set in that file will affect +your program. You may wish to move setting of environment variables to +files that are only run when you sign on, such as @file{.login} or +@file{.profile}. + +@node Working Directory +@section Your program's working directory + +@cindex working directory (of your program) +Each time you start your program with @code{run}, it inherits its +working directory from the current working directory of @value{GDBN}. +The @value{GDBN} working directory is initially whatever it inherited +from its parent process (typically the shell), but you can specify a new +working directory in @value{GDBN} with the @code{cd} command. + +The @value{GDBN} working directory also serves as a default for the commands +that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to +specify files}. + +@table @code +@item cd @var{directory} +@kindex cd +Set the @value{GDBN} working directory to @var{directory}. + +@item pwd +@kindex pwd +Print the @value{GDBN} working directory. +@end table + +@node Input/Output +@section Your program's input and output + +@cindex redirection +@cindex i/o +@cindex terminal +By default, the program you run under @value{GDBN} does input and output to +the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal to +its own terminal modes to interact with you, but it records the terminal +modes your program was using and switches back to them when you continue +running your program. + +@table @code +@item info terminal +@kindex info terminal +Displays information recorded by @value{GDBN} about the terminal modes your +program is using. +@end table + +You can redirect your program's input and/or output using shell +redirection with the @code{run} command. For example, + +@example +run > outfile +@end example + +@noindent +starts your program, diverting its output to the file @file{outfile}. + +@kindex tty +@cindex controlling terminal +Another way to specify where your program should do input and output is +with the @code{tty} command. This command accepts a file name as +argument, and causes this file to be the default for future @code{run} +commands. It also resets the controlling terminal for the child +process, for future @code{run} commands. For example, + +@example +tty /dev/ttyb +@end example + +@noindent +directs that processes started with subsequent @code{run} commands +default to do input and output on the terminal @file{/dev/ttyb} and have +that as their controlling terminal. + +An explicit redirection in @code{run} overrides the @code{tty} command's +effect on the input/output device, but not its effect on the controlling +terminal. + +When you use the @code{tty} command or redirect input in the @code{run} +command, only the input @emph{for your program} is affected. The input +for @value{GDBN} still comes from your terminal. + +@node Attach +@section Debugging an already-running process +@kindex attach +@cindex attach + +@table @code +@item attach @var{process-id} +This command attaches to a running process---one that was started +outside @value{GDBN}. (@code{info files} will show your active +targets.) The command takes as argument a process ID. The usual way to +find out the process-id of a Unix process is with the @code{ps} utility, +or with the @samp{jobs -l} shell command. + +@code{attach} will not repeat if you press @key{RET} a second time after +executing the command. +@end table + +To use @code{attach}, your program must be running in an environment +which supports processes; for example, @code{attach} does not work for +programs on bare-board targets that lack an operating system. You must +also have permission to send the process a signal. + +When using @code{attach}, you should first use the @code{file} command +to specify the program running in the process and load its symbol table. +@xref{Files, ,Commands to Specify Files}. + +The first thing @value{GDBN} does after arranging to debug the specified +process is to stop it. You can examine and modify an attached process +with all the @value{GDBN} commands that are ordinarily available when you start +processes with @code{run}. You can insert breakpoints; you can step and +continue; you can modify storage. If you would rather the process +continue running, you may use the @code{continue} command after +attaching @value{GDBN} to the process. + +@table @code +@item detach +@kindex detach +When you have finished debugging the attached process, you can use the +@code{detach} command to release it from @value{GDBN} control. Detaching +the process continues its execution. After the @code{detach} command, +that process and @value{GDBN} become completely independent once more, and you +are ready to @code{attach} another process or start one with @code{run}. +@code{detach} will not repeat if you press @key{RET} again after +executing the command. +@end table + +If you exit @value{GDBN} or use the @code{run} command while you have an attached +process, you kill that process. By default, you will be asked for +confirmation if you try to do either of these things; you can control +whether or not you need to confirm by using the @code{set confirm} command +(@pxref{Messages/Warnings, ,Optional warnings and messages}). + +@node Kill Process +@c @group +@section Killing the child process + +@table @code +@item kill +@kindex kill +Kill the child process in which your program is running under @value{GDBN}. +@end table + +This command is useful if you wish to debug a core dump instead of a +running process. @value{GDBN} ignores any core dump file while your program +is running. +@c @end group + +On some operating systems, a program cannot be executed outside @value{GDBN} +while you have breakpoints set on it inside @value{GDBN}. You can use the +@code{kill} command in this situation to permit running your program +outside the debugger. + +The @code{kill} command is also useful if you wish to recompile and +relink your program, since on many systems it is impossible to modify an +executable file while it is running in a process. In this case, when you +next type @code{run}, @value{GDBN} will notice that the file has changed, and +will re-read the symbol table (while trying to preserve your current +breakpoint settings). + +@node Process Information +@section Additional process information + +@kindex /proc +@cindex process image +Some operating systems provide a facility called @samp{/proc} that can +be used to examine the image of a running process using file-system +subroutines. If @value{GDBN} is configured for an operating system with this +facility, the command @code{info proc} is available to report on several +kinds of information about the process running your program. + +@table @code +@item info proc +@kindex info proc +Summarize available information about the process. + +@item info proc mappings +@kindex info proc mappings +Report on the address ranges accessible in the program, with information +on whether your program may read, write, or execute each range. + +@item info proc times +@kindex info proc times +Starting time, user CPU time, and system CPU time for your program and +its children. + +@item info proc id +@kindex info proc id +Report on the process IDs related to your program: its own process ID, +the ID of its parent, the process group ID, and the session ID. + +@item info proc status +@kindex info proc status +General information on the state of the process. If the process is +stopped, this report includes the reason for stopping, and any signal +received. + +@item info proc all +Show all the above information about the process. +@end table +@end ifclear + +@node Stopping +@chapter Stopping and Continuing + +The principal purposes of using a debugger are so that you can stop your +program before it terminates; or so that, if your program runs into +trouble, you can investigate and find out why. + +Inside @value{GDBN}, your program may stop for any of several reasons, such +as +@ifclear BARETARGET +a signal, +@end ifclear +a breakpoint, or reaching a new line after a @value{GDBN} +command such as @code{step}. You may then examine and change +variables, set new breakpoints or remove old ones, and then continue +execution. Usually, the messages shown by @value{GDBN} provide ample +explanation of the status of your program---but you can also explicitly +request this information at any time. + +@table @code +@item info program +@kindex info program +Display information about the status of your program: whether it is +running or not, +@ifclear BARETARGET +what process it is, +@end ifclear +and why it stopped. +@end table + +@menu +@ifclear CONLY +* Breakpoints:: Breakpoints, watchpoints, and exceptions +@end ifclear +@ifset CONLY +* Breakpoints:: Breakpoints and watchpoints +@end ifset +@c Remnant makeinfo bug requires blank line after *successful* end-if in menu: + +* Continuing and Stepping:: Resuming execution +@ifset POSIX +* Signals:: Signals +@end ifset +@end menu + +@c makeinfo node-defaulting requires adjacency of @node and sectioning cmds +@c ...hence distribute @node Breakpoints over two possible @if expansions. +@c +@ifclear CONLY +@node Breakpoints +@section Breakpoints, watchpoints, and exceptions +@end ifclear +@ifset CONLY +@node Breakpoints +@section Breakpoints and watchpoints +@end ifset + +@cindex breakpoints +A @dfn{breakpoint} makes your program stop whenever a certain point in +the program is reached. For each breakpoint, you can add various +conditions to control in finer detail whether your program will stop. +You can set breakpoints with the @code{break} command and its variants +(@pxref{Set Breaks, ,Setting breakpoints}), to specify the place where +your program should stop by line number, function name or exact address +in the program. +@ifclear CONLY +In languages with exception handling (such as GNU C++), you can also set +breakpoints where an exception is raised (@pxref{Exception Handling, +,Breakpoints and exceptions}). +@end ifclear + +@cindex watchpoints +@cindex memory tracing +@cindex breakpoint on memory address +@cindex breakpoint on variable modification +A @dfn{watchpoint} is a special breakpoint that stops your program +when the value of an expression changes. You must use a different +command to set watchpoints (@pxref{Set Watchpoints, ,Setting +watchpoints}), but aside from that, you can manage a watchpoint like +any other breakpoint: you enable, disable, and delete both breakpoints +and watchpoints using the same commands. + +You can arrange to have values from your program displayed automatically +whenever @value{GDBN} stops at a breakpoint. @xref{Auto Display, +,Automatic display}. + +@cindex breakpoint numbers +@cindex numbers for breakpoints +@value{GDBN} assigns a number to each breakpoint or watchpoint when you +create it; these numbers are successive integers starting with one. In +many of the commands for controlling various features of breakpoints you +use the breakpoint number to say which breakpoint you want to change. +Each breakpoint may be @dfn{enabled} or @dfn{disabled}; if disabled, it has +no effect on your program until you enable it again. + +@menu +* Set Breaks:: Setting breakpoints +* Set Watchpoints:: Setting watchpoints +@ifclear CONLY +* Exception Handling:: Breakpoints and exceptions +@end ifclear + +* Delete Breaks:: Deleting breakpoints +* Disabling:: Disabling breakpoints +* Conditions:: Break conditions +* Break Commands:: Breakpoint command lists +@ifclear CONLY +* Breakpoint Menus:: Breakpoint menus +@end ifclear +@ifclear BARETARGET +* Error in Breakpoints:: ``Cannot insert breakpoints'' +@end ifclear +@end menu + +@node Set Breaks +@subsection Setting breakpoints + +@c FIXME LMB what does GDB do if no code on line of breakpt? +@c consider in particular declaration with/without initialization. +@c +@c FIXME 2 is there stuff on this already? break at fun start, already init? + +@kindex break +@kindex b +@kindex $bpnum +@cindex latest breakpoint +Breakpoints are set with the @code{break} command (abbreviated +@code{b}). The debugger convenience variable @samp{$bpnum} records the +number of the beakpoint you've set most recently; see @ref{Convenience +Vars,, Convenience variables}, for a discussion of what you can do with +convenience variables. + +You have several ways to say where the breakpoint should go. + +@table @code +@item break @var{function} +Set a breakpoint at entry to function @var{function}. +@ifclear CONLY +When using source languages that permit overloading of symbols, such as +C++, @var{function} may refer to more than one possible place to break. +@xref{Breakpoint Menus,,Breakpoint menus}, for a discussion of that situation. +@end ifclear + +@item break +@var{offset} +@itemx break -@var{offset} +Set a breakpoint some number of lines forward or back from the position +at which execution stopped in the currently selected frame. + +@item break @var{linenum} +Set a breakpoint at line @var{linenum} in the current source file. +That file is the last file whose source text was printed. This +breakpoint will stop your program just before it executes any of the +code on that line. + +@item break @var{filename}:@var{linenum} +Set a breakpoint at line @var{linenum} in source file @var{filename}. + +@item break @var{filename}:@var{function} +Set a breakpoint at entry to function @var{function} found in file +@var{filename}. Specifying a file name as well as a function name is +superfluous except when multiple files contain similarly named +functions. + +@item break *@var{address} +Set a breakpoint at address @var{address}. You can use this to set +breakpoints in parts of your program which do not have debugging +information or source files. + +@item break +When called without any arguments, @code{break} sets a breakpoint at +the next instruction to be executed in the selected stack frame +(@pxref{Stack, ,Examining the Stack}). In any selected frame but the +innermost, this will cause your program to stop as soon as control +returns to that frame. This is similar to the effect of a +@code{finish} command in the frame inside the selected frame---except +that @code{finish} does not leave an active breakpoint. If you use +@code{break} without an argument in the innermost frame, @value{GDBN} will stop +the next time it reaches the current location; this may be useful +inside loops. + +@value{GDBN} normally ignores breakpoints when it resumes execution, until at +least one instruction has been executed. If it did not do this, you +would be unable to proceed past a breakpoint without first disabling the +breakpoint. This rule applies whether or not the breakpoint already +existed when your program stopped. + +@item break @dots{} if @var{cond} +Set a breakpoint with condition @var{cond}; evaluate the expression +@var{cond} each time the breakpoint is reached, and stop only if the +value is nonzero---that is, if @var{cond} evaluates as true. +@samp{@dots{}} stands for one of the possible arguments described +above (or no argument) specifying where to break. @xref{Conditions, +,Break conditions}, for more information on breakpoint conditions. + +@item tbreak @var{args} +@kindex tbreak +Set a breakpoint enabled only for one stop. @var{args} are the +same as for the @code{break} command, and the breakpoint is set in the same +way, but the breakpoint is automatically disabled after the first time your +program stops there. @xref{Disabling, ,Disabling breakpoints}. + +@item rbreak @var{regex} +@kindex rbreak +@cindex regular expression +@c FIXME what kind of regexp? +Set breakpoints on all functions matching the regular expression +@var{regex}. This command +sets an unconditional breakpoint on all matches, printing a list of all +breakpoints it set. Once these breakpoints are set, they are treated +just like the breakpoints set with the @code{break} command. They can +be deleted, disabled, made conditional, etc., in the standard ways. + +@ifclear CONLY +When debugging C++ programs, @code{rbreak} is useful for setting +breakpoints on overloaded functions that are not members of any special +classes. +@end ifclear + +@kindex info breakpoints +@cindex @code{$_} and @code{info breakpoints} +@item info breakpoints @r{[}@var{n}@r{]} +@itemx info break @r{[}@var{n}@r{]} +@itemx info watchpoints @r{[}@var{n}@r{]} +Print a table of all breakpoints and watchpoints set and not +deleted, with the following columns for each breakpoint: + +@table @emph +@item Breakpoint Numbers +@item Type +Breakpoint or watchpoint. +@item Disposition +Whether the breakpoint is marked to be disabled or deleted when hit. +@item Enabled or Disabled +Enabled breakpoints are marked with @samp{y}. @samp{n} marks breakpoints +that are not enabled. +@item Address +Where the breakpoint is in your program, as a memory address +@item What +Where the breakpoint is in the source for your program, as a file and +line number. +@end table + +@noindent +If a breakpoint is conditional, @code{info break} shows the condition on +the line following the affected breakpoint; breakpoint commands, if any, +are listed after that. + +@noindent +@code{info break} with a breakpoint +number @var{n} as argument lists only that breakpoint. The +convenience variable @code{$_} and the default examining-address for +the @code{x} command are set to the address of the last breakpoint +listed (@pxref{Memory, ,Examining memory}). +@end table + +@value{GDBN} allows you to set any number of breakpoints at the same place in +your program. There is nothing silly or meaningless about this. When +the breakpoints are conditional, this is even useful +(@pxref{Conditions, ,Break conditions}). + +@cindex negative breakpoint numbers +@cindex internal @value{GDBN} breakpoints +@value{GDBN} itself sometimes sets breakpoints in your program for special +purposes, such as proper handling of @code{longjmp} (in C programs). +These internal breakpoints are assigned negative numbers, starting with +@code{-1}; @samp{info breakpoints} does not display them. + +You can see these breakpoints with the @value{GDBN} maintenance command +@samp{maint info breakpoints}. + +@table @code +@kindex maint info breakpoints +@item maint info breakpoints +Using the same format as @samp{info breakpoints}, display both the +breakpoints you've set explicitly, and those @value{GDBN} is using for +internal purposes. Internal breakpoints are shown with negative +breakpoint numbers. The type column identifies what kind of breakpoint +is shown: + +@table @code +@item breakpoint +Normal, explicitly set breakpoint. + +@item watchpoint +Normal, explicitly set watchpoint. + +@item longjmp +Internal breakpoint, used to handle correctly stepping through +@code{longjmp} calls. + +@item longjmp resume +Internal breakpoint at the target of a @code{longjmp}. + +@item until +Temporary internal breakpoint used by the @value{GDBN} @code{until} command. + +@item finish +Temporary internal breakpoint used by the @value{GDBN} @code{finish} command. +@end table + +@end table + + +@node Set Watchpoints +@subsection Setting watchpoints +@cindex setting watchpoints + +You can use a watchpoint to stop execution whenever the value of an +expression changes, without having to predict a particular place +where this may happen. + +Watchpoints currently execute two orders of magnitude more slowly than +other breakpoints, but this can be well worth it to catch errors where +you have no clue what part of your program is the culprit. Some +processors provide special hardware to support watchpoint evaluation; future +releases of @value{GDBN} will use such hardware if it is available. + +@table @code +@kindex watch +@item watch @var{expr} +Set a watchpoint for an expression. + +@kindex info watchpoints +@item info watchpoints +This command prints a list of watchpoints and breakpoints; it is the +same as @code{info break}. +@end table + +@ifclear CONLY +@node Exception Handling +@subsection Breakpoints and exceptions +@cindex exception handlers + +Some languages, such as GNU C++, implement exception handling. You can +use @value{GDBN} to examine what caused your program to raise an exception, +and to list the exceptions your program is prepared to handle at a +given point in time. + +@table @code +@item catch @var{exceptions} +@kindex catch +You can set breakpoints at active exception handlers by using the +@code{catch} command. @var{exceptions} is a list of names of exceptions +to catch. +@end table + +You can use @code{info catch} to list active exception handlers. +@xref{Frame Info, ,Information about a frame}. + +There are currently some limitations to exception handling in @value{GDBN}. +These will be corrected in a future release. + +@itemize @bullet +@item +If you call a function interactively, @value{GDBN} normally returns +control to you when the function has finished executing. If the call +raises an exception, however, the call may bypass the mechanism that +returns control to you and cause your program to simply continue +running until it hits a breakpoint, catches a signal that @value{GDBN} is +listening for, or exits. +@item +You cannot raise an exception interactively. +@item +You cannot interactively install an exception handler. +@end itemize + +@cindex raise exceptions +Sometimes @code{catch} is not the best way to debug exception handling: +if you need to know exactly where an exception is raised, it is better to +stop @emph{before} the exception handler is called, since that way you +can see the stack before any unwinding takes place. If you set a +breakpoint in an exception handler instead, it may not be easy to find +out where the exception was raised. + +To stop just before an exception handler is called, you need some +knowledge of the implementation. In the case of GNU C++, exceptions are +raised by calling a library function named @code{__raise_exception} +which has the following ANSI C interface: + +@example + /* @var{addr} is where the exception identifier is stored. + ID is the exception identifier. */ + void __raise_exception (void **@var{addr}, void *@var{id}); +@end example + +@noindent +To make the debugger catch all exceptions before any stack +unwinding takes place, set a breakpoint on @code{__raise_exception} +(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions}). + +With a conditional breakpoint (@pxref{Conditions, ,Break conditions}) +that depends on the value of @var{id}, you can stop your program when +a specific exception is raised. You can use multiple conditional +breakpoints to stop your program when any of a number of exceptions are +raised. +@end ifclear + +@node Delete Breaks +@subsection Deleting breakpoints + +@cindex clearing breakpoints, watchpoints +@cindex deleting breakpoints, watchpoints +It is often necessary to eliminate a breakpoint or watchpoint once it +has done its job and you no longer want your program to stop there. This +is called @dfn{deleting} the breakpoint. A breakpoint that has been +deleted no longer exists; it is forgotten. + +With the @code{clear} command you can delete breakpoints according to +where they are in your program. With the @code{delete} command you can +delete individual breakpoints or watchpoints by specifying their +breakpoint numbers. + +It is not necessary to delete a breakpoint to proceed past it. @value{GDBN} +automatically ignores breakpoints on the first instruction to be executed +when you continue execution without changing the execution address. + +@table @code +@item clear +@kindex clear +Delete any breakpoints at the next instruction to be executed in the +selected stack frame (@pxref{Selection, ,Selecting a frame}). When +the innermost frame is selected, this is a good way to delete a +breakpoint where your program just stopped. + +@item clear @var{function} +@itemx clear @var{filename}:@var{function} +Delete any breakpoints set at entry to the function @var{function}. + +@item clear @var{linenum} +@itemx clear @var{filename}:@var{linenum} +Delete any breakpoints set at or within the code of the specified line. + +@item delete @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@cindex delete breakpoints +@kindex delete +@kindex d +Delete the breakpoints or watchpoints of the numbers specified as +arguments. If no argument is specified, delete all breakpoints (@value{GDBN} +asks confirmation, unless you have @code{set confirm off}). You +can abbreviate this command as @code{d}. +@end table + +@node Disabling +@subsection Disabling breakpoints + +@cindex disabled breakpoints +@cindex enabled breakpoints +Rather than deleting a breakpoint or watchpoint, you might prefer to +@dfn{disable} it. This makes the breakpoint inoperative as if it had +been deleted, but remembers the information on the breakpoint so that +you can @dfn{enable} it again later. + +You disable and enable breakpoints and watchpoints with the +@code{enable} and @code{disable} commands, optionally specifying one or +more breakpoint numbers as arguments. Use @code{info break} or +@code{info watch} to print a list of breakpoints or watchpoints if you +do not know which numbers to use. + +A breakpoint or watchpoint can have any of four different states of +enablement: + +@itemize @bullet +@item +Enabled. The breakpoint will stop your program. A breakpoint set +with the @code{break} command starts out in this state. +@item +Disabled. The breakpoint has no effect on your program. +@item +Enabled once. The breakpoint will stop your program, but +when it does so it will become disabled. A breakpoint set +with the @code{tbreak} command starts out in this state. +@item +Enabled for deletion. The breakpoint will stop your program, but +immediately after it does so it will be deleted permanently. +@end itemize + +You can use the following commands to enable or disable breakpoints and +watchpoints: + +@table @code +@item disable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@kindex disable breakpoints +@kindex disable +@kindex dis +Disable the specified breakpoints---or all breakpoints, if none are +listed. A disabled breakpoint has no effect but is not forgotten. All +options such as ignore-counts, conditions and commands are remembered in +case the breakpoint is enabled again later. You may abbreviate +@code{disable} as @code{dis}. + +@item enable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@kindex enable breakpoints +@kindex enable +Enable the specified breakpoints (or all defined breakpoints). They +become effective once again in stopping your program. + +@item enable @r{[}breakpoints@r{]} once @var{bnums}@dots{} +Enable the specified breakpoints temporarily. Each will be disabled +again the next time it stops your program. + +@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{} +Enable the specified breakpoints to work once and then die. Each of +the breakpoints will be deleted the next time it stops your program. +@end table + +Save for a breakpoint set with @code{tbreak} (@pxref{Set Breaks, +,Setting breakpoints}), breakpoints that you set are initially enabled; +subsequently, they become disabled or enabled only when you use one of +the commands above. (The command @code{until} can set and delete a +breakpoint of its own, but it will not change the state of your other +breakpoints; see @ref{Continuing and Stepping, ,Continuing and +stepping}.) + +@node Conditions +@subsection Break conditions +@cindex conditional breakpoints +@cindex breakpoint conditions + +@c FIXME what is scope of break condition expr? Context where wanted? +@c in particular for a watchpoint? +The simplest sort of breakpoint breaks every time your program reaches a +specified place. You can also specify a @dfn{condition} for a +breakpoint. A condition is just a Boolean expression in your +programming language (@pxref{Expressions, ,Expressions}). A breakpoint with +a condition evaluates the expression each time your program reaches it, +and your program stops only if the condition is @emph{true}. + +This is the converse of using assertions for program validation; in that +situation, you want to stop when the assertion is violated---that is, +when the condition is false. In C, if you want to test an assertion expressed +by the condition @var{assert}, you should set the condition +@samp{! @var{assert}} on the appropriate breakpoint. + +Conditions are also accepted for watchpoints; you may not need them, +since a watchpoint is inspecting the value of an expression anyhow---but +it might be simpler, say, to just set a watchpoint on a variable name, +and specify a condition that tests whether the new value is an interesting +one. + +Break conditions can have side effects, and may even call functions in +your program. This can be useful, for example, to activate functions +that log program progress, or to use your own print functions to +format special data structures. The effects are completely predictable +unless there is another enabled breakpoint at the same address. (In +that case, @value{GDBN} might see the other breakpoint first and stop your +program without checking the condition of this one.) Note that +breakpoint commands are usually more convenient and flexible for the +purpose of performing side effects when a breakpoint is reached +(@pxref{Break Commands, ,Breakpoint command lists}). + +Break conditions can be specified when a breakpoint is set, by using +@samp{if} in the arguments to the @code{break} command. @xref{Set +Breaks, ,Setting breakpoints}. They can also be changed at any time +with the @code{condition} command. The @code{watch} command does not +recognize the @code{if} keyword; @code{condition} is the only way to +impose a further condition on a watchpoint. + +@table @code +@item condition @var{bnum} @var{expression} +@kindex condition +Specify @var{expression} as the break condition for breakpoint or +watchpoint number @var{bnum}. From now on, this breakpoint will stop +your program only if the value of @var{expression} is true (nonzero, in +C). When you use @code{condition}, @value{GDBN} checks @var{expression} +immediately for syntactic correctness, and to determine whether symbols +in it have referents in the context of your breakpoint. +@c FIXME so what does GDB do if there is no referent? Moreover, what +@c about watchpoints? +@value{GDBN} does +not actually evaluate @var{expression} at the time the @code{condition} +command is given, however. @xref{Expressions, ,Expressions}. + +@item condition @var{bnum} +Remove the condition from breakpoint number @var{bnum}. It becomes +an ordinary unconditional breakpoint. +@end table + +@cindex ignore count (of breakpoint) +A special case of a breakpoint condition is to stop only when the +breakpoint has been reached a certain number of times. This is so +useful that there is a special way to do it, using the @dfn{ignore +count} of the breakpoint. Every breakpoint has an ignore count, which +is an integer. Most of the time, the ignore count is zero, and +therefore has no effect. But if your program reaches a breakpoint whose +ignore count is positive, then instead of stopping, it just decrements +the ignore count by one and continues. As a result, if the ignore count +value is @var{n}, the breakpoint will not stop the next @var{n} times it +is reached. + +@table @code +@item ignore @var{bnum} @var{count} +@kindex ignore +Set the ignore count of breakpoint number @var{bnum} to @var{count}. +The next @var{count} times the breakpoint is reached, your program's +execution will not stop; other than to decrement the ignore count, @value{GDBN} +takes no action. + +To make the breakpoint stop the next time it is reached, specify +a count of zero. + +When you use @code{continue} to resume execution of your program from a +breakpoint, you can specify an ignore count directly as an argument to +@code{continue}, rather than using @code{ignore}. @xref{Continuing and +Stepping,,Continuing and stepping}. + +If a breakpoint has a positive ignore count and a condition, the condition +is not checked. Once the ignore count reaches zero, the condition will +be checked. + +You could achieve the effect of the ignore count with a condition such +as @w{@samp{$foo-- <= 0}} using a debugger convenience variable that +is decremented each time. @xref{Convenience Vars, ,Convenience +variables}. +@end table + +@node Break Commands +@subsection Breakpoint command lists + +@cindex breakpoint commands +You can give any breakpoint (or watchpoint) a series of commands to +execute when your program stops due to that breakpoint. For example, you +might want to print the values of certain expressions, or enable other +breakpoints. + +@table @code +@item commands @r{[}@var{bnum}@r{]} +@itemx @dots{} @var{command-list} @dots{} +@itemx end +@kindex commands +@kindex end +Specify a list of commands for breakpoint number @var{bnum}. The commands +themselves appear on the following lines. Type a line containing just +@code{end} to terminate the commands. + +To remove all commands from a breakpoint, type @code{commands} and +follow it immediately with @code{end}; that is, give no commands. + +With no @var{bnum} argument, @code{commands} refers to the last +breakpoint or watchpoint set (not to the breakpoint most recently +encountered). +@end table + +Pressing @key{RET} as a means of repeating the last @value{GDBN} command is +disabled within a @var{command-list}. + +You can use breakpoint commands to start your program up again. Simply +use the @code{continue} command, or @code{step}, or any other command +that resumes execution. + +Any other commands in the command list, after a command that resumes +execution, are ignored. This is because any time you resume execution +(even with a simple @code{next} or @code{step}), you may encounter +another breakpoint---which could have its own command list, leading to +ambiguities about which list to execute. + +@kindex silent +If the first command you specify in a command list is @code{silent}, the +usual message about stopping at a breakpoint is not printed. This may +be desirable for breakpoints that are to print a specific message and +then continue. If none of the remaining commands print anything, you +will see no sign that the breakpoint was reached. @code{silent} is +meaningful only at the beginning of a breakpoint command list. + +The commands @code{echo}, @code{output}, and @code{printf} allow you to +print precisely controlled output, and are often useful in silent +breakpoints. @xref{Output, ,Commands for controlled output}. + +For example, here is how you could use breakpoint commands to print the +value of @code{x} at entry to @code{foo} whenever @code{x} is positive. + +@example +break foo if x>0 +commands +silent +printf "x is %d\n",x +cont +end +@end example + +One application for breakpoint commands is to compensate for one bug so +you can test for another. Put a breakpoint just after the erroneous line +of code, give it a condition to detect the case in which something +erroneous has been done, and give it commands to assign correct values +to any variables that need them. End with the @code{continue} command +so that your program does not stop, and start with the @code{silent} +command so that no output is produced. Here is an example: + +@example +break 403 +commands +silent +set x = y + 4 +cont +end +@end example + +@ifclear CONLY +@node Breakpoint Menus +@subsection Breakpoint menus +@cindex overloading +@cindex symbol overloading + +Some programming languages (notably C++) permit a single function name +to be defined several times, for application in different contexts. +This is called @dfn{overloading}. When a function name is overloaded, +@samp{break @var{function}} is not enough to tell @value{GDBN} where you want +a breakpoint. If you realize this will be a problem, you can use +something like @samp{break @var{function}(@var{types})} to specify which +particular version of the function you want. Otherwise, @value{GDBN} offers +you a menu of numbered choices for different possible breakpoints, and +waits for your selection with the prompt @samp{>}. The first two +options are always @samp{[0] cancel} and @samp{[1] all}. Typing @kbd{1} +sets a breakpoint at each definition of @var{function}, and typing +@kbd{0} aborts the @code{break} command without setting any new +breakpoints. + +For example, the following session excerpt shows an attempt to set a +breakpoint at the overloaded symbol @code{String::after}. +We choose three particular definitions of that function name: + +@c FIXME! This is likely to change to show arg type lists, at least +@smallexample +(@value{GDBP}) b String::after +[0] cancel +[1] all +[2] file:String.cc; line number:867 +[3] file:String.cc; line number:860 +[4] file:String.cc; line number:875 +[5] file:String.cc; line number:853 +[6] file:String.cc; line number:846 +[7] file:String.cc; line number:735 +> 2 4 6 +Breakpoint 1 at 0xb26c: file String.cc, line 867. +Breakpoint 2 at 0xb344: file String.cc, line 875. +Breakpoint 3 at 0xafcc: file String.cc, line 846. +Multiple breakpoints were set. +Use the "delete" command to delete unwanted + breakpoints. +(@value{GDBP}) +@end smallexample +@end ifclear + +@ifclear BARETARGET +@node Error in Breakpoints +@subsection ``Cannot insert breakpoints'' + +@c FIXME: "cannot insert breakpoints" error, v unclear. +@c Q in pending mail to Gilmore. ---pesch@cygnus.com, 26mar91 +@c some light may be shed by looking at instances of +@c ONE_PROCESS_WRITETEXT. But error message seems possible otherwise +@c too. pesch, 20sep91 +Under some operating systems, breakpoints cannot be used in a program if +any other process is running that program. In this situation, +attempting to run or continue a program with a breakpoint causes @value{GDBN} +to stop the other process. + +When this happens, you have three ways to proceed: + +@enumerate +@item +Remove or disable the breakpoints, then continue. + +@item +Suspend @value{GDBN}, and copy the file containing your program to a new name. +Resume @value{GDBN} and use the @code{exec-file} command to specify that @value{GDBN} +should run your program under that name. Then start your program again. + +@c FIXME: RMS commented here "Show example". Maybe when someone +@c explains the first FIXME: in this section... + +@item +Relink your program so that the text segment is nonsharable, using the +linker option @samp{-N}. The operating system limitation may not apply +to nonsharable executables. +@end enumerate +@end ifclear + +@node Continuing and Stepping +@section Continuing and stepping + +@cindex stepping +@cindex continuing +@cindex resuming execution +@dfn{Continuing} means resuming program execution until your program +completes normally. In contrast, @dfn{stepping} means executing just +one more ``step'' of your program, where ``step'' may mean either one +line of source code, or one machine instruction (depending on what +particular command you use). Either when continuing +or when stepping, your program may stop even sooner, due to +@ifset BARETARGET +a breakpoint. +@end ifset +@ifclear BARETARGET +a breakpoint or a signal. (If due to a signal, you may want to use +@code{handle}, or use @samp{signal 0} to resume execution. +@xref{Signals, ,Signals}.) +@end ifclear + +@table @code +@item continue @r{[}@var{ignore-count}@r{]} +@itemx c @r{[}@var{ignore-count}@r{]} +@itemx fg @r{[}@var{ignore-count}@r{]} +@kindex continue +@kindex c +@kindex fg +Resume program execution, at the address where your program last stopped; +any breakpoints set at that address are bypassed. The optional argument +@var{ignore-count} allows you to specify a further number of times to +ignore a breakpoint at this location; its effect is like that of +@code{ignore} (@pxref{Conditions, ,Break conditions}). + +The argument @var{ignore-count} is meaningful only when your program +stopped due to a breakpoint. At other times, the argument to +@code{continue} is ignored. + +The synonyms @code{c} and @code{fg} are provided purely for convenience, +and have exactly the same behavior as @code{continue}. +@end table + +To resume execution at a different place, you can use @code{return} +(@pxref{Returning, ,Returning from a function}) to go back to the +calling function; or @code{jump} (@pxref{Jumping, ,Continuing at a +different address}) to go to an arbitrary location in your program. + +A typical technique for using stepping is to set a breakpoint +@ifclear CONLY +(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions}) +@end ifclear +@ifset CONLY +(@pxref{Breakpoints, ,Breakpoints and watchpoints}) +@end ifset +at the +beginning of the function or the section of your program where a +problem is believed to lie, run your program until it stops at that +breakpoint, and then step through the suspect area, examining the +variables that are interesting, until you see the problem happen. + +@table @code +@item step +@kindex step +@kindex s +Continue running your program until control reaches a different source +line, then stop it and return control to @value{GDBN}. This command is +abbreviated @code{s}. + +@quotation +@emph{Warning:} If you use the @code{step} command while control is +within a function that was compiled without debugging information, +execution proceeds until control reaches a function that does have +debugging information. +@end quotation + +@item step @var{count} +Continue running as in @code{step}, but do so @var{count} times. If a +breakpoint is reached, +@ifclear BARETARGET +or a signal not related to stepping occurs before @var{count} steps, +@end ifclear +stepping stops right away. + +@item next @r{[}@var{count}@r{]} +@kindex next +@kindex n +Continue to the next source line in the current (innermost) stack frame. +Similar to @code{step}, but any function calls appearing within the line +of code are executed without stopping. Execution stops when control +reaches a different line of code at the stack level which was executing +when the @code{next} command was given. This command is abbreviated +@code{n}. + +An argument @var{count} is a repeat count, as for @code{step}. + +@code{next} within a function that lacks debugging information acts like +@code{step}, but any function calls appearing within the code of the +function are executed without stopping. + +@item finish +@kindex finish +Continue running until just after function in the selected stack frame +returns. Print the returned value (if any). + +Contrast this with the @code{return} command (@pxref{Returning, +,Returning from a function}). + +@item until +@kindex until +@itemx u +@kindex u +Continue running until a source line past the current line, in the +current stack frame, is reached. This command is used to avoid single +stepping through a loop more than once. It is like the @code{next} +command, except that when @code{until} encounters a jump, it +automatically continues execution until the program counter is greater +than the address of the jump. + +This means that when you reach the end of a loop after single stepping +though it, @code{until} will cause your program to continue execution +until the loop is exited. In contrast, a @code{next} command at the end +of a loop will simply step back to the beginning of the loop, which +would force you to step through the next iteration. + +@code{until} always stops your program if it attempts to exit the current +stack frame. + +@code{until} may produce somewhat counterintuitive results if the order +of machine code does not match the order of the source lines. For +example, in the following excerpt from a debugging session, the @code{f} +(@code{frame}) command shows that execution is stopped at line +@code{206}; yet when we use @code{until}, we get to line @code{195}: + +@example +(@value{GDBP}) f +#0 main (argc=4, argv=0xf7fffae8) at m4.c:206 +206 expand_input(); +(@value{GDBP}) until +195 for ( ; argc > 0; NEXTARG) @{ +@end example + +This happened because, for execution efficiency, the compiler had +generated code for the loop closure test at the end, rather than the +start, of the loop---even though the test in a C @code{for}-loop is +written before the body of the loop. The @code{until} command appeared +to step back to the beginning of the loop when it advanced to this +expression; however, it has not really gone to an earlier +statement---not in terms of the actual machine code. + +@code{until} with no argument works by means of single +instruction stepping, and hence is slower than @code{until} with an +argument. + +@item until @var{location} +@itemx u @var{location} +Continue running your program until either the specified location is +reached, or the current stack frame returns. @var{location} is any of +the forms of argument acceptable to @code{break} (@pxref{Set Breaks, +,Setting breakpoints}). This form of the command uses breakpoints, +and hence is quicker than @code{until} without an argument. + +@item stepi +@itemx si +@kindex stepi +@kindex si +Execute one machine instruction, then stop and return to the debugger. + +It is often useful to do @samp{display/i $pc} when stepping by machine +instructions. This will cause the next instruction to be executed to +be displayed automatically at each stop. @xref{Auto Display, +,Automatic display}. + +An argument is a repeat count, as in @code{step}. + +@need 750 +@item nexti +@itemx ni +@kindex nexti +@kindex ni +Execute one machine instruction, but if it is a function call, +proceed until the function returns. + +An argument is a repeat count, as in @code{next}. +@end table + +@ifset POSIX +@node Signals +@section Signals +@cindex signals + +A signal is an asynchronous event that can happen in a program. The +operating system defines the possible kinds of signals, and gives each +kind a name and a number. For example, in Unix @code{SIGINT} is the +signal a program gets when you type an interrupt (often @kbd{C-c}); +@code{SIGSEGV} is the signal a program gets from referencing a place in +memory far away from all the areas in use; @code{SIGALRM} occurs when +the alarm clock timer goes off (which happens only if your program has +requested an alarm). + +@cindex fatal signals +Some signals, including @code{SIGALRM}, are a normal part of the +functioning of your program. Others, such as @code{SIGSEGV}, indicate +errors; these signals are @dfn{fatal} (kill your program immediately) if the +program has not specified in advance some other way to handle the signal. +@code{SIGINT} does not indicate an error in your program, but it is normally +fatal so it can carry out the purpose of the interrupt: to kill the program. + +@value{GDBN} has the ability to detect any occurrence of a signal in your +program. You can tell @value{GDBN} in advance what to do for each kind of +signal. + +@cindex handling signals +Normally, @value{GDBN} is set up to ignore non-erroneous signals like @code{SIGALRM} +(so as not to interfere with their role in the functioning of your program) +but to stop your program immediately whenever an error signal happens. +You can change these settings with the @code{handle} command. + +@table @code +@item info signals +@kindex info signals +Print a table of all the kinds of signals and how @value{GDBN} has been told to +handle each one. You can use this to see the signal numbers of all +the defined types of signals. + +@item handle @var{signal} @var{keywords}@dots{} +@kindex handle +Change the way @value{GDBN} handles signal @var{signal}. @var{signal} can be the +number of a signal or its name (with or without the @samp{SIG} at the +beginning). The @var{keywords} say what change to make. +@end table + +@c @group +The keywords allowed by the @code{handle} command can be abbreviated. +Their full names are: + +@table @code +@item nostop +@value{GDBN} should not stop your program when this signal happens. It may +still print a message telling you that the signal has come in. + +@item stop +@value{GDBN} should stop your program when this signal happens. This implies +the @code{print} keyword as well. + +@item print +@value{GDBN} should print a message when this signal happens. + +@item noprint +@value{GDBN} should not mention the occurrence of the signal at all. This +implies the @code{nostop} keyword as well. + +@item pass +@value{GDBN} should allow your program to see this signal; your program will be +able to handle the signal, or may be terminated if the signal is fatal +and not handled. + +@item nopass +@value{GDBN} should not allow your program to see this signal. +@end table +@c @end group + +When a signal stops your program, the signal is not visible until you +continue. Your program will see the signal then, if @code{pass} is in +effect for the signal in question @emph{at that time}. In other words, +after @value{GDBN} reports a signal, you can use the @code{handle} +command with @code{pass} or @code{nopass} to control whether that +signal will be seen by your program when you later continue it. + +You can also use the @code{signal} command to prevent your program from +seeing a signal, or cause it to see a signal it normally would not see, +or to give it any signal at any time. For example, if your program stopped +due to some sort of memory reference error, you might store correct +values into the erroneous variables and continue, hoping to see more +execution; but your program would probably terminate immediately as +a result of the fatal signal once it saw the signal. To prevent this, +you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your +program a signal}. +@end ifset + +@node Stack +@chapter Examining the Stack + +When your program has stopped, the first thing you need to know is where it +stopped and how it got there. + +@cindex call stack +Each time your program performs a function call, the information about +where in your program the call was made from is saved in a block of data +called a @dfn{stack frame}. The frame also contains the arguments of the +call and the local variables of the function that was called. All the +stack frames are allocated in a region of memory called the @dfn{call +stack}. + +When your program stops, the @value{GDBN} commands for examining the +stack allow you to see all of this information. + +@cindex selected frame +One of the stack frames is @dfn{selected} by @value{GDBN} and many +@value{GDBN} commands refer implicitly to the selected frame. In +particular, whenever you ask @value{GDBN} for the value of a variable in +your program, the value is found in the selected frame. There are +special @value{GDBN} commands to select whichever frame you are +interested in. + +When your program stops, @value{GDBN} automatically selects the +currently executing frame and describes it briefly as the @code{frame} +command does (@pxref{Frame Info, ,Information about a frame}). + +@menu +* Frames:: Stack frames +* Backtrace:: Backtraces +* Selection:: Selecting a frame +* Frame Info:: Information on a frame +@ifset MIPS +* MIPS Stack:: MIPS machines and the function stack +@end ifset +@end menu + +@node Frames +@section Stack frames + +@cindex frame +@cindex stack frame +The call stack is divided up into contiguous pieces called @dfn{stack +frames}, or @dfn{frames} for short; each frame is the data associated +with one call to one function. The frame contains the arguments given +to the function, the function's local variables, and the address at +which the function is executing. + +@cindex initial frame +@cindex outermost frame +@cindex innermost frame +When your program is started, the stack has only one frame, that of the +function @code{main}. This is called the @dfn{initial} frame or the +@dfn{outermost} frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function invocation +is eliminated. If a function is recursive, there can be many frames for +the same function. The frame for the function in which execution is +actually occurring is called the @dfn{innermost} frame. This is the most +recently created of all the stack frames that still exist. + +@cindex frame pointer +Inside your program, stack frames are identified by their addresses. A +stack frame consists of many bytes, each of which has its own address; each +kind of computer has a convention for choosing one of those bytes whose +address serves as the address of the frame. Usually this address is kept +in a register called the @dfn{frame pointer register} while execution is +going on in that frame. + +@cindex frame number +@value{GDBN} assigns numbers to all existing stack frames, starting with +zero for the innermost frame, one for the frame that called it, +and so on upward. These numbers do not really exist in your program; +they are assigned by @value{GDBN} to give you a way of designating stack +frames in @value{GDBN} commands. + +@c below produces an acceptable overful hbox. --mew 13aug1993 +@cindex frameless execution +Some compilers provide a way to compile functions so that they operate +without stack frames. (For example, the @code{@value{GCC}} option +@samp{-fomit-frame-pointer} will generate functions without a frame.) +This is occasionally done with heavily used library functions to save +the frame setup time. @value{GDBN} has limited facilities for dealing +with these function invocations. If the innermost function invocation +has no stack frame, @value{GDBN} will nevertheless regard it as though +it had a separate frame, which is numbered zero as usual, allowing +correct tracing of the function call chain. However, @value{GDBN} has +no provision for frameless functions elsewhere in the stack. + +@node Backtrace +@section Backtraces + +A backtrace is a summary of how your program got where it is. It shows one +line per frame, for many frames, starting with the currently executing +frame (frame zero), followed by its caller (frame one), and on up the +stack. + +@table @code +@item backtrace +@itemx bt +@kindex backtrace +@kindex bt +Print a backtrace of the entire stack: one line per frame for all +frames in the stack. + +You can stop the backtrace at any time by typing the system interrupt +character, normally @kbd{C-c}. + +@item backtrace @var{n} +@itemx bt @var{n} +Similar, but print only the innermost @var{n} frames. + +@item backtrace -@var{n} +@itemx bt -@var{n} +Similar, but print only the outermost @var{n} frames. +@end table + +@kindex where +@kindex info stack +@kindex info s +The names @code{where} and @code{info stack} (abbreviated @code{info s}) +are additional aliases for @code{backtrace}. + +Each line in the backtrace shows the frame number and the function name. +The program counter value is also shown---unless you use @code{set +print address off}. The backtrace also shows the source file name and +line number, as well as the arguments to the function. The program +counter value is omitted if it is at the beginning of the code for that +line number. + +Here is an example of a backtrace. It was made with the command +@samp{bt 3}, so it shows the innermost three frames. + +@smallexample +@group +#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) + at builtin.c:993 +#1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242 +#2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08) + at macro.c:71 +(More stack frames follow...) +@end group +@end smallexample + +@noindent +The display for frame zero does not begin with a program counter +value, indicating that your program has stopped at the beginning of the +code for line @code{993} of @code{builtin.c}. + +@node Selection +@section Selecting a frame + +Most commands for examining the stack and other data in your program work on +whichever stack frame is selected at the moment. Here are the commands for +selecting a stack frame; all of them finish by printing a brief description +of the stack frame just selected. + +@table @code +@item frame @var{n} +@itemx f @var{n} +@kindex frame +@kindex f +Select frame number @var{n}. Recall that frame zero is the innermost +(currently executing) frame, frame one is the frame that called the +innermost one, and so on. The highest-numbered frame is the one for +@code{main}. + +@item frame @var{addr} +@itemx f @var{addr} +Select the frame at address @var{addr}. This is useful mainly if the +chaining of stack frames has been damaged by a bug, making it +impossible for @value{GDBN} to assign numbers properly to all frames. In +addition, this can be useful when your program has multiple stacks and +switches between them. + +@ifset SPARC +On the SPARC architecture, @code{frame} needs two addresses to +select an arbitrary frame: a frame pointer and a stack pointer. +@c note to future updaters: this is conditioned on a flag +@c FRAME_SPECIFICATION_DYADIC in the tm-*.h files, currently only used +@c by SPARC, hence the specific attribution. Generalize or list all +@c possibilities if more supported machines start doing this. +@end ifset + +@item up @var{n} +@kindex up +Move @var{n} frames up the stack. For positive numbers @var{n}, this +advances toward the outermost frame, to higher frame numbers, to frames +that have existed longer. @var{n} defaults to one. + +@item down @var{n} +@kindex down +@kindex do +Move @var{n} frames down the stack. For positive numbers @var{n}, this +advances toward the innermost frame, to lower frame numbers, to frames +that were created more recently. @var{n} defaults to one. You may +abbreviate @code{down} as @code{do}. +@end table + +All of these commands end by printing two lines of output describing the +frame. The first line shows the frame number, the function name, the +arguments, and the source file and line number of execution in that +frame. The second line shows the text of that source line. + +For example: +@smallexample +@group +(@value{GDBP}) up +#1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc) + at env.c:10 +10 read_input_file (argv[i]); +@end group +@end smallexample + +After such a printout, the @code{list} command with no arguments will +print ten lines centered on the point of execution in the frame. +@xref{List, ,Printing source lines}. + +@table @code +@item up-silently @var{n} +@itemx down-silently @var{n} +@kindex down-silently +@kindex up-silently +These two commands are variants of @code{up} and @code{down}, +respectively; they differ in that they do their work silently, without +causing display of the new frame. They are intended primarily for use +in @value{GDBN} command scripts, where the output might be unnecessary and +distracting. +@end table + +@node Frame Info +@section Information about a frame + +There are several other commands to print information about the selected +stack frame. + +@table @code +@item frame +@itemx f +When used without any argument, this command does not change which +frame is selected, but prints a brief description of the currently +selected stack frame. It can be abbreviated @code{f}. With an +argument, this command is used to select a stack frame. +@xref{Selection, ,Selecting a frame}. + +@item info frame +@itemx info f +@kindex info frame +@kindex info f +This command prints a verbose description of the selected stack frame, +including the address of the frame, the addresses of the next frame down +(called by this frame) and the next frame up (caller of this frame), the +language that the source code corresponding to this frame was written in, +the address of the frame's arguments, the program counter saved in it +(the address of execution in the caller frame), and which registers +were saved in the frame. The verbose description is useful when +something has gone wrong that has made the stack format fail to fit +the usual conventions. + +@item info frame @var{addr} +@itemx info f @var{addr} +Print a verbose description of the frame at address @var{addr}, +without selecting that frame. The selected frame remains unchanged by +this command. + +@item info args +@kindex info args +Print the arguments of the selected frame, each on a separate line. + +@item info locals +@kindex info locals +Print the local variables of the selected frame, each on a separate +line. These are all variables (declared either static or automatic) +accessible at the point of execution of the selected frame. + +@ifclear CONLY +@item info catch +@kindex info catch +@cindex catch exceptions +@cindex exception handlers +Print a list of all the exception handlers that are active in the +current stack frame at the current point of execution. To see other +exception handlers, visit the associated frame (using the @code{up}, +@code{down}, or @code{frame} commands); then type @code{info catch}. +@xref{Exception Handling, ,Breakpoints and exceptions}. +@end ifclear +@end table + +@ifset MIPS +@node MIPS Stack +@section MIPS machines and the function stack + +@cindex stack on MIPS +@cindex MIPS stack +MIPS based computers use an unusual stack frame, which sometimes +requires @value{GDBN} to search backward in the object code to find the +beginning of a function. + +@cindex response time, MIPS debugging +To improve response time (especially for embedded applications, where +@value{GDBN} may be restricted to a slow serial line for this search) +you may want to limit the size of this search, using one of these +commands: +@c FIXME! So what happens when GDB does *not* find the beginning of a +@c function? + +@cindex @code{heuristic-fence-post} (MIPS) +@table @code +@item set heuristic-fence-post @var{limit} +Restrict @var{GDBN} to examining at most @var{limit} bytes in its search +for the beginning of a function. A value of @code{0} (the default) +means there is no limit. + +@item show heuristic-fence-post +Display the current limit. +@end table + +@noindent +These commands are available @emph{only} when @value{GDBN} is configured +for debugging programs on MIPS processors. +@end ifset + +@node Source +@chapter Examining Source Files + +@value{GDBN} can print parts of your program's source, since the debugging +information recorded in the program tells @value{GDBN} what source files were +used to build it. When your program stops, @value{GDBN} spontaneously prints +the line where it stopped. Likewise, when you select a stack frame +(@pxref{Selection, ,Selecting a frame}), @value{GDBN} prints the line where +execution in that frame has stopped. You can print other portions of +source files by explicit command. + +@ifclear DOSHOST +If you use @value{GDBN} through its GNU Emacs interface, you may prefer to use +Emacs facilities to view source; @pxref{Emacs, ,Using @value{GDBN} under GNU +Emacs}. +@end ifclear + +@menu +* List:: Printing source lines +@ifclear DOSHOST +* Search:: Searching source files +@end ifclear + +* Source Path:: Specifying source directories +* Machine Code:: Source and machine code +@end menu + +@node List +@section Printing source lines + +@kindex list +@kindex l +To print lines from a source file, use the @code{list} command +(abbreviated @code{l}). There are several ways to specify what part +of the file you want to print. + +Here are the forms of the @code{list} command most commonly used: + +@table @code +@item list @var{linenum} +Print lines centered around line number @var{linenum} in the +current source file. + +@item list @var{function} +Print lines centered around the beginning of function +@var{function}. + +@item list +Print more lines. If the last lines printed were printed with a +@code{list} command, this prints lines following the last lines +printed; however, if the last line printed was a solitary line printed +as part of displaying a stack frame (@pxref{Stack, ,Examining the +Stack}), this prints lines centered around that line. + +@item list - +Print lines just before the lines last printed. +@end table + +By default, @value{GDBN} prints ten source lines with any of these forms of +the @code{list} command. You can change this using @code{set listsize}: + +@table @code +@item set listsize @var{count} +@kindex set listsize +Make the @code{list} command display @var{count} source lines (unless +the @code{list} argument explicitly specifies some other number). + +@item show listsize +@kindex show listsize +Display the number of lines that @code{list} will currently display by +default. +@end table + +Repeating a @code{list} command with @key{RET} discards the argument, +so it is equivalent to typing just @code{list}. This is more useful +than listing the same lines again. An exception is made for an +argument of @samp{-}; that argument is preserved in repetition so that +each repetition moves up in the source file. + +@cindex linespec +In general, the @code{list} command expects you to supply zero, one or two +@dfn{linespecs}. Linespecs specify source lines; there are several ways +of writing them but the effect is always to specify some source line. +Here is a complete description of the possible arguments for @code{list}: + +@table @code +@item list @var{linespec} +Print lines centered around the line specified by @var{linespec}. + +@item list @var{first},@var{last} +Print lines from @var{first} to @var{last}. Both arguments are +linespecs. + +@item list ,@var{last} +Print lines ending with @var{last}. + +@item list @var{first}, +Print lines starting with @var{first}. + +@item list + +Print lines just after the lines last printed. + +@item list - +Print lines just before the lines last printed. + +@item list +As described in the preceding table. +@end table + +Here are the ways of specifying a single source line---all the +kinds of linespec. + +@table @code +@item @var{number} +Specifies line @var{number} of the current source file. +When a @code{list} command has two linespecs, this refers to +the same source file as the first linespec. + +@item +@var{offset} +Specifies the line @var{offset} lines after the last line printed. +When used as the second linespec in a @code{list} command that has +two, this specifies the line @var{offset} lines down from the +first linespec. + +@item -@var{offset} +Specifies the line @var{offset} lines before the last line printed. + +@item @var{filename}:@var{number} +Specifies line @var{number} in the source file @var{filename}. + +@item @var{function} +@c FIXME: "of the open-brace" is C-centric. When we add other langs... +Specifies the line of the open-brace that begins the body of the +function @var{function}. + +@item @var{filename}:@var{function} +Specifies the line of the open-brace that begins the body of the +function @var{function} in the file @var{filename}. You only need the +file name with a function name to avoid ambiguity when there are +identically named functions in different source files. + +@item *@var{address} +Specifies the line containing the program address @var{address}. +@var{address} may be any expression. +@end table + +@ifclear DOSHOST +@node Search +@section Searching source files +@cindex searching +@kindex reverse-search + +There are two commands for searching through the current source file for a +regular expression. + +@table @code +@item forward-search @var{regexp} +@itemx search @var{regexp} +@kindex search +@kindex forward-search +The command @samp{forward-search @var{regexp}} checks each line, +starting with the one following the last line listed, for a match for +@var{regexp}. It lists the line that is found. You can use +synonym @samp{search @var{regexp}} or abbreviate the command name as +@code{fo}. + +@item reverse-search @var{regexp} +The command @samp{reverse-search @var{regexp}} checks each line, starting +with the one before the last line listed and going backward, for a match +for @var{regexp}. It lists the line that is found. You can abbreviate +this command as @code{rev}. +@end table +@end ifclear + +@node Source Path +@section Specifying source directories + +@cindex source path +@cindex directories for source files +Executable programs sometimes do not record the directories of the source +files from which they were compiled, just the names. Even when they do, +the directories could be moved between the compilation and your debugging +session. @value{GDBN} has a list of directories to search for source files; +this is called the @dfn{source path}. Each time @value{GDBN} wants a source file, +it tries all the directories in the list, in the order they are present +in the list, until it finds a file with the desired name. Note that +the executable search path is @emph{not} used for this purpose. Neither is +the current working directory, unless it happens to be in the source +path. + +If @value{GDBN} cannot find a source file in the source path, and the object +program records a directory, @value{GDBN} tries that directory too. If the +source path is empty, and there is no record of the compilation +directory, @value{GDBN} will, as a last resort, look in the current +directory. + +Whenever you reset or rearrange the source path, @value{GDBN} will clear out +any information it has cached about where source files are found, where +each line is in the file, etc. + +@kindex directory +When you start @value{GDBN}, its source path is empty. +To add other directories, use the @code{directory} command. + +@table @code +@item directory @var{dirname} @dots{} +Add directory @var{dirname} to the front of the source path. Several +directory names may be given to this command, separated by @samp{:} or +whitespace. You may specify a directory that is already in the source +path; this moves it forward, so it will be searched sooner. + +@kindex cdir +@kindex cwd +@kindex $cdir +@kindex $cwd +@cindex compilation directory +@cindex current directory +@cindex working directory +@cindex directory, current +@cindex directory, compilation +You can use the string @samp{$cdir} to refer to the compilation +directory (if one is recorded), and @samp{$cwd} to refer to the current +working directory. @samp{$cwd} is not the same as @samp{.}---the former +tracks the current working directory as it changes during your @value{GDBN} +session, while the latter is immediately expanded to the current +directory at the time you add an entry to the source path. + +@item directory +Reset the source path to empty again. This requires confirmation. + +@c RET-repeat for @code{directory} is explicitly disabled, but since +@c repeating it would be a no-op we do not say that. (thanks to RMS) + +@item show directories +@kindex show directories +Print the source path: show which directories it contains. +@end table + +If your source path is cluttered with directories that are no longer of +interest, @value{GDBN} may sometimes cause confusion by finding the wrong +versions of source. You can correct the situation as follows: + +@enumerate +@item +Use @code{directory} with no argument to reset the source path to empty. + +@item +Use @code{directory} with suitable arguments to reinstall the +directories you want in the source path. You can add all the +directories in one command. +@end enumerate + +@node Machine Code +@section Source and machine code + +You can use the command @code{info line} to map source lines to program +addresses (and vice versa), and the command @code{disassemble} to display +a range of addresses as machine instructions. + +@table @code +@item info line @var{linespec} +@kindex info line +Print the starting and ending addresses of the compiled code for +source line @var{linespec}. You can specify source lines in any of +the ways understood by the @code{list} command (@pxref{List, ,Printing +source lines}). +@end table + +For example, we can use @code{info line} to discover the location of +the object code for the first line of function +@code{m4_changequote}: + +@smallexample +(@value{GDBP}) info line m4_changecom +Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350. +@end smallexample + +@noindent +We can also inquire (using @code{*@var{addr}} as the form for +@var{linespec}) what source line covers a particular address: +@smallexample +(@value{GDBP}) info line *0x63ff +Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404. +@end smallexample + +@cindex @code{$_} and @code{info line} +After @code{info line}, the default address for the @code{x} command +is changed to the starting address of the line, so that @samp{x/i} is +sufficient to begin examining the machine code (@pxref{Memory, +,Examining memory}). Also, this address is saved as the value of the +convenience variable @code{$_} (@pxref{Convenience Vars, ,Convenience +variables}). + +@table @code +@kindex disassemble +@item disassemble +@cindex assembly instructions +@cindex instructions, assembly +@cindex machine instructions +@cindex listing machine instructions +This specialized command dumps a range of memory as machine +instructions. The default memory range is the function surrounding the +program counter of the selected frame. A single argument to this +command is a program counter value; the function surrounding this value +will be dumped. Two arguments specify a range of addresses (first +inclusive, second exclusive) to dump. +@end table + +@ifclear H8EXCLUSIVE +We can use @code{disassemble} to inspect the object code +range shown in the last @code{info line} example (the example +shows SPARC machine instructions): + + +@smallexample +(@value{GDBP}) disas 0x63e4 0x6404 +Dump of assembler code from 0x63e4 to 0x6404: +0x63e4 : ble 0x63f8 +0x63e8 : sethi %hi(0x4c00), %o0 +0x63ec : ld [%i1+4], %o0 +0x63f0 : b 0x63fc +0x63f4 : ld [%o0+4], %o0 +0x63f8 : or %o0, 0x1a4, %o0 +0x63fc : call 0x9288 +0x6400 : nop +End of assembler dump. +@end smallexample +@end ifclear + +@ifset H8EXCLUSIVE +For example, here is the beginning of the output for the +disassembly of a function @code{fact}: + + +@smallexample +(@value{GDBP}) disas fact +Dump of assembler code for function fact: +to 0x808c: +0x802c : 6d f2 mov.w r2,@@-r7 +0x802e : 6d f3 mov.w r3,@@-r7 +0x8030 : 6d f6 mov.w r6,@@-r7 +0x8032 : 0d 76 mov.w r7,r6 +0x8034 : 6f 70 00 08 mov.w @@(0x8,r7),r0 +0x8038 19 11 sub.w r1,r1 + . + . + . +@end smallexample +@end ifset + +@node Data +@chapter Examining Data + +@cindex printing data +@cindex examining data +@kindex print +@kindex inspect +@c "inspect" is not quite a synonym if you are using Epoch, which we do not +@c document because it is nonstandard... Under Epoch it displays in a +@c different window or something like that. +The usual way to examine data in your program is with the @code{print} +command (abbreviated @code{p}), or its synonym @code{inspect}. +@ifclear CONLY +It evaluates and prints the value of an expression of the language your +program is written in (@pxref{Languages, ,Using @value{GDBN} with Different +Languages}). +@end ifclear + +@table @code +@item print @var{exp} +@itemx print /@var{f} @var{exp} +@var{exp} is an expression (in the source language). By default the +value of @var{exp} is printed in a format appropriate to its data type; +you can choose a different format by specifying @samp{/@var{f}}, where +@var{f} is a letter specifying the format; @pxref{Output Formats,,Output +formats}. + +@item print +@itemx print /@var{f} +If you omit @var{exp}, @value{GDBN} displays the last value again (from the +@dfn{value history}; @pxref{Value History, ,Value history}). This allows you to +conveniently inspect the same value in an alternative format. +@end table + +A more low-level way of examining data is with the @code{x} command. +It examines data in memory at a specified address and prints it in a +specified format. @xref{Memory, ,Examining memory}. + +If you are interested in information about types, or about how the fields +of a struct +@ifclear CONLY +or class +@end ifclear +are declared, use the @code{ptype @var{exp}} +command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}. + +@menu +* Expressions:: Expressions +* Variables:: Program variables +* Arrays:: Artificial arrays +* Output Formats:: Output formats +* Memory:: Examining memory +* Auto Display:: Automatic display +* Print Settings:: Print settings +* Value History:: Value history +* Convenience Vars:: Convenience variables +* Registers:: Registers +@ifclear HAVE-FLOAT +* Floating Point Hardware:: Floating point hardware +@end ifclear +@end menu + +@node Expressions +@section Expressions + +@cindex expressions +@code{print} and many other @value{GDBN} commands accept an expression and +compute its value. Any kind of constant, variable or operator defined +by the programming language you are using is valid in an expression in +@value{GDBN}. This includes conditional expressions, function calls, casts +and string constants. It unfortunately does not include symbols defined +by preprocessor @code{#define} commands. + +@ifclear CONLY +Because C is so widespread, most of the expressions shown in examples in +this manual are in C. @xref{Languages, , Using @value{GDBN} with Different +Languages}, for information on how to use expressions in other +languages. + +In this section, we discuss operators that you can use in @value{GDBN} +expressions regardless of your programming language. + +Casts are supported in all languages, not just in C, because it is so +useful to cast a number into a pointer so as to examine a structure +at that address in memory. +@c FIXME: casts supported---Mod2 true? +@end ifclear + +@value{GDBN} supports these operators in addition to those of programming +languages: + +@table @code +@item @@ +@samp{@@} is a binary operator for treating parts of memory as arrays. +@xref{Arrays, ,Artificial arrays}, for more information. + +@item :: +@samp{::} allows you to specify a variable in terms of the file or +function where it is defined. @xref{Variables, ,Program variables}. + +@item @{@var{type}@} @var{addr} +@cindex @{@var{type}@} +@cindex type casting memory +@cindex memory, viewing as typed object +@cindex casts, to view memory +Refers to an object of type @var{type} stored at address @var{addr} in +memory. @var{addr} may be any expression whose value is an integer or +pointer (but parentheses are required around binary operators, just as in +a cast). This construct is allowed regardless of what kind of data is +normally supposed to reside at @var{addr}. +@end table + +@node Variables +@section Program variables + +The most common kind of expression to use is the name of a variable +in your program. + +Variables in expressions are understood in the selected stack frame +(@pxref{Selection, ,Selecting a frame}); they must either be global +(or static) or be visible according to the scope rules of the +programming language from the point of execution in that frame. This +means that in the function + +@example +foo (a) + int a; +@{ + bar (a); + @{ + int b = test (); + bar (b); + @} +@} +@end example + +@noindent +you can examine and use the variable @code{a} whenever your program is +executing within the function @code{foo}, but you can only use or +examine the variable @code{b} while your program is executing inside +the block where @code{b} is declared. + +@cindex variable name conflict +There is an exception: you can refer to a variable or function whose +scope is a single source file even if the current execution point is not +in this file. But it is possible to have more than one such variable or +function with the same name (in different source files). If that +happens, referring to that name has unpredictable effects. If you wish, +you can specify a static variable in a particular function or file, +using the colon-colon notation: + +@cindex colon-colon +@iftex +@c info cannot cope with a :: index entry, but why deprive hard copy readers? +@kindex :: +@end iftex +@example +@var{file}::@var{variable} +@var{function}::@var{variable} +@end example + +@noindent +Here @var{file} or @var{function} is the name of the context for the +static @var{variable}. In the case of file names, you can use quotes to +make sure @value{GDBN} parses the file name as a single word---for example, +to print a global value of @code{x} defined in @file{f2.c}: + +@example +(@value{GDBP}) p 'f2.c'::x +@end example + +@ifclear CONLY +@cindex C++ scope resolution +This use of @samp{::} is very rarely in conflict with the very similar +use of the same notation in C++. @value{GDBN} also supports use of the C++ +scope resolution operator in @value{GDBN} expressions. +@c FIXME: Um, so what happens in one of those rare cases where it's in +@c conflict?? --mew +@end ifclear + +@cindex wrong values +@cindex variable values, wrong +@quotation +@emph{Warning:} Occasionally, a local variable may appear to have the +wrong value at certain points in a function---just after entry to a new +scope, and just before exit. +@end quotation +You may see this problem when you are stepping by machine instructions. +This is because on most machines, it takes more than one instruction to +set up a stack frame (including local variable definitions); if you are +stepping by machine instructions, variables may appear to have the wrong +values until the stack frame is completely built. On exit, it usually +also takes more than one machine instruction to destroy a stack frame; +after you begin stepping through that group of instructions, local +variable definitions may be gone. + +@node Arrays +@section Artificial arrays + +@cindex artificial array +@kindex @@ +It is often useful to print out several successive objects of the +same type in memory; a section of an array, or an array of +dynamically determined size for which only a pointer exists in the +program. + +You can do this by referring to a contiguous span of memory as an +@dfn{artificial array}, using the binary operator @samp{@@}. The left +operand of @samp{@@} should be the first element of the desired array, +as an individual object. The right operand should be the desired length +of the array. The result is an array value whose elements are all of +the type of the left argument. The first element is actually the left +argument; the second element comes from bytes of memory immediately +following those that hold the first element, and so on. Here is an +example. If a program says + +@example +int *array = (int *) malloc (len * sizeof (int)); +@end example + +@noindent +you can print the contents of @code{array} with + +@example +p *array@@len +@end example + +The left operand of @samp{@@} must reside in memory. Array values made +with @samp{@@} in this way behave just like other arrays in terms of +subscripting, and are coerced to pointers when used in expressions. +Artificial arrays most often appear in expressions via the value history +(@pxref{Value History, ,Value history}), after printing one out. + +Sometimes the artificial array mechanism is not quite enough; in +moderately complex data structures, the elements of interest may not +actually be adjacent---for example, if you are interested in the values +of pointers in an array. One useful work-around in this situation is +to use a convenience variable (@pxref{Convenience Vars, ,Convenience +variables}) as a counter in an expression that prints the first +interesting value, and then repeat that expression via @key{RET}. For +instance, suppose you have an array @code{dtab} of pointers to +structures, and you are interested in the values of a field @code{fv} +in each structure. Here is an example of what you might type: + +@example +set $i = 0 +p dtab[$i++]->fv +@key{RET} +@key{RET} +@dots{} +@end example + +@node Output Formats +@section Output formats + +@cindex formatted output +@cindex output formats +By default, @value{GDBN} prints a value according to its data type. Sometimes +this is not what you want. For example, you might want to print a number +in hex, or a pointer in decimal. Or you might want to view data in memory +at a certain address as a character string or as an instruction. To do +these things, specify an @dfn{output format} when you print a value. + +The simplest use of output formats is to say how to print a value +already computed. This is done by starting the arguments of the +@code{print} command with a slash and a format letter. The format +letters supported are: + +@table @code +@item x +Regard the bits of the value as an integer, and print the integer in +hexadecimal. + +@item d +Print as integer in signed decimal. + +@item u +Print as integer in unsigned decimal. + +@item o +Print as integer in octal. + +@item t +Print as integer in binary. The letter @samp{t} stands for ``two''. +@footnote{@samp{b} cannot be used because these format letters are also +used with the @code{x} command, where @samp{b} stands for ``byte''; +@pxref{Memory,,Examining memory}.} + +@item a +Print as an address, both absolute in hex and as an offset from the +nearest preceding symbol. This format can be used to discover where (in +what function) an unknown address is located: + +@example +(@value{GDBP}) p/a 0x54320 +$3 = 0x54320 <_initialize_vx+396> +@end example + +@item c +Regard as an integer and print it as a character constant. + +@item f +Regard the bits of the value as a floating point number and print +using typical floating point syntax. +@end table + +For example, to print the program counter in hex (@pxref{Registers}), type + +@example +p/x $pc +@end example + +@noindent +Note that no space is required before the slash; this is because command +names in @value{GDBN} cannot contain a slash. + +To reprint the last value in the value history with a different format, +you can use the @code{print} command with just a format and no +expression. For example, @samp{p/x} reprints the last value in hex. + +@node Memory +@section Examining memory + +You can use the command @code{x} (for ``examine'') to examine memory in +any of several formats, independently of your program's data types. + +@cindex examining memory +@table @code +@kindex x +@item x/@var{nfu} @var{addr} +@itemx x @var{addr} +@itemx x +Use the @code{x} command to examine memory. +@end table + +@var{n}, @var{f}, and @var{u} are all optional parameters that specify how +much memory to display and how to format it; @var{addr} is an +expression giving the address where you want to start displaying memory. +If you use defaults for @var{nfu}, you need not type the slash @samp{/}. +Several commands set convenient defaults for @var{addr}. + +@table @r +@item @var{n}, the repeat count +The repeat count is a decimal integer; the default is 1. It specifies +how much memory (counting by units @var{u}) to display. +@c This really is **decimal**; unaffected by 'set radix' as of GDB +@c 4.1.2. + +@item @var{f}, the display format +The display format is one of the formats used by @code{print}, +or @samp{s} (null-terminated string) or @samp{i} (machine instruction). +The default is @samp{x} (hexadecimal) initially, or the format from the +last time you used either @code{x} or @code{print}. + +@item @var{u}, the unit size +The unit size is any of + +@table @code +@item b +Bytes. +@item h +Halfwords (two bytes). +@item w +Words (four bytes). This is the initial default. +@item g +Giant words (eight bytes). +@end table + +Each time you specify a unit size with @code{x}, that size becomes the +default unit the next time you use @code{x}. (For the @samp{s} and +@samp{i} formats, the unit size is ignored and is normally not written.) + +@item @var{addr}, starting display address +@var{addr} is the address where you want @value{GDBN} to begin displaying +memory. The expression need not have a pointer value (though it may); +it is always interpreted as an integer address of a byte of memory. +@xref{Expressions, ,Expressions}, for more information on expressions. The default for +@var{addr} is usually just after the last address examined---but several +other commands also set the default address: @code{info breakpoints} (to +the address of the last breakpoint listed), @code{info line} (to the +starting address of a line), and @code{print} (if you use it to display +a value from memory). +@end table + +For example, @samp{x/3uh 0x54320} is a request to display three halfwords +(@code{h}) of memory, formatted as unsigned decimal integers (@samp{u}), +starting at address @code{0x54320}. @samp{x/4xw $sp} prints the four +words (@samp{w}) of memory above the stack pointer (here, @samp{$sp}; +@pxref{Registers}) in hexadecimal (@samp{x}). + +Since the letters indicating unit sizes are all distinct from the +letters specifying output formats, you do not have to remember whether +unit size or format comes first; either order will work. The output +specifications @samp{4xw} and @samp{4wx} mean exactly the same thing. +(However, the count @var{n} must come first; @samp{wx4} will not work.) + +Even though the unit size @var{u} is ignored for the formats @samp{s} +and @samp{i}, you might still want to use a count @var{n}; for example, +@samp{3i} specifies that you want to see three machine instructions, +including any operands. The command @code{disassemble} gives an +alternative way of inspecting machine instructions; @pxref{Machine +Code,,Source and machine code}. + +All the defaults for the arguments to @code{x} are designed to make it +easy to continue scanning memory with minimal specifications each time +you use @code{x}. For example, after you have inspected three machine +instructions with @samp{x/3i @var{addr}}, you can inspect the next seven +with just @samp{x/7}. If you use @key{RET} to repeat the @code{x} command, +the repeat count @var{n} is used again; the other arguments default as +for successive uses of @code{x}. + +@cindex @code{$_}, @code{$__}, and value history +The addresses and contents printed by the @code{x} command are not saved +in the value history because there is often too much of them and they +would get in the way. Instead, @value{GDBN} makes these values available for +subsequent use in expressions as values of the convenience variables +@code{$_} and @code{$__}. After an @code{x} command, the last address +examined is available for use in expressions in the convenience variable +@code{$_}. The contents of that address, as examined, are available in +the convenience variable @code{$__}. + +If the @code{x} command has a repeat count, the address and contents saved +are from the last memory unit printed; this is not the same as the last +address printed if several units were printed on the last line of output. + +@node Auto Display +@section Automatic display +@cindex automatic display +@cindex display of expressions + +If you find that you want to print the value of an expression frequently +(to see how it changes), you might want to add it to the @dfn{automatic +display list} so that @value{GDBN} will print its value each time your program stops. +Each expression added to the list is given a number to identify it; +to remove an expression from the list, you specify that number. +The automatic display looks like this: + +@example +2: foo = 38 +3: bar[5] = (struct hack *) 0x3804 +@end example + +@noindent +This display shows item numbers, expressions and their current values. As with +displays you request manually using @code{x} or @code{print}, you can +specify the output format you prefer; in fact, @code{display} decides +whether to use @code{print} or @code{x} depending on how elaborate your +format specification is---it uses @code{x} if you specify a unit size, +or one of the two formats (@samp{i} and @samp{s}) that are only +supported by @code{x}; otherwise it uses @code{print}. + +@table @code +@item display @var{exp} +@kindex display +Add the expression @var{exp} to the list of expressions to display +each time your program stops. @xref{Expressions, ,Expressions}. + +@code{display} will not repeat if you press @key{RET} again after using it. + +@item display/@var{fmt} @var{exp} +For @var{fmt} specifying only a display format and not a size or +count, add the expression @var{exp} to the auto-display list but +arrange to display it each time in the specified format @var{fmt}. +@xref{Output Formats,,Output formats}. + +@item display/@var{fmt} @var{addr} +For @var{fmt} @samp{i} or @samp{s}, or including a unit-size or a +number of units, add the expression @var{addr} as a memory address to +be examined each time your program stops. Examining means in effect +doing @samp{x/@var{fmt} @var{addr}}. @xref{Memory, ,Examining memory}. +@end table + +For example, @samp{display/i $pc} can be helpful, to see the machine +instruction about to be executed each time execution stops (@samp{$pc} +is a common name for the program counter; @pxref{Registers}). + +@table @code +@item undisplay @var{dnums}@dots{} +@itemx delete display @var{dnums}@dots{} +@kindex delete display +@kindex undisplay +Remove item numbers @var{dnums} from the list of expressions to display. + +@code{undisplay} will not repeat if you press @key{RET} after using it. +(Otherwise you would just get the error @samp{No display number @dots{}}.) + +@item disable display @var{dnums}@dots{} +@kindex disable display +Disable the display of item numbers @var{dnums}. A disabled display +item is not printed automatically, but is not forgotten. It may be +enabled again later. + +@item enable display @var{dnums}@dots{} +@kindex enable display +Enable display of item numbers @var{dnums}. It becomes effective once +again in auto display of its expression, until you specify otherwise. + +@item display +Display the current values of the expressions on the list, just as is +done when your program stops. + +@item info display +@kindex info display +Print the list of expressions previously set up to display +automatically, each one with its item number, but without showing the +values. This includes disabled expressions, which are marked as such. +It also includes expressions which would not be displayed right now +because they refer to automatic variables not currently available. +@end table + +If a display expression refers to local variables, then it does not make +sense outside the lexical context for which it was set up. Such an +expression is disabled when execution enters a context where one of its +variables is not defined. For example, if you give the command +@code{display last_char} while inside a function with an argument +@code{last_char}, then this argument will be displayed while your program +continues to stop inside that function. When it stops elsewhere---where +there is no variable @code{last_char}---display is disabled. The next time +your program stops where @code{last_char} is meaningful, you can enable the +display expression once again. + +@node Print Settings +@section Print settings + +@cindex format options +@cindex print settings +@value{GDBN} provides the following ways to control how arrays, structures, +and symbols are printed. + +@noindent +These settings are useful for debugging programs in any language: + +@table @code +@item set print address +@itemx set print address on +@kindex set print address +@value{GDBN} will print memory addresses showing the location of stack +traces, structure values, pointer values, breakpoints, and so forth, +even when it also displays the contents of those addresses. The default +is on. For example, this is what a stack frame display looks like, with +@code{set print address on}: + +@smallexample +@group +(@value{GDBP}) f +#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>") + at input.c:530 +530 if (lquote != def_lquote) +@end group +@end smallexample + +@item set print address off +Do not print addresses when displaying their contents. For example, +this is the same stack frame displayed with @code{set print address off}: + +@smallexample +@group +(@value{GDBP}) set print addr off +(@value{GDBP}) f +#0 set_quotes (lq="<<", rq=">>") at input.c:530 +530 if (lquote != def_lquote) +@end group +@end smallexample + +You can use @samp{set print address off} to eliminate all machine +dependent displays from the @value{GDBN} interface. For example, with +@code{print address off}, you should get the same text for backtraces on +all machines---whether or not they involve pointer arguments. + +@item show print address +@kindex show print address +Show whether or not addresses are to be printed. +@end table + +When @value{GDBN} prints a symbolic address, it normally prints the +closest earlier symbol plus an offset. If that symbol does not uniquely +identify the address (for example, it is a name whose scope is a single +source file), you may need to disambiguate. One way to do this is with +@code{info line}, for example @code{info line *0x4537}. Alternately, +you can set @value{GDBN} to print the source file and line number when +it prints a symbolic address: + +@table @code +@item set print symbol-filename on +@kindex set print symbol-filename +Tell @value{GDBN} to print the source file name and line number of a +symbol in the symbolic form of an address. + +@item set print symbol-filename off +Do not print source file name and line number of a symbol. This is the +default. + +@item show print symbol-filename +@kindex show print symbol-filename +Show whether or not @value{GDBN} will print the source file name and +line number of a symbol in the symbolic form of an address. +@end table + +Also, you may wish to see the symbolic form only if the address being +printed is reasonably close to the closest earlier symbol: + +@table @code +@item set print max-symbolic-offset @var{max-offset} +@kindex set print max-symbolic-offset +Tell @value{GDBN} to only display the symbolic form of an address if the +offset between the closest earlier symbol and the address is less than +@var{max-offset}. The default is 0, which means to always print the +symbolic form of an address, if any symbol precedes it. + +@item show print max-symbolic-offset +@kindex show print max-symbolic-offset +Ask how large the maximum offset is that @value{GDBN} will print in a +symbolic address. +@end table + +@table @code +@item set print array +@itemx set print array on +@kindex set print array +@value{GDBN} will pretty-print arrays. This format is more convenient to read, +but uses more space. The default is off. + +@item set print array off +Return to compressed format for arrays. + +@item show print array +@kindex show print array +Show whether compressed or pretty format is selected for displaying +arrays. + +@item set print elements @var{number-of-elements} +@kindex set print elements +If @value{GDBN} is printing a large array, it will stop printing after it has +printed the number of elements set by the @code{set print elements} command. +This limit also applies to the display of strings. +Setting the number of elements to zero means that the printing is unlimited. + +@item show print elements +@kindex show print elements +Display the number of elements of a large array that @value{GDBN} will print +before losing patience. + +@item set print pretty on +@kindex set print pretty +Cause @value{GDBN} to print structures in an indented format with one member per +line, like this: + +@smallexample +@group +$1 = @{ + next = 0x0, + flags = @{ + sweet = 1, + sour = 1 + @}, + meat = 0x54 "Pork" +@} +@end group +@end smallexample + +@item set print pretty off +Cause @value{GDBN} to print structures in a compact format, like this: + +@smallexample +@group +$1 = @{next = 0x0, flags = @{sweet = 1, sour = 1@}, \ +meat = 0x54 "Pork"@} +@end group +@end smallexample + +@noindent +This is the default format. + +@item show print pretty +@kindex show print pretty +Show which format @value{GDBN} will use to print structures. + +@item set print sevenbit-strings on +@kindex set print sevenbit-strings +Print using only seven-bit characters; if this option is set, +@value{GDBN} will display any eight-bit characters (in strings or character +values) using the notation @code{\}@var{nnn}. For example, @kbd{M-a} is +displayed as @code{\341}. + +@item set print sevenbit-strings off +Print using either seven-bit or eight-bit characters, as required. This +is the default. + +@item show print sevenbit-strings +@kindex show print sevenbit-strings +Show whether or not @value{GDBN} will print only seven-bit characters. + +@item set print union on +@kindex set print union +Tell @value{GDBN} to print unions which are contained in structures. This is the +default setting. + +@item set print union off +Tell @value{GDBN} not to print unions which are contained in structures. + +@item show print union +@kindex show print union +Ask @value{GDBN} whether or not it will print unions which are contained in +structures. + +For example, given the declarations + +@smallexample +typedef enum @{Tree, Bug@} Species; +typedef enum @{Big_tree, Acorn, Seedling@} Tree_forms; +typedef enum @{Caterpillar, Cocoon, Butterfly@} + Bug_forms; + +struct thing @{ + Species it; + union @{ + Tree_forms tree; + Bug_forms bug; + @} form; +@}; + +struct thing foo = @{Tree, @{Acorn@}@}; +@end smallexample + +@noindent +with @code{set print union on} in effect @samp{p foo} would print + +@smallexample +$1 = @{it = Tree, form = @{tree = Acorn, bug = Cocoon@}@} +@end smallexample + +@noindent +and with @code{set print union off} in effect it would print + +@smallexample +$1 = @{it = Tree, form = @{...@}@} +@end smallexample +@end table + +@ifclear CONLY +@need 1000 +@noindent +These settings are of interest when debugging C++ programs: + +@table @code +@item set print demangle +@itemx set print demangle on +@kindex set print demangle +Print C++ names in their source form rather than in the encoded +(``mangled'') form passed to the assembler and linker for type-safe +linkage. The default is @samp{on}. + +@item show print demangle +@kindex show print demangle +Show whether C++ names will be printed in mangled or demangled form. + +@item set print asm-demangle +@itemx set print asm-demangle on +@kindex set print asm-demangle +Print C++ names in their source form rather than their mangled form, even +in assembler code printouts such as instruction disassemblies. +The default is off. + +@item show print asm-demangle +@kindex show print asm-demangle +Show whether C++ names in assembly listings will be printed in mangled +or demangled form. + +@item set demangle-style @var{style} +@kindex set demangle-style +@cindex C++ symbol decoding style +@cindex symbol decoding style, C++ +Choose among several encoding schemes used by different compilers to +represent C++ names. The choices for @var{style} are currently: + +@table @code +@item auto +Allow @value{GDBN} to choose a decoding style by inspecting your program. + +@item gnu +Decode based on the GNU C++ compiler (@code{g++}) encoding algorithm. + +@item lucid +Decode based on the Lucid C++ compiler (@code{lcc}) encoding algorithm. + +@item arm +Decode using the algorithm in the @cite{C++ Annotated Reference Manual}. +@strong{Warning:} this setting alone is not sufficient to allow +debugging @code{cfront}-generated executables. @value{GDBN} would +require further enhancement to permit that. +@end table + +@item show demangle-style +@kindex show demangle-style +Display the encoding style currently in use for decoding C++ symbols. + +@item set print object +@itemx set print object on +@kindex set print object +When displaying a pointer to an object, identify the @emph{actual} +(derived) type of the object rather than the @emph{declared} type, using +the virtual function table. + +@item set print object off +Display only the declared type of objects, without reference to the +virtual function table. This is the default setting. + +@item show print object +@kindex show print object +Show whether actual, or declared, object types will be displayed. + +@item set print vtbl +@itemx set print vtbl on +@kindex set print vtbl +Pretty print C++ virtual function tables. The default is off. + +@item set print vtbl off +Do not pretty print C++ virtual function tables. + +@item show print vtbl +@kindex show print vtbl +Show whether C++ virtual function tables are pretty printed, or not. +@end table +@end ifclear + +@node Value History +@section Value history + +@cindex value history +Values printed by the @code{print} command are saved in the @value{GDBN} @dfn{value +history} so that you can refer to them in other expressions. Values are +kept until the symbol table is re-read or discarded (for example with +the @code{file} or @code{symbol-file} commands). When the symbol table +changes, the value history is discarded, since the values may contain +pointers back to the types defined in the symbol table. + +@cindex @code{$} +@cindex @code{$$} +@cindex history number +The values printed are given @dfn{history numbers} by which you can +refer to them. These are successive integers starting with one. +@code{print} shows you the history number assigned to a value by +printing @samp{$@var{num} = } before the value; here @var{num} is the +history number. + +To refer to any previous value, use @samp{$} followed by the value's +history number. The way @code{print} labels its output is designed to +remind you of this. Just @code{$} refers to the most recent value in +the history, and @code{$$} refers to the value before that. +@code{$$@var{n}} refers to the @var{n}th value from the end; @code{$$2} +is the value just prior to @code{$$}, @code{$$1} is equivalent to +@code{$$}, and @code{$$0} is equivalent to @code{$}. + +For example, suppose you have just printed a pointer to a structure and +want to see the contents of the structure. It suffices to type + +@example +p *$ +@end example + +If you have a chain of structures where the component @code{next} points +to the next one, you can print the contents of the next one with this: + +@example +p *$.next +@end example + +@noindent +You can print successive links in the chain by repeating this +command---which you can do by just typing @key{RET}. + +Note that the history records values, not expressions. If the value of +@code{x} is 4 and you type these commands: + +@example +print x +set x=5 +@end example + +@noindent +then the value recorded in the value history by the @code{print} command +remains 4 even though the value of @code{x} has changed. + +@table @code +@kindex show values +@item show values +Print the last ten values in the value history, with their item numbers. +This is like @samp{p@ $$9} repeated ten times, except that @code{show +values} does not change the history. + +@item show values @var{n} +Print ten history values centered on history item number @var{n}. + +@item show values + +Print ten history values just after the values last printed. If no more +values are available, produces no display. +@end table + +Pressing @key{RET} to repeat @code{show values @var{n}} has exactly the +same effect as @samp{show values +}. + +@node Convenience Vars +@section Convenience variables + +@cindex convenience variables +@value{GDBN} provides @dfn{convenience variables} that you can use within +@value{GDBN} to hold on to a value and refer to it later. These variables +exist entirely within @value{GDBN}; they are not part of your program, and +setting a convenience variable has no direct effect on further execution +of your program. That is why you can use them freely. + +Convenience variables are prefixed with @samp{$}. Any name preceded by +@samp{$} can be used for a convenience variable, unless it is one of +the predefined machine-specific register names (@pxref{Registers}). +(Value history references, in contrast, are @emph{numbers} preceded +by @samp{$}. @xref{Value History, ,Value history}.) + +You can save a value in a convenience variable with an assignment +expression, just as you would set a variable in your program. +For example: + +@example +set $foo = *object_ptr +@end example + +@noindent +would save in @code{$foo} the value contained in the object pointed to by +@code{object_ptr}. + +Using a convenience variable for the first time creates it, but its +value is @code{void} until you assign a new value. You can alter the +value with another assignment at any time. + +Convenience variables have no fixed types. You can assign a convenience +variable any type of value, including structures and arrays, even if +that variable already has a value of a different type. The convenience +variable, when used as an expression, has the type of its current value. + +@table @code +@item show convenience +@kindex show convenience +Print a list of convenience variables used so far, and their values. +Abbreviated @code{show con}. +@end table + +One of the ways to use a convenience variable is as a counter to be +incremented or a pointer to be advanced. For example, to print +a field from successive elements of an array of structures: + +@example +set $i = 0 +print bar[$i++]->contents +@i{@dots{} repeat that command by typing @key{RET}.} +@end example + +Some convenience variables are created automatically by @value{GDBN} and given +values likely to be useful. + +@table @code +@item $_ +@kindex $_ +The variable @code{$_} is automatically set by the @code{x} command to +the last address examined (@pxref{Memory, ,Examining memory}). Other +commands which provide a default address for @code{x} to examine also +set @code{$_} to that address; these commands include @code{info line} +and @code{info breakpoint}. The type of @code{$_} is @code{void *} +except when set by the @code{x} command, in which case it is a pointer +to the type of @code{$__}. + +@item $__ +@kindex $__ +The variable @code{$__} is automatically set by the @code{x} command +to the value found in the last address examined. Its type is chosen +to match the format in which the data was printed. +@end table + +@node Registers +@section Registers + +@cindex registers +You can refer to machine register contents, in expressions, as variables +with names starting with @samp{$}. The names of registers are different +for each machine; use @code{info registers} to see the names used on +your machine. + +@table @code +@item info registers +@kindex info registers +Print the names and values of all registers except floating-point +registers (in the selected stack frame). + +@item info all-registers +@kindex info all-registers +@cindex floating point registers +Print the names and values of all registers, including floating-point +registers. + +@item info registers @var{regname} @dots{} +Print the relativized value of each specified register @var{regname}. +@var{regname} may be any register name valid on the machine you are using, with +or without the initial @samp{$}. +@end table + +@value{GDBN} has four ``standard'' register names that are available (in +expressions) on most machines---whenever they do not conflict with an +architecture's canonical mnemonics for registers. The register names +@code{$pc} and @code{$sp} are used for the program counter register and +the stack pointer. @code{$fp} is used for a register that contains a +pointer to the current stack frame, and @code{$ps} is used for a +register that contains the processor status. For example, +you could print the program counter in hex with + +@example +p/x $pc +@end example + +@noindent +or print the instruction to be executed next with + +@example +x/i $pc +@end example + +@noindent +or add four to the stack pointer@footnote{This is a way of removing +one word from the stack, on machines where stacks grow downward in +memory (most machines, nowadays). This assumes that the innermost +stack frame is selected; setting @code{$sp} is not allowed when other +stack frames are selected. To pop entire frames off the stack, +regardless of machine architecture, use @code{return}; +@pxref{Returning, ,Returning from a function}.} with + +@example +set $sp += 4 +@end example + +Whenever possible, these four standard register names are available on +your machine even though the machine has different canonical mnemonics, +so long as there is no conflict. The @code{info registers} command +shows the canonical names. For example, on the SPARC, @code{info +registers} displays the processor status register as @code{$psr} but you +can also refer to it as @code{$ps}. + +@value{GDBN} always considers the contents of an ordinary register as an +integer when the register is examined in this way. Some machines have +special registers which can hold nothing but floating point; these +registers are considered to have floating point values. There is no way +to refer to the contents of an ordinary register as floating point value +(although you can @emph{print} it as a floating point value with +@samp{print/f $@var{regname}}). + +Some registers have distinct ``raw'' and ``virtual'' data formats. This +means that the data format in which the register contents are saved by +the operating system is not the same one that your program normally +sees. For example, the registers of the 68881 floating point +coprocessor are always saved in ``extended'' (raw) format, but all C +programs expect to work with ``double'' (virtual) format. In such +cases, @value{GDBN} normally works with the virtual format only (the format that +makes sense for your program), but the @code{info registers} command +prints the data in both formats. + +Normally, register values are relative to the selected stack frame +(@pxref{Selection, ,Selecting a frame}). This means that you get the +value that the register would contain if all stack frames farther in +were exited and their saved registers restored. In order to see the +true contents of hardware registers, you must select the innermost +frame (with @samp{frame 0}). + +However, @value{GDBN} must deduce where registers are saved, from the machine +code generated by your compiler. If some registers are not saved, or if +@value{GDBN} is unable to locate the saved registers, the selected stack +frame will make no difference. + +@ifset AMD29K +@table @code +@item set rstack_high_address @var{address} +@kindex set rstack_high_address +@cindex AMD 29K register stack +@cindex register stack, AMD29K +On AMD 29000 family processors, registers are saved in a separate +``register stack''. There is no way for @value{GDBN} to determine the extent +of this stack. Normally, @value{GDBN} just assumes that the stack is ``large +enough''. This may result in @value{GDBN} referencing memory locations that +do not exist. If necessary, you can get around this problem by +specifying the ending address of the register stack with the @code{set +rstack_high_address} command. The argument should be an address, which +you will probably want to precede with @samp{0x} to specify in +hexadecimal. + +@item show rstack_high_address +@kindex show rstack_high_address +Display the current limit of the register stack, on AMD 29000 family +processors. +@end table +@end ifset + +@ifclear HAVE-FLOAT +@node Floating Point Hardware +@section Floating point hardware +@cindex floating point + +@c FIXME! Really host, not target? +Depending on the host machine architecture, @value{GDBN} may be able to give +you more information about the status of the floating point hardware. + +@table @code +@item info float +@kindex info float +Display hardware-dependent information about the floating +point unit. The exact contents and layout vary depending on the +floating point chip; on some platforms, @samp{info float} is not +available at all. +@end table +@c FIXME: this is a cop-out. Try to get examples, explanations. Only +@c FIXME...supported currently on arm's and 386's. Mark properly with +@c FIXME... m4 macros to isolate general statements from hardware-dep, +@c FIXME... at that point. +@end ifclear + +@ifclear CONLY +@node Languages +@chapter Using @value{GDBN} with Different Languages +@cindex languages + +@ifset MOD2 +Although programming languages generally have common aspects, they are +rarely expressed in the same manner. For instance, in ANSI C, +dereferencing a pointer @code{p} is accomplished by @code{*p}, but in +Modula-2, it is accomplished by @code{p^}. Values can also be +represented (and displayed) differently. Hex numbers in C are written +like @samp{0x1ae}, while in Modula-2 they appear as @samp{1AEH}. +@end ifset + +@cindex working language +Language-specific information is built into @value{GDBN} for some languages, +allowing you to express operations like the above in your program's +native language, and allowing @value{GDBN} to output values in a manner +consistent with the syntax of your program's native language. The +language you use to build expressions, called the @dfn{working +language}, can be selected manually, or @value{GDBN} can set it +automatically. + +@menu +* Setting:: Switching between source languages +* Show:: Displaying the language +@ifset MOD2 +* Checks:: Type and range checks +@end ifset + +* Support:: Supported languages +@end menu + +@node Setting +@section Switching between source languages + +There are two ways to control the working language---either have @value{GDBN} +set it automatically, or select it manually yourself. You can use the +@code{set language} command for either purpose. On startup, @value{GDBN} +defaults to setting the language automatically. + +@menu +* Manually:: Setting the working language manually +* Automatically:: Having @value{GDBN} infer the source language +@end menu + +@node Manually +@subsection Setting the working language + +If you allow @value{GDBN} to set the language automatically, +expressions are interpreted the same way in your debugging session and +your program. + +@kindex set language +If you wish, you may set the language manually. To do this, issue the +command @samp{set language @var{lang}}, where @var{lang} is the name of +a language, such as +@ifclear MOD2 +@code{c}. +@end ifclear +@ifset MOD2 +@code{c} or @code{modula-2}. +@end ifset +For a list of the supported languages, type @samp{set language}. +@c FIXME: rms: eventually this command should be "help set language". + +@ifset MOD2 +Setting the language manually prevents @value{GDBN} from updating the working +language automatically. This can lead to confusion if you try +to debug a program when the working language is not the same as the +source language, when an expression is acceptable to both +languages---but means different things. For instance, if the current +source file were written in C, and @value{GDBN} was parsing Modula-2, a +command such as: + +@example +print a = b + c +@end example + +@noindent +might not have the effect you intended. In C, this means to add +@code{b} and @code{c} and place the result in @code{a}. The result +printed would be the value of @code{a}. In Modula-2, this means to compare +@code{a} to the result of @code{b+c}, yielding a @code{BOOLEAN} value. +@end ifset + +@node Automatically +@subsection Having @value{GDBN} infer the source language + +To have @value{GDBN} set the working language automatically, use @samp{set +language local} or @samp{set language auto}. @value{GDBN} then infers the +language that a program was written in by looking at the name of its +source files, and examining their extensions: + +@table @file +@ifset MOD2 +@item *.mod +Modula-2 source file +@end ifset + +@item *.c +C source file + +@item *.C +@itemx *.cc +C++ source file +@end table + +This information is recorded for each function or procedure in a source +file. When your program stops in a frame (usually by encountering a +breakpoint), @value{GDBN} sets the working language to the language recorded +for the function in that frame. If the language for a frame is unknown +(that is, if the function or block corresponding to the frame was +defined in a source file that does not have a recognized extension), the +current working language is not changed, and @value{GDBN} issues a warning. + +This may not seem necessary for most programs, which are written +entirely in one source language. However, program modules and libraries +written in one source language can be used by a main program written in +a different source language. Using @samp{set language auto} in this +case frees you from having to set the working language manually. + +@node Show +@section Displaying the language + +The following commands will help you find out which language is the +working language, and also what language source files were written in. + +@kindex show language +@kindex info frame +@kindex info source +@table @code +@item show language +Display the current working language. This is the +language you can use with commands such as @code{print} to +build and compute expressions that may involve variables in your program. + +@item info frame +Among the other information listed here (@pxref{Frame Info, ,Information +about a frame}) is the source language for this frame. This is the +language that will become the working language if you ever use an +identifier that is in this frame. + +@item info source +Among the other information listed here (@pxref{Symbols, ,Examining the +Symbol Table}) is the source language of this source file. +@end table + +@ifset MOD2 +@node Checks +@section Type and range checking + +@quotation +@emph{Warning:} In this release, the @value{GDBN} commands for type and range +checking are included, but they do not yet have any effect. This +section documents the intended facilities. +@end quotation +@c FIXME remove warning when type/range code added + +Some languages are designed to guard you against making seemingly common +errors through a series of compile- and run-time checks. These include +checking the type of arguments to functions and operators, and making +sure mathematical overflows are caught at run time. Checks such as +these help to ensure a program's correctness once it has been compiled +by eliminating type mismatches, and providing active checks for range +errors when your program is running. + +@value{GDBN} can check for conditions like the above if you wish. +Although @value{GDBN} will not check the statements in your program, it +can check expressions entered directly into @value{GDBN} for evaluation via +the @code{print} command, for example. As with the working language, +@value{GDBN} can also decide whether or not to check automatically based on +your program's source language. @xref{Support, ,Supported languages}, +for the default settings of supported languages. + +@menu +* Type Checking:: An overview of type checking +* Range Checking:: An overview of range checking +@end menu + +@cindex type checking +@cindex checks, type +@node Type Checking +@subsection An overview of type checking + +Some languages, such as Modula-2, are strongly typed, meaning that the +arguments to operators and functions have to be of the correct type, +otherwise an error occurs. These checks prevent type mismatch +errors from ever causing any run-time problems. For example, + +@example +1 + 2 @result{} 3 +@exdent but +@error{} 1 + 2.3 +@end example + +The second example fails because the @code{CARDINAL} 1 is not +type-compatible with the @code{REAL} 2.3. + +For expressions you use in @value{GDBN} commands, you can tell the @value{GDBN} +type checker to skip checking; to treat any mismatches as errors and +abandon the expression; or only issue warnings when type mismatches +occur, but evaluate the expression anyway. When you choose the last of +these, @value{GDBN} evaluates expressions like the second example above, but +also issues a warning. + +Even though you may turn type checking off, other type-based reasons may +prevent @value{GDBN} from evaluating an expression. For instance, @value{GDBN} does not +know how to add an @code{int} and a @code{struct foo}. These particular +type errors have nothing to do with the language in use, and usually +arise from expressions, such as the one described above, which make +little sense to evaluate anyway. + +Each language defines to what degree it is strict about type. For +instance, both Modula-2 and C require the arguments to arithmetical +operators to be numbers. In C, enumerated types and pointers can be +represented as numbers, so that they are valid arguments to mathematical +operators. @xref{Support, ,Supported languages}, for further +details on specific languages. + +@value{GDBN} provides some additional commands for controlling the type checker: + +@kindex set check +@kindex set check type +@kindex show check type +@table @code +@item set check type auto +Set type checking on or off based on the current working language. +@xref{Support, ,Supported languages}, for the default settings for +each language. + +@item set check type on +@itemx set check type off +Set type checking on or off, overriding the default setting for the +current working language. Issue a warning if the setting does not +match the language default. If any type mismatches occur in +evaluating an expression while typechecking is on, @value{GDBN} prints a +message and aborts evaluation of the expression. + +@item set check type warn +Cause the type checker to issue warnings, but to always attempt to +evaluate the expression. Evaluating the expression may still +be impossible for other reasons. For example, @value{GDBN} cannot add +numbers and structures. + +@item show type +Show the current setting of the type checker, and whether or not @value{GDBN} is +setting it automatically. +@end table + +@cindex range checking +@cindex checks, range +@node Range Checking +@subsection An overview of range checking + +In some languages (such as Modula-2), it is an error to exceed the +bounds of a type; this is enforced with run-time checks. Such range +checking is meant to ensure program correctness by making sure +computations do not overflow, or indices on an array element access do +not exceed the bounds of the array. + +For expressions you use in @value{GDBN} commands, you can tell +@value{GDBN} to treat range errors in one of three ways: ignore them, +always treat them as errors and abandon the expression, or issue +warnings but evaluate the expression anyway. + +A range error can result from numerical overflow, from exceeding an +array index bound, or when you type a constant that is not a member +of any type. Some languages, however, do not treat overflows as an +error. In many implementations of C, mathematical overflow causes the +result to ``wrap around'' to lower values---for example, if @var{m} is +the largest integer value, and @var{s} is the smallest, then + +@example +@var{m} + 1 @result{} @var{s} +@end example + +This, too, is specific to individual languages, and in some cases +specific to individual compilers or machines. @xref{Support, , +Supported languages}, for further details on specific languages. + +@value{GDBN} provides some additional commands for controlling the range checker: + +@kindex set check +@kindex set check range +@kindex show check range +@table @code +@item set check range auto +Set range checking on or off based on the current working language. +@xref{Support, ,Supported languages}, for the default settings for +each language. + +@item set check range on +@itemx set check range off +Set range checking on or off, overriding the default setting for the +current working language. A warning is issued if the setting does not +match the language default. If a range error occurs, then a message +is printed and evaluation of the expression is aborted. + +@item set check range warn +Output messages when the @value{GDBN} range checker detects a range error, +but attempt to evaluate the expression anyway. Evaluating the +expression may still be impossible for other reasons, such as accessing +memory that the process does not own (a typical example from many Unix +systems). + +@item show range +Show the current setting of the range checker, and whether or not it is +being set automatically by @value{GDBN}. +@end table +@end ifset + +@node Support +@section Supported languages + +@ifset MOD2 +@value{GDBN} 4 supports C, C++, and Modula-2. +@end ifset +@ifclear MOD2 +@value{GDBN} 4 supports C, and C++. +@end ifclear +Some @value{GDBN} features may be used in expressions regardless of the +language you use: the @value{GDBN} @code{@@} and @code{::} operators, +and the @samp{@{type@}addr} construct (@pxref{Expressions, +,Expressions}) can be used with the constructs of any supported +language. + +The following sections detail to what degree each source language is +supported by @value{GDBN}. These sections are not meant to be language +tutorials or references, but serve only as a reference guide to what the +@value{GDBN} expression parser will accept, and what input and output +formats should look like for different languages. There are many good +books written on each of these languages; please look to these for a +language reference or tutorial. + +@ifset MOD2 +@menu +* C:: C and C++ +* Modula-2:: Modula-2 +@end menu + +@node C +@subsection C and C++ +@cindex C and C++ +@cindex expressions in C or C++ + +Since C and C++ are so closely related, many features of @value{GDBN} apply +to both languages. Whenever this is the case, we discuss both languages +together. +@end ifset +@ifclear MOD2 +@c Cancel this below, under same condition, at end of this chapter! +@raisesections +@end ifclear + +@cindex C++ +@kindex g++ +@cindex GNU C++ +The C++ debugging facilities are jointly implemented by the GNU C++ +compiler and @value{GDBN}. Therefore, to debug your C++ code effectively, +you must compile your C++ programs with the GNU C++ compiler, +@code{g++}. +@end ifclear +@ifset CONLY +@node C +@chapter C Language Support +@cindex C language +@cindex expressions in C + +Information specific to the C language is built into @value{GDBN} so that you +can use C expressions while degugging. This also permits @value{GDBN} to +output values in a manner consistent with C conventions. + +@menu +* C Operators:: C operators +* C Constants:: C constants +* Debugging C:: @value{GDBN} and C +@end menu +@end ifset +@ifclear CONLY +@menu +* C Operators:: C and C++ operators +* C Constants:: C and C++ constants +* Cplus expressions:: C++ expressions +* C Defaults:: Default settings for C and C++ +@ifset MOD2 +* C Checks:: C and C++ type and range checks +@end ifset + +* Debugging C:: @value{GDBN} and C +* Debugging C plus plus:: Special features for C++ +@end menu +@end ifclear + +@ifclear CONLY +@cindex C and C++ operators +@node C Operators +@subsubsection C and C++ operators +@end ifclear +@ifset CONLY +@cindex C operators +@node C Operators +@section C operators +@end ifset + +Operators must be defined on values of specific types. For instance, +@code{+} is defined on numbers, but not on structures. Operators are +often defined on groups of types. + +@ifclear CONLY +For the purposes of C and C++, the following definitions hold: +@end ifclear + +@itemize @bullet +@item +@emph{Integral types} include @code{int} with any of its storage-class +specifiers; @code{char}; and @code{enum}. + +@item +@emph{Floating-point types} include @code{float} and @code{double}. + +@item +@emph{Pointer types} include all types defined as @code{(@var{type} +*)}. + +@item +@emph{Scalar types} include all of the above. +@end itemize + +@noindent +The following operators are supported. They are listed here +in order of increasing precedence: + +@table @code +@item , +The comma or sequencing operator. Expressions in a comma-separated list +are evaluated from left to right, with the result of the entire +expression being the last expression evaluated. + +@item = +Assignment. The value of an assignment expression is the value +assigned. Defined on scalar types. + +@item @var{op}= +Used in an expression of the form @w{@code{@var{a} @var{op}= @var{b}}}, +and translated to @w{@code{@var{a} = @var{a op b}}}. +@w{@code{@var{op}=}} and @code{=} have the same precendence. +@var{op} is any one of the operators @code{|}, @code{^}, @code{&}, +@code{<<}, @code{>>}, @code{+}, @code{-}, @code{*}, @code{/}, @code{%}. + +@item ?: +The ternary operator. @code{@var{a} ? @var{b} : @var{c}} can be thought +of as: if @var{a} then @var{b} else @var{c}. @var{a} should be of an +integral type. + +@item || +Logical @sc{or}. Defined on integral types. + +@item && +Logical @sc{and}. Defined on integral types. + +@item | +Bitwise @sc{or}. Defined on integral types. + +@item ^ +Bitwise exclusive-@sc{or}. Defined on integral types. + +@item & +Bitwise @sc{and}. Defined on integral types. + +@item ==@r{, }!= +Equality and inequality. Defined on scalar types. The value of these +expressions is 0 for false and non-zero for true. + +@item <@r{, }>@r{, }<=@r{, }>= +Less than, greater than, less than or equal, greater than or equal. +Defined on scalar types. The value of these expressions is 0 for false +and non-zero for true. + +@item <<@r{, }>> +left shift, and right shift. Defined on integral types. + +@item @@ +The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}). + +@item +@r{, }- +Addition and subtraction. Defined on integral types, floating-point types and +pointer types. + +@item *@r{, }/@r{, }% +Multiplication, division, and modulus. Multiplication and division are +defined on integral and floating-point types. Modulus is defined on +integral types. + +@item ++@r{, }-- +Increment and decrement. When appearing before a variable, the +operation is performed before the variable is used in an expression; +when appearing after it, the variable's value is used before the +operation takes place. + +@item * +Pointer dereferencing. Defined on pointer types. Same precedence as +@code{++}. + +@item & +Address operator. Defined on variables. Same precedence as @code{++}. + +@ifclear CONLY +For debugging C++, @value{GDBN} implements a use of @samp{&} beyond what is +allowed in the C++ language itself: you can use @samp{&(&@var{ref})} +(or, if you prefer, simply @samp{&&@var{ref}}) to examine the address +where a C++ reference variable (declared with @samp{&@var{ref}}) is +stored. +@end ifclear + +@item - +Negative. Defined on integral and floating-point types. Same +precedence as @code{++}. + +@item ! +Logical negation. Defined on integral types. Same precedence as +@code{++}. + +@item ~ +Bitwise complement operator. Defined on integral types. Same precedence as +@code{++}. + + +@item .@r{, }-> +Structure member, and pointer-to-structure member. For convenience, +@value{GDBN} regards the two as equivalent, choosing whether to dereference a +pointer based on the stored type information. +Defined on @code{struct} and @code{union} data. + +@item [] +Array indexing. @code{@var{a}[@var{i}]} is defined as +@code{*(@var{a}+@var{i})}. Same precedence as @code{->}. + +@item () +Function parameter list. Same precedence as @code{->}. + +@ifclear CONLY +@item :: +C++ scope resolution operator. Defined on +@code{struct}, @code{union}, and @code{class} types. +@end ifclear + +@item :: +Doubled colons +@ifclear CONLY +also +@end ifclear +represent the @value{GDBN} scope operator (@pxref{Expressions, +,Expressions}). +@ifclear CONLY +Same precedence as @code{::}, above. +@end ifclear +@end table + +@ifclear CONLY +@cindex C and C++ constants +@node C Constants +@subsubsection C and C++ constants + +@value{GDBN} allows you to express the constants of C and C++ in the +following ways: +@end ifclear +@ifset CONLY +@cindex C constants +@node C Constants +@section C constants + +@value{GDBN} allows you to express the constants of C in the +following ways: +@end ifset + +@itemize @bullet +@item +Integer constants are a sequence of digits. Octal constants are +specified by a leading @samp{0} (ie. zero), and hexadecimal constants by +a leading @samp{0x} or @samp{0X}. Constants may also end with a letter +@samp{l}, specifying that the constant should be treated as a +@code{long} value. + +@item +Floating point constants are a sequence of digits, followed by a decimal +point, followed by a sequence of digits, and optionally followed by an +exponent. An exponent is of the form: +@samp{@w{e@r{[[}+@r{]|}-@r{]}@var{nnn}}}, where @var{nnn} is another +sequence of digits. The @samp{+} is optional for positive exponents. + +@item +Enumerated constants consist of enumerated identifiers, or their +integral equivalents. + +@item +Character constants are a single character surrounded by single quotes +(@code{'}), or a number---the ordinal value of the corresponding character +(usually its @sc{ASCII} value). Within quotes, the single character may +be represented by a letter or by @dfn{escape sequences}, which are of +the form @samp{\@var{nnn}}, where @var{nnn} is the octal representation +of the character's ordinal value; or of the form @samp{\@var{x}}, where +@samp{@var{x}} is a predefined special character---for example, +@samp{\n} for newline. + +@item +String constants are a sequence of character constants surrounded +by double quotes (@code{"}). + +@item +Pointer constants are an integral value. You can also write pointers +to constants using the C operator @samp{&}. + +@item +Array constants are comma-separated lists surrounded by braces @samp{@{} +and @samp{@}}; for example, @samp{@{1,2,3@}} is a three-element array of +integers, @samp{@{@{1,2@}, @{3,4@}, @{5,6@}@}} is a three-by-two array, +and @samp{@{&"hi", &"there", &"fred"@}} is a three-element array of pointers. +@end itemize + +@ifclear CONLY +@node Cplus expressions +@subsubsection C++ expressions + +@cindex expressions in C++ +@value{GDBN} expression handling has a number of extensions to +interpret a significant subset of C++ expressions. + +@cindex C++ support, not in @sc{coff} +@cindex @sc{coff} versus C++ +@cindex C++ and object formats +@cindex object formats and C++ +@cindex a.out and C++ +@cindex @sc{ecoff} and C++ +@cindex @sc{xcoff} and C++ +@cindex @sc{elf}/stabs and C++ +@cindex @sc{elf}/@sc{dwarf} and C++ +@quotation +@emph{Warning:} Most of these extensions depend on the use of additional +debugging information in the symbol table, and thus require a rich, +extendable object code format. In particular, if your system uses +a.out, MIPS @sc{ecoff}, RS/6000 @sc{xcoff}, or Sun @sc{elf} with stabs +extensions to the symbol table, these facilities are all available. +Where the object code format is standard @sc{coff}, on the other hand, +most of the C++ support in @value{GDBN} will @emph{not} work, nor can it. +For the standard SVr4 debugging format, @sc{dwarf} in @sc{elf}, the +standard is still evolving, so the C++ support in @value{GDBN} is still +fragile; when this debugging format stabilizes, however, C++ support +will also be available on systems that use it. +@end quotation + +@enumerate + +@cindex member functions +@item +Member function calls are allowed; you can use expressions like + +@example +count = aml->GetOriginal(x, y) +@end example + +@kindex this +@cindex namespace in C++ +@item +While a member function is active (in the selected stack frame), your +expressions have the same namespace available as the member function; +that is, @value{GDBN} allows implicit references to the class instance +pointer @code{this} following the same rules as C++. + +@cindex call overloaded functions +@cindex type conversions in C++ +@item +You can call overloaded functions; @value{GDBN} will resolve the function +call to the right definition, with one restriction---you must use +arguments of the type required by the function that you want to call. +@value{GDBN} will not perform conversions requiring constructors or +user-defined type operators. + +@cindex reference declarations +@item +@value{GDBN} understands variables declared as C++ references; you can use them in +expressions just as you do in C++ source---they are automatically +dereferenced. + +In the parameter list shown when @value{GDBN} displays a frame, the values of +reference variables are not displayed (unlike other variables); this +avoids clutter, since references are often used for large structures. +The @emph{address} of a reference variable is always shown, unless +you have specified @samp{set print address off}. + +@item +@value{GDBN} supports the C++ name resolution operator @code{::}---your +expressions can use it just as expressions in your program do. Since +one scope may be defined in another, you can use @code{::} repeatedly if +necessary, for example in an expression like +@samp{@var{scope1}::@var{scope2}::@var{name}}. @value{GDBN} also allows +resolving name scope by reference to source files, in both C and C++ +debugging (@pxref{Variables, ,Program variables}). +@end enumerate + +@node C Defaults +@subsubsection C and C++ defaults +@cindex C and C++ defaults + +If you allow @value{GDBN} to set type and range checking automatically, they +both default to @code{off} whenever the working language changes to +C or C++. This happens regardless of whether you, or @value{GDBN}, +selected the working language. + +If you allow @value{GDBN} to set the language automatically, it sets the +working language to C or C++ on entering code compiled from a source file +whose name ends with @file{.c}, @file{.C}, or @file{.cc}. +@xref{Automatically, ,Having @value{GDBN} infer the source language}, for +further details. + +@ifset MOD2 +@c Type checking is (a) primarily motivated by Modula-2, and (b) +@c unimplemented. If (b) changes, it might make sense to let this node +@c appear even if Mod-2 does not, but meanwhile ignore it. pesch 16jul93. +@node C Checks +@subsubsection C and C++ type and range checks +@cindex C and C++ checks + +By default, when @value{GDBN} parses C or C++ expressions, type checking +is not used. However, if you turn type checking on, @value{GDBN} will +consider two variables type equivalent if: + +@itemize @bullet +@item +The two variables are structured and have the same structure, union, or +enumerated tag. + +@item +Two two variables have the same type name, or types that have been +declared equivalent through @code{typedef}. + +@ignore +@c leaving this out because neither J Gilmore nor R Pesch understand it. +@c FIXME--beers? +@item +The two @code{struct}, @code{union}, or @code{enum} variables are +declared in the same declaration. (Note: this may not be true for all C +compilers.) +@end ignore +@end itemize + +Range checking, if turned on, is done on mathematical operations. Array +indices are not checked, since they are often used to index a pointer +that is not itself an array. +@end ifset +@end ifclear + +@ifclear CONLY +@node Debugging C +@subsubsection @value{GDBN} and C +@end ifclear +@ifset CONLY +@node Debugging C +@section @value{GDBN} and C +@end ifset + +The @code{set print union} and @code{show print union} commands apply to +the @code{union} type. When set to @samp{on}, any @code{union} that is +inside a @code{struct} +@ifclear CONLY +or @code{class} +@end ifclear +will also be printed. +Otherwise, it will appear as @samp{@{...@}}. + +The @code{@@} operator aids in the debugging of dynamic arrays, formed +with pointers and a memory allocation function. @xref{Expressions, +,Expressions}. + +@ifclear CONLY +@node Debugging C plus plus +@subsubsection @value{GDBN} features for C++ + +@cindex commands for C++ +Some @value{GDBN} commands are particularly useful with C++, and some are +designed specifically for use with C++. Here is a summary: + +@table @code +@cindex break in overloaded functions +@item @r{breakpoint menus} +When you want a breakpoint in a function whose name is overloaded, +@value{GDBN} breakpoint menus help you specify which function definition +you want. @xref{Breakpoint Menus,,Breakpoint menus}. + +@cindex overloading in C++ +@item rbreak @var{regex} +Setting breakpoints using regular expressions is helpful for setting +breakpoints on overloaded functions that are not members of any special +classes. +@xref{Set Breaks, ,Setting breakpoints}. + +@cindex C++ exception handling +@item catch @var{exceptions} +@itemx info catch +Debug C++ exception handling using these commands. @xref{Exception +Handling, ,Breakpoints and exceptions}. + +@cindex inheritance +@item ptype @var{typename} +Print inheritance relationships as well as other information for type +@var{typename}. +@xref{Symbols, ,Examining the Symbol Table}. + +@cindex C++ symbol display +@item set print demangle +@itemx show print demangle +@itemx set print asm-demangle +@itemx show print asm-demangle +Control whether C++ symbols display in their source form, both when +displaying code as C++ source and when displaying disassemblies. +@xref{Print Settings, ,Print settings}. + +@item set print object +@itemx show print object +Choose whether to print derived (actual) or declared types of objects. +@xref{Print Settings, ,Print settings}. + +@item set print vtbl +@itemx show print vtbl +Control the format for printing virtual function tables. +@xref{Print Settings, ,Print settings}. + +@item @r{Overloaded symbol names} +You can specify a particular definition of an overloaded symbol, using +the same notation that is used to declare such symbols in C++: type +@code{@var{symbol}(@var{types})} rather than just @var{symbol}. You can +also use the @value{GDBN} command-line word completion facilities to list the +available choices, or to finish the type list for you. +@xref{Completion,, Command completion}, for details on how to do this. +@end table +@ifclear MOD2 +@c cancels "raisesections" under same conditions near bgn of chapter +@lowersections +@end ifclear + +@ifset MOD2 +@node Modula-2 +@subsection Modula-2 +@cindex Modula-2 + +The extensions made to @value{GDBN} to support Modula-2 only support +output from the GNU Modula-2 compiler (which is currently being +developed). Other Modula-2 compilers are not currently supported, and +attempting to debug executables produced by them will most likely +result in an error as @value{GDBN} reads in the executable's symbol +table. + +@cindex expressions in Modula-2 +@menu +* M2 Operators:: Built-in operators +* Built-In Func/Proc:: Built-in functions and procedures +* M2 Constants:: Modula-2 constants +* M2 Defaults:: Default settings for Modula-2 +* Deviations:: Deviations from standard Modula-2 +* M2 Checks:: Modula-2 type and range checks +* M2 Scope:: The scope operators @code{::} and @code{.} +* GDB/M2:: @value{GDBN} and Modula-2 +@end menu + +@node M2 Operators +@subsubsection Operators +@cindex Modula-2 operators + +Operators must be defined on values of specific types. For instance, +@code{+} is defined on numbers, but not on structures. Operators are +often defined on groups of types. For the purposes of Modula-2, the +following definitions hold: + +@itemize @bullet + +@item +@emph{Integral types} consist of @code{INTEGER}, @code{CARDINAL}, and +their subranges. + +@item +@emph{Character types} consist of @code{CHAR} and its subranges. + +@item +@emph{Floating-point types} consist of @code{REAL}. + +@item +@emph{Pointer types} consist of anything declared as @code{POINTER TO +@var{type}}. + +@item +@emph{Scalar types} consist of all of the above. + +@item +@emph{Set types} consist of @code{SET} and @code{BITSET} types. + +@item +@emph{Boolean types} consist of @code{BOOLEAN}. +@end itemize + +@noindent +The following operators are supported, and appear in order of +increasing precedence: + +@table @code +@item , +Function argument or array index separator. + +@item := +Assignment. The value of @var{var} @code{:=} @var{value} is +@var{value}. + +@item <@r{, }> +Less than, greater than on integral, floating-point, or enumerated +types. + +@item <=@r{, }>= +Less than, greater than, less than or equal to, greater than or equal to +on integral, floating-point and enumerated types, or set inclusion on +set types. Same precedence as @code{<}. + +@item =@r{, }<>@r{, }# +Equality and two ways of expressing inequality, valid on scalar types. +Same precedence as @code{<}. In @value{GDBN} scripts, only @code{<>} is +available for inequality, since @code{#} conflicts with the script +comment character. + +@item IN +Set membership. Defined on set types and the types of their members. +Same precedence as @code{<}. + +@item OR +Boolean disjunction. Defined on boolean types. + +@item AND@r{, }& +Boolean conjuction. Defined on boolean types. + +@item @@ +The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}). + +@item +@r{, }- +Addition and subtraction on integral and floating-point types, or union +and difference on set types. + +@item * +Multiplication on integral and floating-point types, or set intersection +on set types. + +@item / +Division on floating-point types, or symmetric set difference on set +types. Same precedence as @code{*}. + +@item DIV@r{, }MOD +Integer division and remainder. Defined on integral types. Same +precedence as @code{*}. + +@item - +Negative. Defined on @code{INTEGER} and @code{REAL} data. + +@item ^ +Pointer dereferencing. Defined on pointer types. + +@item NOT +Boolean negation. Defined on boolean types. Same precedence as +@code{^}. + +@item . +@code{RECORD} field selector. Defined on @code{RECORD} data. Same +precedence as @code{^}. + +@item [] +Array indexing. Defined on @code{ARRAY} data. Same precedence as @code{^}. + +@item () +Procedure argument list. Defined on @code{PROCEDURE} objects. Same precedence +as @code{^}. + +@item ::@r{, }. +@value{GDBN} and Modula-2 scope operators. +@end table + +@quotation +@emph{Warning:} Sets and their operations are not yet supported, so @value{GDBN} +will treat the use of the operator @code{IN}, or the use of operators +@code{+}, @code{-}, @code{*}, @code{/}, @code{=}, , @code{<>}, @code{#}, +@code{<=}, and @code{>=} on sets as an error. +@end quotation + +@cindex Modula-2 built-ins +@node Built-In Func/Proc +@subsubsection Built-in functions and procedures + +Modula-2 also makes available several built-in procedures and functions. +In describing these, the following metavariables are used: + +@table @var + +@item a +represents an @code{ARRAY} variable. + +@item c +represents a @code{CHAR} constant or variable. + +@item i +represents a variable or constant of integral type. + +@item m +represents an identifier that belongs to a set. Generally used in the +same function with the metavariable @var{s}. The type of @var{s} should +be @code{SET OF @var{mtype}} (where @var{mtype} is the type of @var{m}). + +@item n +represents a variable or constant of integral or floating-point type. + +@item r +represents a variable or constant of floating-point type. + +@item t +represents a type. + +@item v +represents a variable. + +@item x +represents a variable or constant of one of many types. See the +explanation of the function for details. +@end table + +All Modula-2 built-in procedures also return a result, described below. + +@table @code +@item ABS(@var{n}) +Returns the absolute value of @var{n}. + +@item CAP(@var{c}) +If @var{c} is a lower case letter, it returns its upper case +equivalent, otherwise it returns its argument + +@item CHR(@var{i}) +Returns the character whose ordinal value is @var{i}. + +@item DEC(@var{v}) +Decrements the value in the variable @var{v}. Returns the new value. + +@item DEC(@var{v},@var{i}) +Decrements the value in the variable @var{v} by @var{i}. Returns the +new value. + +@item EXCL(@var{m},@var{s}) +Removes the element @var{m} from the set @var{s}. Returns the new +set. + +@item FLOAT(@var{i}) +Returns the floating point equivalent of the integer @var{i}. + +@item HIGH(@var{a}) +Returns the index of the last member of @var{a}. + +@item INC(@var{v}) +Increments the value in the variable @var{v}. Returns the new value. + +@item INC(@var{v},@var{i}) +Increments the value in the variable @var{v} by @var{i}. Returns the +new value. + +@item INCL(@var{m},@var{s}) +Adds the element @var{m} to the set @var{s} if it is not already +there. Returns the new set. + +@item MAX(@var{t}) +Returns the maximum value of the type @var{t}. + +@item MIN(@var{t}) +Returns the minimum value of the type @var{t}. + +@item ODD(@var{i}) +Returns boolean TRUE if @var{i} is an odd number. + +@item ORD(@var{x}) +Returns the ordinal value of its argument. For example, the ordinal +value of a character is its ASCII value (on machines supporting the +ASCII character set). @var{x} must be of an ordered type, which include +integral, character and enumerated types. + +@item SIZE(@var{x}) +Returns the size of its argument. @var{x} can be a variable or a type. + +@item TRUNC(@var{r}) +Returns the integral part of @var{r}. + +@item VAL(@var{t},@var{i}) +Returns the member of the type @var{t} whose ordinal value is @var{i}. +@end table + +@quotation +@emph{Warning:} Sets and their operations are not yet supported, so +@value{GDBN} will treat the use of procedures @code{INCL} and @code{EXCL} as +an error. +@end quotation + +@cindex Modula-2 constants +@node M2 Constants +@subsubsection Constants + +@value{GDBN} allows you to express the constants of Modula-2 in the following +ways: + +@itemize @bullet + +@item +Integer constants are simply a sequence of digits. When used in an +expression, a constant is interpreted to be type-compatible with the +rest of the expression. Hexadecimal integers are specified by a +trailing @samp{H}, and octal integers by a trailing @samp{B}. + +@item +Floating point constants appear as a sequence of digits, followed by a +decimal point and another sequence of digits. An optional exponent can +then be specified, in the form @samp{E@r{[}+@r{|}-@r{]}@var{nnn}}, where +@samp{@r{[}+@r{|}-@r{]}@var{nnn}} is the desired exponent. All of the +digits of the floating point constant must be valid decimal (base 10) +digits. + +@item +Character constants consist of a single character enclosed by a pair of +like quotes, either single (@code{'}) or double (@code{"}). They may +also be expressed by their ordinal value (their ASCII value, usually) +followed by a @samp{C}. + +@item +String constants consist of a sequence of characters enclosed by a +pair of like quotes, either single (@code{'}) or double (@code{"}). +Escape sequences in the style of C are also allowed. @xref{C +Constants, ,C and C++ constants}, for a brief explanation of escape +sequences. + +@item +Enumerated constants consist of an enumerated identifier. + +@item +Boolean constants consist of the identifiers @code{TRUE} and +@code{FALSE}. + +@item +Pointer constants consist of integral values only. + +@item +Set constants are not yet supported. +@end itemize + +@node M2 Defaults +@subsubsection Modula-2 defaults +@cindex Modula-2 defaults + +If type and range checking are set automatically by @value{GDBN}, they +both default to @code{on} whenever the working language changes to +Modula-2. This happens regardless of whether you, or @value{GDBN}, +selected the working language. + +If you allow @value{GDBN} to set the language automatically, then entering +code compiled from a file whose name ends with @file{.mod} will set the +working language to Modula-2. @xref{Automatically, ,Having @value{GDBN} set +the language automatically}, for further details. + +@node Deviations +@subsubsection Deviations from standard Modula-2 +@cindex Modula-2, deviations from + +A few changes have been made to make Modula-2 programs easier to debug. +This is done primarily via loosening its type strictness: + +@itemize @bullet +@item +Unlike in standard Modula-2, pointer constants can be formed by +integers. This allows you to modify pointer variables during +debugging. (In standard Modula-2, the actual address contained in a +pointer variable is hidden from you; it can only be modified +through direct assignment to another pointer variable or expression that +returned a pointer.) + +@item +C escape sequences can be used in strings and characters to represent +non-printable characters. @value{GDBN} will print out strings with these +escape sequences embedded. Single non-printable characters are +printed using the @samp{CHR(@var{nnn})} format. + +@item +The assignment operator (@code{:=}) returns the value of its right-hand +argument. + +@item +All built-in procedures both modify @emph{and} return their argument. +@end itemize + +@node M2 Checks +@subsubsection Modula-2 type and range checks +@cindex Modula-2 checks + +@quotation +@emph{Warning:} in this release, @value{GDBN} does not yet perform type or +range checking. +@end quotation +@c FIXME remove warning when type/range checks added + +@value{GDBN} considers two Modula-2 variables type equivalent if: + +@itemize @bullet +@item +They are of types that have been declared equivalent via a @code{TYPE +@var{t1} = @var{t2}} statement + +@item +They have been declared on the same line. (Note: This is true of the +GNU Modula-2 compiler, but it may not be true of other compilers.) +@end itemize + +As long as type checking is enabled, any attempt to combine variables +whose types are not equivalent is an error. + +Range checking is done on all mathematical operations, assignment, array +index bounds, and all built-in functions and procedures. + +@node M2 Scope +@subsubsection The scope operators @code{::} and @code{.} +@cindex scope +@kindex . +@cindex colon, doubled as scope operator +@ifinfo +@kindex colon-colon +@c Info cannot handle :: but TeX can. +@end ifinfo +@iftex +@kindex :: +@end iftex + +There are a few subtle differences between the Modula-2 scope operator +(@code{.}) and the @value{GDBN} scope operator (@code{::}). The two have +similar syntax: + +@example + +@var{module} . @var{id} +@var{scope} :: @var{id} +@end example + +@noindent +where @var{scope} is the name of a module or a procedure, +@var{module} the name of a module, and @var{id} is any declared +identifier within your program, except another module. + +Using the @code{::} operator makes @value{GDBN} search the scope +specified by @var{scope} for the identifier @var{id}. If it is not +found in the specified scope, then @value{GDBN} will search all scopes +enclosing the one specified by @var{scope}. + +Using the @code{.} operator makes @value{GDBN} search the current scope for +the identifier specified by @var{id} that was imported from the +definition module specified by @var{module}. With this operator, it is +an error if the identifier @var{id} was not imported from definition +module @var{module}, or if @var{id} is not an identifier in +@var{module}. + +@node GDB/M2 +@subsubsection @value{GDBN} and Modula-2 + +Some @value{GDBN} commands have little use when debugging Modula-2 programs. +Five subcommands of @code{set print} and @code{show print} apply +specifically to C and C++: @samp{vtbl}, @samp{demangle}, +@samp{asm-demangle}, @samp{object}, and @samp{union}. The first four +apply to C++, and the last to the C @code{union} type, which has no direct +analogue in Modula-2. + +The @code{@@} operator (@pxref{Expressions, ,Expressions}), while available +while using any language, is not useful with Modula-2. Its +intent is to aid the debugging of @dfn{dynamic arrays}, which cannot be +created in Modula-2 as they can in C or C++. However, because an +address can be specified by an integral constant, the construct +@samp{@{@var{type}@}@var{adrexp}} is still useful. (@pxref{Expressions, ,Expressions}) + +@cindex @code{#} in Modula-2 +In @value{GDBN} scripts, the Modula-2 inequality operator @code{#} is +interpreted as the beginning of a comment. Use @code{<>} instead. + +@end ifset +@end ifclear + +@node Symbols +@chapter Examining the Symbol Table + +The commands described in this section allow you to inquire about the +symbols (names of variables, functions and types) defined in your +program. This information is inherent in the text of your program and +does not change as your program executes. @value{GDBN} finds it in your +program's symbol table, in the file indicated when you started @value{GDBN} +(@pxref{File Options, ,Choosing files}), or by one of the +file-management commands (@pxref{Files, ,Commands to specify files}). + +@c FIXME! This might be intentionally specific to C and C++; if so, move +@c to someplace in C section of lang chapter. +@cindex symbol names +@cindex names of symbols +@cindex quoting names +Occasionally, you may need to refer to symbols that contain unusual +characters, which @value{GDBN} ordinarily treats as word delimiters. The +most frequent case is in referring to static variables in other +source files (@pxref{Variables,,Program variables}). File names +are recorded in object files as debugging symbols, but @value{GDBN} would +ordinarily parse a typical file name, like @file{foo.c}, as the three words +@samp{foo} @samp{.} @samp{c}. To allow @value{GDBN} to recognize +@samp{foo.c} as a single symbol, enclose it in single quotes; for example, + +@example +p 'foo.c'::x +@end example + +@noindent +looks up the value of @code{x} in the scope of the file @file{foo.c}. + +@table @code +@item info address @var{symbol} +@kindex info address +Describe where the data for @var{symbol} is stored. For a register +variable, this says which register it is kept in. For a non-register +local variable, this prints the stack-frame offset at which the variable +is always stored. + +Note the contrast with @samp{print &@var{symbol}}, which does not work +at all for a register variable, and for a stack local variable prints +the exact address of the current instantiation of the variable. + +@item whatis @var{exp} +@kindex whatis +Print the data type of expression @var{exp}. @var{exp} is not +actually evaluated, and any side-effecting operations (such as +assignments or function calls) inside it do not take place. +@xref{Expressions, ,Expressions}. + +@item whatis +Print the data type of @code{$}, the last value in the value history. + +@item ptype @var{typename} +@kindex ptype +Print a description of data type @var{typename}. @var{typename} may be +the name of a type, or for C code it may have the form +@ifclear CONLY +@samp{class @var{class-name}}, +@end ifclear +@samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or +@samp{enum @var{enum-tag}}. + +@item ptype @var{exp} +@itemx ptype +Print a description of the type of expression @var{exp}. @code{ptype} +differs from @code{whatis} by printing a detailed description, instead +of just the name of the type. + +For example, for this variable declaration: + +@example +struct complex @{double real; double imag;@} v; +@end example + +@noindent +the two commands give this output: + +@example +@group +(@value{GDBP}) whatis v +type = struct complex +(@value{GDBP}) ptype v +type = struct complex @{ + double real; + double imag; +@} +@end group +@end example + +@noindent +As with @code{whatis}, using @code{ptype} without an argument refers to +the type of @code{$}, the last value in the value history. + +@item info types @var{regexp} +@itemx info types +@kindex info types +Print a brief description of all types whose name matches @var{regexp} +(or all types in your program, if you supply no argument). Each +complete typename is matched as though it were a complete line; thus, +@samp{i type value} gives information on all types in your program whose +name includes the string @code{value}, but @samp{i type ^value$} gives +information only on types whose complete name is @code{value}. + +This command differs from @code{ptype} in two ways: first, like +@code{whatis}, it does not print a detailed description; second, it +lists all source files where a type is defined. + +@item info source +@kindex info source +Show the name of the current source file---that is, the source file for +the function containing the current point of execution---and the language +it was written in. + +@item info sources +@kindex info sources +Print the names of all source files in your program for which there is +debugging information, organized into two lists: files whose symbols +have already been read, and files whose symbols will be read when needed. + +@item info functions +@kindex info functions +Print the names and data types of all defined functions. + +@item info functions @var{regexp} +Print the names and data types of all defined functions +whose names contain a match for regular expression @var{regexp}. +Thus, @samp{info fun step} finds all functions whose names +include @code{step}; @samp{info fun ^step} finds those whose names +start with @code{step}. + +@item info variables +@kindex info variables +Print the names and data types of all variables that are declared +outside of functions (i.e., excluding local variables). + +@item info variables @var{regexp} +Print the names and data types of all variables (except for local +variables) whose names contain a match for regular expression +@var{regexp}. + +@ignore +This was never implemented. +@item info methods +@itemx info methods @var{regexp} +@kindex info methods +The @code{info methods} command permits the user to examine all defined +methods within C++ program, or (with the @var{regexp} argument) a +specific set of methods found in the various C++ classes. Many +C++ classes provide a large number of methods. Thus, the output +from the @code{ptype} command can be overwhelming and hard to use. The +@code{info-methods} command filters the methods, printing only those +which match the regular-expression @var{regexp}. +@end ignore + +@item maint print symbols @var{filename} +@itemx maint print psymbols @var{filename} +@itemx maint print msymbols @var{filename} +@kindex maint print symbols +@cindex symbol dump +@kindex maint print psymbols +@cindex partial symbol dump +Write a dump of debugging symbol data into the file @var{filename}. +These commands are used to debug the @value{GDBN} symbol-reading code. Only +symbols with debugging data are included. If you use @samp{maint print +symbols}, @value{GDBN} includes all the symbols for which it has already +collected full details: that is, @var{filename} reflects symbols for +only those files whose symbols @value{GDBN} has read. You can use the +command @code{info sources} to find out which files these are. If you +use @samp{maint print psymbols} instead, the dump shows information about +symbols that @value{GDBN} only knows partially---that is, symbols defined in +files that @value{GDBN} has skimmed, but not yet read completely. Finally, +@samp{maint print msymbols} dumps just the minimal symbol information +required for each object file from which @value{GDBN} has read some symbols. +@xref{Files, ,Commands to specify files}, for a discussion of how +@value{GDBN} reads symbols (in the description of @code{symbol-file}). +@end table + +@node Altering +@chapter Altering Execution + +Once you think you have found an error in your program, you might want to +find out for certain whether correcting the apparent error would lead to +correct results in the rest of the run. You can find the answer by +experiment, using the @value{GDBN} features for altering execution of the +program. + +For example, you can store new values into variables or memory +locations, +@ifclear BARETARGET +give your program a signal, restart it +@end ifclear +@ifset BARETARGET +restart your program +@end ifset +at a different address, or even return prematurely from a function to +its caller. + +@menu +* Assignment:: Assignment to variables +* Jumping:: Continuing at a different address +@ifclear BARETARGET +* Signaling:: Giving your program a signal +@end ifclear + +* Returning:: Returning from a function +* Calling:: Calling your program's functions +* Patching:: Patching your program +@end menu + +@node Assignment +@section Assignment to variables + +@cindex assignment +@cindex setting variables +To alter the value of a variable, evaluate an assignment expression. +@xref{Expressions, ,Expressions}. For example, + +@example +print x=4 +@end example + +@noindent +stores the value 4 into the variable @code{x}, and then prints the +value of the assignment expression (which is 4). +@ifclear CONLY +@xref{Languages, ,Using @value{GDBN} with Different Languages}, for more +information on operators in supported languages. +@end ifclear + +@kindex set variable +@cindex variables, setting +If you are not interested in seeing the value of the assignment, use the +@code{set} command instead of the @code{print} command. @code{set} is +really the same as @code{print} except that the expression's value is +not printed and is not put in the value history (@pxref{Value History, +,Value history}). The expression is evaluated only for its effects. + +If the beginning of the argument string of the @code{set} command +appears identical to a @code{set} subcommand, use the @code{set +variable} command instead of just @code{set}. This command is identical +to @code{set} except for its lack of subcommands. For example, if +your program has a variable @code{width}, you get +an error if you try to set a new value with just @samp{set width=13}, +because @value{GDBN} has the command @code{set width}: + +@example +(@value{GDBP}) whatis width +type = double +(@value{GDBP}) p width +$4 = 13 +(@value{GDBP}) set width=47 +Invalid syntax in expression. +@end example + +@noindent +The invalid expression, of course, is @samp{=47}. In +order to actually set the program's variable @code{width}, use + +@example +(@value{GDBP}) set var width=47 +@end example + +@value{GDBN} allows more implicit conversions in assignments than C; you can +freely store an integer value into a pointer variable or vice versa, +and you can convert any structure to any other structure that is the +same length or shorter. +@comment FIXME: how do structs align/pad in these conversions? +@comment /pesch@cygnus.com 18dec1990 + +To store values into arbitrary places in memory, use the @samp{@{@dots{}@}} +construct to generate a value of specified type at a specified address +(@pxref{Expressions, ,Expressions}). For example, @code{@{int@}0x83040} refers +to memory location @code{0x83040} as an integer (which implies a certain size +and representation in memory), and + +@example +set @{int@}0x83040 = 4 +@end example + +@noindent +stores the value 4 into that memory location. + +@node Jumping +@section Continuing at a different address + +Ordinarily, when you continue your program, you do so at the place where +it stopped, with the @code{continue} command. You can instead continue at +an address of your own choosing, with the following commands: + +@table @code +@item jump @var{linespec} +@kindex jump +Resume execution at line @var{linespec}. Execution will stop +immediately if there is a breakpoint there. @xref{List, ,Printing +source lines}, for a description of the different forms of +@var{linespec}. + +The @code{jump} command does not change the current stack frame, or +the stack pointer, or the contents of any memory location or any +register other than the program counter. If line @var{linespec} is in +a different function from the one currently executing, the results may +be bizarre if the two functions expect different patterns of arguments or +of local variables. For this reason, the @code{jump} command requests +confirmation if the specified line is not in the function currently +executing. However, even bizarre results are predictable if you are +well acquainted with the machine-language code of your program. + +@item jump *@var{address} +Resume execution at the instruction at address @var{address}. +@end table + +You can get much the same effect as the @code{jump} command by storing a +new value into the register @code{$pc}. The difference is that this +does not start your program running; it only changes the address where it +@emph{will} run when it is continued. For example, + +@example +set $pc = 0x485 +@end example + +@noindent +causes the next @code{continue} command or stepping command to execute at +address @code{0x485}, rather than at the address where your program stopped. +@xref{Continuing and Stepping, ,Continuing and stepping}. + +The most common occasion to use the @code{jump} command is to back up, +perhaps with more breakpoints set, over a portion of a program that has +already executed, in order to examine its execution in more detail. + +@ifclear BARETARGET +@c @group +@node Signaling +@section Giving your program a signal + +@table @code +@item signal @var{signal} +@kindex signal +Resume execution where your program stopped, but immediately give it the +signal @var{signal}. @var{signal} can be the name or the number of a +signal. For example, on many systems @code{signal 2} and @code{signal +SIGINT} are both ways of sending an interrupt signal. + +Alternatively, if @var{signal} is zero, continue execution without +giving a signal. This is useful when your program stopped on account of +a signal and would ordinary see the signal when resumed with the +@code{continue} command; @samp{signal 0} causes it to resume without a +signal. + +@code{signal} does not repeat when you press @key{RET} a second time +after executing the command. +@end table +@c @end group + +Invoking the @code{signal} command is not the same as invoking the +@code{kill} utility from the shell. Sending a signal with @code{kill} +causes @value{GDBN} to decide what to do with the signal depending on +the signal handling tables (@pxref{Signals}). The @code{signal} command +passes the signal directly to your program. + +@end ifclear + +@node Returning +@section Returning from a function + +@table @code +@item return +@itemx return @var{expression} +@cindex returning from a function +@kindex return +You can cancel execution of a function call with the @code{return} +command. If you give an +@var{expression} argument, its value is used as the function's return +value. +@end table + +When you use @code{return}, @value{GDBN} discards the selected stack frame +(and all frames within it). You can think of this as making the +discarded frame return prematurely. If you wish to specify a value to +be returned, give that value as the argument to @code{return}. + +This pops the selected stack frame (@pxref{Selection, ,Selecting a +frame}), and any other frames inside of it, leaving its caller as the +innermost remaining frame. That frame becomes selected. The +specified value is stored in the registers used for returning values +of functions. + +The @code{return} command does not resume execution; it leaves the +program stopped in the state that would exist if the function had just +returned. In contrast, the @code{finish} command (@pxref{Continuing +and Stepping, ,Continuing and stepping}) resumes execution until the +selected stack frame returns naturally. + +@node Calling +@section Calling program functions + +@cindex calling functions +@kindex call +@table @code +@item call @var{expr} +Evaluate the expression @var{expr} without displaying @code{void} +returned values. +@end table + +You can use this variant of the @code{print} command if you want to +execute a function from your program, but without cluttering the output +with @code{void} returned values. The result is printed and saved in +the value history, if it is not void. + +@node Patching +@section Patching programs +@cindex patching binaries +@cindex writing into executables +@ifclear BARETARGET +@cindex writing into corefiles +@end ifclear + +By default, @value{GDBN} opens the file containing your program's executable +code +@ifclear BARETARGET +(or the corefile) +@end ifclear +read-only. This prevents accidental alterations +to machine code; but it also prevents you from intentionally patching +your program's binary. + +If you'd like to be able to patch the binary, you can specify that +explicitly with the @code{set write} command. For example, you might +want to turn on internal debugging flags, or even to make emergency +repairs. + +@table @code +@item set write on +@itemx set write off +@kindex set write +If you specify @samp{set write on}, @value{GDBN} will open executable +@ifclear BARETARGET +and core +@end ifclear +files for both reading and writing; if you specify @samp{set write +off} (the default), @value{GDBN} will open them read-only. + +If you have already loaded a file, you must load it again (using the +@code{exec-file} +@ifclear BARETARGET +or @code{core-file} +@end ifclear +command) after changing @code{set write}, for your new setting to take +effect. + +@item show write +@kindex show write +Display whether executable files +@ifclear BARETARGET +and core files +@end ifclear +will be opened for writing as well as reading. +@end table + +@node GDB Files +@chapter @value{GDBN} Files + +@value{GDBN} needs to know the file name of the program to be debugged, both in +order to read its symbol table and in order to start your program. +@ifclear BARETARGET +To debug a core dump of a previous run, you must also tell @value{GDBN} +the name of the core dump file. +@end ifclear + +@menu +* Files:: Commands to specify files +* Symbol Errors:: Errors reading symbol files +@end menu + +@node Files +@section Commands to specify files +@cindex symbol table + +@ifclear BARETARGET +@cindex core dump file +The usual way to specify executable and core dump file names is with +the command arguments given when you start @value{GDBN} (@pxref{Invocation, +,Getting In and Out of @value{GDBN}}. +@end ifclear +@ifset BARETARGET +The usual way to specify an executable file name is with +the command argument given when you start @value{GDBN}, (@pxref{Invocation, +,Getting In and Out of @value{GDBN}}. +@end ifset + +Occasionally it is necessary to change to a different file during a +@value{GDBN} session. Or you may run @value{GDBN} and forget to specify +a file you want to use. In these situations the @value{GDBN} commands +to specify new files are useful. + +@table @code +@item file @var{filename} +@cindex executable file +@kindex file +Use @var{filename} as the program to be debugged. It is read for its +symbols and for the contents of pure memory. It is also the program +executed when you use the @code{run} command. If you do not specify a +directory and the file is not found in the @value{GDBN} working directory, @value{GDBN} +uses the environment variable @code{PATH} as a list of directories to +search, just as the shell does when looking for a program to run. You +can change the value of this variable, for both @value{GDBN} and your program, +using the @code{path} command. + +On systems with memory-mapped files, an auxiliary symbol table file +@file{@var{filename}.syms} may be available for @var{filename}. If it +is, @value{GDBN} will map in the symbol table from +@file{@var{filename}.syms}, starting up more quickly. See the +descriptions of the options @samp{-mapped} and @samp{-readnow} (available +on the command line, and with the commands @code{file}, @code{symbol-file}, +or @code{add-symbol-file}), for more information. + +@item file +@code{file} with no argument makes @value{GDBN} discard any information it +has on both executable file and the symbol table. + +@item exec-file @r{[} @var{filename} @r{]} +@kindex exec-file +Specify that the program to be run (but not the symbol table) is found +in @var{filename}. @value{GDBN} will search the environment variable @code{PATH} +if necessary to locate your program. Omitting @var{filename} means to +discard information on the executable file. + +@item symbol-file @r{[} @var{filename} @r{]} +@kindex symbol-file +Read symbol table information from file @var{filename}. @code{PATH} is +searched when necessary. Use the @code{file} command to get both symbol +table and program to run from the same file. + +@code{symbol-file} with no argument clears out @value{GDBN} information on your +program's symbol table. + +The @code{symbol-file} command causes @value{GDBN} to forget the contents of its +convenience variables, the value history, and all breakpoints and +auto-display expressions. This is because they may contain pointers to +the internal data recording symbols and data types, which are part of +the old symbol table data being discarded inside @value{GDBN}. + +@code{symbol-file} will not repeat if you press @key{RET} again after +executing it once. + +When @value{GDBN} is configured for a particular environment, it will +understand debugging information in whatever format is the standard +generated for that environment; you may use either a GNU compiler, or +other compilers that adhere to the local conventions. Best results are +usually obtained from GNU compilers; for example, using @code{@value{GCC}} +you can generate debugging information for optimized code. + +On some kinds of object files, the @code{symbol-file} command does not +normally read the symbol table in full right away. Instead, it scans +the symbol table quickly to find which source files and which symbols +are present. The details are read later, one source file at a time, +as they are needed. + +The purpose of this two-stage reading strategy is to make @value{GDBN} start up +faster. For the most part, it is invisible except for occasional +pauses while the symbol table details for a particular source file are +being read. (The @code{set verbose} command can turn these pauses +into messages if desired. @xref{Messages/Warnings, ,Optional warnings +and messages}.) + +We have not implemented the two-stage strategy for COFF yet. When the +symbol table is stored in COFF format, @code{symbol-file} reads the +symbol table data in full right away. + +@item symbol-file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]} +@itemx file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]} +@kindex readnow +@cindex reading symbols immediately +@cindex symbols, reading immediately +@kindex mapped +@cindex memory-mapped symbol file +@cindex saving symbol table +You can override the @value{GDBN} two-stage strategy for reading symbol +tables by using the @samp{-readnow} option with any of the commands that +load symbol table information, if you want to be sure @value{GDBN} has the +entire symbol table available. + +@ifclear BARETARGET +If memory-mapped files are available on your system through the +@code{mmap} system call, you can use another option, @samp{-mapped}, to +cause @value{GDBN} to write the symbols for your program into a reusable +file. Future @value{GDBN} debugging sessions will map in symbol information +from this auxiliary symbol file (if the program has not changed), rather +than spending time reading the symbol table from the executable +program. Using the @samp{-mapped} option has the same effect as +starting @value{GDBN} with the @samp{-mapped} command-line option. + +You can use both options together, to make sure the auxiliary symbol +file has all the symbol information for your program. + +The auxiliary symbol file for a program called @var{myprog} is called +@samp{@var{myprog}.syms}. Once this file exists (so long as it is newer +than the corresponding executable), @value{GDBN} will always attempt to use +it when you debug @var{myprog}; no special options or commands are +needed. + +The @file{.syms} file is specific to the host machine where you run +@value{GDBN}. It holds an exact image of the internal @value{GDBN} +symbol table. It cannot be shared across multiple host platforms. + +@c FIXME: for now no mention of directories, since this seems to be in +@c flux. 13mar1992 status is that in theory GDB would look either in +@c current dir or in same dir as myprog; but issues like competing +@c GDB's, or clutter in system dirs, mean that in practice right now +@c only current dir is used. FFish says maybe a special GDB hierarchy +@c (eg rooted in val of env var GDBSYMS) could exist for mappable symbol +@c files. + +@item core-file @r{[} @var{filename} @r{]} +@kindex core +@kindex core-file +Specify the whereabouts of a core dump file to be used as the ``contents +of memory''. Traditionally, core files contain only some parts of the +address space of the process that generated them; @value{GDBN} can access the +executable file itself for other parts. + +@code{core-file} with no argument specifies that no core file is +to be used. + +Note that the core file is ignored when your program is actually running +under @value{GDBN}. So, if you have been running your program and you wish to +debug a core file instead, you must kill the subprocess in which the +program is running. To do this, use the @code{kill} command +(@pxref{Kill Process, ,Killing the child process}). +@end ifclear + +@item load @var{filename} +@kindex load +@ifset GENERIC +Depending on what remote debugging facilities are configured into +@value{GDBN}, the @code{load} command may be available. Where it exists, it +is meant to make @var{filename} (an executable) available for debugging +on the remote system---by downloading, or dynamic linking, for example. +@code{load} also records the @var{filename} symbol table in @value{GDBN}, like +the @code{add-symbol-file} command. + +If your @value{GDBN} does not have a @code{load} command, attempting to +execute it gets the error message ``@code{You can't do that when your +target is @dots{}}'' +@end ifset + +The file is loaded at whatever address is specified in the executable. +For some object file formats, like a.out, the object file format fixes +the address and so it won't necessarily match the address you gave to +the linker. + +@ifset VXWORKS +On VxWorks, @code{load} will dynamically link @var{filename} on the +current target system as well as adding its symbols in @value{GDBN}. +@end ifset + +@ifset I960 +@cindex download to Nindy-960 +With the Nindy interface to an Intel 960 board, @code{load} will +download @var{filename} to the 960 as well as adding its symbols in +@value{GDBN}. +@end ifset + +@ifset H8 +@cindex download to H8/300 or H8/500 +@cindex H8/300 or H8/500 download +@cindex download to Hitachi SH +@cindex Hitachi SH download +When you select remote debugging to a Hitachi SH, H8/300, or H8/500 board +(@pxref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}), +the @code{load} command downloads your program to the Hitachi board and also +opens it as the current executable target for @value{GDBN} on your host +(like the @code{file} command). +@end ifset + +@code{load} will not repeat if you press @key{RET} again after using it. + +@ifclear BARETARGET +@item add-symbol-file @var{filename} @var{address} +@itemx add-symbol-file @var{filename} @var{address} @r{[} -readnow @r{]} @r{[} -mapped @r{]} +@kindex add-symbol-file +@cindex dynamic linking +The @code{add-symbol-file} command reads additional symbol table information +from the file @var{filename}. You would use this command when @var{filename} +has been dynamically loaded (by some other means) into the program that +is running. @var{address} should be the memory address at which the +file has been loaded; @value{GDBN} cannot figure this out for itself. +You can specify @var{address} as an expression. + +The symbol table of the file @var{filename} is added to the symbol table +originally read with the @code{symbol-file} command. You can use the +@code{add-symbol-file} command any number of times; the new symbol data thus +read keeps adding to the old. To discard all old symbol data instead, +use the @code{symbol-file} command. + +@code{add-symbol-file} will not repeat if you press @key{RET} after using it. + +You can use the @samp{-mapped} and @samp{-readnow} options just as with +the @code{symbol-file} command, to change how @value{GDBN} manages the symbol +table information for @var{filename}. +@end ifclear + +@item info files +@itemx info target +@kindex info files +@kindex info target +@code{info files} and @code{info target} are synonymous; both print +the current target (@pxref{Targets, ,Specifying a Debugging Target}), +including the +@ifclear BARETARGET +names of the executable and core dump files +@end ifclear +@ifset BARETARGET +name of the executable file +@end ifset +currently in use by @value{GDBN}, and the files from which symbols were +loaded. The command @code{help targets} lists all possible targets +rather than current ones. +@end table + +All file-specifying commands allow both absolute and relative file names +as arguments. @value{GDBN} always converts the file name to an absolute path +name and remembers it that way. + +@ifclear BARETARGET +@cindex shared libraries +@value{GDBN} supports SunOS, SVR4, and IBM RS/6000 shared libraries. +@value{GDBN} automatically loads symbol definitions from shared libraries +when you use the @code{run} command, or when you examine a core file. +(Before you issue the @code{run} command, @value{GDBN} will not understand +references to a function in a shared library, however---unless you are +debugging a core file). +@c FIXME: next @value{GDBN} release should permit some refs to undef +@c FIXME...symbols---eg in a break cmd---assuming they are from a shared lib + +@table @code +@item info share +@itemx info sharedlibrary +@kindex info sharedlibrary +@kindex info share +Print the names of the shared libraries which are currently loaded. + +@item sharedlibrary @var{regex} +@itemx share @var{regex} +@kindex sharedlibrary +@kindex share +This is an obsolescent command; you can use it to explicitly load shared +object library symbols for files matching a Unix regular expression, but +as with files loaded automatically, it will only load shared libraries +required by your program for a core file or after typing @code{run}. If +@var{regex} is omitted all shared libraries required by your program are +loaded. +@end table +@end ifclear + +@node Symbol Errors +@section Errors reading symbol files + +While reading a symbol file, @value{GDBN} will occasionally encounter problems, +such as symbol types it does not recognize, or known bugs in compiler +output. By default, @value{GDBN} does not notify you of such problems, since +they are relatively common and primarily of interest to people +debugging compilers. If you are interested in seeing information +about ill-constructed symbol tables, you can either ask @value{GDBN} to print +only one message about each such type of problem, no matter how many +times the problem occurs; or you can ask @value{GDBN} to print more messages, +to see how many times the problems occur, with the @code{set +complaints} command (@pxref{Messages/Warnings, ,Optional warnings and +messages}). + +The messages currently printed, and their meanings, include: + +@table @code +@item inner block not inside outer block in @var{symbol} + +The symbol information shows where symbol scopes begin and end +(such as at the start of a function or a block of statements). This +error indicates that an inner scope block is not fully contained +in its outer scope blocks. + +@value{GDBN} circumvents the problem by treating the inner block as if it had +the same scope as the outer block. In the error message, @var{symbol} +may be shown as ``@code{(don't know)}'' if the outer block is not a +function. + +@item block at @var{address} out of order + +The symbol information for symbol scope blocks should occur in +order of increasing addresses. This error indicates that it does not +do so. + +@value{GDBN} does not circumvent this problem, and will have trouble +locating symbols in the source file whose symbols it is reading. (You +can often determine what source file is affected by specifying +@code{set verbose on}. @xref{Messages/Warnings, ,Optional warnings and +messages}.) + +@item bad block start address patched + +The symbol information for a symbol scope block has a start address +smaller than the address of the preceding source line. This is known +to occur in the SunOS 4.1.1 (and earlier) C compiler. + +@value{GDBN} circumvents the problem by treating the symbol scope block as +starting on the previous source line. + +@item bad string table offset in symbol @var{n} + +@cindex foo +Symbol number @var{n} contains a pointer into the string table which is +larger than the size of the string table. + +@value{GDBN} circumvents the problem by considering the symbol to have the +name @code{foo}, which may cause other problems if many symbols end up +with this name. + +@item unknown symbol type @code{0x@var{nn}} + +The symbol information contains new data types that @value{GDBN} does not yet +know how to read. @code{0x@var{nn}} is the symbol type of the misunderstood +information, in hexadecimal. + +@value{GDBN} circumvents the error by ignoring this symbol information. This +will usually allow your program to be debugged, though certain symbols +will not be accessible. If you encounter such a problem and feel like +debugging it, you can debug @code{@value{GDBP}} with itself, breakpoint on +@code{complain}, then go up to the function @code{read_dbx_symtab} and +examine @code{*bufp} to see the symbol. + +@item stub type has NULL name +@value{GDBN} could not find the full definition for +@ifclear CONLY +a struct or class. +@end ifclear +@ifset CONLY +a struct. +@end ifset + +@ifclear CONLY +@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{} + +The symbol information for a C++ member function is missing some +information that recent versions of the compiler should have output +for it. +@end ifclear + +@item info mismatch between compiler and debugger + +@value{GDBN} could not parse a type specification output by the compiler. +@end table + +@node Targets +@chapter Specifying a Debugging Target +@cindex debugging target +@kindex target + +A @dfn{target} is the execution environment occupied by your program. +@ifclear BARETARGET +Often, @value{GDBN} runs in the same host environment as your program; in +that case, the debugging target is specified as a side effect when you +use the @code{file} or @code{core} commands. When you need more +flexibility---for example, running @value{GDBN} on a physically separate +host, or controlling a standalone system over a serial port or a +realtime system over a TCP/IP connection---you +@end ifclear +@ifset BARETARGET +You +@end ifset +can use the @code{target} command to specify one of the target types +configured for @value{GDBN} (@pxref{Target Commands, ,Commands for managing +targets}). + +@menu +* Active Targets:: Active targets +* Target Commands:: Commands for managing targets +* Remote:: Remote debugging +@end menu + +@node Active Targets +@section Active targets +@cindex stacking targets +@cindex active targets +@cindex multiple targets + +@ifclear BARETARGET +There are three classes of targets: processes, core files, and +executable files. @value{GDBN} can work concurrently on up to three active +targets, one in each class. This allows you to (for example) start a +process and inspect its activity without abandoning your work on a core +file. + +For example, if you execute @samp{gdb a.out}, then the executable file +@code{a.out} is the only active target. If you designate a core file as +well---presumably from a prior run that crashed and coredumped---then +@value{GDBN} has two active targets and will use them in tandem, looking +first in the corefile target, then in the executable file, to satisfy +requests for memory addresses. (Typically, these two classes of target +are complementary, since core files contain only a program's +read-write memory---variables and so on---plus machine status, while +executable files contain only the program text and initialized data.) +@end ifclear + +When you type @code{run}, your executable file becomes an active process +target as well. When a process target is active, all @value{GDBN} commands +requesting memory addresses refer to that target; addresses in an +@ifclear BARETARGET +active core file or +@end ifclear +executable file target are obscured while the process +target is active. + +@ifset BARETARGET +Use the @code{exec-file} command to select a +new executable target (@pxref{Files, ,Commands to specify +files}). +@end ifset +@ifclear BARETARGET +Use the @code{core-file} and @code{exec-file} commands to select a +new core file or executable target (@pxref{Files, ,Commands to specify +files}). To specify as a target a process that is already running, use +the @code{attach} command (@pxref{Attach, ,Debugging an +already-running process}). +@end ifclear + +@node Target Commands +@section Commands for managing targets + +@table @code +@item target @var{type} @var{parameters} +Connects the @value{GDBN} host environment to a target +@ifset BARETARGET +machine. +@end ifset +@ifclear BARETARGET +machine or process. A target is typically a protocol for talking to +debugging facilities. You use the argument @var{type} to specify the +type or protocol of the target machine. + +Further @var{parameters} are interpreted by the target protocol, but +typically include things like device names or host names to connect +with, process numbers, and baud rates. +@end ifclear + +The @code{target} command will not repeat if you press @key{RET} again +after executing the command. + +@item help target +@kindex help target +Displays the names of all targets available. To display targets +currently selected, use either @code{info target} or @code{info files} +(@pxref{Files, ,Commands to specify files}). + +@item help target @var{name} +Describe a particular target, including any parameters necessary to +select it. +@end table + +Here are some common targets (available, or not, depending on the GDB +configuration): + +@table @code +@item target exec @var{program} +@kindex target exec +An executable file. @samp{target exec @var{program}} is the same as +@samp{exec-file @var{program}}. + +@ifclear BARETARGET +@item target core @var{filename} +@kindex target core +A core dump file. @samp{target core @var{filename}} is the same as +@samp{core-file @var{filename}}. +@end ifclear + +@ifset REMOTESTUB +@item target remote @var{dev} +@kindex target remote +Remote serial target in GDB-specific protocol. The argument @var{dev} +specifies what serial device to use for the connection (e.g. +@file{/dev/ttya}). @xref{Remote, ,Remote debugging}. +@end ifset + +@ifset SIMS +@item target sim +@kindex target sim +CPU simulator. @xref{Simulator,,Simulated CPU Target}. +@end ifset + +@ifset AMD29K +@item target udi @var{keyword} +@kindex target udi +Remote AMD29K target, using the AMD UDI protocol. The @var{keyword} +argument specifies which 29K board or simulator to use. @xref{UDI29K +Remote,,@value{GDBN} and the UDI protocol for AMD29K}. + +@item target amd-eb @var{dev} @var{speed} @var{PROG} +@kindex target amd-eb +@cindex AMD EB29K +Remote PC-resident AMD EB29K board, attached over serial lines. +@var{dev} is the serial device, as for @code{target remote}; +@var{speed} allows you to specify the linespeed; and @var{PROG} is the +name of the program to be debugged, as it appears to DOS on the PC. +@xref{EB29K Remote, ,@value{GDBN} with a remote EB29K}. + +@end ifset +@ifset H8 +@item target hms +@kindex target hms +A Hitachi SH, H8/300, or H8/500 board, attached via serial line to your host. +@ifclear H8EXCLUSIVE +@c Unix only, not currently of interest for H8-only manual +Use special commands @code{device} and @code{speed} to control the serial +line and the communications speed used. +@end ifclear +@xref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}. + +@end ifset +@ifset I960 +@item target nindy @var{devicename} +@kindex target nindy +An Intel 960 board controlled by a Nindy Monitor. @var{devicename} is +the name of the serial device to use for the connection, e.g. +@file{/dev/ttya}. @xref{i960-Nindy Remote, ,@value{GDBN} with a remote i960 (Nindy)}. + +@end ifset +@ifset ST2000 +@item target st2000 @var{dev} @var{speed} +@kindex target st2000 +A Tandem ST2000 phone switch, running Tandem's STDBUG protocol. @var{dev} +is the name of the device attached to the ST2000 serial line; +@var{speed} is the communication line speed. The arguments are not used +if @value{GDBN} is configured to connect to the ST2000 using TCP or Telnet. +@xref{ST2000 Remote,,@value{GDBN} with a Tandem ST2000}. + +@end ifset +@ifset VXWORKS +@item target vxworks @var{machinename} +@kindex target vxworks +A VxWorks system, attached via TCP/IP. The argument @var{machinename} +is the target system's machine name or IP address. +@xref{VxWorks Remote, ,@value{GDBN} and VxWorks}. +@end ifset +@end table + +@ifset GENERIC +Different targets are available on different configurations of @value{GDBN}; your +configuration may have more or fewer targets. +@end ifset + +@node Remote +@section Remote debugging +@cindex remote debugging + +If you are trying to debug a program running on a machine that cannot run +GDB in the usual way, it is often useful to use remote debugging. For +example, you might use remote debugging on an operating system kernel, or on +a small system which does not have a general purpose operating system +powerful enough to run a full-featured debugger. + +Some configurations of GDB have special serial or TCP/IP interfaces +to make this work with particular debugging targets. In addition, +GDB comes with a generic serial protocol (specific to GDB, but +not specific to any particular target system) which you can use if you +write the remote stubs---the code that will run on the remote system to +communicate with GDB. + +Other remote targets may be available in your +configuration of GDB; use @code{help targets} to list them. + +@ifset GENERIC +@c Text on starting up GDB in various specific cases; it goes up front +@c in manuals configured for any of those particular situations, here +@c otherwise. +@menu +@ifset REMOTESTUB +* Remote Serial:: @value{GDBN} remote serial protocol +@end ifset +@ifset I960 +* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) +@end ifset +@ifset AMD29K +* UDI29K Remote:: @value{GDBN} and the UDI protocol for AMD29K +* EB29K Remote:: @value{GDBN} with a remote EB29K +@end ifset +@ifset VXWORKS +* VxWorks Remote:: @value{GDBN} and VxWorks +@end ifset +@ifset ST2000 +* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 +@end ifset +@ifset H8 +* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors +@end ifset +@ifset MIPS +* MIPS Remote:: @value{GDBN} and MIPS boards +@end ifset +@ifset SIMS +* Simulator:: Simulated CPU target +@end ifset +@end menu + +@include remote.texi +@end ifset + +@node Controlling GDB +@chapter Controlling @value{GDBN} + +You can alter the way @value{GDBN} interacts with you by using +the @code{set} command. For commands controlling how @value{GDBN} displays +data, @pxref{Print Settings, ,Print settings}; other settings are described here. + +@menu +* Prompt:: Prompt +* Editing:: Command editing +* History:: Command history +* Screen Size:: Screen size +* Numbers:: Numbers +* Messages/Warnings:: Optional warnings and messages +@end menu + +@node Prompt +@section Prompt +@cindex prompt + +@value{GDBN} indicates its readiness to read a command by printing a string +called the @dfn{prompt}. This string is normally @samp{(@value{GDBP})}. You +can change the prompt string with the @code{set prompt} command. For +instance, when debugging @value{GDBN} with @value{GDBN}, it is useful to change +the prompt in one of the @value{GDBN} sessions so that you can always tell which +one you are talking to. + +@table @code +@item set prompt @var{newprompt} +@kindex set prompt +Directs @value{GDBN} to use @var{newprompt} as its prompt string henceforth. +@kindex show prompt +@item show prompt +Prints a line of the form: @samp{Gdb's prompt is: @var{your-prompt}} +@end table + +@node Editing +@section Command editing +@cindex readline +@cindex command line editing + +@value{GDBN} reads its input commands via the @dfn{readline} interface. This +GNU library provides consistent behavior for programs which provide a +command line interface to the user. Advantages are @code{emacs}-style +or @code{vi}-style inline editing of commands, @code{csh}-like history +substitution, and a storage and recall of command history across +debugging sessions. + +You may control the behavior of command line editing in @value{GDBN} with the +command @code{set}. + +@table @code +@kindex set editing +@cindex editing +@item set editing +@itemx set editing on +Enable command line editing (enabled by default). + +@item set editing off +Disable command line editing. + +@kindex show editing +@item show editing +Show whether command line editing is enabled. +@end table + +@node History +@section Command history + +@value{GDBN} can keep track of the commands you type during your +debugging sessions, so that you can be certain of precisely what +happened. Use these commands to manage the @value{GDBN} command +history facility. + +@table @code +@cindex history substitution +@cindex history file +@kindex set history filename +@item set history filename @var{fname} +Set the name of the @value{GDBN} command history file to @var{fname}. This is +the file from which @value{GDBN} will read an initial command history +list or to which it will write this list when it exits. This list is +accessed through history expansion or through the history +command editing characters listed below. This file defaults to the +value of the environment variable @code{GDBHISTFILE}, or to +@file{./.gdb_history} if this variable is not set. + +@cindex history save +@kindex set history save +@item set history save +@itemx set history save on +Record command history in a file, whose name may be specified with the +@code{set history filename} command. By default, this option is disabled. + +@item set history save off +Stop recording command history in a file. + +@cindex history size +@kindex set history size +@item set history size @var{size} +Set the number of commands which @value{GDBN} will keep in its history list. +This defaults to the value of the environment variable +@code{HISTSIZE}, or to 256 if this variable is not set. +@end table + +@cindex history expansion +History expansion assigns special meaning to the character @kbd{!}. +@ifset have-readline-appendices +@xref{Event Designators}. +@end ifset + +Since @kbd{!} is also the logical not operator in C, history expansion +is off by default. If you decide to enable history expansion with the +@code{set history expansion on} command, you may sometimes need to +follow @kbd{!} (when it is used as logical not, in an expression) with +a space or a tab to prevent it from being expanded. The readline +history facilities will not attempt substitution on the strings +@kbd{!=} and @kbd{!(}, even when history expansion is enabled. + +The commands to control history expansion are: + +@table @code + +@kindex set history expansion +@item set history expansion on +@itemx set history expansion +Enable history expansion. History expansion is off by default. + +@item set history expansion off +Disable history expansion. + +The readline code comes with more complete documentation of +editing and history expansion features. Users unfamiliar with @code{emacs} +or @code{vi} may wish to read it. +@ifset have-readline-appendices +@xref{Command Line Editing}. +@end ifset + +@c @group +@kindex show history +@item show history +@itemx show history filename +@itemx show history save +@itemx show history size +@itemx show history expansion +These commands display the state of the @value{GDBN} history parameters. +@code{show history} by itself displays all four states. +@c @end group +@end table + +@table @code +@kindex show commands +@item show commands +Display the last ten commands in the command history. + +@item show commands @var{n} +Print ten commands centered on command number @var{n}. + +@item show commands + +Print ten commands just after the commands last printed. +@end table + +@node Screen Size +@section Screen size +@cindex size of screen +@cindex pauses in output + +Certain commands to @value{GDBN} may produce large amounts of +information output to the screen. To help you read all of it, +@value{GDBN} pauses and asks you for input at the end of each page of +output. Type @key{RET} when you want to continue the output, or @kbd{q} +to discard the remaining output. Also, the screen width setting +determines when to wrap lines of output. Depending on what is being +printed, @value{GDBN} tries to break the line at a readable place, +rather than simply letting it overflow onto the following line. + +Normally @value{GDBN} knows the size of the screen from the termcap data base +together with the value of the @code{TERM} environment variable and the +@code{stty rows} and @code{stty cols} settings. If this is not correct, +you can override it with the @code{set height} and @code{set +width} commands: + +@table @code +@item set height @var{lpp} +@itemx show height +@itemx set width @var{cpl} +@itemx show width +@kindex set height +@kindex set width +@kindex show width +@kindex show height +These @code{set} commands specify a screen height of @var{lpp} lines and +a screen width of @var{cpl} characters. The associated @code{show} +commands display the current settings. + +If you specify a height of zero lines, @value{GDBN} will not pause during output +no matter how long the output is. This is useful if output is to a file +or to an editor buffer. + +Likewise, you can specify @samp{set width 0} to prevent @value{GDBN} +from wrapping its output. +@end table + +@node Numbers +@section Numbers +@cindex number representation +@cindex entering numbers + +You can always enter numbers in octal, decimal, or hexadecimal in @value{GDBN} by +the usual conventions: octal numbers begin with @samp{0}, decimal +numbers end with @samp{.}, and hexadecimal numbers begin with @samp{0x}. +Numbers that begin with none of these are, by default, entered in base +10; likewise, the default display for numbers---when no particular +format is specified---is base 10. You can change the default base for +both input and output with the @code{set radix} command. + +@table @code +@kindex set radix +@item set radix @var{base} +Set the default base for numeric input and display. Supported choices +for @var{base} are decimal 8, 10, or 16. @var{base} must itself be +specified either unambiguously or using the current default radix; for +example, any of + +@example +set radix 012 +set radix 10. +set radix 0xa +@end example + +@noindent +will set the base to decimal. On the other hand, @samp{set radix 10} +will leave the radix unchanged no matter what it was. + +@kindex show radix +@item show radix +Display the current default base for numeric input and display. +@end table + +@node Messages/Warnings +@section Optional warnings and messages + +By default, @value{GDBN} is silent about its inner workings. If you are running +on a slow machine, you may want to use the @code{set verbose} command. +It will make @value{GDBN} tell you when it does a lengthy internal operation, so +you will not think it has crashed. + +Currently, the messages controlled by @code{set verbose} are those +which announce that the symbol table for a source file is being read; +see @code{symbol-file} in @ref{Files, ,Commands to specify files}. + +@table @code +@kindex set verbose +@item set verbose on +Enables @value{GDBN} output of certain informational messages. + +@item set verbose off +Disables @value{GDBN} output of certain informational messages. + +@kindex show verbose +@item show verbose +Displays whether @code{set verbose} is on or off. +@end table + +By default, if @value{GDBN} encounters bugs in the symbol table of an object +file, it is silent; but if you are debugging a compiler, you may find +this information useful (@pxref{Symbol Errors, ,Errors reading symbol files}). + +@table @code +@kindex set complaints +@item set complaints @var{limit} +Permits @value{GDBN} to output @var{limit} complaints about each type of unusual +symbols before becoming silent about the problem. Set @var{limit} to +zero to suppress all complaints; set it to a large number to prevent +complaints from being suppressed. + +@kindex show complaints +@item show complaints +Displays how many symbol complaints @value{GDBN} is permitted to produce. +@end table + +By default, @value{GDBN} is cautious, and asks what sometimes seems to be a +lot of stupid questions to confirm certain commands. For example, if +you try to run a program which is already running: + +@example +(@value{GDBP}) run +The program being debugged has been started already. +Start it from the beginning? (y or n) +@end example + +If you are willing to unflinchingly face the consequences of your own +commands, you can disable this ``feature'': + +@table @code +@kindex set confirm +@cindex flinching +@cindex confirmation +@cindex stupid questions +@item set confirm off +Disables confirmation requests. + +@item set confirm on +Enables confirmation requests (the default). + +@item show confirm +@kindex show confirm +Displays state of confirmation requests. +@end table + +@c FIXME this does not really belong here. But where *does* it belong? +@cindex reloading symbols +Some systems allow individual object files that make up your program to +be replaced without stopping and restarting your program. +@ifset VXWORKS +For example, in VxWorks you can simply recompile a defective object file +and keep on running. +@end ifset +If you are running on one of these systems, you can allow @value{GDBN} to +reload the symbols for automatically relinked modules: + +@table @code +@kindex set symbol-reloading +@item set symbol-reloading on +Replace symbol definitions for the corresponding source file when an +object file with a particular name is seen again. + +@item set symbol-reloading off +Do not replace symbol definitions when re-encountering object files of +the same name. This is the default state; if you are not running on a +system that permits automatically relinking modules, you should leave +@code{symbol-reloading} off, since otherwise @value{GDBN} may discard symbols +when linking large programs, that may contain several modules (from +different directories or libraries) with the same name. + +@item show symbol-reloading +Show the current @code{on} or @code{off} setting. +@end table + +@node Sequences +@chapter Canned Sequences of Commands + +Aside from breakpoint commands (@pxref{Break Commands, ,Breakpoint +command lists}), @value{GDBN} provides two ways to store sequences of commands +for execution as a unit: user-defined commands and command files. + +@menu +* Define:: User-defined commands +* Hooks:: User-defined command hooks +* Command Files:: Command files +* Output:: Commands for controlled output +@end menu + +@node Define +@section User-defined commands + +@cindex user-defined command +A @dfn{user-defined command} is a sequence of @value{GDBN} commands to which you +assign a new name as a command. This is done with the @code{define} +command. + +@table @code +@item define @var{commandname} +@kindex define +Define a command named @var{commandname}. If there is already a command +by that name, you are asked to confirm that you want to redefine it. + +The definition of the command is made up of other @value{GDBN} command lines, +which are given following the @code{define} command. The end of these +commands is marked by a line containing @code{end}. + +@item document @var{commandname} +@kindex document +Give documentation to the user-defined command @var{commandname}. The +command @var{commandname} must already be defined. This command reads +lines of documentation just as @code{define} reads the lines of the +command definition, ending with @code{end}. After the @code{document} +command is finished, @code{help} on command @var{commandname} will print +the documentation you have specified. + +You may use the @code{document} command again to change the +documentation of a command. Redefining the command with @code{define} +does not change the documentation. + +@item help user-defined +@kindex help user-defined +List all user-defined commands, with the first line of the documentation +(if any) for each. + +@item show user +@itemx show user @var{commandname} +@kindex show user +Display the @value{GDBN} commands used to define @var{commandname} (but not its +documentation). If no @var{commandname} is given, display the +definitions for all user-defined commands. +@end table + +User-defined commands do not take arguments. When they are executed, the +commands of the definition are not printed. An error in any command +stops execution of the user-defined command. + +Commands that would ask for confirmation if used interactively proceed +without asking when used inside a user-defined command. Many @value{GDBN} commands +that normally print messages to say what they are doing omit the messages +when used in a user-defined command. + +@node Hooks +@section User-defined command hooks +@cindex command files + +You may define @emph{hooks}, which are a special kind of user-defined +command. Whenever you run the command @samp{foo}, if the user-defined +command @samp{hook-foo} exists, it is executed (with no arguments) +before that command. + +In addition, a pseudo-command, @samp{stop} exists. Defining +(@samp{hook-stop}) makes the associated commands execute every time +execution stops in your program: before breakpoint commands are run, +displays are printed, or the stack frame is printed. + +@ifclear BARETARGET +For example, to ignore @code{SIGALRM} signals while +single-stepping, but treat them normally during normal execution, +you could define: + +@example +define hook-stop +handle SIGALRM nopass +end + +define hook-run +handle SIGALRM pass +end + +define hook-continue +handle SIGLARM pass +end +@end example +@end ifclear + +You can define a hook for any single-word command in @value{GDBN}, but +not for command aliases; you should define a hook for the basic command +name, e.g. @code{backtrace} rather than @code{bt}. +@c FIXME! So how does Joe User discover whether a command is an alias +@c or not? +If an error occurs during the execution of your hook, execution of +@value{GDBN} commands stops and @value{GDBN} issues a prompt +(before the command that you actually typed had a chance to run). + +If you try to define a hook which does not match any known command, you +will get a warning from the @code{define} command. + +@node Command Files +@section Command files + +@cindex command files +A command file for @value{GDBN} is a file of lines that are @value{GDBN} commands. Comments +(lines starting with @kbd{#}) may also be included. An empty line in a +command file does nothing; it does not mean to repeat the last command, as +it would from the terminal. + +@cindex init file +@cindex @file{@value{GDBINIT}} +When you start @value{GDBN}, it automatically executes commands from its +@dfn{init files}. These are files named @file{@value{GDBINIT}}. @value{GDBN} reads +the init file (if any) in your home directory and then the init file +(if any) in the current working directory. (The init files are not +executed if you use the @samp{-nx} option; @pxref{Mode Options, +,Choosing modes}.) + +@ifset GENERIC +@cindex init file name +On some configurations of @value{GDBN}, the init file is known by a +different name (these are typically environments where a specialized +form of GDB may need to coexist with other forms, hence a different name +for the specialized version's init file). These are the environments +with special init file names: + +@itemize @bullet +@kindex .vxgdbinit +@item +VxWorks (Wind River Systems real-time OS): @samp{.vxgdbinit} + +@kindex .os68gdbinit +@item +OS68K (Enea Data Systems real-time OS): @samp{.os68gdbinit} + +@kindex .esgdbinit +@item +ES-1800 (Ericsson Telecom AB M68000 emulator): @samp{.esgdbinit} +@end itemize +@end ifset + +You can also request the execution of a command file with the +@code{source} command: + +@table @code +@item source @var{filename} +@kindex source +Execute the command file @var{filename}. +@end table + +The lines in a command file are executed sequentially. They are not +printed as they are executed. An error in any command terminates execution +of the command file. + +Commands that would ask for confirmation if used interactively proceed +without asking when used in a command file. Many @value{GDBN} commands that +normally print messages to say what they are doing omit the messages +when called from command files. + +@node Output +@section Commands for controlled output + +During the execution of a command file or a user-defined command, normal +@value{GDBN} output is suppressed; the only output that appears is what is +explicitly printed by the commands in the definition. This section +describes three commands useful for generating exactly the output you +want. + +@table @code +@item echo @var{text} +@kindex echo +@c I do not consider backslash-space a standard C escape sequence +@c because it is not in ANSI. +Print @var{text}. Nonprinting characters can be included in +@var{text} using C escape sequences, such as @samp{\n} to print a +newline. @strong{No newline will be printed unless you specify one.} +In addition to the standard C escape sequences, a backslash followed +by a space stands for a space. This is useful for displaying a +string with spaces at the beginning or the end, since leading and +trailing spaces are otherwise trimmed from all arguments. +To print @samp{@w{ }and foo =@w{ }}, use the command +@samp{echo \@w{ }and foo = \@w{ }}. + +A backslash at the end of @var{text} can be used, as in C, to continue +the command onto subsequent lines. For example, + +@example +echo This is some text\n\ +which is continued\n\ +onto several lines.\n +@end example + +produces the same output as + +@example +echo This is some text\n +echo which is continued\n +echo onto several lines.\n +@end example + +@item output @var{expression} +@kindex output +Print the value of @var{expression} and nothing but that value: no +newlines, no @samp{$@var{nn} = }. The value is not entered in the +value history either. @xref{Expressions, ,Expressions}, for more information on +expressions. + +@item output/@var{fmt} @var{expression} +Print the value of @var{expression} in format @var{fmt}. You can use +the same formats as for @code{print}. @xref{Output Formats,,Output +formats}, for more information. + +@item printf @var{string}, @var{expressions}@dots{} +@kindex printf +Print the values of the @var{expressions} under the control of +@var{string}. The @var{expressions} are separated by commas and may be +either numbers or pointers. Their values are printed as specified by +@var{string}, exactly as if your program were to execute the C +subroutine + +@example +printf (@var{string}, @var{expressions}@dots{}); +@end example + +For example, you can print two values in hex like this: + +@smallexample +printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo +@end smallexample + +The only backslash-escape sequences that you can use in the format +string are the simple ones that consist of backslash followed by a +letter. +@end table + +@ifclear DOSHOST +@node Emacs +@chapter Using @value{GDBN} under GNU Emacs + +@cindex emacs +A special interface allows you to use GNU Emacs to view (and +edit) the source files for the program you are debugging with +@value{GDBN}. + +To use this interface, use the command @kbd{M-x gdb} in Emacs. Give the +executable file you want to debug as an argument. This command starts +@value{GDBN} as a subprocess of Emacs, with input and output through a newly +created Emacs buffer. + +Using @value{GDBN} under Emacs is just like using @value{GDBN} normally except for two +things: + +@itemize @bullet +@item +All ``terminal'' input and output goes through the Emacs buffer. +@end itemize + +This applies both to @value{GDBN} commands and their output, and to the input +and output done by the program you are debugging. + +This is useful because it means that you can copy the text of previous +commands and input them again; you can even use parts of the output +in this way. + +All the facilities of Emacs' Shell mode are available for interacting +with your program. In particular, you can send signals the usual +way---for example, @kbd{C-c C-c} for an interrupt, @kbd{C-c C-z} for a +stop. + +@itemize @bullet +@item +@value{GDBN} displays source code through Emacs. +@end itemize + +Each time @value{GDBN} displays a stack frame, Emacs automatically finds the +source file for that frame and puts an arrow (@samp{=>}) at the +left margin of the current line. Emacs uses a separate buffer for +source display, and splits the screen to show both your @value{GDBN} session +and the source. + +Explicit @value{GDBN} @code{list} or search commands still produce output as +usual, but you probably will have no reason to use them. + +@quotation +@emph{Warning:} If the directory where your program resides is not your +current directory, it can be easy to confuse Emacs about the location of +the source files, in which case the auxiliary display buffer will not +appear to show your source. @value{GDBN} can find programs by searching your +environment's @code{PATH} variable, so the @value{GDBN} input and output +session will proceed normally; but Emacs does not get enough information +back from @value{GDBN} to locate the source files in this situation. To +avoid this problem, either start @value{GDBN} mode from the directory where +your program resides, or specify a full path name when prompted for the +@kbd{M-x gdb} argument. + +A similar confusion can result if you use the @value{GDBN} @code{file} command to +switch to debugging a program in some other location, from an existing +@value{GDBN} buffer in Emacs. +@end quotation + +By default, @kbd{M-x gdb} calls the program called @file{gdb}. If +you need to call @value{GDBN} by a different name (for example, if you keep +several configurations around, with different names) you can set the +Emacs variable @code{gdb-command-name}; for example, + +@example +(setq gdb-command-name "mygdb") +@end example + +@noindent +(preceded by @kbd{ESC ESC}, or typed in the @code{*scratch*} buffer, or +in your @file{.emacs} file) will make Emacs call the program named +``@code{mygdb}'' instead. + +In the @value{GDBN} I/O buffer, you can use these special Emacs commands in +addition to the standard Shell mode commands: + +@table @kbd +@item C-h m +Describe the features of Emacs' @value{GDBN} Mode. + +@item M-s +Execute to another source line, like the @value{GDBN} @code{step} command; also +update the display window to show the current file and location. + +@item M-n +Execute to next source line in this function, skipping all function +calls, like the @value{GDBN} @code{next} command. Then update the display window +to show the current file and location. + +@item M-i +Execute one instruction, like the @value{GDBN} @code{stepi} command; update +display window accordingly. + +@item M-x gdb-nexti +Execute to next instruction, using the @value{GDBN} @code{nexti} command; update +display window accordingly. + +@item C-c C-f +Execute until exit from the selected stack frame, like the @value{GDBN} +@code{finish} command. + +@item M-c +Continue execution of your program, like the @value{GDBN} @code{continue} +command. + +@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-p}. + +@item M-u +Go up the number of frames indicated by the numeric argument +(@pxref{Arguments, , Numeric Arguments, emacs, The GNU Emacs Manual}), +like the @value{GDBN} @code{up} command. + +@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-u}. + +@item M-d +Go down the number of frames indicated by the numeric argument, like the +@value{GDBN} @code{down} command. + +@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-d}. + +@item C-x & +Read the number where the cursor is positioned, and insert it at the end +of the @value{GDBN} I/O buffer. For example, if you wish to disassemble code +around an address that was displayed earlier, type @kbd{disassemble}; +then move the cursor to the address display, and pick up the +argument for @code{disassemble} by typing @kbd{C-x &}. + +You can customize this further by defining elements of the list +@code{gdb-print-command}; once it is defined, you can format or +otherwise process numbers picked up by @kbd{C-x &} before they are +inserted. A numeric argument to @kbd{C-x &} will both indicate that you +wish special formatting, and act as an index to pick an element of the +list. If the list element is a string, the number to be inserted is +formatted using the Emacs function @code{format}; otherwise the number +is passed as an argument to the corresponding list element. +@end table + +In any source file, the Emacs command @kbd{C-x SPC} (@code{gdb-break}) +tells @value{GDBN} to set a breakpoint on the source line point is on. + +If you accidentally delete the source-display buffer, an easy way to get +it back is to type the command @code{f} in the @value{GDBN} buffer, to +request a frame display; when you run under Emacs, this will recreate +the source buffer if necessary to show you the context of the current +frame. + +The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit +the files with these buffers if you wish; but keep in mind that @value{GDBN} +communicates with Emacs in terms of line numbers. If you add or +delete lines from the text, the line numbers that @value{GDBN} knows will cease +to correspond properly with the code. + +@c The following dropped because Epoch is nonstandard. Reactivate +@c if/when v19 does something similar. ---pesch@cygnus.com 19dec1990 +@ignore +@kindex emacs epoch environment +@kindex epoch +@kindex inspect + +Version 18 of Emacs has a built-in window system called the @code{epoch} +environment. Users of this environment can use a new command, +@code{inspect} which performs identically to @code{print} except that +each value is printed in its own window. +@end ignore +@end ifclear + +@ifset LUCID +@node Energize +@chapter Using @value{GDBN} with Energize + +@cindex Energize +The Energize Programming System is an integrated development environment +that includes a point-and-click interface to many programming tools. +When you use @value{GDBN} in this environment, you can use the standard +Energize graphical interface to drive @value{GDBN}; you can also, if you +choose, type @value{GDBN} commands as usual in a debugging window. Even if +you use the graphical interface, the debugging window (which uses Emacs, +and resembles the standard Emacs interface to @value{GDBN}) displays the +equivalent commands, so that the history of your debugging session is +properly reflected. + +When Energize starts up a @value{GDBN} session, it uses one of the +command-line options @samp{-energize} or @samp{-cadillac} (``cadillac'' +is the name of the communications protocol used by the Energize system). +This option makes @value{GDBN} run as one of the tools in the Energize Tool +Set: it sends all output to the Energize kernel, and accept input from +it as well. + +See the user manual for the Energize Programming System for +information on how to use the Energize graphical interface and the other +development tools that Energize integrates with @value{GDBN}. + +@end ifset + +@node GDB Bugs +@chapter Reporting Bugs in @value{GDBN} +@cindex bugs in @value{GDBN} +@cindex reporting bugs in @value{GDBN} + +Your bug reports play an essential role in making @value{GDBN} reliable. + +Reporting a bug may help you by bringing a solution to your problem, or it +may not. But in any case the principal function of a bug report is to help +the entire community by making the next version of @value{GDBN} work better. Bug +reports are your contribution to the maintenance of @value{GDBN}. + +In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +@menu +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs +@end menu + +@node Bug Criteria +@section Have you found a bug? +@cindex bug criteria + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@item +@cindex fatal signal +@cindex debugger crash +@cindex crash of debugger +If the debugger gets a fatal signal, for any input whatever, that is a +@value{GDBN} bug. Reliable debuggers never crash. + +@item +@cindex error on valid input +If @value{GDBN} produces an error message for valid input, that is a bug. + +@item +@cindex invalid input +If @value{GDBN} does not produce an error message for invalid input, +that is a bug. However, you should note that your idea of +``invalid input'' might be our idea of ``an extension'' or ``support +for traditional practice''. + +@item +If you are an experienced user of debugging tools, your suggestions +for improvement of @value{GDBN} are welcome in any case. +@end itemize + +@node Bug Reporting +@section How to report bugs +@cindex bug reports +@cindex @value{GDBN} bugs, reporting + +A number of companies and individuals offer support for GNU products. +If you obtained @value{GDBN} from a support organization, we recommend you +contact that organization first. + +You can find contact information for many support companies and +individuals in the file @file{etc/SERVICE} in the GNU Emacs +distribution. + +In any event, we also recommend that you send bug reports for @value{GDBN} to one +of these addresses: + +@example +bug-gdb@@prep.ai.mit.edu +@{ucbvax|mit-eddie|uunet@}!prep.ai.mit.edu!bug-gdb +@end example + +@strong{Do not send bug reports to @samp{info-gdb}, or to +@samp{help-gdb}, or to any newsgroups.} Most users of @value{GDBN} do not want to +receive bug reports. Those that do, have arranged to receive @samp{bug-gdb}. + +The mailing list @samp{bug-gdb} has a newsgroup @samp{gnu.gdb.bug} which +serves as a repeater. The mailing list and the newsgroup carry exactly +the same messages. Often people think of posting bug reports to the +newsgroup instead of mailing them. This appears to work, but it has one +problem which can be crucial: a newsgroup posting often lacks a mail +path back to the sender. Thus, if we need to ask for more information, +we may be unable to reach you. For this reason, it is better to send +bug reports to the mailing list. + +As a last resort, send bug reports on paper to: + +@example +GNU Debugger Bugs +Free Software Foundation +545 Tech Square +Cambridge, MA 02139 +@end example + +The fundamental principle of reporting bugs usefully is this: +@strong{report all the facts}. If you are not sure whether to state a +fact or leave it out, state it! + +Often people omit facts because they think they know what causes the +problem and assume that some details do not matter. Thus, you might +assume that the name of the variable you use in an example does not matter. +Well, probably it does not, but one cannot be sure. Perhaps the bug is a +stray memory reference which happens to fetch from the location where that +name is stored in memory; perhaps, if the name were different, the contents +of that location would fool the debugger into doing the right thing despite +the bug. Play it safe and give a specific, complete example. That is the +easiest thing for you to do, and the most helpful. + +Keep in mind that the purpose of a bug report is to enable us to fix +the bug if it is new to us. It is not as important as what happens if +the bug is already known. Therefore, always write your bug reports on +the assumption that the bug has not been reported previously. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' Those bug reports are useless, and we urge everyone to +@emph{refuse to respond to them} except to chide the sender to report +bugs properly. + +To enable us to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of @value{GDBN}. @value{GDBN} announces it if you start with no +arguments; you can also print it at any time using @code{show version}. + +Without this, we will not know whether there is any point in looking for +the bug in the current version of @value{GDBN}. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +What compiler (and its version) was used to compile @value{GDBN}---e.g. +``@value{GCC}--2.0''. + +@item +What compiler (and its version) was used to compile the program you +are debugging---e.g. ``@value{GCC}--2.0''. + +@item +The command arguments you gave the compiler to compile your example and +observe the bug. For example, did you use @samp{-O}? To guarantee +you will not omit something important, list them all. A copy of the +Makefile (or the output from make) is sufficient. + +If we were to try to guess the arguments, we would probably guess wrong +and then we might not encounter the bug. + +@item +A complete input script, and all necessary source files, that will +reproduce the bug. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal.'' + +Of course, if the bug is that @value{GDBN} gets a fatal signal, then we will +certainly notice it. But if the bug is incorrect output, we might not +notice unless it is glaringly wrong. We are human, after all. You +might as well not give us a chance to make a mistake. + +Even if the problem you experience is a fatal signal, you should still +say so explicitly. Suppose something strange is going on, such as, +your copy of @value{GDBN} is out of synch, or you have encountered a +bug in the C library on your system. (This has happened!) Your copy +might crash and ours would not. If you told us to expect a crash, +then when ours fails to crash, we would know that the bug was not +happening for us. If you had not told us to expect a crash, then we +would not be able to draw any conclusion from our observations. + +@item +If you wish to suggest changes to the @value{GDBN} source, send us context +diffs. If you even discuss something in the @value{GDBN} source, refer to +it by context, not by line number. + +The line numbers in our development sources will not match those in your +sources. Your line numbers would convey no useful information to us. +@end itemize + +Here are some things that are not necessary: + +@itemize @bullet +@item +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating +which changes to the input file will make the bug go away and which +changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +We recommend that you save your time for something else. + +Of course, if you can find a simpler example to report @emph{instead} +of the original one, that is a convenience for us. Errors in the +output will be easier to spot, running under the debugger will take +less time, etc. + +However, simplification is not vital; if you do not want to do this, +report the bug anyway and send us the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help us if it is a good one. But do not omit +the necessary information, such as the test case, on the assumption that +a patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand it at all. + +Sometimes with a program as complicated as @value{GDBN} it is very hard to +construct an example that will make the program follow a certain path +through the code. If you do not send us the example, we will not be able +to construct one, so we will not be able to verify that the bug is fixed. + +And if we cannot understand what bug you are trying to fix, or why your +patch should be an improvement, we will not install it. A test case will +help us to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even we cannot guess right about such +things without first using the debugger to find the facts. +@end itemize + +@c The readline documentation is distributed with the readline code +@c and consists of the two following files: +@c rluser.texinfo +@c inc-hist.texi +@c Use -I with makeinfo to point to the appropriate directory, +@c environment var TEXINPUTS with TeX. +@include rluser.texinfo +@include inc-hist.texi + +@ifset NOVEL +@node Renamed Commands +@appendix Renamed Commands + +The following commands were renamed in GDB 4, in order to make the +command set as a whole more consistent and easier to use and remember: + +@kindex add-syms +@kindex delete environment +@kindex info copying +@kindex info convenience +@kindex info directories +@kindex info editing +@kindex info history +@kindex info targets +@kindex info values +@kindex info version +@kindex info warranty +@kindex set addressprint +@kindex set arrayprint +@kindex set prettyprint +@kindex set screen-height +@kindex set screen-width +@kindex set unionprint +@kindex set vtblprint +@kindex set demangle +@kindex set asm-demangle +@kindex set sevenbit-strings +@kindex set array-max +@kindex set caution +@kindex set history write +@kindex show addressprint +@kindex show arrayprint +@kindex show prettyprint +@kindex show screen-height +@kindex show screen-width +@kindex show unionprint +@kindex show vtblprint +@kindex show demangle +@kindex show asm-demangle +@kindex show sevenbit-strings +@kindex show array-max +@kindex show caution +@kindex show history write +@kindex unset + +@c TEXI2ROFF-KILL +@ifinfo +@c END TEXI2ROFF-KILL +@example +OLD COMMAND NEW COMMAND +@c TEXI2ROFF-KILL +--------------- ------------------------------- +@c END TEXI2ROFF-KILL +add-syms add-symbol-file +delete environment unset environment +info convenience show convenience +info copying show copying +info directories show directories +info editing show commands +info history show values +info targets help target +info values show values +info version show version +info warranty show warranty +set/show addressprint set/show print address +set/show array-max set/show print elements +set/show arrayprint set/show print array +set/show asm-demangle set/show print asm-demangle +set/show caution set/show confirm +set/show demangle set/show print demangle +set/show history write set/show history save +set/show prettyprint set/show print pretty +set/show screen-height set/show height +set/show screen-width set/show width +set/show sevenbit-strings set/show print sevenbit-strings +set/show unionprint set/show print union +set/show vtblprint set/show print vtbl + +unset [No longer an alias for delete] +@end example +@c TEXI2ROFF-KILL +@end ifinfo + +@tex +\vskip \parskip\vskip \baselineskip +\halign{\tt #\hfil &\qquad#&\tt #\hfil\cr +{\bf Old Command} &&{\bf New Command}\cr +add-syms &&add-symbol-file\cr +delete environment &&unset environment\cr +info convenience &&show convenience\cr +info copying &&show copying\cr +info directories &&show directories \cr +info editing &&show commands\cr +info history &&show values\cr +info targets &&help target\cr +info values &&show values\cr +info version &&show version\cr +info warranty &&show warranty\cr +set{\rm / }show addressprint &&set{\rm / }show print address\cr +set{\rm / }show array-max &&set{\rm / }show print elements\cr +set{\rm / }show arrayprint &&set{\rm / }show print array\cr +set{\rm / }show asm-demangle &&set{\rm / }show print asm-demangle\cr +set{\rm / }show caution &&set{\rm / }show confirm\cr +set{\rm / }show demangle &&set{\rm / }show print demangle\cr +set{\rm / }show history write &&set{\rm / }show history save\cr +set{\rm / }show prettyprint &&set{\rm / }show print pretty\cr +set{\rm / }show screen-height &&set{\rm / }show height\cr +set{\rm / }show screen-width &&set{\rm / }show width\cr +set{\rm / }show sevenbit-strings &&set{\rm / }show print sevenbit-strings\cr +set{\rm / }show unionprint &&set{\rm / }show print union\cr +set{\rm / }show vtblprint &&set{\rm / }show print vtbl\cr +\cr +unset &&\rm(No longer an alias for delete)\cr +} +@end tex +@c END TEXI2ROFF-KILL +@end ifset + +@ifclear PRECONFIGURED +@node Formatting Documentation +@appendix Formatting Documentation + +@cindex GDB reference card +@cindex reference card +The GDB 4 release includes an already-formatted reference card, ready +for printing with PostScript or GhostScript, in the @file{gdb} +subdirectory of the main source directory@footnote{In +@file{gdb-@value{GDBVN}/gdb/refcard.ps} of the version @value{GDBVN} +release.}. If you can use PostScript or GhostScript with your printer, +you can print the reference card immediately with @file{refcard.ps}. + +The release also includes the source for the reference card. You +can format it, using @TeX{}, by typing: + +@example +make refcard.dvi +@end example + +The GDB reference card is designed to print in landscape mode on US +``letter'' size paper; that is, on a sheet 11 inches wide by 8.5 inches +high. You will need to specify this form of printing as an option to +your @sc{dvi} output program. + +@cindex documentation + +All the documentation for GDB comes as part of the machine-readable +distribution. The documentation is written in Texinfo format, which is +a documentation system that uses a single source file to produce both +on-line information and a printed manual. You can use one of the Info +formatting commands to create the on-line version of the documentation +and @TeX{} (or @code{texi2roff}) to typeset the printed version. + +GDB includes an already formatted copy of the on-line Info version of +this manual in the @file{gdb} subdirectory. The main Info file is +@file{gdb-@var{version-number}/gdb/gdb.info}, and it refers to +subordinate files matching @samp{gdb.info*} in the same directory. If +necessary, you can print out these files, or read them with any editor; +but they are easier to read using the @code{info} subsystem in GNU Emacs +or the standalone @code{info} program, available as part of the GNU +Texinfo distribution. + +If you want to format these Info files yourself, you need one of the +Info formatting programs, such as @code{texinfo-format-buffer} or +@code{makeinfo}. + +If you have @code{makeinfo} installed, and are in the top level GDB +source directory (@file{gdb-@value{GDBVN}}, in the case of version @value{GDBVN}), you can +make the Info file by typing: + +@example +cd gdb +make gdb.info +@end example + +If you want to typeset and print copies of this manual, you need @TeX{}, +a program to print its @sc{dvi} output files, and @file{texinfo.tex}, the +Texinfo definitions file. + +@TeX{} is a typesetting program; it does not print files directly, but +produces output files called @sc{dvi} files. To print a typeset +document, you need a program to print @sc{dvi} files. If your system +has @TeX{} installed, chances are it has such a program. The precise +command to use depends on your system; @kbd{lpr -d} is common; another +(for PostScript devices) is @kbd{dvips}. The @sc{dvi} print command may +require a file name without any extension or a @samp{.dvi} extension. + +@TeX{} also requires a macro definitions file called +@file{texinfo.tex}. This file tells @TeX{} how to typeset a document +written in Texinfo format. On its own, @TeX{} cannot read, much less +typeset a Texinfo file. @file{texinfo.tex} is distributed with GDB +and is located in the @file{gdb-@var{version-number}/texinfo} +directory. + +If you have @TeX{} and a @sc{dvi} printer program installed, you can +typeset and print this manual. First switch to the the @file{gdb} +subdirectory of the main source directory (for example, to +@file{gdb-@value{GDBVN}/gdb}) and then type: + +@example +make gdb.dvi +@end example + +@node Installing GDB +@appendix Installing GDB +@cindex configuring GDB +@cindex installation + +GDB comes with a @code{configure} script that automates the process +of preparing GDB for installation; you can then use @code{make} to +build the @code{gdb} program. +@iftex +@c irrelevant in info file; it's as current as the code it lives with. +@footnote{If you have a more recent version of GDB than @value{GDBVN}, +look at the @file{README} file in the sources; we may have improved the +installation procedures since publishing this manual.} +@end iftex + +The GDB distribution includes all the source code you need for GDB in +a single directory, whose name is usually composed by appending the +version number to @samp{gdb}. + +For example, the GDB version @value{GDBVN} distribution is in the +@file{gdb-@value{GDBVN}} directory. That directory contains: + +@table @code +@item gdb-@value{GDBVN}/configure @r{(and supporting files)} +script for configuring GDB and all its supporting libraries. + +@item gdb-@value{GDBVN}/gdb +the source specific to GDB itself + +@item gdb-@value{GDBVN}/bfd +source for the Binary File Descriptor library + +@item gdb-@value{GDBVN}/include +GNU include files + +@item gdb-@value{GDBVN}/libiberty +source for the @samp{-liberty} free software library + +@item gdb-@value{GDBVN}/opcodes +source for the library of opcode tables and disassemblers + +@item gdb-@value{GDBVN}/readline +source for the GNU command-line interface + +@item gdb-@value{GDBVN}/glob +source for the GNU filename pattern-matching subroutine + +@item gdb-@value{GDBVN}/mmalloc +source for the GNU memory-mapped malloc package +@end table + +The simplest way to configure and build GDB is to run @code{configure} +from the @file{gdb-@var{version-number}} source directory, which in +this example is the @file{gdb-@value{GDBVN}} directory. + +First switch to the @file{gdb-@var{version-number}} source directory +if you are not already in it; then run @code{configure}. Pass the +identifier for the platform on which GDB will run as an +argument. + +For example: + +@example +cd gdb-@value{GDBVN} +./configure @var{host} +make +@end example + +@noindent +where @var{host} is an identifier such as @samp{sun4} or +@samp{decstation}, that identifies the platform where GDB will run. +(You can often leave off @var{host}; @code{configure} tries to guess the +correct value by examining your system.) + +Running @samp{configure @var{host}} and then running @code{make} builds the +@file{bfd}, @file{readline}, @file{mmalloc}, and @file{libiberty} +libraries, then @code{gdb} itself. The configured source files, and the +binaries, are left in the corresponding source directories. + +@code{configure} is a Bourne-shell (@code{/bin/sh}) script; if your +system does not recognize this automatically when you run a different +shell, you may need to run @code{sh} on it explicitly: + +@example +sh configure @var{host} +@end example + +If you run @code{configure} from a directory that contains source +directories for multiple libraries or programs, such as the +@file{gdb-@value{GDBVN}} source directory for version @value{GDBVN}, @code{configure} +creates configuration files for every directory level underneath (unless +you tell it not to, with the @samp{--norecursion} option). + +You can run the @code{configure} script from any of the +subordinate directories in the GDB distribution if you only want to +configure that subdirectory, but be sure to specify a path to it. + +For example, with version @value{GDBVN}, type the following to configure only +the @code{bfd} subdirectory: + +@example +@group +cd gdb-@value{GDBVN}/bfd +../configure @var{host} +@end group +@end example + +You can install @code{@value{GDBP}} anywhere; it has no hardwired paths. +However, you should make sure that the shell on your path (named by +the @samp{SHELL} environment variable) is publicly readable. Remember +that GDB uses the shell to start your program---some systems refuse to +let GDB debug child processes whose programs are not readable. + +@menu +* Separate Objdir:: Compiling GDB in another directory +* Config Names:: Specifying names for hosts and targets +* configure Options:: Summary of options for configure +@end menu + +@node Separate Objdir +@section Compiling GDB in another directory + +If you want to run GDB versions for several host or target machines, +you need a different @code{gdb} compiled for each combination of +host and target. @code{configure} is designed to make this easy by +allowing you to generate each configuration in a separate subdirectory, +rather than in the source directory. If your @code{make} program +handles the @samp{VPATH} feature (GNU @code{make} does), running +@code{make} in each of these directories builds the @code{gdb} +program specified there. + +To build @code{gdb} in a separate directory, run @code{configure} +with the @samp{--srcdir} option to specify where to find the source. +(You also need to specify a path to find @code{configure} +itself from your working directory. If the path to @code{configure} +would be the same as the argument to @samp{--srcdir}, you can leave out +the @samp{--srcdir} option; it will be assumed.) + +For example, with version @value{GDBVN}, you can build GDB in a separate +directory for a Sun 4 like this: + +@example +@group +cd gdb-@value{GDBVN} +mkdir ../gdb-sun4 +cd ../gdb-sun4 +../gdb-@value{GDBVN}/configure sun4 +make +@end group +@end example + +When @code{configure} builds a configuration using a remote source +directory, it creates a tree for the binaries with the same structure +(and using the same names) as the tree under the source directory. In +the example, you'd find the Sun 4 library @file{libiberty.a} in the +directory @file{gdb-sun4/libiberty}, and GDB itself in +@file{gdb-sun4/gdb}. + +One popular reason to build several GDB configurations in separate +directories is to configure GDB for cross-compiling (where GDB +runs on one machine---the host---while debugging programs that run on +another machine---the target). You specify a cross-debugging target by +giving the @samp{--target=@var{target}} option to @code{configure}. + +When you run @code{make} to build a program or library, you must run +it in a configured directory---whatever directory you were in when you +called @code{configure} (or one of its subdirectories). + +The @code{Makefile} that @code{configure} generates in each source +directory also runs recursively. If you type @code{make} in a source +directory such as @file{gdb-@value{GDBVN}} (or in a separate configured +directory configured with @samp{--srcdir=@var{path}/gdb-@value{GDBVN}}), you +will build all the required libraries, and then build GDB. + +When you have multiple hosts or targets configured in separate +directories, you can run @code{make} on them in parallel (for example, +if they are NFS-mounted on each of the hosts); they will not interfere +with each other. + +@node Config Names +@section Specifying names for hosts and targets + +The specifications used for hosts and targets in the @code{configure} +script are based on a three-part naming scheme, but some short predefined +aliases are also supported. The full naming scheme encodes three pieces +of information in the following pattern: + +@example +@var{architecture}-@var{vendor}-@var{os} +@end example + +For example, you can use the alias @code{sun4} as a @var{host} argument, +or as the value for @var{target} in a @code{--target=@var{target}} +option. The equivalent full name is @samp{sparc-sun-sunos4}. + +The @code{configure} script accompanying GDB does not provide +any query facility to list all supported host and target names or +aliases. @code{configure} calls the Bourne shell script +@code{config.sub} to map abbreviations to full names; you can read the +script, if you wish, or you can use it to test your guesses on +abbreviations---for example: + +@smallexample +% sh config.sub sun4 +sparc-sun-sunos4.1.1 +% sh config.sub sun3 +m68k-sun-sunos4.1.1 +% sh config.sub decstation +mips-dec-ultrix4.2 +% sh config.sub hp300bsd +m68k-hp-bsd +% sh config.sub i386v +i386-unknown-sysv +% sh config.sub i786v +Invalid configuration `i786v': machine `i786v' not recognized +@end smallexample + +@noindent +@code{config.sub} is also distributed in the GDB source +directory (@file{gdb-@value{GDBVN}}, for version @value{GDBVN}). + +@node configure Options +@section @code{configure} options + +Here is a summary of the @code{configure} options and arguments that +are most often useful for building @value{GDBN}. @code{configure} also has +several other options not listed here. @inforef{What Configure +Does,,configure.info}, for a full explanation of @code{configure}. +@c FIXME: Would this be more, or less, useful as an xref (ref to printed +@c manual in the printed manual, ref to info file only from the info file)? + +@example +configure @r{[}--help@r{]} + @r{[}--prefix=@var{dir}@r{]} + @r{[}--srcdir=@var{path}@r{]} + @r{[}--norecursion@r{]} @r{[}--rm@r{]} + @r{[}--target=@var{target}@r{]} @var{host} +@end example + +@noindent +You may introduce options with a single @samp{-} rather than +@samp{--} if you prefer; but you may abbreviate option names if you use +@samp{--}. + +@table @code +@item --help +Display a quick summary of how to invoke @code{configure}. + +@item -prefix=@var{dir} +Configure the source to install programs and files under directory +@file{@var{dir}}. + +@item --srcdir=@var{path} +@strong{Warning: using this option requires GNU @code{make}, or another +@code{make} that implements the @code{VPATH} feature.}@* +Use this option to make configurations in directories separate from the +GDB source directories. Among other things, you can use this to +build (or maintain) several configurations simultaneously, in separate +directories. @code{configure} writes configuration specific files in +the current directory, but arranges for them to use the source in the +directory @var{path}. @code{configure} will create directories under +the working directory in parallel to the source directories below +@var{path}. + +@item --norecursion +Configure only the directory level where @code{configure} is executed; do not +propagate configuration to subdirectories. + +@item --rm +@emph{Remove} files otherwise built during configuration. + +@c This does not work (yet if ever). FIXME. +@c @item --parse=@var{lang} @dots{} +@c Configure the GDB expression parser to parse the listed languages. +@c @samp{all} configures GDB for all supported languages. To get a +@c list of all supported languages, omit the argument. Without this +@c option, GDB is configured to parse all supported languages. + +@item --target=@var{target} +Configure GDB for cross-debugging programs running on the specified +@var{target}. Without this option, GDB is configured to debug +programs that run on the same machine (@var{host}) as GDB itself. + +There is no convenient way to generate a list of all available targets. + +@item @var{host} @dots{} +Configure GDB to run on the specified @var{host}. + +There is no convenient way to generate a list of all available hosts. +@end table + +@noindent +@code{configure} accepts other options, for compatibility with +configuring other GNU tools recursively; but these are the only +options that affect GDB or its supporting libraries. +@end ifclear + +@node Index +@unnumbered Index + +@printindex cp + +@tex +% I think something like @colophon should be in texinfo. In the +% meantime: +\long\def\colophon{\hbox to0pt{}\vfill +\centerline{The body of this manual is set in} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/},} +\centerline{{\bf\fontname\tenbf}, and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: pesch@cygnus.com, 1991. +@end tex + +@contents +@bye diff --git a/gnu/usr.bin/gdb/doc/gdbint.texinfo b/gnu/usr.bin/gdb/doc/gdbint.texinfo new file mode 100644 index 00000000000..a2f625771e9 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/gdbint.texinfo @@ -0,0 +1,2658 @@ +\input texinfo +@setfilename gdbint.info +@c $Id: gdbint.texinfo,v 1.1.1.1 1993/10/30 21:59:41 jkh Exp $ + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Gdb-Internals: (gdbint). The GNU debugger's internals. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents the internals of the GNU debugger GDB. + +Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. +Contributed by Cygnus Support. Written by John Gilmore. + +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. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy or distribute modified versions of this +manual under the terms of the GPL (for which purpose this text may be +regarded as a program in the language TeX). +@end ifinfo + +@setchapternewpage off +@settitle GDB Internals +@titlepage +@title{Working in GDB} +@subtitle{A guide to the internals of the GNU debugger} +@author John Gilmore +@author Cygnus Support +@page +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 1.1.1.1 $} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +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. + +@end titlepage + +@node Top +@c Perhaps this should be the title of the document (but only for info, +@c not for TeX). Existing GNU manuals seem inconsistent on this point. +@top Scope of this Document + +This document documents the internals of the GNU debugger, GDB. It is +intended to document aspects of GDB which apply across many different +parts of GDB (for example, @pxref{Coding Style}), or which are global +aspects of design (for example, what are the major modules and which +files document them in detail?). Information which pertains to specific +data structures, functions, variables, etc., should be put in comments +in the source code, not here. It is more likely to get noticed and kept +up to date there. Some of the information in this document should +probably be moved into comments. + +@menu +* README:: The README File +* Getting Started:: Getting started working on GDB +* Debugging GDB:: Debugging GDB with itself +* New Architectures:: Defining a New Host or Target Architecture +* Config:: Adding a New Configuration +* Host:: Adding a New Host +* Native:: Adding a New Native Configuration +* Target:: Adding a New Target +* Languages:: Defining New Source Languages +* Releases:: Configuring GDB for Release +* Partial Symbol Tables:: How GDB reads symbols quickly at startup +* Types:: How GDB keeps track of types +* BFD support for GDB:: How BFD and GDB interface +* Symbol Reading:: Defining New Symbol Readers +* Cleanups:: Cleanups +* Wrapping:: Wrapping Output Lines +* Frames:: Keeping track of function calls +* Remote Stubs:: Code that runs in targets and talks to GDB +* Longjmp Support:: Stepping through longjmp's in the target +* Coding Style:: Strunk and White for GDB maintainers +* Clean Design:: Frank Lloyd Wright for GDB maintainers +* Submitting Patches:: How to get your changes into GDB releases +* Host Conditionals:: What features exist in the host +* Target Conditionals:: What features exist in the target +* Native Conditionals:: Conditionals for when host and target are same +* Obsolete Conditionals:: Conditionals that don't exist any more +* XCOFF:: The Object file format used on IBM's RS/6000 +@end menu + +@node README +@chapter The @file{README} File + +Check the @file{README} file, it often has useful information that does not +appear anywhere else in the directory. + +@node Getting Started +@chapter Getting Started Working on GDB + +GDB is a large and complicated program, and if you first starting to +work on it, it can be hard to know where to start. Fortunately, if you +know how to go about it, there are ways to figure out what is going on: + +@itemize @bullet +@item +This manual, the GDB Internals manual, has information which applies +generally to many parts of GDB. + +@item +Information about particular functions or data structures are located in +comments with those functions or data structures. If you run across a +function or a global variable which does not have a comment correctly +explaining what is does, this can be thought of as a bug in GDB; feel +free to submit a bug report, with a suggested comment if you can figure +out what the comment should say (@pxref{Submitting Patches}). If you +find a comment which is actually wrong, be especially sure to report that. + +Comments explaining the function of macros defined in host, target, or +native dependent files can be in several places. Sometimes they are +repeated every place the macro is defined. Sometimes they are where the +macro is used. Sometimes there is a header file which supplies a +default definition of the macro, and the comment is there. This manual +also has a list of macros (@pxref{Host Conditionals}, @pxref{Target +Conditionals}, @pxref{Native Conditionals}, and @pxref{Obsolete +Conditionals}) with some documentation. + +@item +Start with the header files. Once you some idea of how GDB's internal +symbol tables are stored (see @file{symtab.h}, @file{gdbtypes.h}), you +will find it much easier to understand the code which uses and creates +those symbol tables. + +@item +You may wish to process the information you are getting somehow, to +enhance your understanding of it. Summarize it, translate it to another +language, add some (perhaps trivial or non-useful) feature to GDB, use +the code to predict what a test case would do and write the test case +and verify your prediction, etc. If you are reading code and your eyes +are starting to glaze over, this is a sign you need to use a more active +approach. + +@item +Once you have a part of GDB to start with, you can find more +specifically the part you are looking for by stepping through each +function with the @code{next} command. Do not use @code{step} or you +will quickly get distracted; when the function you are stepping through +calls another function try only to get a big-picture understanding +(perhaps using the comment at the beginning of the function being +called) of what it does. This way you can identify which of the +functions being called by the function you are stepping through is the +one which you are interested in. You may need to examine the data +structures generated at each stage, with reference to the comments in +the header files explaining what the data structures are supposed to +look like. + +Of course, this same technique can be used if you are just reading the +code, rather than actually stepping through it. The same general +principle applies---when the code you are looking at calls something +else, just try to understand generally what the code being called does, +rather than worrying about all its details. + +@item +A good place to start when tracking down some particular area is with a +command which invokes that feature. Suppose you want to know how +single-stepping works. As a GDB user, you know that the @code{step} +command invokes single-stepping. The command is invoked via command +tables (see @file{command.h}); by convention the function which actually +performs the command is formed by taking the name of the command and +adding @samp{_command}, or in the case of an @code{info} subcommand, +@samp{_info}. For example, the @code{step} command invokes the +@code{step_command} function and the @code{info display} command invokes +@code{display_info}. When this convention is not followed, you might +have to use @code{grep} or @kbd{M-x tags-search} in emacs, or run GDB on +itself and set a breakpoint in @code{execute_command}. + +@item +If all of the above fail, it may be appropriate to ask for information +on @code{bug-gdb}. But @emph{never} post a generic question like ``I was +wondering if anyone could give me some tips about understanding +GDB''---if we had some magic secret we would put it in this manual. +Suggestions for improving the manual are always welcome, of course. +@end itemize + +Good luck! + +@node Debugging GDB +@chapter Debugging GDB with itself +If gdb is limping on your machine, this is the preferred way to get it +fully functional. Be warned that in some ancient Unix systems, like +Ultrix 4.2, a program can't be running in one process while it is being +debugged in another. Rather than typing the command @code{@w{./gdb +./gdb}}, which works on Suns and such, you can copy @file{gdb} to +@file{gdb2} and then type @code{@w{./gdb ./gdb2}}. + +When you run gdb in the gdb source directory, it will read a +@file{.gdbinit} file that sets up some simple things to make debugging +gdb easier. The @code{info} command, when executed without a subcommand +in a gdb being debugged by gdb, will pop you back up to the top level +gdb. See @file{.gdbinit} for details. + +If you use emacs, you will probably want to do a @code{make TAGS} after +you configure your distribution; this will put the machine dependent +routines for your local machine where they will be accessed first by +@kbd{M-.} + +Also, make sure that you've either compiled gdb with your local cc, or +have run @code{fixincludes} if you are compiling with gcc. + +@node New Architectures +@chapter Defining a New Host or Target Architecture + +When building support for a new host and/or target, much of the work you +need to do is handled by specifying configuration files; +@pxref{Config,,Adding a New Configuration}. Further work can be +divided into ``host-dependent'' (@pxref{Host,,Adding a New Host}) and +``target-dependent'' (@pxref{Target,,Adding a New Target}). The +following discussion is meant to explain the difference between hosts +and targets. + +@heading What is considered ``host-dependent'' versus ``target-dependent''? + +@dfn{Host} refers to attributes of the system where GDB runs. +@dfn{Target} refers to the system where the program being debugged +executes. In most cases they are the same machine, in which case +a third type of @dfn{Native} attributes come into play. + +Defines and include files needed to build on the host are host support. +Examples are tty support, system defined types, host byte order, host +float format. + +Defines and information needed to handle the target format are target +dependent. Examples are the stack frame format, instruction set, +breakpoint instruction, registers, and how to set up and tear down the stack +to call a function. + +Information that is only needed when the host and target are the same, +is native dependent. One example is Unix child process support; if the +host and target are not the same, doing a fork to start the target +process is a bad idea. The various macros needed for finding the +registers in the @code{upage}, running @code{ptrace}, and such are all in the +native-dependent files. + +Another example of native-dependent code is support for features +that are really part of the target environment, but which require +@code{#include} files that are only available on the host system. +Core file handling and @code{setjmp} handling are two common cases. + +When you want to make GDB work ``native'' on a particular +machine, you have to include all three kinds of information. + +The dependent information in GDB is organized into files by naming +conventions. + +Host-Dependent Files +@table @file +@item config/*/*.mh +Sets Makefile parameters +@item config/*/xm-*.h +Global #include's and #define's and definitions +@item *-xdep.c +Global variables and functions +@end table + +Native-Dependent Files +@table @file +@item config/*/*.mh +Sets Makefile parameters (for @emph{both} host and native) +@item config/*/nm-*.h +#include's and #define's and definitions. This file +is only included by the small number of modules that need it, +so beware of doing feature-test #define's from its macros. +@item *-nat.c +global variables and functions +@end table + +Target-Dependent Files +@table @file +@item config/*/*.mt +Sets Makefile parameters +@item config/*/tm-*.h +Global #include's and #define's and definitions +@item *-tdep.c +Global variables and functions +@end table + +At this writing, most supported hosts have had their host and native +dependencies sorted out properly. There are a few stragglers, which +can be recognized by the absence of NATDEPFILES lines in their +@file{config/*/*.mh}. + +@node Config +@chapter Adding a New Configuration + +Most of the work in making GDB compile on a new machine is in specifying +the configuration of the machine. This is done in a dizzying variety of +header files and configuration scripts, which we hope to make more +sensible soon. Let's say your new host is called an @var{xxx} (e.g. +@samp{sun4}), and its full three-part configuration name is +@code{@var{xarch}-@var{xvend}-@var{xos}} (e.g. @samp{sparc-sun-sunos4}). In +particular: + +In the top level directory, edit @file{config.sub} and add @var{xarch}, +@var{xvend}, and @var{xos} to the lists of supported architectures, +vendors, and operating systems near the bottom of the file. Also, add +@var{xxx} as an alias that maps to +@code{@var{xarch}-@var{xvend}-@var{xos}}. You can test your changes by +running + +@example +./config.sub @var{xxx} +@end example +@noindent +and +@example +./config.sub @code{@var{xarch}-@var{xvend}-@var{xos}} +@end example +@noindent +which should both respond with @code{@var{xarch}-@var{xvend}-@var{xos}} +and no error messages. + +Now, go to the @file{bfd} directory and +create a new file @file{bfd/hosts/h-@var{xxx}.h}. Examine the +other @file{h-*.h} files as templates, and create one that brings in the +right include files for your system, and defines any host-specific +macros needed by BFD, the Binutils, GNU LD, or the Opcodes directories. +(They all share the bfd @file{hosts} directory and the @file{configure.host} +file.) + +Then edit @file{bfd/configure.host}. Add a line to recognize your +@code{@var{xarch}-@var{xvend}-@var{xos}} configuration, and set +@code{my_host} to @var{xxx} when you recognize it. This will cause your +file @file{h-@var{xxx}.h} to be linked to @file{sysdep.h} at configuration +time. When creating the line that recognizes your configuration, +only match the fields that you really need to match; e.g. don't match +match the architecture or manufacturer if the OS is sufficient +to distinguish the configuration that your @file{h-@var{xxx}.h} file supports. +Don't match the manufacturer name unless you really need to. +This should make future ports easier. + +Also, if this host requires any changes to the Makefile, create a file +@file{bfd/config/@var{xxx}.mh}, which includes the required lines. + +It's possible that the @file{libiberty} and @file{readline} directories +won't need any changes for your configuration, but if they do, you can +change the @file{configure.in} file there to recognize your system and +map to an @file{mh-@var{xxx}} file. Then add @file{mh-@var{xxx}} +to the @file{config/} subdirectory, to set any makefile variables you +need. The only current options in there are things like @samp{-DSYSV}. +(This @file{mh-@var{xxx}} naming convention differs from elsewhere +in GDB, by historical accident. It should be cleaned up so that all +such files are called @file{@var{xxx}.mh}.) + +Aha! Now to configure GDB itself! Edit +@file{gdb/configure.in} to recognize your system and set @code{gdb_host} +to @var{xxx}, and (unless your desired target is already available) also +set @code{gdb_target} to something appropriate (for instance, +@var{xxx}). To handle new hosts, modify the segment after the comment +@samp{# per-host}; to handle new targets, modify after @samp{# +per-target}. +@c Would it be simpler to just use different per-host and per-target +@c *scripts*, and call them from {configure} ? + +Finally, you'll need to specify and define GDB's host-, native-, and +target-dependent @file{.h} and @file{.c} files used for your +configuration; the next two chapters discuss those. + + +@node Host +@chapter Adding a New Host + +Once you have specified a new configuration for your host +(@pxref{Config,,Adding a New Configuration}), there are three remaining +pieces to making GDB work on a new machine. First, you have to make it +host on the new machine (compile there, handle that machine's terminals +properly, etc). If you will be cross-debugging to some other kind of +system that's already supported, you are done. + +If you want to use GDB to debug programs that run on the new machine, +you have to get it to understand the machine's object files, symbol +files, and interfaces to processes; @pxref{Target,,Adding a New Target} +and @pxref{Native,,Adding a New Native Configuration} + +Several files control GDB's configuration for host systems: + +@table @file +@item gdb/config/@var{arch}/@var{xxx}.mh +Specifies Makefile fragments needed when hosting on machine @var{xxx}. +In particular, this lists the required machine-dependent object files, +by defining @samp{XDEPFILES=@dots{}}. Also +specifies the header file which describes host @var{xxx}, by defining +@code{XM_FILE= xm-@var{xxx}.h}. You can also define @code{CC}, +@code{REGEX} and @code{REGEX1}, @code{SYSV_DEFINE}, @code{XM_CFLAGS}, +@code{XM_ADD_FILES}, @code{XM_CLIBS}, @code{XM_CDEPS}, +etc.; see @file{Makefile.in}. + +@item gdb/config/@var{arch}/xm-@var{xxx}.h +(@file{xm.h} is a link to this file, created by configure). +Contains C macro definitions describing the host system environment, +such as byte order, host C compiler and library, ptrace support, +and core file structure. Crib from existing @file{xm-*.h} files +to create a new one. + +@item gdb/@var{xxx}-xdep.c +Contains any miscellaneous C code required for this machine +as a host. On many machines it doesn't exist at all. If it does +exist, put @file{@var{xxx}-xdep.o} into the @code{XDEPFILES} line +in @file{gdb/config/mh-@var{xxx}}. +@end table + +@subheading Generic Host Support Files + +There are some ``generic'' versions of routines that can be used by +various systems. These can be customized in various ways by macros +defined in your @file{xm-@var{xxx}.h} file. If these routines work for +the @var{xxx} host, you can just include the generic file's name (with +@samp{.o}, not @samp{.c}) in @code{XDEPFILES}. + +Otherwise, if your machine needs custom support routines, you will need +to write routines that perform the same functions as the generic file. +Put them into @code{@var{xxx}-xdep.c}, and put @code{@var{xxx}-xdep.o} +into @code{XDEPFILES}. + +@table @file +@item ser-bsd.c +This contains serial line support for Berkeley-derived Unix systems. + +@item ser-go32.c +This contains serial line support for 32-bit programs running under DOS +using the GO32 execution environment. + +@item ser-termios.c +This contains serial line support for System V-derived Unix systems. +@end table + +Now, you are now ready to try configuring GDB to compile using your system +as its host. From the top level (above @file{bfd}, @file{gdb}, etc), do: + +@example +./configure @var{xxx} +target=vxworks960 +@end example + +This will configure your system to cross-compile for VxWorks on +the Intel 960, which is probably not what you really want, but it's +a test case that works at this stage. (You haven't set up to be +able to debug programs that run @emph{on} @var{xxx} yet.) + +If this succeeds, you can try building it all with: + +@example +make +@end example + +Repeat until the program configures, compiles, links, and runs. +When run, it won't be able to do much (unless you have a VxWorks/960 +board on your network) but you will know that the host support is +pretty well done. + +Good luck! Comments and suggestions about this section are particularly +welcome; send them to @samp{bug-gdb@@prep.ai.mit.edu}. + +@node Native +@chapter Adding a New Native Configuration + +If you are making GDB run native on the @var{xxx} machine, you have +plenty more work to do. Several files control GDB's configuration for +native support: + +@table @file +@item gdb/config/@var{xarch}/@var{xxx}.mh +Specifies Makefile fragments needed when hosting @emph{or native} +on machine @var{xxx}. +In particular, this lists the required native-dependent object files, +by defining @samp{NATDEPFILES=@dots{}}. Also +specifies the header file which describes native support on @var{xxx}, +by defining @samp{NAT_FILE= nm-@var{xxx}.h}. +You can also define @samp{NAT_CFLAGS}, +@samp{NAT_ADD_FILES}, @samp{NAT_CLIBS}, @samp{NAT_CDEPS}, +etc.; see @file{Makefile.in}. + +@item gdb/config/@var{arch}/nm-@var{xxx}.h +(@file{nm.h} is a link to this file, created by configure). +Contains C macro definitions describing the native system environment, +such as child process control and core file support. +Crib from existing @file{nm-*.h} files to create a new one. + +@item gdb/@var{xxx}-nat.c +Contains any miscellaneous C code required for this native support +of this machine. On some machines it doesn't exist at all. +@end table + +@subheading Generic Native Support Files + +There are some ``generic'' versions of routines that can be used by +various systems. These can be customized in various ways by macros +defined in your @file{nm-@var{xxx}.h} file. If these routines work for +the @var{xxx} host, you can just include the generic file's name (with +@samp{.o}, not @samp{.c}) in @code{NATDEPFILES}. + +Otherwise, if your machine needs custom support routines, you will need +to write routines that perform the same functions as the generic file. +Put them into @code{@var{xxx}-nat.c}, and put @code{@var{xxx}-nat.o} +into @code{NATDEPFILES}. + +@table @file + +@item inftarg.c +This contains the @emph{target_ops vector} that supports Unix child +processes on systems which use ptrace and wait to control the child. + +@item procfs.c +This contains the @emph{target_ops vector} that supports Unix child +processes on systems which use /proc to control the child. + +@item fork-child.c +This does the low-level grunge that uses Unix system calls +to do a "fork and exec" to start up a child process. + +@item infptrace.c +This is the low level interface to inferior processes for systems +using the Unix @code{ptrace} call in a vanilla way. + +@item coredep.c::fetch_core_registers() +Support for reading registers out of a core file. This routine calls +@code{register_addr()}, see below. +Now that BFD is used to read core files, virtually all machines should +use @code{coredep.c}, and should just provide @code{fetch_core_registers} in +@code{@var{xxx}-nat.c} (or @code{REGISTER_U_ADDR} in @code{nm-@var{xxx}.h}). + +@item coredep.c::register_addr() +If your @code{nm-@var{xxx}.h} file defines the macro +@code{REGISTER_U_ADDR(addr, blockend, regno)}, it should be defined to +set @code{addr} to the offset within the @samp{user} +struct of GDB register number @code{regno}. @code{blockend} is the +offset within the ``upage'' of @code{u.u_ar0}. +If @code{REGISTER_U_ADDR} is defined, +@file{coredep.c} will define the @code{register_addr()} function and use +the macro in it. If you do not define @code{REGISTER_U_ADDR}, but you +are using the standard @code{fetch_core_registers()}, you will need to +define your own version of @code{register_addr()}, put it into your +@code{@var{xxx}-nat.c} file, and be sure @code{@var{xxx}-nat.o} is in +the @code{NATDEPFILES} list. If you have your own +@code{fetch_core_registers()}, you may not need a separate +@code{register_addr()}. Many custom @code{fetch_core_registers()} +implementations simply locate the registers themselves.@refill +@end table + +When making GDB run native on a new operating system, +to make it possible to debug +core files, you will need to either write specific code for parsing your +OS's core files, or customize @file{bfd/trad-core.c}. First, use +whatever @code{#include} files your machine uses to define the struct of +registers that is accessible (possibly in the u-area) in a core file +(rather than @file{machine/reg.h}), and an include file that defines whatever +header exists on a core file (e.g. the u-area or a @samp{struct core}). Then +modify @code{trad_unix_core_file_p()} to use these values to set up the +section information for the data segment, stack segment, any other +segments in the core file (perhaps shared library contents or control +information), ``registers'' segment, and if there are two discontiguous +sets of registers (e.g. integer and float), the ``reg2'' segment. This +section information basically delimits areas in the core file in a +standard way, which the section-reading routines in BFD know how to seek +around in. + +Then back in GDB, you need a matching routine called +@code{fetch_core_registers()}. If you can use the generic one, it's in +@file{coredep.c}; if not, it's in your @file{@var{xxx}-nat.c} file. +It will be passed a char pointer to the entire ``registers'' segment, +its length, and a zero; or a char pointer to the entire ``regs2'' +segment, its length, and a 2. The routine should suck out the supplied +register values and install them into GDB's ``registers'' array. +(@xref{New Architectures,,Defining a New Host or Target Architecture}, +for more info about this.) + +If your system uses @file{/proc} to control processes, and uses ELF +format core files, then you may be able to use the same routines +for reading the registers out of processes and out of core files. + +@node Target +@chapter Adding a New Target + +For a new target called @var{ttt}, first specify the configuration as +described in @ref{Config,,Adding a New Configuration}. If your new +target is the same as your new host, you've probably already done that. + +A variety of files specify attributes of the GDB target environment: + +@table @file +@item gdb/config/@var{arch}/@var{ttt}.mt +Contains a Makefile fragment specific to this target. +Specifies what object files are needed for target @var{ttt}, by +defining @samp{TDEPFILES=@dots{}}. +Also specifies the header file which describes @var{ttt}, by defining +@samp{TM_FILE= tm-@var{ttt}.h}. You can also define @samp{TM_CFLAGS}, +@samp{TM_CLIBS}, @samp{TM_CDEPS}, +and other Makefile variables here; see @file{Makefile.in}. + +@item gdb/config/@var{arch}/tm-@var{ttt}.h +(@file{tm.h} is a link to this file, created by configure). +Contains macro definitions about the target machine's +registers, stack frame format and instructions. +Crib from existing @file{tm-*.h} files when building a new one. + +@item gdb/@var{ttt}-tdep.c +Contains any miscellaneous code required for this target machine. +On some machines it doesn't exist at all. Sometimes the macros +in @file{tm-@var{ttt}.h} become very complicated, so they are +implemented as functions here instead, and the macro is simply +defined to call the function. + +@item gdb/exec.c +Defines functions for accessing files that are +executable on the target system. These functions open and examine an +exec file, extract data from one, write data to one, print information +about one, etc. Now that executable files are handled with BFD, every +target should be able to use the generic exec.c rather than its +own custom code. + +@item gdb/@var{arch}-pinsn.c +Prints (disassembles) the target machine's instructions. +This file is usually shared with other target machines which use the +same processor, which is why it is @file{@var{arch}-pinsn.c} rather +than @file{@var{ttt}-pinsn.c}. + +@item gdb/@var{arch}-opcode.h +Contains some large initialized +data structures describing the target machine's instructions. +This is a bit strange for a @file{.h} file, but it's OK since +it is only included in one place. @file{@var{arch}-opcode.h} is shared +between the debugger and the assembler, if the GNU assembler has been +ported to the target machine. + +@item gdb/config/@var{arch}/tm-@var{arch}.h +This often exists to describe the basic layout of the target machine's +processor chip (registers, stack, etc). +If used, it is included by @file{tm-@var{xxx}.h}. It can +be shared among many targets that use the same processor. + +@item gdb/@var{arch}-tdep.c +Similarly, there are often common subroutines that are shared by all +target machines that use this particular architecture. +@end table + +When adding support for a new target machine, there are various areas +of support that might need change, or might be OK. + +If you are using an existing object file format (a.out or COFF), +there is probably little to be done. See @file{bfd/doc/bfd.texinfo} +for more information on writing new a.out or COFF versions. + +If you need to add a new object file format, you must first add it to +BFD. This is beyond the scope of this document right now. Basically +you must build a transfer vector (of type @code{bfd_target}), which will +mean writing all the required routines, and add it to the list in +@file{bfd/targets.c}. + +You must then arrange for the BFD code to provide access to the +debugging symbols. Generally GDB will have to call swapping routines +from BFD and a few other BFD internal routines to locate the debugging +information. As much as possible, GDB should not depend on the BFD +internal data structures. + +For some targets (e.g., COFF), there is a special transfer vector used +to call swapping routines, since the external data structures on various +platforms have different sizes and layouts. Specialized routines that +will only ever be implemented by one object file format may be called +directly. This interface should be described in a file +@file{bfd/libxxx.h}, which is included by GDB. + +If you are adding a new operating system for an existing CPU chip, add a +@file{tm-@var{xos}.h} file that describes the operating system +facilities that are unusual (extra symbol table info; the breakpoint +instruction needed; etc). Then write a +@file{tm-@var{xarch}-@var{xos}.h} that just @code{#include}s +@file{tm-@var{xarch}.h} and @file{tm-@var{xos}.h}. (Now that we have +three-part configuration names, this will probably get revised to +separate the @var{xos} configuration from the @var{xarch} +configuration.) + + +@node Languages +@chapter Adding a Source Language to GDB + +To add other languages to GDB's expression parser, follow the following steps: + +@table @emph +@item Create the expression parser. + +This should reside in a file @file{@var{lang}-exp.y}. Routines for building +parsed expressions into a @samp{union exp_element} list are in @file{parse.c}. + +Since we can't depend upon everyone having Bison, and YACC produces +parsers that define a bunch of global names, the following lines +@emph{must} be included at the top of the YACC parser, to prevent +the various parsers from defining the same global names: + +@example +#define yyparse @var{lang}_parse +#define yylex @var{lang}_lex +#define yyerror @var{lang}_error +#define yylval @var{lang}_lval +#define yychar @var{lang}_char +#define yydebug @var{lang}_debug +#define yypact @var{lang}_pact +#define yyr1 @var{lang}_r1 +#define yyr2 @var{lang}_r2 +#define yydef @var{lang}_def +#define yychk @var{lang}_chk +#define yypgo @var{lang}_pgo +#define yyact @var{lang}_act +#define yyexca @var{lang}_exca +#define yyerrflag @var{lang}_errflag +#define yynerrs @var{lang}_nerrs +@end example + +At the bottom of your parser, define a @code{struct language_defn} and +initialize it with the right values for your language. Define an +@code{initialize_@var{lang}} routine and have it call +@samp{add_language(@var{lang}_language_defn)} to tell the rest of GDB +that your language exists. You'll need some other supporting variables +and functions, which will be used via pointers from your +@code{@var{lang}_language_defn}. See the declaration of @code{struct +language_defn} in @file{language.h}, and the other @file{*-exp.y} files, +for more information. + +@item Add any evaluation routines, if necessary + +If you need new opcodes (that represent the operations of the language), +add them to the enumerated type in @file{expression.h}. Add support +code for these operations in @code{eval.c:evaluate_subexp()}. Add cases +for new opcodes in two functions from @file{parse.c}: +@code{prefixify_subexp()} and @code{length_of_subexp()}. These compute +the number of @code{exp_element}s that a given operation takes up. + +@item Update some existing code + +Add an enumerated identifier for your language to the enumerated type +@code{enum language} in @file{defs.h}. + +Update the routines in @file{language.c} so your language is included. These +routines include type predicates and such, which (in some cases) are +language dependent. If your language does not appear in the switch +statement, an error is reported. + +Also included in @file{language.c} is the code that updates the variable +@code{current_language}, and the routines that translate the +@code{language_@var{lang}} enumerated identifier into a printable +string. + +Update the function @code{_initialize_language} to include your language. This +function picks the default language upon startup, so is dependent upon +which languages that GDB is built for. + +Update @code{allocate_symtab} in @file{symfile.c} and/or symbol-reading +code so that the language of each symtab (source file) is set properly. +This is used to determine the language to use at each stack frame level. +Currently, the language is set based upon the extension of the source +file. If the language can be better inferred from the symbol +information, please set the language of the symtab in the symbol-reading +code. + +Add helper code to @code{expprint.c:print_subexp()} to handle any new +expression opcodes you have added to @file{expression.h}. Also, add the +printed representations of your operators to @code{op_print_tab}. + +@item Add a place of call + +Add a call to @code{@var{lang}_parse()} and @code{@var{lang}_error} in +@code{parse.c:parse_exp_1()}. + +@item Use macros to trim code + +The user has the option of building GDB for some or all of the +languages. If the user decides to build GDB for the language +@var{lang}, then every file dependent on @file{language.h} will have the +macro @code{_LANG_@var{lang}} defined in it. Use @code{#ifdef}s to +leave out large routines that the user won't need if he or she is not +using your language. + +Note that you do not need to do this in your YACC parser, since if GDB +is not build for @var{lang}, then @file{@var{lang}-exp.tab.o} (the +compiled form of your parser) is not linked into GDB at all. + +See the file @file{configure.in} for how GDB is configured for different +languages. + +@item Edit @file{Makefile.in} + +Add dependencies in @file{Makefile.in}. Make sure you update the macro +variables such as @code{HFILES} and @code{OBJS}, otherwise your code may +not get linked in, or, worse yet, it may not get @code{tar}red into the +distribution! +@end table + + +@node Releases +@chapter Configuring GDB for Release + +From the top level directory (containing @file{gdb}, @file{bfd}, +@file{libiberty}, and so on): +@example +make -f Makefile.in gdb.tar.Z +@end example + +This will properly configure, clean, rebuild any files that are +distributed pre-built (e.g. @file{c-exp.tab.c} or @file{refcard.ps}), +and will then make a tarfile. (If the top level directory has already +beenn configured, you can just do @code{make gdb.tar.Z} instead.) + +This procedure requires: +@itemize @bullet +@item symbolic links +@item @code{makeinfo} (texinfo2 level) +@item @TeX{} +@item @code{dvips} +@item @code{yacc} or @code{bison} +@end itemize +@noindent +@dots{} and the usual slew of utilities (@code{sed}, @code{tar}, etc.). + +@subheading TEMPORARY RELEASE PROCEDURE FOR DOCUMENTATION + +@file{gdb.texinfo} is currently marked up using the texinfo-2 macros, +which are not yet a default for anything (but we have to start using +them sometime). + +For making paper, the only thing this implies is the right generation of +@file{texinfo.tex} needs to be included in the distribution. + +For making info files, however, rather than duplicating the texinfo2 +distribution, generate @file{gdb-all.texinfo} locally, and include the files +@file{gdb.info*} in the distribution. Note the plural; @code{makeinfo} will +split the document into one overall file and five or so included files. + + +@node Partial Symbol Tables +@chapter Partial Symbol Tables + +GDB has three types of symbol tables. + +@itemize @bullet +@item full symbol tables (symtabs). These contain the main +information about symbols and addresses. +@item partial symbol tables (psymtabs). These contain enough +information to know when to read the corresponding +part of the full symbol table. +@item minimal symbol tables (msymtabs). These contain information +gleaned from non-debugging symbols. +@end itemize + +This section describes partial symbol tables. + +A psymtab is constructed by doing a very quick pass over an executable +file's debugging information. Small amounts of information are +extracted -- enough to identify which parts of the symbol table will +need to be re-read and fully digested later, when the user needs the +information. The speed of this pass causes GDB to start up very +quickly. Later, as the detailed rereading occurs, it occurs in small +pieces, at various times, and the delay therefrom is mostly invisible to +the user. (@xref{Symbol Reading}.) + +The symbols that show up in a file's psymtab should be, roughly, those +visible to the debugger's user when the program is not running code from +that file. These include external symbols and types, static +symbols and types, and enum values declared at file scope. + +The psymtab also contains the range of instruction addresses that the +full symbol table would represent. + +The idea is that there are only two ways for the user (or much of +the code in the debugger) to reference a symbol: + +@itemize @bullet + +@item by its address +(e.g. execution stops at some address which is inside a function +in this file). The address will be noticed to be in the +range of this psymtab, and the full symtab will be read in. +@code{find_pc_function}, @code{find_pc_line}, and other @code{find_pc_@dots{}} +functions handle this. + +@item by its name +(e.g. the user asks to print a variable, or set a breakpoint on a +function). Global names and file-scope names will be found in the +psymtab, which will cause the symtab to be pulled in. Local names will +have to be qualified by a global name, or a file-scope name, in which +case we will have already read in the symtab as we evaluated the +qualifier. Or, a local symbol can be referenced when +we are "in" a local scope, in which case the first case applies. +@code{lookup_symbol} does most of the work here. + +@end itemize + +The only reason that psymtabs exist is to cause a symtab to be read in +at the right moment. Any symbol that can be elided from a psymtab, +while still causing that to happen, should not appear in it. Since +psymtabs don't have the idea of scope, you can't put local symbols in +them anyway. Psymtabs don't have the idea of the type of a symbol, +either, so types need not appear, unless they will be referenced by +name. + +It is a bug for GDB to behave one way when only a psymtab has been read, +and another way if the corresponding symtab has been read in. Such +bugs are typically caused by a psymtab that does not contain all the +visible symbols, or which has the wrong instruction address ranges. + +The psymtab for a particular section of a symbol-file (objfile) +could be thrown away after the symtab has been read in. The symtab +should always be searched before the psymtab, so the psymtab will +never be used (in a bug-free environment). Currently, +psymtabs are allocated on an obstack, and all the psymbols themselves +are allocated in a pair of large arrays on an obstack, so there is +little to be gained by trying to free them unless you want to do a lot +more work. + +@node Types +@chapter Types + +Fundamental Types (e.g., FT_VOID, FT_BOOLEAN). + +These are the fundamental types that gdb uses internally. Fundamental +types from the various debugging formats (stabs, ELF, etc) are mapped into +one of these. They are basically a union of all fundamental types that +gdb knows about for all the languages that gdb knows about. + +Type Codes (e.g., TYPE_CODE_PTR, TYPE_CODE_ARRAY). + +Each time gdb builds an internal type, it marks it with one of these +types. The type may be a fundamental type, such as TYPE_CODE_INT, or +a derived type, such as TYPE_CODE_PTR which is a pointer to another +type. Typically, several FT_* types map to one TYPE_CODE_* type, and +are distinguished by other members of the type struct, such as whether +the type is signed or unsigned, and how many bits it uses. + +Builtin Types (e.g., builtin_type_void, builtin_type_char). + +These are instances of type structs that roughly correspond to fundamental +types and are created as global types for gdb to use for various ugly +historical reasons. We eventually want to eliminate these. Note for +example that builtin_type_int initialized in gdbtypes.c is basically the +same as a TYPE_CODE_INT type that is initialized in c-lang.c for an +FT_INTEGER fundamental type. The difference is that the builtin_type is +not associated with any particular objfile, and only one instance exists, +while c-lang.c builds as many TYPE_CODE_INT types as needed, with each +one associated with some particular objfile. + +@node BFD support for GDB +@chapter Binary File Descriptor Library Support for GDB + +BFD provides support for GDB in several ways: + +@table @emph +@item identifying executable and core files +BFD will identify a variety of file types, including a.out, coff, and +several variants thereof, as well as several kinds of core files. + +@item access to sections of files +BFD parses the file headers to determine the names, virtual addresses, +sizes, and file locations of all the various named sections in files +(such as the text section or the data section). GDB simply calls +BFD to read or write section X at byte offset Y for length Z. + +@item specialized core file support +BFD provides routines to determine the failing command name stored +in a core file, the signal with which the program failed, and whether +a core file matches (i.e. could be a core dump of) a particular executable +file. + +@item locating the symbol information +GDB uses an internal interface of BFD to determine where to find the +symbol information in an executable file or symbol-file. GDB itself +handles the reading of symbols, since BFD does not ``understand'' debug +symbols, but GDB uses BFD's cached information to find the symbols, +string table, etc. +@end table + +@c The interface for symbol reading is described in @ref{Symbol +@c Reading,,Symbol Reading}. + + +@node Symbol Reading +@chapter Symbol Reading + +GDB reads symbols from "symbol files". The usual symbol file is the +file containing the program which gdb is debugging. GDB can be directed +to use a different file for symbols (with the ``symbol-file'' +command), and it can also read more symbols via the ``add-file'' and ``load'' +commands, or while reading symbols from shared libraries. + +Symbol files are initially opened by @file{symfile.c} using the BFD +library. BFD identifies the type of the file by examining its header. +@code{symfile_init} then uses this identification to locate a +set of symbol-reading functions. + +Symbol reading modules identify themselves to GDB by calling +@code{add_symtab_fns} during their module initialization. The argument +to @code{add_symtab_fns} is a @code{struct sym_fns} which contains +the name (or name prefix) of the symbol format, the length of the prefix, +and pointers to four functions. These functions are called at various +times to process symbol-files whose identification matches the specified +prefix. + +The functions supplied by each module are: + +@table @code +@item @var{xxx}_symfile_init(struct sym_fns *sf) + +Called from @code{symbol_file_add} when we are about to read a new +symbol file. This function should clean up any internal state +(possibly resulting from half-read previous files, for example) +and prepare to read a new symbol file. Note that the symbol file +which we are reading might be a new "main" symbol file, or might +be a secondary symbol file whose symbols are being added to the +existing symbol table. + +The argument to @code{@var{xxx}_symfile_init} is a newly allocated +@code{struct sym_fns} whose @code{bfd} field contains the BFD +for the new symbol file being read. Its @code{private} field +has been zeroed, and can be modified as desired. Typically, +a struct of private information will be @code{malloc}'d, and +a pointer to it will be placed in the @code{private} field. + +There is no result from @code{@var{xxx}_symfile_init}, but it can call +@code{error} if it detects an unavoidable problem. + +@item @var{xxx}_new_init() + +Called from @code{symbol_file_add} when discarding existing symbols. +This function need only handle +the symbol-reading module's internal state; the symbol table data +structures visible to the rest of GDB will be discarded by +@code{symbol_file_add}. It has no arguments and no result. +It may be called after @code{@var{xxx}_symfile_init}, if a new symbol +table is being read, or may be called alone if all symbols are +simply being discarded. + +@item @var{xxx}_symfile_read(struct sym_fns *sf, CORE_ADDR addr, int mainline) + +Called from @code{symbol_file_add} to actually read the symbols from a +symbol-file into a set of psymtabs or symtabs. + +@code{sf} points to the struct sym_fns originally passed to +@code{@var{xxx}_sym_init} for possible initialization. @code{addr} is the +offset between the file's specified start address and its true address +in memory. @code{mainline} is 1 if this is the main symbol table being +read, and 0 if a secondary symbol file (e.g. shared library or +dynamically loaded file) is being read.@refill +@end table + +In addition, if a symbol-reading module creates psymtabs when +@var{xxx}_symfile_read is called, these psymtabs will contain a pointer to +a function @code{@var{xxx}_psymtab_to_symtab}, which can be called from +any point in the GDB symbol-handling code. + +@table @code +@item @var{xxx}_psymtab_to_symtab (struct partial_symtab *pst) + +Called from @code{psymtab_to_symtab} (or the PSYMTAB_TO_SYMTAB +macro) if the psymtab has not already been read in and had its +@code{pst->symtab} pointer set. The argument is the psymtab +to be fleshed-out into a symtab. Upon return, pst->readin +should have been set to 1, and pst->symtab should contain a +pointer to the new corresponding symtab, or zero if there +were no symbols in that part of the symbol file. +@end table + + +@node Cleanups +@chapter Cleanups + +Cleanups are a structured way to deal with things that need to be done +later. When your code does something (like @code{malloc} some memory, or open +a file) that needs to be undone later (e.g. free the memory or close +the file), it can make a cleanup. The cleanup will be done at some +future point: when the command is finished, when an error occurs, or +when your code decides it's time to do cleanups. + +You can also discard cleanups, that is, throw them away without doing +what they say. This is only done if you ask that it be done. + +Syntax: + +@table @code +@item struct cleanup *@var{old_chain}; +Declare a variable which will hold a cleanup chain handle. + +@item @var{old_chain} = make_cleanup (@var{function}, @var{arg}); +Make a cleanup which will cause @var{function} to be called with @var{arg} +(a @code{char *}) later. The result, @var{old_chain}, is a handle that can be +passed to @code{do_cleanups} or @code{discard_cleanups} later. Unless you are +going to call @code{do_cleanups} or @code{discard_cleanups} yourself, +you can ignore the result from @code{make_cleanup}. + + +@item do_cleanups (@var{old_chain}); +Perform all cleanups done since @code{make_cleanup} returned @var{old_chain}. +E.g.: +@example +make_cleanup (a, 0); +old = make_cleanup (b, 0); +do_cleanups (old); +@end example +@noindent +will call @code{b()} but will not call @code{a()}. The cleanup that calls @code{a()} will remain +in the cleanup chain, and will be done later unless otherwise discarded.@refill + +@item discard_cleanups (@var{old_chain}); +Same as @code{do_cleanups} except that it just removes the cleanups from the +chain and does not call the specified functions. + +@end table + +Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they +``should not be called when cleanups are not in place''. This means +that any actions you need to reverse in the case of an error or +interruption must be on the cleanup chain before you call these functions, +since they might never return to your code (they @samp{longjmp} instead). + + +@node Wrapping +@chapter Wrapping Output Lines + +Output that goes through @code{printf_filtered} or @code{fputs_filtered} or +@code{fputs_demangled} needs only to have calls to @code{wrap_here} added +in places that would be good breaking points. The utility routines +will take care of actually wrapping if the line width is exceeded. + +The argument to @code{wrap_here} is an indentation string which is printed +@emph{only} if the line breaks there. This argument is saved away and used +later. It must remain valid until the next call to @code{wrap_here} or +until a newline has been printed through the @code{*_filtered} functions. +Don't pass in a local variable and then return! + +It is usually best to call @code{wrap_here()} after printing a comma or space. +If you call it before printing a space, make sure that your indentation +properly accounts for the leading space that will print if the line wraps +there. + +Any function or set of functions that produce filtered output must finish +by printing a newline, to flush the wrap buffer, before switching to +unfiltered (``@code{printf}'') output. Symbol reading routines that print +warnings are a good example. + + +@node Frames +@chapter Frames + +A frame is a construct that GDB uses to keep track of calling and called +functions. + +@table @code +@item FRAME_FP +in the machine description has no meaning to the machine-independent +part of GDB, except that it is used when setting up a new frame from +scratch, as follows: + +@example + create_new_frame (read_register (FP_REGNUM), read_pc ())); +@end example + +Other than that, all the meaning imparted to @code{FP_REGNUM} is imparted by +the machine-dependent code. So, @code{FP_REGNUM} can have any value that +is convenient for the code that creates new frames. (@code{create_new_frame} +calls @code{INIT_EXTRA_FRAME_INFO} if it is defined; that is where you should +use the @code{FP_REGNUM} value, if your frames are nonstandard.) + +@item FRAME_CHAIN +Given a GDB frame, determine the address of the calling function's +frame. This will be used to create a new GDB frame struct, and then +@code{INIT_EXTRA_FRAME_INFO} and @code{INIT_FRAME_PC} will be called for +the new frame. +@end table + +@node Remote Stubs +@chapter Remote Stubs + +GDB's file @file{remote.c} talks a serial protocol to code that runs +in the target system. GDB provides several sample ``stubs'' that can +be integrated into target programs or operating systems for this purpose; +they are named @file{*-stub.c}. + +The GDB user's manual describes how to put such a stub into your target +code. What follows is a discussion of integrating the SPARC stub +into a complicated operating system (rather than a simple program), +by Stu Grossman, the author of this stub. + +The trap handling code in the stub assumes the following upon entry to +trap_low: + +@enumerate +@item %l1 and %l2 contain pc and npc respectively at the time of the trap +@item traps are disabled +@item you are in the correct trap window +@end enumerate + +As long as your trap handler can guarantee those conditions, then there is no +reason why you shouldn't be able to `share' traps with the stub. The stub has +no requirement that it be jumped to directly from the hardware trap vector. +That is why it calls @code{exceptionHandler()}, which is provided by the external +environment. For instance, this could setup the hardware traps to actually +execute code which calls the stub first, and then transfers to its own trap +handler. + +For the most point, there probably won't be much of an issue with `sharing' +traps, as the traps we use are usually not used by the kernel, and often +indicate unrecoverable error conditions. Anyway, this is all controlled by a +table, and is trivial to modify. +The most important trap for us is for @code{ta 1}. Without that, we +can't single step or do breakpoints. Everything else is unnecessary +for the proper operation of the debugger/stub. + +From reading the stub, it's probably not obvious how breakpoints work. They +are simply done by deposit/examine operations from GDB. + +@node Longjmp Support +@chapter Longjmp Support + +GDB has support for figuring out that the target is doing a +@code{longjmp} and for stopping at the target of the jump, if we are +stepping. This is done with a few specialized internal breakpoints, +which are visible in the @code{maint info breakpoint} command. + +To make this work, you need to define a macro called +@code{GET_LONGJMP_TARGET}, which will examine the @code{jmp_buf} +structure and extract the longjmp target address. Since @code{jmp_buf} +is target specific, you will need to define it in the appropriate +@file{tm-xxx.h} file. Look in @file{tm-sun4os4.h} and +@file{sparc-tdep.c} for examples of how to do this. + +@node Coding Style +@chapter Coding Style + +GDB is generally written using the GNU coding standards, as described in +@file{standards.texi}, which is available for anonymous FTP from GNU +archive sites. There are some additional considerations for GDB +maintainers that reflect the unique environment and style of GDB +maintenance. If you follow these guidelines, GDB will be more +consistent and easier to maintain. + +GDB's policy on the use of prototypes is that prototypes are used +to @emph{declare} functions but never to @emph{define} them. Simple +macros are used in the declarations, so that a non-ANSI compiler can +compile GDB without trouble. The simple macro calls are used like +this: + +@example @code +extern int +memory_remove_breakpoint PARAMS ((CORE_ADDR, char *)); +@end example + +Note the double parentheses around the parameter types. This allows +an arbitrary number of parameters to be described, without freaking +out the C preprocessor. When the function has no parameters, it +should be described like: + +@example @code +void +noprocess PARAMS ((void)); +@end example + +The @code{PARAMS} macro expands to its argument in ANSI C, or to a simple +@code{()} in traditional C. + +All external functions should have a @code{PARAMS} declaration in a +header file that callers include. All static functions should have such +a declaration near the top of their source file. + +We don't have a gcc option that will properly check that these rules +have been followed, but it's GDB policy, and we periodically check it +using the tools available (plus manual labor), and clean up any remnants. + +@node Clean Design +@chapter Clean Design + +In addition to getting the syntax right, there's the little question of +semantics. Some things are done in certain ways in GDB because long +experience has shown that the more obvious ways caused various kinds of +trouble. In particular: + +@table @bullet +@item +You can't assume the byte order of anything that comes from a +target (including @var{value}s, object files, and instructions). Such +things must be byte-swapped using @code{SWAP_TARGET_AND_HOST} in GDB, +or one of the swap routines defined in @file{bfd.h}, such as @code{bfd_get_32}. + +@item +You can't assume that you know what interface is being used to talk to +the target system. All references to the target must go through the +current @code{target_ops} vector. + +@item +You can't assume that the host and target machines are the same machine +(except in the ``native'' support modules). +In particular, you can't assume that the target machine's header files +will be available on the host machine. Target code must bring along its +own header files -- written from scratch or explicitly donated by their +owner, to avoid copyright problems. + +@item +Insertion of new @code{#ifdef}'s will be frowned upon. It's much better +to write the code portably than to conditionalize it for various systems. + +@item +New @code{#ifdef}'s which test for specific compilers or manufacturers +or operating systems are unacceptable. All @code{#ifdef}'s should test +for features. The information about which configurations contain which +features should be segregated into the configuration files. Experience +has proven far too often that a feature unique to one particular system +often creeps into other systems; and that a conditional based on +some predefined macro for your current system will become worthless +over time, as new versions of your system come out that behave differently +with regard to this feature. + +@item +Adding code that handles specific architectures, operating systems, target +interfaces, or hosts, is not acceptable in generic code. If a hook +is needed at that point, invent a generic hook and define it for your +configuration, with something like: + +@example +#ifdef WRANGLE_SIGNALS + WRANGLE_SIGNALS (signo); +#endif +@end example + +In your host, target, or native configuration file, as appropriate, +define @code{WRANGLE_SIGNALS} to do the machine-dependent thing. Take +a bit of care in defining the hook, so that it can be used by other +ports in the future, if they need a hook in the same place. + +If the hook is not defined, the code should do whatever "most" machines +want. Using @code{#ifdef}, as above, is the preferred way to do this, +but sometimes that gets convoluted, in which case use + +@example +#ifndef SPECIAL_FOO_HANDLING +#define SPECIAL_FOO_HANDLING(pc, sp) (0) +#endif +@end example + +where the macro is used or in an appropriate header file. + +Whether to include a @dfn{small} hook, a hook around the exact pieces of +code which are system-dependent, or whether to replace a whole function +with a hook depends on the case. A good example of this dilemma can be +found in @code{get_saved_register}. All machines that GDB 2.8 ran on +just needed the @code{FRAME_FIND_SAVED_REGS} hook to find the saved +registers. Then the SPARC and Pyramid came along, and +@code{HAVE_REGISTER_WINDOWS} and @code{REGISTER_IN_WINDOW_P} were +introduced. Then the 29k and 88k required the @code{GET_SAVED_REGISTER} +hook. The first three are examples of small hooks; the latter replaces +a whole function. In this specific case, it is useful to have both +kinds; it would be a bad idea to replace all the uses of the small hooks +with @code{GET_SAVED_REGISTER}, since that would result in much +duplicated code. Other times, duplicating a few lines of code here or +there is much cleaner than introducing a large number of small hooks. + +Another way to generalize GDB along a particular interface is with an +attribute struct. For example, GDB has been generalized to handle +multiple kinds of remote interfaces -- not by #ifdef's everywhere, but +by defining the "target_ops" structure and having a current target (as +well as a stack of targets below it, for memory references). Whenever +something needs to be done that depends on which remote interface we are +using, a flag in the current target_ops structure is tested (e.g. +`target_has_stack'), or a function is called through a pointer in the +current target_ops structure. In this way, when a new remote interface +is added, only one module needs to be touched -- the one that actually +implements the new remote interface. Other examples of +attribute-structs are BFD access to multiple kinds of object file +formats, or GDB's access to multiple source languages. + +Please avoid duplicating code. For example, in GDB 3.x all the code +interfacing between @code{ptrace} and the rest of GDB was duplicated in +@file{*-dep.c}, and so changing something was very painful. In GDB 4.x, +these have all been consolidated into @file{infptrace.c}. +@file{infptrace.c} can deal with variations between systems the same way +any system-independent file would (hooks, #if defined, etc.), and +machines which are radically different don't need to use infptrace.c at +all. + +@item +@emph{Do} write code that doesn't depend on the sizes of C data types, +the format of the host's floating point numbers, the alignment of anything, +or the order of evaluation of expressions. In short, follow good +programming practices for writing portable C code. + +@end table + +@node Submitting Patches +@chapter Submitting Patches + +Thanks for thinking of offering your changes back to the community of +GDB users. In general we like to get well designed enhancements. +Thanks also for checking in advance about the best way to transfer the +changes. + +The two main problems with getting your patches in are, + +@table @bullet +@item +The GDB maintainers will only install ``cleanly designed'' patches. +You may not always agree on what is clean design. +@pxref{Coding Style}, @pxref{Clean Design}. + +@item +If the maintainers don't have time to put the patch in when it +arrives, or if there is any question about a patch, it +goes into a large queue with everyone else's patches and +bug reports. +@end table + +I don't know how to get past these problems except by continuing to try. + +There are two issues here -- technical and legal. + +The legal issue is that to incorporate substantial changes requires a +copyright assignment from you and/or your employer, granting ownership +of the changes to the Free Software Foundation. You can get the +standard document for doing this by sending mail to +@code{gnu@@prep.ai.mit.edu} and asking for it. I recommend that people +write in "All programs owned by the Free Software Foundation" as "NAME +OF PROGRAM", so that changes in many programs (not just GDB, but GAS, +Emacs, GCC, etc) can be contributed with only one piece of legalese +pushed through the bureacracy and filed with the FSF. I can't start +merging changes until this paperwork is received by the FSF (their +rules, which I follow since I maintain it for them). + +Technically, the easiest way to receive changes is to receive each +feature as a small context diff or unidiff, suitable for "patch". +Each message sent to me should include the changes to C code and +header files for a single feature, plus ChangeLog entries for each +directory where files were modified, and diffs for any changes needed +to the manuals (gdb/doc/gdb.texi or gdb/doc/gdbint.texi). If there +are a lot of changes for a single feature, they can be split down +into multiple messages. + +In this way, if I read and like the feature, I can add it to the +sources with a single patch command, do some testing, and check it in. +If you leave out the ChangeLog, I have to write one. If you leave +out the doc, I have to puzzle out what needs documenting. Etc. + +The reason to send each change in a separate message is that I will +not install some of the changes. They'll be returned to you with +questions or comments. If I'm doing my job, my message back to you +will say what you have to fix in order to make the change acceptable. +The reason to have separate messages for separate features is so +that other changes (which I @emph{am} willing to accept) can be installed +while one or more changes are being reworked. If multiple features +are sent in a single message, I tend to not put in the effort to sort +out the acceptable changes from the unacceptable, so none of the +features get installed until all are acceptable. + +If this sounds painful or authoritarian, well, it is. But I get a lot +of bug reports and a lot of patches, and most of them don't get +installed because I don't have the time to finish the job that the bug +reporter or the contributor could have done. Patches that arrive +complete, working, and well designed, tend to get installed on the day +they arrive. The others go into a queue and get installed if and when +I scan back over the queue -- which can literally take months +sometimes. It's in both our interests to make patch installation easy +-- you get your changes installed, and I make some forward progress on +GDB in a normal 12-hour day (instead of them having to wait until I +have a 14-hour or 16-hour day to spend cleaning up patches before I +can install them). + +Please send patches to @code{bug-gdb@@prep.ai.mit.edu}, if they are less +than about 25,000 characters. If longer than that, either make them +available somehow (e.g. anonymous FTP), and announce it on +@code{bug-gdb}, or send them directly to the GDB maintainers at +@code{gdb-patches@@cygnus.com}. + +@node Host Conditionals +@chapter Host Conditionals + +When GDB is configured and compiled, various macros are defined or left +undefined, to control compilation based on the attributes of the host +system. These macros and their meanings are: + +@emph{NOTE: For now, both host and target conditionals are here. +Eliminate target conditionals from this list as they are identified.} + +@table @code +@item BLOCK_ADDRESS_FUNCTION_RELATIVE +dbxread.c +@item GDBINIT_FILENAME +The default name of GDB's initialization file (normally @file{.gdbinit}). +@item KERNELDEBUG +tm-hppa.h +@item MEM_FNS_DECLARED +Your host config file defines this if it includes +declarations of @code{memcpy} and @code{memset}. Define this +to avoid conflicts between the native include +files and the declarations in @file{defs.h}. +@item NO_SYS_FILE +dbxread.c +@item PYRAMID_CONTROL_FRAME_DEBUGGING +pyr-xdep.c +@item SIGWINCH_HANDLER_BODY +utils.c +@item ADDITIONAL_OPTIONS +main.c +@item ADDITIONAL_OPTION_CASES +main.c +@item ADDITIONAL_OPTION_HANDLER +main.c +@item ADDITIONAL_OPTION_HELP +main.c +@item ADDR_BITS_REMOVE +defs.h +@item AIX_BUGGY_PTRACE_CONTINUE +infptrace.c +@item ALIGN_STACK_ON_STARTUP +main.c +@item ALTOS +altos-xdep.c +@item ALTOS_AS +xm-altos.h +@item ASCII_COFF +remote-adapt.c +@item BADMAG +coffread.c +@item BCS +tm-delta88.h +@item BEFORE_MAIN_LOOP_HOOK +main.c +@item BELIEVE_PCC_PROMOTION +coffread.c +@item BELIEVE_PCC_PROMOTION_TYPE +stabsread.c +@item BITS_BIG_ENDIAN +defs.h +@item BKPT_AT_MAIN +solib.c +@item BLOCK_ADDRESS_ABSOLUTE +dbxread.c +@item BPT_VECTOR +tm-m68k.h +@item BREAKPOINT +tm-m68k.h +@item BREAKPOINT_DEBUG +breakpoint.c +@item BROKEN_LARGE_ALLOCA +Avoid large @code{alloca}'s. For example, on sun's, Large alloca's fail +because the attempt to increase the stack limit in main() fails because +shared libraries are allocated just below the initial stack limit. The +SunOS kernel will not allow the stack to grow into the area occupied by +the shared libraries. +@item BSTRING +regex.c +@item CALL_DUMMY +valops.c +@item CALL_DUMMY_LOCATION +inferior.h +@item CALL_DUMMY_STACK_ADJUST +valops.c +@item CANNOT_FETCH_REGISTER +hppabsd-xdep.c +@item CANNOT_STORE_REGISTER +findvar.c +@item CFRONT_PRODUCER +dwarfread.c +@item CHILD_PREPARE_TO_STORE +inftarg.c +@item CLEAR_DEFERRED_STORES +inflow.c +@item CLEAR_SOLIB +objfiles.c +@item COFF_ENCAPSULATE +hppabsd-tdep.c +@item COFF_FORMAT +symm-tdep.c +@item CORE_NEEDS_RELOCATION +stack.c +@item CPLUS_MARKER +cplus-dem.c +@item CREATE_INFERIOR_HOOK +infrun.c +@item C_ALLOCA +regex.c +@item C_GLBLREG +coffread.c +@item DBXREAD_ONLY +partial-stab.h +@item DBX_PARM_SYMBOL_CLASS +stabsread.c +@item DEBUG +remote-adapt.c +@item DEBUG_INFO +partial-stab.h +@item DEBUG_PTRACE +hppabsd-xdep.c +@item DECR_PC_AFTER_BREAK +breakpoint.c +@item DEFAULT_PROMPT +The default value of the prompt string (normally @code{"(gdb) "}). +@item DELTA88 +m88k-xdep.c +@item DEV_TTY +symmisc.c +@item DGUX +m88k-xdep.c +@item DISABLE_UNSETTABLE_BREAK +breakpoint.c +@item DONT_USE_REMOTE +remote.c +@item DO_DEFERRED_STORES +infrun.c +@item DO_REGISTERS_INFO +infcmd.c +@item EXTRACT_RETURN_VALUE +tm-m68k.h +@item EXTRACT_STRUCT_VALUE_ADDRESS +values.c +@item EXTRA_FRAME_INFO +frame.h +@item EXTRA_SYMTAB_INFO +symtab.h +@item FILES_INFO_HOOK +target.c +@item FLOAT_INFO +infcmd.c +@item FOPEN_RB +defs.h +@item FRAMELESS_FUNCTION_INVOCATION +blockframe.c +@item FRAME_ARGS_ADDRESS_CORRECT +stack.c +@item FRAME_CHAIN_COMBINE +blockframe.c +@item FRAME_CHAIN_VALID +frame.h +@item FRAME_CHAIN_VALID_ALTERNATE +frame.h +@item FRAME_FIND_SAVED_REGS +stack.c +@item FRAME_GET_BASEREG_VALUE +frame.h +@item FRAME_NUM_ARGS +tm-m68k.h +@item FRAME_SPECIFICATION_DYADIC +stack.c +@item FUNCTION_EPILOGUE_SIZE +coffread.c +@item F_OK +xm-ultra3.h +@item GCC2_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_MANGLE_BUG +symtab.c +@item GCC_PRODUCER +dwarfread.c +@item GET_SAVED_REGISTER +findvar.c +@item GPLUS_PRODUCER +dwarfread.c +@item HANDLE_RBRAC +partial-stab.h +@item HAVE_MMAP +In some cases, use the system call @code{mmap} for reading symbol +tables. For some machines this allows for sharing and quick updates. +@item HAVE_REGISTER_WINDOWS +findvar.c +@item HAVE_SIGSETMASK +main.c +@item HAVE_TERMIO +inflow.c +@item HEADER_SEEK_FD +arm-tdep.c +@item HOSTING_ONLY +xm-rtbsd.h +@item HOST_BYTE_ORDER +ieee-float.c +@item HPUX_ASM +xm-hp300hpux.h +@item HPUX_VERSION_5 +hp300ux-xdep.c +@item HP_OS_BUG +infrun.c +@item I80960 +remote-vx.c +@item IEEE_DEBUG +ieee-float.c +@item IEEE_FLOAT +valprint.c +@item IGNORE_SYMBOL +dbxread.c +@item INIT_EXTRA_FRAME_INFO +blockframe.c +@item INIT_EXTRA_SYMTAB_INFO +symfile.c +@item INIT_FRAME_PC +blockframe.c +@item INNER_THAN +valops.c +@item INT_MAX +defs.h +@item INT_MIN +defs.h +@item IN_GDB +i960-pinsn.c +@item IN_SIGTRAMP +infrun.c +@item IN_SOLIB_TRAMPOLINE +infrun.c +@item ISATTY +main.c +@item IS_TRAPPED_INTERNALVAR +values.c +@item KERNELDEBUG +dbxread.c +@item KERNEL_DEBUGGING +tm-ultra3.h +@item KERNEL_U_ADDR +Define this to the address of the @code{u} structure (the ``user struct'', +also known as the ``u-page'') in kernel virtual memory. GDB needs to know +this so that it can subtract this address from absolute addresses in +the upage, that are obtained via ptrace or from core files. On systems +that don't need this value, set it to zero. +@item KERNEL_U_ADDR_BSD +Define this to cause GDB to determine the address of @code{u} at runtime, +by using Berkeley-style @code{nlist} on the kernel's image in the root +directory. +@item KERNEL_U_ADDR_HPUX +Define this to cause GDB to determine the address of @code{u} at runtime, +by using HP-style @code{nlist} on the kernel's image in the root +directory. +@item LCC_PRODUCER +dwarfread.c +@item LOG_FILE +remote-adapt.c +@item LONGERNAMES +cplus-dem.c +@item LONGEST +defs.h +@item CC_HAS_LONG_LONG +defs.h +@item PRINTF_HAS_LONG_LONG +defs.h +@item LONG_MAX +defs.h +@item LSEEK_NOT_LINEAR +source.c +@item L_LNNO32 +coffread.c +@item L_SET +This macro is used as the argument to lseek (or, most commonly, bfd_seek). +FIXME, it should be replaced by SEEK_SET instead, which is the POSIX equivalent. +@item MACHKERNELDEBUG +hppabsd-tdep.c +@item MAINTENANCE +dwarfread.c +@item MAINTENANCE_CMDS +If the value of this is 1, then a number of optional maintenance commands +are compiled in. +@item MALLOC_INCOMPATIBLE +Define this if the system's prototype for @code{malloc} differs from the +@sc{ANSI} definition. +@item MIPSEL +mips-tdep.c +@item MMAP_BASE_ADDRESS +When using HAVE_MMAP, the first mapping should go at this address. +@item MMAP_INCREMENT +when using HAVE_MMAP, this is the increment between mappings. +@item MONO +ser-go32.c +@item MOTOROLA +xm-altos.h +@item NBPG +altos-xdep.c +@item NEED_POSIX_SETPGID +infrun.c +@item NEED_TEXT_START_END +exec.c +@item NFAILURES +regex.c +@item NORETURN +(in defs.h - is this really useful to define/undefine?) +@item NOTDEF +regex.c +@item NOTDEF +remote-adapt.c +@item NOTDEF +remote-mm.c +@item NOTICE_SIGNAL_HANDLING_CHANGE +infrun.c +@item NO_HIF_SUPPORT +remote-mm.c +@item NO_JOB_CONTROL +signals.h +@item NO_MMALLOC +GDB will use the @code{mmalloc} library for memory allocation for symbol +reading, unless this symbol is defined. Define it on systems +on which @code{mmalloc} does not +work for some reason. One example is the DECstation, where its RPC +library can't cope with our redefinition of @code{malloc} to call +@code{mmalloc}. When defining @code{NO_MMALLOC}, you will also have +to override the setting of @code{MMALLOC_LIB} to empty, in the Makefile. +Therefore, this define is usually set on the command line by overriding +@code{MMALLOC_DISABLE} in @file{config/*/*.mh}, rather than by defining +it in @file{xm-*.h}. +@item NO_MMALLOC_CHECK +Define this if you are using @code{mmalloc}, but don't want the overhead +of checking the heap with @code{mmcheck}. +@item NO_SIGINTERRUPT +remote-adapt.c +@item NO_SINGLE_STEP +infptrace.c +@item NS32K_SVC_IMMED_OPERANDS +ns32k-opcode.h +@item NUMERIC_REG_NAMES +mips-tdep.c +@item N_SETV +dbxread.c +@item N_SET_MAGIC +hppabsd-tdep.c +@item NaN +tm-umax.h +@item ONE_PROCESS_WRITETEXT +breakpoint.c +@item O_BINARY +exec.c +@item O_RDONLY +xm-ultra3.h +@item PC +convx-opcode.h +@item PCC_SOL_BROKEN +dbxread.c +@item PC_IN_CALL_DUMMY +inferior.h +@item PC_LOAD_SEGMENT +stack.c +@item PRINT_RANDOM_SIGNAL +infcmd.c +@item PRINT_REGISTER_HOOK +infcmd.c +@item PRINT_TYPELESS_INTEGER +valprint.c +@item PROCESS_LINENUMBER_HOOK +buildsym.c +@item PROLOGUE_FIRSTLINE_OVERLAP +infrun.c +@item PSIGNAL_IN_SIGNAL_H +defs.h +@item PUSH_ARGUMENTS +valops.c +@item PYRAMID_CONTROL_FRAME_DEBUGGING +pyr-xdep.c +@item PYRAMID_CORE +pyr-xdep.c +@item PYRAMID_PTRACE +pyr-xdep.c +@item REGISTER_BYTES +remote.c +@item REGISTER_NAMES +tm-a29k.h +@item REG_STACK_SEGMENT +exec.c +@item REG_STRUCT_HAS_ADDR +findvar.c +@item RE_NREGS +regex.h +@item R_FP +dwarfread.c +@item R_OK +xm-altos.h +@item SEEK_END +state.c +@item SEEK_SET +state.c +@item SEM +coffread.c +@item SET_STACK_LIMIT_HUGE +When defined, stack limits will be raised to their maximum. Use this +if your host supports @code{setrlimit} and you have trouble with +@code{stringtab} in @file{dbxread.c}. + +Also used in @file{fork-child.c} to return stack limits before child +processes are forked. +@item SHELL_COMMAND_CONCAT +infrun.c +@item SHELL_FILE +infrun.c +@item SHIFT_INST_REGS +breakpoint.c +@item SIGN_EXTEND_CHAR +regex.c +@item SIGTRAP_STOP_AFTER_LOAD +infrun.c +@item SKIP_PROLOGUE +tm-m68k.h +@item SKIP_PROLOGUE_FRAMELESS_P +blockframe.c +@item SKIP_TRAMPOLINE_CODE +infrun.c +@item SOLIB_ADD +core.c +@item SOLIB_CREATE_INFERIOR_HOOK +infrun.c +@item STACK_ALIGN +valops.c +@item START_INFERIOR_TRAPS_EXPECTED +infrun.c +@item STOP_SIGNAL +main.c +@item STORE_RETURN_VALUE +tm-m68k.h +@item SUN4_COMPILER_FEATURE +infrun.c +@item SUN_FIXED_LBRAC_BUG +dbxread.c +@item SVR4_SHARED_LIBS +solib.c +@item SWITCH_ENUM_BUG +regex.c +@item SYM1 +tm-ultra3.h +@item SYMBOL_RELOADING_DEFAULT +symfile.c +@item SYNTAX_TABLE +regex.c +@item Sword +regex.c +@item TDESC +infrun.c +@item TIOCGETC +inflow.c +@item TIOCGLTC +inflow.c +@item TIOCGPGRP +inflow.c +@item TIOCLGET +inflow.c +@item TIOCLSET +inflow.c +@item TIOCNOTTY +inflow.c +@item T_ARG +coffread.c +@item T_VOID +coffread.c +@item UINT_MAX +defs.h +@item UPAGES +altos-xdep.c +@item USER +m88k-tdep.c +@item USE_GAS +xm-news.h +@item USE_O_NOCTTY +inflow.c +@item USE_STRUCT_CONVENTION +values.c +@item USG +Means that System V (prior to SVR4) include files are in use. +(FIXME: This symbol is abused in @file{infrun.c}, @file{regex.c}, +@file{remote-nindy.c}, and @file{utils.c} for other things, at the moment.) +@item USIZE +xm-m88k.h +@item U_FPSTATE +i386-xdep.c +@item VARIABLES_INSIDE_BLOCK +dbxread.c +@item WRS_ORIG +remote-vx.c +@item _LANG_c +language.c +@item _LANG_m2 +language.c +@item __GNUC__ +news-xdep.c +@item __GO32__ +inflow.c +@item __HPUX_ASM__ +xm-hp300hpux.h +@item __INT_VARARGS_H +printcmd.c +@item __not_on_pyr_yet +pyr-xdep.c +@item alloca +defs.h +@item const +defs.h +@item GOULD_PN +gould-pinsn.c +@item hp800 +xm-hppabsd.h +@item hpux +hppabsd-core.c +@item lint +valarith.c +@item longest_to_int +defs.h +@item mc68020 +m68k-stub.c +@item notdef +gould-pinsn.c +@item ns32k_opcodeT +ns32k-opcode.h +@item sgi +mips-tdep.c +@item sparc +regex.c +@item sun +m68k-tdep.c +@item sun386 +tm-sun386.h +@item test +regex.c +@item ultrix +xm-mips.h +@item volatile +defs.h +@end table + +@node Target Conditionals +@chapter Target Conditionals + +When GDB is configured and compiled, various macros are defined or left +undefined, to control compilation based on the attributes of the target +system. These macros and their meanings are: + +@emph{NOTE: For now, both host and target conditionals are here. +Eliminate host conditionals from this list as they are identified.} + +@table @code +@item PUSH_DUMMY_FRAME +Used in @samp{call_function_by_hand} to create an artificial stack frame. +@item POP_FRAME +Used in @samp{call_function_by_hand} to remove an artificial stack frame. +@item BLOCK_ADDRESS_FUNCTION_RELATIVE +dbxread.c +@item KERNELDEBUG +tm-hppa.h +@item NO_SYS_FILE +dbxread.c +@item PYRAMID_CONTROL_FRAME_DEBUGGING +pyr-xdep.c +@item SIGWINCH_HANDLER_BODY +utils.c +@item ADDITIONAL_OPTIONS +main.c +@item ADDITIONAL_OPTION_CASES +main.c +@item ADDITIONAL_OPTION_HANDLER +main.c +@item ADDITIONAL_OPTION_HELP +main.c +@item ADDR_BITS_REMOVE +defs.h +@item ALIGN_STACK_ON_STARTUP +main.c +@item ALTOS +altos-xdep.c +@item ALTOS_AS +xm-altos.h +@item ASCII_COFF +remote-adapt.c +@item BADMAG +coffread.c +@item BCS +tm-delta88.h +@item BEFORE_MAIN_LOOP_HOOK +main.c +@item BELIEVE_PCC_PROMOTION +coffread.c +@item BELIEVE_PCC_PROMOTION_TYPE +stabsread.c +@item BITS_BIG_ENDIAN +defs.h +@item BKPT_AT_MAIN +solib.c +@item BLOCK_ADDRESS_ABSOLUTE +dbxread.c +@item BPT_VECTOR +tm-m68k.h +@item BREAKPOINT +tm-m68k.h +@item BREAKPOINT_DEBUG +breakpoint.c +@item BSTRING +regex.c +@item CALL_DUMMY +valops.c +@item CALL_DUMMY_LOCATION +inferior.h +@item CALL_DUMMY_STACK_ADJUST +valops.c +@item CANNOT_FETCH_REGISTER +hppabsd-xdep.c +@item CANNOT_STORE_REGISTER +findvar.c +@item CFRONT_PRODUCER +dwarfread.c +@item CHILD_PREPARE_TO_STORE +inftarg.c +@item CLEAR_DEFERRED_STORES +inflow.c +@item CLEAR_SOLIB +objfiles.c +@item COFF_ENCAPSULATE +hppabsd-tdep.c +@item COFF_FORMAT +symm-tdep.c +@item CORE_NEEDS_RELOCATION +stack.c +@item CPLUS_MARKER +cplus-dem.c +@item CREATE_INFERIOR_HOOK +infrun.c +@item C_ALLOCA +regex.c +@item C_GLBLREG +coffread.c +@item DBXREAD_ONLY +partial-stab.h +@item DBX_PARM_SYMBOL_CLASS +stabsread.c +@item DEBUG +remote-adapt.c +@item DEBUG_INFO +partial-stab.h +@item DEBUG_PTRACE +hppabsd-xdep.c +@item DECR_PC_AFTER_BREAK +breakpoint.c +@item DELTA88 +m88k-xdep.c +@item DEV_TTY +symmisc.c +@item DGUX +m88k-xdep.c +@item DISABLE_UNSETTABLE_BREAK +breakpoint.c +@item DONT_USE_REMOTE +remote.c +@item DO_DEFERRED_STORES +infrun.c +@item DO_REGISTERS_INFO +infcmd.c +@item END_OF_TEXT_DEFAULT +This is an expression that should designate the end of the text section +(? FIXME ?) +@item EXTRACT_RETURN_VALUE +tm-m68k.h +@item EXTRACT_STRUCT_VALUE_ADDRESS +values.c +@item EXTRA_FRAME_INFO +frame.h +@item EXTRA_SYMTAB_INFO +symtab.h +@item FILES_INFO_HOOK +target.c +@item FLOAT_INFO +infcmd.c +@item FOPEN_RB +defs.h +@item FP0_REGNUM +a68v-xdep.c +@item FPC_REGNUM +mach386-xdep.c +@item FP_REGNUM +parse.c +@item FPU +Unused? 6-oct-92 rich@@cygnus.com. FIXME. +@item FRAMELESS_FUNCTION_INVOCATION +blockframe.c +@item FRAME_ARGS_ADDRESS_CORRECT +stack.c +@item FRAME_CHAIN +Given FRAME, return a pointer to the calling frame. +@item FRAME_CHAIN_COMBINE +blockframe.c +@item FRAME_CHAIN_VALID +frame.h +@item FRAME_CHAIN_VALID_ALTERNATE +frame.h +@item FRAME_FIND_SAVED_REGS +stack.c +@item FRAME_GET_BASEREG_VALUE +frame.h +@item FRAME_NUM_ARGS +tm-m68k.h +@item FRAME_SPECIFICATION_DYADIC +stack.c +@item FRAME_SAVED_PC +Given FRAME, return the pc saved there. That is, the return address. +@item FUNCTION_EPILOGUE_SIZE +coffread.c +@item F_OK +xm-ultra3.h +@item GCC2_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_MANGLE_BUG +symtab.c +@item GCC_PRODUCER +dwarfread.c +@item GDB_TARGET_IS_HPPA +This determines whether horrible kludge code in dbxread.c and partial-stab.h +is used to mangle multiple-symbol-table files from HPPA's. This should all +be ripped out, and a scheme like elfread.c used. +@item GDB_TARGET_IS_MACH386 +mach386-xdep.c +@item GDB_TARGET_IS_SUN3 +a68v-xdep.c +@item GDB_TARGET_IS_SUN386 +sun386-xdep.c +@item GET_LONGJMP_TARGET +For most machines, this is a target-dependent parameter. On the DECstation +and the Iris, this is a native-dependent parameter, since is +needed to define it. + +This macro determines the target PC address that longjmp() will jump +to, assuming that we have just stopped at a longjmp breakpoint. It +takes a CORE_ADDR * as argument, and stores the target PC value through +this pointer. It examines the current state of the machine as needed. +@item GET_SAVED_REGISTER +findvar.c +@item GPLUS_PRODUCER +dwarfread.c +@item GR64_REGNUM +remote-adapt.c +@item GR64_REGNUM +remote-mm.c +@item HANDLE_RBRAC +partial-stab.h +@item HAVE_68881 +m68k-tdep.c +@item HAVE_REGISTER_WINDOWS +findvar.c +@item HAVE_SIGSETMASK +main.c +@item HAVE_TERMIO +inflow.c +@item HEADER_SEEK_FD +arm-tdep.c +@item HOSTING_ONLY +xm-rtbsd.h +@item HOST_BYTE_ORDER +ieee-float.c +@item HPUX_ASM +xm-hp300hpux.h +@item HPUX_VERSION_5 +hp300ux-xdep.c +@item HP_OS_BUG +infrun.c +@item I80960 +remote-vx.c +@item IBM6000_TARGET +Shows that we are configured for an IBM RS/6000 target. This conditional +should be eliminated (FIXME) and replaced by feature-specific macros. +It was introduced in haste and we are repenting at leisure. +@item IEEE_DEBUG +ieee-float.c +@item IEEE_FLOAT +valprint.c +@item IGNORE_SYMBOL +dbxread.c +@item INIT_EXTRA_FRAME_INFO +blockframe.c +@item INIT_EXTRA_SYMTAB_INFO +symfile.c +@item INIT_FRAME_PC +blockframe.c +@item INNER_THAN +valops.c +@item INT_MAX +defs.h +@item INT_MIN +defs.h +@item IN_GDB +i960-pinsn.c +@item IN_SIGTRAMP +infrun.c +@item IN_SOLIB_TRAMPOLINE +infrun.c +@item ISATTY +main.c +@item IS_TRAPPED_INTERNALVAR +values.c +@item KERNELDEBUG +dbxread.c +@item KERNEL_DEBUGGING +tm-ultra3.h +@item LCC_PRODUCER +dwarfread.c +@item LOG_FILE +remote-adapt.c +@item LONGERNAMES +cplus-dem.c +@item LONGEST +defs.h +@item CC_HAS_LONG_LONG +defs.h +@item PRINTF_HAS_LONG_LONG +defs.h +@item LONG_MAX +defs.h +@item L_LNNO32 +coffread.c +@item MACHKERNELDEBUG +hppabsd-tdep.c +@item MAINTENANCE +dwarfread.c +@item MIPSEL +mips-tdep.c +@item MOTOROLA +xm-altos.h +@item NBPG +altos-xdep.c +@item NEED_POSIX_SETPGID +infrun.c +@item NEED_TEXT_START_END +exec.c +@item NFAILURES +regex.c +@item NNPC_REGNUM +infrun.c +@item NOTDEF +regex.c +@item NOTDEF +remote-adapt.c +@item NOTDEF +remote-mm.c +@item NOTICE_SIGNAL_HANDLING_CHANGE +infrun.c +@item NO_HIF_SUPPORT +remote-mm.c +@item NO_SIGINTERRUPT +remote-adapt.c +@item NO_SINGLE_STEP +infptrace.c +@item NPC_REGNUM +infcmd.c +@item NS32K_SVC_IMMED_OPERANDS +ns32k-opcode.h +@item NUMERIC_REG_NAMES +mips-tdep.c +@item N_SETV +dbxread.c +@item N_SET_MAGIC +hppabsd-tdep.c +@item NaN +tm-umax.h +@item ONE_PROCESS_WRITETEXT +breakpoint.c +@item PC +convx-opcode.h +@item PCC_SOL_BROKEN +dbxread.c +@item PC_IN_CALL_DUMMY +inferior.h +@item PC_LOAD_SEGMENT +stack.c +@item PC_REGNUM +parse.c +@item PRINT_RANDOM_SIGNAL +infcmd.c +@item PRINT_REGISTER_HOOK +infcmd.c +@item PRINT_TYPELESS_INTEGER +valprint.c +@item PROCESS_LINENUMBER_HOOK +buildsym.c +@item PROLOGUE_FIRSTLINE_OVERLAP +infrun.c +@item PSIGNAL_IN_SIGNAL_H +defs.h +@item PS_REGNUM +parse.c +@item PUSH_ARGUMENTS +valops.c +@item REGISTER_BYTES +remote.c +@item REGISTER_NAMES +tm-a29k.h +@item REG_STACK_SEGMENT +exec.c +@item REG_STRUCT_HAS_ADDR +findvar.c +@item RE_NREGS +regex.h +@item R_FP +dwarfread.c +@item R_OK +xm-altos.h +@item SDB_REG_TO_REGNUM +Define this to convert sdb register numbers +into gdb regnums. If not defined, no conversion will be done. +@item SEEK_END +state.c +@item SEEK_SET +state.c +@item SEM +coffread.c +@item SHELL_COMMAND_CONCAT +infrun.c +@item SHELL_FILE +infrun.c +@item SHIFT_INST_REGS +breakpoint.c +@item SIGN_EXTEND_CHAR +regex.c +@item SIGTRAP_STOP_AFTER_LOAD +infrun.c +@item SKIP_PROLOGUE +tm-m68k.h +@item SKIP_PROLOGUE_FRAMELESS_P +blockframe.c +@item SKIP_TRAMPOLINE_CODE +infrun.c +@item SOLIB_ADD +core.c +@item SOLIB_CREATE_INFERIOR_HOOK +infrun.c +@item SP_REGNUM +parse.c +@item STAB_REG_TO_REGNUM +Define this to convert stab register numbers (as gotten from `r' declarations) +into gdb regnums. If not defined, no conversion will be done. +@item STACK_ALIGN +valops.c +@item START_INFERIOR_TRAPS_EXPECTED +infrun.c +@item STOP_SIGNAL +main.c +@item STORE_RETURN_VALUE +tm-m68k.h +@item SUN4_COMPILER_FEATURE +infrun.c +@item SUN_FIXED_LBRAC_BUG +dbxread.c +@item SVR4_SHARED_LIBS +solib.c +@item SWITCH_ENUM_BUG +regex.c +@item SYM1 +tm-ultra3.h +@item SYMBOL_RELOADING_DEFAULT +symfile.c +@item SYNTAX_TABLE +regex.c +@item Sword +regex.c +@item TARGET_BYTE_ORDER +defs.h +@item TARGET_CHAR_BIT +defs.h +@item TARGET_COMPLEX_BIT +defs.h +@item TARGET_DOUBLE_BIT +defs.h +@item TARGET_DOUBLE_COMPLEX_BIT +defs.h +@item TARGET_FLOAT_BIT +defs.h +@item TARGET_INT_BIT +defs.h +@item TARGET_LONG_BIT +defs.h +@item TARGET_LONG_DOUBLE_BIT +defs.h +@item TARGET_LONG_LONG_BIT +defs.h +@item TARGET_PTR_BIT +defs.h +@item TARGET_READ_PC +@item TARGET_WRITE_PC +@item TARGET_READ_SP +@item TARGET_WRITE_SP +@item TARGET_READ_FP +@item TARGET_WRITE_FP +These change the behavior of @code{read_pc}, @code{write_pc}, +@code{read_sp}, @code{write_sp}, @code{read_fp} and @code{write_fp}. +For most targets, these may be left undefined. GDB will call the +read and write register functions with the relevant @code{_REGNUM} argument. + +These macros are useful when a target keeps one of these registers in a +hard to get at place; for example, part in a segment register and part +in an ordinary register. + +@item TARGET_SHORT_BIT +defs.h +@item TDESC +infrun.c +@item T_ARG +coffread.c +@item T_VOID +coffread.c +@item UINT_MAX +defs.h +@item USER +m88k-tdep.c +@item USE_GAS +xm-news.h +@item USE_STRUCT_CONVENTION +values.c +@item USIZE +xm-m88k.h +@item U_FPSTATE +i386-xdep.c +@item VARIABLES_INSIDE_BLOCK +dbxread.c +@item WRS_ORIG +remote-vx.c +@item _LANG_c +language.c +@item _LANG_m2 +language.c +@item __GO32__ +inflow.c +@item __HPUX_ASM__ +xm-hp300hpux.h +@item __INT_VARARGS_H +printcmd.c +@item __not_on_pyr_yet +pyr-xdep.c +@item GOULD_PN +gould-pinsn.c +@item hp800 +xm-hppabsd.h +@item hpux +hppabsd-core.c +@item longest_to_int +defs.h +@item mc68020 +m68k-stub.c +@item ns32k_opcodeT +ns32k-opcode.h +@item sgi +mips-tdep.c +@item sparc +regex.c +@item sun +m68k-tdep.c +@item sun386 +tm-sun386.h +@item test +(Define this to enable testing code in regex.c.) +@end table + +@node Native Conditionals +@chapter Native Conditionals + +When GDB is configured and compiled, various macros are defined or left +undefined, to control compilation when the host and target systems +are the same. These macros should be defined (or left undefined) +in @file{nm-@var{system}.h}. + +@table @code +@item ATTACH_DETACH +If defined, then gdb will include support for the @code{attach} and +@code{detach} commands. +@item FETCH_INFERIOR_REGISTERS +Define this if the native-dependent code will provide its +own routines +@code{fetch_inferior_registers} and @code{store_inferior_registers} in +@file{@var{HOST}-nat.c}. +If this symbol is @emph{not} defined, and @file{infptrace.c} +is included in this configuration, the default routines in +@file{infptrace.c} are used for these functions. +@item GET_LONGJMP_TARGET +For most machines, this is a target-dependent parameter. On the DECstation +and the Iris, this is a native-dependent parameter, since is +needed to define it. + +This macro determines the target PC address that longjmp() will jump +to, assuming that we have just stopped at a longjmp breakpoint. It +takes a CORE_ADDR * as argument, and stores the target PC value through +this pointer. It examines the current state of the machine as needed. +@item PROC_NAME_FMT +Defines the format for the name of a @file{/proc} device. Should be +defined in @file{nm.h} @emph{only} in order to override the default +definition in @file{procfs.c}. +@item PTRACE_FP_BUG +mach386-xdep.c +@item PTRACE_ARG3_TYPE +The type of the third argument to the @code{ptrace} system call, if it exists +and is different from @code{int}. +@item REGISTER_U_ADDR +Defines the offset of the registers in the ``u area''; @pxref{Host}. +@item USE_PROC_FS +This determines whether small routines in @file{*-tdep.c}, which +translate register values +between GDB's internal representation and the /proc representation, +are compiled. +@item U_REGS_OFFSET +This is the offset of the registers in the upage. It need only be +defined if the generic ptrace register access routines in +@file{infptrace.c} are being used (that is, +@file{infptrace.c} is configured in, and +@code{FETCH_INFERIOR_REGISTERS} is not defined). If the default value +from @file{infptrace.c} is good enough, leave it undefined. + +The default value means that u.u_ar0 @emph{points to} the location of the +registers. I'm guessing that @code{#define U_REGS_OFFSET 0} means that +u.u_ar0 @emph{is} the location of the registers. +@end table + +@node Obsolete Conditionals +@chapter Obsolete Conditionals + +Fragments of old code in GDB sometimes reference or set the following +configuration macros. They should not be used by new code, and +old uses should be removed as those parts of the debugger are +otherwise touched. + +@table @code +@item STACK_END_ADDR +This macro used to define where the end of the stack appeared, for use +in interpreting core file formats that don't record this address in the +core file itself. This information is now configured in BFD, and GDB +gets the info portably from there. The values in GDB's configuration +files should be moved into BFD configuration files (if needed there), +and deleted from all of GDB's config files. + +Any @file{@var{foo}-xdep.c} file that references STACK_END_ADDR +is so old that it has never been converted to use BFD. Now that's old! +@end table + +@node XCOFF +@chapter The XCOFF Object File Format + +The IBM RS/6000 running AIX uses an object file format called xcoff. +The COFF sections, symbols, and line numbers are used, but debugging +symbols are dbx-style stabs whose strings are located in the +@samp{.debug} section (rather than the string table). For more +information, @xref{Top,,,stabs,The Stabs Debugging Format}, and search +for XCOFF. + +The shared library scheme has a nice clean interface for figuring out +what shared libraries are in use, but the catch is that everything which +refers to addresses (symbol tables and breakpoints at least) needs to be +relocated for both shared libraries and the main executable. At least +using the standard mechanism this can only be done once the program has +been run (or the core file has been read). + +@contents +@bye diff --git a/gnu/usr.bin/gdb/doc/h8-cfg.texi b/gnu/usr.bin/gdb/doc/h8-cfg.texi new file mode 100644 index 00000000000..823c7c244b5 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/h8-cfg.texi @@ -0,0 +1,47 @@ +@c GDB version number is recorded in the variable GDBVN +@include GDBvn.texi +@c +@set AGGLOMERATION +@clear AMD29K +@set BARETARGET +@clear CONLY +@set DOSHOST +@clear FORTRAN +@clear FSFDOC +@clear GDBSERVER +@clear GENERIC +@set H8 +@set H8EXCLUSIVE +@clear HAVE-FLOAT +@clear I960 +@clear MOD2 +@clear NOVEL +@clear POSIX +@set PRECONFIGURED +@clear REMOTESTUB +@set SIMS +@clear SERIAL +@clear SPARC +@clear ST2000 +@clear VXWORKS +@clear Z8K +@c ---------------------------------------------------------------------- +@c STRINGS: +@c +@c Name of GDB program. Used also for (gdb) prompt string. +@set GDBP gdb +@c +@c Name of GDB product. Used in running text. +@set GDBN GDB +@c +@c Name of GDB initialization file. +@set GDBINIT .gdbinit +@c +@c Name of target. +@set TARGET Hitachi Microprocessors +@c +@c Name of GCC product +@set NGCC GCC +@c +@c Name of GCC program +@set GCC gcc diff --git a/gnu/usr.bin/gdb/doc/libgdb.texinfo b/gnu/usr.bin/gdb/doc/libgdb.texinfo new file mode 100644 index 00000000000..c67c3a88359 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/libgdb.texinfo @@ -0,0 +1,1471 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename libgdb.info +@settitle Libgdb +@setchapternewpage odd +@c %**end of header + +@ifinfo +This file documents libgdb, the GNU library for symbolic debuggers. + +Copyright 1993 Cygnus Support + +Permission is granted to ... +@end ifinfo + +@c This title page illustrates only one of the +@c two methods of forming a title page. + +@titlepage +@title Libgdb +@subtitle Version 0.1 +@subtitle 27 Sep 1993 +@author Thomas Lord + +@c The following two commands +@c start the copyright page. +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1993 COPYRIGHT-OWNER + +Published by ... + +Permission is granted to ... +@end titlepage + +@node Top, Overview, (dir), (dir) + +@ifinfo + +Libgdb is a library which provides the core functionality of a symbolic +debugger. It is derived from GNU GDB and depends on the BFD library. + +This is an early draft of this document. Subsequent versions will likely +contain revisions, deletions and additions. + +This document applies to version 0.0. + +Text marked `[[[' indicates areas which require expansion. + +Many nodes describe library entry points by giving a prototype and brief +description: + +@deftypefun {const char **} gdb_warranty () +(warranty_info) +Return a pointer to the text of the GDB disclaimer. +@end deftypefun + +The parenthesized symbols (e.g. `(warranty_info)') refer to the +existing GDB source and generally indicate where to find code with +which to implement the library function. +@end ifinfo + +@menu +* Copying:: Your rights and freedoms. +* Overview:: The basics of libgdb and this document. +* Conventions:: Programming conventions for users of libgdb. +* Targets:: Selecting debugging targets and symbol tables. +* Symtabs:: Accessing symbol tables and debugging information. +* Source:: Relating inferiors to source files. +* Running:: Creating, continuing, and stepping through an + inferior process. +* Stopping:: Using breakpoints, signaling an inferior. +* Stack:: Accessing an inferior's execution stack. +* Expressions:: How to parse and evaluate expressions in the + context of an inferior. +* Values:: Data from the inferior, the values of expressions. +* Examining:: Formatting values as strings. +* Types:: Examining the types of an inferiors data. +@end menu + + +@node Copying, Overview, top, top +@comment node-name, next, previous, up +@chapter Copying +@cindex copying + +blah blah + +@node Overview, Conventions, Copying, top +@comment node-name, next, previous, up +@chapter Overview +@cindex overview +@cindex definitions + + +Libgdb is a library which provides the core functionality of a symbolic +debugger. It is derived from GNU GDB and depends on the BFD library. + +target +inferior + + + +@node Conventions, Targets, Overview, top +@comment node-name, next, previous, up +@chapter Programming Conventions for Libgdb Clients +@cindex Conventions + +@heading Naming Conventions + +Names intentionally exported from libgdb all begin @code{gdb_} +as in @code{gdb_use_file}. + + +@heading Error Returns + +Libgdb functions that might not succeed generally have a return +type of @code{gdb_error_t}. + +@deftypefun {const char *} gdb_error_msg (gdb_error_t @var{error}) +returns a reasonable error message for @var{error}. +@end deftypefun + + +@heading Blocking I/O + +[[[....]]] + + +@heading Global Parameters +@subheading the current directory +@deftypefun gdb_error_t gdb_cd (char * @var{dir}) +Specify gdb's default directory as well as the working +directory for the inferior (when first started).@* +(cd_command) +@end deftypefun + +@deftypefun {char *} gdb_copy_pwd () +Make a copy of the name of gdb's default directory.@* +(pwd_command) +@end deftypefun + + +@subheading controlling the input/output radix +@deftypefun gdb_error_t gdb_set_base (int) +Change the default output radix to 10 or 16, or set it to 0 +(heuristic). This command is mostly obsolete now that the print +command allows formats to apply to aggregates, but is still handy +occasionally.@* +(set_base_command) +@end deftypefun + +@deftypefun gdb_error_t gdb_set_input_radix (int) +@deftypefunx gdb_error_t gdb_set_output_radix (int) +@deftypefunx gdb_error_t gdb_set_radix (int) +Valid output radixes are only 0 (heuristic), 10, and 16.@* +(set_radix) +@end deftypefun + + +@subheading manipulating environments +@deftp Type {struct environ} +@example +struct environ +@{ + int allocated; + char ** vector; +@} +@end example +A `struct environ' holds a description of environment +variable bindings. +@end deftp + +@deftypefun {struct environ *} gdb_make_environ () +Create a new (empty) environment.@* +(make_environ) +@end deftypefun + +@deftypefun {void} gdb_free_environ (struct environ *) +Free an environment allocated by `gdb_make_environ'.@* +(free_environ) +@end deftypefun + +@deftypefun {void} gdb_init_environ (struct environ * env) +Copy the processes environment into ENV.@* +(init_environ) +@end deftypefun + +@deftypefun {char **} gdb_get_in_environ (const struct environ * @var{env}, const char * @var{var}) +Look up the binding of @var{var} in @var{env}.@* +(get_in_environ) +@end deftypefun + + +@deftypefun {void} gdb_set_in_environ (struct environ * @var{env}, const char * @var{var}, const char * @var{value}) +Lookup/bind variables within an environment. +(set_in_environ) +@end deftypefun + + +@subheading legal notices +@deftypefun {char **} gdb_copying () +@deftypefunx {char **} gdb_warranty () +These return pointers to NULL terminated arrays of strings. +They contain text which describes the conditions under which +libgdb is distributed (`gdb_copying') and which explains to +users that there is no warranty for libgdb (`gdb_warranty').@* +(show_warranty_command, show_copying_command) +@end deftypefun + + +@subheading the inferior's terminal +@deftypefun void gdb_inferiors_io (int @var{std_in}, int @var{std_out}, int @var{std_err}) +Assert that the given descriptors should be copied into +descriptors 0, 1, and 2 of the inferior when it +is next run. +@end deftypefun + + +@heading callbacks + +One idiom used in several places deserves mention. +At times, it makes sense for libgdb functions to +invoke functions provided by the libgdb client. +Where this is the case, callback structures are used +to refer to client functions. For example, here +are the declarations for a callback to which libgdb +will pass an integer and a character pointer. + +@example +struct a_gdb_cback; +typedef void (*a_gdb_cback_fn) (struct a_gdb_cback *, + int, char *); +@end example + +Suppose the client wants the callback to be implemented +by @code{foo} which we will assume takes not only the integer +and character pointer, but also a floating point number. +The client could use these declarations: + +@example +struct my_cback +@{ + struct a_gdb_cback gdb_cback; /* must be first */ + float magic_number; +@}; + +void +foo_helper (struct a_gdb_cback * callback, int i, char * cp) +@{ + foo ( ((struct my_cback *)callback)->magic_number, i, c); +@} + +struct my_cback +@{ + foo_helper, + 1079252848.8 +@} the_cback; +@end example + + +@subheading stream callbacks + +A common kind of callback takes just a character pointer, +presumed to point to part or all of an informational +message. + +@example +struct gdb_stream_cback; +typedef void (*gdb_stream_cback_fn) (struct gdb_stream_cback *, + char *); +@end example + + +@subheading integer callbacks + +Another common kind of callback takes just an integer. + +@example +struct gdb_int_cback; +typedef void (*gdb_int_cback_fn) (struct gdb_int_cback *, int); +@end example + +@node Targets, Symtabs, Conventions, top +@comment node-name, next, previous, up +@chapter Selecting Targets and Symbol Tables for Debugging +@cindex targets + +@deftypefun gdb_error_t gdb_use_file (char * @var{filename}) +Arrange to read both executable code and symbol table information +from FILENAME. + +This is exactly equivalent to a sequence of two calls: +@example + gdb_use_exec_file (filename); + gdb_use_symbol_file (filename); +@end example +(file_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_use_exec_file (char * @var{filename}) +Read the code to debug from `filename'.@* +(exec_file_command) +@end deftypefun + + +@deftypefun {char *} gdb_get_exec_file () +Return the name of the executable file as a string or 0 +if there is none. +@end deftypefun + + +@deftypefun gdb_error_t gdb_use_core (char * @var{filename}) +Specify the whereabouts of a core dump file to be used as the +"contents of memory". Traditionally, core files contain only some +parts of the address space of the process that generated them; GDB +can access the executable file itself for other parts. + +If @var{filename} is @code{NULL}, no core file is used.@* +(core_file_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_use_symbol_file (char * @var{filename}) +Arrange to read symbol table information from `filename'. + +This is the same as: + + gdb_symbol_file_add (filename, 1, (CORE_ADDR)0, 1, 0, 0); + +See @code{gdb_symbol_file_add} for finer control over the symbol +table.@* +(symbol_file_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_symbol_file_add (@var{name}, @var{verbose}, @var{text_addr}, @var{replace}, @var{eager}) +Arrange to read additional symbol table information from +the file `name'. + +The arguments are: +@itemize @minus +@item struct gdb_stream_cback * @var{info_out} + +Callback to handle informational output. + +@item char * @var{name} + +If not 0, verbose output will occur. + +@item int @var{be_verbose} + +Regulates the amount of informational output produced. + +@item CORE_ADDR @var{text_addr} + +is the address at which the named file is presumed to have +been loaded. + +@item int @var{replace}@* + +If not 0, this will become the only file +in the symbol table -- all previously loaded +symbol table information will be discarded. + +@item int @var{readnow} + +If not 0, eagerly read symbols from this file,otherwise +symbols will only be read lazily (as needed). +@end itemize +@end deftypefun + + +@deftypefun {char *} gdb_copy_exec_path () +Make a copy of the execution path.@* +[[[implement: strsave(get_in_environ (inferior_environ, "PATH"));]]]@* +(path_info) +@end deftypefun + + +@deftypefun void gdb_mod_exec_path (char * @var{dirnames}) +Add zero or more directories to the front of the execution path. +@var{dirnames} should be a colon separated list of directory names.@* +(path_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_target_device (char * @var{name}) +Connects the libgdb host environment to a target machine +or process.@* +(target foo) +@end deftypefun + + +@deftypefun gdb_error_t gdb_set_baud (int @var{rate}) +If using a remote target connected by a serial port, +use RATE as the communication speed. +@end deftypefun + + +@deftypefun gdb_error_t gdb_set_target_debugging (int @var{level}) +Choose the level of verboseness of with which a remote +target produces debugging output. +@end deftypefun + +@node Symtabs, Source, Targets, top +@comment node-name, next, previous, up +@chapter Accessing symbol tables and debugging information. +@cindex Symtabs +@cindex {Symbol Tables} + +@deftp Type {struct symtab} +Each source file is represented by a struct symtab. +In many contexts, @code{struct symtab *} is used in preference +to a {char *} filename to refer to the source. +@end deftp + + +@deftypefun {char *} gdb_symtab_to_filename (struct symtab *) +@deftypefunx {char *} gdb_symtab_to_dirname (struct symtab *) +Return the location of the file corresponding to this symtab. +@code{gdb_symtab_to_dirname} might return @code{NULL} if no directory +is known. @code{gdb_symtab_to_line_count} might return -1 if line +number information is unavailable. +@end deftypefun + +@deftypefun int gdb_symtab_to_line_count (struct symtab *) +(See also `Source') +@end deftypefun + + +@deftypefun {struct symtab *} gdb_filename_to_symtab (char * @var{filename}) +Lookup the symbol table of a source file named NAME.@* +(lookup_symtab) +@end deftypefun + + +@deftp Type {struct symtab_and_line} +@example +struct symtab_and_line +@{ + struct symtab *symtab; + int line; + CORE_ADDR pc; + CORE_ADDR end; +@} +@end example + +@code{struct symtab_and_line} is used to refer to a particular line +of source code. It is used to locate breakpoints in the source +code and the executable. + +@code{line} starts at 1 and proceeds through symtab->nlines. +0 is never a valid line number; it is used to indicate +that line number information is not available. +@end deftp + + +@deftypefun {struct symtab_and_line} gdb_find_pc_line (CORE_ADDR @var{pc}, int @var{notcurrent}) +Find the source file and line number for a given @var{pc} value. +Return a structure containing a symtab pointer, a line number, +and a pc range for the entire source line. +The value's @code{.pc} field is NOT the specified @var{pc}. +@var{notcurrent} nonzero means, if specified pc is on a line boundary, +use the line that ends there. Otherwise, in that case, the line +that begins there is used.@* +(find_pc_line) +@end deftypefun + + +@deftypefun gdb_error_t gdb_find_line (struct symtab_and_line * @var{out}, struct symtab *, int) +Create a symtab_and_line for a given symtab and line number. +In other words, if you know the source file and line, +this returns a location for the breakpoint.@* +(resolve_sal_pc) +@end deftypefun + + +@deftypefun {struct symtabs_and_lines} gdb_decode_line (@var{argptr}, @var{firstln}, @var{default_symtab}, @var{default_line}, @var{canonical}) +@example + char ** argptr; + int funfirstline; + struct symtab * default_symtab; + int default_line; + char *** canonical; +@end example + Parse a string that specifies a line number in GDB syntax. + @var{argptr} will be advanced over the characters actually parsed. + + The string can be: + + LINENUM -- that line number in current file. PC returned is 0. + FILE:LINENUM -- that line in that file. PC returned is 0. + FUNCTION -- line number of openbrace of that function. + PC returned is the start of the function. + VARIABLE -- line number of definition of that variable. + PC returned is 0. + FILE:FUNCTION -- likewise, but prefer functions in that file. + *EXPR -- line in which address EXPR appears. + + FUNCTION may be an undebuggable function found in minimal symbol + table. + + If the argument FUNFIRSTLINE is nonzero, we want the first line + of real code inside a function when a function is specified. + + DEFAULT_SYMTAB specifies the file to use if none is specified. + It defaults to current_source_symtab. + + DEFAULT_LINE specifies the line number to use for relative line + numbers (that start with signs). Defaults to current_source_line. + If CANONICAL is non-NULL, store an array of strings containing the + canonical line specs there if necessary. Currently overloaded + member functions and line numbers or static functions without a + filename yield a canonical line spec. The array and the line spec + strings are allocated on the heap, it is the callers responsibility + to free them. + + Note that it is possible to return zero for the symtab + if no file is validly specified. Callers must check that. + Also, the line number returned may be invalid. + + The return value of this function includes allocated memory + which the caller is responsible for freeing: + + struct symtabs_and_lines sals; + sals = decode_line_spec (arg, 1); + .... + free (sals.sals);@* +(decode_line_1) +@end deftypefun + + +@deftp Type {struct block *} +Lexical environments in the program are represented by struct block. +These are useful as arguements to expression parsing functions (see +`Expressions'). +@end deftp + + +@deftypefun {struct block *} gdb_block_for_pc (CORE_ADDR) +Return the innermost lexical block containing the +specified pc value, or 0 if there is none.@* +(block_for_pc) +@end deftypefun + + +@deftypefun {struct block *} gdb_get_frame_block (FRAME @var{frame}) +This returns the block being executed by a given +stack frame (see `Stack')@* +(get_frame_block) +@end deftypefun + + +@deftypefun int gdb_find_line_pc_range (@var{syms}, @var{line}, @var{start_out}, @var{end_out}) +@example +struct symtab * @var{start_out}; +int @var{line}; +CORE_ADDR * @var{start_out}; +CORE_ADDR * @var{end_out}; +@end example +Find the range of pc values in a line.@* +Store the starting pc of the line into @code{*@var{startptr}}. +and the ending pc (start of next line) into @code{*@var{endptr}}. + +Returns 1 to indicate success.@* +Returns 0 if could not find the specified line.@* +(find_line_pc_range) +@end deftypefun + + +@deftypefun int gdb_find_pc_partial_function (@var{pc}, @var{name}, @var{address}, @var{endaddr}) +@example +CORE_ADDR @var{pc}; +char **@var{name}; +CORE_ADDR *@var{address}; +CORE_ADDR *@var{endaddr}; +@end example +Finds the "function" (text symbol) that is smaller than @var{pc} but +greatest of all of the potential text symbols. Sets @code{*@var{name}} +and/or @code{*@var{address}} conditionally if that pointer is non-null. If +@var{endaddr} is non-null, then set @code{*@var{endaddr}} to be the end of +the function (exclusive), but passing @var{endaddr} as non-null means that +the function might cause symbols to be read. This function either succeeds +or fails (not halfway succeeds). If it succeeds, it sets +@code{*@var{name}}, @code{*@var{address}}, and @code{*@var{endaddr}} to +real information and returns 1. If it fails, it sets @code{*@var{name}}, +@code{*@var{address}}, and @code{*@var{endaddr}} to zero and returns 0. + +@example + pc = get_frame_pc (selected_frame); + if (find_pc_partial_function (pc, &name, &low, &high) == 0) + error ("No function contains program counter for selected frame.\n"); +@end example +(find_pc_partial_function) +@end deftypefun + + +@deftypefun void gdb_list_symbols (@var{info_out}, @var{regexp}, @var{class}, @var{bpt}) +@example +struct gdb_stream_cback * @var{info_out}; +char * @var{regexp}; +int @var{class}; +int @var{bpt}; +@end example +List all symbols (if @var{regexp} is NULL) or all symbols matching @var{regexp}. + + +If @var{class} is ... +@itemize @bullet +@item +0, list all symbols except functions, type names, and +constants (enums). +@item +1, list only functions. +@item +2, list only type names. +@item +3, list only method names. +@end itemize +BPT is non-zero if set a breakpoint at the functions we find.@* +(variables_info, functions_info, types_info, list_symbols) +@end deftypefun + + +@deftypefun int gdb_locals_info (struct gdb_stream_cback * @var{info_out}, FRAME @var{frame}) +Print all the local variables in the given frame. +including all the blocks active in that frame +at its current pc. + +Returns 1 if the job was done, +or 0 if nothing was printed because we have no info +on the function running in @var{frame}.@* +(locals_info) +@end deftypefun + + +@deftypefun int print_frame_arg_vars (struct gdb_stream_cback *, FRAME) +Similar to `gdb_locals_info'.@* +(args_info) +@end deftypefun + +@node Source, Running, Symtabs, top +@comment node-name, next, previous, up +@chapter Relating Inferiors to Source Files +@cindex source +@cindex {source files} + +How to find the source that corresponds to executable code and the +executable code that corresponds to a line of source. + +@deftypefun {char *} gdb_copy_source_fullname (struct symtab *@var{s}) +Return a copy of the full path name to a source file. +(See `Symtabs' for more information about filenames +and symbol tables.). +@end deftypefun + + +@deftypefun int gdb_open_source_file (struct symtab *@var{s}) +Open a source file corresponding to @var{s}. Returns a file descriptor +or negative number for error. +[[[We may decide not to provide this function.]]]@* +(open_source_file) +@end deftypefun + + +@deftypefun int gdb_source_line_pos (struct symtab * @var{s}, int @var{lineno}) +Return the byte offset of a given line of source +or a negative number if @var{lineno} is out of range.@* +(find_source_lines) +@end deftypefun + + + -- IDIOM: The gdb command `show directories'. +@example + puts_filtered ("Source directories searched: "); + puts_filtered (source_path); + puts_filtered ("\n"); +@end example +(show_directories) + + +@deftypefun {char *} gdb_source_path () +Return the path in which source files are sought.@* +(source_path) +@end deftypefun + + +@deftypefun void gdb_modify_source_path (char * @var{dirnames}) +Change the source path according to dirnames.@* +(directory_command) +@end deftypefun + + +See `Symtabs' for functions relating symbol tables to files. +(source_info) + + +See `Symtabs' for functions relating source lines to PC values. +(line_info) + + +[[[Try to expose sources_info without having to introduce struct object *?]]] +(sources_info) + + +@node Running, Stopping, Source, top +@comment node-name, next, previous, up +@chapter Creating, Continuing, and Stepping Through an Inferior Process +@cindex running + + +@deftypefun gdb_error_t gdb_target_create_inferior (@var{exec}, @var{args}, @var{environ}) +@example +char * @var{exec_file}; +char * @var{inferior_args}; +char ** @var{inferior_environment_vector}; +@end example +Create a running inferior. +[[[I think the exec_file parameter is redundant. Perhaps this will take +only two arguments.]]]@* +(run_command, target_create_inferior) +@end deftypefun + + +@deftypefun int gdb_target_has_execution () +Return non-0 if an inferior is running.@* +(target_has_execution) +@end deftypefun + + +@deftypefun void gdb_target_kill () +Kill the inferior process. Make it go away. +The inferior may become a core file. +If so, gdb_target_has_stack() will return non-0.@* +(target_kill) +@end deftypefun + + +@deftypefun gdb_error_t gdb_step_1 (@var{skip_subs}, @var{single_inst}, @var{repeat_count}) +@example +int skip_subs; +int single_inst; +int repeat_count; +@end example +Continue a program a little bit. Roughly: +@example + for (; count > 0; --count) + gdb_clear_proceed_status (); + gdb_proceed (...); +@end example +(next_command, nexti_command, step_command, stepi_command) +@end deftypefun + + + -- IDIOM: Continuing a program where it stopped. +@example + gdb_clear_proceed_status (); + gdb_proceed ((CORE_ADDR) -1, -1, 0); +@end example +(continue_command) + + + -- IDIOM: Continuing a program giving it a specified signal. +@example + gdb_clear_proceed_status (); + gdb_proceed ((CORE_ADDR) -1, signum, 0); +@end example +(signal_command) + + +@deftypefun {char *} strtosigno (char * @var{str}) +(Typical use:) +@example + signum = strtosigno (signum_exp); + + if (signum == 0) + /* Not found as a name, try it as an expression. */ + signum = parse_and_eval_address (signum_exp); + + gdb_clear_proceed_status (); + gdb_proceed (); +@end example +@end deftypefun + + + -- IDIOM: Continuing a program at a specified address. +@example + gdb_clear_proceed_status (); + gdb_proceed (addr, 0, 0); +@end example +(jump_command) + + +@deftypefun gdb_error_t gdb_finish () +"finish": Set a temporary breakpoint at the place +the selected frame will return to, then continue. +This is a convenience function but it summarizes a lot +of other stuff.@* +(finish_command) +@end deftypefun + + +@deftypefun void gdb_clear_proceed_status () +Clear out all variables saying what to do when inferior is continued. +First do this, then set the ones you want, then call @code{gdb_proceed}. + + [[[Some of these should be documented, others hidden.]]] +@example + The variables are: + trap_expected = 0; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + step_over_calls = -1; + stop_after_trap = 0; + stop_soon_quietly = 0; + proceed_to_finish = 0; + breakpoint_proceeded = 1; /* We're about to proceed... */ + + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&stop_bpstat); +@end example +(clear_proceed_status) +@end deftypefun + + +@deftypefun void gdb_proceed (CORE_ADDR @var{addr}, int @var{signal}, int @var{step}) +Basic routine for continuing the program in various fashions. + +@var{addr} is the address to resume at, or -1 for resume where stopped.@* +@var{signal} is the signal to give it, or 0 for none, +or -1 for act according to how it stopped.@* +@var{step} is nonzero if should trap after one instruction. +-1 means return after that and print nothing.@* +You should probably set various step_... variables +before calling here, if you are stepping. + +You should call @code{gdb_clear_proceed_status} before calling proceed. +(See the documentation for @code{gdb_clear_proceed_status} for more +parameters to @code{gdb_proceed}).@* +(proceed) +@end deftypefun + + +@deftypefun gdb_error_t gdb_return (value @var{return_value}, FRAME @var{frame}) +Make @var{frame} return to @var{value} to it's caller. +Unlike the other functions in this section, this doesn't +call proceed. +(return_command) +@end deftypefun + + +@deftypefun int gdb_inferior_pid () +0 or the valid pid of an inferior. +@end deftypefun + + +@deftypefun gdb_error_t gdb_attach (int @var{pid}) +takes a program started up outside of gdb and +`attaches'' to it. This stops it cold in its tracks and allows us +to start debugging it. and wait for the trace-trap that results +from attaching.@* +(attach_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_detach (int @var{signal_num}) +Takes a program previously attached to and detaches it. +The program resumes execution and will no longer stop +on signals, etc. We better not have left any breakpoints +in the program or it'll die when it hits one. For this +to work, it may be necessary for the process to have been +previously attached. It *might* work if the program was +started via the normal ptrace (PTRACE_TRACEME).@* +(detach_command) +@end deftypefun + +@node Stopping, Stack, Running, top +@comment node-name, next, previous, up +@chapter Using Breakpoints, Signaling an Inferior +@cindex stopping +@cindex breakpoints + + +@deftp Type {struct breakpoint} +Breakpoints are typically represented @code{struct breakpoint *}. +@end deftp + + +@deftypefun {struct breakpoint *} gdb_find_breakpoint (int) +Find a breakpoint given it's number (return 0 if it doesn't exist). +@end deftypefun + +@deftypefun gdb_error_t gdb_set_break (struct breakpoint * @var{brk_out}, struct symtab_and_line) +@deftypefunx gdb_error_t gdb_set_tbreak (struct breakpoint *, struct symtab_and_line) +@deftypefunx gdb_error_t gdb_set_until (struct breakpoint *, struct symtab_and_line) +These three are like their command language counterparts. +They are front ends to `gdb_set_raw_breakpoint'. +See `Symtabs' for sources of `struct symtab_and_line'.@* +(break_command, break_command_1, until_command, tbreak_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_set_watchpt (@var{brk_out}, @var{exp_string}, @var{exp}, @var{exp_valid_block}) +@example +struct breakpoint * @var{brk_out}; +char * @var{exp_string}; +struct expression * @var{exp}; +struct block * @var{expression_valid_block}; +@end example +Set a watchpoint for the given expression.@* +(watch_command) +@end deftypefun + + +@deftypefun void gdb_set_ignore_count (int @var{bptnum}, int @var{count}) +Set ignore-count of breakpoint number BPTNUM to COUNT.@* +(set_ignore_count) +@end deftypefun + + +@deftypefun {struct gdb_bp_condition *} gdb_set_condition (@var{bp}, @var{exp_str}, @var{cond}) +@example +int @var{pbtnum}; +char * @var{exp_str}; +struct gdb_bp_condition * @var{cond}; + +typedef int (*gdb_bp_fn) (struct gdb_bp_condition *, int bp_num); +struct gdb_bp_condition +@{ + gdb_bp_fn fn; +@}; +@end example +Add a condition to a breakpoint. +The condition is a callback which should return +0 to skip the breakpoint, and 1 to break at it. +It is called at times when the break might occur. + +A useful application of these callbacks to attach +an expression to breakpoints like the gdb `condition' +command. See `Expressions' for the parsing and +evaluation of expressions.@* +(condition_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_enable_breakpoint (struct breakpoint * @var{bpt}, int @var{once}) +@deftypefunx gdb_error_t gdb_disable_breakpoint (struct breakpoint * @var{bpt}) +Enable/disable a breakpoint. If `once' is not 0, the +breakpoint is only temporarily enabled.@* +(enable_breakpoint, disable_breakpoint, enable_command) +@end deftypefun + + +@deftypefun gdb_error_t gdb_delete_breakpoint (struct breakpoint * @var{bpt}) +Delete a breakpoint and clean up all traces of it in the +data structures.@* +(delete_breakpoint) +@end deftypefun + + +@deftypefun void gdb_clear_breakpoints (struct symtabs_and_lines * @var{sals}) +Clear breakpoints from a list of program locations as +might be returned by `gdb_decode_line' (see `Symtabs').@* +(clear_command) +@end deftypefun + + +@deftypefun {static struct symtabs_and_lines} get_catch_sals (int @var{this_level_only}) +Return the line numbers of all exception handlers currently +active (or `this_level_only'?? [[[?]]]). +[[[The implementation should remember to resolve_sal_pc]]] +@end deftypefun + + +@deftp Type {struct breakpoint_cback} +@example +typedef void (*breakpoint_cback_fn) (struct breakpoint_cback *, int bp_num); +struct breakpoint_cback +@{ + breakpoint_cback_fn fn; +@}; +@end example + +Breakpoints can have an associated function which is called +when the program is stopped by that breakpoint.@* +(commands_command) +@end deftp + + +@deftypefun {struct breakpoint_cback *} gdb_set_breakpoint_cback (int @var{bp_num}, struct breakpoint_cback *) +This sets a breakpoint callback and returns the previous callback value +for that breakpoint. +[[[In the long run, the command interpreter should be available + for the use of hooks like this one.]]] +@end deftypefun + + +@deftypefun {struct breakpoint_cback *} gdb_get_breakpoint_cback (int @var{bp_num}) +@end deftypefun + + +@deftypefun void gdb_breakpoints_info (struct gdb_stream_cback, int @var{bp_num}, int @var{watches}) +Print information on breakpoint number @var{bnum}, or -1 if all. +If @var{watches} is zero, process only breakpoints; if @var{watches} +is nonzero, process only watchpoints. +[[[In the long run, expose the information read off by this function.]]]@* +(info breakpoints, info watchpoints, breakpoints_info, breakpoint_1) +@end deftypefun + + +@deftypefun void gdb_catch_info (struct gdb_stream_cback *) +Print a list of all the exception handlers that are active in the +current stack frame at the current point of execution.@* +(catch_info) +@end deftypefun + + +@deftypefun void gdb_handle_command (char * @var{args}) +Takes arguments like the gdb command `handle' and has +the same effect.@* +(handle_command) +@end deftypefun + + +@deftypefun void gdb_signals_info (struct gdb_stream_cback *) +Show how signals are handled.@* +(signals_info) +@end deftypefun + + +@node Stack, Expressions, Stopping, top +@comment node-name, next, previous, up +@chapter Accessing An Inferior's Execution Stack +@cindex stack +@cindex FRAME +@cindex {stack frames} + + + +@deftp Type FRAME +This type representing active stack frames in the inferior. +Consider this type opaque. +@end deftp + + +@deftypefun FRAME gdb_get_innermost_frame () +Returns the innermost frame or the frame most recently designated +as current by a call to gdb_set_current_frame.@* +(get_current_frame) +@end deftypefun + + +@deftypefun FRAME gdb_get_caller_frame (FRAME @var{frame}) +Return the frame that called @var{frame}.@* +If @var{frame} is the original frame (it has no caller), return 0.@* +(get_prev_frame) +@end deftypefun + + +@deftypefun FRAME gdb_get_called_frame (FRAME @var{frame}) +Return the frame that @var{frame} calls (0 if @var{frame} is the innermost +frame).@* +(get_next_frame) +@end deftypefun + + +@deftypefun FRAME gdb_parse_frame_specification (char * @var{frame_exp}) +Read a frame specification in whatever the appropriate format is. +Call @code{error}() If the specification is in any way invalid (i.e. +this function never returns NULL).@* +(parse_frame_specification) +@end deftypefun + + +@deftypefun CORE_ADDR get_frame_pc (FRAME @var{frame})@* +(Example use: Implementing @code{disassemble_command})@* +(get_frame_pc) +@end deftypefun + + +@deftypefun FRAME gdb_selected_frame () +The "selected" stack frame is used by default for local and +arg access. May be @code{NULL}, for no selected frame.@* +(variable selected_frame) +@end deftypefun + + +@deftypefun int gdb_selected_frame_level () +Level of the selected frame:@* +0 for innermost,@* +1 for its caller,@* +or -1 for frame specified by address with no defined level.@* +(variable selected_frame_level) +@end deftypefun + + +@deftypefun void gdb_select_frame (FRAME @var{frame}, int @var{level}) +Select frame @var{frame}, and note that its stack level is @var{level}. +@var{level} may be -1 if an actual level number is not known. +Calls @code{set_language} to establish the correct language for the +selected frame. +@end deftypefun + + + -- IDIOM: Computing Frame Levels@* +@example +/* Try to figure out what level this frame is as before a + call to gdb_select_frame. But if there is + no current stack, don't error out, just pass -1 + instead. */ +frame1 = 0; +level = -1; +if (get_current_frame()) @{ + for (frame1 = get_prev_frame (0); + frame1 && frame1 != frame; + frame1 = get_prev_frame (frame1)) + level++; +@} +@end example + + +@deftypefun void gdb_print_stack_frame (@var{cback}, @var{frame}, @var{level}, @var{source}) +@example +struct gdb_stream_cback * @var{cback}; +FRAME @var{frame}; +int @var{level}; +int @var{source}; +@end example +Print a stack frame briefly. @var{frame} should be the frame id +and @var{level} should be its level in the stack (or -1 for level not defined). +This prints the level, the function executing, the arguments, +and the file name and line number.@* +If the pc is not at the beginning of the source line, +the actual pc is printed at the beginning.@* +If @var{source} is 1, print the source line as well.@* +If @var{source} is -1, print ONLY the source line.@* +(print_stack_frame) +@end deftypefun + + +@deftypefun void gdb_print_backtrace (cback, @var{count}, @var{from_tty}) +@example +struct gdb_stream_cback * @var{cback}; +int @var{count}; +int @var{from_tty}; +@end example +Print briefly all stack frames or just the innermost @var{count} frames.@* +(backtrace_command) +@end deftypefun + + +@deftypefun FRAME gdb_find_relative_frame (FRAME @var{frame}, int * @var{level_offset_ptr}) +Find a frame a certain number of levels away from @var{frame}. +@var{level_offset_ptr} points to an int containing the number of levels. +Positive means go to earlier frames (up); negative, the reverse. +The int that contains the number of levels is counted toward +zero as the frames for those levels are found. +If the top or bottom frame is reached, that frame is returned, +but the final value of @var{*level_offset_ptr} is nonzero and indicates +how much farther the original request asked to go. +@end deftypefun + + +@deftypefun FRAME gdb_select_frame_downward (int @var{count}) +@deftypefunx FRAME gdb_select_frame_upward (int @var{count}) +Simply a combination of find_relative_frame and select_frame. +Returns the newly selected frame.@* +(down_silently_command, up_silently_command) +@end deftypefun + + +@deftypefun void gdb_frame_info (struct gdb_stream_cback * @var{cback}, FRAME @var{frame}) +Print verbosely the selected the argument @var{frame}. +This means absolutely all information in the frame is printed.@* +(frame_info) +@end deftypefun + + +@node Expressions, Values, Stack, top +@comment node-name, next, previous, up +@chapter How to Parse and Evaluate Expressions +@cindex parsing +@cindex expressions +@cindex {expression evaluation} +@cindex evaluation + + +@deftp Type {struct expression *} +This represents a parsed expression as might be used for a +breakpoint condition. +@end deftp + + +@deftp Type {struct block} +Describes a lexical environment. +@end deftp + +See also `Values' +See also `Examining' + + +@deftypefun struct expression * parse_exp_1 (char ** @var{stringptr}, struct block * @var{block} int @var{comma}) +Read an expression from the string @code{*@var{stringptr}} points to, +parse it, and return a pointer to a struct expression that we malloc. +Use @var{block} as the lexical context for variable names; +if @var{block} is zero, use the block of the selected stack frame. +Meanwhile, advance @code{*@var{stringptr}} to point after the expression, +at the first nonwhite character that is not part of the expression +(possibly a null character). + +If @var{comma} is nonzero, stop if a comma is reached. +(See `Stack' for information about the selected frame) +@end deftypefun + + +@deftypefun gdb_error_t gdb_evaluate_expression (value * @var{value_out}, struct expression * @var{exp}) +Evaluate an expression. See `values' for more information about +the return type.@* +(evaluate_expression) +@end deftypefun + + +@deftypefun value gdb_evaluate_type (struct expression @var{*exp}) +Evaluate an expression, avoiding all memory references +and getting a value whose type alone is correct.@* +(evaluate_type) +@end deftypefun + + + +@node Values, Examining, Expressions, top +@comment node-name, next, previous, up +@chapter Data from the Inferior, the Values of Expressions +@cindex values +@cindex {expression values} + +Values are allocated by functions such as @code{gdb_evaluate_expression}. +All currently allocated values are on the list @code{all_values} and can be +freed by calling @code{gdb_free_all_values}. + +To preserve a value across calls to @code{gdb_free_all_values}, use +@code{gdb_release_value}. Values added to the history list are automaticly +released. To free a released value use @code{gdb_free_value}. + + +@deftypefun void gdb_free_value (value) +Free the memory associated with a released value. +Do not call this function except on values that have been +passed to @code{gdb_release_value}.@* +(gdb_value_free) +@end deftypefun + + +@deftypefun void gdb_free_all_values (void) +Free all allocated values which haven't been released. +This should be called periodically from outside the dynamic +scope of libgdb functions.@* +(free_all_values) +@end deftypefun + + +@deftypefun void gdb_release_value (value @var{val}) +Remove a value from the list @code{all_values} in order to +protect it from @code{gdb_free_all_values}.@* +(release_value) +@end deftypefun + + +There is a `history list' -- a numbered list of values for +future reference. These can be referred to in expressions, +for example. + +@deftypefun int gdb_record_latest_value (value @var{val}) +Add a value to the history list.@* +(record_latest_value) +@end deftypefun + + +@deftypefun value gdb_access_value_history (int @var{index}) +Retrieve a value from the history list.@* +(access_value_history) +@end deftypefun + + +[[[At the moment, the only libgdb use for values is + string formatting (see `Examining'). So, they are treated + as opaque. It'd be useful to expose more of them in the long run.]]] + + +@node Examining, Types, Values, top +@comment node-name, next, previous, up +@chapter Formatting Values as Strings +@cindex examining +@cindex printing +@cindex formatting +@cindex {pretty printing} + + +Many functions in this section use @code{struct gdb_stream_cback}. +That structure is explained in `Basics'. + + +@deftypefun void gdb_print_formatted (struct gdb_stream_cback * @var{cback}, value @var{val}, int @var{format}, int @var{size}) +Print value @var{val} on a stream according to @var{format}, a letter or 0. +Do not end with a newline. +0 means print @var{val} according to its own type. +@var{size} is the letter for the size of datum being printed. +This is used to pad hex numbers so they line up.@* +(print_formatted) +@end deftypefun + + +@deftypefun static void gdb_printf_command (struct gdb_stream_cback * @var{cback}, char * @var{format}, value * @var{values}, int @var{n_values})@* +(printf_command) +@end deftypefun + + +@deftypefun int gdb_value_print (struct gdb_stream_cback * @var{cback}, @var{value}, int @var{format}, enum @var{val_prettyprint}) +Print the value @var{val} in C-ish syntax on @var{stream}. +@var{format} is a format-letter, or 0 for print in natural format of data type. +If the object printed is a string pointer, returns +the number of string bytes printed. +[[[implementation: watch the change in argument order]]]@* +(value_print) +@end deftypefun + + + -- IDIOM: This prints the values of all convenience variables: +@example +for (var = internalvars; var; var = var->next) +@{ +printf_filtered ("$%s = ", var->name); +value_print (var->value, stdout, 0, Val_pretty_default); +printf_filtered ("\n"); +@} +@end example + + +@deftypefun int gdb_print_insn (struct gdb_stream_cback * @var{cback}, CORE_ADDR @var{memaddr}) +Print the instruction at @var{memaddr} and return the +length of the instruction in bytes.@* +(print_insn) +@end deftypefun + + +@deftypefun void gdb_print_address (struct gdb_stream_cback * @var{cback}, CORE_ADDR @var{addr}) +Print address @var{addr} symbolically on @var{stream}. +First print it as a number. Then perhaps print +@code{} after the number.@* +(print_address) +@end deftypefun + + + -- IDIOM: This is the core of a dissasemble command: +@example +for (pc = low; pc < high; ) +@{ + print_address (pc, stdout); + printf_filtered (":\t"); + pc += print_insn (pc, stdout); + printf_filtered ("\n"); +@} +@end example +Advice for computing pc extents like @code{low} and @code{high} +can be found in `Symtabs' -- for example, @code{gdb_find_line_pc_range}.@* +(disassemble_command) + + +@deftypefun void gdb_print_registers (struct gdb_stream_cback * @var{cback}, int @var{regnum}, int @var{fpregs}, int @var{fancy}) +Print the values of registers. +@var{regnum} can be -1 (print all the registers) or a specific register number. +If @var{regnum} is -1, @var{fpregs} determines whether floating point registers are +shown.@* +(info registers, info all-registers, nofp_registers_info, all_registers_info) +@end deftypefun + + +@deftypefun char * gdb_register_name (int @var{i}) +Look up a register name by number. +@end deftypefun + + +@deftypefun int gdb_parse_register_name (char ** @var{name}) +Parse a register name and advance a text pointer. +Return -1 for bogus names. +@end deftypefun + + +@deftypefun CORE_ADDR gdb_read_pc () +Return the contents of the inferior's program counter. +@end deftypefun + + +@deftypefun int gdb_is_stepping () +If true, the inferior is stopped after being stepped. +@end deftypefun + + +@deftypefun void gdb_current_breakpoints (gdb_int_cback) +Call a callback for each of the current breakpoints.@* +(program_info) +@end deftypefun + + +@deftypefun int gdb_stop_signal () +Return the signal that stopped the inferior. +@end deftypefun + + +@deftypefun char * strsigno (int) +Return a symbolic name for a signal. +@end deftypefun + + +@deftypefun void gdb_target_info (struct gdb_stream_cback *) +Print status information about target we're accessing.@* +(target_files_info, e.g. child_files_info) +@end deftypefun + + +float_info +[[[what is appropriate?]]] + + +@deftypefun void gdb_address_info (struct gdb_stream_cback * @var{cback}, char * @var{symbol}); +Like the `info address' command -- show where @var{symbol} +is located.@* +(address_info) +@end deftypefun + + +@node Types, top, Examining, top +@comment node-name, next, previous, up +@chapter Examining the Types of an Inferior's Data +@cindex types + + +@deftp Type {struct type} +@code{struct type *} is used to represent a type. For example, that is +the type returned by the macro @code{VALUE_TYPE(val)} which yields the +type of inferior data recorded in @code{val}. (see `evaluate_type' in +`Expressions'). +@end deftp + + +@deftypefun void type_print (@var{type}, @var{varstring}, @var{stream_cback}, @var{show}) +@example +struct type @var{*type}; +char @var{*varstring}; +struct gdb_stream_cback * @var{stream_cback}; +FILE @var{*stream}; +int @var{show}; +@end example +Print a description of a type @var{type} in the form of a declaration of a +variable named @var{varstring}. (@var{varstring} is demangled if necessary.) +Output goes to @var{stream_cback}. + +If @var{show} is positive, we show the contents of the outermost level +of structure even if there is a type name that could be used instead. +If @var{show} is negative, we never show the details of elements' types. +(See `Basics' for an explanation of `struct gdb_stream_cback'). +@end deftypefun + + +[[[In the long run, we need something to programmaticly read off type + structures in a machine/language independent way.]]] + +@bye diff --git a/gnu/usr.bin/gdb/doc/lpsrc.sed b/gnu/usr.bin/gdb/doc/lpsrc.sed new file mode 100644 index 00000000000..1c7af4aaf48 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/lpsrc.sed @@ -0,0 +1,13 @@ +/font defs: ---/,/end font defs ---/c\ +%-------------------- PostScript (long names) font defs: -----------------\ +\\font\\bbf=Times-Bold at 10pt\ +\\font\\vbbf=Times-Bold at 12pt\ +\\font\\smrm=Times-Roman at 6pt\ +\\font\\brm=Times-Roman at 10pt\ +\\font\\rm=Times-Roman at 8pt\ +\\font\\it=Times-Italic at 8pt\ +\\font\\tt=Courier at 8pt\ +% Used only for \copyright, replacing plain TeX macro.\ +\\font\\sym=Symbol at 7pt\ +\\def\\copyright{{\\sym\\char'323}}\ +%-------------------- end font defs --------------------------------- diff --git a/gnu/usr.bin/gdb/doc/psrc.sed b/gnu/usr.bin/gdb/doc/psrc.sed new file mode 100644 index 00000000000..9bb557eae21 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/psrc.sed @@ -0,0 +1,13 @@ +/font defs: ---/,/end font defs ---/c\ +%-------------------- PostScript (K Berry names) font defs: --------------\ +\\font\\bbf=ptmb at 10pt\ +\\font\\vbbf=ptmb at 12pt\ +\\font\\smrm=ptmr at 6pt\ +\\font\\brm=ptmr at 10pt\ +\\font\\rm=ptmr at 8pt\ +\\font\\it=ptmri at 8pt\ +\\font\\tt=pcrr at 8pt\ +% Used only for \copyright, replacing plain TeX macro.\ +\\font\\sym=psyr at 7pt\ +\\def\\copyright{{\\sym\\char'323}}\ +%-------------------- end font defs --------------------------------- diff --git a/gnu/usr.bin/gdb/doc/refcard.ps b/gnu/usr.bin/gdb/doc/refcard.ps new file mode 100644 index 00000000000..0046b795faf --- /dev/null +++ b/gnu/usr.bin/gdb/doc/refcard.ps @@ -0,0 +1,798 @@ +%!PS-Adobe-2.0 +%%Creator: dvips 5.47 Copyright 1986-91 Radical Eye Software +%%Title: refcard.dvi +%%Pages: 2 1 +%%BoundingBox: 0 0 612 792 +%%EndComments +%%BeginProcSet: tex.pro +/TeXDict 200 dict def TeXDict begin /N /def load def /B{bind def}N /S /exch +load def /X{S N}B /TR /translate load N /isls false N /vsize 10 N /@rigin{ +isls{[0 1 -1 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale +Resolution VResolution vsize neg mul TR matrix currentmatrix dup dup 4 get +round 4 exch put dup dup 5 get round 5 exch put setmatrix}N /@letter{/vsize 10 +N}B /@landscape{/isls true N /vsize -1 N}B /@a4{/vsize 10.6929133858 N}B /@a3{ +/vsize 15.5531 N}B /@ledger{/vsize 16 N}B /@legal{/vsize 13 N}B /@manualfeed{ +statusdict /manualfeed true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N +/FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{/nn 8 dict N nn begin +/FontType 3 N /FontMatrix fntrx N /FontBBox FBB N string /base X array +/BitMaps X /BuildChar{CharBuilder}N /Encoding IE N end dup{/foo setfont}2 +array copy cvx N load 0 nn put /ctr 0 N[}B /df{/sf 1 N /fntrx FMat N df-tail} +B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0]N df-tail}B /E{pop nn dup definefont +setfont}B /ch-width{ch-data dup length 5 sub get}B /ch-height{ch-data dup +length 4 sub get}B /ch-xoff{128 ch-data dup length 3 sub get sub}B /ch-yoff{ +ch-data dup length 2 sub get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B +/ch-image{ch-data dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 +N /rw 0 N /rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S +dup /base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0 +ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff setcachedevice +ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff .1 add]{ch-image} +imagemask restore}B /D{/cc X dup type /stringtype ne{]}if nn /base get cc ctr +put nn /BitMaps get S ctr S sf 1 ne{dup dup length 1 sub dup 2 index S get sf +div put}if put /ctr ctr 1 add N}B /I{cc 1 add D}B /bop{userdict /bop-hook +known{bop-hook}if /SI save N @rigin 0 0 moveto}N /eop{clear SI restore +showpage userdict /eop-hook known{eop-hook}if}N /@start{userdict /start-hook +known{start-hook}if /VResolution X /Resolution X 1000 div /DVImag X /IE 256 +array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for}N /p /show load N +/RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X +/rulex X V}B /V statusdict begin /product where{pop product dup length 7 ge{0 +7 getinterval(Display)eq}{pop false}ifelse}{false}ifelse end{{gsave TR -.1 -.1 +TR 1 1 scale rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1 +-.1 TR rulex ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /a{ +moveto}B /delta 0 N /tail{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{ +S p tail}B /c{-4 M}B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B +/j{3 M}B /k{4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w +}B /q{p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p +a}B /bos{/SS save N}B /eos{clear SS restore}B end +%%EndProcSet +TeXDict begin 1000 300 300 @start /Fa 3 104 df<0003FE0000000FFF8000003C01E000 +00F000780001C0001C00030000060006000003000C0000018018000000C018000000C030000000 +603000000060600000003060000000306000000030C000000018C000000018C000000018C00000 +0018C000000018C000000018C000000018C000000018C000000018600000003060000000306000 +0000303000000060300000006018000000C018000000C00C000001800600000300030000060001 +C0001C0000F0007800003C01E000000FFF80000003FE000025277E9D2A>13 +D<003C00E001C00180038003800380038003800380038003800380038003800380038003000700 +1C00F0001C00070003000380038003800380038003800380038003800380038003800380018001 +C000E0003C0E297D9E15>102 DI E /Fb 1 59 +df<60F0F06004047C830C>58 D E /Fc 61 125 df<01F8000604000C0E00180E001800001800 +00180000FFFE001806001806001806001806001806001806001806001806001806001806001806 +007E1F801114809313>12 D<01FE00060E000C0E00180600180600180600180600FFFE00180600 +1806001806001806001806001806001806001806001806001806001806007E1F801114809313> +I<4100E380618020802080208041004100820009097F9311>34 D<020002000F8032406220C210 +C270C270E220F2007F003FC00FE002E002704230E230C2308220426022C01F00020002000C187E +9511>36 D<40E06020202040408003097D9309>39 D<01020408103020606040C0C0C0C0C0C0C0 +C0C0C040606020301008040201081E7E950D>I<80402010080C04060602030303030303030303 +03020606040C0810204080081E7E950D>I<006000006000006000006000006000006000006000 +006000006000006000FFFFF0FFFFF0006000006000006000006000006000006000006000006000 +00600000600014167E9119>43 D<40E06020202040408003097D8209>II<40 +E04003037D8209>I<0010003000600060006000C000C000C00180018003000300030006000600 +06000C000C000C0018001800300030003000600060006000C000C0000C1D7E9511>I<0F0030C0 +606060604020C030C030C030C030C030C030C030C030C03040206060606030C00F000C137E9211 +>I<0C001C00EC000C000C000C000C000C000C000C000C000C000C000C000C000C000C000C00FF +C00A137D9211>I<1F0060C06060F070F030603000700070006000C001C0018002000400081010 +1020207FE0FFE00C137E9211>I<40E0400000000000000040E040030D7D8C09>58 +D<40E0400000000000000040E06020202040408003137D8C09>I<003000003000007800007800 +007800009C00009C00011E00010E00010E0002070002070004038007FF800403800801C00801C0 +1000E03800E0FE07FC16147F9319>65 DI<00FC200703600C00E0180060300060700020600020E00000E00000E00000E00000 +E00000E000006000207000203000201800400C008007030000FC0013147E9318>III<00FC200703600C00E0180060300060700020600020E00000E00000 +E00000E00000E00FF8E000E06000E07000E03000E01800E00C00E007036000FC2015147E931A> +71 D76 +DII<01 +F800070E001C03803801C03000C07000E0600060E00070E00070E00070E00070E00070E0007070 +00E07000E03000C03801C01C0380070E0001F80014147E9319>II82 D<7FFFF0607030407010407010807008807008807008007000007000007000007000 +00700000700000700000700000700000700000700000700007FF0015147F9318>84 +DI87 +D89 D<208041004100820082 +008200C300E380410009097A9311>92 D<7F00E1C0E0404060006007E038606060C060C064C064 +61E43E380E0D7E8C11>97 DI<0FE0187020706020C000C000C000C000C00060 +00201018200FC00C0D7F8C0F>I<00780018001800180018001800180F98187820386018C018C0 +18C018C018C0186018203810580F9E0F147F9312>I<0F80104020206030C010FFF0C000C000C0 +006000201018200FC00C0D7F8C0F>I<03C00CE018E01840180018001800FF0018001800180018 +0018001800180018001800180018007F000B1480930A>I<0F3C30E62040606060606060204030 +C02F00600060003FE03FF06018C00CC00CC00C601830300FC00F147F8C11>I +I<2070200000000000F03030303030303030303030FC06157F9409>I<02070200000000000F03 +0303030303030303030303030343E2E67C081B82940A>IIIII<0FC0186020106018C00CC00CC00CC00CC00C +6018601838700FC00E0D7F8C11>II<0F88184820386018C018C018C018C018C018 +6018203818580F9800180018001800180018007E0F137F8C11>II<3E806180C080C080E0007E003F8003C080C0 +80C0C0C0E1809F000A0D7F8C0D>I<10001000100030007000FF80300030003000300030003000 +300030803080308011000E0009127F910D>IIIIIII124 D E /Fd 2 94 df91 +D93 D E /Fe 27 123 df<001F8F000020D9800060990000C0300000C03000 +00C0300000C0300007FFFE000180300001806000018060000180600001806000030060000300C0 +000300C0000300C0000300C0000600C00006018000060180000601800004010000CCC30000C8C6 +000070780000191A819315>11 D<000FF000301800601000600000C00000C00000C00007FFE000 +C0600180600180C00180C00180C00180C00181800301900301900301900301A00300E006000006 +0000060000C40000C80000700000151A819314>I45 +D<000080000180000300000300000600000600000C000018000018000030000030000060000060 +0000C0000180000180000300000300000600000C00000C00001800001800003000003000006000 +00C00000C00000800000111D7E9512>47 D<07C03F8000C00C0001600800016008000120080001 +300800023010000218100002181000020C1000040C200004042000040620000402200008034000 +080340000801C0000801C00018008000FE00800019147E9319>78 D<07B00C7010703060606060 +606060C0C0C0C8C0C841C862D03C700D0D7C8C12>97 D<7C000C00180018001800180030003700 +388030C060C060C060C060C0C180C180C1004300660038000A147C9310>I<07800C4010603040 +600060006000C000C0004020404021801E000B0D7C8C10>I<007C000C00180018001800180030 +07B00C7010703060606060606060C0C0C0C8C0C841C862D03C700E147C9312>I<07800C401020 +304060407F8060004000C0004020604021801E000B0D7C8C10>I<001C00660064006000C000C0 +00C007F800C001800180018001800180030003000300030003000200060006000600C400C80070 +000F1A81930B>I<01D8023804380C3018301830183030603060306010E019C00EC000C000C001 +80C180C3007C000D137E8C10>I<3E0006000C000C000C000C00180019E01E3018303830303030 +3030306060606460C460C4C0C8C0700E147D9312>I<02060000000000384C4C8C981818303262 +62643807147D930B>I<7C0C181818183030303060606060C0D0D0D0D06006147C9309>108 +D<30F878590D8C4E0E0C9C0E0C980C0C180C0C180C0C3018183018193018313018316030326030 +1C180D7D8C1C>I<30F05B184C189C189818181818183030303230623062606460380F0D7D8C13> +I<03800C6018203030603060306030C060C06040C0608023001E000C0D7C8C12>I<0C78168C13 +0426062606060606060C0C0C0C0C080C101A2019C018001800300030003000FC000F137F8C12> +I<31F05A184C109C009800180018003000300030003000600060000D0D7D8C0F>114 +D<0700188018C0308038001E001F0003800180C180810082007C000A0D7D8C0E>I<04000C000C +000C001800FF8018001800300030003000300060006100610062006400380009127D910C>I<38 +184C184C188C3098301830183030603064306430E411E80E380E0D7D8C12>I<38104C384C108C +10981018101810302030203040304018800F000D0D7D8C10>I<071E09E311C221802180018001 +800300030403044308C51078E0100D7F8C10>120 D<38184C184C188C30983018301830306030 +60306030E011C00EC000C000802180630046003C000D137D8C11>I<06100F2010E00040008001 +0002000C00102020203840478083000C0D7E8C0E>I E /Ff 55 123 df<0100030003000F803F +E073704338C338C338C31073007F003FC00FE003F003384318E318E318E33073603FC00F800300 +030001000D1A7E9612>36 D<07001F8019C039C039C039C039BE3B3E3E701C701C701CE03EE06F +E0E7C0E3C4E38E63CE7EFC3C380F147F9312>38 D<070007000700E738FFF87FF01FC01FC07FF0 +FFF8E7380700070007000D0E7E9012>42 D<038003800380038003800380FFFEFFFEFFFE038003 +8003800380038003800F0F7F9112>I<60F0F878183030E0C00509798312>II<60F0F0600404798312>I<0018003800380070007000E000E001C001C001C003800380 +070007000E000E001C001C001C003800380070007000E000E000C0000D1A7E9612>I<07C00FE0 +1C703838701C701CE00EE00EE00EE00EE00EE00EE00EE01E701C701C38381C700FE007C00F147F +9312>I<0F803FC070E0E070E038E038403800380030007000E000C00180030006000C00183830 +387FF87FF80D147E9312>50 D<0FE03FF07838701C201C001C0038007807E007F00038001C000E +000E400EE00EE01C78383FF00FC00F147F9312>I55 +D<60F0F06000000000000060F0F060040E798D12>58 D<0038007801F003E00F801F003C00F800 +F000F8003C001F000F8003E001F0007800380D117E9212>60 DI<4000E000F0007C003E000F8007C001E000F8007800F801E007C00F +803E007C00F000E00040000D137E9312>I<03E007F01E18381C30FC71FE739EE30EE70EE70EE7 +0EE70EE30C739C71F830F038001E0E07FE03F80F147F9312>64 D<03E60FFE1C3E381E700E700E +600EE000E000E000E000E000E000600E700E700E381C1C380FF003E00F147F9312>67 +D69 DI73 D77 +DI<3FE07FF07070E038E038E038E038E038E038E038E038E038E038E038E038 +E038E03870707FF03FE00D147E9312>II82 +D<1F303FF070F0E070E070E070E00070007F003FC00FE000F0003800386038E038E030F070FFE0 +CF800D147E9312>I<7FFEFFFEE38EE38EE38E0380038003800380038003800380038003800380 +0380038003801FF01FF00F147F9312>II<3F807FC070E0207000700FF03FF07870E070E070E07070F03FFE1F3E0F0E7E8D12> +97 DI<07F01FF8383870106000E000E000E000E0006000703838381FF007E0 +0D0E7E8D12>I<00F800F8003800380038003807B81FF8387870386038E038E038E038E0386038 +707838781FFE0FBE0F147F9312>I<07801FE0387070706038E038FFF8FFF8E000600070383838 +1FF007C00D0E7E8D12>I<007E00FF01C70382038003807FFEFFFE038003800380038003800380 +03800380038003803FF83FF81014809312>I<0F9E1FFF38E7707070707070707038E03FC03F80 +70003FE03FF83FFC701EE00EE00EE00E600C783C1FF00FE010167F8D12>II< +06000F000F000600000000000000FF00FF000700070007000700070007000700070007000700FF +F0FFF00C157D9412>I<00C001E001E000C00000000000001FE01FE000E000E000E000E000E000 +E000E000E000E000E000E000E000E000E000E040C0E1C0FF807E000B1C7E9412>IIIII<0F803FE038E07070E038E038E038E038E038F0787070 +38E03FE00F800D0E7E8D12>II<079C1FFC387C703C601CE01CE01CE01C +E01C601C703C387C1FFC079C001C001C001C001C001C007F007F10157F8D12>II<1FF03FF06070C070E000 +7F003FE00FF000786018E018F030FFE0DFC00D0E7E8D12>I<06000E000E000E007FF8FFF80E00 +0E000E000E000E000E000E000E380E380E3807F003C00D127F9112>IIII<7C7C7C7C1CF00EE00FC007C00380078007C00EE01EF0 +1C70FC7EFC7E0F0E7F8D12>II<3FFC7FFC7038707000E001C003800700 +0E001C1C381C701CFFFCFFFC0E0E7F8D12>I E /Fg 35 122 df<00038000000380000007C000 +0007C0000007C000000FE000000FE000001FF000001BF000001BF0000031F8000031F8000061FC +000060FC0000E0FE0000C07E0000C07E0001803F0001FFFF0003FFFF8003001F8003001F800600 +0FC006000FC00E000FE00C0007E0FFC07FFEFFC07FFE1F1C7E9B24>65 DI<001FE02000FFF8 +E003F80FE007C003E00F8001E01F0000E03E0000E03E0000607E0000607C000060FC000000FC00 +0000FC000000FC000000FC000000FC000000FC000000FC0000007C0000607E0000603E0000603E +0000C01F0000C00F80018007C0030003F80E0000FFFC00001FE0001B1C7D9B22>III +I<000FF008007FFE3801FC07F807E001F80F8000781F0000783F0000383E0000387E0000187C00 +0018FC000000FC000000FC000000FC000000FC000000FC000000FC007FFFFC007FFF7C0001F87E +0001F83E0001F83F0001F81F0001F80F8001F807E001F801FC07F8007FFE78000FF818201C7D9B +26>II76 D78 D80 D<07F8201FFEE03C07E07801E07000 +E0F000E0F00060F00060F80000FE0000FFE0007FFE003FFF003FFF800FFFC007FFE0007FE00003 +F00001F00000F0C000F0C000F0C000E0E000E0F001C0FC03C0EFFF0083FC00141C7D9B1B>83 +D<7FFFFFE07FFFFFE0781F81E0701F80E0601F8060E01F8070C01F8030C01F8030C01F8030C01F +8030001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F8000001F8000001F800007FFFE0007FFFE001C1C7E9B +21>II87 D<0FF8001C1E003E0F803E07803E07 +C01C07C00007C0007FC007E7C01F07C03C07C07C07C0F807C0F807C0F807C0780BC03E13F80FE1 +F815127F9117>97 DI<03FC000E0E001C1F003C1F00781F +00780E00F80000F80000F80000F80000F80000F800007800007801803C01801C03000E0E0003F8 +0011127E9115>I<000FF0000FF00001F00001F00001F00001F00001F00001F00001F00001F000 +01F001F9F00F07F01C03F03C01F07801F07801F0F801F0F801F0F801F0F801F0F801F0F801F078 +01F07801F03C01F01C03F00F0FFE03F9FE171D7E9C1B>I<01FC000F07001C03803C01C07801C0 +7801E0F801E0F801E0FFFFE0F80000F80000F800007800007C00603C00601E00C00F038001FC00 +13127F9116>I<03F8F00E0F381E0F381C07303C07803C07803C07803C07801C07001E0F000E0E +001BF8001000001800001800001FFF001FFFC00FFFE01FFFF07801F8F00078F00078F000787000 +707800F01E03C007FF00151B7F9118>103 DI<1E003F00 +3F003F003F001E00000000000000000000000000FF00FF001F001F001F001F001F001F001F001F +001F001F001F001F001F001F00FFE0FFE00B1E7F9D0E>I +107 DIII<01FC000F07801C01 +C03C01E07800F07800F0F800F8F800F8F800F8F800F8F800F8F800F87800F07800F03C01E01E03 +C00F078001FC0015127F9118>II114 D<1FD830786018E018E018F000FF807FE07FF01FF807FC007CC01CC01CE01CE018F8 +30CFC00E127E9113>I<0300030003000300070007000F000F003FFCFFFC1F001F001F001F001F +001F001F001F001F001F0C1F0C1F0C1F0C0F08079803F00E1A7F9913>II120 +DI E /Fh 47 122 df<020408103020604040C0C0C0C0C0C0C0C0404060203010 +080402071A7F920C>40 D<8040201018080C0404060606060606060604040C081810204080071A +7E920C>I<40E060202040408003087E8209>44 D<40E04003037E8209>46 +D<0C003C00CC000C000C000C000C000C000C000C000C000C000C000C000C00FF8009107E8F0F> +49 D<1F00618040C08060C0600060006000C00180030006000C00102020207FC0FFC00B107F8F +0F>I<1F00218060C060C000C0008001800F00008000400060C060C060804060801F000B107F8F +0F>I<0300030007000F000B001300330023004300C300FFE003000300030003001FE00B107F8F +0F>I<1F00318060C0C040C060C060C06040E021E01E600060004060C0608043003E000B107F8F +0F>57 D<40E040000000000040E060202040408003107E8A09>59 D<03E0000C180010040023C2 +004631004C0D00980C80980C80980C80980C80980C804C0C80463C8023C7001000000C038003FC +0011117E9017>64 D66 D<03F10C0B1807300360014001C000C000C000C000C0004001600130 +0218020C0C03F010117E9016>II70 +D<03F1000C0B00180700300300600100400100C00000C00000C00000C03FC0C003004003006003 +003003001803000C070003F90012117E9017>I73 D76 D78 D80 +D82 D<1F2060E0006080208020800060003E001F80 +00C00060002080208020C040E0C09F000B117E9011>I<7FFF8060C18040C080C0C0C080C04080 +C04000C00000C00000C00000C00000C00000C00000C00000C00000C00000C0000FFC0012117F90 +16>III<3E006300018001800F8031804180C190C19063903DE00C0B7F8A0F>97 +DI<1F8030C06000C000C000C000C000C000604030801F000A0B7F8A0E>I<01E0006000600060 +006000600F6030E06060C060C060C060C060C060606030E01F780D117F9011>I<1F00318060C0 +C0C0FFC0C000C000C000604030801F000A0B7F8A0E>I<07000D801800180018001800FE001800 +180018001800180018001800180018007E00091180900A>I<1EF0331061806180618033003E00 +400060003F803FC060E0C060C060C06060C01F000C117F8A0F>II<30703000000000F03030 +30303030303030FC0612809108>I107 DIII<1F00318060C0 +C060C060C060C060C06060C031801F000B0B7F8A0F>II114 D<3E028280783E038181C2BC080B7F8A0C>I<10103030FE3030 +303030323232321C070F7F8E0C>IIII121 +D E /Fi 12 86 df66 +D<0003FE0080001FFF818000FF01E38001F8003F8003E0001F8007C0000F800F800007801F8000 +07803F000003803F000003807F000001807E000001807E00000180FE00000000FE00000000FE00 +000000FE00000000FE00000000FE00000000FE00000000FE000000007E000000007E000001807F +000001803F000001803F000003801F800003000F8000030007C000060003F0000C0001F8003800 +00FF00F000001FFFC0000003FE000021227DA128>IIII<0003FE0040001FFFC0C0007F00F1C001F8003FC003F0 +000FC007C00007C00FC00003C01F800003C03F000001C03F000001C07F000000C07E000000C07E +000000C0FE00000000FE00000000FE00000000FE00000000FE00000000FE00000000FE00000000 +FE000FFFFC7E000FFFFC7F00001FC07F00001FC03F00001FC03F00001FC01F80001FC00FC0001F +C007E0001FC003F0001FC001FC003FC0007F80E7C0001FFFC3C00003FF00C026227DA12C>I73 +D75 D78 D<0007FC0000003FFF800000FC07E00003F001F80007E000FC000FC0007E001F8000 +3F001F80003F003F00001F803F00001F807F00001FC07E00000FC07E00000FC0FE00000FE0FE00 +000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE07E +00000FC07F00001FC07F00001FC03F00001F803F81F03F801F83F83F000FC70C7E0007E606FC00 +03F607F80000FF07E000003FFF80000007FF80200000038020000001C020000001E0E0000001FF +E0000001FFC0000000FFC0000000FFC00000007F800000007F000000001E00232C7DA12A>81 +DI85 D E end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 300 +TeXDict begin @landscape +%%EndSetup +%%Page: 1 1 +bop -225 -183 a Fi(GDB)14 b(QUICK)g(REFERENCE)22 b Fh(GDB)14 +b(V)n(ersion)h(4)-225 -91 y Fg(Essen)o(tial)c(Commands)-225 +-45 y Ff(gdb)i Fe(pr)n(o)n(gr)n(am)f Fd([)p Fe(c)n(or)n(e)p +Fd(])24 b Fc(debug)14 b Fe(pr)n(o)n(gr)n(am)e Fd([)p Fc(using)i(coredump)g +Fe(c)n(or)n(e)p Fd(])-225 9 y Ff(b)f Fd([)p Fe(\014le)p Ff(:)p +Fd(])p Fe(function)68 b Fc(set)13 b(breakp)q(oin)o(t)i(at)e +Fe(function)g Fd([)p Fc(in)h Fe(\014le)p Fd(])-225 63 y Ff(run)f +Fd([)p Fe(ar)n(glist)p Fd(])126 b Fc(start)13 b(y)o(our)h(program)f +Fd([)p Fc(with)h Fe(ar)n(glist)p Fd(])-225 106 y Ff(bt)274 +b Fc(bac)o(ktrace:)20 b(displa)o(y)c(program)d(stac)o(k)-225 +143 y Ff(p)g Fe(expr)214 b Fc(displa)o(y)15 b(the)f(v)n(alue)h(of)e(an)h +(expression)-225 180 y Ff(c)292 b Fc(con)o(tin)o(ue)14 b(running)h(y)o(our)f +(program)-225 218 y Ff(n)292 b Fc(next)14 b(line,)h(stepping)g(o)o(v)o(er)f +(function)g(calls)-225 255 y Ff(s)292 b Fc(next)14 b(line,)h(stepping)g(in)o +(to)f(function)h(calls)-225 352 y Fg(Starting)c(GDB)-225 398 +y Ff(gdb)256 b Fc(start)13 b(GDB,)h(with)g(no)g(debugging)g(\014les)-225 +435 y Ff(gdb)f Fe(pr)n(o)n(gr)n(am)121 b Fc(b)q(egin)14 b(debugging)g +Fe(pr)n(o)n(gr)n(am)-225 472 y Ff(gdb)f Fe(pr)n(o)n(gr)n(am)f(c)n(or)n(e)48 +b Fc(debug)14 b(coredump)g Fe(c)n(or)n(e)f Fc(pro)q(duced)h(b)o(y)105 +510 y Fe(pr)n(o)n(gr)n(am)-225 548 y Ff(gdb)f(--help)135 b +Fc(describ)q(e)14 b(command)g(line)g(options)-225 647 y Fg(Stopping)c(GDB) +-225 692 y Ff(quit)238 b Fc(exit)14 b(GDB;)g(also)g Ff(q)f +Fc(or)g Ff(EOF)g Fc(\(eg)g Ff(C-d)p Fc(\))-225 734 y Ff(INTERRUPT)148 +b Fc(\(eg)13 b Ff(C-c)p Fc(\))g(terminate)g(curren)o(t)h(command,)h(or)105 +771 y(send)g(to)e(running)i(pro)q(cess)-225 868 y Fg(Getting)c(Help)-225 +914 y Ff(help)238 b Fc(list)14 b(classes)g(of)g(commands)-225 +951 y Ff(help)e Fe(class)155 b Fc(one-line)14 b(descriptions)h(for)f +(commands)g(in)105 988 y Fe(class)-225 1021 y Ff(help)e Fe(c)n(ommand)83 +b Fc(describ)q(e)14 b Fe(c)n(ommand)-225 1119 y Fg(Executing)e(y)o(our)h +(Program)-225 1165 y Ff(run)g Fe(ar)n(glist)150 b Fc(start)13 +b(y)o(our)h(program)f(with)i Fe(ar)n(glist)-225 1203 y Ff(run)256 +b Fc(start)13 b(y)o(our)h(program)f(with)i(curren)o(t)f(argumen)o(t)105 +1240 y(list)-225 1273 y Ff(run)f Fb(:)7 b(:)g(:)12 b Ff(<)p +Fe(inf)h Ff(>)p Fe(outf)32 b Fc(start)13 b(y)o(our)h(program)f(with)i(input,) +g(output)105 1310 y(redirected)-225 1360 y Ff(kill)238 b Fc(kill)15 +b(running)g(program)-225 1434 y Ff(tty)e Fe(dev)193 b Fc(use)14 +b Fe(dev)f Fc(as)g(stdin)i(and)f(stdout)g(for)g(next)g Ff(run)-225 +1472 y(set)f(args)f Fe(ar)n(glist)66 b Fc(sp)q(ecify)15 b Fe(ar)n(glist)d +Fc(for)i(next)g Ff(run)-225 1509 y(set)f(args)171 b Fc(sp)q(ecify)15 +b(empt)o(y)f(argumen)o(t)g(list)-225 1546 y Ff(show)e(args)154 +b Fc(displa)o(y)15 b(argumen)o(t)f(list)-225 1621 y Ff(show)e(environment)28 +b Fc(sho)o(w)13 b(all)i(en)o(vironmen)o(t)g(v)n(ariables)-225 +1659 y Ff(show)d(env)h Fe(var)110 b Fc(sho)o(w)13 b(v)n(alue)i(of)f(en)o +(vironmen)o(t)h(v)n(ariable)f Fe(var)-225 1696 y Ff(set)f(env)g +Fe(var)f(string)28 b Fc(set)13 b(en)o(vironmen)o(t)j(v)n(ariable)e +Fe(var)-225 1733 y Ff(unset)e(env)h Fe(var)92 b Fc(remo)o(v)o(e)13 +b Fe(var)g Fc(from)h(en)o(vironmen)o(t)-225 1820 y Fg(Shell)d(Commands)-225 +1866 y Ff(cd)i Fe(dir)217 b Fc(c)o(hange)13 b(w)o(orking)h(directory)g(to)f +Fe(dir)-225 1903 y Ff(pwd)256 b Fc(Prin)o(t)15 b(w)o(orking)e(directory)-225 +1941 y Ff(make)f Fb(:)7 b(:)g(:)176 b Fc(call)14 b(\\)p Ff(make)p +Fc(")-225 1978 y Ff(shell)e Fe(cmd)146 b Fc(execute)13 b(arbitrary)h(shell)h +(command)f(string)-225 2100 y Fd([)f(])h Fh(surround)f(optional)j(argumen)o +(ts)45 b Fb(:)7 b(:)g(:)13 b Fh(sho)o(w)h(one)f(or)h(more)f(argumen)o(ts)-216 +2174 y(c)-230 2175 y Fa(\015)p Fh(1991,)h(1992)h(F)n(ree)d(Soft)o(w)o(are)h +(F)n(oundation,)h(Inc.)60 b(P)o(ermissions)15 b(on)f(bac)o(k)p +800 -217 1 9 v 800 2175 V 875 -183 a Fg(Breakp)q(oin)o(ts)d(and)j(W)l(atc)o +(hp)q(oin)o(ts)875 -132 y Ff(break)e Fd([)p Fe(\014le)p Ff(:)p +Fd(])p Fe(line)875 -86 y Ff(b)i Fd([)p Fe(\014le)p Ff(:)p Fd(])p +Fe(line)1185 -132 y Fc(set)g(breakp)q(oin)o(t)g(at)f Fe(line)h +Fc(n)o(um)o(b)q(er)h Fd([)p Fc(in)f Fe(\014le)p Fd(])1185 -94 +y Fc(eg:)33 b Ff(break)12 b(main.c:37)875 -32 y(break)g Fd([)p +Fe(\014le)p Ff(:)p Fd(])p Fe(func)57 b Fc(set)14 b(breakp)q(oin)o(t)g(at)f +Fe(func)h Fd([)p Fc(in)g Fe(\014le)p Fd(])875 11 y Ff(break)e(+)p +Fe(o\013set)875 48 y Ff(break)g(-)p Fe(o\013set)1185 11 y Fc(set)i(break)f +(at)h Fe(o\013set)f Fc(lines)i(from)f(curren)o(t)g(stop)875 +87 y Ff(break)e(*)p Fe(addr)121 b Fc(set)14 b(breakp)q(oin)o(t)g(at)f +(address)h Fe(addr)875 124 y Ff(break)220 b Fc(set)14 b(breakp)q(oin)o(t)g +(at)f(next)i(instruction)875 161 y Ff(break)d Fb(:)7 b(:)g(:)12 +b Ff(if)i Fe(expr)31 b Fc(break)14 b(conditionally)h(on)f(nonzero)f +Fe(expr)875 211 y Ff(cond)g Fe(n)h Fd([)p Fe(expr)p Fd(])103 +b Fc(new)13 b(conditional)i(expression)g(on)e(breakp)q(oin)o(t)1206 +248 y Fe(n)p Fc(;)h(mak)o(e)g(unconditional)h(if)g(no)e Fe(expr)875 +286 y Ff(tbreak)f Fb(:)7 b(:)g(:)140 b Fc(temp)q(orary)13 b(break;)i(disable) +f(when)g(reac)o(hed)875 324 y Ff(rbreak)e Fe(r)n(e)n(gex)115 +b Fc(break)14 b(on)f(all)i(functions)g(matc)o(hing)f Fe(r)n(e)n(gex)875 +361 y Ff(watch)e Fe(expr)143 b Fc(set)14 b(a)f(w)o(atc)o(hp)q(oin)o(t)h(for)f +(expression)i Fe(expr)875 398 y Ff(catch)d Fe(x)192 b Fc(break)14 +b(at)f(C++)i(handler)f(for)g(exception)g Fe(x)875 473 y Ff(info)f(break)135 +b Fc(sho)o(w)13 b(de\014ned)i(breakp)q(oin)o(ts)875 511 y Ff(info)e(watch)135 +b Fc(sho)o(w)13 b(de\014ned)i(w)o(atc)o(hp)q(oin)o(ts)875 585 +y Ff(clear)220 b Fc(delete)14 b(breakp)q(oin)o(ts)g(at)g(next)g(instruction) +875 635 y Ff(clear)e Fd([)p Fe(\014le)p Ff(:)p Fd(])p Fe(fun)73 +b Fc(delete)14 b(breakp)q(oin)o(ts)g(at)g(en)o(try)g(to)f Fe(fun)p +Fc(\(\))875 688 y Ff(clear)f Fd([)p Fe(\014le)p Ff(:)p Fd(])p +Fe(line)66 b Fc(delete)14 b(breakp)q(oin)o(ts)g(on)g(source)f(line)875 +742 y Ff(delete)f Fd([)p Fe(n)p Fd(])147 b Fc(delete)14 b(breakp)q(oin)o(ts)g +Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 823 y Ff(disable)c +Fd([)p Fe(n)p Fd(])130 b Fc(disable)15 b(breakp)q(oin)o(ts)f +Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 877 y Ff(enable)d +Fd([)p Fe(n)p Fd(])147 b Fc(enable)14 b(breakp)q(oin)o(ts)g +Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 931 y Ff(enable)d(once)g +Fd([)p Fe(n)p Fd(])63 b Fc(enable)14 b(breakp)q(oin)o(ts)g +Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])p Fc(;)1206 969 +y(disable)f(again)g(when)f(reac)o(hed)875 1018 y Ff(enable)f(del)h +Fd([)p Fe(n)p Fd(])80 b Fc(enable)14 b(breakp)q(oin)o(ts)g +Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])p Fc(;)1206 1055 +y(delete)e(when)h(reac)o(hed)875 1105 y Ff(ignore)e Fe(n)i(c)n(ount)76 +b Fc(ignore)13 b(breakp)q(oin)o(t)i Fe(n)p Fc(,)f Fe(c)n(ount)g +Fc(times)875 1180 y Ff(commands)d Fe(n)946 1217 y Fd([)p Ff(silent)p +Fd(])946 1255 y Fe(c)n(ommand-list)1185 1180 y Fc(execute)i(GDB)h +Fe(c)n(ommand-list)e Fc(ev)o(ery)j(time)1206 1217 y(breakp)q(oin)o(t)f +Fe(n)g Fc(is)g(reac)o(hed.)21 b Fd([)p Ff(silent)1206 1263 +y Fc(suppresses)14 b(default)h(displa)o(y)p Fd(])875 1306 y +Ff(end)256 b Fc(end)14 b(of)g Fe(c)n(ommand-list)875 1393 y +Fg(Program)f(Stac)o(k)875 1445 y Ff(backtrace)e Fd([)p Fe(n)p +Fd(])875 1490 y Ff(bt)i Fd([)p Fe(n)p Fd(])1185 1445 y Fc(prin)o(t)i(trace)e +(of)g(all)h(frames)g(in)h(stac)o(k;)f(or)f(of)h Fe(n)1206 1482 +y Fc(frames|innermost)g(if)h Fe(n)p Ff(>0)p Fc(,)e(outermost)h(if)1206 +1519 y Fe(n)p Ff(<0)875 1563 y(frame)e Fd([)p Fe(n)p Fd(])165 +b Fc(select)13 b(frame)h(n)o(um)o(b)q(er)h Fe(n)f Fc(or)f(frame)h(at)g +(address)1206 1600 y Fe(n)p Fc(;)g(if)h(no)e Fe(n)p Fc(,)i(displa)o(y)g +(curren)o(t)f(frame)875 1639 y Ff(up)f Fe(n)242 b Fc(select)13 +b(frame)h Fe(n)g Fc(frames)g(up)875 1676 y Ff(down)f Fe(n)206 +b Fc(select)13 b(frame)h Fe(n)g Fc(frames)g(do)o(wn)875 1720 +y Ff(info)f(frame)f Fd([)p Fe(addr)p Fd(])30 b Fc(describ)q(e)14 +b(selected)g(frame,)g(or)f(frame)h(at)f Fe(addr)875 1763 y +Ff(info)g(args)153 b Fc(argumen)o(ts)14 b(of)f(selected)h(frame)875 +1800 y Ff(info)f(locals)117 b Fc(lo)q(cal)13 b(v)n(ariables)i(of)e(selected)h +(frame)875 1844 y Ff(info)f(reg)f Fd([)p Fe(rn)p Fd(])p Fb(:)7 +b(:)g(:)875 1889 y Ff(info)13 b(all-reg)e Fd([)p Fe(rn)p Fd(])1185 +1844 y Fc(register)i(v)n(alues)i Fd([)p Fc(for)e(regs)g Fe(rn)s +Fd(])g Fc(in)h(selected)1206 1881 y(frame;)g Ff(all-reg)d Fc(includes)k +(\015oating)e(p)q(oin)o(t)875 1933 y Ff(info)g(catch)135 b +Fc(exception)14 b(handlers)h(activ)o(e)e(in)i(selected)f(frame)p +1900 -217 V 1900 2175 V 1975 -183 a Fg(Execution)f(Con)o(trol)1975 +-138 y Ff(continue)e Fd([)p Fe(c)n(ount)p Fd(])1975 -92 y Ff(c)j +Fd([)p Fe(c)n(ount)p Fd(])2285 -138 y Fc(con)o(tin)o(ue)g(running;)i(if)e +Fe(c)n(ount)g Fc(sp)q(eci\014ed,)g(ignore)2306 -100 y(this)g(breakp)q(oin)o +(t)h(next)f Fe(c)n(ount)g Fc(times)1975 -26 y Ff(step)f Fd([)p +Fe(c)n(ount)p Fd(])1975 20 y Ff(s)h Fd([)p Fe(c)n(ount)p Fd(])2285 +-26 y Fc(execute)g(un)o(til)h(another)e(line)i(reac)o(hed;)f(rep)q(eat)2306 +12 y Fe(c)n(ount)f Fc(times)i(if)f(sp)q(eci\014ed)1975 74 y +Ff(stepi)e Fd([)p Fe(c)n(ount)p Fd(])1975 120 y Ff(si)h Fd([)p +Fe(c)n(ount)p Fd(])2285 74 y Fc(step)h(b)o(y)h(mac)o(hine)f(instructions)h +(rather)f(than)2306 111 y(source)f(lines)1975 186 y Ff(next)g +Fd([)p Fe(c)n(ount)p Fd(])1975 232 y Ff(n)h Fd([)p Fe(c)n(ount)p +Fd(])2285 186 y Fc(execute)g(next)g(line,)h(including)h(an)o(y)e(function) +2306 223 y(calls)1975 286 y Ff(nexti)e Fd([)p Fe(c)n(ount)p +Fd(])1975 331 y Ff(ni)h Fd([)p Fe(c)n(ount)p Fd(])2285 286 +y Fc(next)h(mac)o(hine)h(instruction)g(rather)e(than)2306 323 +y(source)g(line)1975 398 y Ff(until)f Fd([)p Fe(lo)n(c)n(ation)p +Fd(])67 b Fc(run)14 b(un)o(til)i(next)e(instruction)h(\(or)e +Fe(lo)n(c)n(ation)p Fc(\))1975 441 y Ff(finish)202 b Fc(run)14 +b(un)o(til)i(selected)e(stac)o(k)f(frame)h(returns)1975 484 +y Ff(return)e Fd([)p Fe(expr)p Fd(])101 b Fc(p)q(op)14 b(selected)g(stac)o(k) +f(frame)h(without)2306 522 y(executing)g Fd([)p Fc(setting)f(return)i(v)n +(alue)p Fd(])1975 566 y Ff(signal)d Fe(num)125 b Fc(resume)14 +b(execution)g(with)g(signal)h Fe(s)f Fc(\(none)f(if)i Ff(0)p +Fc(\))1975 604 y Ff(jump)e Fe(line)1975 641 y Ff(jump)g(*)p +Fe(addr)n(ess)2285 604 y Fc(resume)h(execution)g(at)g(sp)q(eci\014ed)g +Fe(line)f Fc(n)o(um)o(b)q(er)2306 641 y(or)g Fe(addr)n(ess)1975 +681 y Ff(set)g(var=)p Fe(expr)106 b Fc(ev)n(aluate)14 b Fe(expr)e +Fc(without)i(displa)o(ying)i(it;)f(use)2306 718 y(for)e(altering)h(program)f +(v)n(ariables)1975 815 y Fg(Displa)o(y)1975 867 y Ff(print)f +Fd([)p Ff(/)p Fe(f)6 b Fd(])13 b([)p Fe(expr)p Fd(])1975 913 +y Ff(p)h Fd([)p Ff(/)p Fe(f)5 b Fd(])13 b([)p Fe(expr)p Fd(])2285 +867 y Fc(sho)o(w)h(v)n(alue)g(of)g Fe(expr)e Fd([)p Fc(or)h(last)h(v)n(alue)h +Ff($)p Fd(])2306 904 y Fc(according)e(to)g(format)h Fe(f)p +Fc(:)2046 956 y Ff(x)221 b Fc(hexadecimal)2046 993 y Ff(d)g +Fc(signed)14 b(decimal)2046 1030 y Ff(u)221 b Fc(unsigned)15 +b(decimal)2046 1068 y Ff(o)221 b Fc(o)q(ctal)2046 1105 y Ff(t)g +Fc(binary)2046 1142 y Ff(a)g Fc(address,)14 b(absolute)g(and)g(relativ)o(e) +2046 1180 y Ff(c)221 b Fc(c)o(haracter)2046 1217 y Ff(f)g Fc(\015oating)13 +b(p)q(oin)o(t)1975 1266 y Ff(call)g Fd([)p Ff(/)p Fe(f)5 b +Fd(])13 b Fe(expr)89 b Fc(lik)o(e)15 b Ff(print)d Fc(but)i(do)q(es)g(not)g +(displa)o(y)h Ff(void)1975 1320 y(x)f Fd([)p Ff(/)p Fe(Nuf)5 +b Fd(])14 b Fe(expr)98 b Fc(examine)14 b(memory)g(at)g(address)g +Fe(expr)p Fc(;)f(optional)2306 1358 y(format)g(sp)q(ec)h(follo)o(ws)g(slash) +2011 1396 y Fe(N)249 b Fc(coun)o(t)14 b(of)f(ho)o(w)h(man)o(y)h(units)g(to)e +(displa)o(y)2011 1433 y Fe(u)256 b Fc(unit)15 b(size;)f(one)g(of)2356 +1471 y Ff(b)f Fc(individual)k(b)o(ytes)2356 1508 y Ff(h)c Fc(halfw)o(ords)h +(\(t)o(w)o(o)f(b)o(ytes\))2356 1545 y Ff(w)g Fc(w)o(ords)h(\(four)g(b)o +(ytes\))2356 1583 y Ff(g)f Fc(gian)o(t)h(w)o(ords)f(\(eigh)o(t)h(b)o(ytes\)) +2011 1620 y Fe(f)263 b Fc(prin)o(ting)15 b(format.)21 b(An)o(y)14 +b Ff(print)e Fc(format,)i(or)2356 1657 y Ff(s)f Fc(n)o(ull-terminated)j +(string)2356 1695 y Ff(i)d Fc(mac)o(hine)h(instructions)1975 +1738 y Ff(disassem)d Fd([)p Fe(addr)p Fd(])62 b Fc(displa)o(y)15 +b(memory)g(as)e(mac)o(hine)h(instructions)1975 1840 y Fg(Automatic)e(Displa)o +(y)1975 1891 y Ff(display)g Fd([)p Ff(/)p Fe(f)5 b Fd(])13 +b Fe(expr)36 b Fc(sho)o(w)14 b(v)n(alue)g(of)g Fe(expr)e Fc(eac)o(h)i(time)g +(program)2306 1929 y(stops)g Fd([)p Fc(according)e(to)i(format)f +Fe(f)6 b Fd(])1975 1972 y Ff(display)184 b Fc(displa)o(y)15 +b(all)g(enabled)f(expressions)h(on)f(list)1975 2014 y Ff(undisplay)d +Fe(n)118 b Fc(remo)o(v)o(e)14 b(n)o(um)o(b)q(er\(s\))h Fe(n)f +Fc(from)g(list)h(of)2306 2051 y(automatically)f(displa)o(y)o(ed)h +(expressions)1975 2091 y Ff(disable)d(disp)g Fe(n)69 b Fc(disable)15 +b(displa)o(y)g(for)f(expression\(s\))h(n)o(um)o(b)q(er)g Fe(n)1975 +2132 y Ff(enable)d(disp)g Fe(n)87 b Fc(enable)14 b(displa)o(y)h(for)f +(expression\(s\))h(n)o(um)o(b)q(er)g Fe(n)1975 2170 y Ff(info)e(display)99 +b Fc(n)o(um)o(b)q(ered)15 b(list)g(of)e(displa)o(y)j(expressions)p +eop +%%Page: 2 2 +bop -225 -183 a Fg(Expressions)-225 -138 y Fe(expr)245 b Fc(an)13 +b(expression)i(in)g(C,)f(C++,)g(or)g(Mo)q(dula-2)105 -100 y(\(including)i +(function)f(calls\),)f(or:)-225 -60 y Fe(addr)s Ff(@)p Fe(len)176 +b Fc(an)13 b(arra)o(y)h(of)f Fe(len)h Fc(elemen)o(ts)h(b)q(eginning)f(at)105 +-23 y Fe(addr)-225 10 y(\014le)p Ff(::)p Fe(nm)182 b Fc(a)13 +b(v)n(ariable)h(or)g(function)h Fe(nm)e Fc(de\014ned)i(in)f +Fe(\014le)-225 59 y Fa(f)p Fe(typ)n(e)p Fa(g)p Fe(addr)138 +b Fc(read)13 b(memory)h(at)g Fe(addr)e Fc(as)h(sp)q(eci\014ed)h +Fe(typ)n(e)-225 105 y Ff($)292 b Fc(most)13 b(recen)o(t)h(displa)o(y)o(ed)i +(v)n(alue)-225 142 y Ff($)p Fe(n)273 b(n)p Fc(th)14 b(displa)o(y)o(ed)i(v)n +(alue)-225 179 y Ff($$)274 b Fc(displa)o(y)o(ed)15 b(v)n(alue)g(previous)g +(to)e($)-225 217 y Ff($$)p Fe(n)255 b(n)p Fc(th)14 b(displa)o(y)o(ed)i(v)n +(alue)e(bac)o(k)g(from)g($)-225 254 y Ff($)p -205 254 11 2 +v 292 w Fc(last)g(address)g(examined)g(with)h Ff(x)-225 291 +y($)p -205 291 V -193 291 V 292 w Fc(v)n(alue)f(at)g(address)g($)p +357 291 10 2 v -225 329 a Ff($)p Fe(var)243 b Fc(con)o(v)o(enience)14 +b(v)n(ariable;)h(assign)f(an)o(y)g(v)n(alue)-225 410 y Ff(show)e(values)g +Fd([)p Fe(n)p Fd(])63 b Fc(sho)o(w)13 b(last)h(10)f(v)n(alues)i +Fd([)p Fc(or)e(surrounding)i($)p Fe(n)p Fd(])-225 453 y Ff(show)d +(convenience)28 b Fc(displa)o(y)15 b(all)f(con)o(v)o(enience)h(v)n(ariables) +-225 550 y Fg(Sym)o(b)q(ol)d(T)l(able)-225 595 y Ff(info)g(address)g +Fe(s)74 b Fc(sho)o(w)13 b(where)h(sym)o(b)q(ol)h Fe(s)f Fc(is)g(stored)-225 +645 y Ff(info)e(func)h Fd([)p Fe(r)n(e)n(gex)p Fd(])42 b Fc(sho)o(w)13 +b(names,)i(t)o(yp)q(es)f(of)g(de\014ned)g(functions)105 682 +y(\(all,)h(or)e(matc)o(hing)h Fe(r)n(e)n(gex)p Fc(\))-225 733 +y Ff(info)e(var)h Fd([)p Fe(r)n(e)n(gex)p Fd(])60 b Fc(sho)o(w)13 +b(names,)i(t)o(yp)q(es)f(of)g(global)f(v)n(ariables)i(\(all,)105 +770 y(or)f(matc)o(hing)g Fe(r)n(e)n(gex)p Fc(\))-225 821 y +Ff(whatis)e Fd([)p Fe(expr)p Fd(])-225 867 y Ff(ptype)g Fd([)p +Fe(expr)p Fd(])85 821 y Fc(sho)o(w)h(data)h(t)o(yp)q(e)g(of)g +Fe(expr)e Fd([)p Fc(or)h Ff($)p Fd(])g Fc(without)105 858 y(ev)n(aluating;)i +Ff(ptype)d Fc(giv)o(es)i(more)g(detail)-225 910 y Ff(ptype)e +Fe(typ)n(e)147 b Fc(describ)q(e)14 b(t)o(yp)q(e,)h(struct,)f(union,)h(or)f +(en)o(um)-225 1008 y Fg(GDB)f(Scripts)-225 1054 y Ff(source)f +Fe(script)104 b Fc(read,)14 b(execute)f(GDB)h(commands)g(from)g(\014le)105 +1091 y Fe(script)-225 1147 y Ff(define)e Fe(cmd)-154 1184 y(c)n(ommand-list) +85 1147 y Fc(create)g(new)i(GDB)g(command)g Fe(cmd)p Fc(;)f(execute)105 +1184 y(script)i(de\014ned)f(b)o(y)h Fe(c)n(ommand-list)-225 +1222 y Ff(end)256 b Fc(end)14 b(of)g Fe(c)n(ommand-list)-225 +1260 y Ff(document)d Fe(cmd)-154 1297 y(help-text)85 1260 y +Fc(create)h(online)j(do)q(cumen)o(tation)f(for)f(new)h(GDB)105 +1297 y(command)g Fe(cmd)-225 1335 y Ff(end)256 b Fc(end)14 +b(of)g Fe(help-text)-225 1432 y Fg(Signals)-225 1478 y Ff(handle)e +Fe(signal)h(act)44 b Fc(sp)q(ecify)15 b(GDB)e(actions)h(for)f +Fe(signal)p Fc(:)-190 1515 y Ff(print)185 b Fc(announce)13 +b(signal)-190 1553 y Ff(noprint)149 b Fc(b)q(e)13 b(silen)o(t)i(for)f(signal) +-190 1590 y Ff(stop)203 b Fc(halt)14 b(execution)g(on)g(signal)-190 +1627 y Ff(nostop)167 b Fc(do)13 b(not)h(halt)g(execution)-190 +1665 y Ff(pass)203 b Fc(allo)o(w)13 b(y)o(our)h(program)f(to)h(handle)g +(signal)-190 1702 y Ff(nopass)167 b Fc(do)13 b(not)h(allo)o(w)g(y)o(our)g +(program)f(to)g(see)h(signal)-225 1739 y Ff(info)e(signals)100 +b Fc(sho)o(w)13 b(table)h(of)g(signals,)h(GDB)e(action)h(for)f(eac)o(h)-225 +1838 y Fg(Debugging)e(T)l(argets)-225 1884 y Ff(target)h Fe(typ)n(e)g(p)n(ar) +n(am)24 b Fc(connect)13 b(to)g(target)g(mac)o(hine,)i(pro)q(cess,)e(or)h +(\014le)-225 1921 y Ff(help)e(target)118 b Fc(displa)o(y)15 +b(a)o(v)n(ailable)g(targets)-225 1958 y Ff(attach)d Fe(p)n(ar)n(am)97 +b Fc(connect)13 b(to)g(another)h(pro)q(cess)-225 1996 y Ff(detach)202 +b Fc(release)13 b(target)f(from)i(GDB)g(con)o(trol)p 800 -217 +1 9 v 800 2175 V 875 -183 a Fg(Con)o(trollin)o(g)d(GDB)875 +-138 y Ff(set)i Fe(p)n(ar)n(am)f(value)61 b Fc(set)14 b(one)f(of)h(GDB's)g +(in)o(ternal)h(parameters)875 -100 y Ff(show)e Fe(p)n(ar)n(am)132 +b Fc(displa)o(y)15 b(curren)o(t)f(setting)g(of)g(parameter)875 +-51 y(P)o(arameters)f(understo)q(o)q(d)h(b)o(y)h Ff(set)e Fc(and)h +Ff(show)p Fc(:)910 -13 y Ff(complaints)d Fe(limit)i Fc(n)o(um)o(b)q(er)i(of)e +(messages)h(on)f(un)o(usual)j(sym)o(b)q(ols)910 28 y Ff(confirm)c +Fe(on/o\013)43 b Fc(enable)14 b(or)f(disable)i(cautionary)f(queries)910 +66 y Ff(editing)e Fe(on/o\013)43 b Fc(con)o(trol)13 b Ff(readline)e +Fc(command-line)k(editing)910 103 y Ff(height)d Fe(lpp)110 +b Fc(n)o(um)o(b)q(er)15 b(of)e(lines)i(b)q(efore)f(pause)g(in)g(displa)o(y) +910 145 y Ff(language)d Fe(lang)58 b Fc(Language)12 b(for)h(GDB)h +(expressions)h(\()p Ff(auto)p Fc(,)e Ff(c)g Fc(or)1206 182 +y Ff(modula-2)p Fc(\))910 222 y Ff(listsize)e Fe(n)101 b Fc(n)o(um)o(b)q(er) +15 b(of)e(lines)i(sho)o(wn)f(b)o(y)h Ff(list)910 259 y(prompt)d +Fe(str)114 b Fc(use)14 b Fe(str)f Fc(as)g(GDB)h(prompt)910 +297 y Ff(radix)e Fe(b)n(ase)111 b Fc(o)q(ctal,)13 b(decimal,)i(or)e(hex)i(n)o +(um)o(b)q(er)1206 334 y(represen)o(tation)910 374 y Ff(verbose)d +Fe(on/o\013)43 b Fc(con)o(trol)13 b(messages)g(when)h(loading)g(sym)o(b)q +(ols)910 411 y Ff(width)e Fe(cpl)130 b Fc(n)o(um)o(b)q(er)15 +b(of)e(c)o(haracters)g(b)q(efore)h(line)g(folded)910 449 y +Ff(write)e Fe(on/o\013)79 b Fc(Allo)o(w)13 b(or)h(forbid)g(patc)o(hing)h +(binary)m(,)g(core)e(\014les)1206 486 y(\(when)g(reop)q(ened)h(with)g +Ff(exec)f Fc(or)g Ff(core)p Fc(\))910 526 y Ff(history)f Fb(:)7 +b(:)g(:)910 563 y Ff(h)14 b Fb(:)7 b(:)g(:)1185 526 y Fc(groups)14 +b(with)g(the)g(follo)o(wing)g(options:)910 598 y Ff(h)g(exp)f +Fe(o\013/on)82 b Fc(disable/enable)14 b Ff(readline)d Fc(history)k(expansion) +910 635 y Ff(h)f(file)e Fe(\014lename)33 b Fc(\014le)14 b(for)f(recording)h +(GDB)f(command)h(history)910 672 y Ff(h)g(size)e Fe(size)104 +b Fc(n)o(um)o(b)q(er)15 b(of)e(commands)h(k)o(ept)h(in)f(history)h(list)910 +710 y Ff(h)f(save)e Fe(o\013/on)65 b Fc(con)o(trol)13 b(use)h(of)g(external)g +(\014le)g(for)f(command)1206 747 y(history)910 803 y Ff(print)f +Fb(:)7 b(:)g(:)910 840 y Ff(p)14 b Fb(:)7 b(:)g(:)1185 803 +y Fc(groups)14 b(with)g(the)g(follo)o(wing)g(options:)910 882 +y Ff(p)g(address)d Fe(on/o\013)h Fc(prin)o(t)j(memory)f(addresses)g(in)g +(stac)o(ks,)h(v)n(alues)910 923 y Ff(p)f(array)e Fe(o\013/on)47 +b Fc(compact)13 b(or)g(attractiv)o(e)g(format)h(for)g(arra)o(ys)910 +965 y Ff(p)g(demangl)d Fe(on/o\013)h Fc(source)h(\(demangled\))h(or)g(in)o +(ternal)g(form)g(for)1206 1002 y(C++)g(sym)o(b)q(ols)910 1042 +y Ff(p)g(asm-dem)d Fe(on/o\013)h Fc(demangle)i(C++)g(sym)o(b)q(ols)h(in)g +(mac)o(hine-)1206 1079 y(instruction)g(output)910 1118 y Ff(p)f(elements)d +Fe(limit)17 b Fc(n)o(um)o(b)q(er)e(of)e(arra)o(y)h(elemen)o(ts)g(to)g(displa) +o(y)910 1160 y Ff(p)g(object)e Fe(on/o\013)29 b Fc(prin)o(t)15 +b(C++)f(deriv)o(ed)h(t)o(yp)q(es)g(for)e(ob)r(jects)910 1201 +y Ff(p)h(pretty)e Fe(o\013/on)29 b Fc(struct)14 b(displa)o(y:)23 +b(compact)13 b(or)g(inden)o(ted)910 1243 y Ff(p)h(union)e Fe(on/o\013)47 +b Fc(displa)o(y)15 b(of)f(union)h(mem)o(b)q(ers)910 1284 y +Ff(p)f(vtbl)e Fe(o\013/on)65 b Fc(displa)o(y)15 b(of)f(C++)h(virtual)f +(function)h(tables)875 1359 y Ff(show)e(commands)81 b Fc(sho)o(w)13 +b(last)h(10)f(commands)875 1396 y Ff(show)g(commands)e Fe(n)51 +b Fc(sho)o(w)13 b(10)g(commands)h(around)g(n)o(um)o(b)q(er)h +Fe(n)875 1434 y Ff(show)e(commands)e(+)52 b Fc(sho)o(w)13 b(next)i(10)e +(commands)875 1521 y Fg(W)l(orking)g(Files)875 1573 y Ff(file)g +Fd([)p Fe(\014le)p Fd(])156 b Fc(use)14 b Fe(\014le)f Fc(for)h(b)q(oth)g(sym) +o(b)q(ols)h(and)f(executable;)1206 1610 y(with)g(no)g(arg,)f(discard)h(b)q +(oth)875 1659 y Ff(core)f Fd([)p Fe(\014le)p Fd(])156 b Fc(read)13 +b Fe(\014le)h Fc(as)f(coredump;)i(or)e(discard)875 1713 y Ff(exec)g +Fd([)p Fe(\014le)p Fd(])156 b Fc(use)14 b Fe(\014le)f Fc(as)h(executable)g +(only;)h(or)e(discard)875 1767 y Ff(symbol)f Fd([)p Fe(\014le)p +Fd(])121 b Fc(use)14 b(sym)o(b)q(ol)h(table)f(from)g Fe(\014le)p +Fc(;)f(or)h(discard)875 1810 y Ff(load)f Fe(\014le)180 b Fc(dynamically)15 +b(link)h Fe(\014le)f Fc(and)f(add)g(its)h(sym)o(b)q(ols)875 +1848 y Ff(add-sym)c Fe(\014le)j(addr)45 b Fc(read)13 b(additional)i(sym)o(b)q +(ols)g(from)f Fe(\014le)p Fc(,)1206 1885 y(dynamically)h(loaded)f(at)f +Fe(addr)875 1923 y Ff(info)g(files)135 b Fc(displa)o(y)15 b(w)o(orking)f +(\014les)g(and)g(targets)f(in)i(use)875 1961 y Ff(path)e Fe(dirs)167 +b Fc(add)14 b Fe(dirs)f Fc(to)g(fron)o(t)h(of)g(path)g(searc)o(hed)f(for)1206 +1998 y(executable)g(and)h(sym)o(b)q(ol)h(\014les)875 2037 y +Ff(show)e(path)153 b Fc(displa)o(y)15 b(executable)f(and)g(sym)o(b)q(ol)h +(\014le)f(path)875 2074 y Ff(info)f(share)135 b Fc(list)15 +b(names)e(of)h(shared)g(libraries)h(curren)o(tly)1206 2111 +y(loaded)p 1900 -217 V 1900 2175 V 1975 -183 a Fg(Source)e(Files)1975 +-138 y Ff(dir)g Fe(names)148 b Fc(add)14 b(directory)g Fe(names)f +Fc(to)h(fron)o(t)g(of)f(source)2306 -100 y(path)1975 -62 y +Ff(dir)256 b Fc(clear)13 b(source)h(path)1975 -25 y Ff(show)f(dir)171 +b Fc(sho)o(w)14 b(curren)o(t)g(source)f(path)1975 50 y Ff(list)238 +b Fc(sho)o(w)14 b(next)g(ten)g(lines)h(of)e(source)1975 87 +y Ff(list)g(-)207 b Fc(sho)o(w)14 b(previous)g(ten)g(lines)1975 +125 y Ff(list)f Fe(lines)156 b Fc(displa)o(y)15 b(source)f(surrounding)h +Fe(lines)p Fc(,)f(sp)q(eci\014ed)2306 162 y(as:)2011 206 y +Fd([)p Fe(\014le)p Ff(:)p Fd(])p Fe(num)122 b Fc(line)15 b(n)o(um)o(b)q(er)g +Fd([)p Fc(in)f(named)g(\014le)p Fd(])2011 260 y([)p Fe(\014le)p +Ff(:)p Fd(])p Fe(function)63 b Fc(b)q(eginning)15 b(of)e(function)i +Fd([)p Fc(in)f(named)g(\014le)p Fd(])2011 303 y Ff(+)p Fe(o\013)217 +b(o\013)14 b Fc(lines)h(after)e(last)h(prin)o(ted)2011 340 +y Ff(-)p Fe(o\013)217 b(o\013)14 b Fc(lines)h(previous)f(to)g(last)g(prin)o +(ted)2011 377 y Ff(*)p Fe(addr)n(ess)145 b Fc(line)15 b(con)o(taining)f +Fe(addr)n(ess)1975 415 y Ff(list)f Fe(f)p Ff(,)p Fe(l)187 b +Fc(from)14 b(line)h Fe(f)e Fc(to)g(line)i Fe(l)1975 452 y Ff(info)e(line)f +Fe(num)76 b Fc(sho)o(w)14 b(starting,)g(ending)g(addresses)g(of)2306 +489 y(compiled)g(co)q(de)f(for)h(source)f(line)i Fe(num)1975 +528 y Ff(info)e(source)117 b Fc(sho)o(w)14 b(name)f(of)h(curren)o(t)g(source) +f(\014le)1975 565 y Ff(info)g(sources)99 b Fc(list)15 b(all)f(source)f +(\014les)h(in)h(use)1975 603 y Ff(forw)e Fe(r)n(e)n(gex)150 +b Fc(searc)o(h)13 b(follo)o(wing)h(source)g(lines)h(for)e Fe(r)n(e)n(gex)1975 +640 y Ff(rev)g Fe(r)n(e)n(gex)168 b Fc(searc)o(h)13 b(preceding)h(source)g +(lines)h(for)e Fe(r)n(e)n(gex)1975 737 y Fg(GDB)g(under)f(GNU)i(Emacs)1975 +782 y Ff(M-x)f(gdb)189 b Fc(run)14 b(GDB)g(under)h(Emacs)1975 +820 y Ff(C-h)e(m)225 b Fc(describ)q(e)14 b(GDB)g(mo)q(de)1975 +857 y Ff(M-s)256 b Fc(step)14 b(one)f(line)i(\()p Ff(step)p +Fc(\))1975 899 y Ff(M-n)256 b Fc(next)14 b(line)h(\()p Ff(next)p +Fc(\))1975 936 y Ff(M-i)256 b Fc(step)14 b(one)f(instruction)i(\()p +Ff(stepi)p Fc(\))1975 978 y Ff(C-c)e(C-f)189 b Fc(\014nish)15 +b(curren)o(t)f(stac)o(k)g(frame)f(\()p Ff(finish)p Fc(\))1975 +1015 y Ff(M-c)256 b Fc(con)o(tin)o(ue)14 b(\()p Ff(cont)p Fc(\))1975 +1052 y Ff(M-u)256 b Fc(up)14 b Fe(ar)n(g)f Fc(frames)h(\()p +Ff(up)p Fc(\))1975 1094 y Ff(M-d)256 b Fc(do)o(wn)14 b Fe(ar)n(g)f +Fc(frames)h(\()p Ff(down)p Fc(\))1975 1131 y Ff(C-x)f(&)225 +b Fc(cop)o(y)14 b(n)o(um)o(b)q(er)h(from)f(p)q(oin)o(t,)h(insert)f(at)f(end) +1975 1169 y Ff(C-x)g(SPC)189 b Fc(\(in)14 b(source)g(\014le\))g(set)f(break)h +(at)g(p)q(oin)o(t)1975 1267 y Fg(GDB)f(License)1975 1313 y +Ff(show)g(copying)99 b Fc(Displa)o(y)15 b(GNU)e(General)g(Public)i(License) +1975 1350 y Ff(show)e(warranty)81 b Fc(There)13 b(is)i(NO)e(W)l(ARRANTY)g +(for)h(GDB.)2306 1387 y(Displa)o(y)h(full)g(no-w)o(arran)o(t)o(y)f(statemen)o +(t.)2024 1622 y Fh(Cop)o(yrigh)o(t)2185 1621 y(c)2171 1622 +y Fa(\015)o Fh(1991,)h(1992,)f(1993)h(F)n(ree)d(Soft)o(w)o(are)i(F)n +(oundation,)f(Inc.)2215 1660 y(Roland)i(P)o(esc)o(h)f(\(p)q(esc)o(h@cygn)o +(us.com\))1997 1697 y(The)f(author)h(assumes)f(no)h(resp)q(onsibilit)o(y)j +(for)c(an)o(y)h(errors)g(on)g(this)h(card.)1975 1759 y(This)g(card)e(ma)o(y)g +(b)q(e)g(freely)h(distributed)g(under)f(the)g(terms)g(of)g(the)h(GNU)1975 +1797 y(General)h(Public)g(License.)2012 1834 y(Please)f(con)o(tribute)g(to)g +(dev)o(elopmen)o(t)e(of)i(this)h(card)e(b)o(y)h(annotating)h(it.)1975 +1896 y(GDB)g(itself)f(is)h(free)e(soft)o(w)o(are;)g(y)o(ou)h(are)g(w)o +(elcome)e(to)i(distribute)h(copies)f(of)1975 1934 y(it)h(under)e(the)g(terms) +g(of)g(the)g(GNU)i(General)g(Public)g(License.)20 b(There)12 +b(is)1975 1971 y(absolutely)k(no)d(w)o(arran)o(t)o(y)i(for)e(GDB.)p +eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/gnu/usr.bin/gdb/doc/refcard.tex b/gnu/usr.bin/gdb/doc/refcard.tex new file mode 100644 index 00000000000..589960805f2 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/refcard.tex @@ -0,0 +1,646 @@ +%%%%%%%%%%%%%%%% gdb-refcard.tex %%%%%%%%%%%%%%%% + +%This file is TeX source for a reference card describing GDB, the GNU debugger. +%$Id: refcard.tex,v 1.1.1.1 1993/10/30 21:59:42 jkh Exp $ +%Copyright (C) 1991, 1992 Free Software Foundation, Inc. +%Permission is granted to make and distribute verbatim copies of +%this reference provided the copyright notices and permission notices +%are preserved on all copies. +% +%TeX markup is a programming language; accordingly this file is source +%for a program to generate a reference. +% +%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 1, 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 can find a copy of the GNU General Public License in the GDB +%manual; or write to the Free Software Foundation, Inc., +%675 Mass Ave, Cambridge, MA 02139, USA. +% +%You can contact the author as: pesch@cygnus.com +% +% Roland Pesch +% Cygnus Support +% 1937 Landings Drive +% Mountain View, CA 94043 USA +% +% +1 415 903 1400 +% +% +% +% 22-AUG-1993 Andreas Vogel +% +% Modifications made in order to handle different papersizes correctly. +% You only have to set the total width and height of the paper, the +% horizontal and vertical margin space measured from *paper edge* +% and the interline and interspec spacing. +% In order to support a new papersize, you have to fiddle with the +% latter four dimensions. Just try out a few values. +% All other values will be computed at process time so it should be +% quite easy to support different paper sizes - only four values to +% guess :-) +% +% To find the configuration places, just search for the string +% "CONFIGURATION". +% +% Andreas Vogel (av@ssw.de) +% +% +% +% Uncomment the following `magnification' command if you want to print +% out in a larger font. Caution! You may need larger paper. You had +% best avoid using 3-column output if you try this. See the ``Three +% column format'' section below if you want to print in three column +% format. +% +%\magnification=\magstep 1 +% +% NOTE ON INTENTIONAL OMISSIONS: This reference card includes most GDB +% commands, but due to space constraints there are some things I chose +% to omit. In general, not all synonyms for commands are covered, nor +% all variations of a command. +% The GDB-under-Emacs section omits gdb-mode functions without default +% keybindings. GDB startup options are not described. +% set print sevenbit-strings, set symbol-reloading omitted. +% printsyms, printpsyms, omitted since they're for GDB maintenance primarily +% share omitted due to obsolescence +% set check range/type omitted at least til code is in GDB. +% +%-------------------- Three column format ----------------------- + +%%%% --- To disable three column format, comment out this entire section + +% Three-column format for landscape printing + +%-------- Papersize defs: + +\newdimen\totalwidth \newdimen\totalheight +\newdimen\hmargin \newdimen\vmargin +\newdimen\secskip \newdimen\lskip +\newdimen\barwidth \newdimen\barheight +\newdimen\intersecwidth + +%% +%% START CONFIGURATION - PAPERSIZE DEFINITIONS +%------- Papersize params: +%% US letter paper (8.5x11in) +%% +\totalwidth=11in % total width of paper +\totalheight=8.5in % total height of paper +\hmargin=.25in % horizontal margin width +\vmargin=.25in % vertical margin width +\secskip=1pc % space between refcard secs +\lskip=2pt % extra skip between \sec entries +%------- end papersize params +%% +%% change according to personal taste, not papersize dependent +%% +\barwidth=.1pt % width of the cropmark bar +\barheight=2pt % height of the cropmark bar +\intersecwidth=0.5em % width between \itmwid and \dfnwid +%% +%% END CONFIGURATION - PAPERSIZE DEFINITIONS +%% + +%% +%% values to be computed - nothing to configure +%% +\newdimen\fullhsize % width of area without margins +\newdimen\itmwid % width of item column +\newdimen\dfnwid % width of definition column +\newdimen\temp % only for temporary use + +%% +%% adjust the offsets so the margins are measured *from paper edge* +%% +\hoffset=-1in \advance \hoffset by \hmargin +\voffset=-1in \advance \voffset by \vmargin + +%% +%% fullhsize = totalwidth - (2 * hmargin) +%% +\fullhsize=\totalwidth +\temp=\hmargin \multiply \temp by 2 \advance \fullhsize by -\temp + +%% +%% hsize = (fullhsize - (4 * hmargin) - (2 * barwidth)) / 3 +%% +\hsize=\fullhsize +\temp=\hmargin \multiply \temp by 4 \advance \hsize by -\temp +\temp=\barwidth \multiply \temp by 2 \advance \hsize by -\temp +\divide \hsize by 3 + +%% +%% vsize = totalheight - (2 * vmargin) +%% +\vsize=\totalheight +\temp=\vmargin \multiply \temp by 2 \advance \vsize by -\temp + +%% +%% itmwid = (hsize - intersecwidth) * 1/3 +%% dfnwid = (hsize - intersecwidth) * 2/3 +%% +\temp=\hsize \advance \temp by -\intersecwidth \divide \temp by 3 +\itmwid=\temp +\dfnwid=\hsize \advance \dfnwid by -\itmwid + +%-------- end papersize defs + + +\def\fulline{\hbox to \fullhsize} +\let\lcr=L \newbox\leftcolumn\newbox\centercolumn +\output={\if L\lcr + \global\setbox\leftcolumn=\columnbox \global\let\lcr=C + \else + \if C\lcr + \global\setbox\centercolumn=\columnbox \global\let\lcr=R + \else \tripleformat \global\let\lcr=L + \fi + \fi +% \ifnum\outputpenalty>-20000 \else\dosupereject\fi + } + +%% +%% START CONFIGURATION - ALTERNATIVE FOLDING GUIDES +%% +%% For NO printed folding guide, +%% comment out other \def\vdecor's and uncomment: + +%\def\vdecor{\hskip\hmargin plus1fil\hskip\barwidth plus1fil\hskip\hmargin plus1fil} + +%% For SOLID LINE folding guide, +%% comment out other \def\vdecor's and uncomment: + +%\def\vdecor{\hskip\hmargin plus1fil \vrule width \barwidth \hskip\hmargin plus1fil} + +%% For SMALL MARKS NEAR TOP AND BOTTOM as folding guide, +%% comment out other \def\vdecor's and uncomment: + +\def\vdecor{\hskip\hmargin plus1fil +\vbox to \vsize{\hbox to \barwidth{\vrule height\barheight width\barwidth}\vfill +\hbox to \barwidth{\vrule height\barheight width\barwidth}}%THIS PERCENT SIGN IS ESSENTIAL +\hskip\hmargin plus1fil} + +%% +%% END CONFIGURATION - ALTERNATIVES FOR FOLDING GUIDES +%% + +\def\tripleformat{\shipout\vbox{\fulline{\box\leftcolumn\vdecor + \box\centercolumn\vdecor + \columnbox} + } + \advancepageno} +\def\columnbox{\leftline{\pagebody}} +\def\bye{\par\vfill + \supereject + \if R\lcr \null\vfill\eject\fi + \end} + +%-------------------- end three column format ----------------------- + +%-------------------- Computer Modern font defs: -------------------- +\font\bbf=cmbx10 +\font\vbbf=cmbx12 +\font\smrm=cmr6 +\font\brm=cmr10 +\font\rm=cmr7 +\font\it=cmti7 +\font\tt=cmtt8 +%-------------------- end font defs --------------------------------- + +% +\hyphenpenalty=5000\tolerance=2000\raggedright\raggedbottom +\normalbaselineskip=9pt\baselineskip=9pt +% +\parindent=0pt +\parskip=0pt +\footline={\vbox to0pt{\hss}} +% +\def\ctl#1{{\tt C-#1}} +\def\opt#1{{\brm[{\rm #1}]}} +\def\xtra#1{\noalign{\smallskip{\tt#1}}} +% +\long\def\sec#1;#2\endsec{\vskip \secskip +\halign{% +%COL 1 (of halign): +\vtop{\hsize=\itmwid\tt +##\par\vskip \lskip }\hfil +%COL 2 (of halign): +&\vtop{\hsize=\dfnwid\hangafter=1\hangindent=\intersecwidth +\rm ##\par\vskip \lskip}\cr +%Tail of \long\def fills in halign body with \sec args: +\noalign{{\bbf #1}\vskip \lskip} +#2 +} +} + +{\vbbf GDB QUICK REFERENCE}\hfil{\smrm GDB Version 4}\qquad + +\sec Essential Commands; +gdb {\it program} \opt{{\it core}}&debug {\it program} \opt{using +coredump {\it core}}\cr +b \opt{\it file\tt:}{\it function}&set breakpoint at {\it function} \opt{in \it file}\cr +run \opt{{\it arglist}}&start your program \opt{with {\it arglist}}\cr +bt& backtrace: display program stack\cr +p {\it expr}&display the value of an expression\cr +c &continue running your program\cr +n &next line, stepping over function calls\cr +s &next line, stepping into function calls\cr +\endsec + +\sec Starting GDB; +gdb&start GDB, with no debugging files\cr +gdb {\it program}&begin debugging {\it program}\cr +gdb {\it program core}&debug coredump {\it core} produced by {\it +program}\cr +gdb --help&describe command line options\cr +\endsec + +\sec Stopping GDB; +quit&exit GDB; also {\tt q} or {\tt EOF} (eg \ctl{d})\cr +INTERRUPT&(eg \ctl{c}) terminate current command, or send to running process\cr +\endsec + +\sec Getting Help; +help&list classes of commands\cr +help {\it class}&one-line descriptions for commands in {\it class}\cr +help {\it command}&describe {\it command}\cr +\endsec + +\sec Executing your Program; +run {\it arglist}&start your program with {\it arglist}\cr +run&start your program with current argument list\cr +run $\ldots$ <{\it inf} >{\it outf}&start your program with input, output +redirected\cr +\cr +kill&kill running program\cr +\cr +tty {\it dev}&use {\it dev} as stdin and stdout for next {\tt run}\cr +set args {\it arglist}&specify {\it arglist} for next +{\tt run}\cr +set args&specify empty argument list\cr +show args&display argument list\cr +\cr +show environment&show all environment variables\cr +show env {\it var}&show value of environment variable {\it var}\cr +set env {\it var} {\it string}&set environment variable {\it var}\cr +unset env {\it var}&remove {\it var} from environment\cr +\endsec + +\sec Shell Commands; +cd {\it dir}&change working directory to {\it dir}\cr +pwd&Print working directory\cr +make $\ldots$&call ``{\tt make}''\cr +shell {\it cmd}&execute arbitrary shell command string\cr +\endsec + +\vfill +\line{\smrm \opt{ } surround optional arguments \hfill $\ldots$ show +one or more arguments} +\vskip\baselineskip +\centerline{\smrm \copyright 1991, 1992 Free Software Foundation, Inc.\qquad Permissions on back} +\eject +\sec Breakpoints and Watchpoints; +break \opt{\it file\tt:}{\it line}\par +b \opt{\it file\tt:}{\it line}&set breakpoint at {\it line} number \opt{in \it file}\par +eg:\quad{\tt break main.c:37}\quad\cr +break \opt{\it file\tt:}{\it func}&set breakpoint at {\it +func} \opt{in \it file}\cr +break +{\it offset}\par +break -{\it offset}&set break at {\it offset} lines from current stop\cr +break *{\it addr}&set breakpoint at address {\it addr}\cr +break&set breakpoint at next instruction\cr +break $\ldots$ if {\it expr}&break conditionally on nonzero {\it expr}\cr +cond {\it n} \opt{\it expr}&new conditional expression on breakpoint +{\it n}; make unconditional if no {\it expr}\cr +tbreak $\ldots$&temporary break; disable when reached\cr +rbreak {\it regex}&break on all functions matching {\it regex}\cr +watch {\it expr}&set a watchpoint for expression {\it expr}\cr +catch {\it x}&break at C++ handler for exception {\it x}\cr +\cr +info break&show defined breakpoints\cr +info watch&show defined watchpoints\cr +\cr +clear&delete breakpoints at next instruction\cr +clear \opt{\it file\tt:}{\it fun}&delete breakpoints at entry to {\it fun}()\cr +clear \opt{\it file\tt:}{\it line}&delete breakpoints on source line \cr +delete \opt{{\it n}}&delete breakpoints +\opt{or breakpoint {\it n}}\cr +\cr +disable \opt{{\it n}}&disable breakpoints +\opt{or breakpoint {\it n}} +\cr +enable \opt{{\it n}}&enable breakpoints +\opt{or breakpoint {\it n}} +\cr +enable once \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}}; +disable again when reached +\cr +enable del \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}}; +delete when reached +\cr +\cr +ignore {\it n} {\it count}&ignore breakpoint {\it n}, {\it count} +times\cr +\cr +commands {\it n}\par +\qquad \opt{\tt silent}\par +\qquad {\it command-list}&execute GDB {\it command-list} every time breakpoint {\it n} is reached. \opt{{\tt silent} suppresses default +display}\cr +end&end of {\it command-list}\cr +\endsec + +\sec Program Stack; +backtrace \opt{\it n}\par +bt \opt{\it n}&print trace of all frames in stack; or of {\it n} +frames---innermost if {\it n}{\tt >0}, outermost if {\it n}{\tt <0}\cr +frame \opt{\it n}&select frame number {\it n} or frame at address {\it +n}; if no {\it n}, display current frame\cr +up {\it n}&select frame {\it n} frames up\cr +down {\it n}&select frame {\it n} frames down\cr +info frame \opt{\it addr}&describe selected frame, or frame at +{\it addr}\cr +info args&arguments of selected frame\cr +info locals&local variables of selected frame\cr +info reg \opt{\it rn}$\ldots$\par +info all-reg \opt{\it rn}®ister values \opt{for regs {\it rn\/}} in +selected frame; {\tt all-reg} includes floating point\cr +info catch&exception handlers active in selected frame\cr +\endsec + +\vfill\eject +\sec Execution Control; +continue \opt{\it count}\par +c \opt{\it count}&continue running; if {\it count} specified, ignore +this breakpoint next {\it count} times\cr +\cr +step \opt{\it count}\par +s \opt{\it count}&execute until another line reached; repeat {\it count} times if +specified\cr +stepi \opt{\it count}\par +si \opt{\it count}&step by machine instructions rather than source +lines\cr +\cr +next \opt{\it count}\par +n \opt{\it count}&execute next line, including any function calls\cr +nexti \opt{\it count}\par +ni \opt{\it count}&next machine instruction rather than source +line\cr +\cr +until \opt{\it location}&run until next instruction (or {\it +location})\cr +finish&run until selected stack frame returns\cr +return \opt{\it expr}&pop selected stack frame without executing +\opt{setting return value}\cr +signal {\it num}&resume execution with signal {\it s} (none if {\tt 0})\cr +jump {\it line}\par +jump *{\it address}&resume execution at specified {\it line} number or +{\it address}\cr +set var={\it expr}&evaluate {\it expr} without displaying it; use for +altering program variables\cr +\endsec + +\sec Display; +print \opt{\tt/{\it f}\/} \opt{\it expr}\par +p \opt{\tt/{\it f}\/} \opt{\it expr}&show value of {\it expr} \opt{or +last value \tt \$} according to format {\it f}:\cr +\qquad x&hexadecimal\cr +\qquad d&signed decimal\cr +\qquad u&unsigned decimal\cr +\qquad o&octal\cr +\qquad t&binary\cr +\qquad a&address, absolute and relative\cr +\qquad c&character\cr +\qquad f&floating point\cr +call \opt{\tt /{\it f}\/} {\it expr}&like {\tt print} but does not display +{\tt void}\cr +x \opt{\tt/{\it Nuf}\/} {\it expr}&examine memory at address {\it expr}; +optional format spec follows slash\cr +\quad {\it N}&count of how many units to display\cr +\quad {\it u}&unit size; one of\cr +&{\tt\qquad b}\ individual bytes\cr +&{\tt\qquad h}\ halfwords (two bytes)\cr +&{\tt\qquad w}\ words (four bytes)\cr +&{\tt\qquad g}\ giant words (eight bytes)\cr +\quad {\it f}&printing format. Any {\tt print} format, or\cr +&{\tt\qquad s}\ null-terminated string\cr +&{\tt\qquad i}\ machine instructions\cr +disassem \opt{\it addr}&display memory as machine instructions\cr +\endsec + +\sec Automatic Display; +display \opt{\tt/\it f\/} {\it expr}&show value of {\it expr} each time +program stops \opt{according to format {\it f}\/}\cr +display&display all enabled expressions on list\cr +undisplay {\it n}&remove number(s) {\it n} from list of +automatically displayed expressions\cr +disable disp {\it n}&disable display for expression(s) number {\it +n}\cr +enable disp {\it n}&enable display for expression(s) number {\it +n}\cr +info display&numbered list of display expressions\cr +\endsec + +\vfill\eject + +\sec Expressions; +{\it expr}&an expression in C, C++, or Modula-2 (including function calls), or:\cr +{\it addr\/}@{\it len}&an array of {\it len} elements beginning at {\it +addr}\cr +{\it file}::{\it nm}&a variable or function {\it nm} defined in {\it +file}\cr +$\tt\{${\it type}$\tt\}${\it addr}&read memory at {\it addr} as specified +{\it type}\cr +\$&most recent displayed value\cr +\${\it n}&{\it n}th displayed value\cr +\$\$&displayed value previous to \$\cr +\$\${\it n}&{\it n}th displayed value back from \$\cr +\$\_&last address examined with {\tt x}\cr +\$\_\_&value at address \$\_\cr +\${\it var}&convenience variable; assign any value\cr +\cr +show values \opt{{\it n}}&show last 10 values \opt{or surrounding +\${\it n}}\cr +show convenience&display all convenience variables\cr +\endsec + +\sec Symbol Table; +info address {\it s}&show where symbol {\it s} is stored\cr +info func \opt{\it regex}&show names, types of defined functions +(all, or matching {\it regex})\cr +info var \opt{\it regex}&show names, types of global variables (all, +or matching {\it regex})\cr +whatis \opt{\it expr}\par +ptype \opt{\it expr}&show data type of {\it expr} \opt{or \tt \$} +without evaluating; {\tt ptype} gives more detail\cr +ptype {\it type}&describe type, struct, union, or enum\cr +\endsec + +\sec GDB Scripts; +source {\it script}&read, execute GDB commands from file {\it +script}\cr +\cr +define {\it cmd}\par +\qquad {\it command-list}&create new GDB command {\it cmd}; +execute script defined by {\it command-list}\cr +end&end of {\it command-list}\cr +document {\it cmd}\par +\qquad {\it help-text}&create online documentation +for new GDB command {\it cmd}\cr +end&end of {\it help-text}\cr +\endsec + +\sec Signals; +handle {\it signal} {\it act}&specify GDB actions for {\it signal}:\cr +\quad print&announce signal\cr +\quad noprint&be silent for signal\cr +\quad stop&halt execution on signal\cr +\quad nostop&do not halt execution\cr +\quad pass&allow your program to handle signal\cr +\quad nopass&do not allow your program to see signal\cr +info signals&show table of signals, GDB action for each\cr +\endsec + +\sec Debugging Targets; +target {\it type} {\it param}&connect to target machine, process, or file\cr +help target&display available targets\cr +attach {\it param}&connect to another process\cr +detach&release target from GDB control\cr +\endsec + +\vfill\eject +\sec Controlling GDB; +set {\it param} {\it value}&set one of GDB's internal parameters\cr +show {\it param}&display current setting of parameter\cr +\xtra{\rm Parameters understood by {\tt set} and {\tt show}:} +\quad complaints {\it limit}&number of messages on unusual symbols\cr +\quad confirm {\it on/off}&enable or disable cautionary queries\cr +\quad editing {\it on/off}&control {\tt readline} command-line editing\cr +\quad height {\it lpp}&number of lines before pause in display\cr +\quad language {\it lang}&Language for GDB expressions ({\tt auto}, {\tt c} or +{\tt modula-2})\cr +\quad listsize {\it n}&number of lines shown by {\tt list}\cr +\quad prompt {\it str}&use {\it str} as GDB prompt\cr +\quad radix {\it base}&octal, decimal, or hex number representation\cr +\quad verbose {\it on/off}&control messages when loading +symbols\cr +\quad width {\it cpl}&number of characters before line folded\cr +\quad write {\it on/off}&Allow or forbid patching binary, core files +(when reopened with {\tt exec} or {\tt core}) +\cr +\quad history $\ldots$\par +\quad h $\ldots$&groups with the following options:\cr +\quad h exp {\it off/on}&disable/enable {\tt readline} history expansion\cr +\quad h file {\it filename}&file for recording GDB command history\cr +\quad h size {\it size}&number of commands kept in history list\cr +\quad h save {\it off/on}&control use of external file for +command history\cr +\cr +\quad print $\ldots$\par +\quad p $\ldots$&groups with the following options:\cr +\quad p address {\it on/off}&print memory addresses in stacks, +values\cr +\quad p array {\it off/on}&compact or attractive format for +arrays\cr +\quad p demangl {\it on/off}&source (demangled) or internal form for C++ +symbols\cr +\quad p asm-dem {\it on/off}&demangle C++ symbols in +machine-instruction output\cr +\quad p elements {\it limit}&number of array elements to display\cr +\quad p object {\it on/off}&print C++ derived types for objects\cr +\quad p pretty {\it off/on}&struct display: compact or indented\cr +\quad p union {\it on/off}&display of union members\cr +\quad p vtbl {\it off/on}&display of C++ virtual function +tables\cr +\cr +show commands&show last 10 commands\cr +show commands {\it n}&show 10 commands around number {\it n}\cr +show commands +&show next 10 commands\cr +\endsec + +\sec Working Files; +file \opt{\it file}&use {\it file} for both symbols and executable; +with no arg, discard both\cr +core \opt{\it file}&read {\it file} as coredump; or discard\cr +exec \opt{\it file}&use {\it file} as executable only; or discard\cr +symbol \opt{\it file}&use symbol table from {\it file}; or discard\cr +load {\it file}&dynamically link {\it file\/} and add its symbols\cr +add-sym {\it file} {\it addr}&read additional symbols from {\it file}, +dynamically loaded at {\it addr}\cr +info files&display working files and targets in use\cr +path {\it dirs}&add {\it dirs} to front of path searched for +executable and symbol files\cr +show path&display executable and symbol file path\cr +info share&list names of shared libraries currently loaded\cr +\endsec + +\vfill\eject +\sec Source Files; +dir {\it names}&add directory {\it names} to front of source path\cr +dir&clear source path\cr +show dir&show current source path\cr +\cr +list&show next ten lines of source\cr +list -&show previous ten lines\cr +list {\it lines}&display source surrounding {\it lines}, +specified as:\cr +\quad{\opt{\it file\tt:}\it num}&line number \opt{in named file}\cr +\quad{\opt{\it file\tt:}\it function}&beginning of function \opt{in +named file}\cr +\quad{\tt +\it off}&{\it off} lines after last printed\cr +\quad{\tt -\it off}&{\it off} lines previous to last printed\cr +\quad{\tt*\it address}&line containing {\it address}\cr +list {\it f},{\it l}&from line {\it f} to line {\it l}\cr +info line {\it num}&show starting, ending addresses of compiled code for +source line {\it num}\cr +info source&show name of current source file\cr +info sources&list all source files in use\cr +forw {\it regex}&search following source lines for {\it regex}\cr +rev {\it regex}&search preceding source lines for {\it regex}\cr +\endsec + +\sec GDB under GNU Emacs; +M-x gdb&run GDB under Emacs\cr +\ctl{h} m&describe GDB mode\cr +M-s&step one line ({\tt step})\cr +M-n&next line ({\tt next})\cr +M-i&step one instruction ({\tt stepi})\cr +\ctl{c} \ctl{f}&finish current stack frame ({\tt finish})\cr +M-c&continue ({\tt cont})\cr +M-u&up {\it arg} frames ({\tt up})\cr +M-d&down {\it arg} frames ({\tt down})\cr +\ctl{x} \&© number from point, insert at end\cr +\ctl{x} SPC&(in source file) set break at point\cr +\endsec + +\sec GDB License; +show copying&Display GNU General Public License\cr +show warranty&There is NO WARRANTY for GDB. Display full no-warranty +statement.\cr +\endsec + + +\vfill +{\smrm\parskip=6pt +\centerline{Copyright \copyright 1991, 1992, 1993 Free Software Foundation, Inc.} +\centerline{Roland Pesch (pesch@cygnus.com)} +\centerline{The author assumes no responsibility for any errors on this card.} + +This card may be freely distributed under the terms of the GNU +General Public License. + +\centerline{Please contribute to development of this card by +annotating it.} + +GDB itself is free software; you are welcome to distribute copies of +it under the terms of the GNU General Public License. There is +absolutely no warranty for GDB. +} +\end diff --git a/gnu/usr.bin/gdb/doc/remote.texi b/gnu/usr.bin/gdb/doc/remote.texi new file mode 100644 index 00000000000..5b7ec90e1e8 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/remote.texi @@ -0,0 +1,1294 @@ +@c -*- Texinfo -*- +@c Copyright (c) 1990 1991 1992 1993 Free Software Foundation, Inc. +@c This file is part of the source for the GDB manual. +@c This text diverted to "Remote Debugging" section in general case; +@c however, if we're doing a manual specifically for one of these, it +@c belongs up front (in "Getting In and Out" chapter). + +@ifset REMOTESTUB +@node Remote Serial +@subsection The @value{GDBN} remote serial protocol + +@cindex remote serial debugging, overview +To debug a program running on another machine (the debugging +@dfn{target} machine), you must first arrange for all the usual +prerequisites for the program to run by itself. For example, for a C +program, you need + +@enumerate +@item +A startup routine to set up the C runtime environment; these usually +have a name like @file{crt0}. The startup routine may be supplied by +your hardware supplier, or you may have to write your own. + +@item +You probably need a C subroutine library to support your program's +subroutine calls, notably managing input and output. + +@item +A way of getting your program to the other machine---for example, a +download program. These are often supplied by the hardware +manufacturer, but you may have to write your own from hardware +documentation. +@end enumerate + +The next step is to arrange for your program to use a serial port to +communicate with the machine where @value{GDBN} is running (the @dfn{host} +machine). In general terms, the scheme looks like this: + +@table @emph +@item On the host, +@value{GDBN} already understands how to use this protocol; when everything +else is set up, you can simply use the @samp{target remote} command +(@pxref{Targets,,Specifying a Debugging Target}). + +@item On the target, +you must link with your program a few special-purpose subroutines that +implement the @value{GDBN} remote serial protocol. The file containing these +subroutines is called a @dfn{debugging stub}. + +@ifset GDBSERVER +On certain remote targets, you can use an auxiliary program +@code{gdbserver} instead of linking a stub into your program. +@xref{Server,,Using the @code{gdbserver} program}, for details. +@end ifset +@end table + +The debugging stub is specific to the architecture of the remote +machine; for example, use @file{sparc-stub.c} to debug programs on +@sc{sparc} boards. + +@cindex remote serial stub list +These working remote stubs are distributed with @value{GDBN}: + +@table @code +@item sparc-stub.c +@kindex sparc-stub.c +For @sc{sparc} architectures. + +@item m68k-stub.c +@kindex m68k-stub.c +@cindex Motorola 680x0 +@cindex 680x0 +For Motorola 680x0 architectures. + +@item i386-stub.c +@kindex i386-stub.c +@cindex Intel +@cindex 386 +For Intel 386 and compatible architectures. +@end table + +The @file{README} file in the @value{GDBN} distribution may list other +recently added stubs. + +@menu +* Stub Contents:: What the stub can do for you +* Bootstrapping:: What you must do for the stub +* Debug Session:: Putting it all together +* Protocol:: Outline of the communication protocol +@ifset GDBSERVER +* Server:: Using the `gdbserver' program +@end ifset +@end menu + +@node Stub Contents +@subsubsection What the stub can do for you + +@cindex remote serial stub +The debugging stub for your architecture supplies these three +subroutines: + +@table @code +@item set_debug_traps +@kindex set_debug_traps +@cindex remote serial stub, initialization +This routine arranges for @code{handle_exception} to run when your +program stops. You must call this subroutine explicitly near the +beginning of your program. + +@item handle_exception +@kindex handle_exception +@cindex remote serial stub, main routine +This is the central workhorse, but your program never calls it +explicitly---the setup code arranges for @code{handle_exception} to +run when a trap is triggered. + +@code{handle_exception} takes control when your program stops during +execution (for example, on a breakpoint), and mediates communications +with @value{GDBN} on the host machine. This is where the communications +protocol is implemented; @code{handle_exception} acts as the @value{GDBN} +representative on the target machine; it begins by sending summary +information on the state of your program, then continues to execute, +retrieving and transmitting any information @value{GDBN} needs, until you +execute a @value{GDBN} command that makes your program resume; at that point, +@code{handle_exception} returns control to your own code on the target +machine. + +@item breakpoint +@cindex @code{breakpoint} subroutine, remote +Use this auxiliary subroutine to make your program contain a +breakpoint. Depending on the particular situation, this may be the only +way for @value{GDBN} to get control. For instance, if your target +machine has some sort of interrupt button, you won't need to call this; +pressing the interrupt button will transfer control to +@code{handle_exception}---in effect, to @value{GDBN}. On some machines, +simply receiving characters on the serial port may also trigger a trap; +again, in that situation, you don't need to call @code{breakpoint} from +your own program---simply running @samp{target remote} from the host +@value{GDBN} session will get control. + +Call @code{breakpoint} if none of these is true, or if you simply want +to make certain your program stops at a predetermined point for the +start of your debugging session. +@end table + +@node Bootstrapping +@subsubsection What you must do for the stub + +@cindex remote stub, support routines +The debugging stubs that come with @value{GDBN} are set up for a particular +chip architecture, but they have no information about the rest of your +debugging target machine. To allow the stub to work, you must supply +these special low-level subroutines: + +@table @code +@item int getDebugChar() +@kindex getDebugChar +Write this subroutine to read a single character from the serial port. +It may be identical to @code{getchar} for your target system; a +different name is used to allow you to distinguish the two if you wish. + +@item void putDebugChar(int) +@kindex putDebugChar +Write this subroutine to write a single character to the serial port. +It may be identical to @code{putchar} for your target system; a +different name is used to allow you to distinguish the two if you wish. + +@item void exceptionHandler (int @var{exception_number}, void *@var{exception_address}) +@kindex exceptionHandler +Write this function to install @var{exception_address} in the exception +handling tables. You need to do this because the stub does not have any +way of knowing what the exception handling tables on your target system +are like (for example, the processor's table might be in @sc{rom}, +containing entries which point to a table in @sc{ram}). +@var{exception_number} is the exception number which should be changed; +its meaning is architecture-dependent (for example, different numbers +might represent divide by zero, misaligned access, etc). When this +exception occurs, control should be transferred directly to +@var{exception_address}, and the processor state (stack, registers, +etc.) should be just as it is when a processor exception occurs. So if +you want to use a jump instruction to reach @var{exception_address}, it +should be a simple jump, not a jump to subroutine. + +For the 386, @var{exception_address} should be installed as an interrupt +gate so that interrupts are masked while the handler runs. The gate +should be at privilege level 0 (the most privileged level). The +@sc{sparc} and 68k stubs are able to mask interrupts themself without +help from @code{exceptionHandler}. + +@item void flush_i_cache() +@kindex flush_i_cache +Write this subroutine to flush the instruction cache, if any, on your +target machine. If there is no instruction cache, this subroutine may +be a no-op. + +On target machines that have instruction caches, @value{GDBN} requires this +function to make certain that the state of your program is stable. +@end table + +@noindent +You must also make sure this library routine is available: + +@table @code +@item void *memset(void *, int, int) +@kindex memset +This is the standard library function @code{memset} that sets an area of +memory to a known value. If you have one of the free versions of +@code{libc.a}, @code{memset} can be found there; otherwise, you must +either obtain it from your hardware manufacturer, or write your own. +@end table + +If you do not use the GNU C compiler, you may need other standard +library subroutines as well; this will vary from one stub to another, +but in general the stubs are likely to use any of the common library +subroutines which @code{gcc} generates as inline code. + + +@node Debug Session +@subsubsection Putting it all together + +@cindex remote serial debugging summary +In summary, when your program is ready to debug, you must follow these +steps. + +@enumerate +@item +Make sure you have the supporting low-level routines +(@pxref{Bootstrapping,,What you must do for the stub}): +@display +@code{getDebugChar}, @code{putDebugChar}, +@code{flush_i_cache}, @code{memset}, @code{exceptionHandler}. +@end display + +@item +Insert these lines near the top of your program: + +@example +set_debug_traps(); +breakpoint(); +@end example + +@item +For the 680x0 stub only, you need to provide a variable called +@code{exceptionHook}. Normally you just use + +@example +void (*exceptionHook)() = 0; +@end example + +but if before calling @code{set_debug_traps}, you set it to point to a +function in your program, that function is called when +@code{@value{GDBN}} continues after stopping on a trap (for example, bus +error). The function indicated by @code{exceptionHook} is called with +one parameter: an @code{int} which is the exception number. + +@item +Compile and link together: your program, the @value{GDBN} debugging stub for +your target architecture, and the supporting subroutines. + +@item +Make sure you have a serial connection between your target machine and +the @value{GDBN} host, and identify the serial port used for this on the host. + +@item +@c The "remote" target now provides a `load' command, so we should +@c document that. FIXME. +Download your program to your target machine (or get it there by +whatever means the manufacturer provides), and start it. + +@item +To start remote debugging, run @value{GDBN} on the host machine, and specify +as an executable file the program that is running in the remote machine. +This tells @value{GDBN} how to find your program's symbols and the contents +of its pure text. + +@cindex serial line, @code{target remote} +Then establish communication using the @code{target remote} command. +Its argument specifies how to communicate with the target +machine---either via a devicename attached to a direct serial line, or a +TCP port (usually to a terminal server which in turn has a serial line +to the target). For example, to use a serial line connected to the +device named @file{/dev/ttyb}: + +@example +target remote /dev/ttyb +@end example + +@cindex TCP port, @code{target remote} +To use a TCP connection, use an argument of the form +@code{@var{host}:port}. For example, to connect to port 2828 on a +terminal server named @code{manyfarms}: + +@example +target remote manyfarms:2828 +@end example +@end enumerate + +Now you can use all the usual commands to examine and change data and to +step and continue the remote program. + +To resume the remote program and stop debugging it, use the @code{detach} +command. + +@cindex interrupting remote programs +@cindex remote programs, interrupting +Whenever @value{GDBN} is waiting for the remote program, if you type the +interrupt character (often @key{C-C}), @value{GDBN} attempts to stop the +program. This may or may not succeed, depending in part on the hardware +and the serial drivers the remote system uses. If you type the +interrupt character once again, @value{GDBN} displays this prompt: + +@example +Interrupted while waiting for the program. +Give up (and stop debugging it)? (y or n) +@end example + +If you type @kbd{y}, @value{GDBN} abandons the remote debugging session. +(If you decide you want to try again later, you can use @samp{target +remote} again to connect once more.) If you type @kbd{n}, @value{GDBN} +goes back to waiting. + +@node Protocol +@subsubsection Outline of the communication protocol + +@cindex debugging stub, example +@cindex remote stub, example +@cindex stub example, remote debugging +The stub files provided with @value{GDBN} implement the target side of the +communication protocol, and the @value{GDBN} side is implemented in the +@value{GDBN} source file @file{remote.c}. Normally, you can simply allow +these subroutines to communicate, and ignore the details. (If you're +implementing your own stub file, you can still ignore the details: start +with one of the existing stub files. @file{sparc-stub.c} is the best +organized, and therefore the easiest to read.) + +However, there may be occasions when you need to know something about +the protocol---for example, if there is only one serial port to your +target machine, you might want your program to do something special if +it recognizes a packet meant for @value{GDBN}. + +@cindex protocol, @value{GDBN} remote serial +@cindex serial protocol, @value{GDBN} remote +@cindex remote serial protocol +All @value{GDBN} commands and responses (other than acknowledgements, which +are single characters) are sent as a packet which includes a +checksum. A packet is introduced with the character @samp{$}, and ends +with the character @samp{#} followed by a two-digit checksum: + +@example +$@var{packet info}#@var{checksum} +@end example + +@cindex checksum, for @value{GDBN} remote +@noindent +@var{checksum} is computed as the modulo 256 sum of the @var{packet +info} characters. + +When either the host or the target machine receives a packet, the first +response expected is an acknowledgement: a single character, either +@samp{+} (to indicate the package was received correctly) or @samp{-} +(to request retransmission). + +The host (@value{GDBN}) sends commands, and the target (the debugging stub +incorporated in your program) sends data in response. The target also +sends data when your program stops. + +Command packets are distinguished by their first character, which +identifies the kind of command. + +These are the commands currently supported: + +@table @code +@item g +Requests the values of CPU registers. + +@item G +Sets the values of CPU registers. + +@item m@var{addr},@var{count} +Read @var{count} bytes at location @var{addr}. + +@item M@var{addr},@var{count}:@dots{} +Write @var{count} bytes at location @var{addr}. + +@item c +@itemx c@var{addr} +Resume execution at the current address (or at @var{addr} if supplied). + +@item s +@itemx s@var{addr} +Step the target program for one instruction, from either the current +program counter or from @var{addr} if supplied. + +@item k +Kill the target program. + +@item ? +Report the most recent signal. To allow you to take advantage of the +@value{GDBN} signal handling commands, one of the functions of the debugging +stub is to report CPU traps as the corresponding POSIX signal values. +@end table + +@kindex set remotedebug +@kindex show remotedebug +@cindex packets, reporting on stdout +@cindex serial connections, debugging +If you have trouble with the serial connection, you can use the command +@code{set remotedebug}. This makes @value{GDBN} report on all packets sent +back and forth across the serial line to the remote machine. The +packet-debugging information is printed on the @value{GDBN} standard output +stream. @code{set remotedebug off} turns it off, and @code{show +remotedebug} will show you its current state. + +@ifset GDBSERVER +@node Server +@subsubsection Using the @code{gdbserver} program + +@kindex gdbserver +@cindex remote connection without stubs +@code{gdbserver} is a control program for Unix-like systems, which +allows you to connect your program with a remote @value{GDBN} via +@code{target remote}---but without linking in the usual debugging stub. + +@code{gdbserver} is not a complete replacement for the debugging stubs, +because it requires essentially the same operating-system facilities +that @value{GDBN} itself does. In fact, a system that can run +@code{gdbserver} to connect to a remote @value{GDBN} could also run +@var{GDBN} locally! @code{gdbserver} is sometimes useful nevertheless, +because it is a much smaller program than @value{GDBN} itself. It is +also easier to port than all of @var{GDBN}, so you may be able to get +started more quickly on a new system by using @code{gdbserver}. + +@value{GDBN} and @code{gdbserver} communicate via either a serial line +or a TCP connection, using the standard @value{GDBN} remote serial +protocol. + +@table @emph +@item On the target, +you need to have a copy of the program you want to debug. +@code{gdbserver} does not need your program's symbol table, so you can +strip the program if necessary to save space. @value{GDBN} on the host +system does all the symbol handling. + +To use the server, you must tell it how to communicate with @value{GDB}; +the name of your program; and the arguments for your program. The +syntax is: + +@smallexample +target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ] +@end smallexample + +@var{comm} is either a device name (to use a serial line) or a TCP +hostname and portnumber. For example, to debug emacs with the argument +@samp{foo.txt} and communicate with @value{GDBN} over the serial port +@file{/dev/com1}: + +@smallexample +target> gdbserver /dev/com1 emacs foo.txt +@end smallexample + +@code{gdbserver} waits passively for the host @value{GDBN} to communicate +with it. + +To use a TCP connection instead of a serial line: + +@smallexample +target> gdbserver host:2345 emacs foo.txt +@end smallexample + +The only difference from the previous example is the first argument, +specifying that you are communicating with the host @value{GDBN} via +TCP. The @samp{host:2345} argument means that @code{gdbserver} is to +expect a TCP connection from machine @samp{host} to local TCP port 2345. +(Currently, the @samp{host} part is ignored.) You can choose any number +you want for the port number as long as it does not conflict with any +TCP ports already in use on the target system.@footnote{If you choose a +port number that conflicts with another service, @code{gdbserver} prints +an error message and exits.} You must use the same port number with the +host @value{GDBN} @code{target remote} command. + +@item On the host, +you need an unstripped copy of your program, since +@value{GDBN} needs symbols and debugging information. Start up +@value{GDBN} as usual, using the name of the local copy of your program +as the first argument. (You may also need the +@samp{--baud} option if the serial line is running at anything other than 9600 bps.) +After that, use @code{target remote} to establish communications with @code{gdbserver}. Its argument is either +a device name (usually a serial device, like @file{/dev/ttyb}), or a TCP +port descriptof in the form @code{@var{host}:@var{PORT}}. For example: + +@smallexample +(@value{GDBP}) target remote /dev/ttyb +@end smallexample + +@noindent +communicates with the server via serial line @file{/dev/ttyb}, and + +@smallexample +(@value{GDBP}) target remote the-target:2345 +@end smallexample + +@noindent +communicates via a TCP connection to port 2345 on host @file{the-target}. +For TCP connections, you must start up @code{gdbserver} prior to using +the @code{target remote} command. Otherwise you may get an error whose +text depends on the host system, but which usually looks something like +@samp{Connection refused}. +@end table +@end ifset + +@end ifset + +@ifset I960 +@node i960-Nindy Remote +@subsection @value{GDBN} with a remote i960 (Nindy) + +@cindex Nindy +@cindex i960 +@dfn{Nindy} is a ROM Monitor program for Intel 960 target systems. When +@value{GDBN} is configured to control a remote Intel 960 using Nindy, you can +tell @value{GDBN} how to connect to the 960 in several ways: + +@itemize @bullet +@item +Through command line options specifying serial port, version of the +Nindy protocol, and communications speed; + +@item +By responding to a prompt on startup; + +@item +By using the @code{target} command at any point during your @value{GDBN} +session. @xref{Target Commands, ,Commands for managing targets}. + +@end itemize + +@menu +* Nindy Startup:: Startup with Nindy +* Nindy Options:: Options for Nindy +* Nindy Reset:: Nindy reset command +@end menu + +@node Nindy Startup +@subsubsection Startup with Nindy + +If you simply start @code{@value{GDBP}} without using any command-line +options, you are prompted for what serial port to use, @emph{before} you +reach the ordinary @value{GDBN} prompt: + +@example +Attach /dev/ttyNN -- specify NN, or "quit" to quit: +@end example + +@noindent +Respond to the prompt with whatever suffix (after @samp{/dev/tty}) +identifies the serial port you want to use. You can, if you choose, +simply start up with no Nindy connection by responding to the prompt +with an empty line. If you do this and later wish to attach to Nindy, +use @code{target} (@pxref{Target Commands, ,Commands for managing targets}). + +@node Nindy Options +@subsubsection Options for Nindy + +These are the startup options for beginning your @value{GDBN} session with a +Nindy-960 board attached: + +@table @code +@item -r @var{port} +Specify the serial port name of a serial interface to be used to connect +to the target system. This option is only available when @value{GDBN} is +configured for the Intel 960 target architecture. You may specify +@var{port} as any of: a full pathname (e.g. @samp{-r /dev/ttya}), a +device name in @file{/dev} (e.g. @samp{-r ttya}), or simply the unique +suffix for a specific @code{tty} (e.g. @samp{-r a}). + +@item -O +(An uppercase letter ``O'', not a zero.) Specify that @value{GDBN} should use +the ``old'' Nindy monitor protocol to connect to the target system. +This option is only available when @value{GDBN} is configured for the Intel 960 +target architecture. + +@quotation +@emph{Warning:} if you specify @samp{-O}, but are actually trying to +connect to a target system that expects the newer protocol, the connection +fails, appearing to be a speed mismatch. @value{GDBN} repeatedly +attempts to reconnect at several different line speeds. You can abort +this process with an interrupt. +@end quotation + +@item -brk +Specify that @value{GDBN} should first send a @code{BREAK} signal to the target +system, in an attempt to reset it, before connecting to a Nindy target. + +@quotation +@emph{Warning:} Many target systems do not have the hardware that this +requires; it only works with a few boards. +@end quotation +@end table + +The standard @samp{-b} option controls the line speed used on the serial +port. + +@c @group +@node Nindy Reset +@subsubsection Nindy reset command + +@table @code +@item reset +@kindex reset +For a Nindy target, this command sends a ``break'' to the remote target +system; this is only useful if the target has been equipped with a +circuit to perform a hard reset (or some other interesting action) when +a break is detected. +@end table +@c @end group +@end ifset + +@ifset AMD29K +@node UDI29K Remote +@subsection @value{GDBN} and the UDI protocol for AMD29K + +@cindex UDI +@cindex AMD29K via UDI +@value{GDBN} supports AMD's UDI (``Universal Debugger Interface'') +protocol for debugging the a29k processor family. To use this +configuration with AMD targets running the MiniMON monitor, you need the +program @code{MONTIP}, available from AMD at no charge. You can also +use @value{GDBN} with the UDI conformant a29k simulator program +@code{ISSTIP}, also available from AMD. + +@table @code +@item target udi @var{keyword} +@kindex udi +Select the UDI interface to a remote a29k board or simulator, where +@var{keyword} is an entry in the AMD configuration file @file{udi_soc}. +This file contains keyword entries which specify parameters used to +connect to a29k targets. If the @file{udi_soc} file is not in your +working directory, you must set the environment variable @samp{UDICONF} +to its pathname. +@end table + +@node EB29K Remote +@subsection @value{GDBN} and the EBMON protocol for AMD29K + +@cindex EB29K board +@cindex running 29K programs + +AMD distributes a 29K development board meant to fit in a PC, together +with a DOS-hosted monitor program called @code{EBMON}. As a shorthand +term, this development system is called the ``EB29K''. To use +@value{GDBN} from a Unix system to run programs on the EB29K board, you +must first connect a serial cable between the PC (which hosts the EB29K +board) and a serial port on the Unix system. In the following, we +assume you've hooked the cable between the PC's @file{COM1} port and +@file{/dev/ttya} on the Unix system. + +@menu +* Comms (EB29K):: Communications setup +* gdb-EB29K:: EB29K cross-debugging +* Remote Log:: Remote log +@end menu + +@node Comms (EB29K) +@subsubsection Communications setup + +The next step is to set up the PC's port, by doing something like this +in DOS on the PC: + +@example +C:\> MODE com1:9600,n,8,1,none +@end example + +@noindent +This example---run on an MS DOS 4.0 system---sets the PC port to 9600 +bps, no parity, eight data bits, one stop bit, and no ``retry'' action; +you must match the communications parameters when establishing the Unix +end of the connection as well. +@c FIXME: Who knows what this "no retry action" crud from the DOS manual may +@c mean? It's optional; leave it out? ---pesch@cygnus.com, 25feb91 + +To give control of the PC to the Unix side of the serial line, type +the following at the DOS console: + +@example +C:\> CTTY com1 +@end example + +@noindent +(Later, if you wish to return control to the DOS console, you can use +the command @code{CTTY con}---but you must send it over the device that +had control, in our example over the @file{COM1} serial line). + +From the Unix host, use a communications program such as @code{tip} or +@code{cu} to communicate with the PC; for example, + +@example +cu -s 9600 -l /dev/ttya +@end example + +@noindent +The @code{cu} options shown specify, respectively, the linespeed and the +serial port to use. If you use @code{tip} instead, your command line +may look something like the following: + +@example +tip -9600 /dev/ttya +@end example + +@noindent +Your system may require a different name where we show +@file{/dev/ttya} as the argument to @code{tip}. The communications +parameters, including which port to use, are associated with the +@code{tip} argument in the ``remote'' descriptions file---normally the +system table @file{/etc/remote}. +@c FIXME: What if anything needs doing to match the "n,8,1,none" part of +@c the DOS side's comms setup? cu can support -o (odd +@c parity), -e (even parity)---apparently no settings for no parity or +@c for character size. Taken from stty maybe...? John points out tip +@c can set these as internal variables, eg ~s parity=none; man stty +@c suggests that it *might* work to stty these options with stdin or +@c stdout redirected... ---pesch@cygnus.com, 25feb91 + +@kindex EBMON +Using the @code{tip} or @code{cu} connection, change the DOS working +directory to the directory containing a copy of your 29K program, then +start the PC program @code{EBMON} (an EB29K control program supplied +with your board by AMD). You should see an initial display from +@code{EBMON} similar to the one that follows, ending with the +@code{EBMON} prompt @samp{#}--- + +@example +C:\> G: + +G:\> CD \usr\joe\work29k + +G:\USR\JOE\WORK29K> EBMON +Am29000 PC Coprocessor Board Monitor, version 3.0-18 +Copyright 1990 Advanced Micro Devices, Inc. +Written by Gibbons and Associates, Inc. + +Enter '?' or 'H' for help + +PC Coprocessor Type = EB29K +I/O Base = 0x208 +Memory Base = 0xd0000 + +Data Memory Size = 2048KB +Available I-RAM Range = 0x8000 to 0x1fffff +Available D-RAM Range = 0x80002000 to 0x801fffff + +PageSize = 0x400 +Register Stack Size = 0x800 +Memory Stack Size = 0x1800 + +CPU PRL = 0x3 +Am29027 Available = No +Byte Write Available = Yes + +# ~. +@end example + +Then exit the @code{cu} or @code{tip} program (done in the example by +typing @code{~.} at the @code{EBMON} prompt). @code{EBMON} will keep +running, ready for @value{GDBN} to take over. + +For this example, we've assumed what is probably the most convenient +way to make sure the same 29K program is on both the PC and the Unix +system: a PC/NFS connection that establishes ``drive @code{G:}'' on the +PC as a file system on the Unix host. If you do not have PC/NFS or +something similar connecting the two systems, you must arrange some +other way---perhaps floppy-disk transfer---of getting the 29K program +from the Unix system to the PC; @value{GDBN} will @emph{not} download it over the +serial line. + +@node gdb-EB29K +@subsubsection EB29K cross-debugging + +Finally, @code{cd} to the directory containing an image of your 29K +program on the Unix system, and start @value{GDBN}---specifying as argument the +name of your 29K program: + +@example +cd /usr/joe/work29k +@value{GDBP} myfoo +@end example + +Now you can use the @code{target} command: + +@example +target amd-eb /dev/ttya 9600 MYFOO +@c FIXME: test above 'target amd-eb' as spelled, with caps! caps are meant to +@c emphasize that this is the name as seen by DOS (since I think DOS is +@c single-minded about case of letters). ---pesch@cygnus.com, 25feb91 +@end example + +@noindent +In this example, we've assumed your program is in a file called +@file{myfoo}. Note that the filename given as the last argument to +@code{target amd-eb} should be the name of the program as it appears to DOS. +In our example this is simply @code{MYFOO}, but in general it can include +a DOS path, and depending on your transfer mechanism may not resemble +the name on the Unix side. + +At this point, you can set any breakpoints you wish; when you are ready +to see your program run on the 29K board, use the @value{GDBN} command +@code{run}. + +To stop debugging the remote program, use the @value{GDBN} @code{detach} +command. + +To return control of the PC to its console, use @code{tip} or @code{cu} +once again, after your @value{GDBN} session has concluded, to attach to +@code{EBMON}. You can then type the command @code{q} to shut down +@code{EBMON}, returning control to the DOS command-line interpreter. +Type @code{CTTY con} to return command input to the main DOS console, +and type @kbd{~.} to leave @code{tip} or @code{cu}. + +@node Remote Log +@subsubsection Remote log +@kindex eb.log +@cindex log file for EB29K + +The @code{target amd-eb} command creates a file @file{eb.log} in the +current working directory, to help debug problems with the connection. +@file{eb.log} records all the output from @code{EBMON}, including echoes +of the commands sent to it. Running @samp{tail -f} on this file in +another window often helps to understand trouble with @code{EBMON}, or +unexpected events on the PC side of the connection. + +@end ifset + +@ifset ST2000 +@node ST2000 Remote +@subsection @value{GDBN} with a Tandem ST2000 + +To connect your ST2000 to the host system, see the manufacturer's +manual. Once the ST2000 is physically attached, you can run + +@example +target st2000 @var{dev} @var{speed} +@end example + +@noindent +to establish it as your debugging environment. @var{dev} is normally +the name of a serial device, such as @file{/dev/ttya}, connected to the +ST2000 via a serial line. You can instead specify @var{dev} as a TCP +connection (for example, to a serial line attached via a terminal +concentrator) using the syntax @code{@var{hostname}:@var{portnumber}}. + +The @code{load} and @code{attach} commands are @emph{not} defined for +this target; you must load your program into the ST2000 as you normally +would for standalone operation. @value{GDBN} will read debugging information +(such as symbols) from a separate, debugging version of the program +available on your host computer. +@c FIXME!! This is terribly vague; what little content is here is +@c basically hearsay. + +@cindex ST2000 auxiliary commands +These auxiliary @value{GDBN} commands are available to help you with the ST2000 +environment: + +@table @code +@item st2000 @var{command} +@kindex st2000 @var{cmd} +@cindex STDBUG commands (ST2000) +@cindex commands to STDBUG (ST2000) +Send a @var{command} to the STDBUG monitor. See the manufacturer's +manual for available commands. + +@item connect +@cindex connect (to STDBUG) +Connect the controlling terminal to the STDBUG command monitor. When +you are done interacting with STDBUG, typing either of two character +sequences will get you back to the @value{GDBN} command prompt: +@kbd{@key{RET}~.} (Return, followed by tilde and period) or +@kbd{@key{RET}~@key{C-d}} (Return, followed by tilde and control-D). +@end table +@end ifset + +@ifset VXWORKS +@node VxWorks Remote +@subsection @value{GDBN} and VxWorks +@cindex VxWorks + +@value{GDBN} enables developers to spawn and debug tasks running on networked +VxWorks targets from a Unix host. Already-running tasks spawned from +the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on +both the Unix host and on the VxWorks target. The program +@code{gdb} is installed and executed on the Unix host. (It may be +installed with the name @code{vxgdb}, to distinguish it from a +@value{GDBN} for debugging programs on the host itself.) + +The following information on connecting to VxWorks was current when +this manual was produced; newer releases of VxWorks may use revised +procedures. + +The remote debugging interface (RDB) routines are installed and executed +on the VxWorks target. These routines are included in the VxWorks library +@file{rdb.a} and are incorporated into the system image when source-level +debugging is enabled in the VxWorks configuration. + +@kindex INCLUDE_RDB +If you wish, you can define @code{INCLUDE_RDB} in the VxWorks +configuration file @file{configAll.h} to include the RDB interface +routines and spawn the source debugging task @code{tRdbTask} when +VxWorks is booted. For more information on configuring and remaking +VxWorks, see the manufacturer's manual. +@c VxWorks, see the @cite{VxWorks Programmer's Guide}. + +Once you have included the RDB interface in your VxWorks system image +and set your Unix execution search path to find @value{GDBN}, you are ready +to run @value{GDBN}. From your Unix host, run @code{gdb} (or +@code{vxgdb}, depending on your installation). + +@value{GDBN} comes up showing the prompt: + +@example +(vxgdb) +@end example + +@menu +* VxWorks Connection:: Connecting to VxWorks +* VxWorks Download:: VxWorks download +* VxWorks Attach:: Running tasks +@end menu + +@node VxWorks Connection +@subsubsection Connecting to VxWorks + +The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the +network. To connect to a target whose host name is ``@code{tt}'', type: + +@example +(vxgdb) target vxworks tt +@end example + +@value{GDBN} displays messages like these: + +@smallexample +Attaching remote machine across net... +Connected to tt. +@end smallexample + +@value{GDBN} then attempts to read the symbol tables of any object modules +loaded into the VxWorks target since it was last booted. @value{GDBN} locates +these files by searching the directories listed in the command search +path (@pxref{Environment, ,Your program's environment}); if it fails +to find an object file, it displays a message such as: + +@example +prog.o: No such file or directory. +@end example + +When this happens, add the appropriate directory to the search path with +the @value{GDBN} command @code{path}, and execute the @code{target} +command again. + +@node VxWorks Download +@subsubsection VxWorks download + +@cindex download to VxWorks +If you have connected to the VxWorks target and you want to debug an +object that has not yet been loaded, you can use the @value{GDBN} +@code{load} command to download a file from Unix to VxWorks +incrementally. The object file given as an argument to the @code{load} +command is actually opened twice: first by the VxWorks target in order +to download the code, then by @value{GDBN} in order to read the symbol +table. This can lead to problems if the current working directories on +the two systems differ. If both systems have NFS mounted the same +filesystems, you can avoid these problems by using absolute paths. +Otherwise, it is simplest to set the working directory on both systems +to the directory in which the object file resides, and then to reference +the file by its name, without any path. For instance, a program +@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks +and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this +program, type this on VxWorks: + +@example +-> cd "@var{vxpath}/vw/demo/rdb" +@end example + +Then, in @value{GDBN}, type: + +@example +(vxgdb) cd @var{hostpath}/vw/demo/rdb +(vxgdb) load prog.o +@end example + +@value{GDBN} displays a response similar to this: + +@smallexample +Reading symbol data from wherever/vw/demo/rdb/prog.o... done. +@end smallexample + +You can also use the @code{load} command to reload an object module +after editing and recompiling the corresponding source file. Note that +this will cause @value{GDBN} to delete all currently-defined breakpoints, +auto-displays, and convenience variables, and to clear the value +history. (This is necessary in order to preserve the integrity of +debugger data structures that reference the target system's symbol +table.) + +@node VxWorks Attach +@subsubsection Running tasks + +@cindex running VxWorks tasks +You can also attach to an existing task using the @code{attach} command as +follows: + +@example +(vxgdb) attach @var{task} +@end example + +@noindent +where @var{task} is the VxWorks hexadecimal task ID. The task can be running +or suspended when you attach to it. If running, it will be suspended at +the time of attachment. +@end ifset + +@ifset H8 +@node Hitachi Remote +@subsection @value{GDBN} and Hitachi Microprocessors +@value{GDBN} needs to know these things to talk to your +Hitachi SH, H8/300, or H8/500: + +@enumerate +@item +that you want to use @samp{target hms}, the remote debugging interface +for Hitachi microprocessors (this is the default when GDB is configured +specifically for the Hitachi SH, H8/300, or H8/500); + +@item +what serial device connects your host to your Hitachi board (the first +serial device available on your host is the default); + +@ignore +@c this is only for Unix hosts, not currently of interest. +@item +what speed to use over the serial device. +@end ignore +@end enumerate + +@ifclear H8EXCLUSIVE +@c only for Unix hosts +@kindex device +@cindex serial device, Hitachi micros +Use the special @code{@value{GDBP}} command @samp{device @var{port}} if you +need to explicitly set the serial device. The default @var{port} is the +first available port on your host. This is only necessary on Unix +hosts, where it is typically something like @file{/dev/ttya}. + +@kindex speed +@cindex serial line speed, Hitachi micros +@code{@value{GDBP}} has another special command to set the communications +speed: @samp{speed @var{bps}}. This command also is only used from Unix +hosts; on DOS hosts, set the line speed as usual from outside GDB with +the DOS @kbd{mode} command (for instance, @w{@samp{mode +com2:9600,n,8,1,p}} for a 9600 bps connection). + +The @samp{device} and @samp{speed} commands are available only when you +use a Unix host to debug your Hitachi microprocessor programs. If you +use a DOS host, +@end ifclear +@value{GDBN} depends on an auxiliary terminate-and-stay-resident program +called @code{asynctsr} to communicate with the development board +through a PC serial port. You must also use the DOS @code{mode} command +to set up the serial port on the DOS side. + +@ifset DOSHOST +The following sample session illustrates the steps needed to start a +program under @value{GDBN} control on an H8/300. The example uses a +sample H8/300 program called @file{t.x}. The procedure is the same for +the Hitachi SH and the H8/500. + +First hook up your development board. In this example, we use a +board attached to serial port @code{COM2}; if you use a different serial +port, substitute its name in the argument of the @code{mode} command. +When you call @code{asynctsr}, the auxiliary comms program used by the +degugger, you give it just the numeric part of the serial port's name; +for example, @samp{asyncstr 2} below runs @code{asyncstr} on +@code{COM2}. + +@example +(eg-C:\H8300\TEST) mode com2:9600,n,8,1,p + +Resident portion of MODE loaded + +COM2: 9600, n, 8, 1, p + +(eg-C:\H8300\TEST) asynctsr 2 +@end example + +@quotation +@emph{Warning:} We have noticed a bug in PC-NFS that conflicts with +@code{asynctsr}. If you also run PC-NFS on your DOS host, you may need to +disable it, or even boot without it, to use @code{asynctsr} to control +your development board. +@end quotation + +@kindex target hms +Now that serial communications are set up, and the development board is +connected, you can start up @value{GDBN}. Call @code{@value{GDBP}} with +the name of your program as the argument. @code{@value{GDBP}} prompts +you, as usual, with the prompt @samp{(@value{GDBP})}. Use two special +commands to begin your debugging session: @samp{target hms} to specify +cross-debugging to the Hitachi board, and the @code{load} command to +download your program to the board. @code{load} displays the names of +the program's sections, and a @samp{*} for each 2K of data downloaded. +(If you want to refresh @value{GDBN} data on symbols or on the +executable file without downloading, use the @value{GDBN} commands +@code{file} or @code{symbol-file}. These commands, and @code{load} +itself, are described in @ref{Files,,Commands to specify files}.) + +@smallexample +(eg-C:\H8300\TEST) @value{GDBP} t.x +GDB is free software and you are welcome to distribute copies + of it under certain conditions; type "show copying" to see + the conditions. +There is absolutely no warranty for GDB; type "show warranty" +for details. +GDB @value{GDBVN}, Copyright 1992 Free Software Foundation, Inc... +(gdb) target hms +Connected to remote H8/300 HMS system. +(gdb) load t.x +.text : 0x8000 .. 0xabde *********** +.data : 0xabde .. 0xad30 * +.stack : 0xf000 .. 0xf014 * +@end smallexample + +At this point, you're ready to run or debug your program. From here on, +you can use all the usual @value{GDBN} commands. The @code{break} command +sets breakpoints; the @code{run} command starts your program; +@code{print} or @code{x} display data; the @code{continue} command +resumes execution after stopping at a breakpoint. You can use the +@code{help} command at any time to find out more about @value{GDBN} commands. + +Remember, however, that @emph{operating system} facilities aren't +available on your development board; for example, if your program hangs, +you can't send an interrupt---but you can press the @sc{reset} switch! + +Use the @sc{reset} button on the development board +@itemize @bullet +@item +to interrupt your program (don't use @kbd{ctl-C} on the DOS host---it has +no way to pass an interrupt signal to the development board); and + +@item +to return to the @value{GDBN} command prompt after your program finishes +normally. The communications protocol provides no other way for @value{GDBN} +to detect program completion. +@end itemize + +In either case, @value{GDBN} will see the effect of a @sc{reset} on the +development board as a ``normal exit'' of your program. +@end ifset +@end ifset + +@ifset MIPS +@node MIPS Remote +@subsection @value{GDBN} and remote MIPS boards + +@cindex MIPS boards +@value{GDBN} can use the MIPS remote debugging protocol to talk to a +MIPS board attached to a serial line. This is available when +you configure @value{GDBN} with @samp{--target=mips-idt-ecoff}. + +@kindex target mips @var{port} +To run a program on the board, start up @code{@value{GDBP}} with the +name of your program as the argument. To connect to the board, use the +command @samp{target mips @var{port}}, where @var{port} is the name of +the serial port connected to the board. If the program has not already +been downloaded to the board, you may use the @code{load} command to +download it. You can then use all the usual @value{GDBN} commands. + +You can also specify @var{port} as a TCP connection (for instance, to a +serial line managed by a terminal concentrator), using the syntax +@code{@var{hostname}:@var{portnumber}}. + +@cindex @code{remotedebug}, MIPS protocol +@c FIXME! For this to be useful, you must know something about the MIPS +@c FIXME...protocol. Where is it described? +You can see some debugging information about communications with the board +by setting the @code{remotedebug} variable. If you set it to 1 using +@samp{set remotedebug 1} every packet will be displayed. If you set it +to 2 every character will be displayed. You can check the current value +at any time with the command @samp{show remotedebug}. + +@cindex @code{timeout}, MIPS protocol +@cindex @code{retransmit-timeout}, MIPS protocol +@kindex set timeout +@kindex show timeout +@kindex set retransmit-timeout +@kindex show retransmit-timeout +You can control the timeout used while waiting for a packet, in the MIPS +remote protocol, with the @code{set timeout @var{seconds}} command. The +default is 5 seconds. Similarly, you can control the timeout used while +waiting for an acknowledgement of a packet with the @code{set +retransmit-timeout @var{seconds}} command. The default is 3 seconds. +You can inspect both values with @code{show timeout} and @code{show +retransmit-timeout}. (These commands are @emph{only} available when +@value{GDBN} is configured for @samp{--target=mips-idt-ecoff}.) + +@kindex set mipsfpu off +@cindex MIPS remote floating point +@cindex floating point, MIPS remote +If your target board does not support the MIPS floating point +coprocessor, you should use the command @samp{set mipsfpu off} (you may +wish to put this in your @value{GDBINIT} file). This tells @value{GDBN} +how to find the return value of functions which return floating point +values. It also allows @value{GDBN} to avoid saving the floating point +registers when calling functions on the board. +@end ifset + +@ifset SIMS +@node Simulator +@subsection Simulated CPU target + +@ifset GENERIC +@cindex simulator +@cindex simulator, Z8000 +@cindex Z8000 simulator +@cindex simulator, H8/300 or H8/500 +@cindex H8/300 or H8/500 simulator +@cindex simulator, Hitachi SH +@cindex Hitachi SH simulator +@cindex CPU simulator +For some configurations, @value{GDBN} includes a CPU simulator that you +can use instead of a hardware CPU to debug your programs. Currently, +a simulator is available when @value{GDBN} is configured to debug Zilog +Z8000 or Hitachi microprocessor targets. +@end ifset + +@ifclear GENERIC +@ifset H8 +@cindex simulator, H8/300 or H8/500 +@cindex Hitachi H8/300 or H8/500 simulator +@cindex simulator, Hitachi SH +@cindex Hitachi SH simulator +When configured for debugging Hitachi microprocessor targets, +@value{GDBN} includes a CPU simulator for the target chip (a Hitachi SH, +H8/300, or H8/500). +@end ifset + +@ifset Z8K +@cindex simulator, Z8000 +@cindex Zilog Z8000 simulator +When configured for debugging Zilog Z8000 targets, @value{GDBN} includes +a Z8000 simulator. +@end ifset +@end ifclear + +@ifset Z8K +For the Z8000 family, @samp{target sim} simulates either the Z8002 (the +unsegmented variant of the Z8000 architecture) or the Z8001 (the +segmented variant). The simulator recognizes which architecture is +appropriate by inspecting the object code. +@end ifset + +@table @code +@item target sim +@kindex sim +@kindex target sim +Debug programs on a simulated CPU +@ifset GENERIC +(which CPU depends on the @value{GDBN} configuration) +@end ifset +@end table + +@noindent +After specifying this target, you can debug programs for the simulated +CPU in the same style as programs for your host computer; use the +@code{file} command to load a new program image, the @code{run} command +to run your program, and so on. + +As well as making available all the usual machine registers (see +@code{info reg}), this debugging target provides three additional items +of information as specially named registers: + +@table @code +@item cycles +Counts clock-ticks in the simulator. + +@item insts +Counts instructions run in the simulator. + +@item time +Execution time in 60ths of a second. +@end table + +You can refer to these values in @value{GDBN} expressions with the usual +conventions; for example, @w{@samp{b fputc if $cycles>5000}} sets a +conditional breakpoint that will suspend only after at least 5000 +simulated clock ticks. +@end ifset diff --git a/gnu/usr.bin/gdb/doc/stabs.texinfo b/gnu/usr.bin/gdb/doc/stabs.texinfo new file mode 100644 index 00000000000..23d8e7baa99 --- /dev/null +++ b/gnu/usr.bin/gdb/doc/stabs.texinfo @@ -0,0 +1,3795 @@ +\input texinfo +@setfilename stabs.info + +@c @finalout + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Stabs:: The "stabs" debugging information format. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This document describes the stabs debugging symbol tables. + +Copyright 1992, 1993 Free Software Foundation, Inc. +Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon, +and David MacKenzie. + +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. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy or distribute modified versions of this +manual under the terms of the GPL (for which purpose this text may be +regarded as a program in the language TeX). +@end ifinfo + +@setchapternewpage odd +@settitle STABS +@titlepage +@title The ``stabs'' debug format +@author Julia Menapace, Jim Kingdon, David MacKenzie +@author Cygnus Support +@page +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 1.1.1.1 $} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc. +Contributed by Cygnus Support. + +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. + +@end titlepage + +@ifinfo +@node Top +@top The "stabs" representation of debugging information + +This document describes the stabs debugging format. + +@menu +* Overview:: Overview of stabs +* Program Structure:: Encoding of the structure of the program +* Constants:: Constants +* Variables:: +* Types:: Type definitions +* Symbol Tables:: Symbol information in symbol tables +* Cplusplus:: Appendixes: +* Stab Types:: Symbol types in a.out files +* Symbol Descriptors:: Table of symbol descriptors +* Type Descriptors:: Table of type descriptors +* Expanded Reference:: Reference information by stab type +* Questions:: Questions and anomolies +* XCOFF Differences:: Differences between GNU stabs in a.out + and GNU stabs in XCOFF +* Sun Differences:: Differences between GNU stabs and Sun + native stabs +* Stabs In ELF:: Stabs in an ELF file. +* Symbol Types Index:: Index of symbolic stab symbol type names. +@end menu +@end ifinfo + + +@node Overview +@chapter Overview of Stabs + +@dfn{Stabs} refers to a format for information that describes a program +to a debugger. This format was apparently invented by +@c FIXME! <> at +the University of California at Berkeley, for the @code{pdx} Pascal +debugger; the format has spread widely since then. + +This document is one of the few published sources of documentation on +stabs. It is believed to be comprehensive for stabs used by C. The +lists of symbol descriptors (@pxref{Symbol Descriptors}) and type +descriptors (@pxref{Type Descriptors}) are believed to be completely +comprehensive. Stabs for COBOL-specific features and for variant +records (used by Pascal and Modula-2) are poorly documented here. + +Other sources of information on stabs are @cite{Dbx and Dbxtool +Interfaces}, 2nd edition, by Sun, 1988, and @cite{AIX Version 3.2 Files +Reference}, Fourth Edition, September 1992, "dbx Stabstring Grammar" in +the a.out section, page 2-31. This document is believed to incorporate +the information from those two sources except where it explictly directs +you to them for more information. + +@menu +* Flow:: Overview of debugging information flow +* Stabs Format:: Overview of stab format +* String Field:: The string field +* C Example:: A simple example in C source +* Assembly Code:: The simple example at the assembly level +@end menu + +@node Flow +@section Overview of Debugging Information Flow + +The GNU C compiler compiles C source in a @file{.c} file into assembly +language in a @file{.s} file, which the assembler translates into +a @file{.o} file, which the linker combines with other @file{.o} files and +libraries to produce an executable file. + +With the @samp{-g} option, GCC puts in the @file{.s} file additional +debugging information, which is slightly transformed by the assembler +and linker, and carried through into the final executable. This +debugging information describes features of the source file like line +numbers, the types and scopes of variables, and function names, +parameters, and scopes. + +For some object file formats, the debugging information is encapsulated +in assembler directives known collectively as @dfn{stab} (symbol table) +directives, which are interspersed with the generated code. Stabs are +the native format for debugging information in the a.out and XCOFF +object file formats. The GNU tools can also emit stabs in the COFF and +ECOFF object file formats. + +The assembler adds the information from stabs to the symbol information +it places by default in the symbol table and the string table of the +@file{.o} file it is building. The linker consolidates the @file{.o} +files into one executable file, with one symbol table and one string +table. Debuggers use the symbol and string tables in the executable as +a source of debugging information about the program. + +@node Stabs Format +@section Overview of Stab Format + +There are three overall formats for stab assembler directives, +differentiated by the first word of the stab. The name of the directive +describes which combination of four possible data fields follows. It is +either @code{.stabs} (string), @code{.stabn} (number), or @code{.stabd} +(dot). IBM's XCOFF assembler uses @code{.stabx} (and some other +directives such as @code{.file} and @code{.bi}) instead of +@code{.stabs}, @code{.stabn} or @code{.stabd}. + +The overall format of each class of stab is: + +@example +.stabs "@var{string}",@var{type},@var{other},@var{desc},@var{value} +.stabn @var{type},@var{other},@var{desc},@var{value} +.stabd @var{type},@var{other},@var{desc} +.stabx "@var{string}",@var{value},@var{type},@var{sdb-type} +@end example + +@c what is the correct term for "current file location"? My AIX +@c assembler manual calls it "the value of the current location counter". +For @code{.stabn} and @code{.stabd}, there is no @var{string} (the +@code{n_strx} field is zero; see @ref{Symbol Tables}). For +@code{.stabd}, the @var{value} field is implicit and has the value of +the current file location. For @code{.stabx}, the @var{sdb-type} field +is unused for stabs and can always be set to zero. The @var{other} +field is almost always unused and can be set to zero. + +The number in the @var{type} field gives some basic information about +which type of stab this is (or whether it @emph{is} a stab, as opposed +to an ordinary symbol). Each valid type number defines a different stab +type; further, the stab type defines the exact interpretation of, and +possible values for, any remaining @var{string}, @var{desc}, or +@var{value} fields present in the stab. @xref{Stab Types}, for a list +in numeric order of the valid @var{type} field values for stab directives. + +@node String Field +@section The String Field + +For most stabs the string field holds the meat of the +debugging information. The flexible nature of this field +is what makes stabs extensible. For some stab types the string field +contains only a name. For other stab types the contents can be a great +deal more complex. + +The overall format of the string field for most stab types is: + +@example +"@var{name}:@var{symbol-descriptor} @var{type-information}" +@end example + +@var{name} is the name of the symbol represented by the stab. +@var{name} can be omitted, which means the stab represents an unnamed +object. For example, @samp{:t10=*2} defines type 10 as a pointer to +type 2, but does not give the type a name. Omitting the @var{name} +field is supported by AIX dbx and GDB after about version 4.8, but not +other debuggers. GCC sometimes uses a single space as the name instead +of omitting the name altogether; apparently that is supported by most +debuggers. + +The @var{symbol-descriptor} following the @samp{:} is an alphabetic +character that tells more specifically what kind of symbol the stab +represents. If the @var{symbol-descriptor} is omitted, but type +information follows, then the stab represents a local variable. For a +list of symbol descriptors, see @ref{Symbol Descriptors}. The @samp{c} +symbol descriptor is an exception in that it is not followed by type +information. @xref{Constants}. + +@var{type-information} is either a @var{type-number}, or +@samp{@var{type-number}=}. A @var{type-number} alone is a type +reference, referring directly to a type that has already been defined. + +The @samp{@var{type-number}=} form is a type definition, where the +number represents a new type which is about to be defined. The type +definition may refer to other types by number, and those type numbers +may be followed by @samp{=} and nested definitions. + +In a type definition, if the character that follows the equals sign is +non-numeric then it is a @var{type-descriptor}, and tells what kind of +type is about to be defined. Any other values following the +@var{type-descriptor} vary, depending on the @var{type-descriptor}. +@xref{Type Descriptors}, for a list of @var{type-descriptor} values. If +a number follows the @samp{=} then the number is a @var{type-reference}. +For a full description of types, @ref{Types}. + +There is an AIX extension for type attributes. Following the @samp{=} +are any number of type attributes. Each one starts with @samp{@@} and +ends with @samp{;}. Debuggers, including AIX's dbx and GDB 4.10, skip +any type attributes they do not recognize. GDB 4.9 and other versions +of dbx may not do this. Because of a conflict with C++ +(@pxref{Cplusplus}), new attributes should not be defined which begin +with a digit, @samp{(}, or @samp{-}; GDB may be unable to distinguish +those from the C++ type descriptor @samp{@@}. The attributes are: + +@table @code +@item a@var{boundary} +@var{boundary} is an integer specifying the alignment. I assume it +applies to all variables of this type. + +@item s@var{size} +Size in bits of a variable of this type. + +@item p@var{integer} +Pointer class (for checking). Not sure what this means, or how +@var{integer} is interpreted. + +@item P +Indicate this is a packed type, meaning that structure fields or array +elements are placed more closely in memory, to save memory at the +expense of speed. +@end table + +All of this can make the string field quite long. All +versions of GDB, and some versions of dbx, can handle arbitrarily long +strings. But many versions of dbx cretinously limit the strings to +about 80 characters, so compilers which must work with such dbx's need +to split the @code{.stabs} directive into several @code{.stabs} +directives. Each stab duplicates exactly all but the +string field. The string field of +every stab except the last is marked as continued with a +double-backslash at the end. Removing the backslashes and concatenating +the string fields of each stab produces the original, +long string. + +@node C Example +@section A Simple Example in C Source + +To get the flavor of how stabs describe source information for a C +program, let's look at the simple program: + +@example +main() +@{ + printf("Hello world"); +@} +@end example + +When compiled with @samp{-g}, the program above yields the following +@file{.s} file. Line numbers have been added to make it easier to refer +to parts of the @file{.s} file in the description of the stabs that +follows. + +@node Assembly Code +@section The Simple Example at the Assembly Level + +This simple ``hello world'' example demonstrates several of the stab +types used to describe C language source files. + +@example +1 gcc2_compiled.: +2 .stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0 +3 .stabs "hello.c",100,0,0,Ltext0 +4 .text +5 Ltext0: +6 .stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 +7 .stabs "char:t2=r2;0;127;",128,0,0,0 +8 .stabs "long int:t3=r1;-2147483648;2147483647;",128,0,0,0 +9 .stabs "unsigned int:t4=r1;0;-1;",128,0,0,0 +10 .stabs "long unsigned int:t5=r1;0;-1;",128,0,0,0 +11 .stabs "short int:t6=r1;-32768;32767;",128,0,0,0 +12 .stabs "long long int:t7=r1;0;-1;",128,0,0,0 +13 .stabs "short unsigned int:t8=r1;0;65535;",128,0,0,0 +14 .stabs "long long unsigned int:t9=r1;0;-1;",128,0,0,0 +15 .stabs "signed char:t10=r1;-128;127;",128,0,0,0 +16 .stabs "unsigned char:t11=r1;0;255;",128,0,0,0 +17 .stabs "float:t12=r1;4;0;",128,0,0,0 +18 .stabs "double:t13=r1;8;0;",128,0,0,0 +19 .stabs "long double:t14=r1;8;0;",128,0,0,0 +20 .stabs "void:t15=15",128,0,0,0 +21 .align 4 +22 LC0: +23 .ascii "Hello, world!\12\0" +24 .align 4 +25 .global _main +26 .proc 1 +27 _main: +28 .stabn 68,0,4,LM1 +29 LM1: +30 !#PROLOGUE# 0 +31 save %sp,-136,%sp +32 !#PROLOGUE# 1 +33 call ___main,0 +34 nop +35 .stabn 68,0,5,LM2 +36 LM2: +37 LBB2: +38 sethi %hi(LC0),%o1 +39 or %o1,%lo(LC0),%o0 +40 call _printf,0 +41 nop +42 .stabn 68,0,6,LM3 +43 LM3: +44 LBE2: +45 .stabn 68,0,6,LM4 +46 LM4: +47 L1: +48 ret +49 restore +50 .stabs "main:F1",36,0,0,_main +51 .stabn 192,0,0,LBB2 +52 .stabn 224,0,0,LBE2 +@end example + +@node Program Structure +@chapter Encoding the Structure of the Program + +The elements of the program structure that stabs encode include the name +of the main function, the names of the source and include files, the +line numbers, procedure names and types, and the beginnings and ends of +blocks of code. + +@menu +* Main Program:: Indicate what the main program is +* Source Files:: The path and name of the source file +* Include Files:: Names of include files +* Line Numbers:: +* Procedures:: +* Nested Procedures:: +* Block Structure:: +@end menu + +@node Main Program +@section Main Program + +@findex N_MAIN +Most languages allow the main program to have any name. The +@code{N_MAIN} stab type tells the debugger the name that is used in this +program. Only the string field is significant; it is the name of +a function which is the main program. Most C compilers do not use this +stab (they expect the debugger to assume that the name is @code{main}), +but some C compilers emit an @code{N_MAIN} stab for the @code{main} +function. + +@node Source Files +@section Paths and Names of the Source Files + +@findex N_SO +Before any other stabs occur, there must be a stab specifying the source +file. This information is contained in a symbol of stab type +@code{N_SO}; the string field contains the name of the file. The +value of the symbol is the start address of the portion of the +text section corresponding to that file. + +With the Sun Solaris2 compiler, the desc field contains a +source-language code. +@c Do the debuggers use it? What are the codes? -djm + +Some compilers (for example, GCC2 and SunOS4 @file{/bin/cc}) also +include the directory in which the source was compiled, in a second +@code{N_SO} symbol preceding the one containing the file name. This +symbol can be distinguished by the fact that it ends in a slash. Code +from the @code{cfront} C++ compiler can have additional @code{N_SO} symbols for +nonexistent source files after the @code{N_SO} for the real source file; +these are believed to contain no useful information. + +For example: + +@example +.stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0 # @r{100 is N_SO} +.stabs "hello.c",100,0,0,Ltext0 + .text +Ltext0: +@end example + +Instead of @code{N_SO} symbols, XCOFF uses a @code{.file} assembler +directive which assembles to a standard COFF @code{.file} symbol; +explaining this in detail is outside the scope of this document. + +@node Include Files +@section Names of Include Files + +There are several schemes for dealing with include files: the +traditional @code{N_SOL} approach, Sun's @code{N_BINCL} approach, and the +XCOFF @code{C_BINCL} approach (which despite the similar name has little in +common with @code{N_BINCL}). + +@findex N_SOL +An @code{N_SOL} symbol specifies which include file subsequent symbols +refer to. The string field is the name of the file and the value is the +text address corresponding to the end of the previous include file and +the start of this one. To specify the main source file again, use an +@code{N_SOL} symbol with the name of the main source file. + +@findex N_BINCL +@findex N_EINCL +@findex N_EXCL +The @code{N_BINCL} approach works as follows. An @code{N_BINCL} symbol +specifies the start of an include file. In an object file, only the +string is significant; the Sun linker puts data into some of the +other fields. The end of the include file is marked by an +@code{N_EINCL} symbol (which has no string field). In an object +file, there is no significant data in the @code{N_EINCL} symbol; the Sun +linker puts data into some of the fields. @code{N_BINCL} and +@code{N_EINCL} can be nested. + +If the linker detects that two source files have identical stabs between +an @code{N_BINCL} and @code{N_EINCL} pair (as will generally be the case +for a header file), then it only puts out the stabs once. Each +additional occurance is replaced by an @code{N_EXCL} symbol. I believe +the Sun (SunOS4, not sure about Solaris) linker is the only one which +supports this feature. +@c What do the fields of N_EXCL contain? -djm + +@findex C_BINCL +@findex C_EINCL +For the start of an include file in XCOFF, use the @file{.bi} assembler +directive, which generates a @code{C_BINCL} symbol. A @file{.ei} +directive, which generates a @code{C_EINCL} symbol, denotes the end of +the include file. Both directives are followed by the name of the +source file in quotes, which becomes the string for the symbol. +The value of each symbol, produced automatically by the assembler +and linker, is the offset into the executable of the beginning +(inclusive, as you'd expect) or end (inclusive, as you would not expect) +of the portion of the COFF line table that corresponds to this include +file. @code{C_BINCL} and @code{C_EINCL} do not nest. + +@node Line Numbers +@section Line Numbers + +@findex N_SLINE +An @code{N_SLINE} symbol represents the start of a source line. The +desc field contains the line number and the value +contains the code address for the start of that source line. On most +machines the address is absolute; for Sun's stabs-in-ELF, it is relative +to the function in which the @code{N_SLINE} symbol occurs. + +@findex N_DSLINE +@findex N_BSLINE +GNU documents @code{N_DSLINE} and @code{N_BSLINE} symbols for line +numbers in the data or bss segments, respectively. They are identical +to @code{N_SLINE} but are relocated differently by the linker. They +were intended to be used to describe the source location of a variable +declaration, but I believe that GCC2 actually puts the line number in +the desc field of the stab for the variable itself. GDB has been +ignoring these symbols (unless they contain a string field) since +at least GDB 3.5. + +For single source lines that generate discontiguous code, such as flow +of control statements, there may be more than one line number entry for +the same source line. In this case there is a line number entry at the +start of each code range, each with the same line number. + +XCOFF does not use stabs for line numbers. Instead, it uses COFF line +numbers (which are outside the scope of this document). Standard COFF +line numbers cannot deal with include files, but in XCOFF this is fixed +with the @code{C_BINCL} method of marking include files (@pxref{Include +Files}). + +@node Procedures +@section Procedures + +@findex N_FUN, for functions +@findex N_FNAME +@findex N_STSYM, for functions (Sun acc) +@findex N_GSYM, for functions (Sun acc) +All of the following stabs normally use the @code{N_FUN} symbol type. +However, Sun's @code{acc} compiler on SunOS4 uses @code{N_GSYM} and +@code{N_STSYM}, which means that the value of the stab for the function +is useless and the debugger must get the address of the function from +the non-stab symbols instead. BSD Fortran is said to use @code{N_FNAME} +with the same restriction; the value of the symbol is not useful (I'm +not sure it really does use this, because GDB doesn't handle this and no +one has complained). + +A function is represented by an @samp{F} symbol descriptor for a global +(extern) function, and @samp{f} for a static (local) function. The +value is the address of the start of the function. For @code{a.out}, it +is already relocated. For stabs in ELF, the SunPRO compiler version +2.0.1 and GCC put out an address which gets relocated by the linker. In +a future release SunPRO is planning to put out zero, in which case the +address can be found from the ELF (non-stab) symbol. Because looking +things up in the ELF symbols would probably be slow, I'm not sure how to +find which symbol of that name is the right one, and this doesn't +provide any way to deal with nested functions, it would probably be +better to make the value of the stab an address relative to the start of +the file. See @ref{Stabs In ELF} for more information on linker +relocation of stabs in ELF files. + +The type information of the stab represents the return type of the +function; thus @samp{foo:f5} means that foo is a function returning type +5. There is no need to try to get the line number of the start of the +function from the stab for the function; it is in the next +@code{N_SLINE} symbol. + +@c FIXME: verify whether the "I suspect" below is true or not. +Some compilers (such as Sun's Solaris compiler) support an extension for +specifying the types of the arguments. I suspect this extension is not +used for old (non-prototyped) function definitions in C. If the +extension is in use, the type information of the stab for the function +is followed by type information for each argument, with each argument +preceded by @samp{;}. An argument type of 0 means that additional +arguments are being passed, whose types and number may vary (@samp{...} +in ANSI C). GDB has tolerated this extension (parsed the syntax, if not +necessarily used the information) since at least version 4.8; I don't +know whether all versions of dbx tolerate it. The argument types given +here are not redundant with the symbols for the formal parameters +(@pxref{Parameters}); they are the types of the arguments as they are +passed, before any conversions might take place. For example, if a C +function which is declared without a prototype takes a @code{float} +argument, the value is passed as a @code{double} but then converted to a +@code{float}. Debuggers need to use the types given in the arguments +when printing values, but when calling the function they need to use the +types given in the symbol defining the function. + +If the return type and types of arguments of a function which is defined +in another source file are specified (i.e., a function prototype in ANSI +C), traditionally compilers emit no stab; the only way for the debugger +to find the information is if the source file where the function is +defined was also compiled with debugging symbols. As an extension the +Solaris compiler uses symbol descriptor @samp{P} followed by the return +type of the function, followed by the arguments, each preceded by +@samp{;}, as in a stab with symbol descriptor @samp{f} or @samp{F}. +This use of symbol descriptor @samp{P} can be distinguished from its use +for register parameters (@pxref{Register Parameters}) by the fact that it has +symbol type @code{N_FUN}. + +The AIX documentation also defines symbol descriptor @samp{J} as an +internal function. I assume this means a function nested within another +function. It also says symbol descriptor @samp{m} is a module in +Modula-2 or extended Pascal. + +Procedures (functions which do not return values) are represented as +functions returning the @code{void} type in C. I don't see why this couldn't +be used for all languages (inventing a @code{void} type for this purpose if +necessary), but the AIX documentation defines @samp{I}, @samp{P}, and +@samp{Q} for internal, global, and static procedures, respectively. +These symbol descriptors are unusual in that they are not followed by +type information. + +The following example shows a stab for a function @code{main} which +returns type number @code{1}. The @code{_main} specified for the value +is a reference to an assembler label which is used to fill in the start +address of the function. + +@example +.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN} +@end example + +The stab representing a procedure is located immediately following the +code of the procedure. This stab is in turn directly followed by a +group of other stabs describing elements of the procedure. These other +stabs describe the procedure's parameters, its block local variables, and +its block structure. + +@node Nested Procedures +@section Nested Procedures + +For any of the symbol descriptors representing procedures, after the +symbol descriptor and the type information is optionally a scope +specifier. This consists of a comma, the name of the procedure, another +comma, and the name of the enclosing procedure. The first name is local +to the scope specified, and seems to be redundant with the name of the +symbol (before the @samp{:}). This feature is used by GCC, and +presumably Pascal, Modula-2, etc., compilers, for nested functions. + +If procedures are nested more than one level deep, only the immediately +containing scope is specified. For example, this code: + +@example +int +foo (int x) +@{ + int bar (int y) + @{ + int baz (int z) + @{ + return x + y + z; + @} + return baz (x + 2 * y); + @} + return x + bar (3 * x); +@} +@end example + +@noindent +produces the stabs: + +@example +.stabs "baz:f1,baz,bar",36,0,0,_baz.15 # @r{36 is N_FUN} +.stabs "bar:f1,bar,foo",36,0,0,_bar.12 +.stabs "foo:F1",36,0,0,_foo +@end example + +@node Block Structure +@section Block Structure + +@findex N_LBRAC +@findex N_RBRAC +The program's block structure is represented by the @code{N_LBRAC} (left +brace) and the @code{N_RBRAC} (right brace) stab types. The variables +defined inside a block precede the @code{N_LBRAC} symbol for most +compilers, including GCC. Other compilers, such as the Convex, Acorn +RISC machine, and Sun @code{acc} compilers, put the variables after the +@code{N_LBRAC} symbol. The values of the @code{N_LBRAC} and +@code{N_RBRAC} symbols are the start and end addresses of the code of +the block, respectively. For most machines, they are relative to the +starting address of this source file. For the Gould NP1, they are +absolute. For Sun's stabs-in-ELF, they are relative to the function in +which they occur. + +The @code{N_LBRAC} and @code{N_RBRAC} stabs that describe the block +scope of a procedure are located after the @code{N_FUN} stab that +represents the procedure itself. + +Sun documents the desc field of @code{N_LBRAC} and +@code{N_RBRAC} symbols as containing the nesting level of the block. +However, dbx seems to not care, and GCC always sets desc to +zero. + +@node Constants +@chapter Constants + +The @samp{c} symbol descriptor indicates that this stab represents a +constant. This symbol descriptor is an exception to the general rule +that symbol descriptors are followed by type information. Instead, it +is followed by @samp{=} and one of the following: + +@table @code +@item b @var{value} +Boolean constant. @var{value} is a numeric value; I assume it is 0 for +false or 1 for true. + +@item c @var{value} +Character constant. @var{value} is the numeric value of the constant. + +@item e @var{type-information} , @var{value} +Constant whose value can be represented as integral. +@var{type-information} is the type of the constant, as it would appear +after a symbol descriptor (@pxref{String Field}). @var{value} is the +numeric value of the constant. GDB 4.9 does not actually get the right +value if @var{value} does not fit in a host @code{int}, but it does not +do anything violent, and future debuggers could be extended to accept +integers of any size (whether unsigned or not). This constant type is +usually documented as being only for enumeration constants, but GDB has +never imposed that restriction; I don't know about other debuggers. + +@item i @var{value} +Integer constant. @var{value} is the numeric value. The type is some +sort of generic integer type (for GDB, a host @code{int}); to specify +the type explicitly, use @samp{e} instead. + +@item r @var{value} +Real constant. @var{value} is the real value, which can be @samp{INF} +(optionally preceded by a sign) for infinity, @samp{QNAN} for a quiet +NaN (not-a-number), or @samp{SNAN} for a signalling NaN. If it is a +normal number the format is that accepted by the C library function +@code{atof}. + +@item s @var{string} +String constant. @var{string} is a string enclosed in either @samp{'} +(in which case @samp{'} characters within the string are represented as +@samp{\'} or @samp{"} (in which case @samp{"} characters within the +string are represented as @samp{\"}). + +@item S @var{type-information} , @var{elements} , @var{bits} , @var{pattern} +Set constant. @var{type-information} is the type of the constant, as it +would appear after a symbol descriptor (@pxref{String Field}). +@var{elements} is the number of elements in the set (does this means +how many bits of @var{pattern} are actually used, which would be +redundant with the type, or perhaps the number of bits set in +@var{pattern}? I don't get it), @var{bits} is the number of bits in the +constant (meaning it specifies the length of @var{pattern}, I think), +and @var{pattern} is a hexadecimal representation of the set. AIX +documentation refers to a limit of 32 bytes, but I see no reason why +this limit should exist. This form could probably be used for arbitrary +constants, not just sets; the only catch is that @var{pattern} should be +understood to be target, not host, byte order and format. +@end table + +The boolean, character, string, and set constants are not supported by +GDB 4.9, but it ignores them. GDB 4.8 and earlier gave an error +message and refused to read symbols from the file containing the +constants. + +The above information is followed by @samp{;}. + +@node Variables +@chapter Variables + +Different types of stabs describe the various ways that variables can be +allocated: on the stack, globally, in registers, in common blocks, +statically, or as arguments to a function. + +@menu +* Stack Variables:: Variables allocated on the stack. +* Global Variables:: Variables used by more than one source file. +* Register Variables:: Variables in registers. +* Common Blocks:: Variables statically allocated together. +* Statics:: Variables local to one source file. +* Based Variables:: Fortran pointer based variables. +* Parameters:: Variables for arguments to functions. +@end menu + +@node Stack Variables +@section Automatic Variables Allocated on the Stack + +If a variable's scope is local to a function and its lifetime is only as +long as that function executes (C calls such variables +@dfn{automatic}), it can be allocated in a register (@pxref{Register +Variables}) or on the stack. + +@findex N_LSYM +Each variable allocated on the stack has a stab with the symbol +descriptor omitted. Since type information should begin with a digit, +@samp{-}, or @samp{(}, only those characters precluded from being used +for symbol descriptors. However, the Acorn RISC machine (ARM) is said +to get this wrong: it puts out a mere type definition here, without the +preceding @samp{@var{type-number}=}. This is a bad idea; there is no +guarantee that type descriptors are distinct from symbol descriptors. +Stabs for stack variables use the @code{N_LSYM} stab type. + +The value of the stab is the offset of the variable within the +local variables. On most machines this is an offset from the frame +pointer and is negative. The location of the stab specifies which block +it is defined in; see @ref{Block Structure}. + +For example, the following C code: + +@example +int +main () +@{ + int x; +@} +@end example + +produces the following stabs: + +@example +.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN} +.stabs "x:1",128,0,0,-12 # @r{128 is N_LSYM} +.stabn 192,0,0,LBB2 # @r{192 is N_LBRAC} +.stabn 224,0,0,LBE2 # @r{224 is N_RBRAC} +@end example + +@xref{Procedures} for more information on the @code{N_FUN} stab, and +@ref{Block Structure} for more information on the @code{N_LBRAC} and +@code{N_RBRAC} stabs. + +@node Global Variables +@section Global Variables + +@findex N_GSYM +A variable whose scope is not specific to just one source file is +represented by the @samp{G} symbol descriptor. These stabs use the +@code{N_GSYM} stab type. The type information for the stab +(@pxref{String Field}) gives the type of the variable. + +For example, the following source code: + +@example +char g_foo = 'c'; +@end example + +@noindent +yields the following assembly code: + +@example +.stabs "g_foo:G2",32,0,0,0 # @r{32 is N_GSYM} + .global _g_foo + .data +_g_foo: + .byte 99 +@end example + +The address of the variable represented by the @code{N_GSYM} is not +contained in the @code{N_GSYM} stab. The debugger gets this information +from the external symbol for the global variable. In the example above, +the @code{.global _g_foo} and @code{_g_foo:} lines tell the assembler to +produce an external symbol. + +@node Register Variables +@section Register Variables + +@findex N_RSYM +@c According to an old version of this manual, AIX uses C_RPSYM instead +@c of C_RSYM. I am skeptical; this should be verified. +Register variables have their own stab type, @code{N_RSYM}, and their +own symbol descriptor, @samp{r}. The stab's value is the +number of the register where the variable data will be stored. +@c .stabs "name:type",N_RSYM,0,RegSize,RegNumber (Sun doc) + +AIX defines a separate symbol descriptor @samp{d} for floating point +registers. This seems unnecessary; why not just just give floating +point registers different register numbers? I have not verified whether +the compiler actually uses @samp{d}. + +If the register is explicitly allocated to a global variable, but not +initialized, as in: + +@example +register int g_bar asm ("%g5"); +@end example + +@noindent +then the stab may be emitted at the end of the object file, with +the other bss symbols. + +@node Common Blocks +@section Common Blocks + +A common block is a statically allocated section of memory which can be +referred to by several source files. It may contain several variables. +I believe Fortran is the only language with this feature. + +@findex N_BCOMM +@findex N_ECOMM +@findex C_BCOMM +@findex C_ECOMM +A @code{N_BCOMM} stab begins a common block and an @code{N_ECOMM} stab +ends it. The only field that is significant in these two stabs is the +string, which names a normal (non-debugging) symbol that gives the +address of the common block. According to IBM documentation, only the +@code{N_BCOMM} has the name of the common block (even though their +compiler actually puts it both places). + +@findex N_ECOML +@findex C_ECOML +The stabs for the members of the common block are between the +@code{N_BCOMM} and the @code{N_ECOMM}; the value of each stab is the +offset within the common block of that variable. IBM uses the +@code{C_ECOML} stab type, and there is a corresponding @code{N_ECOML} +stab type, but Sun's Fortran compiler uses @code{N_GSYM} instead. The +variables within a common block use the @samp{V} symbol descriptor (I +believe this is true of all Fortran variables). Other stabs (at least +type declarations using @code{C_DECL}) can also be between the +@code{N_BCOMM} and the @code{N_ECOMM}. + +@node Statics +@section Static Variables + +Initialized static variables are represented by the @samp{S} and +@samp{V} symbol descriptors. @samp{S} means file scope static, and +@samp{V} means procedure scope static. + +@c This is probably not worth mentioning; it is only true on the sparc +@c for `double' variables which although declared const are actually in +@c the data segment (the text segment can't guarantee 8 byte alignment). +@c (although GCC +@c 2.4.5 has a bug in that it uses @code{N_FUN}, so neither dbx nor GDB can +@c find the variables) +@findex N_STSYM +@findex N_LCSYM +@findex N_FUN, for variables +@findex N_ROSYM +In a.out files, @code{N_STSYM} means the data section, @code{N_FUN} +means the text section, and @code{N_LCSYM} means the bss section. For +those systems with a read-only data section separate from the text +section (Solaris), @code{N_ROSYM} means the read-only data section. + +For example, the source lines: + +@example +static const int var_const = 5; +static int var_init = 2; +static int var_noinit; +@end example + +@noindent +yield the following stabs: + +@example +.stabs "var_const:S1",36,0,0,_var_const # @r{36 is N_FUN} +@dots{} +.stabs "var_init:S1",38,0,0,_var_init # @r{38 is N_STSYM} +@dots{} +.stabs "var_noinit:S1",40,0,0,_var_noinit # @r{40 is N_LCSYM} +@end example + +In XCOFF files, each symbol has a section number, so the stab type +need not indicate the section. + +In ECOFF files, the storage class is used to specify the section, so the +stab type need not indicate the section. + +In ELF files, for the SunPRO compiler version 2.0.1, symbol descriptor +@samp{S} means that the address is absolute (the linker relocates it) +and symbol descriptor @samp{V} means that the address is relative to the +start of the relevant section for that compilation unit. SunPRO has +plans to have the linker stop relocating stabs; I suspect that their the +debugger gets the address from the corresponding ELF (not stab) symbol. +I'm not sure how to find which symbol of that name is the right one. +The clean way to do all this would be to have a the value of a symbol +descriptor @samp{S} symbol be an offset relative to the start of the +file, just like everything else, but that introduces obvious +compatibility problems. For more information on linker stab relocation, +@xref{Stabs In ELF}. + +@node Based Variables +@section Fortran Based Variables + +Fortran (at least, the Sun and SGI dialects of FORTRAN-77) has a feature +which allows allocating arrays with @code{malloc}, but which avoids +blurring the line between arrays and pointers the way that C does. In +stabs such a variable uses the @samp{b} symbol descriptor. + +For example, the Fortran declarations + +@example +real foo, foo10(10), foo10_5(10,5) +pointer (foop, foo) +pointer (foo10p, foo10) +pointer (foo105p, foo10_5) +@end example + +produce the stabs + +@example +foo:b6 +foo10:bar3;1;10;6 +foo10_5:bar3;1;5;ar3;1;10;6 +@end example + +In this example, @code{real} is type 6 and type 3 is an integral type +which is the type of the subscripts of the array (probably +@code{integer}). + +The @samp{b} symbol descriptor is like @samp{V} in that it denotes a +statically allocated symbol whose scope is local to a function; see +@xref{Statics}. The value of the symbol, instead of being the address +of the variable itself, is the address of a pointer to that variable. +So in the above example, the value of the @code{foo} stab is the address +of a pointer to a real, the value of the @code{foo10} stab is the +address of a pointer to a 10-element array of reals, and the value of +the @code{foo10_5} stab is the address of a pointer to a 5-element array +of 10-element arrays of reals. + +@node Parameters +@section Parameters + +Formal parameters to a function are represented by a stab (or sometimes +two; see below) for each parameter. The stabs are in the order in which +the debugger should print the parameters (i.e., the order in which the +parameters are declared in the source file). The exact form of the stab +depends on how the parameter is being passed. + +@findex N_PSYM +Parameters passed on the stack use the symbol descriptor @samp{p} and +the @code{N_PSYM} symbol type. The value of the symbol is an offset +used to locate the parameter on the stack; its exact meaning is +machine-dependent, but on most machines it is an offset from the frame +pointer. + +As a simple example, the code: + +@example +main (argc, argv) + int argc; + char **argv; +@end example + +produces the stabs: + +@example +.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN} +.stabs "argc:p1",160,0,0,68 # @r{160 is N_PSYM} +.stabs "argv:p20=*21=*2",160,0,0,72 +@end example + +The type definition of @code{argv} is interesting because it contains +several type definitions. Type 21 is pointer to type 2 (char) and +@code{argv} (type 20) is pointer to type 21. + +@c FIXME: figure out what these mean and describe them coherently. +The following symbol descriptors are also said to go with @code{N_PSYM}. +The value of the symbol is said to be an offset from the argument +pointer (I'm not sure whether this is true or not). + +@example +pP (<>) +pF Fortran function parameter +X (function result variable) +@end example + +@menu +* Register Parameters:: +* Local Variable Parameters:: +* Reference Parameters:: +* Conformant Arrays:: +@end menu + +@node Register Parameters +@subsection Passing Parameters in Registers + +If the parameter is passed in a register, then traditionally there are +two symbols for each argument: + +@example +.stabs "arg:p1" . . . ; N_PSYM +.stabs "arg:r1" . . . ; N_RSYM +@end example + +Debuggers use the second one to find the value, and the first one to +know that it is an argument. + +@findex C_RPSYM +@findex N_RSYM, for parameters +Because that approach is kind of ugly, some compilers use symbol +descriptor @samp{P} or @samp{R} to indicate an argument which is in a +register. Symbol type @code{C_RPSYM} is used with @samp{R} and +@code{N_RSYM} is used with @samp{P}. The symbol's value is +the register number. @samp{P} and @samp{R} mean the same thing; the +difference is that @samp{P} is a GNU invention and @samp{R} is an IBM +(XCOFF) invention. As of version 4.9, GDB should handle either one. + +There is at least one case where GCC uses a @samp{p} and @samp{r} pair +rather than @samp{P}; this is where the argument is passed in the +argument list and then loaded into a register. + +According to the AIX documentation, symbol descriptor @samp{D} is for a +parameter passed in a floating point register. This seems +unnecessary---why not just use @samp{R} with a register number which +indicates that it's a floating point register? I haven't verified +whether the system actually does what the documentation indicates. + +@c FIXME: On the hppa this is for any type > 8 bytes, I think, and not +@c for small structures (investigate). +On the sparc and hppa, for a @samp{P} symbol whose type is a structure +or union, the register contains the address of the structure. On the +sparc, this is also true of a @samp{p} and @samp{r} pair (using Sun +@code{cc}) or a @samp{p} symbol. However, if a (small) structure is +really in a register, @samp{r} is used. And, to top it all off, on the +hppa it might be a structure which was passed on the stack and loaded +into a register and for which there is a @samp{p} and @samp{r} pair! I +believe that symbol descriptor @samp{i} is supposed to deal with this +case (it is said to mean "value parameter by reference, indirect +access"; I don't know the source for this information), but I don't know +details or what compilers or debuggers use it, if any (not GDB or GCC). +It is not clear to me whether this case needs to be dealt with +differently than parameters passed by reference (@pxref{Reference Parameters}). + +@node Local Variable Parameters +@subsection Storing Parameters as Local Variables + +There is a case similar to an argument in a register, which is an +argument that is actually stored as a local variable. Sometimes this +happens when the argument was passed in a register and then the compiler +stores it as a local variable. If possible, the compiler should claim +that it's in a register, but this isn't always done. + +@findex N_LSYM, for parameter +Some compilers use the pair of symbols approach described above +(@samp{@var{arg}:p} followed by @samp{@var{arg}:}); this includes GCC1 +(not GCC2) on the sparc when passing a small structure and GCC2 +(sometimes) when the argument type is @code{float} and it is passed as a +@code{double} and converted to @code{float} by the prologue (in the +latter case the type of the @samp{@var{arg}:p} symbol is @code{double} +and the type of the @samp{@var{arg}:} symbol is @code{float}). + +GCC, at least on the 960, has another solution to the same problem. It +uses a single @samp{p} symbol descriptor for an argument which is stored +as a local variable but uses @code{N_LSYM} instead of @code{N_PSYM}. In +this case, the value of the symbol is an offset relative to the local +variables for that function, not relative to the arguments; on some +machines those are the same thing, but not on all. + +@c This is mostly just background info; the part that logically belongs +@c here is the last sentence. +On the VAX or on other machines in which the calling convention includes +the number of words of arguments actually passed, the debugger (GDB at +least) uses the parameter symbols to keep track of whether it needs to +print nameless arguments in addition to the formal parameters which it +has printed because each one has a stab. For example, in + +@example +extern int fprintf (FILE *stream, char *format, @dots{}); +@dots{} +fprintf (stdout, "%d\n", x); +@end example + +there are stabs for @code{stream} and @code{format}. On most machines, +the debugger can only print those two arguments (because it has no way +of knowing that additional arguments were passed), but on the VAX or +other machines with a calling convention which indicates the number of +words of arguments, the debugger can print all three arguments. To do +so, the parameter symbol (symbol descriptor @samp{p}) (not necessarily +@samp{r} or symbol descriptor omitted symbols) needs to contain the +actual type as passed (for example, @code{double} not @code{float} if it +is passed as a double and converted to a float). + +@node Reference Parameters +@subsection Passing Parameters by Reference + +If the parameter is passed by reference (e.g., Pascal @code{VAR} +parameters), then the symbol descriptor is @samp{v} if it is in the +argument list, or @samp{a} if it in a register. Other than the fact +that these contain the address of the parameter rather than the +parameter itself, they are identical to @samp{p} and @samp{R}, +respectively. I believe @samp{a} is an AIX invention; @samp{v} is +supported by all stabs-using systems as far as I know. + +@node Conformant Arrays +@subsection Passing Conformant Array Parameters + +@c Is this paragraph correct? It is based on piecing together patchy +@c information and some guesswork +Conformant arrays are a feature of Modula-2, and perhaps other +languages, in which the size of an array parameter is not known to the +called function until run-time. Such parameters have two stabs: a +@samp{x} for the array itself, and a @samp{C}, which represents the size +of the array. The value of the @samp{x} stab is the offset in the +argument list where the address of the array is stored (it this right? +it is a guess); the value of the @samp{C} stab is the offset in the +argument list where the size of the array (in elements? in bytes?) is +stored. + +@node Types +@chapter Defining Types + +The examples so far have described types as references to previously +defined types, or defined in terms of subranges of or pointers to +previously defined types. This chapter describes the other type +descriptors that may follow the @samp{=} in a type definition. + +@menu +* Builtin Types:: Integers, floating point, void, etc. +* Miscellaneous Types:: Pointers, sets, files, etc. +* Cross-References:: Referring to a type not yet defined. +* Subranges:: A type with a specific range. +* Arrays:: An aggregate type of same-typed elements. +* Strings:: Like an array but also has a length. +* Enumerations:: Like an integer but the values have names. +* Structures:: An aggregate type of different-typed elements. +* Typedefs:: Giving a type a name. +* Unions:: Different types sharing storage. +* Function Types:: +@end menu + +@node Builtin Types +@section Builtin Types + +Certain types are built in (@code{int}, @code{short}, @code{void}, +@code{float}, etc.); the debugger recognizes these types and knows how +to handle them. Thus, don't be surprised if some of the following ways +of specifying builtin types do not specify everything that a debugger +would need to know about the type---in some cases they merely specify +enough information to distinguish the type from other types. + +The traditional way to define builtin types is convolunted, so new ways +have been invented to describe them. Sun's @code{acc} uses special +builtin type descriptors (@samp{b} and @samp{R}), and IBM uses negative +type numbers. GDB accepts all three ways, as of version 4.8; dbx just +accepts the traditional builtin types and perhaps one of the other two +formats. The following sections describe each of these formats. + +@menu +* Traditional Builtin Types:: Put on your seatbelts and prepare for kludgery +* Builtin Type Descriptors:: Builtin types with special type descriptors +* Negative Type Numbers:: Builtin types using negative type numbers +@end menu + +@node Traditional Builtin Types +@subsection Traditional Builtin Types + +This is the traditional, convoluted method for defining builtin types. +There are several classes of such type definitions: integer, floating +point, and @code{void}. + +@menu +* Traditional Integer Types:: +* Traditional Other Types:: +@end menu + +@node Traditional Integer Types +@subsubsection Traditional Integer Types + +Often types are defined as subranges of themselves. If the bounding values +fit within an @code{int}, then they are given normally. For example: + +@example +.stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 # @r{128 is N_LSYM} +.stabs "char:t2=r2;0;127;",128,0,0,0 +@end example + +Builtin types can also be described as subranges of @code{int}: + +@example +.stabs "unsigned short:t6=r1;0;65535;",128,0,0,0 +@end example + +If the lower bound of a subrange is 0 and the upper bound is -1, +the type is an unsigned integral type whose bounds are too +big to describe in an @code{int}. Traditionally this is only used for +@code{unsigned int} and @code{unsigned long}: + +@example +.stabs "unsigned int:t4=r1;0;-1;",128,0,0,0 +@end example + +For larger types, GCC 2.4.5 puts out bounds in octal, with one or more +leading zeroes. In this case a negative bound consists of a number +which is a 1 bit (for the sign bit) followed by a 0 bit for each bit in +the number (except the sign bit), and a positive bound is one which is a +1 bit for each bit in the number (except possibly the sign bit). All +known versions of dbx and GDB version 4 accept this (at least in the +sense of not refusing to process the file), but GDB 3.5 refuses to read +the whole file containing such symbols. So GCC 2.3.3 did not output the +proper size for these types. As an example of octal bounds, the string +fields of the stabs for 64 bit integer types look like: + +@c .stabs directives, etc., omitted to make it fit on the page. +@example +long int:t3=r1;001000000000000000000000;000777777777777777777777; +long unsigned int:t5=r1;000000000000000000000000;001777777777777777777777; +@end example + +If the lower bound of a subrange is 0 and the upper bound is negative, +the type is an unsigned integral type whose size in bytes is the +absolute value of the upper bound. I believe this is a Convex +convention for @code{unsigned long long}. + +If the lower bound of a subrange is negative and the upper bound is 0, +the type is a signed integral type whose size in bytes is +the absolute value of the lower bound. I believe this is a Convex +convention for @code{long long}. To distinguish this from a legitimate +subrange, the type should be a subrange of itself. I'm not sure whether +this is the case for Convex. + +@node Traditional Other Types +@subsubsection Traditional Other Types + +If the upper bound of a subrange is 0 and the lower bound is positive, +the type is a floating point type, and the lower bound of the subrange +indicates the number of bytes in the type: + +@example +.stabs "float:t12=r1;4;0;",128,0,0,0 +.stabs "double:t13=r1;8;0;",128,0,0,0 +@end example + +However, GCC writes @code{long double} the same way it writes +@code{double}, so there is no way to distinguish. + +@example +.stabs "long double:t14=r1;8;0;",128,0,0,0 +@end example + +Complex types are defined the same way as floating-point types; there is +no way to distinguish a single-precision complex from a double-precision +floating-point type. + +The C @code{void} type is defined as itself: + +@example +.stabs "void:t15=15",128,0,0,0 +@end example + +I'm not sure how a boolean type is represented. + +@node Builtin Type Descriptors +@subsection Defining Builtin Types Using Builtin Type Descriptors + +This is the method used by Sun's @code{acc} for defining builtin types. +These are the type descriptors to define builtin types: + +@table @code +@c FIXME: clean up description of width and offset, once we figure out +@c what they mean +@item b @var{signed} @var{char-flag} @var{width} ; @var{offset} ; @var{nbits} ; +Define an integral type. @var{signed} is @samp{u} for unsigned or +@samp{s} for signed. @var{char-flag} is @samp{c} which indicates this +is a character type, or is omitted. I assume this is to distinguish an +integral type from a character type of the same size, for example it +might make sense to set it for the C type @code{wchar_t} so the debugger +can print such variables differently (Solaris does not do this). Sun +sets it on the C types @code{signed char} and @code{unsigned char} which +arguably is wrong. @var{width} and @var{offset} appear to be for small +objects stored in larger ones, for example a @code{short} in an +@code{int} register. @var{width} is normally the number of bytes in the +type. @var{offset} seems to always be zero. @var{nbits} is the number +of bits in the type. + +Note that type descriptor @samp{b} used for builtin types conflicts with +its use for Pascal space types (@pxref{Miscellaneous Types}); they can +be distinguished because the character following the type descriptor +will be a digit, @samp{(}, or @samp{-} for a Pascal space type, or +@samp{u} or @samp{s} for a builtin type. + +@item w +Documented by AIX to define a wide character type, but their compiler +actually uses negative type numbers (@pxref{Negative Type Numbers}). + +@item R @var{fp-type} ; @var{bytes} ; +Define a floating point type. @var{fp-type} has one of the following values: + +@table @code +@item 1 (NF_SINGLE) +IEEE 32-bit (single precision) floating point format. + +@item 2 (NF_DOUBLE) +IEEE 64-bit (double precision) floating point format. + +@item 3 (NF_COMPLEX) +@item 4 (NF_COMPLEX16) +@item 5 (NF_COMPLEX32) +@c "GDB source" really means @file{include/aout/stab_gnu.h}, but trying +@c to put that here got an overfull hbox. +These are for complex numbers. A comment in the GDB source describes +them as Fortran @code{complex}, @code{double complex}, and +@code{complex*16}, respectively, but what does that mean? (i.e., Single +precision? Double precison?). + +@item 6 (NF_LDOUBLE) +Long double. This should probably only be used for Sun format +@code{long double}, and new codes should be used for other floating +point formats (@code{NF_DOUBLE} can be used if a @code{long double} is +really just an IEEE double, of course). +@end table + +@var{bytes} is the number of bytes occupied by the type. This allows a +debugger to perform some operations with the type even if it doesn't +understand @var{fp-type}. + +@item g @var{type-information} ; @var{nbits} +Documented by AIX to define a floating type, but their compiler actually +uses negative type numbers (@pxref{Negative Type Numbers}). + +@item c @var{type-information} ; @var{nbits} +Documented by AIX to define a complex type, but their compiler actually +uses negative type numbers (@pxref{Negative Type Numbers}). +@end table + +The C @code{void} type is defined as a signed integral type 0 bits long: +@example +.stabs "void:t19=bs0;0;0",128,0,0,0 +@end example +The Solaris compiler seems to omit the trailing semicolon in this case. +Getting sloppy in this way is not a swift move because if a type is +embedded in a more complex expression it is necessary to be able to tell +where it ends. + +I'm not sure how a boolean type is represented. + +@node Negative Type Numbers +@subsection Negative Type Numbers + +This is the method used in XCOFF for defining builtin types. +Since the debugger knows about the builtin types anyway, the idea of +negative type numbers is simply to give a special type number which +indicates the builtin type. There is no stab defining these types. + +There are several subtle issues with negative type numbers. + +One is the size of the type. A builtin type (for example the C types +@code{int} or @code{long}) might have different sizes depending on +compiler options, the target architecture, the ABI, etc. This issue +doesn't come up for IBM tools since (so far) they just target the +RS/6000; the sizes indicated below for each size are what the IBM +RS/6000 tools use. To deal with differing sizes, either define separate +negative type numbers for each size (which works but requires changing +the debugger, and, unless you get both AIX dbx and GDB to accept the +change, introduces an incompatibility), or use a type attribute +(@pxref{String Field}) to define a new type with the appropriate size +(which merely requires a debugger which understands type attributes, +like AIX dbx). For example, + +@example +.stabs "boolean:t10=@@s8;-16",128,0,0,0 +@end example + +defines an 8-bit boolean type, and + +@example +.stabs "boolean:t10=@@s64;-16",128,0,0,0 +@end example + +defines a 64-bit boolean type. + +A similar issue is the format of the type. This comes up most often for +floating-point types, which could have various formats (particularly +extended doubles, which vary quite a bit even among IEEE systems). +Again, it is best to define a new negative type number for each +different format; changing the format based on the target system has +various problems. One such problem is that the Alpha has both VAX and +IEEE floating types. One can easily imagine one library using the VAX +types and another library in the same executable using the IEEE types. +Another example is that the interpretation of whether a boolean is true +or false can be based on the least significant bit, most significant +bit, whether it is zero, etc., and different compilers (or different +options to the same compiler) might provide different kinds of boolean. + +The last major issue is the names of the types. The name of a given +type depends @emph{only} on the negative type number given; these do not +vary depending on the language, the target system, or anything else. +One can always define separate type numbers---in the following list you +will see for example separate @code{int} and @code{integer*4} types +which are identical except for the name. But compatibility can be +maintained by not inventing new negative type numbers and instead just +defining a new type with a new name. For example: + +@example +.stabs "CARDINAL:t10=-8",128,0,0,0 +@end example + +Here is the list of negative type numbers. The phrase @dfn{integral +type} is used to mean twos-complement (I strongly suspect that all +machines which use stabs use twos-complement; most machines use +twos-complement these days). + +@table @code +@item -1 +@code{int}, 32 bit signed integral type. + +@item -2 +@code{char}, 8 bit type holding a character. Both GDB and dbx on AIX +treat this as signed. GCC uses this type whether @code{char} is signed +or not, which seems like a bad idea. The AIX compiler (@code{xlc}) seems to +avoid this type; it uses -5 instead for @code{char}. + +@item -3 +@code{short}, 16 bit signed integral type. + +@item -4 +@code{long}, 32 bit signed integral type. + +@item -5 +@code{unsigned char}, 8 bit unsigned integral type. + +@item -6 +@code{signed char}, 8 bit signed integral type. + +@item -7 +@code{unsigned short}, 16 bit unsigned integral type. + +@item -8 +@code{unsigned int}, 32 bit unsigned integral type. + +@item -9 +@code{unsigned}, 32 bit unsigned integral type. + +@item -10 +@code{unsigned long}, 32 bit unsigned integral type. + +@item -11 +@code{void}, type indicating the lack of a value. + +@item -12 +@code{float}, IEEE single precision. + +@item -13 +@code{double}, IEEE double precision. + +@item -14 +@code{long double}, IEEE double precision. The compiler claims the size +will increase in a future release, and for binary compatibility you have +to avoid using @code{long double}. I hope when they increase it they +use a new negative type number. + +@item -15 +@code{integer}. 32 bit signed integral type. + +@item -16 +@code{boolean}. 32 bit type. How is the truth value encoded? Is it +the least significant bit or is it a question of whether the whole value +is zero or non-zero? + +@item -17 +@code{short real}. IEEE single precision. + +@item -18 +@code{real}. IEEE double precision. + +@item -19 +@code{stringptr}. @xref{Strings}. + +@item -20 +@code{character}, 8 bit unsigned character type. + +@item -21 +@code{logical*1}, 8 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -22 +@code{logical*2}, 16 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -23 +@code{logical*4}, 32 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -24 +@code{logical}, 32 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -25 +@code{complex}. A complex type consisting of two IEEE single-precision +floating point values. + +@item -26 +@code{complex}. A complex type consisting of two IEEE double-precision +floating point values. + +@item -27 +@code{integer*1}, 8 bit signed integral type. + +@item -28 +@code{integer*2}, 16 bit signed integral type. + +@item -29 +@code{integer*4}, 32 bit signed integral type. + +@item -30 +@code{wchar}. Wide character, 16 bits wide, unsigned (what format? +Unicode?). +@end table + +@node Miscellaneous Types +@section Miscellaneous Types + +@table @code +@item b @var{type-information} ; @var{bytes} +Pascal space type. This is documented by IBM; what does it mean? + +This use of the @samp{b} type descriptor can be distinguished +from its use for builtin integral types (@pxref{Builtin Type +Descriptors}) because the character following the type descriptor is +always a digit, @samp{(}, or @samp{-}. + +@item B @var{type-information} +A volatile-qualified version of @var{type-information}. This is +a Sun extension. References and stores to a variable with a +volatile-qualified type must not be optimized or cached; they +must occur as the user specifies them. + +@item d @var{type-information} +File of type @var{type-information}. As far as I know this is only used +by Pascal. + +@item k @var{type-information} +A const-qualified version of @var{type-information}. This is a Sun +extension. A variable with a const-qualified type cannot be modified. + +@item M @var{type-information} ; @var{length} +Multiple instance type. The type seems to composed of @var{length} +repetitions of @var{type-information}, for example @code{character*3} is +represented by @samp{M-2;3}, where @samp{-2} is a reference to a +character type (@pxref{Negative Type Numbers}). I'm not sure how this +differs from an array. This appears to be a Fortran feature. +@var{length} is a bound, like those in range types; see @ref{Subranges}. + +@item S @var{type-information} +Pascal set type. @var{type-information} must be a small type such as an +enumeration or a subrange, and the type is a bitmask whose length is +specified by the number of elements in @var{type-information}. + +@item * @var{type-information} +Pointer to @var{type-information}. +@end table + +@node Cross-References +@section Cross-References to Other Types + +A type can be used before it is defined; one common way to deal with +that situation is just to use a type reference to a type which has not +yet been defined. + +Another way is with the @samp{x} type descriptor, which is followed by +@samp{s} for a structure tag, @samp{u} for a union tag, or @samp{e} for +a enumerator tag, followed by the name of the tag, followed by @samp{:}. +For example, the following C declarations: + +@example +struct foo; +struct foo *bar; +@end example + +@noindent +produce: + +@example +.stabs "bar:G16=*17=xsfoo:",32,0,0,0 +@end example + +Not all debuggers support the @samp{x} type descriptor, so on some +machines GCC does not use it. I believe that for the above example it +would just emit a reference to type 17 and never define it, but I +haven't verified that. + +Modula-2 imported types, at least on AIX, use the @samp{i} type +descriptor, which is followed by the name of the module from which the +type is imported, followed by @samp{:}, followed by the name of the +type. There is then optionally a comma followed by type information for +the type. This differs from merely naming the type (@pxref{Typedefs}) in +that it identifies the module; I don't understand whether the name of +the type given here is always just the same as the name we are giving +it, or whether this type descriptor is used with a nameless stab +(@pxref{String Field}), or what. The symbol ends with @samp{;}. + +@node Subranges +@section Subrange Types + +The @samp{r} type descriptor defines a type as a subrange of another +type. It is followed by type information for the type of which it is a +subrange, a semicolon, an integral lower bound, a semicolon, an +integral upper bound, and a semicolon. The AIX documentation does not +specify the trailing semicolon, in an effort to specify array indexes +more cleanly, but a subrange which is not an array index has always +included a trailing semicolon (@pxref{Arrays}). + +Instead of an integer, either bound can be one of the following: + +@table @code +@item A @var{offset} +The bound is passed by reference on the stack at offset @var{offset} +from the argument list. @xref{Parameters}, for more information on such +offsets. + +@item T @var{offset} +The bound is passed by value on the stack at offset @var{offset} from +the argument list. + +@item a @var{register-number} +The bound is pased by reference in register number +@var{register-number}. + +@item t @var{register-number} +The bound is passed by value in register number @var{register-number}. + +@item J +There is no bound. +@end table + +Subranges are also used for builtin types; see @ref{Traditional Builtin Types}. + +@node Arrays +@section Array Types + +Arrays use the @samp{a} type descriptor. Following the type descriptor +is the type of the index and the type of the array elements. If the +index type is a range type, it ends in a semicolon; otherwise +(for example, if it is a type reference), there does not +appear to be any way to tell where the types are separated. In an +effort to clean up this mess, IBM documents the two types as being +separated by a semicolon, and a range type as not ending in a semicolon +(but this is not right for range types which are not array indexes, +@pxref{Subranges}). I think probably the best solution is to specify +that a semicolon ends a range type, and that the index type and element +type of an array are separated by a semicolon, but that if the index +type is a range type, the extra semicolon can be omitted. GDB (at least +through version 4.9) doesn't support any kind of index type other than a +range anyway; I'm not sure about dbx. + +It is well established, and widely used, that the type of the index, +unlike most types found in the stabs, is merely a type definition, not +type information (@pxref{String Field}) (that is, it need not start with +@samp{@var{type-number}=} if it is defining a new type). According to a +comment in GDB, this is also true of the type of the array elements; it +gives @samp{ar1;1;10;ar1;1;10;4} as a legitimate way to express a two +dimensional array. According to AIX documentation, the element type +must be type information. GDB accepts either. + +The type of the index is often a range type, expressed as the type +descriptor @samp{r} and some parameters. It defines the size of the +array. In the example below, the range @samp{r1;0;2;} defines an index +type which is a subrange of type 1 (integer), with a lower bound of 0 +and an upper bound of 2. This defines the valid range of subscripts of +a three-element C array. + +For example, the definition: + +@example +char char_vec[3] = @{'a','b','c'@}; +@end example + +@noindent +produces the output: + +@example +.stabs "char_vec:G19=ar1;0;2;2",32,0,0,0 + .global _char_vec + .align 4 +_char_vec: + .byte 97 + .byte 98 + .byte 99 +@end example + +If an array is @dfn{packed}, the elements are spaced more +closely than normal, saving memory at the expense of speed. For +example, an array of 3-byte objects might, if unpacked, have each +element aligned on a 4-byte boundary, but if packed, have no padding. +One way to specify that something is packed is with type attributes +(@pxref{String Field}). In the case of arrays, another is to use the +@samp{P} type descriptor instead of @samp{a}. Other than specifying a +packed array, @samp{P} is identical to @samp{a}. + +@c FIXME-what is it? A pointer? +An open array is represented by the @samp{A} type descriptor followed by +type information specifying the type of the array elements. + +@c FIXME: what is the format of this type? A pointer to a vector of pointers? +An N-dimensional dynamic array is represented by + +@example +D @var{dimensions} ; @var{type-information} +@end example + +@c Does dimensions really have this meaning? The AIX documentation +@c doesn't say. +@var{dimensions} is the number of dimensions; @var{type-information} +specifies the type of the array elements. + +@c FIXME: what is the format of this type? A pointer to some offsets in +@c another array? +A subarray of an N-dimensional array is represented by + +@example +E @var{dimensions} ; @var{type-information} +@end example + +@c Does dimensions really have this meaning? The AIX documentation +@c doesn't say. +@var{dimensions} is the number of dimensions; @var{type-information} +specifies the type of the array elements. + +@node Strings +@section Strings + +Some languages, like C or the original Pascal, do not have string types, +they just have related things like arrays of characters. But most +Pascals and various other languages have string types, which are +indicated as follows: + +@table @code +@item n @var{type-information} ; @var{bytes} +@var{bytes} is the maximum length. I'm not sure what +@var{type-information} is; I suspect that it means that this is a string +of @var{type-information} (thus allowing a string of integers, a string +of wide characters, etc., as well as a string of characters). Not sure +what the format of this type is. This is an AIX feature. + +@item z @var{type-information} ; @var{bytes} +Just like @samp{n} except that this is a gstring, not an ordinary +string. I don't know the difference. + +@item N +Pascal Stringptr. What is this? This is an AIX feature. +@end table + +@node Enumerations +@section Enumerations + +Enumerations are defined with the @samp{e} type descriptor. + +@c FIXME: Where does this information properly go? Perhaps it is +@c redundant with something we already explain. +The source line below declares an enumeration type at file scope. +The type definition is located after the @code{N_RBRAC} that marks the end of +the previous procedure's block scope, and before the @code{N_FUN} that marks +the beginning of the next procedure's block scope. Therefore it does not +describe a block local symbol, but a file local one. + +The source line: + +@example +enum e_places @{first,second=3,last@}; +@end example + +@noindent +generates the following stab: + +@example +.stabs "e_places:T22=efirst:0,second:3,last:4,;",128,0,0,0 +@end example + +The symbol descriptor (@samp{T}) says that the stab describes a +structure, enumeration, or union tag. The type descriptor @samp{e}, +following the @samp{22=} of the type definition narrows it down to an +enumeration type. Following the @samp{e} is a list of the elements of +the enumeration. The format is @samp{@var{name}:@var{value},}. The +list of elements ends with @samp{;}. + +There is no standard way to specify the size of an enumeration type; it +is determined by the architecture (normally all enumerations types are +32 bits). There should be a way to specify an enumeration type of +another size; type attributes would be one way to do this. @xref{Stabs +Format}. + +@node Structures +@section Structures + +The encoding of structures in stabs can be shown with an example. + +The following source code declares a structure tag and defines an +instance of the structure in global scope. Then a @code{typedef} equates the +structure tag with a new type. Seperate stabs are generated for the +structure tag, the structure @code{typedef}, and the structure instance. The +stabs for the tag and the @code{typedef} are emited when the definitions are +encountered. Since the structure elements are not initialized, the +stab and code for the structure variable itself is located at the end +of the program in the bss section. + +@example +struct s_tag @{ + int s_int; + float s_float; + char s_char_vec[8]; + struct s_tag* s_next; +@} g_an_s; + +typedef struct s_tag s_typedef; +@end example + +The structure tag has an @code{N_LSYM} stab type because, like the +enumeration, the symbol has file scope. Like the enumeration, the +symbol descriptor is @samp{T}, for enumeration, structure, or tag type. +The type descriptor @samp{s} following the @samp{16=} of the type +definition narrows the symbol type to structure. + +Following the @samp{s} type descriptor is the number of bytes the +structure occupies, followed by a description of each structure element. +The structure element descriptions are of the form @var{name:type, bit +offset from the start of the struct, number of bits in the element}. + +@c FIXME: phony line break. Can probably be fixed by using an example +@c with fewer fields. +@example +# @r{128 is N_LSYM} +.stabs "s_tag:T16=s20s_int:1,0,32;s_float:12,32,32; + s_char_vec:17=ar1;0;7;2,64,64;s_next:18=*16,128,32;;",128,0,0,0 +@end example + +In this example, the first two structure elements are previously defined +types. For these, the type following the @samp{@var{name}:} part of the +element description is a simple type reference. The other two structure +elements are new types. In this case there is a type definition +embedded after the @samp{@var{name}:}. The type definition for the +array element looks just like a type definition for a standalone array. +The @code{s_next} field is a pointer to the same kind of structure that +the field is an element of. So the definition of structure type 16 +contains a type definition for an element which is a pointer to type 16. + +@node Typedefs +@section Giving a Type a Name + +To give a type a name, use the @samp{t} symbol descriptor. The type +is specified by the type information (@pxref{String Field}) for the stab. +For example, + +@example +.stabs "s_typedef:t16",128,0,0,0 # @r{128 is N_LSYM} +@end example + +specifies that @code{s_typedef} refers to type number 16. Such stabs +have symbol type @code{N_LSYM} (or @code{C_DECL} for XCOFF). + +If you are specifying the tag name for a structure, union, or +enumeration, use the @samp{T} symbol descriptor instead. I believe C is +the only language with this feature. + +If the type is an opaque type (I believe this is a Modula-2 feature), +AIX provides a type descriptor to specify it. The type descriptor is +@samp{o} and is followed by a name. I don't know what the name +means---is it always the same as the name of the type, or is this type +descriptor used with a nameless stab (@pxref{String Field})? There +optionally follows a comma followed by type information which defines +the type of this type. If omitted, a semicolon is used in place of the +comma and the type information, and the type is much like a generic +pointer type---it has a known size but little else about it is +specified. + +@node Unions +@section Unions + +@example +union u_tag @{ + int u_int; + float u_float; + char* u_char; +@} an_u; +@end example + +This code generates a stab for a union tag and a stab for a union +variable. Both use the @code{N_LSYM} stab type. If a union variable is +scoped locally to the procedure in which it is defined, its stab is +located immediately preceding the @code{N_LBRAC} for the procedure's block +start. + +The stab for the union tag, however, is located preceding the code for +the procedure in which it is defined. The stab type is @code{N_LSYM}. This +would seem to imply that the union type is file scope, like the struct +type @code{s_tag}. This is not true. The contents and position of the stab +for @code{u_type} do not convey any infomation about its procedure local +scope. + +@c FIXME: phony line break. Can probably be fixed by using an example +@c with fewer fields. +@smallexample +# @r{128 is N_LSYM} +.stabs "u_tag:T23=u4u_int:1,0,32;u_float:12,0,32;u_char:21,0,32;;", + 128,0,0,0 +@end smallexample + +The symbol descriptor @samp{T}, following the @samp{name:} means that +the stab describes an enumeration, structure, or union tag. The type +descriptor @samp{u}, following the @samp{23=} of the type definition, +narrows it down to a union type definition. Following the @samp{u} is +the number of bytes in the union. After that is a list of union element +descriptions. Their format is @var{name:type, bit offset into the +union, number of bytes for the element;}. + +The stab for the union variable is: + +@example +.stabs "an_u:23",128,0,0,-20 # @r{128 is N_LSYM} +@end example + +@samp{-20} specifies where the variable is stored (@pxref{Stack +Variables}). + +@node Function Types +@section Function Types + +Various types can be defined for function variables. These types are +not used in defining functions (@pxref{Procedures}); they are used for +things like pointers to functions. + +The simple, traditional, type is type descriptor @samp{f} is followed by +type information for the return type of the function, followed by a +semicolon. + +This does not deal with functions for which the number and types of the +parameters are part of the type, as in Modula-2 or ANSI C. AIX provides +extensions to specify these, using the @samp{f}, @samp{F}, @samp{p}, and +@samp{R} type descriptors. + +First comes the type descriptor. If it is @samp{f} or @samp{F}, this +type involves a function rather than a procedure, and the type +information for the return type of the function follows, followed by a +comma. Then comes the number of parameters to the function and a +semicolon. Then, for each parameter, there is the name of the parameter +followed by a colon (this is only present for type descriptors @samp{R} +and @samp{F} which represent Pascal function or procedure parameters), +type information for the parameter, a comma, 0 if passed by reference or +1 if passed by value, and a semicolon. The type definition ends with a +semicolon. + +For example, this variable definition: + +@example +int (*g_pf)(); +@end example + +@noindent +generates the following code: + +@example +.stabs "g_pf:G24=*25=f1",32,0,0,0 + .common _g_pf,4,"bss" +@end example + +The variable defines a new type, 24, which is a pointer to another new +type, 25, which is a function returning @code{int}. + +@node Symbol Tables +@chapter Symbol Information in Symbol Tables + +This chapter describes the format of symbol table entries +and how stab assembler directives map to them. It also describes the +transformations that the assembler and linker make on data from stabs. + +@menu +* Symbol Table Format:: +* Transformations On Symbol Tables:: +@end menu + +@node Symbol Table Format +@section Symbol Table Format + +Each time the assembler encounters a stab directive, it puts +each field of the stab into a corresponding field in a symbol table +entry of its output file. If the stab contains a string field, the +symbol table entry for that stab points to a string table entry +containing the string data from the stab. Assembler labels become +relocatable addresses. Symbol table entries in a.out have the format: + +@c FIXME: should refer to external, not internal. +@example +struct internal_nlist @{ + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + bfd_vma n_value; /* value of symbol */ +@}; +@end example + +If the stab has a string, the @code{n_strx} field holds the offset in +bytes of the string within the string table. The string is terminated +by a NUL character. If the stab lacks a string (for example, it was +produced by a @code{.stabn} or @code{.stabd} directive), the +@code{n_strx} field is zero. + +Symbol table entries with @code{n_type} field values greater than 0x1f +originated as stabs generated by the compiler (with one random +exception). The other entries were placed in the symbol table of the +executable by the assembler or the linker. + +@node Transformations On Symbol Tables +@section Transformations on Symbol Tables + +The linker concatenates object files and does fixups of externally +defined symbols. + +You can see the transformations made on stab data by the assembler and +linker by examining the symbol table after each pass of the build. To +do this, use @samp{nm -ap}, which dumps the symbol table, including +debugging information, unsorted. For stab entries the columns are: +@var{value}, @var{other}, @var{desc}, @var{type}, @var{string}. For +assembler and linker symbols, the columns are: @var{value}, @var{type}, +@var{string}. + +The low 5 bits of the stab type tell the linker how to relocate the +value of the stab. Thus for stab types like @code{N_RSYM} and +@code{N_LSYM}, where the value is an offset or a register number, the +low 5 bits are @code{N_ABS}, which tells the linker not to relocate the +value. + +Where the value of a stab contains an assembly language label, +it is transformed by each build step. The assembler turns it into a +relocatable address and the linker turns it into an absolute address. + +@menu +* Transformations On Static Variables:: +* Transformations On Global Variables:: +* ELF Transformations:: In ELF, things are a bit different. +@end menu + +@node Transformations On Static Variables +@subsection Transformations on Static Variables + +This source line defines a static variable at file scope: + +@example +static int s_g_repeat +@end example + +@noindent +The following stab describes the symbol: + +@example +.stabs "s_g_repeat:S1",38,0,0,_s_g_repeat +@end example + +@noindent +The assembler transforms the stab into this symbol table entry in the +@file{.o} file. The location is expressed as a data segment offset. + +@example +00000084 - 00 0000 STSYM s_g_repeat:S1 +@end example + +@noindent +In the symbol table entry from the executable, the linker has made the +relocatable address absolute. + +@example +0000e00c - 00 0000 STSYM s_g_repeat:S1 +@end example + +@node Transformations On Global Variables +@subsection Transformations on Global Variables + +Stabs for global variables do not contain location information. In +this case, the debugger finds location information in the assembler or +linker symbol table entry describing the variable. The source line: + +@example +char g_foo = 'c'; +@end example + +@noindent +generates the stab: + +@example +.stabs "g_foo:G2",32,0,0,0 +@end example + +The variable is represented by two symbol table entries in the object +file (see below). The first one originated as a stab. The second one +is an external symbol. The upper case @samp{D} signifies that the +@code{n_type} field of the symbol table contains 7, @code{N_DATA} with +local linkage. The stab's value is zero since the value is not used for +@code{N_GSYM} stabs. The value of the linker symbol is the relocatable +address corresponding to the variable. + +@example +00000000 - 00 0000 GSYM g_foo:G2 +00000080 D _g_foo +@end example + +@noindent +These entries as transformed by the linker. The linker symbol table +entry now holds an absolute address: + +@example +00000000 - 00 0000 GSYM g_foo:G2 +@dots{} +0000e008 D _g_foo +@end example + +@node ELF Transformations +@subsection Transformations of Stabs in ELF Files + +For ELF files, use @code{objdump --stabs} instead of @code{nm} to show +the stabs in an object or executable file. @code{objdump} is a GNU +utility; Sun does not provide any equivalent. + +The following example is for a stab whose value is an address is +relative to the compilation unit (@pxref{Stabs In ELF}). For example, +if the source line + +@example +static int ld = 5; +@end example + +appears within a function, then the assembly language output from the +compiler contains: + +@example +.Ddata.data: +@dots{} + .stabs "ld:V(0,3)",0x26,0,4,.L18-Ddata.data # @r{0x26 is N_STSYM} +@dots{} +.L18: + .align 4 + .word 0x5 +@end example + +Because the value is formed by subtracting one symbol from another, the +value is absolute, not relocatable, and so the object file contains + +@example +Symnum n_type n_othr n_desc n_value n_strx String +31 STSYM 0 4 00000004 680 ld:V(0,3) +@end example + +without any relocations, and the executable file also contains + +@example +Symnum n_type n_othr n_desc n_value n_strx String +31 STSYM 0 4 00000004 680 ld:V(0,3) +@end example + +@node Cplusplus +@chapter GNU C++ Stabs + +@menu +* Basic Cplusplus Types:: +* Simple Classes:: +* Class Instance:: +* Methods:: Method definition +* Protections:: +* Method Modifiers:: +* Virtual Methods:: +* Inheritence:: +* Virtual Base Classes:: +* Static Members:: +@end menu + +Type descriptors added for C++ descriptions: + +@table @code +@item # +method type (@code{##} if minimal debug) + +@item @@ +Member (class and variable) type. It is followed by type information +for the offset basetype, a comma, and type information for the type of +the field being pointed to. (FIXME: this is acknowledged to be +gibberish. Can anyone say what really goes here?). + +Note that there is a conflict between this and type attributes +(@pxref{String Field}); both use type descriptor @samp{@@}. +Fortunately, the @samp{@@} type descriptor used in this C++ sense always +will be followed by a digit, @samp{(}, or @samp{-}, and type attributes +never start with those things. +@end table + +@node Basic Cplusplus Types +@section Basic Types For C++ + +<< the examples that follow are based on a01.C >> + + +C++ adds two more builtin types to the set defined for C. These are +the unknown type and the vtable record type. The unknown type, type +16, is defined in terms of itself like the void type. + +The vtable record type, type 17, is defined as a structure type and +then as a structure tag. The structure has four fields: delta, index, +pfn, and delta2. pfn is the function pointer. + +<< In boilerplate $vtbl_ptr_type, what are the fields delta, +index, and delta2 used for? >> + +This basic type is present in all C++ programs even if there are no +virtual methods defined. + +@display +.stabs "struct_name:sym_desc(type)type_def(17)=type_desc(struct)struct_bytes(8) + elem_name(delta):type_ref(short int),bit_offset(0),field_bits(16); + elem_name(index):type_ref(short int),bit_offset(16),field_bits(16); + elem_name(pfn):type_def(18)=type_desc(ptr to)type_ref(void), + bit_offset(32),field_bits(32); + elem_name(delta2):type_def(short int);bit_offset(32),field_bits(16);;" + N_LSYM, NIL, NIL +@end display + +@smallexample +.stabs "$vtbl_ptr_type:t17=s8 + delta:6,0,16;index:6,16,16;pfn:18=*15,32,32;delta2:6,32,16;;" + ,128,0,0,0 +@end smallexample + +@display +.stabs "name:sym_dec(struct tag)type_ref($vtbl_ptr_type)",N_LSYM,NIL,NIL,NIL +@end display + +@example +.stabs "$vtbl_ptr_type:T17",128,0,0,0 +@end example + +@node Simple Classes +@section Simple Class Definition + +The stabs describing C++ language features are an extension of the +stabs describing C. Stabs representing C++ class types elaborate +extensively on the stab format used to describe structure types in C. +Stabs representing class type variables look just like stabs +representing C language variables. + +Consider the following very simple class definition. + +@example +class baseA @{ +public: + int Adat; + int Ameth(int in, char other); +@}; +@end example + +The class @code{baseA} is represented by two stabs. The first stab describes +the class as a structure type. The second stab describes a structure +tag of the class type. Both stabs are of stab type @code{N_LSYM}. Since the +stab is not located between an @code{N_FUN} and an @code{N_LBRAC} stab this indicates +that the class is defined at file scope. If it were, then the @code{N_LSYM} +would signify a local variable. + +A stab describing a C++ class type is similar in format to a stab +describing a C struct, with each class member shown as a field in the +structure. The part of the struct format describing fields is +expanded to include extra information relevent to C++ class members. +In addition, if the class has multiple base classes or virtual +functions the struct format outside of the field parts is also +augmented. + +In this simple example the field part of the C++ class stab +representing member data looks just like the field part of a C struct +stab. The section on protections describes how its format is +sometimes extended for member data. + +The field part of a C++ class stab representing a member function +differs substantially from the field part of a C struct stab. It +still begins with @samp{name:} but then goes on to define a new type number +for the member function, describe its return type, its argument types, +its protection level, any qualifiers applied to the method definition, +and whether the method is virtual or not. If the method is virtual +then the method description goes on to give the vtable index of the +method, and the type number of the first base class defining the +method. + +When the field name is a method name it is followed by two colons rather +than one. This is followed by a new type definition for the method. +This is a number followed by an equal sign and the type descriptor +@samp{#}, indicating a method type, and a second @samp{#}, indicating +that this is the @dfn{minimal} type of method definition used by GCC2, +not larger method definitions used by earlier versions of GCC. This is +followed by a type reference showing the return type of the method and a +semi-colon. + +The format of an overloaded operator method name differs from that of +other methods. It is @samp{op$::@var{operator-name}.} where +@var{operator-name} is the operator name such as @samp{+} or @samp{+=}. +The name ends with a period, and any characters except the period can +occur in the @var{operator-name} string. + +The next part of the method description represents the arguments to the +method, preceeded by a colon and ending with a semi-colon. The types of +the arguments are expressed in the same way argument types are expressed +in C++ name mangling. In this example an @code{int} and a @code{char} +map to @samp{ic}. + +This is followed by a number, a letter, and an asterisk or period, +followed by another semicolon. The number indicates the protections +that apply to the member function. Here the 2 means public. The +letter encodes any qualifier applied to the method definition. In +this case, @samp{A} means that it is a normal function definition. The dot +shows that the method is not virtual. The sections that follow +elaborate further on these fields and describe the additional +information present for virtual methods. + + +@display +.stabs "class_name:sym_desc(type)type_def(20)=type_desc(struct)struct_bytes(4) + field_name(Adat):type(int),bit_offset(0),field_bits(32); + + method_name(Ameth)::type_def(21)=type_desc(method)return_type(int); + :arg_types(int char); + protection(public)qualifier(normal)virtual(no);;" + N_LSYM,NIL,NIL,NIL +@end display + +@smallexample +.stabs "baseA:t20=s4Adat:1,0,32;Ameth::21=##1;:ic;2A.;;",128,0,0,0 + +.stabs "class_name:sym_desc(struct tag)",N_LSYM,NIL,NIL,NIL + +.stabs "baseA:T20",128,0,0,0 +@end smallexample + +@node Class Instance +@section Class Instance + +As shown above, describing even a simple C++ class definition is +accomplished by massively extending the stab format used in C to +describe structure types. However, once the class is defined, C stabs +with no modifications can be used to describe class instances. The +following source: + +@example +main () @{ + baseA AbaseA; +@} +@end example + +@noindent +yields the following stab describing the class instance. It looks no +different from a standard C stab describing a local variable. + +@display +.stabs "name:type_ref(baseA)", N_LSYM, NIL, NIL, frame_ptr_offset +@end display + +@example +.stabs "AbaseA:20",128,0,0,-20 +@end example + +@node Methods +@section Method Definition + +The class definition shown above declares Ameth. The C++ source below +defines Ameth: + +@example +int +baseA::Ameth(int in, char other) +@{ + return in; +@}; +@end example + + +This method definition yields three stabs following the code of the +method. One stab describes the method itself and following two describe +its parameters. Although there is only one formal argument all methods +have an implicit argument which is the @code{this} pointer. The @code{this} +pointer is a pointer to the object on which the method was called. Note +that the method name is mangled to encode the class name and argument +types. Name mangling is described in the @sc{arm} (@cite{The Annotated +C++ Reference Manual}, by Ellis and Stroustrup, @sc{isbn} +0-201-51459-1); @file{gpcompare.texi} in Cygnus GCC distributions +describes the differences between GNU mangling and @sc{arm} +mangling. +@c FIXME: Use @xref, especially if this is generally installed in the +@c info tree. +@c FIXME: This information should be in a net release, either of GCC or +@c GDB. But gpcompare.texi doesn't seem to be in the FSF GCC. + +@example +.stabs "name:symbol_desriptor(global function)return_type(int)", + N_FUN, NIL, NIL, code_addr_of_method_start + +.stabs "Ameth__5baseAic:F1",36,0,0,_Ameth__5baseAic +@end example + +Here is the stab for the @code{this} pointer implicit argument. The +name of the @code{this} pointer is always @code{this}. Type 19, the +@code{this} pointer is defined as a pointer to type 20, @code{baseA}, +but a stab defining @code{baseA} has not yet been emited. Since the +compiler knows it will be emited shortly, here it just outputs a cross +reference to the undefined symbol, by prefixing the symbol name with +@samp{xs}. + +@example +.stabs "name:sym_desc(register param)type_def(19)= + type_desc(ptr to)type_ref(baseA)= + type_desc(cross-reference to)baseA:",N_RSYM,NIL,NIL,register_number + +.stabs "this:P19=*20=xsbaseA:",64,0,0,8 +@end example + +The stab for the explicit integer argument looks just like a parameter +to a C function. The last field of the stab is the offset from the +argument pointer, which in most systems is the same as the frame +pointer. + +@example +.stabs "name:sym_desc(value parameter)type_ref(int)", + N_PSYM,NIL,NIL,offset_from_arg_ptr + +.stabs "in:p1",160,0,0,72 +@end example + +<< The examples that follow are based on A1.C >> + +@node Protections +@section Protections + + +In the simple class definition shown above all member data and +functions were publicly accessable. The example that follows +contrasts public, protected and privately accessable fields and shows +how these protections are encoded in C++ stabs. + +@c FIXME: What does "part of the string" mean? +Protections for class member data are signified by two characters +embedded in the stab defining the class type. These characters are +located after the name: part of the string. @samp{/0} means private, +@samp{/1} means protected, and @samp{/2} means public. If these +characters are omited this means that the member is public. The +following C++ source: + +@example +class all_data @{ +private: + int priv_dat; +protected: + char prot_dat; +public: + float pub_dat; +@}; +@end example + +@noindent +generates the following stab to describe the class type all_data. + +@display +.stabs "class_name:sym_desc(type)type_def(19)=type_desc(struct)struct_bytes + data_name:/protection(private)type_ref(int),bit_offset,num_bits; + data_name:/protection(protected)type_ref(char),bit_offset,num_bits; + data_name:(/num omited, private)type_ref(float),bit_offset,num_bits;;" + N_LSYM,NIL,NIL,NIL +@end display + +@smallexample +.stabs "all_data:t19=s12 + priv_dat:/01,0,32;prot_dat:/12,32,8;pub_dat:12,64,32;;",128,0,0,0 +@end smallexample + +Protections for member functions are signified by one digit embeded in +the field part of the stab describing the method. The digit is 0 if +private, 1 if protected and 2 if public. Consider the C++ class +definition below: + +@example +class all_methods @{ +private: + int priv_meth(int in)@{return in;@}; +protected: + char protMeth(char in)@{return in;@}; +public: + float pubMeth(float in)@{return in;@}; +@}; +@end example + +It generates the following stab. The digit in question is to the left +of an @samp{A} in each case. Notice also that in this case two symbol +descriptors apply to the class name struct tag and struct type. + +@display +.stabs "class_name:sym_desc(struct tag&type)type_def(21)= + sym_desc(struct)struct_bytes(1) + meth_name::type_def(22)=sym_desc(method)returning(int); + :args(int);protection(private)modifier(normal)virtual(no); + meth_name::type_def(23)=sym_desc(method)returning(char); + :args(char);protection(protected)modifier(normal)virual(no); + meth_name::type_def(24)=sym_desc(method)returning(float); + :args(float);protection(public)modifier(normal)virtual(no);;", + N_LSYM,NIL,NIL,NIL +@end display + +@smallexample +.stabs "all_methods:Tt21=s1priv_meth::22=##1;:i;0A.;protMeth::23=##2;:c;1A.; + pubMeth::24=##12;:f;2A.;;",128,0,0,0 +@end smallexample + +@node Method Modifiers +@section Method Modifiers (@code{const}, @code{volatile}, @code{const volatile}) + +<< based on a6.C >> + +In the class example described above all the methods have the normal +modifier. This method modifier information is located just after the +protection information for the method. This field has four possible +character values. Normal methods use @samp{A}, const methods use +@samp{B}, volatile methods use @samp{C}, and const volatile methods use +@samp{D}. Consider the class definition below: + +@example +class A @{ +public: + int ConstMeth (int arg) const @{ return arg; @}; + char VolatileMeth (char arg) volatile @{ return arg; @}; + float ConstVolMeth (float arg) const volatile @{return arg; @}; +@}; +@end example + +This class is described by the following stab: + +@display +.stabs "class(A):sym_desc(struct)type_def(20)=type_desc(struct)struct_bytes(1) + meth_name(ConstMeth)::type_def(21)sym_desc(method) + returning(int);:arg(int);protection(public)modifier(const)virtual(no); + meth_name(VolatileMeth)::type_def(22)=sym_desc(method) + returning(char);:arg(char);protection(public)modifier(volatile)virt(no) + meth_name(ConstVolMeth)::type_def(23)=sym_desc(method) + returning(float);:arg(float);protection(public)modifer(const volatile) + virtual(no);;", @dots{} +@end display + +@example +.stabs "A:T20=s1ConstMeth::21=##1;:i;2B.;VolatileMeth::22=##2;:c;2C.; + ConstVolMeth::23=##12;:f;2D.;;",128,0,0,0 +@end example + +@node Virtual Methods +@section Virtual Methods + +<< The following examples are based on a4.C >> + +The presence of virtual methods in a class definition adds additional +data to the class description. The extra data is appended to the +description of the virtual method and to the end of the class +description. Consider the class definition below: + +@example +class A @{ +public: + int Adat; + virtual int A_virt (int arg) @{ return arg; @}; +@}; +@end example + +This results in the stab below describing class A. It defines a new +type (20) which is an 8 byte structure. The first field of the class +struct is @samp{Adat}, an integer, starting at structure offset 0 and +occupying 32 bits. + +The second field in the class struct is not explicitly defined by the +C++ class definition but is implied by the fact that the class +contains a virtual method. This field is the vtable pointer. The +name of the vtable pointer field starts with @samp{$vf} and continues with a +type reference to the class it is part of. In this example the type +reference for class A is 20 so the name of its vtable pointer field is +@samp{$vf20}, followed by the usual colon. + +Next there is a type definition for the vtable pointer type (21). +This is in turn defined as a pointer to another new type (22). + +Type 22 is the vtable itself, which is defined as an array, indexed by +a range of integers between 0 and 1, and whose elements are of type +17. Type 17 was the vtable record type defined by the boilerplate C++ +type definitions, as shown earlier. + +The bit offset of the vtable pointer field is 32. The number of bits +in the field are not specified when the field is a vtable pointer. + +Next is the method definition for the virtual member function @code{A_virt}. +Its description starts out using the same format as the non-virtual +member functions described above, except instead of a dot after the +@samp{A} there is an asterisk, indicating that the function is virtual. +Since is is virtual some addition information is appended to the end +of the method description. + +The first number represents the vtable index of the method. This is a +32 bit unsigned number with the high bit set, followed by a +semi-colon. + +The second number is a type reference to the first base class in the +inheritence hierarchy defining the virtual member function. In this +case the class stab describes a base class so the virtual function is +not overriding any other definition of the method. Therefore the +reference is to the type number of the class that the stab is +describing (20). + +This is followed by three semi-colons. One marks the end of the +current sub-section, one marks the end of the method field, and the +third marks the end of the struct definition. + +For classes containing virtual functions the very last section of the +string part of the stab holds a type reference to the first base +class. This is preceeded by @samp{~%} and followed by a final semi-colon. + +@display +.stabs "class_name(A):type_def(20)=sym_desc(struct)struct_bytes(8) + field_name(Adat):type_ref(int),bit_offset(0),field_bits(32); + field_name(A virt func ptr):type_def(21)=type_desc(ptr to)type_def(22)= + sym_desc(array)index_type_ref(range of int from 0 to 1); + elem_type_ref(vtbl elem type), + bit_offset(32); + meth_name(A_virt)::typedef(23)=sym_desc(method)returning(int); + :arg_type(int),protection(public)normal(yes)virtual(yes) + vtable_index(1);class_first_defining(A);;;~%first_base(A);", + N_LSYM,NIL,NIL,NIL +@end display + +@c FIXME: bogus line break. +@example +.stabs "A:t20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32; + A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0 +@end example + +@node Inheritence +@section Inheritence + +Stabs describing C++ derived classes include additional sections that +describe the inheritence hierarchy of the class. A derived class stab +also encodes the number of base classes. For each base class it tells +if the base class is virtual or not, and if the inheritence is private +or public. It also gives the offset into the object of the portion of +the object corresponding to each base class. + +This additional information is embeded in the class stab following the +number of bytes in the struct. First the number of base classes +appears bracketed by an exclamation point and a comma. + +Then for each base type there repeats a series: two digits, a number, +a comma, another number, and a semi-colon. + +The first of the two digits is 1 if the base class is virtual and 0 if +not. The second digit is 2 if the derivation is public and 0 if not. + +The number following the first two digits is the offset from the start +of the object to the part of the object pertaining to the base class. + +After the comma, the second number is a type_descriptor for the base +type. Finally a semi-colon ends the series, which repeats for each +base class. + +The source below defines three base classes @code{A}, @code{B}, and +@code{C} and the derived class @code{D}. + + +@example +class A @{ +public: + int Adat; + virtual int A_virt (int arg) @{ return arg; @}; +@}; + +class B @{ +public: + int B_dat; + virtual int B_virt (int arg) @{return arg; @}; +@}; + +class C @{ +public: + int Cdat; + virtual int C_virt (int arg) @{return arg; @}; +@}; + +class D : A, virtual B, public C @{ +public: + int Ddat; + virtual int A_virt (int arg ) @{ return arg+1; @}; + virtual int B_virt (int arg) @{ return arg+2; @}; + virtual int C_virt (int arg) @{ return arg+3; @}; + virtual int D_virt (int arg) @{ return arg; @}; +@}; +@end example + +Class stabs similar to the ones described earlier are generated for +each base class. + +@c FIXME!!! the linebreaks in the following example probably make the +@c examples literally unusable, but I don't know any other way to get +@c them on the page. +@c One solution would be to put some of the type definitions into +@c separate stabs, even if that's not exactly what the compiler actually +@c emits. +@smallexample +.stabs "A:T20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32; + A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0 + +.stabs "B:Tt25=s8Bdat:1,0,32;$vf25:21,32;B_virt::26=##1; + :i;2A*-2147483647;25;;;~%25;",128,0,0,0 + +.stabs "C:Tt28=s8Cdat:1,0,32;$vf28:21,32;C_virt::29=##1; + :i;2A*-2147483647;28;;;~%28;",128,0,0,0 +@end smallexample + +In the stab describing derived class @code{D} below, the information about +the derivation of this class is encoded as follows. + +@display +.stabs "derived_class_name:symbol_descriptors(struct tag&type)= + type_descriptor(struct)struct_bytes(32)!num_bases(3), + base_virtual(no)inheritence_public(no)base_offset(0), + base_class_type_ref(A); + base_virtual(yes)inheritence_public(no)base_offset(NIL), + base_class_type_ref(B); + base_virtual(no)inheritence_public(yes)base_offset(64), + base_class_type_ref(C); @dots{} +@end display + +@c FIXME! fake linebreaks. +@smallexample +.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat: + 1,160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt: + :32:i;2A*-2147483647;25;;C_virt::32:i;2A*-2147483647; + 28;;D_virt::32:i;2A*-2147483646;31;;;~%20;",128,0,0,0 +@end smallexample + +@node Virtual Base Classes +@section Virtual Base Classes + +A derived class object consists of a concatination in memory of the data +areas defined by each base class, starting with the leftmost and ending +with the rightmost in the list of base classes. The exception to this +rule is for virtual inheritence. In the example above, class @code{D} +inherits virtually from base class @code{B}. This means that an +instance of a @code{D} object will not contain its own @code{B} part but +merely a pointer to a @code{B} part, known as a virtual base pointer. + +In a derived class stab, the base offset part of the derivation +information, described above, shows how the base class parts are +ordered. The base offset for a virtual base class is always given as 0. +Notice that the base offset for @code{B} is given as 0 even though +@code{B} is not the first base class. The first base class @code{A} +starts at offset 0. + +The field information part of the stab for class @code{D} describes the field +which is the pointer to the virtual base class @code{B}. The vbase pointer +name is @samp{$vb} followed by a type reference to the virtual base class. +Since the type id for @code{B} in this example is 25, the vbase pointer name +is @samp{$vb25}. + +@c FIXME!! fake linebreaks below +@smallexample +.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat:1, + 160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt::32:i; + 2A*-2147483647;25;;C_virt::32:i;2A*-2147483647;28;;D_virt: + :32:i;2A*-2147483646;31;;;~%20;",128,0,0,0 +@end smallexample + +Following the name and a semicolon is a type reference describing the +type of the virtual base class pointer, in this case 24. Type 24 was +defined earlier as the type of the @code{B} class @code{this} pointer. The +@code{this} pointer for a class is a pointer to the class type. + +@example +.stabs "this:P24=*25=xsB:",64,0,0,8 +@end example + +Finally the field offset part of the vbase pointer field description +shows that the vbase pointer is the first field in the @code{D} object, +before any data fields defined by the class. The layout of a @code{D} +class object is a follows, @code{Adat} at 0, the vtable pointer for +@code{A} at 32, @code{Cdat} at 64, the vtable pointer for C at 96, the +virtual base pointer for @code{B} at 128, and @code{Ddat} at 160. + + +@node Static Members +@section Static Members + +The data area for a class is a concatenation of the space used by the +data members of the class. If the class has virtual methods, a vtable +pointer follows the class data. The field offset part of each field +description in the class stab shows this ordering. + +<< How is this reflected in stabs? See Cygnus bug #677 for some info. >> + +@node Stab Types +@appendix Table of Stab Types + +The following are all the possible values for the stab type field, for +@code{a.out} files, in numeric order. This does not apply to XCOFF, but +it does apply to stabs in ELF. Stabs in ECOFF use these values but add +0x8f300 to distinguish them from non-stab symbols. + +The symbolic names are defined in the file @file{include/aout/stabs.def}. + +@menu +* Non-Stab Symbol Types:: Types from 0 to 0x1f +* Stab Symbol Types:: Types from 0x20 to 0xff +@end menu + +@node Non-Stab Symbol Types +@appendixsec Non-Stab Symbol Types + +The following types are used by the linker and assembler, not by stab +directives. Since this document does not attempt to describe aspects of +object file format other than the debugging format, no details are +given. + +@c Try to get most of these to fit on a single line. +@iftex +@tableindent=1.5in +@end iftex + +@table @code +@item 0x0 N_UNDF +Undefined symbol + +@item 0x2 N_ABS +File scope absolute symbol + +@item 0x3 N_ABS | N_EXT +External absolute symbol + +@item 0x4 N_TEXT +File scope text symbol + +@item 0x5 N_TEXT | N_EXT +External text symbol + +@item 0x6 N_DATA +File scope data symbol + +@item 0x7 N_DATA | N_EXT +External data symbol + +@item 0x8 N_BSS +File scope BSS symbol + +@item 0x9 N_BSS | N_EXT +External BSS symbol + +@item 0x0c N_FN_SEQ +Same as @code{N_FN}, for Sequent compilers + +@item 0x0a N_INDR +Symbol is indirected to another symbol + +@item 0x12 N_COMM +Common---visible after shared library dynamic link + +@item 0x14 N_SETA +Absolute set element + +@item 0x16 N_SETT +Text segment set element + +@item 0x18 N_SETD +Data segment set element + +@item 0x1a N_SETB +BSS segment set element + +@item 0x1c N_SETV +Pointer to set vector + +@item 0x1e N_WARNING +Print a warning message during linking + +@item 0x1f N_FN +File name of a @file{.o} file +@end table + +@node Stab Symbol Types +@appendixsec Stab Symbol Types + +The following symbol types indicate that this is a stab. This is the +full list of stab numbers, including stab types that are used in +languages other than C. + +@table @code +@item 0x20 N_GSYM +Global symbol; see @ref{Global Variables}. + +@item 0x22 N_FNAME +Function name (for BSD Fortran); see @ref{Procedures}. + +@item 0x24 N_FUN +Function name (@pxref{Procedures}) or text segment variable +(@pxref{Statics}). + +@item 0x26 N_STSYM +Data segment file-scope variable; see @ref{Statics}. + +@item 0x28 N_LCSYM +BSS segment file-scope variable; see @ref{Statics}. + +@item 0x2a N_MAIN +Name of main routine; see @ref{Main Program}. + +@item 0x2c N_ROSYM +Variable in @code{.rodata} section; see @ref{Statics}. + +@item 0x30 N_PC +Global symbol (for Pascal); see @ref{N_PC}. + +@item 0x32 N_NSYMS +Number of symbols (according to Ultrix V4.0); see @ref{N_NSYMS}. + +@item 0x34 N_NOMAP +No DST map; see @ref{N_NOMAP}. + +@c FIXME: describe this solaris feature in the body of the text (see +@c comments in include/aout/stab.def). +@item 0x38 N_OBJ +Object file (Solaris2). + +@c See include/aout/stab.def for (a little) more info. +@item 0x3c N_OPT +Debugger options (Solaris2). + +@item 0x40 N_RSYM +Register variable; see @ref{Register Variables}. + +@item 0x42 N_M2C +Modula-2 compilation unit; see @ref{N_M2C}. + +@item 0x44 N_SLINE +Line number in text segment; see @ref{Line Numbers}. + +@item 0x46 N_DSLINE +Line number in data segment; see @ref{Line Numbers}. + +@item 0x48 N_BSLINE +Line number in bss segment; see @ref{Line Numbers}. + +@item 0x48 N_BROWS +Sun source code browser, path to @file{.cb} file; see @ref{N_BROWS}. + +@item 0x4a N_DEFD +GNU Modula2 definition module dependency; see @ref{N_DEFD}. + +@item 0x4c N_FLINE +Function start/body/end line numbers (Solaris2). + +@item 0x50 N_EHDECL +GNU C++ exception variable; see @ref{N_EHDECL}. + +@item 0x50 N_MOD2 +Modula2 info "for imc" (according to Ultrix V4.0); see @ref{N_MOD2}. + +@item 0x54 N_CATCH +GNU C++ @code{catch} clause; see @ref{N_CATCH}. + +@item 0x60 N_SSYM +Structure of union element; see @ref{N_SSYM}. + +@item 0x62 N_ENDM +Last stab for module (Solaris2). + +@item 0x64 N_SO +Path and name of source file; see @ref{Source Files}. + +@item 0x80 N_LSYM +Stack variable (@pxref{Stack Variables}) or type (@pxref{Typedefs}). + +@item 0x82 N_BINCL +Beginning of an include file (Sun only); see @ref{Include Files}. + +@item 0x84 N_SOL +Name of include file; see @ref{Include Files}. + +@item 0xa0 N_PSYM +Parameter variable; see @ref{Parameters}. + +@item 0xa2 N_EINCL +End of an include file; see @ref{Include Files}. + +@item 0xa4 N_ENTRY +Alternate entry point; see @ref{N_ENTRY}. + +@item 0xc0 N_LBRAC +Beginning of a lexical block; see @ref{Block Structure}. + +@item 0xc2 N_EXCL +Place holder for a deleted include file; see @ref{Include Files}. + +@item 0xc4 N_SCOPE +Modula2 scope information (Sun linker); see @ref{N_SCOPE}. + +@item 0xe0 N_RBRAC +End of a lexical block; see @ref{Block Structure}. + +@item 0xe2 N_BCOMM +Begin named common block; see @ref{Common Blocks}. + +@item 0xe4 N_ECOMM +End named common block; see @ref{Common Blocks}. + +@item 0xe8 N_ECOML +Member of a common block; see @ref{Common Blocks}. + +@c FIXME: How does this really work? Move it to main body of document. +@item 0xea N_WITH +Pascal @code{with} statement: type,,0,0,offset (Solaris2). + +@item 0xf0 N_NBTEXT +Gould non-base registers; see @ref{Gould}. + +@item 0xf2 N_NBDATA +Gould non-base registers; see @ref{Gould}. + +@item 0xf4 N_NBBSS +Gould non-base registers; see @ref{Gould}. + +@item 0xf6 N_NBSTS +Gould non-base registers; see @ref{Gould}. + +@item 0xf8 N_NBLCS +Gould non-base registers; see @ref{Gould}. +@end table + +@c Restore the default table indent +@iftex +@tableindent=.8in +@end iftex + +@node Symbol Descriptors +@appendix Table of Symbol Descriptors + +The symbol descriptor is the character which follows the colon in many +stabs, and which tells what kind of stab it is. @xref{String Field}, +for more information about their use. + +@c Please keep this alphabetical +@table @code +@c In TeX, this looks great, digit is in italics. But makeinfo insists +@c on putting it in `', not realizing that @var should override @code. +@c I don't know of any way to make makeinfo do the right thing. Seems +@c like a makeinfo bug to me. +@item @var{digit} +@itemx ( +@itemx - +Variable on the stack; see @ref{Stack Variables}. + +@item a +Parameter passed by reference in register; see @ref{Reference Parameters}. + +@item b +Based variable; see @ref{Based Variables}. + +@item c +Constant; see @ref{Constants}. + +@item C +Conformant array bound (Pascal, maybe other languages); @ref{Conformant +Arrays}. Name of a caught exception (GNU C++). These can be +distinguished because the latter uses @code{N_CATCH} and the former uses +another symbol type. + +@item d +Floating point register variable; see @ref{Register Variables}. + +@item D +Parameter in floating point register; see @ref{Register Parameters}. + +@item f +File scope function; see @ref{Procedures}. + +@item F +Global function; see @ref{Procedures}. + +@item G +Global variable; see @ref{Global Variables}. + +@item i +@xref{Register Parameters}. + +@item I +Internal (nested) procedure; see @ref{Nested Procedures}. + +@item J +Internal (nested) function; see @ref{Nested Procedures}. + +@item L +Label name (documented by AIX, no further information known). + +@item m +Module; see @ref{Procedures}. + +@item p +Argument list parameter; see @ref{Parameters}. + +@item pP +@xref{Parameters}. + +@item pF +Fortran Function parameter; see @ref{Parameters}. + +@item P +Unfortunately, three separate meanings have been independently invented +for this symbol descriptor. At least the GNU and Sun uses can be +distinguished by the symbol type. Global Procedure (AIX) (symbol type +used unknown); see @ref{Procedures}. Register parameter (GNU) (symbol +type @code{N_PSYM}); see @ref{Parameters}. Prototype of function +referenced by this file (Sun @code{acc}) (symbol type @code{N_FUN}). + +@item Q +Static Procedure; see @ref{Procedures}. + +@item R +Register parameter; see @ref{Register Parameters}. + +@item r +Register variable; see @ref{Register Variables}. + +@item S +File scope variable; see @ref{Statics}. + +@item t +Type name; see @ref{Typedefs}. + +@item T +Enumeration, structure, or union tag; see @ref{Typedefs}. + +@item v +Parameter passed by reference; see @ref{Reference Parameters}. + +@item V +Procedure scope static variable; see @ref{Statics}. + +@item x +Conformant array; see @ref{Conformant Arrays}. + +@item X +Function return variable; see @ref{Parameters}. +@end table + +@node Type Descriptors +@appendix Table of Type Descriptors + +The type descriptor is the character which follows the type number and +an equals sign. It specifies what kind of type is being defined. +@xref{String Field}, for more information about their use. + +@table @code +@item @var{digit} +@itemx ( +Type reference; see @ref{String Field}. + +@item - +Reference to builtin type; see @ref{Negative Type Numbers}. + +@item # +Method (C++); see @ref{Cplusplus}. + +@item * +Pointer; see @ref{Miscellaneous Types}. + +@item & +Reference (C++). + +@item @@ +Type Attributes (AIX); see @ref{String Field}. Member (class and variable) +type (GNU C++); see @ref{Cplusplus}. + +@item a +Array; see @ref{Arrays}. + +@item A +Open array; see @ref{Arrays}. + +@item b +Pascal space type (AIX); see @ref{Miscellaneous Types}. Builtin integer +type (Sun); see @ref{Builtin Type Descriptors}. + +@item B +Volatile-qualified type; see @ref{Miscellaneous Types}. + +@item c +Complex builtin type; see @ref{Builtin Type Descriptors}. + +@item C +COBOL Picture type. See AIX documentation for details. + +@item d +File type; see @ref{Miscellaneous Types}. + +@item D +N-dimensional dynamic array; see @ref{Arrays}. + +@item e +Enumeration type; see @ref{Enumerations}. + +@item E +N-dimensional subarray; see @ref{Arrays}. + +@item f +Function type; see @ref{Function Types}. + +@item F +Pascal function parameter; see @ref{Function Types} + +@item g +Builtin floating point type; see @ref{Builtin Type Descriptors}. + +@item G +COBOL Group. See AIX documentation for details. + +@item i +Imported type; see @ref{Cross-References}. + +@item k +Const-qualified type; see @ref{Miscellaneous Types}. + +@item K +COBOL File Descriptor. See AIX documentation for details. + +@item M +Multiple instance type; see @ref{Miscellaneous Types}. + +@item n +String type; see @ref{Strings}. + +@item N +Stringptr; see @ref{Strings}. + +@item o +Opaque type; see @ref{Typedefs}. + +@item p +Procedure; see @ref{Function Types}. + +@item P +Packed array; see @ref{Arrays}. + +@item r +Range type; see @ref{Subranges}. + +@item R +Builtin floating type; see @ref{Builtin Type Descriptors} (Sun). Pascal +subroutine parameter; see @ref{Function Types} (AIX). Detecting this +conflict is possible with careful parsing (hint: a Pascal subroutine +parameter type will always contain a comma, and a builtin type +descriptor never will). + +@item s +Structure type; see @ref{Structures}. + +@item S +Set type; see @ref{Miscellaneous Types}. + +@item u +Union; see @ref{Unions}. + +@item v +Variant record. This is a Pascal and Modula-2 feature which is like a +union within a struct in C. See AIX documentation for details. + +@item w +Wide character; see @ref{Builtin Type Descriptors}. + +@item x +Cross-reference; see @ref{Cross-References}. + +@item z +gstring; see @ref{Strings}. +@end table + +@node Expanded Reference +@appendix Expanded Reference by Stab Type + +@c FIXME: This appendix should go away; see N_PSYM or N_SO for an example. + +For a full list of stab types, and cross-references to where they are +described, see @ref{Stab Types}. This appendix just duplicates certain +information from the main body of this document; eventually the +information will all be in one place. + +Format of an entry: + +The first line is the symbol type (see @file{include/aout/stab.def}). + +The second line describes the language constructs the symbol type +represents. + +The third line is the stab format with the significant stab fields +named and the rest NIL. + +Subsequent lines expand upon the meaning and possible values for each +significant stab field. @samp{#} stands in for the type descriptor. + +Finally, any further information. + +@menu +* N_PC:: Pascal global symbol +* N_NSYMS:: Number of symbols +* N_NOMAP:: No DST map +* N_M2C:: Modula-2 compilation unit +* N_BROWS:: Path to .cb file for Sun source code browser +* N_DEFD:: GNU Modula2 definition module dependency +* N_EHDECL:: GNU C++ exception variable +* N_MOD2:: Modula2 information "for imc" +* N_CATCH:: GNU C++ "catch" clause +* N_SSYM:: Structure or union element +* N_ENTRY:: Alternate entry point +* N_SCOPE:: Modula2 scope information (Sun only) +* Gould:: non-base register symbols used on Gould systems +* N_LENG:: Length of preceding entry +@end menu + +@node N_PC +@section N_PC + +@deffn @code{.stabs} N_PC +@findex N_PC +Global symbol (for Pascal). + +@example +"name" -> "symbol_name" <> +value -> supposedly the line number (stab.def is skeptical) +@end example + +@display +@file{stabdump.c} says: + +global pascal symbol: name,,0,subtype,line +<< subtype? >> +@end display +@end deffn + +@node N_NSYMS +@section N_NSYMS + +@deffn @code{.stabn} N_NSYMS +@findex N_NSYMS +Number of symbols (according to Ultrix V4.0). + +@display + 0, files,,funcs,lines (stab.def) +@end display +@end deffn + +@node N_NOMAP +@section N_NOMAP + +@deffn @code{.stabs} N_NOMAP +@findex N_NOMAP +No DST map for symbol (according to Ultrix V4.0). I think this means a +variable has been optimized out. + +@display + name, ,0,type,ignored (stab.def) +@end display +@end deffn + +@node N_M2C +@section N_M2C + +@deffn @code{.stabs} N_M2C +@findex N_M2C +Modula-2 compilation unit. + +@example +"string" -> "unit_name,unit_time_stamp[,code_time_stamp]" +desc -> unit_number +value -> 0 (main unit) + 1 (any other unit) +@end example +@end deffn + +@node N_BROWS +@section N_BROWS + +@deffn @code{.stabs} N_BROWS +@findex N_BROWS +Sun source code browser, path to @file{.cb} file + +<> +"path to associated @file{.cb} file" + +Note: N_BROWS has the same value as N_BSLINE. +@end deffn + +@node N_DEFD +@section N_DEFD + +@deffn @code{.stabn} N_DEFD +@findex N_DEFD +GNU Modula2 definition module dependency. + +GNU Modula-2 definition module dependency. The value is the +modification time of the definition file. The other field is non-zero +if it is imported with the GNU M2 keyword @code{%INITIALIZE}. Perhaps +@code{N_M2C} can be used if there are enough empty fields? +@end deffn + +@node N_EHDECL +@section N_EHDECL + +@deffn @code{.stabs} N_EHDECL +@findex N_EHDECL +GNU C++ exception variable <>. + +"@var{string} is variable name" + +Note: conflicts with @code{N_MOD2}. +@end deffn + +@node N_MOD2 +@section N_MOD2 + +@deffn @code{.stab?} N_MOD2 +@findex N_MOD2 +Modula2 info "for imc" (according to Ultrix V4.0) + +Note: conflicts with @code{N_EHDECL} <> +@end deffn + +@node N_CATCH +@section N_CATCH + +@deffn @code{.stabn} N_CATCH +@findex N_CATCH +GNU C++ @code{catch} clause + +GNU C++ @code{catch} clause. The value is its address. The desc field +is nonzero if this entry is immediately followed by a @code{CAUGHT} stab +saying what exception was caught. Multiple @code{CAUGHT} stabs means +that multiple exceptions can be caught here. If desc is 0, it means all +exceptions are caught here. +@end deffn + +@node N_SSYM +@section N_SSYM + +@deffn @code{.stabn} N_SSYM +@findex N_SSYM +Structure or union element. + +The value is the offset in the structure. + +<> +@end deffn + +@node N_ENTRY +@section N_ENTRY + +@deffn @code{.stabn} N_ENTRY +@findex N_ENTRY +Alternate entry point. +The value is its address. +<> +@end deffn + +@node N_SCOPE +@section N_SCOPE + +@deffn @code{.stab?} N_SCOPE +@findex N_SCOPE +Modula2 scope information (Sun linker) +<> +@end deffn + +@node Gould +@section Non-base registers on Gould systems + +@deffn @code{.stab?} N_NBTEXT +@deffnx @code{.stab?} N_NBDATA +@deffnx @code{.stab?} N_NBBSS +@deffnx @code{.stab?} N_NBSTS +@deffnx @code{.stab?} N_NBLCS +@findex N_NBTEXT +@findex N_NBDATA +@findex N_NBBSS +@findex N_NBSTS +@findex N_NBLCS +These are used on Gould systems for non-base registers syms. + +However, the following values are not the values used by Gould; they are +the values which GNU has been documenting for these values for a long +time, without actually checking what Gould uses. I include these values +only because perhaps some someone actually did something with the GNU +information (I hope not, why GNU knowingly assigned wrong values to +these in the header file is a complete mystery to me). + +@example +240 0xf0 N_NBTEXT ?? +242 0xf2 N_NBDATA ?? +244 0xf4 N_NBBSS ?? +246 0xf6 N_NBSTS ?? +248 0xf8 N_NBLCS ?? +@end example +@end deffn + +@node N_LENG +@section N_LENG + +@deffn @code{.stabn} N_LENG +@findex N_LENG +Second symbol entry containing a length-value for the preceding entry. +The value is the length. +@end deffn + +@node Questions +@appendix Questions and Anomalies + +@itemize @bullet +@item +@c I think this is changed in GCC 2.4.5 to put the line number there. +For GNU C stabs defining local and global variables (@code{N_LSYM} and +@code{N_GSYM}), the desc field is supposed to contain the source +line number on which the variable is defined. In reality the desc +field is always 0. (This behavior is defined in @file{dbxout.c} and +putting a line number in desc is controlled by @samp{#ifdef +WINNING_GDB}, which defaults to false). GDB supposedly uses this +information if you say @samp{list @var{var}}. In reality, @var{var} can +be a variable defined in the program and GDB says @samp{function +@var{var} not defined}. + +@item +In GNU C stabs, there seems to be no way to differentiate tag types: +structures, unions, and enums (symbol descriptor @samp{T}) and typedefs +(symbol descriptor @samp{t}) defined at file scope from types defined locally +to a procedure or other more local scope. They all use the @code{N_LSYM} +stab type. Types defined at procedure scope are emited after the +@code{N_RBRAC} of the preceding function and before the code of the +procedure in which they are defined. This is exactly the same as +types defined in the source file between the two procedure bodies. +GDB overcompensates by placing all types in block #1, the block for +symbols of file scope. This is true for default, @samp{-ansi} and +@samp{-traditional} compiler options. (Bugs gcc/1063, gdb/1066.) + +@item +What ends the procedure scope? Is it the proc block's @code{N_RBRAC} or the +next @code{N_FUN}? (I believe its the first.) + +@item +@c FIXME: This should go with the other stuff about global variables. +Global variable stabs don't have location information. This comes +from the external symbol for the same variable. The external symbol +has a leading underbar on the _name of the variable and the stab does +not. How do we know these two symbol table entries are talking about +the same symbol when their names are different? (Answer: the debugger +knows that external symbols have leading underbars). + +@c FIXME: This is absurdly vague; there all kinds of differences, some +@c of which are the same between gnu & sun, and some of which aren't. +@c In particular, I'm pretty sure GCC works with Sun dbx by default. +@c @item +@c Can GCC be configured to output stabs the way the Sun compiler +@c does, so that their native debugging tools work? It doesn't by +@c default. GDB reads either format of stab. (GCC or SunC). How about +@c dbx? +@end itemize + +@node XCOFF Differences +@appendix Differences Between GNU Stabs in a.out and GNU Stabs in XCOFF + +@c FIXME: Merge *all* these into the main body of the document. +The AIX/RS6000 native object file format is XCOFF with stabs. This +appendix only covers those differences which are not covered in the main +body of this document. + +@itemize @bullet +@item +BSD a.out stab types correspond to AIX XCOFF storage classes. In general +the mapping is @code{N_@var{stabtype}} becomes @code{C_@var{stabtype}}. +Some stab types in a.out are not supported in XCOFF; most of these use +@code{C_DECL}. + +@c FIXME: Get C_* types for the block, figure out whether it is always +@c used (I suspect not), explain clearly, and move to node Statics. +Exception: initialised static @code{N_STSYM} and un-initialized static +@code{N_LCSYM} both map to the @code{C_STSYM} storage class. But the +distinction is preserved because in XCOFF @code{N_STSYM} and +@code{N_LCSYM} must be emited in a named static block. Begin the block +with @samp{.bs s[RW] data_section_name} for @code{N_STSYM} or @samp{.bs +s bss_section_name} for @code{N_LCSYM}. End the block with @samp{.es}. + +@c FIXME: I think they are trying to say something about whether the +@c assembler defaults the value to the location counter. +@item +If the XCOFF stab is an @code{N_FUN} (@code{C_FUN}) then follow the +string field with @samp{,.} instead of just @samp{,}. +@end itemize + +I think that's it for @file{.s} file differences. They could stand to be +better presented. This is just a list of what I have noticed so far. +There are a @emph{lot} of differences in the information in the symbol +tables of the executable and object files. + +Mapping of a.out stab types to XCOFF storage classes: + +@example +stab type storage class +------------------------------- +N_GSYM C_GSYM +N_FNAME unused +N_FUN C_FUN +N_STSYM C_STSYM +N_LCSYM C_STSYM +N_MAIN unknown +N_PC unknown +N_RSYM C_RSYM +unknown C_RPSYM +N_M2C unknown +N_SLINE unknown +N_DSLINE unknown +N_BSLINE unknown +N_BROWSE unchanged +N_CATCH unknown +N_SSYM unknown +N_SO unknown +N_LSYM C_LSYM +various C_DECL +N_BINCL unknown +N_SOL unknown +N_PSYM C_PSYM +N_EINCL unknown +N_ENTRY C_ENTRY +N_LBRAC unknown +N_EXCL unknown +N_SCOPE unknown +N_RBRAC unknown +N_BCOMM C_BCOMM +N_ECOMM C_ECOMM +N_ECOML C_ECOML + +N_LENG unknown +@end example + +@node Sun Differences +@appendix Differences Between GNU Stabs and Sun Native Stabs + +@c FIXME: Merge all this stuff into the main body of the document. + +@itemize @bullet +@item +GNU C stabs define @emph{all} types, file or procedure scope, as +@code{N_LSYM}. Sun doc talks about using @code{N_GSYM} too. + +@item +Sun C stabs use type number pairs in the format +(@var{file-number},@var{type-number}) where @var{file-number} is a +number starting with 1 and incremented for each sub-source file in the +compilation. @var{type-number} is a number starting with 1 and +incremented for each new type defined in the compilation. GNU C stabs +use the type number alone, with no source file number. +@end itemize + +@node Stabs In ELF +@appendix Using Stabs With The ELF Object File Format + +The ELF object file format allows tools to create object files with +custom sections containing any arbitrary data. To use stabs in ELF +object files, the tools create two custom sections, a section named +@code{.stab} which contains an array of fixed length structures, one +struct per stab, and a section named @code{.stabstr} containing all the +variable length strings that are referenced by stabs in the @code{.stab} +section. The byte order of the stabs binary data matches the byte order +of the ELF file itself, as determined from the @code{EI_DATA} field in +the @code{e_ident} member of the ELF header. + +The first stab in the @code{.stab} section for each compilation unit is +synthetic, generated entirely by the assembler, with no corresponding +@code{.stab} directive as input to the assembler. This stab contains +the following fields: + +@table @code +@item n_strx +Offset in the @code{.stabstr} section to the source filename. + +@item n_type +@code{N_UNDF}. + +@item n_other +Unused field, always zero. + +@item n_desc +Count of upcoming symbols, i.e., the number of remaining stabs for this +source file. + +@item n_value +Size of the string table fragment associated with this source file, in +bytes. +@end table + +The @code{.stabstr} section always starts with a null byte (so that string +offsets of zero reference a null string), followed by random length strings, +each of which is null byte terminated. + +The ELF section header for the @code{.stab} section has its +@code{sh_link} member set to the section number of the @code{.stabstr} +section, and the @code{.stabstr} section has its ELF section +header @code{sh_type} member set to @code{SHT_STRTAB} to mark it as a +string table. + +To keep linking fast, it is a bad idea to have the linker relocating +stabs, so (except for a few cases, see below) none of the addresses in +the @code{n_value} field of the stabs are relocated by the linker. +Instead they are relative to the source file (or some entity smaller +than a source file, like a function). To find the address of each +section corresponding to a given source file, the compiler puts out +symbols giving the address of each section for a given source file. +Since these are ELF (not stab) symbols, the linker relocates them +correctly without having to touch the stabs section. They are named +@code{Bbss.bss} for the bss section, @code{Ddata.data} for the data +section, and @code{Drodata.rodata} for the rodata section. For the text +section, there is no such symbol (but there should be, see below). For +an example of how these symbols work, @xref{ELF Transformations}. GCC +does not provide these symbols; it instead relies on the stabs getting +relocated, which slows down linking. Thus addresses which would +normally be relative to @code{Bbss.bss}, etc., are already relocated. +The Sun linker provided with Solaris 2.2 and earlier relocates stabs +using normal ELF relocation information, as it would do for any section. +Sun has been threatening to kludge their linker to not do this (to speed +up linking), even though the correct way to avoid having the linker do +these relocations is to have the compiler no longer output relocatable +values. Last I heard they had been talked out of the linker kludge. +See Sun point patch 101052-01 and Sun bug 1142109. This affects +@samp{S} symbol descriptor stabs (@pxref{Statics}) and functions +(@pxref{Procedures}). In the latter case, to adopt the clean solution +(making the value of the stab relative to the start of the compilation +unit), it would be necessary to invent a @code{Ttext.text} symbol, +analogous to the @code{Bbss.bss}, etc., symbols. I recommend this +rather than using a zero value and getting the address from the ELF +symbols. + +@node Symbol Types Index +@unnumbered Symbol Types Index + +@printindex fn + +@contents +@bye diff --git a/gnu/usr.bin/gdb/gdb/COPYING b/gnu/usr.bin/gdb/gdb/COPYING new file mode 100644 index 00000000000..a43ea2126fb --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/gdb/gdb/Makefile b/gnu/usr.bin/gdb/gdb/Makefile new file mode 100644 index 00000000000..4ef28320d6f --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/Makefile @@ -0,0 +1,72 @@ +PROG = gdb +BINDIR= /usr/bin +SRCS = main.c blockframe.c breakpoint.c findvar.c stack.c thread.c \ + source.c values.c eval.c valops.c valarith.c valprint.c printcmd.c \ + symtab.c symfile.c symmisc.c infcmd.c infrun.c command.c utils.c \ + expprint.c environ.c gdbtypes.c copying.c i386-tdep.c i386-pinsn.c \ + freebsd-solib.c ser-unix.c exec.c fork-child.c infptrace.c inftarg.c \ + corelow.c coredep.c freebsd-nat.c remote.c dcache.c remote-utils.c \ + mem-break.c target.c putenv.c parse.c language.c buildsym.c \ + objfiles.c minsyms.c maint.c demangle.c dbxread.c coffread.c \ + elfread.c dwarfread.c mipsread.c stabsread.c core.c c-lang.c \ + ch-lang.c m2-lang.c complaints.c typeprint.c c-typeprint.c \ + ch-typeprint.c m2-typeprint.c c-valprint.c cp-valprint.c ch-valprint.c \ + m2-valprint.c nlmread.c serial.c inflow.c regex.c init.c \ + c-exp.tab.c ch-exp.tab.c m2-exp.tab.c version.c i386-dis.c dis-buf.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 y.tab.c + mv c-exp.new ./c-exp.tab.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 y.tab.c + mv 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 y.tab.c + mv m2-exp.new ./m2-exp.tab.c + + + +CFLAGS+= -I$(.CURDIR)/. -I/usr/include/readline -I$(.CURDIR)/../bfd +CFLAGS+= -DTRAD_CORE +LDADD+= -lreadline -ltermcap + +.if exists(${.CURDIR}/../libiberty/obj) +LDADD+= -L${.CURDIR}/../libiberty/obj -liberty +DPADD+= ${.CURDIR}/../libiberty/obj/libiberty.a +.else +LDADD+= -L${.CURDIR}/../libiberty/ -liberty +DPADD+= ${.CURDIR}/../libiberty/libiberty.a +.endif + +.if exists(${.CURDIR}/../bfd/obj) +LDADD+= -L${.CURDIR}/../bfd/obj -lbfd +DPADD+= ${.CURDIR}/../bfd/obj/libbfd.a +.else +LDADD+= -L${.CURDIR}/../bfd/ -lbfd +DPADD+= ${.CURDIR}/../bfd/libbfd.a +.endif + +.if exists(${.CURDIR}/../mmalloc/obj) +LDADD+= -L${.CURDIR}/../mmalloc/obj -lmmalloc +DPADD+= ${.CURDIR}/../mmalloc/obj/libmmalloc.a +.else +LDADD+= -L${.CURDIR}/../mmalloc/ -lmmalloc +DPADD+= ${.CURDIR}/../mmalloc/libmmalloc.a +.endif + + +.include diff --git a/gnu/usr.bin/gdb/gdb/ansidecl.h b/gnu/usr.bin/gdb/gdb/ansidecl.h new file mode 100644 index 00000000000..fdc4072120e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ansidecl.h @@ -0,0 +1,139 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +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. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + PTR `void *' `char *' + LONG_DOUBLE `long double' `double' + VOLATILE `volatile' `' + SIGNED `signed' `' + PTRCONST `void *const' `char *' + + CONST is also defined, but is obsolete. Just use const. + + DEFUN (name, arglist, args) + + Defines function NAME. + + ARGLIST lists the arguments, separated by commas and enclosed in + parentheses. ARGLIST becomes the argument list in traditional C. + + ARGS list the arguments with their types. It becomes a prototype in + ANSI C, and the type declarations in traditional C. Arguments should + be separated with `AND'. For functions with a variable number of + arguments, the last thing listed should be `DOTS'. + + DEFUN_VOID (name) + + Defines a function NAME, which takes no arguments. + + obsolete -- EXFUN (name, (prototype)) -- obsolete. + + Replaced by PARAMS. Do not use; will disappear someday soon. + Was used in external function declarations. + In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in + parentheses). In traditional C it is `NAME()'. + For a function that takes no arguments, PROTOTYPE should be `(void)'. + + PARAMS ((args)) + + We could use the EXFUN macro to handle prototype declarations, but + the name is misleading and the result is ugly. So we just define a + simple macro to handle the parameter lists, as in: + + static int foo PARAMS ((int, char)); + + This produces: `static int foo();' or `static int foo (int, char);' + + EXFUN would have done it like this: + + static int EXFUN (foo, (int, char)); + + but the function is not external...and it's hard to visually parse + the function name out of the mess. EXFUN should be considered + obsolete; new code should be written to use PARAMS. + + For example: + extern int printf PARAMS ((CONST char *format DOTS)); + int DEFUN(fprintf, (stream, format), + FILE *stream AND CONST char *format DOTS) { ... } + void DEFUN_VOID(abort) { ... } +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#define AND , +#define NOARGS void +#define CONST const +#define VOLATILE volatile +#define SIGNED signed +#define DOTS , ... + +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) + +#define PROTO(type, name, arglist) type name arglist +#define PARAMS(paramlist) paramlist + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define AND ; +#define NOARGS +#define CONST +#ifndef const /* some systems define it in header files for non-ansi mode */ +#define const +#endif +#define VOLATILE +#define SIGNED +#define DOTS + +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#define PROTO(type, name, arglist) type name () +#define PARAMS(paramlist) () + +#endif /* ANSI C. */ + +#endif /* ansidecl.h */ diff --git a/gnu/usr.bin/gdb/gdb/aout/aout64.h b/gnu/usr.bin/gdb/gdb/aout/aout64.h new file mode 100644 index 00000000000..018e6ddb068 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/aout64.h @@ -0,0 +1,431 @@ +/* `a.out' object-file definitions, including extensions to 64-bit fields */ + +#ifndef __A_OUT_64_H__ +#define __A_OUT_64_H__ + +/* This is the layout on disk of the 32-bit or 64-bit exec header. */ + +#ifndef external_exec +struct external_exec +{ + bfd_byte e_info[4]; /* magic number and stuff */ + bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */ + bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */ + bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */ + bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */ + bfd_byte e_entry[BYTES_IN_WORD]; /* start address */ + bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */ + bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */ +}; + +#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7) + +/* Magic numbers for a.out files */ + +#if ARCH_SIZE==64 +#define OMAGIC 0x1001 /* Code indicating object file */ +#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */ +#define NMAGIC 0x1003 /* Code indicating pure executable. */ + +/* There is no 64-bit QMAGIC as far as I know. */ + +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#else +#define OMAGIC 0407 /* ...object file or impure executable. */ +#define NMAGIC 0410 /* Code indicating pure executable. */ +#define ZMAGIC 0413 /* Code indicating demand-paged executable. */ + +/* This indicates a demand-paged executable with the header in the text. + As far as I know it is only used by 386BSD and/or BSDI. */ +#define QMAGIC 0314 +# ifndef N_BADMAG +# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC \ + && N_MAGIC(x) != QMAGIC) +# endif /* N_BADMAG */ +#endif + +#endif + +#ifdef QMAGIC +#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC) +#else +#define N_IS_QMAGIC(x) (0) +#endif + +/* The difference between PAGE_SIZE and N_SEGSIZE is that PAGE_SIZE is + the the finest granularity at which you can page something, thus it + controls the padding (if any) before the text segment of a ZMAGIC + file. N_SEGSIZE is the resolution at which things can be marked as + read-only versus read/write, so it controls the padding between the + text segment and the data segment (in memory; on disk the padding + between them is PAGE_SIZE). PAGE_SIZE and N_SEGSIZE are the same + for most machines, but different for sun3. */ + +/* By default, segment size is constant. But some machines override this + to be a function of the a.out header (e.g. machine type). */ + +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif + +/* Virtual memory address of the text section. + This is getting very complicated. A good reason to discard a.out format + for something that specifies these fields explicitly. But til then... + + * OMAGIC and NMAGIC files: + (object files: text for "relocatable addr 0" right after the header) + start at 0, offset is EXEC_BYTES_SIZE, size as stated. + * The text address, offset, and size of ZMAGIC files depend + on the entry point of the file: + * entry point below TEXT_START_ADDR: + (hack for SunOS shared libraries) + start at 0, offset is 0, size as stated. + * If N_HEADER_IN_TEXT(x) is true (which defaults to being the + case when the entry point is EXEC_BYTES_SIZE or further into a page): + no padding is needed; text can start after exec header. Sun + considers the text segment of such files to include the exec header; + for BFD's purposes, we don't, which makes more work for us. + start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE, + size as stated minus EXEC_BYTES_SIZE. + * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when + the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page + aligned)): (padding is needed so that text can start at a page boundary) + start at TEXT_START_ADDR, offset PAGE_SIZE, size as stated. + + Specific configurations may want to hardwire N_HEADER_IN_TEXT, + for efficiency or to allow people to play games with the entry point. + In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos, + and as 0 for most other hosts (Sony News, Vax Ultrix, etc). + (Do this in the appropriate bfd target file.) + (The default is a heuristic that will break if people try changing + the entry point, perhaps with the ld -e flag.) + + * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true, + and for which the starting address is PAGE_SIZE (or should this be + SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC). + */ + +/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header + in the text. */ +#ifndef N_HEADER_IN_TEXT +#define N_HEADER_IN_TEXT(x) (((x).a_entry & (PAGE_SIZE-1)) >= EXEC_BYTES_SIZE) +#endif + +/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC + files. */ +#ifndef N_SHARED_LIB +#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR) +#endif + +#ifndef N_TXTADDR +#define N_TXTADDR(x) \ + (/* The address of a QMAGIC file is always one page in, */ \ + /* with the header in the text. */ \ + N_IS_QMAGIC (x) ? PAGE_SIZE + EXEC_BYTES_SIZE : \ + N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\ + N_SHARED_LIB(x) ? 0 : \ + N_HEADER_IN_TEXT(x) ? \ + TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\ + TEXT_START_ADDR /* a page of padding */\ + ) +#endif + +/* Offset in an a.out of the start of the text section. */ +#ifndef N_TXTOFF +#define N_TXTOFF(x) \ + (/* For {O,N,Q}MAGIC, no padding. */ \ + N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \ + N_SHARED_LIB(x) ? 0 : \ + N_HEADER_IN_TEXT(x) ? \ + EXEC_BYTES_SIZE : /* no padding */\ + PAGE_SIZE /* a page of padding */\ + ) +#endif +/* Size of the text section. It's always as stated, except that we + offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF + for ZMAGIC files that nominally include the exec header + as part of the first page of text. (BFD doesn't consider the + exec header to be part of the text segment.) */ +#ifndef N_TXTSIZE +#define N_TXTSIZE(x) \ + (/* For QMAGIC, we don't consider the header part of the text section. */\ + N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \ + (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \ + N_HEADER_IN_TEXT(x) ? \ + (x).a_text - EXEC_BYTES_SIZE: /* no padding */\ + (x).a_text /* a page of padding */\ + ) +#endif +/* The address of the data segment in virtual memory. + It is the text segment address, plus text segment size, rounded + up to a N_SEGSIZE boundary for pure or pageable files. */ +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \ + : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1)))) +#endif +/* The address of the BSS segment -- immediately after the data segment. */ + +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + +/* Offsets of the various portions of the file after the text segment. */ + +/* For {N,Q,Z}MAGIC, there is padding to make the data segment start + on a page boundary. Most of the time the a_text field (and thus + N_TXTSIZE) already contains this padding. But if it doesn't (I + think maybe this happens on BSDI and/or 386BSD), then add it. */ + +#ifndef N_DATOFF +#define N_DATOFF(x) \ + (N_MAGIC(x) == OMAGIC ? N_TXTOFF(x) + N_TXTSIZE(x) : \ + PAGE_SIZE + ((N_TXTOFF(x) + N_TXTSIZE(x) - 1) & ~(PAGE_SIZE - 1))) +#endif + +#ifndef N_TRELOFF +#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) +#endif +#ifndef N_DRELOFF +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#endif +#ifndef N_SYMOFF +#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) +#endif +#ifndef N_STROFF +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#endif + +/* Symbols */ +#ifndef external_nlist +struct external_nlist { + bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */ + bfd_byte e_type[1]; /* type of symbol */ + bfd_byte e_other[1]; /* misc info (usually empty) */ + bfd_byte e_desc[2]; /* description field */ + bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */ +}; +#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD) +#endif + +struct internal_nlist { + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + bfd_vma n_value; /* value of symbol */ +}; + +/* The n_type field is the symbol type, containing: */ + +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol -- defined at particular addr */ +#define N_TEXT 4 /* Text sym -- defined at offset in text seg */ +#define N_DATA 6 /* Data sym -- defined at offset in data seg */ +#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */ +#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */ +#define N_FN 0x1f /* File name of .o file */ +#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */ +/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */ +#define N_TYPE 0x1e +#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */ + +#define N_INDR 0x0a + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + elements value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* Relocations + + There are two types of relocation flavours for a.out systems, + standard and extended. The standard form is used on systems where the + instruction has room for all the bits of an offset to the operand, whilst + the extended form is used when an address operand has to be split over n + instructions. Eg, on the 68k, each move instruction can reference + the target with a displacement of 16 or 32 bits. On the sparc, move + instructions use an offset of 14 bits, so the offset is stored in + the reloc field, and the data in the section is ignored. +*/ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct reloc_std_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ +}; + +#define RELOC_STD_BITS_PCREL_BIG 0x80 +#define RELOC_STD_BITS_PCREL_LITTLE 0x01 + +#define RELOC_STD_BITS_LENGTH_BIG 0x60 +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */ +#define RELOC_STD_BITS_LENGTH_LITTLE 0x06 +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG 0x10 +#define RELOC_STD_BITS_EXTERN_LITTLE 0x08 + +#define RELOC_STD_BITS_BASEREL_BIG 0x08 +#define RELOC_STD_BITS_BASEREL_LITTLE 0x08 + +#define RELOC_STD_BITS_JMPTABLE_BIG 0x04 +#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04 + +#define RELOC_STD_BITS_RELATIVE_BIG 0x02 +#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02 + +#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */ + +struct reloc_std_internal +{ + bfd_vma r_address; /* Address (within segment) to be relocated. */ + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in files the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ + unsigned int r_baserel:1; /* Linkage table relative */ + unsigned int r_jmptable:1; /* pc-relative to jump table */ + unsigned int r_relative:1; /* "relative relocation" */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero */ +}; + + +/* EXTENDED RELOCS */ + +struct reloc_ext_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ + bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */ +}; + +#define RELOC_EXT_BITS_EXTERN_BIG 0x80 +#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01 + +#define RELOC_EXT_BITS_TYPE_BIG 0x1F +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8 +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 + +/* Bytes per relocation entry */ +#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD) + +enum reloc_type +{ + /* simple relocations */ + RELOC_8, /* data[0:7] = addend + sv */ + RELOC_16, /* data[0:15] = addend + sv */ + RELOC_32, /* data[0:31] = addend + sv */ + /* pc-rel displacement */ + RELOC_DISP8, /* data[0:7] = addend - pc + sv */ + RELOC_DISP16, /* data[0:15] = addend - pc + sv */ + RELOC_DISP32, /* data[0:31] = addend - pc + sv */ + /* Special */ + RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */ + RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */ + RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */ + RELOC_22, /* data[0:21] = (addend + sv) */ + RELOC_13, /* data[0:12] = (addend + sv) */ + RELOC_LO10, /* data[0:9] = (addend + sv) */ + RELOC_SFA_BASE, + RELOC_SFA_OFF13, + /* P.I.C. (base-relative) */ + RELOC_BASE10, /* Not sure - maybe we can do this the */ + RELOC_BASE13, /* right way now */ + RELOC_BASE22, + /* for some sort of pc-rel P.I.C. (?) */ + RELOC_PC10, + RELOC_PC22, + /* P.I.C. jump table */ + RELOC_JMP_TBL, + /* reputedly for shared libraries somehow */ + RELOC_SEGOFF16, + RELOC_GLOB_DAT, + RELOC_JMP_SLOT, + RELOC_RELATIVE, + + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */ + RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */ + + /* 29K relocation types */ + RELOC_JUMPTARG, + RELOC_CONST, + RELOC_CONSTH, + + + /* Q . + What are the other ones, + Since this is a clean slate, can we throw away the ones we dont + understand ? Should we sort the values ? What about using a + microcode format like the 68k ? + */ + NO_RELOC + }; + + +struct reloc_internal { + bfd_vma r_address; /* offset of of data to relocate */ + long r_index; /* symbol table index of symbol */ + enum reloc_type r_type; /* relocation type */ + bfd_vma r_addend; /* datum addend */ +}; + +/* Q. + Should the length of the string table be 4 bytes or 8 bytes ? + + Q. + What about archive indexes ? + + */ + +#endif /* __A_OUT_64_H__ */ diff --git a/gnu/usr.bin/gdb/gdb/aout/ar.h b/gnu/usr.bin/gdb/gdb/aout/ar.h new file mode 100644 index 00000000000..cca636d8193 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/ar.h @@ -0,0 +1,32 @@ +/* archive file definition for GNU software */ + +/* So far this is correct for BSDish archives. Don't forget that + files must begin on an even byte boundary. */ + +#ifndef __GNU_AR_H__ +#define __GNU_AR_H__ + +#define ARMAG "!\n" /* For COFF and a.out archives */ +#define ARMAGB "!\n" /* For b.out archives */ +#define SARMAG 8 +#define ARFMAG "`\n" + +/* The ar_date field of the armap (__.SYMDEF) member of an archive + must be greater than the modified date of the entire file, or + BSD-derived linkers complain. We originally write the ar_date with + this offset from the real file's mod-time. After finishing the + file, we rewrite ar_date if it's not still greater than the mod date. */ + +#define ARMAP_TIME_OFFSET 60 + +struct ar_hdr { + char ar_name[16]; /* name of this member */ + char ar_date[12]; /* file mtime */ + char ar_uid[6]; /* owner uid; printed as decimal */ + char ar_gid[6]; /* owner gid; printed as decimal */ + char ar_mode[8]; /* file mode, printed as octal */ + char ar_size[10]; /* file size, printed as decimal */ + char ar_fmag[2]; /* should contain ARFMAG */ +}; + +#endif /* __GNU_AR_H__ */ diff --git a/gnu/usr.bin/gdb/gdb/aout/ranlib.h b/gnu/usr.bin/gdb/gdb/aout/ranlib.h new file mode 100644 index 00000000000..53e35ce2e0e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/ranlib.h @@ -0,0 +1,62 @@ +/* ranlib.h -- archive library index member definition for GNU. + Copyright 1990-1991 Free Software Foundation, Inc. + +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. */ + +/* The Symdef member of an archive contains two things: + a table that maps symbol-string offsets to file offsets, + and a symbol-string table. All the symbol names are + run together (each with trailing null) in the symbol-string + table. There is a single longword bytecount on the front + of each of these tables. Thus if we have two symbols, + "foo" and "_bar", that are in archive members at offsets + 200 and 900, it would look like this: + 16 ; byte count of index table + 0 ; offset of "foo" in string table + 200 ; offset of foo-module in file + 4 ; offset of "bar" in string table + 900 ; offset of bar-module in file + 9 ; byte count of string table + "foo\0_bar\0" ; string table */ + +#define RANLIBMAG "__.SYMDEF" /* Archive file name containing index */ +#define RANLIBSKEW 3 /* Creation time offset */ + +/* Format of __.SYMDEF: + First, a longword containing the size of the 'symdef' data that follows. + Second, zero or more 'symdef' structures. + Third, a longword containing the length of symbol name strings. + Fourth, zero or more symbol name strings (each followed by a null). */ + +struct symdef + { + union + { + unsigned long string_offset; /* In the file */ + char *name; /* In memory, sometimes */ + } s; + /* this points to the front of the file header (AKA member header -- + a struct ar_hdr), not to the front of the file or into the file). + in other words it only tells you which file to read */ + unsigned long file_offset; + }; + +/* Compatability with BSD code */ + +#define ranlib symdef +#define ran_un s +#define ran_strx string_offset +#define ran_name name +#define ran_off file_offset diff --git a/gnu/usr.bin/gdb/gdb/aout/stab.def b/gnu/usr.bin/gdb/gdb/aout/stab.def new file mode 100644 index 00000000000..9d1da7d6eb8 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/stab.def @@ -0,0 +1,264 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988, 1991 Free Software Foundation, Inc. + +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. */ + +/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files + overlaps the N_UNDF used for ordinary symbols. In ELF files, the + debug information is in a different file section, so there is no conflict. + This symbol's n_value gives the size of the string section associated + with this file. The symbol's n_strx (relative to the just-updated + string section start address) gives the name of the source file, + e.g. "foo.c", without any path information. The symbol's n_desc gives + the count of upcoming symbols associated with this file (not including + this one). */ +/* __define_stab (N_UNDF, 0x00, "UNDF") */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. + "Static Sym". */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Solaris2: Read-only data symbols. */ +__define_stab (N_ROSYM, 0x2c, "ROSYM") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ +__define_stab (N_NSYMS, 0x32, "NSYMS") + +/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ +__define_stab (N_NOMAP, 0x34, "NOMAP") + +/* New stab from Solaris 2. Like N_SO, but for the object file. Two in + a row provide the build directory and the relative path of the .o from it. + Solaris2 uses this to avoid putting the stabs info into the linked + executable; this stab goes into the ".stab.index" section, and the debugger + reads the real stabs directly from the .o files instead. */ +__define_stab (N_OBJ, 0x38, "OBJ") + +/* New stab from Solaris 2. Options for the debugger, related to the + source language for this module. E.g. whether to use ANSI + integral promotions or traditional integral promotions. */ +__define_stab (N_OPT, 0x3c, "OPT") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. On Solaris2, the line number is + relative to the start of the current function. */ +__define_stab (N_SLINE, 0x44, "SLINE") + +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") + +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". THIS VALUE + OVERLAPS WITH N_BSLINE! */ +__define_stab (N_BROWS, 0x48, "BROWS") + +/* GNU Modula-2 definition module dependency. Value is the modification time + of the definition file. Other is non-zero if it is imported with the + GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there + are enough empty fields? */ +__define_stab(N_DEFD, 0x4a, "DEFD") + +/* New in Solaris2. Function start/body/end line numbers. */ +__define_stab(N_FLINE, 0x4C, "FLINE") + +/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 + and one is for C++. Still,... */ +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") +/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ +__define_stab (N_MOD2, 0x50, "MOD2") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Solaris2: Last stab emitted for module. */ +__define_stab (N_ENDM, 0x62, "ENDM") + +/* Name of main source file. + Value is starting text address of the compilation. + If multiple N_SO's appear, the first to contain a trailing / is the + compilation directory. The first to not contain a trailing / is the + source file name, relative to the compilation directory. Others (perhaps + resulting from cfront) are ignored. + On Solaris2, value is undefined, but desc is a source-language code. */ + +__define_stab (N_SO, 0x64, "SO") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") + +/* Name of sub-source file (#include file). + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* End of an include file. No name. + This and N_BINCL act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") + +/* Place holder for deleted include file. Replaces a N_BINCL and everything + up to the corresponding N_EINCL. The Sun linker generates these when + it finds multiple identical copies of the symbols from an include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") + +/* End named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") + +/* Member of a common block; value is offset within the common block. + This should occur within a BCOMM/ECOMM pair. */ +__define_stab (N_ECOML, 0xe8, "ECOML") + +/* Solaris2: Pascal "with" statement: type,,0,0,offset */ +__define_stab (N_WITH, 0xea, "WITH") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") + +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | In most cases, the low bit is the EXTernal bit| + + | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | + | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + + | 08 BSS | 0A INDR | 0C FN_SEQ | 0E | + | 09 |EXT | 0B | 0D | 0F | + + | 10 | 12 COMM | 14 SETA | 16 SETT | + | 11 | 13 | 15 | 17 | + + | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| + | 19 | 1B | 1D | 1F FN | + + |_______________________________________________| + | Debug entries with bit 01 set are unused. | + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E | + | 30 PC | 32 NSYMS | 34 NOMAP | 36 | + | 38 OBJ | 3A | 3C OPT | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | + | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E | + | 50 EHDECL*| 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 ENDM | 64 SO | 66 | + | 68 | 6A | 6C | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA WITH | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + * 50 EHDECL is also MOD2. + * 48 BSLINE is also BROWS. + */ diff --git a/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h b/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h new file mode 100644 index 00000000000..477b87d6d86 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/stab_gnu.h @@ -0,0 +1,36 @@ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "aout/stab.def" +LAST_UNUSED_STAB_CODE +}; + +#undef __define_stab + +/* Definitions of "desc" field for N_SO stabs in Solaris2. */ + +#define N_SO_AS 1 +#define N_SO_C 2 +#define N_SO_ANSI_C 3 +#define N_SO_CC 4 /* C++ */ +#define N_SO_FORTRAN 5 +#define N_SO_PASCAL 6 + +/* Solaris2: Floating point type values in basic types. */ + +#define NF_NONE 0 +#define NF_SINGLE 1 /* IEEE 32-bit */ +#define NF_DOUBLE 2 /* IEEE 64-bit */ +#define NF_COMPLEX 3 /* Fortran complex */ +#define NF_COMPLEX16 4 /* Fortran double complex */ +#define NF_COMPLEX32 5 /* Fortran complex*16 */ +#define NF_LDOUBLE 6 /* Long double (whatever that is) */ + +#endif /* __GNU_STAB_ */ diff --git a/gnu/usr.bin/gdb/gdb/blockframe.c b/gnu/usr.bin/gdb/gdb/blockframe.c new file mode 100644 index 00000000000..c7b3fdce26b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/blockframe.c @@ -0,0 +1,821 @@ +/* Get info from stack frames; + convert between frames, blocks, functions and pc values. + Copyright 1986, 1987, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "frame.h" +#include "gdbcore.h" +#include "value.h" /* for read_register */ +#include "target.h" /* for target_has_stack */ +#include "inferior.h" /* for read_pc */ + +/* Is ADDR inside the startup file? Note that if your machine + has a way to detect the bottom of the stack, there is no need + to call this function from FRAME_CHAIN_VALID; the reason for + doing so is that some machines have no way of detecting bottom + of stack. + + A PC of zero is always considered to be the bottom of the stack. */ + +int +inside_entry_file (addr) + CORE_ADDR addr; +{ + if (addr == 0) + return 1; + if (symfile_objfile == 0) + return 0; +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + /* Do not stop backtracing if the pc is in the call dummy + at the entry point. */ + if (PC_IN_CALL_DUMMY (addr, 0, 0)) + return 0; +#endif + return (addr >= symfile_objfile -> ei.entry_file_lowpc && + addr < symfile_objfile -> ei.entry_file_highpc); +} + +/* Test a specified PC value to see if it is in the range of addresses + that correspond to the main() function. See comments above for why + we might want to do this. + + Typically called from FRAME_CHAIN_VALID. + + A PC of zero is always considered to be the bottom of the stack. */ + +int +inside_main_func (pc) +CORE_ADDR pc; +{ + if (pc == 0) + return 1; + if (symfile_objfile == 0) + return 0; + return (symfile_objfile -> ei.main_func_lowpc <= pc && + symfile_objfile -> ei.main_func_highpc > pc); +} + +/* Test a specified PC value to see if it is in the range of addresses + that correspond to the process entry point function. See comments + in objfiles.h for why we might want to do this. + + Typically called from FRAME_CHAIN_VALID. + + A PC of zero is always considered to be the bottom of the stack. */ + +int +inside_entry_func (pc) +CORE_ADDR pc; +{ + if (pc == 0) + return 1; + if (symfile_objfile == 0) + return 0; +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + /* Do not stop backtracing if the pc is in the call dummy + at the entry point. */ + if (PC_IN_CALL_DUMMY (pc, 0, 0)) + return 0; +#endif + return (symfile_objfile -> ei.entry_func_lowpc <= pc && + symfile_objfile -> ei.entry_func_highpc > pc); +} + +/* Address of innermost stack frame (contents of FP register) */ + +static FRAME current_frame; + +/* + * Cache for frame addresses already read by gdb. Valid only while + * inferior is stopped. Control variables for the frame cache should + * be local to this module. + */ +struct obstack frame_cache_obstack; + +/* Return the innermost (currently executing) stack frame. */ + +FRAME +get_current_frame () +{ + /* We assume its address is kept in a general register; + param.h says which register. */ + + return current_frame; +} + +void +set_current_frame (frame) + FRAME frame; +{ + current_frame = frame; +} + +FRAME +create_new_frame (addr, pc) + FRAME_ADDR addr; + CORE_ADDR pc; +{ + struct frame_info *fci; /* Same type as FRAME */ + char *name; + + fci = (struct frame_info *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_info)); + + /* Arbitrary frame */ + fci->next = (struct frame_info *) 0; + fci->prev = (struct frame_info *) 0; + fci->frame = addr; + fci->pc = pc; + find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + fci->signal_handler_caller = IN_SIGTRAMP (fci->pc, name); + +#ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO (0, fci); +#endif + + return fci; +} + +/* Return the frame that called FRAME. + If FRAME is the original frame (it has no caller), return 0. */ + +FRAME +get_prev_frame (frame) + FRAME frame; +{ + /* We're allowed to know that FRAME and "struct frame_info *" are + the same */ + return get_prev_frame_info (frame); +} + +/* Return the frame that FRAME calls (0 if FRAME is the innermost + frame). */ + +FRAME +get_next_frame (frame) + FRAME frame; +{ + /* We're allowed to know that FRAME and "struct frame_info *" are + the same */ + return frame->next; +} + +/* + * Flush the entire frame cache. + */ +void +flush_cached_frames () +{ + /* Since we can't really be sure what the first object allocated was */ + obstack_free (&frame_cache_obstack, 0); + obstack_init (&frame_cache_obstack); + + current_frame = (struct frame_info *) 0; /* Invalidate cache */ +} + +/* Flush the frame cache, and start a new one if necessary. */ +void +reinit_frame_cache () +{ + flush_cached_frames (); + if (target_has_stack) + { + set_current_frame (create_new_frame (read_fp (), read_pc ())); + select_frame (get_current_frame (), 0); + } + else + { + set_current_frame (0); + select_frame ((FRAME) 0, -1); + } +} + +/* Return a structure containing various interesting information + about a specified stack frame. */ +/* How do I justify including this function? Well, the FRAME + identifier format has gone through several changes recently, and + it's not completely inconceivable that it could happen again. If + it does, have this routine around will help */ + +struct frame_info * +get_frame_info (frame) + FRAME frame; +{ + return frame; +} + +/* If a machine allows frameless functions, it should define a macro + FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct + frame_info for the frame, and FRAMELESS should be set to nonzero + if it represents a frameless function invocation. */ + +/* Return nonzero if the function for this frame lacks a prologue. Many + machines can define FRAMELESS_FUNCTION_INVOCATION to just call this + function. */ + +int +frameless_look_for_prologue (frame) + FRAME frame; +{ + CORE_ADDR func_start, after_prologue; + func_start = (get_pc_function_start (frame->pc) + + FUNCTION_START_OFFSET); + if (func_start) + { + after_prologue = func_start; +#ifdef SKIP_PROLOGUE_FRAMELESS_P + /* This is faster, since only care whether there *is* a prologue, + not how long it is. */ + SKIP_PROLOGUE_FRAMELESS_P (after_prologue); +#else + SKIP_PROLOGUE (after_prologue); +#endif + return after_prologue == func_start; + } + else + /* If we can't find the start of the function, we don't really + know whether the function is frameless, but we should be able + to get a reasonable (i.e. best we can do under the + circumstances) backtrace by saying that it isn't. */ + return 0; +} + +/* Default a few macros that people seldom redefine. */ + +#if !defined (INIT_FRAME_PC) +#define INIT_FRAME_PC(fromleaf, prev) \ + prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \ + prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ()); +#endif + +#ifndef FRAME_CHAIN_COMBINE +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) +#endif + +/* Return a structure containing various interesting information + about the frame that called NEXT_FRAME. Returns NULL + if there is no such frame. */ + +struct frame_info * +get_prev_frame_info (next_frame) + FRAME next_frame; +{ + FRAME_ADDR address = 0; + struct frame_info *prev; + int fromleaf = 0; + char *name; + + /* If the requested entry is in the cache, return it. + Otherwise, figure out what the address should be for the entry + we're about to add to the cache. */ + + if (!next_frame) + { +#if 0 + /* This screws value_of_variable, which just wants a nice clean + NULL return from block_innermost_frame if there are no frames. + I don't think I've ever seen this message happen otherwise. + And returning NULL here is a perfectly legitimate thing to do. */ + if (!current_frame) + { + error ("You haven't set up a process's stack to examine."); + } +#endif + + return current_frame; + } + + /* If we have the prev one, return it */ + if (next_frame->prev) + return next_frame->prev; + + /* On some machines it is possible to call a function without + setting up a stack frame for it. On these machines, we + define this macro to take two args; a frameinfo pointer + identifying a frame and a variable to set or clear if it is + or isn't leafless. */ +#ifdef FRAMELESS_FUNCTION_INVOCATION + /* Still don't want to worry about this except on the innermost + frame. This macro will set FROMLEAF if NEXT_FRAME is a + frameless function invocation. */ + if (!(next_frame->next)) + { + FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf); + if (fromleaf) + address = next_frame->frame; + } +#endif + + if (!fromleaf) + { + /* Two macros defined in tm.h specify the machine-dependent + actions to be performed here. + First, get the frame's chain-pointer. + If that is zero, the frame is the outermost frame or a leaf + called by the outermost frame. This means that if start + calls main without a frame, we'll return 0 (which is fine + anyway). + + Nope; there's a problem. This also returns when the current + routine is a leaf of main. This is unacceptable. We move + this to after the ffi test; I'd rather have backtraces from + start go curfluy than have an abort called from main not show + main. */ + address = FRAME_CHAIN (next_frame); + if (!FRAME_CHAIN_VALID (address, next_frame)) + return 0; + address = FRAME_CHAIN_COMBINE (address, next_frame); + } + if (address == 0) + return 0; + + prev = (struct frame_info *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_info)); + + if (next_frame) + next_frame->prev = prev; + prev->next = next_frame; + prev->prev = (struct frame_info *) 0; + prev->frame = address; + prev->signal_handler_caller = 0; + +/* This change should not be needed, FIXME! We should + determine whether any targets *need* INIT_FRAME_PC to happen + after INIT_EXTRA_FRAME_INFO and come up with a simple way to + express what goes on here. + + INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame + (where the PC is already set up) and here (where it isn't). + INIT_FRAME_PC is only called from here, always after + INIT_EXTRA_FRAME_INFO. + + The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the PC + value (which hasn't been set yet). Some other machines appear to + require INIT_EXTRA_FRAME_INFO before they can do INIT_FRAME_PC. Phoo. + + We shouldn't need INIT_FRAME_PC_FIRST to add more complication to + an already overcomplicated part of GDB. gnu@cygnus.com, 15Sep92. + + To answer the question, yes the sparc needs INIT_FRAME_PC after + INIT_EXTRA_FRAME_INFO. Suggested scheme: + + SETUP_INNERMOST_FRAME() + Default version is just create_new_frame (read_fp ()), + read_pc ()). Machines with extra frame info would do that (or the + local equivalent) and then set the extra fields. + SETUP_ARBITRARY_FRAME(argc, argv) + Only change here is that create_new_frame would no longer init extra + frame info; SETUP_ARBITRARY_FRAME would have to do that. + INIT_PREV_FRAME(fromleaf, prev) + Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC. + std_frame_pc(fromleaf, prev) + This is the default setting for INIT_PREV_FRAME. It just does what + the default INIT_FRAME_PC does. Some machines will call it from + INIT_PREV_FRAME (either at the beginning, the end, or in the middle). + Some machines won't use it. + kingdon@cygnus.com, 13Apr93. */ + +#ifdef INIT_FRAME_PC_FIRST + INIT_FRAME_PC_FIRST (fromleaf, prev); +#endif + +#ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO(fromleaf, prev); +#endif + + /* This entry is in the frame queue now, which is good since + FRAME_SAVED_PC may use that queue to figure out it's value + (see tm-sparc.h). We want the pc saved in the inferior frame. */ + INIT_FRAME_PC(fromleaf, prev); + + find_pc_partial_function (prev->pc, &name, + (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + if (IN_SIGTRAMP (prev->pc, name)) + prev->signal_handler_caller = 1; + + return prev; +} + +CORE_ADDR +get_frame_pc (frame) + FRAME frame; +{ + struct frame_info *fi; + fi = get_frame_info (frame); + return fi->pc; +} + +#if defined (FRAME_FIND_SAVED_REGS) +/* Find the addresses in which registers are saved in FRAME. */ + +void +get_frame_saved_regs (frame_info_addr, saved_regs_addr) + struct frame_info *frame_info_addr; + struct frame_saved_regs *saved_regs_addr; +{ + FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr); +} +#endif + +/* Return the innermost lexical block in execution + in a specified stack frame. The frame address is assumed valid. */ + +struct block * +get_frame_block (frame) + FRAME frame; +{ + struct frame_info *fi; + CORE_ADDR pc; + + fi = get_frame_info (frame); + + pc = fi->pc; + if (fi->next != 0 && fi->next->signal_handler_caller == 0) + /* We are not in the innermost frame and we were not interrupted + by a signal. We need to subtract one to get the correct block, + in case the call instruction was the last instruction of the block. + If there are any machines on which the saved pc does not point to + after the call insn, we probably want to make fi->pc point after + the call insn anyway. */ + --pc; + return block_for_pc (pc); +} + +struct block * +get_current_block () +{ + return block_for_pc (read_pc ()); +} + +CORE_ADDR +get_pc_function_start (pc) + CORE_ADDR pc; +{ + register struct block *bl; + register struct symbol *symbol; + register struct minimal_symbol *msymbol; + CORE_ADDR fstart; + + if ((bl = block_for_pc (pc)) != NULL && + (symbol = block_function (bl)) != NULL) + { + bl = SYMBOL_BLOCK_VALUE (symbol); + fstart = BLOCK_START (bl); + } + else if ((msymbol = lookup_minimal_symbol_by_pc (pc)) != NULL) + { + fstart = SYMBOL_VALUE_ADDRESS (msymbol); + } + else + { + fstart = 0; + } + return (fstart); +} + +/* Return the symbol for the function executing in frame FRAME. */ + +struct symbol * +get_frame_function (frame) + FRAME frame; +{ + register struct block *bl = get_frame_block (frame); + if (bl == 0) + return 0; + return block_function (bl); +} + +/* Return the blockvector immediately containing the innermost lexical block + containing the specified pc value, or 0 if there is none. + PINDEX is a pointer to the index value of the block. If PINDEX + is NULL, we don't pass this information back to the caller. */ + +struct blockvector * +blockvector_for_pc (pc, pindex) + register CORE_ADDR pc; + int *pindex; +{ + register struct block *b; + register int bot, top, half; + register struct symtab *s; + struct blockvector *bl; + + /* First search all symtabs for one whose file contains our pc */ + s = find_pc_symtab (pc); + if (s == 0) + return 0; + + bl = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bl, 0); + + /* Then search that symtab for the smallest block that wins. */ + /* Use binary search to find the last block that starts before PC. */ + + bot = 0; + top = BLOCKVECTOR_NBLOCKS (bl); + + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + b = BLOCKVECTOR_BLOCK (bl, bot + half); + if (BLOCK_START (b) <= pc) + bot += half; + else + top = bot + half; + } + + /* Now search backward for a block that ends after PC. */ + + while (bot >= 0) + { + b = BLOCKVECTOR_BLOCK (bl, bot); + if (BLOCK_END (b) > pc) + { + if (pindex) + *pindex = bot; + return bl; + } + bot--; + } + + return 0; +} + +/* Return the innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +struct block * +block_for_pc (pc) + register CORE_ADDR pc; +{ + register struct blockvector *bl; + int index; + + bl = blockvector_for_pc (pc, &index); + if (bl) + return BLOCKVECTOR_BLOCK (bl, index); + return 0; +} + +/* Return the function containing pc value PC. + Returns 0 if function is not known. */ + +struct symbol * +find_pc_function (pc) + CORE_ADDR pc; +{ + register struct block *b = block_for_pc (pc); + if (b == 0) + return 0; + return block_function (b); +} + +/* These variables are used to cache the most recent result + * of find_pc_partial_function. */ + +static CORE_ADDR cache_pc_function_low = 0; +static CORE_ADDR cache_pc_function_high = 0; +static char *cache_pc_function_name = 0; + +/* Clear cache, e.g. when symbol table is discarded. */ + +void +clear_pc_function_cache() +{ + cache_pc_function_low = 0; + cache_pc_function_high = 0; + cache_pc_function_name = (char *)0; +} + +/* Finds the "function" (text symbol) that is smaller than PC but + greatest of all of the potential text symbols. Sets *NAME and/or + *ADDRESS conditionally if that pointer is non-null. If ENDADDR is + non-null, then set *ENDADDR to be the end of the function + (exclusive), but passing ENDADDR as non-null means that the + function might cause symbols to be read. This function either + succeeds or fails (not halfway succeeds). If it succeeds, it sets + *NAME, *ADDRESS, and *ENDADDR to real information and returns 1. + If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero + and returns 0. */ + +int +find_pc_partial_function (pc, name, address, endaddr) + CORE_ADDR pc; + char **name; + CORE_ADDR *address; + CORE_ADDR *endaddr; +{ + struct partial_symtab *pst; + struct symbol *f; + struct minimal_symbol *msymbol; + struct partial_symbol *psb; + struct obj_section *sec; + + if (pc >= cache_pc_function_low && pc < cache_pc_function_high) + goto return_cached_value; + + /* If sigtramp is in the u area, it counts as a function (especially + important for step_1). */ +#if defined SIGTRAMP_START + if (IN_SIGTRAMP (pc, (char *)NULL)) + { + cache_pc_function_low = SIGTRAMP_START; + cache_pc_function_high = SIGTRAMP_END; + cache_pc_function_name = ""; + + goto return_cached_value; + } +#endif + + msymbol = lookup_minimal_symbol_by_pc (pc); + pst = find_pc_psymtab (pc); + if (pst) + { + /* Need to read the symbols to get a good value for the end address. */ + if (endaddr != NULL && !pst->readin) + { + /* Need to get the terminal in case symbol-reading produces + output. */ + target_terminal_ours_for_output (); + PSYMTAB_TO_SYMTAB (pst); + } + + if (pst->readin) + { + /* Checking whether the msymbol has a larger value is for the + "pathological" case mentioned in print_frame_info. */ + f = find_pc_function (pc); + if (f != NULL + && (msymbol == NULL + || (BLOCK_START (SYMBOL_BLOCK_VALUE (f)) + >= SYMBOL_VALUE_ADDRESS (msymbol)))) + { + cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_name = SYMBOL_NAME (f); + goto return_cached_value; + } + } + else + { + /* Now that static symbols go in the minimal symbol table, perhaps + we could just ignore the partial symbols. But at least for now + we use the partial or minimal symbol, whichever is larger. */ + psb = find_pc_psymbol (pst, pc); + + if (psb + && (msymbol == NULL || + (SYMBOL_VALUE_ADDRESS (psb) + >= SYMBOL_VALUE_ADDRESS (msymbol)))) + { + /* This case isn't being cached currently. */ + if (address) + *address = SYMBOL_VALUE_ADDRESS (psb); + if (name) + *name = SYMBOL_NAME (psb); + /* endaddr non-NULL can't happen here. */ + return 1; + } + } + } + + /* Not in the normal symbol tables, see if the pc is in a known section. + If it's not, then give up. This ensures that anything beyond the end + of the text seg doesn't appear to be part of the last function in the + text segment. */ + + sec = find_pc_section (pc); + + if (!sec) + msymbol = NULL; + + /* Must be in the minimal symbol table. */ + if (msymbol == NULL) + { + /* No available symbol. */ + if (name != NULL) + *name = 0; + if (address != NULL) + *address = 0; + if (endaddr != NULL) + *endaddr = 0; + return 0; + } + + /* See if we're in a transfer table for Sun shared libs. */ + + if (msymbol -> type == mst_text) + cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); + else + /* It is a transfer table for Sun shared libraries. */ + cache_pc_function_low = pc - FUNCTION_START_OFFSET; + + cache_pc_function_name = SYMBOL_NAME (msymbol); + + /* Use the lesser of the next minimal symbol, or the end of the section, as + the end of the function. */ + + if (SYMBOL_NAME (msymbol + 1) != NULL + && SYMBOL_VALUE_ADDRESS (msymbol + 1) < sec->endaddr) + cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + 1); + else + /* We got the start address from the last msymbol in the objfile. + So the end address is the end of the section. */ + cache_pc_function_high = sec->endaddr; + + return_cached_value: + if (address) + *address = cache_pc_function_low; + if (name) + *name = cache_pc_function_name; + if (endaddr) + *endaddr = cache_pc_function_high; + return 1; +} + +/* Return the innermost stack frame executing inside of BLOCK, + or NULL if there is no such frame. If BLOCK is NULL, just return NULL. */ + +FRAME +block_innermost_frame (block) + struct block *block; +{ + struct frame_info *fi; + register FRAME frame; + register CORE_ADDR start; + register CORE_ADDR end; + + if (block == NULL) + return NULL; + + start = BLOCK_START (block); + end = BLOCK_END (block); + + frame = 0; + while (1) + { + frame = get_prev_frame (frame); + if (frame == 0) + return 0; + fi = get_frame_info (frame); + if (fi->pc >= start && fi->pc < end) + return frame; + } +} + +#ifdef SIGCONTEXT_PC_OFFSET +/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */ + +CORE_ADDR +sigtramp_saved_pc (frame) + FRAME frame; +{ + CORE_ADDR sigcontext_addr; + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT; + int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT; + + /* Get sigcontext address, it is the third parameter on the stack. */ + if (frame->next) + sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next) + + FRAME_ARGS_SKIP + sigcontext_offs, + ptrbytes); + else + sigcontext_addr = read_memory_integer (read_register (SP_REGNUM) + + sigcontext_offs, + ptrbytes); + + /* Don't cause a memory_error when accessing sigcontext in case the stack + layout has changed or the stack is corrupt. */ + target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes); + return extract_unsigned_integer (buf, ptrbytes); +} +#endif /* SIGCONTEXT_PC_OFFSET */ + +void +_initialize_blockframe () +{ + obstack_init (&frame_cache_obstack); +} diff --git a/gnu/usr.bin/gdb/gdb/breakpoint.c b/gnu/usr.bin/gdb/gdb/breakpoint.c new file mode 100644 index 00000000000..69694c016f6 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/breakpoint.c @@ -0,0 +1,3301 @@ +/* Everything about breakpoints, for GDB. + Copyright 1986, 1987, 1989, 1990, 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. */ + +#include "defs.h" +#include +#include "symtab.h" +#include "frame.h" +#include "breakpoint.h" +#include "gdbtypes.h" +#include "expression.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "value.h" +#include "ctype.h" +#include "command.h" +#include "inferior.h" +#include "target.h" +#include "language.h" +#include +#include "demangle.h" + +/* local function prototypes */ + +static void +catch_command_1 PARAMS ((char *, int, int)); + +static void +enable_delete_command PARAMS ((char *, int)); + +static void +enable_delete_breakpoint PARAMS ((struct breakpoint *)); + +static void +enable_once_command PARAMS ((char *, int)); + +static void +enable_once_breakpoint PARAMS ((struct breakpoint *)); + +static void +disable_command PARAMS ((char *, int)); + +static void +disable_breakpoint PARAMS ((struct breakpoint *)); + +static void +enable_command PARAMS ((char *, int)); + +static void +enable_breakpoint PARAMS ((struct breakpoint *)); + +static void +map_breakpoint_numbers PARAMS ((char *, void (*)(struct breakpoint *))); + +static void +ignore_command PARAMS ((char *, int)); + +static int +breakpoint_re_set_one PARAMS ((char *)); + +static void +delete_command PARAMS ((char *, int)); + +static void +clear_command PARAMS ((char *, int)); + +static void +catch_command PARAMS ((char *, int)); + +static struct symtabs_and_lines +get_catch_sals PARAMS ((int)); + +static void +watch_command PARAMS ((char *, int)); + +static void +tbreak_command PARAMS ((char *, int)); + +static void +break_command_1 PARAMS ((char *, int, int)); + +static void +mention PARAMS ((struct breakpoint *)); + +static struct breakpoint * +set_raw_breakpoint PARAMS ((struct symtab_and_line)); + +static void +check_duplicates PARAMS ((CORE_ADDR)); + +static void +describe_other_breakpoints PARAMS ((CORE_ADDR)); + +static void +breakpoints_info PARAMS ((char *, int)); + +static void +breakpoint_1 PARAMS ((int, int)); + +static bpstat +bpstat_alloc PARAMS ((struct breakpoint *, bpstat)); + +static int +breakpoint_cond_eval PARAMS ((char *)); + +static void +cleanup_executing_breakpoints PARAMS ((int)); + +static void +commands_command PARAMS ((char *, int)); + +static void +condition_command PARAMS ((char *, int)); + +static int +get_number PARAMS ((char **)); + +static void +set_breakpoint_count PARAMS ((int)); + + +extern int addressprint; /* Print machine addresses? */ +extern int demangle; /* Print de-mangled symbol names? */ + +/* Are we executing breakpoint commands? */ +static int executing_breakpoint_commands; + +/* Walk the following statement or block through all breakpoints. + ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current + breakpoint. */ + +#define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next) + +#define ALL_BREAKPOINTS_SAFE(b,tmp) \ + for (b = breakpoint_chain; \ + b? (tmp=b->next, 1): 0; \ + b = tmp) + +/* Chain of all breakpoints defined. */ + +struct breakpoint *breakpoint_chain; + +/* Number of last breakpoint made. */ + +static int breakpoint_count; + +/* Set breakpoint count to NUM. */ +static void +set_breakpoint_count (num) + int num; +{ + breakpoint_count = num; + set_internalvar (lookup_internalvar ("bpnum"), + value_from_longest (builtin_type_int, (LONGEST) num)); +} + +/* Default address, symtab and line to put a breakpoint at + for "break" command with no arg. + if default_breakpoint_valid is zero, the other three are + not valid, and "break" with no arg is an error. + + This set by print_stack_frame, which calls set_default_breakpoint. */ + +int default_breakpoint_valid; +CORE_ADDR default_breakpoint_address; +struct symtab *default_breakpoint_symtab; +int default_breakpoint_line; + +/* Flag indicating extra verbosity for xgdb. */ +extern int xgdb_verbose; + +/* *PP is a string denoting a breakpoint. Get the number of the breakpoint. + Advance *PP after the string and any trailing whitespace. + + Currently the string can either be a number or "$" followed by the name + of a convenience variable. Making it an expression wouldn't work well + for map_breakpoint_numbers (e.g. "4 + 5 + 6"). */ +static int +get_number (pp) + char **pp; +{ + int retval; + char *p = *pp; + + if (p == NULL) + /* Empty line means refer to the last breakpoint. */ + return breakpoint_count; + else if (*p == '$') + { + /* Make a copy of the name, so we can null-terminate it + to pass to lookup_internalvar(). */ + char *varname; + char *start = ++p; + value val; + + while (isalnum (*p) || *p == '_') + p++; + varname = (char *) alloca (p - start + 1); + strncpy (varname, start, p - start); + varname[p - start] = '\0'; + val = value_of_internalvar (lookup_internalvar (varname)); + if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_INT) + error ( +"Convenience variables used to specify breakpoints must have integer values." + ); + retval = (int) value_as_long (val); + } + else + { + if (*p == '-') + ++p; + while (*p >= '0' && *p <= '9') + ++p; + if (p == *pp) + /* There is no number here. (e.g. "cond a == b"). */ + error_no_arg ("breakpoint number"); + retval = atoi (*pp); + } + if (!(isspace (*p) || *p == '\0')) + error ("breakpoint number expected"); + while (isspace (*p)) + p++; + *pp = p; + return retval; +} + +/* condition N EXP -- set break condition of breakpoint N to EXP. */ + +static void +condition_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b; + char *p; + register int bnum; + + if (arg == 0) + error_no_arg ("breakpoint number"); + + p = arg; + bnum = get_number (&p); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (b->cond) + { + free ((PTR)b->cond); + b->cond = 0; + } + if (b->cond_string != NULL) + free ((PTR)b->cond_string); + + if (*p == 0) + { + b->cond = 0; + b->cond_string = NULL; + if (from_tty) + printf_filtered ("Breakpoint %d now unconditional.\n", bnum); + } + else + { + arg = p; + /* I don't know if it matters whether this is the string the user + typed in or the decompiled expression. */ + b->cond_string = savestring (arg, strlen (arg)); + b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0); + if (*arg) + error ("Junk at end of expression"); + } + return; + } + + error ("No breakpoint number %d.", bnum); +} + +/* ARGSUSED */ +static void +commands_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b; + char *p; + register int bnum; + struct command_line *l; + + /* If we allowed this, we would have problems with when to + free the storage, if we change the commands currently + being read from. */ + + if (executing_breakpoint_commands) + error ("Can't use the \"commands\" command among a breakpoint's commands."); + + p = arg; + bnum = get_number (&p); + if (p && *p) + error ("Unexpected extra arguments following breakpoint number."); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (from_tty && input_from_terminal_p ()) + printf_filtered ("Type commands for when breakpoint %d is hit, one per line.\n\ +End with a line saying just \"end\".\n", bnum); + l = read_command_lines (); + free_command_lines (&b->commands); + b->commands = l; + return; + } + error ("No breakpoint number %d.", bnum); +} + +extern int memory_breakpoint_size; /* from mem-break.c */ + +/* Like target_read_memory() but if breakpoints are inserted, return + the shadow contents instead of the breakpoints themselves. + + Read "memory data" from whatever target or inferior we have. + Returns zero if successful, errno value if not. EIO is used + for address out of bounds. If breakpoints are inserted, returns + shadow contents, not the breakpoints themselves. From breakpoint.c. */ + +int +read_memory_nobpt (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + unsigned len; +{ + int status; + struct breakpoint *b; + + if (memory_breakpoint_size < 0) + /* No breakpoints on this machine. FIXME: This should be + dependent on the debugging target. Probably want + target_insert_breakpoint to return a size, saying how many + bytes of the shadow contents are used, or perhaps have + something like target_xfer_shadow. */ + return target_read_memory (memaddr, myaddr, len); + + ALL_BREAKPOINTS (b) + { + if (b->type == bp_watchpoint || !b->inserted) + continue; + else if (b->address + memory_breakpoint_size <= memaddr) + /* The breakpoint is entirely before the chunk of memory + we are reading. */ + continue; + else if (b->address >= memaddr + len) + /* The breakpoint is entirely after the chunk of memory we + are reading. */ + continue; + else + { + /* Copy the breakpoint from the shadow contents, and recurse + for the things before and after. */ + + /* Addresses and length of the part of the breakpoint that + we need to copy. */ + CORE_ADDR membpt = b->address; + unsigned int bptlen = memory_breakpoint_size; + /* Offset within shadow_contents. */ + int bptoffset = 0; + + if (membpt < memaddr) + { + /* Only copy the second part of the breakpoint. */ + bptlen -= memaddr - membpt; + bptoffset = memaddr - membpt; + membpt = memaddr; + } + + if (membpt + bptlen > memaddr + len) + { + /* Only copy the first part of the breakpoint. */ + bptlen -= (membpt + bptlen) - (memaddr + len); + } + + memcpy (myaddr + membpt - memaddr, + b->shadow_contents + bptoffset, bptlen); + + if (membpt > memaddr) + { + /* Copy the section of memory before the breakpoint. */ + status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr); + if (status != 0) + return status; + } + + if (membpt + bptlen < memaddr + len) + { + /* Copy the section of memory after the breakpoint. */ + status = read_memory_nobpt + (membpt + bptlen, + myaddr + membpt + bptlen - memaddr, + memaddr + len - (membpt + bptlen)); + if (status != 0) + return status; + } + return 0; + } + } + /* Nothing overlaps. Just call read_memory_noerr. */ + return target_read_memory (memaddr, myaddr, len); +} + +/* insert_breakpoints is used when starting or continuing the program. + remove_breakpoints is used when the program stops. + Both return zero if successful, + or an `errno' value if could not write the inferior. */ + +int +insert_breakpoints () +{ + register struct breakpoint *b; + int val = 0; + int disabled_breaks = 0; + + ALL_BREAKPOINTS (b) + if (b->type != bp_watchpoint + && b->enable != disabled + && ! b->inserted + && ! b->duplicate) + { + val = target_insert_breakpoint(b->address, b->shadow_contents); + if (val) + { + /* Can't set the breakpoint. */ +#if defined (DISABLE_UNSETTABLE_BREAK) + if (DISABLE_UNSETTABLE_BREAK (b->address)) + { + val = 0; + b->enable = disabled; + if (!disabled_breaks) + { + fprintf (stderr, + "Cannot insert breakpoint %d:\n", b->number); + printf_filtered ("Disabling shared library breakpoints:\n"); + } + disabled_breaks = 1; + printf_filtered ("%d ", b->number); + } + else +#endif + { + fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number); +#ifdef ONE_PROCESS_WRITETEXT + fprintf (stderr, + "The same program may be running in another process.\n"); +#endif + memory_error (val, b->address); /* which bombs us out */ + } + } + else + b->inserted = 1; + } + if (disabled_breaks) + printf_filtered ("\n"); + return val; +} + +int +remove_breakpoints () +{ + register struct breakpoint *b; + int val; + +#ifdef BREAKPOINT_DEBUG + printf ("Removing breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + + ALL_BREAKPOINTS (b) + if (b->type != bp_watchpoint && b->inserted) + { + val = target_remove_breakpoint(b->address, b->shadow_contents); + if (val) + return val; + b->inserted = 0; +#ifdef BREAKPOINT_DEBUG + printf ("Removed breakpoint at %s", + local_hex_string((unsigned long) b->address)); + printf (", shadow %s", + local_hex_string((unsigned long) b->shadow_contents[0])); + printf (", %s.\n", + local_hex_string((unsigned long) b->shadow_contents[1])); +#endif /* BREAKPOINT_DEBUG */ + } + + return 0; +} + +/* Clear the "inserted" flag in all breakpoints. */ + +void +mark_breakpoints_out () +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + b->inserted = 0; +} + +/* Clear the "inserted" flag in all breakpoints and delete any breakpoints + which should go away between runs of the program. */ + +void +breakpoint_init_inferior () +{ + register struct breakpoint *b, *temp; + + ALL_BREAKPOINTS_SAFE (b, temp) + { + b->inserted = 0; + + /* If the call dummy breakpoint is at the entry point it will + cause problems when the inferior is rerun, so we better + get rid of it. */ + if (b->type == bp_call_dummy) + delete_breakpoint (b); + } +} + +/* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC. + When continuing from a location with a breakpoint, + we actually single step once before calling insert_breakpoints. */ + +int +breakpoint_here_p (pc) + CORE_ADDR pc; +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && b->address == pc) + return 1; + + return 0; +} + +/* breakpoint_match_thread (PC, PID) returns true if the breakpoint at PC + is valid for process/thread PID. */ + +int +breakpoint_thread_match (pc, pid) + CORE_ADDR pc; + int pid; +{ + struct breakpoint *b; + int thread; + + thread = pid_to_thread_id (pid); + + ALL_BREAKPOINTS (b) + if (b->enable != disabled + && b->address == pc + && (b->thread == -1 || b->thread == thread)) + return 1; + + return 0; +} + + +/* bpstat stuff. External routines' interfaces are documented + in breakpoint.h. */ + +/* Clear a bpstat so that it says we are not at any breakpoint. + Also free any storage that is part of a bpstat. */ + +void +bpstat_clear (bsp) + bpstat *bsp; +{ + bpstat p; + bpstat q; + + if (bsp == 0) + return; + p = *bsp; + while (p != NULL) + { + q = p->next; + if (p->old_val != NULL) + value_free (p->old_val); + free ((PTR)p); + p = q; + } + *bsp = NULL; +} + +/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that + is part of the bpstat is copied as well. */ + +bpstat +bpstat_copy (bs) + bpstat bs; +{ + bpstat p = NULL; + bpstat tmp; + bpstat retval = NULL; + + if (bs == NULL) + return bs; + + for (; bs != NULL; bs = bs->next) + { + tmp = (bpstat) xmalloc (sizeof (*tmp)); + memcpy (tmp, bs, sizeof (*tmp)); + if (p == NULL) + /* This is the first thing in the chain. */ + retval = tmp; + else + p->next = tmp; + p = tmp; + } + p->next = NULL; + return retval; +} + +/* Find the bpstat associated with this breakpoint */ + +bpstat +bpstat_find_breakpoint(bsp, breakpoint) + bpstat bsp; + struct breakpoint *breakpoint; +{ + if (bsp == NULL) return NULL; + + for (;bsp != NULL; bsp = bsp->next) { + if (bsp->breakpoint_at == breakpoint) return bsp; + } + return NULL; +} + +/* Return the breakpoint number of the first breakpoint we are stopped + at. *BSP upon return is a bpstat which points to the remaining + breakpoints stopped at (but which is not guaranteed to be good for + anything but further calls to bpstat_num). + Return 0 if passed a bpstat which does not indicate any breakpoints. */ + +int +bpstat_num (bsp) + bpstat *bsp; +{ + struct breakpoint *b; + + if ((*bsp) == NULL) + return 0; /* No more breakpoint values */ + else + { + b = (*bsp)->breakpoint_at; + *bsp = (*bsp)->next; + if (b == NULL) + return -1; /* breakpoint that's been deleted since */ + else + return b->number; /* We have its number */ + } +} + +/* Modify BS so that the actions will not be performed. */ + +void +bpstat_clear_actions (bs) + bpstat bs; +{ + for (; bs != NULL; bs = bs->next) + { + bs->commands = NULL; + if (bs->old_val != NULL) + { + value_free (bs->old_val); + bs->old_val = NULL; + } + } +} + +/* Stub for cleaning up our state if we error-out of a breakpoint command */ +/* ARGSUSED */ +static void +cleanup_executing_breakpoints (ignore) + int ignore; +{ + executing_breakpoint_commands = 0; +} + +/* Execute all the commands associated with all the breakpoints at this + location. Any of these commands could cause the process to proceed + beyond this point, etc. We look out for such changes by checking + the global "breakpoint_proceeded" after each command. */ + +void +bpstat_do_actions (bsp) + bpstat *bsp; +{ + bpstat bs; + struct cleanup *old_chain; + + executing_breakpoint_commands = 1; + old_chain = make_cleanup (cleanup_executing_breakpoints, 0); + +top: + bs = *bsp; + + breakpoint_proceeded = 0; + for (; bs != NULL; bs = bs->next) + { + while (bs->commands) + { + char *line = bs->commands->line; + bs->commands = bs->commands->next; + execute_command (line, 0); + /* If the inferior is proceeded by the command, bomb out now. + The bpstat chain has been blown away by wait_for_inferior. + But since execution has stopped again, there is a new bpstat + to look at, so start over. */ + if (breakpoint_proceeded) + goto top; + } + } + + executing_breakpoint_commands = 0; + discard_cleanups (old_chain); +} + +/* This is the normal print_it function for a bpstat. In the future, + much of this logic could (should?) be moved to bpstat_stop_status, + by having it set different print_it functions. */ + +static int +print_it_normal (bs) + bpstat bs; +{ + /* bs->breakpoint_at can be NULL if it was a momentary breakpoint + which has since been deleted. */ + if (bs->breakpoint_at == NULL + || (bs->breakpoint_at->type != bp_breakpoint + && bs->breakpoint_at->type != bp_watchpoint)) + return 0; + + if (bs->breakpoint_at->type == bp_breakpoint) + { + /* I think the user probably only wants to see one breakpoint + number, not all of them. */ + printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number); + return 0; + } + + if (bs->old_val != NULL) + { + printf_filtered ("\nWatchpoint %d, ", bs->breakpoint_at->number); + print_expression (bs->breakpoint_at->exp, stdout); + printf_filtered ("\nOld value = "); + value_print (bs->old_val, stdout, 0, Val_pretty_default); + printf_filtered ("\nNew value = "); + value_print (bs->breakpoint_at->val, stdout, 0, + Val_pretty_default); + printf_filtered ("\n"); + value_free (bs->old_val); + bs->old_val = NULL; + return 0; + } + /* We can't deal with it. Maybe another member of the bpstat chain can. */ + return -1; +} + +/* Print a message indicating what happened. Returns nonzero to + say that only the source line should be printed after this (zero + return means print the frame as well as the source line). */ +/* Currently we always return zero. */ +int +bpstat_print (bs) + bpstat bs; +{ + int val; + + if (bs == NULL) + return 0; + + val = (*bs->print_it) (bs); + if (val >= 0) + return val; + + /* Maybe another breakpoint in the chain caused us to stop. + (Currently all watchpoints go on the bpstat whether hit or + not. That probably could (should) be changed, provided care is taken + with respect to bpstat_explains_signal). */ + if (bs->next) + return bpstat_print (bs->next); + + /* We reached the end of the chain without printing anything. */ + return 0; +} + +/* Evaluate the expression EXP and return 1 if value is zero. + This is used inside a catch_errors to evaluate the breakpoint condition. + The argument is a "struct expression *" that has been cast to char * to + make it pass through catch_errors. */ + +static int +breakpoint_cond_eval (exp) + char *exp; +{ + return !value_true (evaluate_expression ((struct expression *)exp)); +} + +/* Allocate a new bpstat and chain it to the current one. */ + +static bpstat +bpstat_alloc (b, cbs) + register struct breakpoint *b; + bpstat cbs; /* Current "bs" value */ +{ + bpstat bs; + + bs = (bpstat) xmalloc (sizeof (*bs)); + cbs->next = bs; + bs->breakpoint_at = b; + /* If the condition is false, etc., don't do the commands. */ + bs->commands = NULL; + bs->old_val = NULL; + bs->print_it = print_it_normal; + return bs; +} + +/* Return the frame which we can use to evaluate the expression + whose valid block is valid_block, or NULL if not in scope. + + This whole concept is probably not the way to do things (it is incredibly + slow being the main reason, not to mention fragile (e.g. the sparc + frame pointer being fetched as 0 bug causes it to stop)). Instead, + introduce a version of "struct frame" which survives over calls to the + inferior, but which is better than FRAME_ADDR in the sense that it lets + us evaluate expressions relative to that frame (on some machines, it + can just be a FRAME_ADDR). Save one of those instead of (or in addition + to) the exp_valid_block, and then use it to evaluate the watchpoint + expression, with no need to do all this backtracing every time. + + Or better yet, what if it just copied the struct frame and its next + frame? Off the top of my head, I would think that would work + because things like (a29k) rsize and msize, or (sparc) bottom just + depend on the frame, and aren't going to be different just because + the inferior has done something. Trying to recalculate them + strikes me as a lot of work, possibly even impossible. Saving the + next frame is needed at least on a29k, where get_saved_register + uses fi->next->saved_msp. For figuring out whether that frame is + still on the stack, I guess this needs to be machine-specific (e.g. + a29k) but I think + + read_fp () INNER_THAN watchpoint_frame->frame + + would generally work. + + Of course the scope of the expression could be less than a whole + function; perhaps if the innermost frame is the one which the + watchpoint is relative to (another machine-specific thing, usually + + FRAMELESS_FUNCTION_INVOCATION (get_current_frame(), fromleaf) + read_fp () == wp_frame->frame + && !fromleaf + + ), *then* it could do a + + contained_in (get_current_block (), wp->exp_valid_block). + + */ + +FRAME +within_scope (valid_block) + struct block *valid_block; +{ + FRAME fr = get_current_frame (); + struct frame_info *fi = get_frame_info (fr); + CORE_ADDR func_start; + + /* If caller_pc_valid is true, we are stepping through + a function prologue, which is bounded by callee_func_start + (inclusive) and callee_prologue_end (exclusive). + caller_pc is the pc of the caller. + + Yes, this is hairy. */ + static int caller_pc_valid = 0; + static CORE_ADDR caller_pc; + static CORE_ADDR callee_func_start; + static CORE_ADDR callee_prologue_end; + + find_pc_partial_function (fi->pc, (PTR)NULL, &func_start, (CORE_ADDR *)NULL); + func_start += FUNCTION_START_OFFSET; + if (fi->pc == func_start) + { + /* We just called a function. The only other case I + can think of where the pc would equal the pc of the + start of a function is a frameless function (i.e. + no prologue) where we branch back to the start + of the function. In that case, SKIP_PROLOGUE won't + find one, and we'll clear caller_pc_valid a few lines + down. */ + caller_pc_valid = 1; + caller_pc = SAVED_PC_AFTER_CALL (fr); + callee_func_start = func_start; + SKIP_PROLOGUE (func_start); + callee_prologue_end = func_start; + } + if (caller_pc_valid) + { + if (fi->pc < callee_func_start + || fi->pc >= callee_prologue_end) + caller_pc_valid = 0; + } + + if (contained_in (block_for_pc (caller_pc_valid + ? caller_pc + : fi->pc), + valid_block)) + { + return fr; + } + fr = get_prev_frame (fr); + + /* If any active frame is in the exp_valid_block, then it's + OK. Note that this might not be the same invocation of + the exp_valid_block that we were watching a little while + ago, or the same one as when the watchpoint was set (e.g. + we are watching a local variable in a recursive function. + When we return from a recursive invocation, then we are + suddenly watching a different instance of the variable). + + At least for now I am going to consider this a feature. */ + for (; fr != NULL; fr = get_prev_frame (fr)) + { + fi = get_frame_info (fr); + if (contained_in (block_for_pc (fi->pc), + valid_block)) + { + return fr; + } + } + return NULL; +} + +/* Possible return values for watchpoint_check (this can't be an enum + because of check_errors). */ +/* The watchpoint has been disabled. */ +#define WP_DISABLED 1 +/* The value has changed. */ +#define WP_VALUE_CHANGED 2 +/* The value has not changed. */ +#define WP_VALUE_NOT_CHANGED 3 + +/* Check watchpoint condition. */ +static int +watchpoint_check (p) + char *p; +{ + bpstat bs = (bpstat) p; + FRAME fr; + + int within_current_scope; + if (bs->breakpoint_at->exp_valid_block == NULL) + within_current_scope = 1; + else + { + fr = within_scope (bs->breakpoint_at->exp_valid_block); + within_current_scope = fr != NULL; + if (within_current_scope) + /* If we end up stopping, the current frame will get selected + in normal_stop. So this call to select_frame won't affect + the user. */ + select_frame (fr, -1); + } + + if (within_current_scope) + { + /* We use value_{,free_to_}mark because it could be a + *long* time before we return to the command level and + call free_all_values. We can't call free_all_values because + we might be in the middle of evaluating a function call. */ + + value mark = value_mark (); + value new_val = evaluate_expression (bs->breakpoint_at->exp); + if (!value_equal (bs->breakpoint_at->val, new_val)) + { + release_value (new_val); + value_free_to_mark (mark); + bs->old_val = bs->breakpoint_at->val; + bs->breakpoint_at->val = new_val; + /* We will stop here */ + return WP_VALUE_CHANGED; + } + else + { + /* Nothing changed, don't do anything. */ + value_free_to_mark (mark); + /* We won't stop here */ + return WP_VALUE_NOT_CHANGED; + } + } + else + { + /* This seems like the only logical thing to do because + if we temporarily ignored the watchpoint, then when + we reenter the block in which it is valid it contains + garbage (in the case of a function, it may have two + garbage values, one before and one after the prologue). + So we can't even detect the first assignment to it and + watch after that (since the garbage may or may not equal + the first value assigned). */ + bs->breakpoint_at->enable = disabled; + printf_filtered ("\ +Watchpoint %d disabled because the program has left the block in\n\ +which its expression is valid.\n", bs->breakpoint_at->number); + return WP_DISABLED; + } +} + +/* This is used when everything which needs to be printed has + already been printed. But we still want to print the frame. */ +static int +print_it_done (bs) + bpstat bs; +{ + return 0; +} + +/* This is used when nothing should be printed for this bpstat entry. */ + +static int +print_it_noop (bs) + bpstat bs; +{ + return -1; +} + +/* Get a bpstat associated with having just stopped at address *PC + and frame address FRAME_ADDRESS. Update *PC to point at the + breakpoint (if we hit a breakpoint). NOT_A_BREAKPOINT is nonzero + if this is known to not be a real breakpoint (it could still be a + watchpoint, though). */ + +/* Determine whether we stopped at a breakpoint, etc, or whether we + don't understand this stop. Result is a chain of bpstat's such that: + + if we don't understand the stop, the result is a null pointer. + + if we understand why we stopped, the result is not null. + + Each element of the chain refers to a particular breakpoint or + watchpoint at which we have stopped. (We may have stopped for + several reasons concurrently.) + + Each element of the chain has valid next, breakpoint_at, + commands, FIXME??? fields. + + */ + +bpstat +bpstat_stop_status (pc, frame_address, not_a_breakpoint) + CORE_ADDR *pc; + FRAME_ADDR frame_address; + int not_a_breakpoint; +{ + register struct breakpoint *b; + CORE_ADDR bp_addr; +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) + /* True if we've hit a breakpoint (as opposed to a watchpoint). */ + int real_breakpoint = 0; +#endif + /* Root of the chain of bpstat's */ + struct bpstat root_bs[1]; + /* Pointer to the last thing in the chain currently. */ + bpstat bs = root_bs; + + /* Get the address where the breakpoint would have been. */ + bp_addr = *pc - DECR_PC_AFTER_BREAK; + + ALL_BREAKPOINTS (b) + { + if (b->enable == disabled) + continue; + + if (b->type != bp_watchpoint && b->address != bp_addr) + continue; + + if (b->type != bp_watchpoint && not_a_breakpoint) + continue; + + /* Come here if it's a watchpoint, or if the break address matches */ + + bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */ + + bs->stop = 1; + bs->print = 1; + + if (b->type == bp_watchpoint) + { + static char message1[] = + "Error evaluating expression for watchpoint %d\n"; + char message[sizeof (message1) + 30 /* slop */]; + sprintf (message, message1, b->number); + switch (catch_errors (watchpoint_check, (char *) bs, message, + RETURN_MASK_ALL)) + { + case WP_DISABLED: + /* We've already printed what needs to be printed. */ + bs->print_it = print_it_done; + /* Stop. */ + break; + case WP_VALUE_CHANGED: + /* Stop. */ + break; + case WP_VALUE_NOT_CHANGED: + /* Don't stop. */ + bs->print_it = print_it_noop; + bs->stop = 0; + continue; + default: + /* Can't happen. */ + /* FALLTHROUGH */ + case 0: + /* Error from catch_errors. */ + b->enable = disabled; + printf_filtered ("Watchpoint %d disabled.\n", b->number); + /* We've already printed what needs to be printed. */ + bs->print_it = print_it_done; + /* Stop. */ + break; + } + } +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) + else + real_breakpoint = 1; +#endif + + if (b->frame && b->frame != frame_address) + bs->stop = 0; + else + { + int value_is_zero = 0; + + if (b->cond) + { + /* Need to select the frame, with all that implies + so that the conditions will have the right context. */ + select_frame (get_current_frame (), 0); + value_is_zero + = catch_errors (breakpoint_cond_eval, (char *)(b->cond), + "Error in testing breakpoint condition:\n", + RETURN_MASK_ALL); + /* FIXME-someday, should give breakpoint # */ + free_all_values (); + } + if (b->cond && value_is_zero) + { + bs->stop = 0; + } + else if (b->ignore_count > 0) + { + b->ignore_count--; + bs->stop = 0; + } + else + { + /* We will stop here */ + if (b->disposition == disable) + b->enable = disabled; + bs->commands = b->commands; + if (b->silent) + bs->print = 0; + if (bs->commands && STREQ ("silent", bs->commands->line)) + { + bs->commands = bs->commands->next; + bs->print = 0; + } + } + } + /* Print nothing for this entry if we dont stop or if we dont print. */ + if (bs->stop == 0 || bs->print == 0) + bs->print_it = print_it_noop; + } + + bs->next = NULL; /* Terminate the chain */ + bs = root_bs->next; /* Re-grab the head of the chain */ +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) + if (bs) + { + if (real_breakpoint) + { + *pc = bp_addr; +#if defined (SHIFT_INST_REGS) + SHIFT_INST_REGS(); +#else /* No SHIFT_INST_REGS. */ + write_pc (bp_addr); +#endif /* No SHIFT_INST_REGS. */ + } + } +#endif /* DECR_PC_AFTER_BREAK != 0. */ + return bs; +} + +/* Tell what to do about this bpstat. */ +struct bpstat_what +bpstat_what (bs) + bpstat bs; +{ + /* Classify each bpstat as one of the following. */ + enum class { + /* This bpstat element has no effect on the main_action. */ + no_effect = 0, + + /* There was a watchpoint, stop but don't print. */ + wp_silent, + + /* There was a watchpoint, stop and print. */ + wp_noisy, + + /* There was a breakpoint but we're not stopping. */ + bp_nostop, + + /* There was a breakpoint, stop but don't print. */ + bp_silent, + + /* There was a breakpoint, stop and print. */ + bp_noisy, + + /* We hit the longjmp breakpoint. */ + long_jump, + + /* We hit the longjmp_resume breakpoint. */ + long_resume, + + /* This is just used to count how many enums there are. */ + class_last + }; + + /* Here is the table which drives this routine. So that we can + format it pretty, we define some abbreviations for the + enum bpstat_what codes. */ +#define keep_c BPSTAT_WHAT_KEEP_CHECKING +#define stop_s BPSTAT_WHAT_STOP_SILENT +#define stop_n BPSTAT_WHAT_STOP_NOISY +#define single BPSTAT_WHAT_SINGLE +#define setlr BPSTAT_WHAT_SET_LONGJMP_RESUME +#define clrlr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME +#define clrlrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE +/* "Can't happen." Might want to print an error message. + abort() is not out of the question, but chances are GDB is just + a bit confused, not unusable. */ +#define err BPSTAT_WHAT_STOP_NOISY + + /* Given an old action and a class, come up with a new action. */ + /* One interesting property of this table is that wp_silent is the same + as bp_silent and wp_noisy is the same as bp_noisy. That is because + after stopping, the check for whether to step over a breakpoint + (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without + reference to how we stopped. We retain separate wp_silent and bp_silent + codes in case we want to change that someday. */ + static const enum bpstat_what_main_action + table[(int)class_last][(int)BPSTAT_WHAT_LAST] = + { + /* old action */ + /* keep_c stop_s stop_n single setlr clrlr clrlrs */ + +/*no_effect*/ {keep_c, stop_s, stop_n, single, setlr , clrlr , clrlrs}, +/*wp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s}, +/*wp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n}, +/*bp_nostop*/ {single, stop_s, stop_n, single, setlr , clrlrs, clrlrs}, +/*bp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s}, +/*bp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n}, +/*long_jump*/ {setlr , stop_s, stop_n, setlr , err , err , err }, +/*long_resume*/ {clrlr , stop_s, stop_n, clrlrs, err , err , err } + }; +#undef keep_c +#undef stop_s +#undef stop_n +#undef single +#undef setlr +#undef clrlr +#undef clrlrs +#undef err + enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING; + struct bpstat_what retval; + + retval.call_dummy = 0; + retval.step_resume = 0; + for (; bs != NULL; bs = bs->next) + { + enum class bs_class = no_effect; + if (bs->breakpoint_at == NULL) + /* I suspect this can happen if it was a momentary breakpoint + which has since been deleted. */ + continue; + switch (bs->breakpoint_at->type) + { + case bp_breakpoint: + case bp_until: + case bp_finish: + if (bs->stop) + { + if (bs->print) + bs_class = bp_noisy; + else + bs_class = bp_silent; + } + else + bs_class = bp_nostop; + break; + case bp_watchpoint: + if (bs->stop) + { + if (bs->print) + bs_class = wp_noisy; + else + bs_class = wp_silent; + } + else + /* There was a watchpoint, but we're not stopping. This requires + no further action. */ + bs_class = no_effect; + break; + case bp_longjmp: + bs_class = long_jump; + break; + case bp_longjmp_resume: + bs_class = long_resume; + break; + case bp_step_resume: +#if 0 + /* Need to temporarily disable this until we can fix the bug + with nexting over a breakpoint with ->stop clear causing + an infinite loop. For now, treat the breakpoint as having + been hit even if the frame is wrong. */ + if (bs->stop) + { +#endif + retval.step_resume = 1; + /* We don't handle this via the main_action. */ + bs_class = no_effect; +#if 0 + } + else + /* It is for the wrong frame. */ + bs_class = bp_nostop; +#endif + break; + case bp_call_dummy: + /* Make sure the action is stop (silent or noisy), so infrun.c + pops the dummy frame. */ + bs_class = bp_silent; + retval.call_dummy = 1; + break; + } + current_action = table[(int)bs_class][(int)current_action]; + } + retval.main_action = current_action; + return retval; +} + +/* Nonzero if we should step constantly (e.g. watchpoints on machines + without hardware support). This isn't related to a specific bpstat, + just to things like whether watchpoints are set. */ + +int +bpstat_should_step () +{ + struct breakpoint *b; + ALL_BREAKPOINTS (b) + if (b->enable == enabled && b->type == bp_watchpoint) + return 1; + return 0; +} + +/* Print information on breakpoint number BNUM, or -1 if all. + If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS + is nonzero, process only watchpoints. */ + +static void +breakpoint_1 (bnum, allflag) + int bnum; + int allflag; +{ + register struct breakpoint *b; + register struct command_line *l; + register struct symbol *sym; + CORE_ADDR last_addr = (CORE_ADDR)-1; + int found_a_breakpoint = 0; + static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint", + "longjmp", "longjmp resume", "step resume", + "call dummy" }; + static char *bpdisps[] = {"del", "dis", "keep"}; + static char bpenables[] = "ny"; + char wrap_indent[80]; + + ALL_BREAKPOINTS (b) + if (bnum == -1 + || bnum == b->number) + { +/* We only print out user settable breakpoints unless the allflag is set. */ + if (!allflag + && b->type != bp_breakpoint + && b->type != bp_watchpoint) + continue; + + if (!found_a_breakpoint++) + printf_filtered ("Num Type Disp Enb %sWhat\n", + addressprint ? "Address " : ""); + + printf_filtered ("%-3d %-14s %-4s %-3c ", + b->number, + bptypes[(int)b->type], + bpdisps[(int)b->disposition], + bpenables[(int)b->enable]); + strcpy (wrap_indent, " "); + if (addressprint) + strcat (wrap_indent, " "); + switch (b->type) + { + case bp_watchpoint: + print_expression (b->exp, stdout); + break; + + case bp_breakpoint: + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_step_resume: + case bp_call_dummy: + if (addressprint) + printf_filtered ("%s ", local_hex_string_custom ((unsigned long) b->address, "08l")); + + last_addr = b->address; + if (b->source_file) + { + sym = find_pc_function (b->address); + if (sym) + { + fputs_filtered ("in ", stdout); + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout); + wrap_here (wrap_indent); + fputs_filtered (" at ", stdout); + } + fputs_filtered (b->source_file, stdout); + printf_filtered (":%d", b->line_number); + } + else + print_address_symbolic (b->address, stdout, demangle, " "); + break; + } + + printf_filtered ("\n"); + + if (b->frame) + printf_filtered ("\tstop only in stack frame at %s\n", + local_hex_string((unsigned long) b->frame)); + if (b->cond) + { + printf_filtered ("\tstop only if "); + print_expression (b->cond, stdout); + printf_filtered ("\n"); + } + if (b->ignore_count) + printf_filtered ("\tignore next %d hits\n", b->ignore_count); + if ((l = b->commands)) + while (l) + { + fputs_filtered ("\t", stdout); + fputs_filtered (l->line, stdout); + fputs_filtered ("\n", stdout); + l = l->next; + } + } + + if (!found_a_breakpoint) + { + if (bnum == -1) + printf_filtered ("No breakpoints or watchpoints.\n"); + else + printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum); + } + else + /* Compare against (CORE_ADDR)-1 in case some compiler decides + that a comparison of an unsigned with -1 is always false. */ + if (last_addr != (CORE_ADDR)-1) + set_next_address (last_addr); +} + +/* ARGSUSED */ +static void +breakpoints_info (bnum_exp, from_tty) + char *bnum_exp; + int from_tty; +{ + int bnum = -1; + + if (bnum_exp) + bnum = parse_and_eval_address (bnum_exp); + + breakpoint_1 (bnum, 0); +} + +#if MAINTENANCE_CMDS + +/* ARGSUSED */ +static void +maintenance_info_breakpoints (bnum_exp, from_tty) + char *bnum_exp; + int from_tty; +{ + int bnum = -1; + + if (bnum_exp) + bnum = parse_and_eval_address (bnum_exp); + + breakpoint_1 (bnum, 1); +} + +#endif + +/* Print a message describing any breakpoints set at PC. */ + +static void +describe_other_breakpoints (pc) + register CORE_ADDR pc; +{ + register int others = 0; + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->address == pc) + others++; + if (others > 0) + { + printf ("Note: breakpoint%s ", (others > 1) ? "s" : ""); + ALL_BREAKPOINTS (b) + if (b->address == pc) + { + others--; + printf ("%d%s%s ", + b->number, + (b->enable == disabled) ? " (disabled)" : "", + (others > 1) ? "," : ((others == 1) ? " and" : "")); + } + printf ("also set at pc %s.\n", local_hex_string((unsigned long) pc)); + } +} + +/* Set the default place to put a breakpoint + for the `break' command with no arguments. */ + +void +set_default_breakpoint (valid, addr, symtab, line) + int valid; + CORE_ADDR addr; + struct symtab *symtab; + int line; +{ + default_breakpoint_valid = valid; + default_breakpoint_address = addr; + default_breakpoint_symtab = symtab; + default_breakpoint_line = line; +} + +/* Rescan breakpoints at address ADDRESS, + marking the first one as "first" and any others as "duplicates". + This is so that the bpt instruction is only inserted once. */ + +static void +check_duplicates (address) + CORE_ADDR address; +{ + register struct breakpoint *b; + register int count = 0; + + if (address == 0) /* Watchpoints are uninteresting */ + return; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && b->address == address) + { + count++; + b->duplicate = count > 1; + } +} + +/* Low level routine to set a breakpoint. + Takes as args the three things that every breakpoint must have. + Returns the breakpoint object so caller can set other things. + Does not set the breakpoint number! + Does not print anything. + + ==> This routine should not be called if there is a chance of later + error(); otherwise it leaves a bogus breakpoint on the chain. Validate + your arguments BEFORE calling this routine! */ + +static struct breakpoint * +set_raw_breakpoint (sal) + struct symtab_and_line sal; +{ + register struct breakpoint *b, *b1; + + b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint)); + memset (b, 0, sizeof (*b)); + b->address = sal.pc; + if (sal.symtab == NULL) + b->source_file = NULL; + else + b->source_file = savestring (sal.symtab->filename, + strlen (sal.symtab->filename)); + b->thread = -1; + b->line_number = sal.line; + b->enable = enabled; + b->next = 0; + b->silent = 0; + b->ignore_count = 0; + b->commands = NULL; + b->frame = 0; + + /* Add this breakpoint to the end of the chain + so that a list of breakpoints will come out in order + of increasing numbers. */ + + b1 = breakpoint_chain; + if (b1 == 0) + breakpoint_chain = b; + else + { + while (b1->next) + b1 = b1->next; + b1->next = b; + } + + check_duplicates (sal.pc); + + return b; +} + +static void +create_longjmp_breakpoint(func_name) + char *func_name; +{ + struct symtab_and_line sal; + struct breakpoint *b; + static int internal_breakpoint_number = -1; + + if (func_name != NULL) + { + struct minimal_symbol *m; + + m = lookup_minimal_symbol(func_name, (struct objfile *)NULL); + if (m) + sal.pc = SYMBOL_VALUE_ADDRESS (m); + else + return; + } + else + sal.pc = 0; + + sal.symtab = NULL; + sal.line = 0; + + b = set_raw_breakpoint(sal); + if (!b) return; + + b->type = func_name != NULL ? bp_longjmp : bp_longjmp_resume; + b->disposition = donttouch; + b->enable = disabled; + b->silent = 1; + if (func_name) + b->addr_string = strsave(func_name); + b->number = internal_breakpoint_number--; +} + +/* Call this routine when stepping and nexting to enable a breakpoint if we do + a longjmp(). When we hit that breakpoint, call + set_longjmp_resume_breakpoint() to figure out where we are going. */ + +void +enable_longjmp_breakpoint() +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_longjmp) + { + b->enable = enabled; + check_duplicates (b->address); + } +} + +void +disable_longjmp_breakpoint() +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if ( b->type == bp_longjmp + || b->type == bp_longjmp_resume) + { + b->enable = disabled; + check_duplicates (b->address); + } +} + +/* Call this after hitting the longjmp() breakpoint. Use this to set a new + breakpoint at the target of the jmp_buf. + + FIXME - This ought to be done by setting a temporary breakpoint that gets + deleted automatically... +*/ + +void +set_longjmp_resume_breakpoint(pc, frame) + CORE_ADDR pc; + FRAME frame; +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_longjmp_resume) + { + b->address = pc; + b->enable = enabled; + if (frame != NULL) + b->frame = FRAME_FP(frame); + else + b->frame = 0; + check_duplicates (b->address); + return; + } +} + +/* Set a breakpoint that will evaporate an end of command + at address specified by SAL. + Restrict it to frame FRAME if FRAME is nonzero. */ + +struct breakpoint * +set_momentary_breakpoint (sal, frame, type) + struct symtab_and_line sal; + FRAME frame; + enum bptype type; +{ + register struct breakpoint *b; + b = set_raw_breakpoint (sal); + b->type = type; + b->enable = enabled; + b->disposition = donttouch; + b->frame = (frame ? FRAME_FP (frame) : 0); + return b; +} + +#if 0 +void +clear_momentary_breakpoints () +{ + register struct breakpoint *b; + ALL_BREAKPOINTS (b) + if (b->disposition == delete) + { + delete_breakpoint (b); + break; + } +} +#endif + +/* Tell the user we have just set a breakpoint B. */ +static void +mention (b) + struct breakpoint *b; +{ + switch (b->type) + { + case bp_watchpoint: + printf_filtered ("Watchpoint %d: ", b->number); + print_expression (b->exp, stdout); + break; + case bp_breakpoint: + printf_filtered ("Breakpoint %d at %s", b->number, + local_hex_string((unsigned long) b->address)); + if (b->source_file) + printf_filtered (": file %s, line %d.", + b->source_file, b->line_number); + break; + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_step_resume: + break; + } + printf_filtered ("\n"); +} + +#if 0 +/* Nobody calls this currently. */ +/* Set a breakpoint from a symtab and line. + If TEMPFLAG is nonzero, it is a temporary breakpoint. + ADDR_STRING is a malloc'd string holding the name of where we are + setting the breakpoint. This is used later to re-set it after the + program is relinked and symbols are reloaded. + Print the same confirmation messages that the breakpoint command prints. */ + +void +set_breakpoint (s, line, tempflag, addr_string) + struct symtab *s; + int line; + int tempflag; + char *addr_string; +{ + register struct breakpoint *b; + struct symtab_and_line sal; + + sal.symtab = s; + sal.line = line; + sal.pc = 0; + resolve_sal_pc (&sal); /* Might error out */ + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = 0; + b->addr_string = addr_string; + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; + + mention (b); +} +#endif /* 0 */ + +/* Set a breakpoint according to ARG (function, linenum or *address) + and make it temporary if TEMPFLAG is nonzero. */ + +static void +break_command_1 (arg, tempflag, from_tty) + char *arg; + int tempflag, from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + register struct expression *cond = 0; + register struct breakpoint *b; + + /* Pointers in arg to the start, and one past the end, of the condition. */ + char *cond_start = NULL; + char *cond_end = NULL; + /* Pointers in arg to the start, and one past the end, + of the address part. */ + char *addr_start = NULL; + char *addr_end = NULL; + struct cleanup *old_chain; + struct cleanup *canonical_strings_chain = NULL; + char **canonical = (char **)NULL; + int i; + int thread; + + sals.sals = NULL; + sals.nelts = 0; + + sal.line = sal.pc = sal.end = 0; + sal.symtab = 0; + + /* If no arg given, or if first arg is 'if ', use the default breakpoint. */ + + if (!arg || (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t'))) + { + if (default_breakpoint_valid) + { + sals.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + sal.pc = default_breakpoint_address; + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + sals.sals[0] = sal; + sals.nelts = 1; + } + else + error ("No default breakpoint address now."); + } + else + { + addr_start = arg; + + /* Force almost all breakpoints to be in terms of the + current_source_symtab (which is decode_line_1's default). This + should produce the results we want almost all of the time while + leaving default_breakpoint_* alone. */ + if (default_breakpoint_valid + && (!current_source_symtab + || (arg && (*arg == '+' || *arg == '-')))) + sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, + default_breakpoint_line, &canonical); + else + sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical); + + addr_end = arg; + } + + if (! sals.nelts) + return; + + /* Make sure that all storage allocated in decode_line_1 gets freed in case + the following `for' loop errors out. */ + old_chain = make_cleanup (free, sals.sals); + if (canonical != (char **)NULL) + { + make_cleanup (free, canonical); + canonical_strings_chain = make_cleanup (null_cleanup, 0); + for (i = 0; i < sals.nelts; i++) + { + if (canonical[i] != NULL) + make_cleanup (free, canonical[i]); + } + } + + thread = -1; /* No specific thread yet */ + + /* Resolve all line numbers to PC's, and verify that conditions + can be parsed, before setting any breakpoints. */ + for (i = 0; i < sals.nelts; i++) + { + char *tok, *end_tok; + int toklen; + + resolve_sal_pc (&sals.sals[i]); + + tok = arg; + + while (tok && *tok) + { + while (*tok == ' ' || *tok == '\t') + tok++; + + end_tok = tok; + + while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000') + end_tok++; + + toklen = end_tok - tok; + + if (toklen >= 1 && strncmp (tok, "if", toklen) == 0) + { + tok = cond_start = end_tok + 1; + cond = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0); + cond_end = tok; + } + else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0) + { + char *tmptok; + + tok = end_tok + 1; + tmptok = tok; + thread = strtol (tok, &tok, 0); + if (tok == tmptok) + error ("Junk after thread keyword."); + if (!valid_thread_id (thread)) + error ("Unknown thread %d\n", thread); + } + else + error ("Junk at end of arguments."); + } + } + + /* Remove the canonical strings from the cleanup, they are needed below. */ + if (canonical != (char **)NULL) + discard_cleanups (canonical_strings_chain); + + /* Now set all the breakpoints. */ + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; + + if (from_tty) + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = cond; + b->thread = thread; + + /* If a canonical line spec is needed use that instead of the + command string. */ + if (canonical != (char **)NULL && canonical[i] != NULL) + b->addr_string = canonical[i]; + else if (addr_start) + b->addr_string = savestring (addr_start, addr_end - addr_start); + if (cond_start) + b->cond_string = savestring (cond_start, cond_end - cond_start); + + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; + + mention (b); + } + + if (sals.nelts > 1) + { + printf ("Multiple breakpoints were set.\n"); + printf ("Use the \"delete\" command to delete unwanted breakpoints.\n"); + } + do_cleanups (old_chain); +} + +/* Helper function for break_command_1 and disassemble_command. */ + +void +resolve_sal_pc (sal) + struct symtab_and_line *sal; +{ + CORE_ADDR pc; + + if (sal->pc == 0 && sal->symtab != 0) + { + pc = find_line_pc (sal->symtab, sal->line); + if (pc == 0) + error ("No line %d in file \"%s\".", + sal->line, sal->symtab->filename); + sal->pc = pc; + } +} + +void +break_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, 0, from_tty); +} + +static void +tbreak_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, 1, from_tty); +} + +/* ARGSUSED */ +static void +watch_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct breakpoint *b; + struct symtab_and_line sal; + struct expression *exp; + struct block *exp_valid_block; + struct value *val; + + sal.pc = 0; + sal.symtab = NULL; + sal.line = 0; + + /* Parse arguments. */ + innermost_block = NULL; + exp = parse_expression (arg); + exp_valid_block = innermost_block; + val = evaluate_expression (exp); + release_value (val); + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + + /* Now set up the breakpoint. */ + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_watchpoint; + b->disposition = donttouch; + b->exp = exp; + b->exp_valid_block = exp_valid_block; + b->val = val; + b->cond = 0; + b->cond_string = NULL; + b->exp_string = savestring (arg, strlen (arg)); + mention (b); +} + +/* + * Helper routine for the until_command routine in infcmd.c. Here + * because it uses the mechanisms of breakpoints. + */ +/* ARGSUSED */ +void +until_break_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + FRAME prev_frame = get_prev_frame (selected_frame); + struct breakpoint *breakpoint; + struct cleanup *old_chain; + + clear_proceed_status (); + + /* Set a breakpoint where the user wants it and at return from + this function */ + + if (default_breakpoint_valid) + sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, + default_breakpoint_line, (char ***)NULL); + else + sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, (char ***)NULL); + + if (sals.nelts != 1) + error ("Couldn't get information on specified line."); + + sal = sals.sals[0]; + free ((PTR)sals.sals); /* malloc'd, so freed */ + + if (*arg) + error ("Junk at end of arguments."); + + resolve_sal_pc (&sal); + + breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until); + + old_chain = make_cleanup(delete_breakpoint, breakpoint); + + /* Keep within the current frame */ + + if (prev_frame) + { + struct frame_info *fi; + + fi = get_frame_info (prev_frame); + sal = find_pc_line (fi->pc, 0); + sal.pc = fi->pc; + breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until); + make_cleanup(delete_breakpoint, breakpoint); + } + + proceed (-1, -1, 0); + do_cleanups(old_chain); +} + +#if 0 +/* These aren't used; I don't konw what they were for. */ +/* Set a breakpoint at the catch clause for NAME. */ +static int +catch_breakpoint (name) + char *name; +{ +} + +static int +disable_catch_breakpoint () +{ +} + +static int +delete_catch_breakpoint () +{ +} + +static int +enable_catch_breakpoint () +{ +} +#endif /* 0 */ + +struct sal_chain +{ + struct sal_chain *next; + struct symtab_and_line sal; +}; + +#if 0 +/* This isn't used; I don't know what it was for. */ +/* For each catch clause identified in ARGS, run FUNCTION + with that clause as an argument. */ +static struct symtabs_and_lines +map_catch_names (args, function) + char *args; + int (*function)(); +{ + register char *p = args; + register char *p1; + struct symtabs_and_lines sals; +#if 0 + struct sal_chain *sal_chain = 0; +#endif + + if (p == 0) + error_no_arg ("one or more catch names"); + + sals.nelts = 0; + sals.sals = NULL; + + while (*p) + { + p1 = p; + /* Don't swallow conditional part. */ + if (p1[0] == 'i' && p1[1] == 'f' + && (p1[2] == ' ' || p1[2] == '\t')) + break; + + if (isalpha (*p1)) + { + p1++; + while (isalnum (*p1) || *p1 == '_' || *p1 == '$') + p1++; + } + + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be catch names."); + + *p1 = 0; +#if 0 + if (function (p)) + { + struct sal_chain *next + = (struct sal_chain *)alloca (sizeof (struct sal_chain)); + next->next = sal_chain; + next->sal = get_catch_sal (p); + sal_chain = next; + goto win; + } +#endif + printf ("No catch clause for exception %s.\n", p); +#if 0 + win: +#endif + p = p1; + while (*p == ' ' || *p == '\t') p++; + } +} +#endif /* 0 */ + +/* This shares a lot of code with `print_frame_label_vars' from stack.c. */ + +static struct symtabs_and_lines +get_catch_sals (this_level_only) + int this_level_only; +{ + register struct blockvector *bl; + register struct block *block; + int index, have_default = 0; + struct frame_info *fi; + CORE_ADDR pc; + struct symtabs_and_lines sals; + struct sal_chain *sal_chain = 0; + char *blocks_searched; + + /* Not sure whether an error message is always the correct response, + but it's better than a core dump. */ + if (selected_frame == NULL) + error ("No selected frame."); + block = get_frame_block (selected_frame); + fi = get_frame_info (selected_frame); + pc = fi->pc; + + sals.nelts = 0; + sals.sals = NULL; + + if (block == 0) + error ("No symbol table info available.\n"); + + bl = blockvector_for_pc (BLOCK_END (block) - 4, &index); + blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); + memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); + + while (block != 0) + { + CORE_ADDR end = BLOCK_END (block) - 4; + int last_index; + + if (bl != blockvector_for_pc (end, &index)) + error ("blockvector blotch"); + if (BLOCKVECTOR_BLOCK (bl, index) != block) + error ("blockvector botch"); + last_index = BLOCKVECTOR_NBLOCKS (bl); + index += 1; + + /* Don't print out blocks that have gone by. */ + while (index < last_index + && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc) + index++; + + while (index < last_index + && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end) + { + if (blocks_searched[index] == 0) + { + struct block *b = BLOCKVECTOR_BLOCK (bl, index); + int nsyms; + register int i; + register struct symbol *sym; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (STREQ (SYMBOL_NAME (sym), "default")) + { + if (have_default) + continue; + have_default = 1; + } + if (SYMBOL_CLASS (sym) == LOC_LABEL) + { + struct sal_chain *next = (struct sal_chain *) + alloca (sizeof (struct sal_chain)); + next->next = sal_chain; + next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0); + sal_chain = next; + } + } + blocks_searched[index] = 1; + } + index++; + } + if (have_default) + break; + if (sal_chain && this_level_only) + break; + + /* After handling the function's top-level block, stop. + Don't continue to its superblock, the block of + per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + + if (sal_chain) + { + struct sal_chain *tmp_chain; + + /* Count the number of entries. */ + for (index = 0, tmp_chain = sal_chain; tmp_chain; + tmp_chain = tmp_chain->next) + index++; + + sals.nelts = index; + sals.sals = (struct symtab_and_line *) + xmalloc (index * sizeof (struct symtab_and_line)); + for (index = 0; sal_chain; sal_chain = sal_chain->next, index++) + sals.sals[index] = sal_chain->sal; + } + + return sals; +} + +/* Commands to deal with catching exceptions. */ + +static void +catch_command_1 (arg, tempflag, from_tty) + char *arg; + int tempflag; + int from_tty; +{ + /* First, translate ARG into something we can deal with in terms + of breakpoints. */ + + struct symtabs_and_lines sals; + struct symtab_and_line sal; + register struct expression *cond = 0; + register struct breakpoint *b; + char *save_arg; + int i; + + sal.line = sal.pc = sal.end = 0; + sal.symtab = 0; + + /* If no arg given, or if first arg is 'if ', all active catch clauses + are breakpointed. */ + + if (!arg || (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t'))) + { + /* Grab all active catch clauses. */ + sals = get_catch_sals (0); + } + else + { + /* Grab selected catch clauses. */ + error ("catch NAME not implemented"); +#if 0 + /* This isn't used; I don't know what it was for. */ + sals = map_catch_names (arg, catch_breakpoint); +#endif + } + + if (! sals.nelts) + return; + + save_arg = arg; + for (i = 0; i < sals.nelts; i++) + { + resolve_sal_pc (&sals.sals[i]); + + while (arg && *arg) + { + if (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t')) + cond = parse_exp_1 ((arg += 2, &arg), + block_for_pc (sals.sals[i].pc), 0); + else + error ("Junk at end of arguments."); + } + arg = save_arg; + } + + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; + + if (from_tty) + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = cond; + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; + + mention (b); + } + + if (sals.nelts > 1) + { + printf ("Multiple breakpoints were set.\n"); + printf ("Use the \"delete\" command to delete unwanted breakpoints.\n"); + } + free ((PTR)sals.sals); +} + +#if 0 +/* These aren't used; I don't know what they were for. */ +/* Disable breakpoints on all catch clauses described in ARGS. */ +static void +disable_catch (args) + char *args; +{ + /* Map the disable command to catch clauses described in ARGS. */ +} + +/* Enable breakpoints on all catch clauses described in ARGS. */ +static void +enable_catch (args) + char *args; +{ + /* Map the disable command to catch clauses described in ARGS. */ +} + +/* Delete breakpoints on all catch clauses in the active scope. */ +static void +delete_catch (args) + char *args; +{ + /* Map the delete command to catch clauses described in ARGS. */ +} +#endif /* 0 */ + +static void +catch_command (arg, from_tty) + char *arg; + int from_tty; +{ + catch_command_1 (arg, 0, from_tty); +} + +static void +clear_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b, *b1; + struct symtabs_and_lines sals; + struct symtab_and_line sal; + register struct breakpoint *found; + int i; + + if (arg) + { + sals = decode_line_spec (arg, 1); + } + else + { + sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line)); + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + sal.pc = 0; + if (sal.symtab == 0) + error ("No source file specified."); + + sals.sals[0] = sal; + sals.nelts = 1; + } + + for (i = 0; i < sals.nelts; i++) + { + /* If exact pc given, clear bpts at that pc. + But if sal.pc is zero, clear all bpts on specified line. */ + sal = sals.sals[i]; + found = (struct breakpoint *) 0; + while (breakpoint_chain + && (sal.pc + ? breakpoint_chain->address == sal.pc + : (breakpoint_chain->source_file != NULL + && sal.symtab != NULL + && STREQ (breakpoint_chain->source_file, + sal.symtab->filename) + && breakpoint_chain->line_number == sal.line))) + { + b1 = breakpoint_chain; + breakpoint_chain = b1->next; + b1->next = found; + found = b1; + } + + ALL_BREAKPOINTS (b) + while (b->next + && b->next->type != bp_watchpoint + && (sal.pc + ? b->next->address == sal.pc + : (b->next->source_file != NULL + && sal.symtab != NULL + && STREQ (b->next->source_file, sal.symtab->filename) + && b->next->line_number == sal.line))) + { + b1 = b->next; + b->next = b1->next; + b1->next = found; + found = b1; + } + + if (found == 0) + { + if (arg) + error ("No breakpoint at %s.", arg); + else + error ("No breakpoint at this line."); + } + + if (found->next) from_tty = 1; /* Always report if deleted more than one */ + if (from_tty) printf ("Deleted breakpoint%s ", found->next ? "s" : ""); + while (found) + { + if (from_tty) printf ("%d ", found->number); + b1 = found->next; + delete_breakpoint (found); + found = b1; + } + if (from_tty) putchar ('\n'); + } + free ((PTR)sals.sals); +} + +/* Delete breakpoint in BS if they are `delete' breakpoints. + This is called after any breakpoint is hit, or after errors. */ + +void +breakpoint_auto_delete (bs) + bpstat bs; +{ + for (; bs; bs = bs->next) + if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete + && bs->stop) + delete_breakpoint (bs->breakpoint_at); +} + +/* Delete a breakpoint and clean up all traces of it in the data structures. */ + +void +delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + register struct breakpoint *b; + register bpstat bs; + + if (bpt->inserted) + target_remove_breakpoint(bpt->address, bpt->shadow_contents); + + if (breakpoint_chain == bpt) + breakpoint_chain = bpt->next; + + ALL_BREAKPOINTS (b) + if (b->next == bpt) + { + b->next = bpt->next; + break; + } + + check_duplicates (bpt->address); + /* If this breakpoint was inserted, and there is another breakpoint + at the same address, we need to insert the other breakpoint. */ + if (bpt->inserted) + { + ALL_BREAKPOINTS (b) + if (b->address == bpt->address + && !b->duplicate + && b->enable != disabled) + { + int val; + val = target_insert_breakpoint (b->address, b->shadow_contents); + if (val != 0) + { + fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number); + memory_error (val, b->address); /* which bombs us out */ + } + else + b->inserted = 1; + } + } + + free_command_lines (&bpt->commands); + if (bpt->cond) + free (bpt->cond); + if (bpt->cond_string != NULL) + free (bpt->cond_string); + if (bpt->addr_string != NULL) + free (bpt->addr_string); + if (bpt->exp_string != NULL) + free (bpt->exp_string); + if (bpt->source_file != NULL) + free (bpt->source_file); + + if (xgdb_verbose && bpt->type == bp_breakpoint) + printf ("breakpoint #%d deleted\n", bpt->number); + + /* Be sure no bpstat's are pointing at it after it's been freed. */ + /* FIXME, how can we find all bpstat's? We just check stop_bpstat for now. */ + for (bs = stop_bpstat; bs; bs = bs->next) + if (bs->breakpoint_at == bpt) + bs->breakpoint_at = NULL; + free ((PTR)bpt); +} + +static void +delete_command (arg, from_tty) + char *arg; + int from_tty; +{ + + if (arg == 0) + { + /* Ask user only if there are some breakpoints to delete. */ + if (!from_tty + || (breakpoint_chain && query ("Delete all breakpoints? ", 0, 0))) + { + /* No arg; clear all breakpoints. */ + while (breakpoint_chain) + delete_breakpoint (breakpoint_chain); + } + } + else + map_breakpoint_numbers (arg, delete_breakpoint); +} + +/* Reset a breakpoint given it's struct breakpoint * BINT. + The value we return ends up being the return value from catch_errors. + Unused in this case. */ + +static int +breakpoint_re_set_one (bint) + char *bint; +{ + struct breakpoint *b = (struct breakpoint *)bint; /* get past catch_errs */ + int i; + struct symtabs_and_lines sals; + char *s; + enum enable save_enable; + + switch (b->type) + { + case bp_breakpoint: + if (b->addr_string == NULL) + { + /* Anything without a string can't be re-set. */ + delete_breakpoint (b); + return 0; + } + /* In case we have a problem, disable this breakpoint. We'll restore + its status if we succeed. */ + save_enable = b->enable; + b->enable = disabled; + + s = b->addr_string; + sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0, (char ***)NULL); + for (i = 0; i < sals.nelts; i++) + { + resolve_sal_pc (&sals.sals[i]); + + /* Reparse conditions, they might contain references to the + old symtab. */ + if (b->cond_string != NULL) + { + s = b->cond_string; + if (b->cond) + free ((PTR)b->cond); + b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0); + } + + /* We need to re-set the breakpoint if the address changes...*/ + if (b->address != sals.sals[i].pc + /* ...or new and old breakpoints both have source files, and + the source file name or the line number changes... */ + || (b->source_file != NULL + && sals.sals[i].symtab != NULL + && (!STREQ (b->source_file, sals.sals[i].symtab->filename) + || b->line_number != sals.sals[i].line) + ) + /* ...or we switch between having a source file and not having + one. */ + || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL)) + ) + { + if (b->source_file != NULL) + free (b->source_file); + if (sals.sals[i].symtab == NULL) + b->source_file = NULL; + else + b->source_file = + savestring (sals.sals[i].symtab->filename, + strlen (sals.sals[i].symtab->filename)); + b->line_number = sals.sals[i].line; + b->address = sals.sals[i].pc; + + check_duplicates (b->address); + + mention (b); + } + b->enable = save_enable; /* Restore it, this worked. */ + } + free ((PTR)sals.sals); + break; + + case bp_watchpoint: + innermost_block = NULL; + /* The issue arises of what context to evaluate this in. The same + one as when it was set, but what does that mean when symbols have + been re-read? We could save the filename and functionname, but + if the context is more local than that, the best we could do would + be something like how many levels deep and which index at that + particular level, but that's going to be less stable than filenames + or functionnames. */ + /* So for now, just use a global context. */ + b->exp = parse_expression (b->exp_string); + b->exp_valid_block = innermost_block; + b->val = evaluate_expression (b->exp); + release_value (b->val); + if (VALUE_LAZY (b->val)) + value_fetch_lazy (b->val); + + if (b->cond_string != NULL) + { + s = b->cond_string; + b->cond = parse_exp_1 (&s, (struct block *)0, 0); + } + if (b->enable == enabled) + mention (b); + break; + + default: + printf_filtered ("Deleting unknown breakpoint type %d\n", b->type); + /* fall through */ + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_call_dummy: + delete_breakpoint (b); + break; + } + + return 0; +} + +/* Re-set all breakpoints after symbols have been re-loaded. */ +void +breakpoint_re_set () +{ + struct breakpoint *b, *temp; + static char message1[] = "Error in re-setting breakpoint %d:\n"; + char message[sizeof (message1) + 30 /* slop */]; + + ALL_BREAKPOINTS_SAFE (b, temp) + { + sprintf (message, message1, b->number); /* Format possible error msg */ + catch_errors (breakpoint_re_set_one, (char *) b, message, + RETURN_MASK_ALL); + } + + create_longjmp_breakpoint("longjmp"); + create_longjmp_breakpoint("_longjmp"); + create_longjmp_breakpoint("siglongjmp"); + create_longjmp_breakpoint(NULL); + +#if 0 + /* Took this out (temporaliy at least), since it produces an extra + blank line at startup. This messes up the gdbtests. -PB */ + /* Blank line to finish off all those mention() messages we just printed. */ + printf_filtered ("\n"); +#endif +} + +/* Set ignore-count of breakpoint number BPTNUM to COUNT. + If from_tty is nonzero, it prints a message to that effect, + which ends with a period (no newline). */ + +void +set_ignore_count (bptnum, count, from_tty) + int bptnum, count, from_tty; +{ + register struct breakpoint *b; + + if (count < 0) + count = 0; + + ALL_BREAKPOINTS (b) + if (b->number == bptnum) + { + b->ignore_count = count; + if (!from_tty) + return; + else if (count == 0) + printf_filtered ("Will stop next time breakpoint %d is reached.", + bptnum); + else if (count == 1) + printf_filtered ("Will ignore next crossing of breakpoint %d.", + bptnum); + else + printf_filtered ("Will ignore next %d crossings of breakpoint %d.", + count, bptnum); + return; + } + + error ("No breakpoint number %d.", bptnum); +} + +/* Clear the ignore counts of all breakpoints. */ +void +breakpoint_clear_ignore_counts () +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + b->ignore_count = 0; +} + +/* Command to set ignore-count of breakpoint N to COUNT. */ + +static void +ignore_command (args, from_tty) + char *args; + int from_tty; +{ + char *p = args; + register int num; + + if (p == 0) + error_no_arg ("a breakpoint number"); + + num = get_number (&p); + + if (*p == 0) + error ("Second argument (specified ignore-count) is missing."); + + set_ignore_count (num, + longest_to_int (value_as_long (parse_and_eval (p))), + from_tty); + printf_filtered ("\n"); +} + +/* Call FUNCTION on each of the breakpoints + whose numbers are given in ARGS. */ + +static void +map_breakpoint_numbers (args, function) + char *args; + void (*function) PARAMS ((struct breakpoint *)); +{ + register char *p = args; + char *p1; + register int num; + register struct breakpoint *b; + + if (p == 0) + error_no_arg ("one or more breakpoint numbers"); + + while (*p) + { + p1 = p; + + num = get_number (&p1); + + ALL_BREAKPOINTS (b) + if (b->number == num) + { + function (b); + goto win; + } + printf ("No breakpoint number %d.\n", num); + win: + p = p1; + } +} + +static void +enable_breakpoint (bpt) + struct breakpoint *bpt; +{ + FRAME save_selected_frame = NULL; + int save_selected_frame_level = -1; + + bpt->enable = enabled; + + if (xgdb_verbose && bpt->type == bp_breakpoint) + printf ("breakpoint #%d enabled\n", bpt->number); + + check_duplicates (bpt->address); + if (bpt->type == bp_watchpoint) + { + if (bpt->exp_valid_block != NULL) + { + FRAME fr = within_scope (bpt->exp_valid_block); + if (fr == NULL) + { + printf_filtered ("\ +Cannot enable watchpoint %d because the block in which its expression\n\ +is valid is not currently in scope.\n", bpt->number); + bpt->enable = disabled; + return; + } + save_selected_frame = selected_frame; + save_selected_frame_level = selected_frame_level; + select_frame (fr, -1); + } + + value_free (bpt->val); + + bpt->val = evaluate_expression (bpt->exp); + release_value (bpt->val); + if (VALUE_LAZY (bpt->val)) + value_fetch_lazy (bpt->val); + + if (save_selected_frame_level >= 0) + select_frame (save_selected_frame, save_selected_frame_level); + } +} + +/* ARGSUSED */ +static void +enable_command (args, from_tty) + char *args; + int from_tty; +{ + struct breakpoint *bpt; + if (args == 0) + ALL_BREAKPOINTS (bpt) + switch (bpt->type) + { + case bp_breakpoint: + case bp_watchpoint: + enable_breakpoint (bpt); + default: + continue; + } + else + map_breakpoint_numbers (args, enable_breakpoint); +} + +static void +disable_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = disabled; + + if (xgdb_verbose && bpt->type == bp_breakpoint) + printf_filtered ("breakpoint #%d disabled\n", bpt->number); + + check_duplicates (bpt->address); +} + +/* ARGSUSED */ +static void +disable_command (args, from_tty) + char *args; + int from_tty; +{ + register struct breakpoint *bpt; + if (args == 0) + ALL_BREAKPOINTS (bpt) + switch (bpt->type) + { + case bp_breakpoint: + case bp_watchpoint: + disable_breakpoint (bpt); + default: + continue; + } + else + map_breakpoint_numbers (args, disable_breakpoint); +} + +static void +enable_once_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = enabled; + bpt->disposition = disable; + + check_duplicates (bpt->address); +} + +/* ARGSUSED */ +static void +enable_once_command (args, from_tty) + char *args; + int from_tty; +{ + map_breakpoint_numbers (args, enable_once_breakpoint); +} + +static void +enable_delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = enabled; + bpt->disposition = delete; + + check_duplicates (bpt->address); +} + +/* ARGSUSED */ +static void +enable_delete_command (args, from_tty) + char *args; + int from_tty; +{ + map_breakpoint_numbers (args, enable_delete_breakpoint); +} + +/* + * Use default_breakpoint_'s, or nothing if they aren't valid. + */ +struct symtabs_and_lines +decode_line_spec_1 (string, funfirstline) + char *string; + int funfirstline; +{ + struct symtabs_and_lines sals; + if (string == 0) + error ("Empty line specification."); + if (default_breakpoint_valid) + sals = decode_line_1 (&string, funfirstline, + default_breakpoint_symtab, default_breakpoint_line, + (char ***)NULL); + else + sals = decode_line_1 (&string, funfirstline, + (struct symtab *)NULL, 0, (char ***)NULL); + if (*string) + error ("Junk at end of line specification: %s", string); + return sals; +} + +void +_initialize_breakpoint () +{ + breakpoint_chain = 0; + /* Don't bother to call set_breakpoint_count. $bpnum isn't useful + before a breakpoint is set. */ + breakpoint_count = 0; + + add_com ("ignore", class_breakpoint, ignore_command, + "Set ignore-count of breakpoint number N to COUNT."); + + add_com ("commands", class_breakpoint, commands_command, + "Set commands to be executed when a breakpoint is hit.\n\ +Give breakpoint number as argument after \"commands\".\n\ +With no argument, the targeted breakpoint is the last one set.\n\ +The commands themselves follow starting on the next line.\n\ +Type a line containing \"end\" to indicate the end of them.\n\ +Give \"silent\" as the first line to make the breakpoint silent;\n\ +then no output is printed when it is hit, except what the commands print."); + + add_com ("condition", class_breakpoint, condition_command, + "Specify breakpoint number N to break only if COND is true.\n\ +N is an integer; COND is an expression to be evaluated whenever\n\ +breakpoint N is reached. "); + + add_com ("tbreak", class_breakpoint, tbreak_command, + "Set a temporary breakpoint. Args like \"break\" command.\n\ +Like \"break\" except the breakpoint is only enabled temporarily,\n\ +so it will be disabled when hit. Equivalent to \"break\" followed\n\ +by using \"enable once\" on the breakpoint number."); + + add_prefix_cmd ("enable", class_breakpoint, enable_command, + "Enable some breakpoints.\n\ +Give breakpoint numbers (separated by spaces) as arguments.\n\ +With no subcommand, breakpoints are enabled until you command otherwise.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +With a subcommand you can enable temporarily.", + &enablelist, "enable ", 1, &cmdlist); + + add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, + "Enable some breakpoints.\n\ +Give breakpoint numbers (separated by spaces) as arguments.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +May be abbreviated to simply \"enable\".\n", + &enablebreaklist, "enable breakpoints ", 1, &enablelist); + + add_cmd ("once", no_class, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\ +See the \"tbreak\" command which sets a breakpoint and enables it once.", + &enablebreaklist); + + add_cmd ("delete", no_class, enable_delete_command, + "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it is deleted.", + &enablebreaklist); + + add_cmd ("delete", no_class, enable_delete_command, + "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it is deleted.", + &enablelist); + + add_cmd ("once", no_class, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\ +See the \"tbreak\" command which sets a breakpoint and enables it once.", + &enablelist); + + add_prefix_cmd ("disable", class_breakpoint, disable_command, + "Disable some breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To disable all breakpoints, give no argument.\n\ +A disabled breakpoint is not forgotten, but has no effect until reenabled.", + &disablelist, "disable ", 1, &cmdlist); + add_com_alias ("dis", "disable", class_breakpoint, 1); + add_com_alias ("disa", "disable", class_breakpoint, 1); + + add_cmd ("breakpoints", class_alias, disable_command, + "Disable some breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To disable all breakpoints, give no argument.\n\ +A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\ +This command may be abbreviated \"disable\".", + &disablelist); + + add_prefix_cmd ("delete", class_breakpoint, delete_command, + "Delete some breakpoints or auto-display expressions.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument.\n\ +\n\ +Also a prefix command for deletion of other GDB objects.\n\ +The \"unset\" command is also an alias for \"delete\".", + &deletelist, "delete ", 1, &cmdlist); + add_com_alias ("d", "delete", class_breakpoint, 1); + + add_cmd ("breakpoints", class_alias, delete_command, + "Delete some breakpoints or auto-display expressions.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument.\n\ +This command may be abbreviated \"delete\".", + &deletelist); + + add_com ("clear", class_breakpoint, clear_command, + "Clear breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, all breakpoints in that line are cleared.\n\ +If function is specified, breakpoints at beginning of function are cleared.\n\ +If an address is specified, breakpoints at that address are cleared.\n\n\ +With no argument, clears all breakpoints in the line that the selected frame\n\ +is executing in.\n\ +\n\ +See also the \"delete\" command which clears breakpoints by number."); + + add_com ("break", class_breakpoint, break_command, + "Set breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, break at start of code for that line.\n\ +If function is specified, break at start of code for that function.\n\ +If an address is specified, break at that exact address.\n\ +With no arg, uses current execution address of selected stack frame.\n\ +This is useful for breaking on return to a stack frame.\n\ +\n\ +Multiple breakpoints at one place are permitted, and useful if conditional.\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints."); + add_com_alias ("b", "break", class_run, 1); + add_com_alias ("br", "break", class_run, 1); + add_com_alias ("bre", "break", class_run, 1); + add_com_alias ("brea", "break", class_run, 1); + + add_info ("breakpoints", breakpoints_info, + "Status of user-settable breakpoints, or breakpoint number NUMBER.\n\ +The \"Type\" column indicates one of:\n\ +\tbreakpoint - normal breakpoint\n\ +\twatchpoint - watchpoint\n\ +The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\ +the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\ +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\ +address and file/line number respectively.\n\n\ +Convenience variable \"$_\" and default examine address for \"x\"\n\ +are set to the address of the last breakpoint listed.\n\n\ +Convenience variable \"$bpnum\" contains the number of the last\n\ +breakpoint set."); + +#if MAINTENANCE_CMDS + + add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints, + "Status of all breakpoints, or breakpoint number NUMBER.\n\ +The \"Type\" column indicates one of:\n\ +\tbreakpoint - normal breakpoint\n\ +\twatchpoint - watchpoint\n\ +\tlongjmp - internal breakpoint used to step through longjmp()\n\ +\tlongjmp resume - internal breakpoint at the target of longjmp()\n\ +\tuntil - internal breakpoint used by the \"until\" command\n\ +\tfinish - internal breakpoint used by the \"finish\" command\n\ +The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\ +the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\ +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\ +address and file/line number respectively.\n\n\ +Convenience variable \"$_\" and default examine address for \"x\"\n\ +are set to the address of the last breakpoint listed.\n\n\ +Convenience variable \"$bpnum\" contains the number of the last\n\ +breakpoint set.", + &maintenanceinfolist); + +#endif /* MAINTENANCE_CMDS */ + + add_com ("catch", class_breakpoint, catch_command, + "Set breakpoints to catch exceptions that are raised.\n\ +Argument may be a single exception to catch, multiple exceptions\n\ +to catch, or the default exception \"default\". If no arguments\n\ +are given, breakpoints are set at all exception handlers catch clauses\n\ +within the current scope.\n\ +\n\ +A condition specified for the catch applies to all breakpoints set\n\ +with this command\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints."); + + add_com ("watch", class_breakpoint, watch_command, + "Set a watchpoint for an expression.\n\ +A watchpoint stops execution of your program whenever the value of\n\ +an expression changes."); + + add_info ("watchpoints", breakpoints_info, + "Synonym for ``info breakpoints''."); +} + +/* OK, when we call objfile_relocate, we need to relocate breakpoints + too. breakpoint_re_set is not a good choice--for example, if + addr_string contains just a line number without a file name the + breakpoint might get set in a different file. In general, there is + no need to go all the way back to the user's string (though this might + work if some effort were made to canonicalize it), since symtabs and + everything except addresses are still valid. + + Probably the best way to solve this is to have each breakpoint save + the objfile and the section number that was used to set it (if set + by "*addr", probably it is best to use find_pc_line to get a symtab + and use the objfile and block_line_section for that symtab). Then + objfile_relocate can call fixup_breakpoints with the objfile and + the new_offsets, and it can relocate only the appropriate breakpoints. */ + +#ifdef IBM6000_TARGET +/* But for now, just kludge it based on the concept that before an + objfile is relocated the breakpoint is below 0x10000000, and afterwards + it is higher, so that way we only relocate each breakpoint once. */ + +void +fixup_breakpoints (low, high, delta) + CORE_ADDR low; + CORE_ADDR high; + CORE_ADDR delta; +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + { + if (b->address >= low && b->address <= high) + b->address += delta; + } +} +#endif diff --git a/gnu/usr.bin/gdb/gdb/breakpoint.h b/gnu/usr.bin/gdb/gdb/breakpoint.h new file mode 100644 index 00000000000..5005450804d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/breakpoint.h @@ -0,0 +1,372 @@ +/* Data structures associated with breakpoints in GDB. + Copyright (C) 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. */ + +#if !defined (BREAKPOINT_H) +#define BREAKPOINT_H 1 + +#include "frame.h" +#include "value.h" + +/* This is the maximum number of bytes a breakpoint instruction can take. + Feel free to increase it. It's just used in a few places to size + arrays that should be independent of the target architecture. */ + +#define BREAKPOINT_MAX 16 + +/* Type of breakpoint. */ +/* FIXME In the future, we should fold all other breakpoint-like things into + here. This includes: + + * single-step (for machines where we have to simulate single stepping) + (probably, though perhaps it is better for it to look as much as + possible like a single-step to wait_for_inferior). */ + +enum bptype { + bp_breakpoint, /* Normal breakpoint */ + bp_until, /* used by until command */ + bp_finish, /* used by finish command */ + bp_watchpoint, /* Watchpoint */ + bp_longjmp, /* secret breakpoint to find longjmp() */ + bp_longjmp_resume, /* secret breakpoint to escape longjmp() */ + + /* Used by wait_for_inferior for stepping over subroutine calls, for + stepping over signal handlers, and for skipping prologues. */ + bp_step_resume, + + /* The breakpoint at the end of a call dummy. */ + /* FIXME: What if the function we are calling longjmp()s out of the + call, or the user gets out with the "return" command? We currently + have no way of cleaning up the breakpoint in these (obscure) situations. + (Probably can solve this by noticing longjmp, "return", etc., it's + similar to noticing when a watchpoint on a local variable goes out + of scope (with hardware support for watchpoints)). */ + bp_call_dummy +}; + +/* States of enablement of breakpoint. */ + +enum enable { disabled, enabled}; + +/* Disposition of breakpoint. Ie: what to do after hitting it. */ + +enum bpdisp { + delete, /* Delete it */ + disable, /* Disable it */ + donttouch /* Leave it alone */ +}; + +/* Note that the ->silent field is not currently used by any commands + (though the code is in there if it was to be, and set_raw_breakpoint + does set it to 0). I implemented it because I thought it would be + useful for a hack I had to put in; I'm going to leave it in because + I can see how there might be times when it would indeed be useful */ + +/* This is for a breakpoint or a watchpoint. */ + +struct breakpoint +{ + struct breakpoint *next; + /* Type of breakpoint. */ + enum bptype type; + /* Zero means disabled; remember the info but don't break here. */ + enum enable enable; + /* What to do with this breakpoint after we hit it. */ + enum bpdisp disposition; + /* Number assigned to distinguish breakpoints. */ + int number; + + /* Address to break at, or NULL if not a breakpoint. */ + CORE_ADDR address; + + /* Line number of this address. Only matters if address is + non-NULL. */ + + int line_number; + + /* Source file name of this address. Only matters if address is + non-NULL. */ + + char *source_file; + + /* Non-zero means a silent breakpoint (don't print frame info + if we stop here). */ + unsigned char silent; + /* Number of stops at this breakpoint that should + be continued automatically before really stopping. */ + int ignore_count; + /* "Real" contents of byte where breakpoint has been inserted. + Valid only when breakpoints are in the program. Under the complete + control of the target insert_breakpoint and remove_breakpoint routines. + No other code should assume anything about the value(s) here. */ + char shadow_contents[BREAKPOINT_MAX]; + /* Nonzero if this breakpoint is now inserted. Only matters if address + is non-NULL. */ + char inserted; + /* Nonzero if this is not the first breakpoint in the list + for the given address. Only matters if address is non-NULL. */ + char duplicate; + /* Chain of command lines to execute when this breakpoint is hit. */ + struct command_line *commands; + /* Stack depth (address of frame). If nonzero, break only if fp + equals this. */ + FRAME_ADDR frame; + /* Conditional. Break only if this expression's value is nonzero. */ + struct expression *cond; + + /* String we used to set the breakpoint (malloc'd). Only matters if + address is non-NULL. */ + char *addr_string; + /* String form of the breakpoint condition (malloc'd), or NULL if there + is no condition. */ + char *cond_string; + /* String form of exp (malloc'd), or NULL if none. */ + char *exp_string; + + /* The expression we are watching, or NULL if not a watchpoint. */ + struct expression *exp; + /* The largest block within which it is valid, or NULL if it is + valid anywhere (e.g. consists just of global symbols). */ + struct block *exp_valid_block; + /* Value of the watchpoint the last time we checked it. */ + value val; + /* Thread number for thread-specific breakpoint, or -1 if don't care */ + int thread; +}; + +/* The following stuff is an abstract data type "bpstat" ("breakpoint status"). + This provides the ability to determine whether we have stopped at a + breakpoint, and what we should do about it. */ + +typedef struct bpstat *bpstat; + +/* Interface: */ +/* Clear a bpstat so that it says we are not at any breakpoint. + Also free any storage that is part of a bpstat. */ +extern void bpstat_clear PARAMS ((bpstat *)); + +/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that + is part of the bpstat is copied as well. */ +extern bpstat bpstat_copy PARAMS ((bpstat)); + +/* FIXME: prototypes uses equivalence between FRAME_ADDR and CORE_ADDR */ +extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, CORE_ADDR, int)); + +/* This bpstat_what stuff tells wait_for_inferior what to do with a + breakpoint (a challenging task). */ + +enum bpstat_what_main_action { + /* Perform various other tests; that is, this bpstat does not + say to perform any action (e.g. failed watchpoint and nothing + else). */ + BPSTAT_WHAT_KEEP_CHECKING, + + /* Rather than distinguish between noisy and silent stops here, it + might be cleaner to have bpstat_print make that decision (also + taking into account stop_print_frame and source_only). But the + implications are a bit scary (interaction with auto-displays, etc.), + so I won't try it. */ + + /* Stop silently. */ + BPSTAT_WHAT_STOP_SILENT, + + /* Stop and print. */ + BPSTAT_WHAT_STOP_NOISY, + + /* Remove breakpoints, single step once, then put them back in and + go back to what we were doing. It's possible that this should be + removed from the main_action and put into a separate field, to more + cleanly handle BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE. */ + BPSTAT_WHAT_SINGLE, + + /* Set longjmp_resume breakpoint, remove all other breakpoints, + and continue. The "remove all other breakpoints" part is required + if we are also stepping over another breakpoint as well as doing + the longjmp handling. */ + BPSTAT_WHAT_SET_LONGJMP_RESUME, + + /* Clear longjmp_resume breakpoint, then handle as + BPSTAT_WHAT_KEEP_CHECKING. */ + BPSTAT_WHAT_CLEAR_LONGJMP_RESUME, + + /* Clear longjmp_resume breakpoint, then handle as BPSTAT_WHAT_SINGLE. */ + BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE, + + /* This is just used to keep track of how many enums there are. */ + BPSTAT_WHAT_LAST +}; + +struct bpstat_what { + enum bpstat_what_main_action main_action; + + /* Did we hit the step resume breakpoint? This is separate from the + main_action to allow for it to be combined with any of the main + actions. */ + int step_resume; + + /* Did we hit a call dummy breakpoint? This only goes with a main_action + of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of + continuing from a call dummy without popping the frame is not a + useful one). */ + int call_dummy; +}; + +/* Tell what to do about this bpstat. */ +struct bpstat_what bpstat_what PARAMS ((bpstat)); + +/* Find the bpstat associated with a breakpoint. NULL otherwise. */ +bpstat bpstat_find_breakpoint PARAMS ((bpstat, struct breakpoint *)); + +/* Nonzero if a signal that we got in wait() was due to circumstances + explained by the BS. */ +/* Currently that is true if we have hit a breakpoint, or if there is + a watchpoint enabled. */ +#define bpstat_explains_signal(bs) ((bs) != NULL) + +/* Nonzero if we should step constantly (e.g. watchpoints on machines + without hardware support). This isn't related to a specific bpstat, + just to things like whether watchpoints are set. */ +extern int bpstat_should_step PARAMS ((void)); + +/* Print a message indicating what happened. Returns nonzero to + say that only the source line should be printed after this (zero + return means print the frame as well as the source line). */ +extern int bpstat_print PARAMS ((bpstat)); + +/* Return the breakpoint number of the first breakpoint we are stopped + at. *BSP upon return is a bpstat which points to the remaining + breakpoints stopped at (but which is not guaranteed to be good for + anything but further calls to bpstat_num). + Return 0 if passed a bpstat which does not indicate any breakpoints. */ +extern int bpstat_num PARAMS ((bpstat *)); + +/* Perform actions associated with having stopped at *BSP. Actually, we just + use this for breakpoint commands. Perhaps other actions will go here + later, but this is executed at a late time (from the command loop). */ +extern void bpstat_do_actions PARAMS ((bpstat *)); + +/* Modify BS so that the actions will not be performed. */ +extern void bpstat_clear_actions PARAMS ((bpstat)); + +/* Implementation: */ +struct bpstat +{ + /* Linked list because there can be two breakpoints at the + same place, and a bpstat reflects the fact that both have been hit. */ + bpstat next; + /* Breakpoint that we are at. */ + struct breakpoint *breakpoint_at; + /* Commands left to be done. */ + struct command_line *commands; + /* Old value associated with a watchpoint. */ + value old_val; + + /* Nonzero if this breakpoint tells us to print the frame. */ + char print; + + /* Nonzero if this breakpoint tells us to stop. */ + char stop; + + /* Function called by bpstat_print to print stuff associated with + this element of the bpstat chain. Returns 0 or 1 just like + bpstat_print, or -1 if it can't deal with it. */ + int (*print_it) PARAMS((bpstat bs)); +}; + +/* Prototypes for breakpoint-related functions. */ + +#ifdef __STDC__ /* Forward declarations for prototypes */ +struct frame_info; +#endif + +extern int +breakpoint_here_p PARAMS ((CORE_ADDR)); + +extern int +breakpoint_thread_match PARAMS ((CORE_ADDR, int)); + +extern void +until_break_command PARAMS ((char *, int)); + +extern void +breakpoint_re_set PARAMS ((void)); + +extern void +clear_momentary_breakpoints PARAMS ((void)); + +/* FIXME: Prototype uses equivalence of "struct frame_info *" and FRAME */ +extern struct breakpoint * +set_momentary_breakpoint PARAMS ((struct symtab_and_line, + struct frame_info *, + enum bptype)); + +extern void +set_ignore_count PARAMS ((int, int, int)); + +extern void +set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int)); + +extern void +mark_breakpoints_out PARAMS ((void)); + +extern void +breakpoint_init_inferior PARAMS ((void)); + +extern void +delete_breakpoint PARAMS ((struct breakpoint *)); + +extern void +breakpoint_auto_delete PARAMS ((bpstat)); + +extern void +breakpoint_clear_ignore_counts PARAMS ((void)); + +extern void +break_command PARAMS ((char *, int)); + +extern int +insert_breakpoints PARAMS ((void)); + +extern int +remove_breakpoints PARAMS ((void)); + +extern void +enable_longjmp_breakpoint PARAMS ((void)); + +extern void +disable_longjmp_breakpoint PARAMS ((void)); + +extern void +set_longjmp_resume_breakpoint PARAMS ((CORE_ADDR, FRAME)); + +/* The following are for displays, which aren't really breakpoints, but + here is as good a place as any for them. */ + +extern void +disable_current_display PARAMS ((void)); + +extern void +do_displays PARAMS ((void)); + +extern void +disable_display PARAMS ((int)); + +extern void +clear_displays PARAMS ((void)); + +#endif /* !defined (BREAKPOINT_H) */ diff --git a/gnu/usr.bin/gdb/gdb/buildsym.c b/gnu/usr.bin/gdb/gdb/buildsym.c new file mode 100644 index 00000000000..dfa9be13162 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/buildsym.c @@ -0,0 +1,950 @@ +/* Support routines for building symbol tables in GDB's internal format. + Copyright 1986, 1987, 1988, 1989, 1990, 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. */ + +/* This module provides subroutines used for creating and adding to + the symbol table. These routines are called from various symbol- + file-reading routines. + + Routines to support specific debugging information formats (stabs, + DWARF, etc) belong somewhere else. */ + +#include "defs.h" +#include "bfd.h" +#include "obstack.h" +#include "symtab.h" +#include "symfile.h" /* Needed for "struct complaint" */ +#include "objfiles.h" +#include "complaints.h" +#include + +/* Ask buildsym.h to define the vars it normally declares `extern'. */ +#define EXTERN /**/ +#include "buildsym.h" /* Our own declarations */ +#undef EXTERN + +static int +compare_line_numbers PARAMS ((const void *, const void *)); + +static struct blockvector * +make_blockvector PARAMS ((struct objfile *)); + + +/* Initial sizes of data structures. These are realloc'd larger if needed, + and realloc'd down to the size actually used, when completed. */ + +#define INITIAL_CONTEXT_STACK_SIZE 10 +#define INITIAL_LINE_VECTOR_LENGTH 1000 + + +/* Complaints about the symbols we have encountered. */ + +struct complaint innerblock_complaint = + {"inner block not inside outer block in %s", 0, 0}; + +struct complaint innerblock_anon_complaint = + {"inner block not inside outer block", 0, 0}; + +struct complaint blockvector_complaint = + {"block at 0x%lx out of order", 0, 0}; + + +/* maintain the lists of symbols and blocks */ + +/* Add a symbol to one of the lists of symbols. */ + +void +add_symbol_to_list (symbol, listhead) + struct symbol *symbol; + struct pending **listhead; +{ + register struct pending *link; + + /* We keep PENDINGSIZE symbols in each link of the list. + If we don't have a link with room in it, add a new link. */ + if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE) + { + if (free_pendings) + { + link = free_pendings; + free_pendings = link->next; + } + else + { + link = (struct pending *) xmalloc (sizeof (struct pending)); + } + + link->next = *listhead; + *listhead = link; + link->nsyms = 0; + } + + (*listhead)->symbol[(*listhead)->nsyms++] = symbol; +} + +/* Find a symbol named NAME on a LIST. NAME need not be '\0'-terminated; + LENGTH is the length of the name. */ + +struct symbol * +find_symbol_in_list (list, name, length) + struct pending *list; + char *name; + int length; +{ + int j; + char *pp; + + while (list != NULL) + { + for (j = list->nsyms; --j >= 0; ) + { + pp = SYMBOL_NAME (list->symbol[j]); + if (*pp == *name && strncmp (pp, name, length) == 0 && + pp[length] == '\0') + { + return (list->symbol[j]); + } + } + list = list->next; + } + return (NULL); +} + +/* At end of reading syms, or in case of quit, + really free as many `struct pending's as we can easily find. */ + +/* ARGSUSED */ +void +really_free_pendings (foo) + int foo; +{ + struct pending *next, *next1; +#if 0 + struct pending_block *bnext, *bnext1; +#endif + + for (next = free_pendings; next; next = next1) + { + next1 = next->next; + free ((PTR)next); + } + free_pendings = NULL; + +#if 0 /* Now we make the links in the symbol_obstack, so don't free them. */ + for (bnext = pending_blocks; bnext; bnext = bnext1) + { + bnext1 = bnext->next; + free ((PTR)bnext); + } +#endif + pending_blocks = NULL; + + for (next = file_symbols; next != NULL; next = next1) + { + next1 = next->next; + free ((PTR)next); + } + file_symbols = NULL; + + for (next = global_symbols; next != NULL; next = next1) + { + next1 = next->next; + free ((PTR)next); + } + global_symbols = NULL; +} + +/* Take one of the lists of symbols and make a block from it. + Keep the order the symbols have in the list (reversed from the input file). + Put the block on the list of pending blocks. */ + +void +finish_block (symbol, listhead, old_blocks, start, end, objfile) + struct symbol *symbol; + struct pending **listhead; + struct pending_block *old_blocks; + CORE_ADDR start, end; + struct objfile *objfile; +{ + register struct pending *next, *next1; + register struct block *block; + register struct pending_block *pblock; + struct pending_block *opblock; + register int i; + register int j; + + /* Count the length of the list of symbols. */ + + for (next = *listhead, i = 0; + next; + i += next->nsyms, next = next->next) + { + /*EMPTY*/; + } + + block = (struct block *) obstack_alloc (&objfile -> symbol_obstack, + (sizeof (struct block) + ((i - 1) * sizeof (struct symbol *)))); + + /* Copy the symbols into the block. */ + + BLOCK_NSYMS (block) = i; + for (next = *listhead; next; next = next->next) + { + for (j = next->nsyms - 1; j >= 0; j--) + { + BLOCK_SYM (block, --i) = next->symbol[j]; + } + } + + BLOCK_START (block) = start; + BLOCK_END (block) = end; + /* Superblock filled in when containing block is made */ + BLOCK_SUPERBLOCK (block) = NULL; + BLOCK_GCC_COMPILED (block) = processing_gcc_compilation; + + /* Put the block in as the value of the symbol that names it. */ + + if (symbol) + { + SYMBOL_BLOCK_VALUE (symbol) = block; + BLOCK_FUNCTION (block) = symbol; + } + else + { + BLOCK_FUNCTION (block) = NULL; + } + + /* Now "free" the links of the list, and empty the list. */ + + for (next = *listhead; next; next = next1) + { + next1 = next->next; + next->next = free_pendings; + free_pendings = next; + } + *listhead = NULL; + + /* Install this block as the superblock + of all blocks made since the start of this scope + that don't have superblocks yet. */ + + opblock = NULL; + for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next) + { + if (BLOCK_SUPERBLOCK (pblock->block) == NULL) + { +#if 1 + /* Check to be sure the blocks are nested as we receive them. + If the compiler/assembler/linker work, this just burns a small + amount of time. */ + if (BLOCK_START (pblock->block) < BLOCK_START (block) || + BLOCK_END (pblock->block) > BLOCK_END (block)) + { + if (symbol) + { + complain (&innerblock_complaint, + SYMBOL_SOURCE_NAME (symbol)); + } + else + { + complain (&innerblock_anon_complaint); + } + BLOCK_START (pblock->block) = BLOCK_START (block); + BLOCK_END (pblock->block) = BLOCK_END (block); + } +#endif + BLOCK_SUPERBLOCK (pblock->block) = block; + } + opblock = pblock; + } + + /* Record this block on the list of all blocks in the file. + Put it after opblock, or at the beginning if opblock is 0. + This puts the block in the list after all its subblocks. */ + + /* Allocate in the symbol_obstack to save time. + It wastes a little space. */ + pblock = (struct pending_block *) + obstack_alloc (&objfile -> symbol_obstack, + sizeof (struct pending_block)); + pblock->block = block; + if (opblock) + { + pblock->next = opblock->next; + opblock->next = pblock; + } + else + { + pblock->next = pending_blocks; + pending_blocks = pblock; + } +} + +static struct blockvector * +make_blockvector (objfile) + struct objfile *objfile; +{ + register struct pending_block *next; + register struct blockvector *blockvector; + register int i; + + /* Count the length of the list of blocks. */ + + for (next = pending_blocks, i = 0; next; next = next->next, i++) {;} + + blockvector = (struct blockvector *) + obstack_alloc (&objfile -> symbol_obstack, + (sizeof (struct blockvector) + + (i - 1) * sizeof (struct block *))); + + /* Copy the blocks into the blockvector. + This is done in reverse order, which happens to put + the blocks into the proper order (ascending starting address). + finish_block has hair to insert each block into the list + after its subblocks in order to make sure this is true. */ + + BLOCKVECTOR_NBLOCKS (blockvector) = i; + for (next = pending_blocks; next; next = next->next) + { + BLOCKVECTOR_BLOCK (blockvector, --i) = next->block; + } + +#if 0 /* Now we make the links in the obstack, so don't free them. */ + /* Now free the links of the list, and empty the list. */ + + for (next = pending_blocks; next; next = next1) + { + next1 = next->next; + free (next); + } +#endif + pending_blocks = NULL; + +#if 1 /* FIXME, shut this off after a while to speed up symbol reading. */ + /* Some compilers output blocks in the wrong order, but we depend + on their being in the right order so we can binary search. + Check the order and moan about it. FIXME. */ + if (BLOCKVECTOR_NBLOCKS (blockvector) > 1) + { + for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) + { + if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1)) + > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))) + { + complain (&blockvector_complaint, + (unsigned long) BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))); + } + } + } +#endif + + return (blockvector); +} + + +/* Start recording information about source code that came from an included + (or otherwise merged-in) source file with a different name. NAME is + the name of the file (cannot be NULL), DIRNAME is the directory in which + it resides (or NULL if not known). */ + +void +start_subfile (name, dirname) + char *name; + char *dirname; +{ + register struct subfile *subfile; + + /* See if this subfile is already known as a subfile of the + current main source file. */ + + for (subfile = subfiles; subfile; subfile = subfile->next) + { + if (STREQ (subfile->name, name)) + { + current_subfile = subfile; + return; + } + } + + /* This subfile is not known. Add an entry for it. + Make an entry for this subfile in the list of all subfiles + of the current main source file. */ + + subfile = (struct subfile *) xmalloc (sizeof (struct subfile)); + subfile->next = subfiles; + subfiles = subfile; + current_subfile = subfile; + + /* Save its name and compilation directory name */ + subfile->name = (name == NULL)? NULL : strdup (name); + subfile->dirname = (dirname == NULL) ? NULL : strdup (dirname); + + /* Initialize line-number recording for this subfile. */ + subfile->line_vector = NULL; + + /* Default the source language to whatever can be deduced from + the filename. If nothing can be deduced (such as for a C/C++ + include file with a ".h" extension), then inherit whatever + language the previous subfile had. This kludgery is necessary + because there is no standard way in some object formats to + record the source language. Also, when symtabs are allocated + we try to deduce a language then as well, but it is too late + for us to use that information while reading symbols, since + symtabs aren't allocated until after all the symbols have + been processed for a given source file. */ + + subfile->language = deduce_language_from_filename (subfile->name); + if (subfile->language == language_unknown && + subfile->next != NULL) + { + subfile->language = subfile->next->language; + } + + /* cfront output is a C program, so in most ways it looks like a C + program. But to demangle we need to set the language to C++. We + can distinguish cfront code by the fact that it has #line + directives which specify a file name ending in .C. + + So if the filename of this subfile ends in .C, then change the language + of any pending subfiles from C to C++. We also accept any other C++ + suffixes accepted by deduce_language_from_filename (in particular, + some people use .cxx with cfront). */ + + if (subfile->name) + { + struct subfile *s; + + if (deduce_language_from_filename (subfile->name) == language_cplus) + for (s = subfiles; s != NULL; s = s->next) + if (s->language == language_c) + s->language = language_cplus; + } + + /* And patch up this file if necessary. */ + if (subfile->language == language_c + && subfile->next != NULL + && subfile->next->language == language_cplus) + { + subfile->language = language_cplus; + } +} + +/* For stabs readers, the first N_SO symbol is assumed to be the source + file name, and the subfile struct is initialized using that assumption. + If another N_SO symbol is later seen, immediately following the first + one, then the first one is assumed to be the directory name and the + second one is really the source file name. + + So we have to patch up the subfile struct by moving the old name value to + dirname and remembering the new name. Some sanity checking is performed + to ensure that the state of the subfile struct is reasonable and that the + old name we are assuming to be a directory name actually is (by checking + for a trailing '/'). */ + +void +patch_subfile_names (subfile, name) + struct subfile *subfile; + char *name; +{ + if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL + && subfile->name[strlen(subfile->name)-1] == '/') + { + subfile->dirname = subfile->name; + subfile->name = strdup (name); + + /* Default the source language to whatever can be deduced from + the filename. If nothing can be deduced (such as for a C/C++ + include file with a ".h" extension), then inherit whatever + language the previous subfile had. This kludgery is necessary + because there is no standard way in some object formats to + record the source language. Also, when symtabs are allocated + we try to deduce a language then as well, but it is too late + for us to use that information while reading symbols, since + symtabs aren't allocated until after all the symbols have + been processed for a given source file. */ + + subfile->language = deduce_language_from_filename (subfile->name); + if (subfile->language == language_unknown && + subfile->next != NULL) + { + subfile->language = subfile->next->language; + } + } +} + + +/* Handle the N_BINCL and N_EINCL symbol types + that act like N_SOL for switching source files + (different subfiles, as we call them) within one object file, + but using a stack rather than in an arbitrary order. */ + +void +push_subfile () +{ + register struct subfile_stack *tem + = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack)); + + tem->next = subfile_stack; + subfile_stack = tem; + if (current_subfile == NULL || current_subfile->name == NULL) + { + abort (); + } + tem->name = current_subfile->name; +} + +char * +pop_subfile () +{ + register char *name; + register struct subfile_stack *link = subfile_stack; + + if (link == NULL) + { + abort (); + } + name = link->name; + subfile_stack = link->next; + free ((PTR)link); + return (name); +} + + +/* Add a linetable entry for line number LINE and address PC to the line + vector for SUBFILE. */ + +void +record_line (subfile, line, pc) + register struct subfile *subfile; + int line; + CORE_ADDR pc; +{ + struct linetable_entry *e; + /* Ignore the dummy line number in libg.o */ + + if (line == 0xffff) + { + return; + } + + /* Make sure line vector exists and is big enough. */ + if (!subfile->line_vector) + { + subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH; + subfile->line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + subfile->line_vector_length * sizeof (struct linetable_entry)); + subfile->line_vector->nitems = 0; + } + + if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length) + { + subfile->line_vector_length *= 2; + subfile->line_vector = (struct linetable *) + xrealloc ((char *) subfile->line_vector, (sizeof (struct linetable) + + subfile->line_vector_length * sizeof (struct linetable_entry))); + } + + e = subfile->line_vector->item + subfile->line_vector->nitems++; + e->line = line; e->pc = pc; +} + + +/* Needed in order to sort line tables from IBM xcoff files. Sigh! */ + +static int +compare_line_numbers (ln1p, ln2p) + const PTR ln1p; + const PTR ln2p; +{ + struct linetable_entry *ln1 = (struct linetable_entry *) ln1p; + struct linetable_entry *ln2 = (struct linetable_entry *) ln2p; + + /* Note: this code does not assume that CORE_ADDRs can fit in ints. + Please keep it that way. */ + if (ln1->pc < ln2->pc) + return -1; + + if (ln1->pc > ln2->pc) + return 1; + + /* If pc equal, sort by line. I'm not sure whether this is optimum + behavior (see comment at struct linetable in symtab.h). */ + return ln1->line - ln2->line; +} + + +/* Start a new symtab for a new source file. + Called, for example, when a stabs symbol of type N_SO is seen, or when + a DWARF TAG_compile_unit DIE is seen. + It indicates the start of data for one original source file. */ + +void +start_symtab (name, dirname, start_addr) + char *name; + char *dirname; + CORE_ADDR start_addr; +{ + + last_source_file = name; + last_source_start_addr = start_addr; + file_symbols = NULL; + global_symbols = NULL; + within_function = 0; + + /* Context stack is initially empty. Allocate first one with room for + 10 levels; reuse it forever afterward. */ + if (context_stack == NULL) + { + context_stack_size = INITIAL_CONTEXT_STACK_SIZE; + context_stack = (struct context_stack *) + xmalloc (context_stack_size * sizeof (struct context_stack)); + } + context_stack_depth = 0; + + /* Initialize the list of sub source files with one entry + for this file (the top-level source file). */ + + subfiles = NULL; + current_subfile = NULL; + start_subfile (name, dirname); +} + +/* Finish the symbol definitions for one main source file, + close off all the lexical contexts for that file + (creating struct block's for them), then make the struct symtab + for that file and put it in the list of all such. + + END_ADDR is the address of the end of the file's text. + SECTION is the section number (in objfile->section_offsets) of + the blockvector and linetable. + + Note that it is possible for end_symtab() to return NULL. In particular, + for the DWARF case at least, it will return NULL when it finds a + compilation unit that has exactly one DIE, a TAG_compile_unit DIE. This + can happen when we link in an object file that was compiled from an empty + source file. Returning NULL is probably not the correct thing to do, + because then gdb will never know about this empty file (FIXME). */ + +struct symtab * +end_symtab (end_addr, sort_pending, sort_linevec, objfile, section) + CORE_ADDR end_addr; + int sort_pending; + int sort_linevec; + struct objfile *objfile; + int section; +{ + register struct symtab *symtab = NULL; + register struct blockvector *blockvector; + register struct subfile *subfile; + register struct context_stack *cstk; + struct subfile *nextsub; + + /* Finish the lexical context of the last function in the file; + pop the context stack. */ + + if (context_stack_depth > 0) + { + context_stack_depth--; + cstk = &context_stack[context_stack_depth]; + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, end_addr, objfile); + + if (context_stack_depth > 0) + { + /* This is said to happen with SCO. The old coffread.c code + simply emptied the context stack, so we do the same. FIXME: + Find out why it is happening. This is not believed to happen + in most cases (even for coffread.c); it used to be an abort(). */ + static struct complaint msg = + {"Context stack not empty in end_symtab", 0, 0}; + complain (&msg); + context_stack_depth = 0; + } + } + + /* It is unfortunate that in xcoff, pending blocks might not be ordered + in this stage. Especially, blocks for static functions will show up at + the end. We need to sort them, so tools like `find_pc_function' and + `find_pc_block' can work reliably. */ + + if (sort_pending && pending_blocks) + { + /* FIXME! Remove this horrid bubble sort and use qsort!!! */ + int swapped; + do + { + struct pending_block *pb, *pbnext; + + pb = pending_blocks; + pbnext = pb->next; + swapped = 0; + + while (pbnext) + { + /* swap blocks if unordered! */ + + if (BLOCK_START(pb->block) < BLOCK_START(pbnext->block)) + { + struct block *tmp = pb->block; + pb->block = pbnext->block; + pbnext->block = tmp; + swapped = 1; + } + pb = pbnext; + pbnext = pbnext->next; + } + } while (swapped); + } + + /* Cleanup any undefined types that have been left hanging around + (this needs to be done before the finish_blocks so that + file_symbols is still good). + + Both cleanup_undefined_types and finish_global_stabs are stabs + specific, but harmless for other symbol readers, since on gdb + startup or when finished reading stabs, the state is set so these + are no-ops. FIXME: Is this handled right in case of QUIT? Can + we make this cleaner? */ + + cleanup_undefined_types (); + finish_global_stabs (objfile); + + if (pending_blocks == NULL + && file_symbols == NULL + && global_symbols == NULL) + { + /* Ignore symtabs that have no functions with real debugging info */ + blockvector = NULL; + } + else + { + /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the blockvector. */ + finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr, + objfile); + finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr, + objfile); + blockvector = make_blockvector (objfile); + } + +#ifdef PROCESS_LINENUMBER_HOOK + PROCESS_LINENUMBER_HOOK (); /* Needed for xcoff. */ +#endif + + /* Now create the symtab objects proper, one for each subfile. */ + /* (The main file is the last one on the chain.) */ + + for (subfile = subfiles; subfile; subfile = nextsub) + { + int linetablesize = 0; + /* If we have blocks of symbols, make a symtab. + Otherwise, just ignore this file and any line number info in it. */ + symtab = NULL; + if (blockvector) + { + if (subfile->line_vector) + { + linetablesize = sizeof (struct linetable) + + subfile->line_vector->nitems * sizeof (struct linetable_entry); +#if 0 + /* I think this is artifact from before it went on the obstack. + I doubt we'll need the memory between now and when we + free it later in this function. */ + /* First, shrink the linetable to make more memory. */ + subfile->line_vector = (struct linetable *) + xrealloc ((char *) subfile->line_vector, linetablesize); +#endif + /* If sort_linevec is false, we might want just check to make + sure they are sorted and complain() if not, as a way of + tracking down compilers/symbol readers which don't get + them sorted right. */ + + if (sort_linevec) + qsort (subfile->line_vector->item, + subfile->line_vector->nitems, + sizeof (struct linetable_entry), compare_line_numbers); + } + + /* Now, allocate a symbol table. */ + symtab = allocate_symtab (subfile->name, objfile); + + /* Fill in its components. */ + symtab->blockvector = blockvector; + if (subfile->line_vector) + { + /* Reallocate the line table on the symbol obstack */ + symtab->linetable = (struct linetable *) + obstack_alloc (&objfile -> symbol_obstack, linetablesize); + memcpy (symtab->linetable, subfile->line_vector, linetablesize); + } + else + { + symtab->linetable = NULL; + } + symtab->block_line_section = section; + if (subfile->dirname) + { + /* Reallocate the dirname on the symbol obstack */ + symtab->dirname = (char *) + obstack_alloc (&objfile -> symbol_obstack, + strlen (subfile -> dirname) + 1); + strcpy (symtab->dirname, subfile->dirname); + } + else + { + symtab->dirname = NULL; + } + symtab->free_code = free_linetable; + symtab->free_ptr = NULL; + + /* Use whatever language we have been using for this subfile, + not the one that was deduced in allocate_symtab from the + filename. We already did our own deducing when we created + the subfile, and we may have altered our opinion of what + language it is from things we found in the symbols. */ + symtab->language = subfile->language; + + /* All symtabs for the main file and the subfiles share a + blockvector, so we need to clear primary for everything but + the main file. */ + + symtab->primary = 0; + } + if (subfile->name != NULL) + { + free ((PTR) subfile->name); + } + if (subfile->dirname != NULL) + { + free ((PTR) subfile->dirname); + } + if (subfile->line_vector != NULL) + { + free ((PTR) subfile->line_vector); + } + + nextsub = subfile->next; + free ((PTR)subfile); + } + + /* Set this for the main source file. */ + if (symtab) + { + symtab->primary = 1; + } + + last_source_file = NULL; + current_subfile = NULL; + + return (symtab); +} + + +/* Push a context block. Args are an identifying nesting level (checkable + when you pop it), and the starting PC address of this context. */ + +struct context_stack * +push_context (desc, valu) + int desc; + CORE_ADDR valu; +{ + register struct context_stack *new; + + if (context_stack_depth == context_stack_size) + { + context_stack_size *= 2; + context_stack = (struct context_stack *) + xrealloc ((char *) context_stack, + (context_stack_size * sizeof (struct context_stack))); + } + + new = &context_stack[context_stack_depth++]; + new->depth = desc; + new->locals = local_symbols; + new->old_blocks = pending_blocks; + new->start_addr = valu; + new->name = NULL; + + local_symbols = NULL; + + return (new); +} + + +/* Compute a small integer hash code for the given name. */ + +int +hashname (name) + char *name; +{ + register char *p = name; + register int total = p[0]; + register int c; + + c = p[1]; + total += c << 2; + if (c) + { + c = p[2]; + total += c << 4; + if (c) + { + total += p[3] << 6; + } + } + + /* Ensure result is positive. */ + if (total < 0) + { + total += (1000 << 6); + } + return (total % HASHSIZE); +} + + +/* Initialize anything that needs initializing when starting to read + a fresh piece of a symbol file, e.g. reading in the stuff corresponding + to a psymtab. */ + +void +buildsym_init () +{ + free_pendings = NULL; + file_symbols = NULL; + global_symbols = NULL; + pending_blocks = NULL; +} + +/* Initialize anything that needs initializing when a completely new + symbol file is specified (not just adding some symbols from another + file, e.g. a shared library). */ + +void +buildsym_new_init () +{ + buildsym_init (); +} + +/* Initializer for this module */ + +void +_initialize_buildsym () +{ +} diff --git a/gnu/usr.bin/gdb/gdb/buildsym.h b/gnu/usr.bin/gdb/gdb/buildsym.h new file mode 100644 index 00000000000..e034863f396 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/buildsym.h @@ -0,0 +1,259 @@ +/* Build symbol tables in GDB's internal format. + Copyright (C) 1986-1991 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. */ + +#if !defined (BUILDSYM_H) +#define BUILDSYM_H 1 + +/* This module provides definitions used for creating and adding to + the symbol table. These routines are called from various symbol- + file-reading routines. + + They originated in dbxread.c of gdb-4.2, and were split out to + make xcoffread.c more maintainable by sharing code. + + Variables declared in this file can be defined by #define-ing + the name EXTERN to null. It is used to declare variables that + are normally extern, but which get defined in a single module + using this technique. */ + +#ifndef EXTERN +#define EXTERN extern +#endif + +#define HASHSIZE 127 /* Size of things hashed via hashname() */ + +/* Name of source file whose symbol data we are now processing. + This comes from a symbol of type N_SO. */ + +EXTERN char *last_source_file; + +/* Core address of start of text of current source file. + This too comes from the N_SO symbol. */ + +EXTERN CORE_ADDR last_source_start_addr; + +/* The list of sub-source-files within the current individual compilation. + Each file gets its own symtab with its own linetable and associated info, + but they all share one blockvector. */ + +struct subfile +{ + struct subfile *next; + char *name; + char *dirname; + struct linetable *line_vector; + int line_vector_length; + enum language language; +}; + +EXTERN struct subfile *subfiles; + +EXTERN struct subfile *current_subfile; + +/* Global variable which, when set, indicates that we are processing a + .o file compiled with gcc */ + +EXTERN unsigned char processing_gcc_compilation; + +/* When set, we are processing a .o file compiled by sun acc. This is + misnamed; it refers to all stabs-in-elf implementations which use + N_UNDF the way Sun does, including Solaris gcc. Hopefully all + stabs-in-elf implementations ever invented will choose to be + compatible. */ + +EXTERN unsigned char processing_acc_compilation; + +/* Count symbols as they are processed, for error messages. */ + +EXTERN unsigned int symnum; + +/* Record the symbols defined for each context in a list. + We don't create a struct block for the context until we + know how long to make it. */ + +#define PENDINGSIZE 100 + +struct pending +{ + struct pending *next; + int nsyms; + struct symbol *symbol[PENDINGSIZE]; +}; + +/* List of free `struct pending' structures for reuse. */ + +EXTERN struct pending *free_pendings; + +/* Here are the three lists that symbols are put on. */ + +EXTERN struct pending *file_symbols; /* static at top level, and types */ + +EXTERN struct pending *global_symbols; /* global functions and variables */ + +EXTERN struct pending *local_symbols; /* everything local to lexic context */ + +/* Stack representing unclosed lexical contexts + (that will become blocks, eventually). */ + +struct context_stack +{ + /* Outer locals at the time we entered */ + + struct pending *locals; + + /* Pointer into blocklist as of entry */ + + struct pending_block *old_blocks; + + /* Name of function, if any, defining context*/ + + struct symbol *name; + + /* PC where this context starts */ + + CORE_ADDR start_addr; + + /* Temp slot for exception handling. */ + + CORE_ADDR end_addr; + + /* For error-checking matching push/pop */ + + int depth; + +}; + +EXTERN struct context_stack *context_stack; + +/* Index of first unused entry in context stack. */ + +EXTERN int context_stack_depth; + +/* Currently allocated size of context stack. */ + +EXTERN int context_stack_size; + +/* Macro "function" for popping contexts from the stack. Pushing is done + by a real function, push_context. This returns a pointer to a struct + context_stack. */ + +#define pop_context() (&context_stack[--context_stack_depth]); + +/* Nonzero if within a function (so symbols should be local, + if nothing says specifically). */ + +EXTERN int within_function; + +/* List of blocks already made (lexical contexts already closed). + This is used at the end to make the blockvector. */ + +struct pending_block +{ + struct pending_block *next; + struct block *block; +}; + +EXTERN struct pending_block *pending_blocks; + + +struct subfile_stack +{ + struct subfile_stack *next; + char *name; +}; + +EXTERN struct subfile_stack *subfile_stack; + +#define next_symbol_text() (*next_symbol_text_func)() + +/* Function to invoke get the next symbol. Return the symbol name. */ + +EXTERN char *(*next_symbol_text_func) PARAMS ((void)); + +/* Vector of types defined so far, indexed by their type numbers. + Used for both stabs and coff. + (In newer sun systems, dbx uses a pair of numbers in parens, + as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be + translated through the type_translations hash table to get + the index into the type vector.) */ + +EXTERN struct type **type_vector; + +/* Number of elements allocated for type_vector currently. */ + +EXTERN int type_vector_length; + +/* Initial size of type vector. Is realloc'd larger if needed, + and realloc'd down to the size actually used, when completed. */ + +#define INITIAL_TYPE_VECTOR_LENGTH 160 + +extern void +add_symbol_to_list PARAMS ((struct symbol *, struct pending **)); + +extern struct symbol * +find_symbol_in_list PARAMS ((struct pending *, char *, int)); + +extern void +finish_block PARAMS ((struct symbol *, struct pending **, + struct pending_block *, CORE_ADDR, CORE_ADDR, + struct objfile *)); + +extern void +really_free_pendings PARAMS ((int foo)); + +extern void +start_subfile PARAMS ((char *, char *)); + +extern void +patch_subfile_names PARAMS ((struct subfile *subfile, char *name)); + +extern void +push_subfile PARAMS ((void)); + +extern char * +pop_subfile PARAMS ((void)); + +extern struct symtab * +end_symtab PARAMS ((CORE_ADDR, int, int, struct objfile *, int)); + +extern void +scan_file_globals PARAMS ((struct objfile *)); + +extern void +buildsym_new_init PARAMS ((void)); + +extern void +buildsym_init PARAMS ((void)); + +extern struct context_stack * +push_context PARAMS ((int, CORE_ADDR)); + +extern void +record_line PARAMS ((struct subfile *, int, CORE_ADDR)); + +extern void +start_symtab PARAMS ((char *, char *, CORE_ADDR)); + +extern int +hashname PARAMS ((char *)); + +#undef EXTERN + +#endif /* defined (BUILDSYM_H) */ diff --git a/gnu/usr.bin/gdb/gdb/c-exp.tab.c b/gnu/usr.bin/gdb/gdb/c-exp.tab.c new file mode 100644 index 00000000000..924dfc66e42 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/c-exp.tab.c @@ -0,0 +1,2648 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define yyparse c_parse +#define yylex c_lex +#define yyerror c_error +#define yychar c_char +#define yyval c_val +#define yylval c_lval +#define yydebug c_debug +#define yynerrs c_nerrs +#define yyerrflag c_errflag +#define yyss c_ss +#define yyssp c_ssp +#define yyvs c_vs +#define yyvsp c_vsp +#define yylhs c_lhs +#define yylen c_len +#define yydefred c_defred +#define yydgoto c_dgoto +#define yysindex c_sindex +#define yyrindex c_rindex +#define yygindex c_gindex +#define yytable c_table +#define yycheck c_check +#define yyname c_name +#define yyrule c_rule +#define YYPREFIX "c_" +#line 38 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" + +#include "defs.h" +#include "expression.h" +#include "parser-defs.h" +#include "value.h" +#include "language.h" +#include "c-lang.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth c_maxdepth +#define yyparse c_parse +#define yylex c_lex +#define yyerror c_error +#define yylval c_lval +#define yychar c_char +#define yydebug c_debug +#define yypact c_pact +#define yyr1 c_r1 +#define yyr2 c_r2 +#define yydef c_def +#define yychk c_chk +#define yypgo c_pgo +#define yyact c_act +#define yyexca c_exca +#define yyerrflag c_errflag +#define yynerrs c_nerrs +#define yyps c_ps +#define yypv c_pv +#define yys c_s +#define yy_yys c_yys +#define yystate c_state +#define yytmp c_tmp +#define yyv c_v +#define yy_yyv c_yyv +#define yyval c_val +#define yylloc c_lloc +#define yyreds c_reds /* With YYDEBUG defined */ +#define yytoks c_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#line 102 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +typedef union + { + LONGEST lval; + struct { + LONGEST val; + struct type *type; + } typed_val; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } YYSTYPE; +#line 125 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +/* YYSTYPE gets defined by %union */ +static int +parse_number PARAMS ((char *, int, int, YYSTYPE *)); +#line 121 "y.tab.c" +#define INT 257 +#define FLOAT 258 +#define STRING 259 +#define NAME 260 +#define TYPENAME 261 +#define NAME_OR_INT 262 +#define STRUCT 263 +#define CLASS 264 +#define UNION 265 +#define ENUM 266 +#define SIZEOF 267 +#define UNSIGNED 268 +#define COLONCOLON 269 +#define TEMPLATE 270 +#define ERROR 271 +#define SIGNED_KEYWORD 272 +#define LONG 273 +#define SHORT 274 +#define INT_KEYWORD 275 +#define CONST_KEYWORD 276 +#define VOLATILE_KEYWORD 277 +#define LAST 278 +#define REGNAME 279 +#define VARIABLE 280 +#define ASSIGN_MODIFY 281 +#define THIS 282 +#define ABOVE_COMMA 283 +#define OROR 284 +#define ANDAND 285 +#define EQUAL 286 +#define NOTEQUAL 287 +#define LEQ 288 +#define GEQ 289 +#define LSH 290 +#define RSH 291 +#define UNARY 292 +#define INCREMENT 293 +#define DECREMENT 294 +#define ARROW 295 +#define BLOCKNAME 296 +#define YYERRCODE 256 +short c_lhs[] = { -1, + 0, 0, 3, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 21, 1, 6, 20, 20, 20, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 19, 19, 4, 5, 5, + 4, 4, 4, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 13, 13, 12, 12, 12, 12, 12, 15, + 15, 11, 11, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 18, 18, 18, 18, 10, 10, 16, 16, 16, + 16, 17, 17, +}; +short c_len[] = { 2, + 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 4, 3, 3, + 4, 4, 0, 5, 1, 0, 1, 3, 1, 3, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 3, 3, 1, 1, 1, 1, 1, + 1, 1, 4, 1, 1, 1, 3, 3, 3, 4, + 1, 2, 1, 1, 2, 2, 2, 3, 3, 1, + 2, 1, 2, 1, 3, 2, 1, 2, 1, 2, + 3, 2, 3, 1, 3, 6, 8, 9, 1, 1, + 1, 1, 2, 3, 2, 3, 3, 4, 2, 3, + 2, 2, 2, 2, 2, 1, 2, 1, 5, 2, + 2, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, +}; +short c_defred[] = { 0, + 56, 58, 64, 132, 99, 57, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, + 60, 61, 62, 65, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 25, 0, 0, 0, 2, 59, 71, + 0, 0, 0, 94, 73, 0, 128, 130, 131, 129, + 111, 112, 113, 114, 0, 0, 0, 122, 0, 0, + 123, 115, 72, 0, 124, 125, 117, 0, 103, 109, + 120, 121, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 14, 0, 0, 0, 23, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 89, 0, 77, 87, 0, 0, 0, 0, 104, + 110, 0, 106, 33, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 16, 0, 20, 19, 0, 0, 0, 29, 0, 0, + 30, 0, 95, 0, 69, 78, 79, 83, 81, 0, + 90, 92, 0, 0, 0, 0, 0, 88, 86, 0, + 0, 108, 0, 0, 0, 0, 0, 22, 0, 0, + 0, 0, 70, 91, 0, 0, 93, 85, 119, 0, + 24, 0, 0, 0, 0, 97, 0, 98, +}; +short c_dgoto[] = { 35, + 36, 78, 38, 39, 40, 41, 169, 183, 57, 185, + 122, 123, 124, 44, 125, 175, 45, 62, 46, 113, + 166, +}; +short c_sindex[] = { 1773, + 0, 0, 0, 0, 0, 0, -243, -243, -243, -243, + 1839, -240, -243, -243, -56, -260, -266, 0, 1303, 1303, + 0, 0, 0, 0, 1773, 1773, 1773, 1773, 1773, 1773, + 0, 1773, 1773, 0, 0, 2134, -24, 0, 0, 0, + 1773, -16, -36, 0, 0, -233, 0, 0, 0, 0, + 0, 0, 0, 0, 1773, 83, -219, 0, -217, -208, + 0, 0, 0, 57, 0, 0, 0, -199, 0, 0, + 0, 0, 83, 83, 83, 83, 83, 74, -12, 83, + 83, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, + 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, + 1773, 1773, 1773, 0, 0, 2136, 2175, 1773, 0, 1773, + 2134, -28, -17, 1303, -35, 31, 31, 31, 31, -90, + 1807, 0, -3, 0, 0, -243, 49, -52, -148, 0, + 0, 1303, 0, 0, 1773, 2134, 2134, 2099, 2197, 2208, + 2236, 2269, 2304, 2474, 2474, 743, 743, 743, 743, 615, + 615, 273, 320, 320, 83, 83, 83, 0, 1773, 0, + 0, 1773, 0, 0, -44, 1773, 2134, 0, 1773, 1773, + 0, -137, 0, -243, 0, 0, 0, 0, 0, 63, + 0, 0, -16, 28, 80, 117, 477, 0, 0, 0, + 1653, 0, -32, 83, 1773, 83, 83, 0, 106, 83, + 2134, 136, 0, 0, 145, 1303, 0, 0, 0, 2169, + 0, 129, -16, 155, 2276, 0, 171, 0, +}; +short c_rindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1146, 0, 0, 1403, 1413, 1691, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 16, 188, 0, 0, 0, + -13, 206, 79, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 213, 0, 0, 1716, 1721, + 0, 0, 0, 0, 0, 0, 0, 1730, 0, 0, + 0, 0, 311, 402, 414, 487, 515, 0, 0, 583, + 673, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -19, 0, 0, 0, 0, 10, 52, 111, 359, 0, + 0, 0, 492, 0, 0, 0, 0, 0, 1746, 0, + 0, 0, 0, 0, 0, 668, 892, 0, 881, 153, + 479, 1135, 128, 1583, 1620, 1366, 1438, 1546, 1572, 1264, + 1312, 1236, 1182, 1224, 782, 794, 853, 40, 0, 0, + 0, 0, 0, 0, 0, 193, 239, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 201, -30, 0, 0, 0, 0, 0, 99, + 138, 0, 0, 928, 0, 967, 1056, 0, 0, 1110, + -18, 0, 0, 0, 0, 0, 0, 0, 0, 110, + 0, 0, 257, 544, 0, 0, 0, 0, +}; +short c_gindex[] = { 0, + 2543, 5, 0, 0, 42, 0, 107, 75, 450, 13, + 115, 0, 148, 0, 120, 989, 0, 215, 0, 81, + 0, +}; +#define YYTABLESIZE 2769 +short c_table[] = { 110, + 133, 118, 181, 121, 37, 119, 173, 114, 70, 75, + 74, 114, 68, 74, 69, 4, 47, 48, 49, 110, + 58, 27, 28, 114, 27, 28, 170, 114, 135, 209, + 26, 74, 59, 60, 61, 126, 187, 133, 133, 130, + 133, 133, 133, 133, 133, 133, 133, 133, 198, 128, + 75, 76, 50, 75, 120, 129, 4, 130, 133, 4, + 133, 133, 133, 133, 133, 118, 131, 121, 118, 119, + 121, 75, 119, 174, 42, 133, 130, 130, 74, 130, + 130, 130, 130, 130, 130, 130, 130, 120, 114, 191, + 174, 133, 76, 133, 133, 76, 168, 130, 68, 130, + 130, 130, 130, 130, 79, 27, 28, 168, 4, 53, + 82, 26, 165, 76, 134, 112, 132, 110, 120, 74, + 207, 120, 109, 206, 133, 133, 192, 48, 107, 127, + 130, 202, 130, 130, 75, 68, 68, 63, 68, 68, + 68, 68, 68, 68, 68, 68, 211, 160, 163, 170, + 53, 82, 51, 53, 82, 204, 68, 208, 68, 68, + 68, 68, 68, 130, 130, 48, 180, 53, 48, 214, + 53, 48, 82, 108, 63, 63, 76, 212, 63, 63, + 63, 63, 63, 63, 63, 48, 173, 1, 48, 68, + 48, 68, 68, 51, 215, 63, 51, 63, 63, 63, + 63, 63, 53, 74, 58, 3, 193, 47, 48, 49, + 51, 218, 15, 51, 206, 51, 65, 66, 61, 171, + 48, 48, 68, 68, 47, 48, 49, 217, 63, 67, + 63, 63, 115, 26, 53, 82, 26, 188, 5, 116, + 117, 126, 189, 50, 126, 51, 199, 0, 0, 15, + 15, 48, 48, 15, 15, 15, 15, 15, 0, 15, + 50, 63, 63, 176, 177, 178, 179, 0, 186, 66, + 15, 0, 15, 15, 15, 15, 15, 51, 0, 5, + 213, 133, 5, 0, 133, 133, 133, 133, 133, 133, + 133, 133, 0, 133, 133, 133, 205, 127, 0, 0, + 127, 0, 0, 116, 117, 15, 15, 0, 99, 103, + 7, 0, 109, 0, 101, 99, 0, 100, 107, 102, + 130, 0, 0, 130, 130, 130, 130, 130, 130, 130, + 130, 5, 130, 130, 130, 0, 15, 15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, + 0, 7, 7, 7, 7, 7, 103, 7, 80, 109, + 0, 101, 0, 108, 0, 107, 102, 67, 7, 0, + 7, 7, 7, 7, 7, 104, 105, 106, 0, 68, + 0, 0, 68, 68, 68, 68, 68, 68, 68, 68, + 53, 68, 68, 68, 0, 0, 0, 0, 0, 80, + 0, 8, 80, 7, 7, 0, 0, 0, 48, 0, + 108, 48, 48, 6, 0, 0, 0, 0, 63, 0, + 80, 63, 63, 63, 63, 63, 63, 63, 63, 0, + 0, 0, 63, 51, 7, 7, 51, 51, 8, 8, + 0, 0, 8, 8, 8, 8, 8, 0, 8, 43, + 6, 6, 0, 0, 6, 6, 6, 6, 6, 8, + 6, 8, 8, 8, 8, 8, 0, 0, 71, 72, + 0, 6, 0, 6, 6, 6, 6, 6, 50, 43, + 0, 0, 0, 80, 0, 0, 11, 0, 0, 0, + 43, 84, 0, 15, 8, 8, 15, 15, 15, 15, + 15, 15, 15, 15, 43, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 12, 0, 0, 182, 0, 50, + 0, 0, 50, 11, 11, 8, 8, 11, 11, 11, + 11, 11, 84, 11, 0, 84, 50, 6, 6, 50, + 0, 50, 0, 96, 11, 0, 11, 11, 11, 11, + 11, 12, 12, 84, 0, 12, 12, 12, 12, 12, + 0, 12, 0, 172, 0, 104, 105, 106, 0, 0, + 184, 50, 12, 0, 12, 12, 12, 12, 12, 11, + 11, 184, 9, 0, 96, 0, 0, 96, 0, 0, + 0, 7, 0, 0, 7, 7, 7, 7, 7, 7, + 7, 7, 50, 50, 0, 96, 0, 12, 12, 0, + 11, 11, 104, 105, 106, 0, 84, 0, 0, 9, + 9, 0, 0, 9, 9, 9, 9, 9, 0, 9, + 0, 0, 0, 0, 0, 0, 184, 0, 12, 12, + 9, 0, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 103, 0, 0, 109, 184, 101, 99, 0, 100, + 107, 102, 0, 0, 184, 0, 0, 55, 96, 0, + 0, 0, 10, 0, 0, 9, 9, 0, 98, 0, + 0, 0, 8, 0, 0, 8, 8, 8, 8, 8, + 8, 8, 8, 0, 6, 0, 0, 6, 6, 6, + 6, 6, 6, 6, 6, 108, 9, 9, 55, 10, + 10, 55, 0, 10, 10, 10, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, + 10, 0, 10, 10, 10, 10, 10, 5, 0, 7, + 8, 9, 10, 0, 12, 0, 14, 0, 15, 16, + 17, 18, 19, 20, 0, 0, 0, 0, 0, 50, + 55, 0, 50, 50, 0, 10, 10, 11, 0, 0, + 11, 11, 11, 11, 11, 11, 11, 11, 0, 103, + 0, 35, 109, 0, 101, 99, 0, 100, 107, 102, + 0, 0, 55, 36, 0, 12, 10, 10, 12, 12, + 12, 12, 12, 12, 12, 12, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 35, 35, + 0, 0, 35, 35, 35, 35, 35, 0, 35, 0, + 36, 36, 0, 108, 36, 36, 36, 36, 36, 35, + 36, 35, 35, 35, 35, 35, 0, 0, 0, 0, + 0, 36, 37, 36, 36, 36, 36, 36, 0, 0, + 0, 0, 0, 9, 0, 0, 9, 9, 9, 9, + 9, 9, 9, 9, 35, 35, 0, 0, 0, 0, + 52, 0, 0, 0, 0, 0, 36, 36, 0, 37, + 37, 54, 0, 37, 37, 37, 37, 37, 0, 37, + 0, 0, 0, 0, 0, 35, 35, 104, 105, 106, + 37, 0, 37, 37, 37, 37, 37, 36, 36, 0, + 0, 52, 0, 0, 52, 0, 0, 32, 0, 0, + 0, 0, 54, 0, 0, 54, 0, 0, 52, 0, + 0, 52, 0, 52, 0, 37, 37, 0, 0, 54, + 0, 0, 0, 10, 0, 0, 10, 10, 10, 10, + 10, 10, 10, 10, 32, 32, 18, 0, 32, 32, + 32, 32, 32, 52, 32, 0, 37, 37, 0, 0, + 0, 0, 0, 0, 54, 32, 0, 32, 32, 32, + 32, 32, 0, 0, 0, 51, 52, 53, 54, 0, + 0, 63, 64, 18, 18, 52, 0, 18, 18, 18, + 18, 18, 0, 18, 0, 0, 54, 0, 0, 0, + 32, 32, 0, 0, 18, 0, 18, 18, 18, 18, + 18, 0, 96, 97, 0, 104, 105, 106, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 21, 0, 0, 0, 18, + 18, 0, 35, 0, 0, 35, 35, 35, 35, 35, + 35, 35, 35, 0, 36, 0, 0, 36, 36, 36, + 36, 36, 36, 36, 36, 0, 0, 0, 0, 0, + 18, 18, 21, 21, 161, 164, 21, 21, 21, 21, + 21, 0, 21, 0, 0, 0, 0, 0, 0, 31, + 0, 0, 0, 21, 190, 21, 21, 21, 21, 21, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 49, 0, 37, 37, 37, 37, + 37, 37, 37, 37, 0, 116, 31, 31, 21, 21, + 31, 31, 31, 31, 31, 0, 31, 0, 0, 0, + 0, 52, 203, 0, 52, 0, 0, 31, 0, 31, + 31, 31, 31, 31, 0, 49, 0, 0, 49, 21, + 21, 38, 0, 116, 0, 116, 116, 116, 0, 116, + 0, 0, 49, 0, 0, 49, 0, 49, 0, 0, + 0, 0, 31, 31, 0, 0, 0, 116, 32, 0, + 0, 32, 32, 32, 32, 32, 32, 32, 32, 38, + 0, 0, 38, 39, 38, 38, 38, 49, 49, 0, + 0, 0, 0, 31, 31, 34, 116, 0, 0, 38, + 0, 38, 38, 38, 38, 38, 0, 18, 0, 0, + 18, 18, 18, 18, 18, 18, 18, 18, 49, 49, + 0, 39, 0, 40, 39, 0, 39, 39, 39, 0, + 116, 0, 0, 34, 38, 38, 34, 0, 0, 34, + 0, 39, 0, 39, 39, 39, 39, 39, 0, 0, + 0, 0, 0, 34, 0, 34, 34, 34, 34, 34, + 0, 40, 0, 0, 40, 38, 38, 40, 0, 0, + 0, 41, 0, 0, 0, 0, 39, 39, 0, 0, + 0, 40, 0, 40, 40, 40, 40, 0, 34, 34, + 0, 0, 0, 0, 0, 0, 21, 0, 0, 21, + 21, 21, 21, 21, 21, 21, 21, 39, 39, 41, + 0, 0, 41, 0, 0, 41, 40, 40, 0, 34, + 34, 0, 0, 0, 0, 46, 0, 0, 0, 41, + 0, 41, 41, 41, 41, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, + 31, 0, 0, 31, 31, 31, 31, 31, 31, 31, + 31, 0, 118, 46, 41, 41, 46, 0, 0, 46, + 0, 0, 101, 0, 116, 49, 0, 0, 49, 49, + 0, 116, 116, 46, 0, 46, 46, 46, 46, 0, + 0, 0, 0, 0, 0, 41, 41, 47, 0, 0, + 118, 0, 118, 118, 118, 0, 118, 0, 0, 0, + 101, 0, 101, 101, 101, 0, 101, 0, 46, 46, + 0, 0, 38, 0, 118, 38, 38, 38, 38, 38, + 38, 38, 38, 0, 101, 47, 0, 0, 47, 0, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 46, + 46, 0, 0, 118, 0, 47, 0, 47, 47, 47, + 47, 0, 0, 101, 39, 0, 0, 39, 39, 39, + 39, 39, 39, 39, 39, 0, 34, 0, 0, 34, + 34, 34, 34, 34, 34, 34, 34, 118, 0, 0, + 47, 47, 0, 0, 0, 0, 0, 101, 0, 0, + 0, 0, 0, 0, 40, 44, 0, 40, 40, 40, + 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, + 0, 47, 47, 5, 0, 7, 8, 9, 10, 0, + 12, 45, 14, 0, 15, 16, 17, 18, 19, 20, + 0, 0, 42, 44, 0, 0, 44, 0, 0, 44, + 0, 0, 41, 0, 0, 41, 41, 41, 41, 41, + 41, 41, 41, 44, 0, 44, 44, 44, 44, 45, + 0, 0, 45, 0, 0, 45, 0, 0, 0, 43, + 42, 0, 0, 42, 0, 0, 42, 0, 0, 45, + 0, 45, 45, 45, 45, 0, 0, 0, 44, 44, + 42, 0, 0, 42, 0, 42, 46, 0, 0, 46, + 46, 46, 46, 46, 46, 0, 0, 43, 0, 0, + 43, 0, 0, 43, 45, 45, 0, 0, 0, 44, + 44, 118, 0, 0, 0, 42, 42, 43, 118, 118, + 43, 101, 43, 0, 0, 32, 0, 0, 101, 101, + 102, 0, 30, 0, 0, 45, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 42, 42, 0, 0, + 0, 0, 43, 43, 0, 124, 0, 0, 47, 0, + 125, 47, 47, 47, 47, 47, 47, 0, 102, 105, + 102, 102, 102, 0, 102, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 43, 107, 0, 0, 0, 0, + 0, 0, 102, 124, 0, 124, 124, 124, 125, 124, + 125, 125, 125, 0, 125, 0, 0, 105, 0, 105, + 105, 105, 0, 105, 0, 34, 0, 124, 33, 0, + 0, 102, 125, 107, 0, 107, 107, 107, 0, 107, + 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32, 124, 107, 0, 0, + 25, 125, 30, 0, 27, 102, 0, 26, 0, 0, + 105, 0, 0, 0, 0, 0, 44, 0, 0, 44, + 44, 44, 44, 44, 44, 0, 107, 0, 0, 0, + 124, 0, 0, 0, 118, 125, 121, 182, 119, 0, + 0, 0, 45, 0, 105, 45, 45, 45, 45, 45, + 45, 0, 0, 42, 0, 0, 42, 42, 42, 42, + 107, 32, 0, 0, 0, 0, 25, 0, 55, 0, + 27, 0, 0, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 34, 0, 120, 33, 0, + 43, 0, 0, 43, 43, 43, 43, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 0, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 0, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 29, 0, 31, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, + 0, 34, 0, 0, 33, 0, 102, 102, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 124, 0, 0, 0, 0, 125, + 0, 124, 124, 0, 0, 0, 125, 125, 105, 0, + 0, 0, 0, 0, 0, 105, 105, 0, 0, 0, + 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, + 0, 107, 107, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 0, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 0, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 29, 5, 31, 7, + 8, 9, 10, 0, 12, 0, 14, 0, 15, 16, + 17, 18, 19, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 28, 29, 0, 31, 103, 89, 0, 109, 0, + 101, 99, 0, 100, 107, 102, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 195, 0, 92, 83, + 93, 84, 98, 0, 0, 0, 0, 0, 0, 0, + 103, 89, 0, 109, 0, 101, 99, 159, 100, 107, + 102, 0, 0, 0, 0, 0, 0, 0, 0, 108, + 0, 0, 88, 92, 83, 93, 84, 98, 0, 0, + 0, 0, 0, 0, 0, 103, 89, 0, 109, 0, + 101, 99, 0, 100, 107, 102, 162, 0, 0, 0, + 0, 0, 87, 0, 108, 0, 0, 88, 92, 0, + 93, 84, 98, 103, 89, 0, 109, 0, 101, 99, + 0, 100, 107, 102, 103, 89, 0, 109, 0, 101, + 99, 0, 100, 107, 102, 0, 92, 87, 93, 108, + 98, 0, 88, 0, 0, 0, 0, 92, 0, 93, + 0, 98, 103, 89, 0, 109, 0, 101, 99, 0, + 100, 107, 102, 0, 0, 0, 0, 108, 0, 0, + 88, 0, 87, 0, 0, 92, 0, 93, 108, 98, + 0, 88, 0, 0, 0, 103, 89, 0, 109, 0, + 101, 99, 0, 100, 107, 102, 216, 0, 0, 0, + 87, 0, 0, 0, 0, 0, 108, 0, 92, 88, + 93, 87, 98, 0, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 109, 0, 101, 99, 0, 100, 107, + 102, 0, 0, 0, 0, 0, 0, 0, 0, 108, + 0, 0, 0, 92, 0, 93, 0, 98, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 0, 0, 85, 86, 90, 91, 94, 95, 96, 97, + 0, 104, 105, 106, 108, 47, 158, 49, 7, 8, + 9, 10, 0, 12, 0, 14, 0, 15, 16, 17, + 18, 19, 20, 0, 82, 0, 0, 85, 86, 90, + 91, 94, 95, 96, 97, 0, 104, 105, 106, 0, + 0, 50, 0, 0, 47, 158, 49, 7, 8, 9, + 10, 0, 12, 0, 14, 0, 15, 16, 17, 18, + 19, 20, 85, 86, 90, 91, 94, 95, 96, 97, + 0, 104, 105, 106, 0, 0, 0, 0, 0, 0, + 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 86, 90, 91, 94, 95, 96, 97, 0, 104, + 105, 106, 0, 90, 91, 94, 95, 96, 97, 0, + 104, 105, 106, 0, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 109, 0, 101, 99, 0, 100, 107, + 102, 90, 91, 94, 95, 96, 97, 0, 104, 105, + 106, 0, 0, 92, 0, 93, 5, 98, 7, 8, + 9, 10, 0, 12, 0, 14, 0, 15, 16, 17, + 18, 19, 20, 56, 90, 91, 94, 95, 96, 97, + 0, 104, 105, 106, 108, 0, 0, 73, 74, 75, + 76, 77, 0, 0, 80, 81, 0, 0, 0, 0, + 0, 0, 0, 111, 0, 0, 0, 0, 0, 90, + 91, 94, 95, 96, 97, 0, 104, 105, 106, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 0, 0, 0, 0, + 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 194, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 196, 0, 0, 197, 0, 0, 0, 111, 0, + 0, 200, 201, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 194, 0, 0, 0, 210, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 94, 95, 96, 97, 0, 104, 105, 106, +}; +short c_check[] = { 44, + 0, 38, 93, 40, 0, 42, 42, 40, 275, 0, + 41, 40, 273, 44, 275, 0, 260, 261, 262, 44, + 261, 41, 41, 40, 44, 44, 44, 40, 41, 62, + 44, 62, 273, 274, 275, 269, 40, 37, 38, 0, + 40, 41, 42, 43, 44, 45, 46, 47, 93, 269, + 41, 0, 296, 44, 91, 273, 41, 275, 58, 44, + 60, 61, 62, 63, 64, 38, 275, 40, 38, 42, + 40, 62, 42, 126, 0, 275, 37, 38, 0, 40, + 41, 42, 43, 44, 45, 46, 47, 91, 40, 41, + 126, 91, 41, 93, 94, 44, 125, 58, 0, 60, + 61, 62, 63, 64, 30, 125, 125, 125, 93, 0, + 0, 125, 108, 62, 41, 41, 60, 44, 91, 41, + 41, 91, 40, 44, 124, 125, 275, 0, 46, 55, + 91, 269, 93, 94, 125, 37, 38, 0, 40, 41, + 42, 43, 44, 45, 46, 47, 41, 106, 107, 44, + 41, 41, 0, 44, 44, 93, 58, 41, 60, 61, + 62, 63, 64, 124, 125, 38, 257, 58, 41, 41, + 61, 44, 62, 91, 37, 38, 125, 42, 41, 42, + 43, 44, 45, 46, 47, 58, 42, 0, 61, 91, + 63, 93, 94, 41, 40, 58, 44, 60, 61, 62, + 63, 64, 93, 125, 261, 0, 132, 260, 261, 262, + 58, 41, 0, 61, 44, 63, 273, 274, 275, 113, + 93, 94, 124, 125, 260, 261, 262, 215, 91, 15, + 93, 94, 269, 41, 125, 125, 44, 123, 0, 276, + 277, 41, 123, 296, 44, 93, 166, -1, -1, 37, + 38, 124, 125, 41, 42, 43, 44, 45, -1, 47, + 296, 124, 125, 116, 117, 118, 119, -1, 121, 269, + 58, -1, 60, 61, 62, 63, 64, 125, -1, 41, + 206, 281, 44, -1, 284, 285, 286, 287, 288, 289, + 290, 291, -1, 293, 294, 295, 269, 41, -1, -1, + 44, -1, -1, 276, 277, 93, 94, -1, 269, 37, + 0, -1, 40, -1, 42, 43, -1, 45, 46, 47, + 281, -1, -1, 284, 285, 286, 287, 288, 289, 290, + 291, 93, 293, 294, 295, -1, 124, 125, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 37, 38, -1, + -1, 41, 42, 43, 44, 45, 37, 47, 0, 40, + -1, 42, -1, 91, -1, 46, 47, 269, 58, -1, + 60, 61, 62, 63, 64, 293, 294, 295, -1, 281, + -1, -1, 284, 285, 286, 287, 288, 289, 290, 291, + 281, 293, 294, 295, -1, -1, -1, -1, -1, 41, + -1, 0, 44, 93, 94, -1, -1, -1, 281, -1, + 91, 284, 285, 0, -1, -1, -1, -1, 281, -1, + 62, 284, 285, 286, 287, 288, 289, 290, 291, -1, + -1, -1, 295, 281, 124, 125, 284, 285, 37, 38, + -1, -1, 41, 42, 43, 44, 45, -1, 47, 0, + 37, 38, -1, -1, 41, 42, 43, 44, 45, 58, + 47, 60, 61, 62, 63, 64, -1, -1, 19, 20, + -1, 58, -1, 60, 61, 62, 63, 64, 0, 30, + -1, -1, -1, 125, -1, -1, 0, -1, -1, -1, + 41, 0, -1, 281, 93, 94, 284, 285, 286, 287, + 288, 289, 290, 291, 55, -1, 93, 94, -1, -1, + -1, -1, -1, -1, 0, -1, -1, 41, -1, 41, + -1, -1, 44, 37, 38, 124, 125, 41, 42, 43, + 44, 45, 41, 47, -1, 44, 58, 124, 125, 61, + -1, 63, -1, 0, 58, -1, 60, 61, 62, 63, + 64, 37, 38, 62, -1, 41, 42, 43, 44, 45, + -1, 47, -1, 114, -1, 293, 294, 295, -1, -1, + 121, 93, 58, -1, 60, 61, 62, 63, 64, 93, + 94, 132, 0, -1, 41, -1, -1, 44, -1, -1, + -1, 281, -1, -1, 284, 285, 286, 287, 288, 289, + 290, 291, 124, 125, -1, 62, -1, 93, 94, -1, + 124, 125, 293, 294, 295, -1, 125, -1, -1, 37, + 38, -1, -1, 41, 42, 43, 44, 45, -1, 47, + -1, -1, -1, -1, -1, -1, 187, -1, 124, 125, + 58, -1, 60, 61, 62, 63, 64, -1, -1, -1, + -1, 37, -1, -1, 40, 206, 42, 43, -1, 45, + 46, 47, -1, -1, 215, -1, -1, 0, 125, -1, + -1, -1, 0, -1, -1, 93, 94, -1, 64, -1, + -1, -1, 281, -1, -1, 284, 285, 286, 287, 288, + 289, 290, 291, -1, 281, -1, -1, 284, 285, 286, + 287, 288, 289, 290, 291, 91, 124, 125, 41, 37, + 38, 44, -1, 41, 42, 43, 44, 45, -1, 47, + -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, + 58, -1, 60, 61, 62, 63, 64, 261, -1, 263, + 264, 265, 266, -1, 268, -1, 270, -1, 272, 273, + 274, 275, 276, 277, -1, -1, -1, -1, -1, 281, + 93, -1, 284, 285, -1, 93, 94, 281, -1, -1, + 284, 285, 286, 287, 288, 289, 290, 291, -1, 37, + -1, 0, 40, -1, 42, 43, -1, 45, 46, 47, + -1, -1, 125, 0, -1, 281, 124, 125, 284, 285, + 286, 287, 288, 289, 290, 291, 64, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 37, 38, + -1, -1, 41, 42, 43, 44, 45, -1, 47, -1, + 37, 38, -1, 91, 41, 42, 43, 44, 45, 58, + 47, 60, 61, 62, 63, 64, -1, -1, -1, -1, + -1, 58, 0, 60, 61, 62, 63, 64, -1, -1, + -1, -1, -1, 281, -1, -1, 284, 285, 286, 287, + 288, 289, 290, 291, 93, 94, -1, -1, -1, -1, + 0, -1, -1, -1, -1, -1, 93, 94, -1, 37, + 38, 0, -1, 41, 42, 43, 44, 45, -1, 47, + -1, -1, -1, -1, -1, 124, 125, 293, 294, 295, + 58, -1, 60, 61, 62, 63, 64, 124, 125, -1, + -1, 41, -1, -1, 44, -1, -1, 0, -1, -1, + -1, -1, 41, -1, -1, 44, -1, -1, 58, -1, + -1, 61, -1, 63, -1, 93, 94, -1, -1, 58, + -1, -1, -1, 281, -1, -1, 284, 285, 286, 287, + 288, 289, 290, 291, 37, 38, 0, -1, 41, 42, + 43, 44, 45, 93, 47, -1, 124, 125, -1, -1, + -1, -1, -1, -1, 93, 58, -1, 60, 61, 62, + 63, 64, -1, -1, -1, 7, 8, 9, 10, -1, + -1, 13, 14, 37, 38, 125, -1, 41, 42, 43, + 44, 45, -1, 47, -1, -1, 125, -1, -1, -1, + 93, 94, -1, -1, 58, -1, 60, 61, 62, 63, + 64, -1, 290, 291, -1, 293, 294, 295, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 124, 125, -1, -1, 0, -1, -1, -1, 93, + 94, -1, 281, -1, -1, 284, 285, 286, 287, 288, + 289, 290, 291, -1, 281, -1, -1, 284, 285, 286, + 287, 288, 289, 290, 291, -1, -1, -1, -1, -1, + 124, 125, 37, 38, 106, 107, 41, 42, 43, 44, + 45, -1, 47, -1, -1, -1, -1, -1, -1, 0, + -1, -1, -1, 58, 126, 60, 61, 62, 63, 64, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 281, 0, -1, 284, 285, 286, 287, + 288, 289, 290, 291, -1, 0, 37, 38, 93, 94, + 41, 42, 43, 44, 45, -1, 47, -1, -1, -1, + -1, 281, 174, -1, 284, -1, -1, 58, -1, 60, + 61, 62, 63, 64, -1, 41, -1, -1, 44, 124, + 125, 0, -1, 38, -1, 40, 41, 42, -1, 44, + -1, -1, 58, -1, -1, 61, -1, 63, -1, -1, + -1, -1, 93, 94, -1, -1, -1, 62, 281, -1, + -1, 284, 285, 286, 287, 288, 289, 290, 291, 38, + -1, -1, 41, 0, 43, 44, 45, 93, 94, -1, + -1, -1, -1, 124, 125, 0, 91, -1, -1, 58, + -1, 60, 61, 62, 63, 64, -1, 281, -1, -1, + 284, 285, 286, 287, 288, 289, 290, 291, 124, 125, + -1, 38, -1, 0, 41, -1, 43, 44, 45, -1, + 125, -1, -1, 38, 93, 94, 41, -1, -1, 44, + -1, 58, -1, 60, 61, 62, 63, 64, -1, -1, + -1, -1, -1, 58, -1, 60, 61, 62, 63, 64, + -1, 38, -1, -1, 41, 124, 125, 44, -1, -1, + -1, 0, -1, -1, -1, -1, 93, 94, -1, -1, + -1, 58, -1, 60, 61, 62, 63, -1, 93, 94, + -1, -1, -1, -1, -1, -1, 281, -1, -1, 284, + 285, 286, 287, 288, 289, 290, 291, 124, 125, 38, + -1, -1, 41, -1, -1, 44, 93, 94, -1, 124, + 125, -1, -1, -1, -1, 0, -1, -1, -1, 58, + -1, 60, 61, 62, 63, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 124, 125, -1, + 281, -1, -1, 284, 285, 286, 287, 288, 289, 290, + 291, -1, 0, 38, 93, 94, 41, -1, -1, 44, + -1, -1, 0, -1, 269, 281, -1, -1, 284, 285, + -1, 276, 277, 58, -1, 60, 61, 62, 63, -1, + -1, -1, -1, -1, -1, 124, 125, 0, -1, -1, + 38, -1, 40, 41, 42, -1, 44, -1, -1, -1, + 38, -1, 40, 41, 42, -1, 44, -1, 93, 94, + -1, -1, 281, -1, 62, 284, 285, 286, 287, 288, + 289, 290, 291, -1, 62, 38, -1, -1, 41, -1, + -1, 44, -1, -1, -1, -1, -1, -1, -1, 124, + 125, -1, -1, 91, -1, 58, -1, 60, 61, 62, + 63, -1, -1, 91, 281, -1, -1, 284, 285, 286, + 287, 288, 289, 290, 291, -1, 281, -1, -1, 284, + 285, 286, 287, 288, 289, 290, 291, 125, -1, -1, + 93, 94, -1, -1, -1, -1, -1, 125, -1, -1, + -1, -1, -1, -1, 281, 0, -1, 284, 285, 286, + 287, 288, 289, 290, 291, -1, -1, -1, -1, -1, + -1, 124, 125, 261, -1, 263, 264, 265, 266, -1, + 268, 0, 270, -1, 272, 273, 274, 275, 276, 277, + -1, -1, 0, 38, -1, -1, 41, -1, -1, 44, + -1, -1, 281, -1, -1, 284, 285, 286, 287, 288, + 289, 290, 291, 58, -1, 60, 61, 62, 63, 38, + -1, -1, 41, -1, -1, 44, -1, -1, -1, 0, + 38, -1, -1, 41, -1, -1, 44, -1, -1, 58, + -1, 60, 61, 62, 63, -1, -1, -1, 93, 94, + 58, -1, -1, 61, -1, 63, 281, -1, -1, 284, + 285, 286, 287, 288, 289, -1, -1, 38, -1, -1, + 41, -1, -1, 44, 93, 94, -1, -1, -1, 124, + 125, 269, -1, -1, -1, 93, 94, 58, 276, 277, + 61, 269, 63, -1, -1, 33, -1, -1, 276, 277, + 0, -1, 40, -1, -1, 124, 125, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 124, 125, -1, -1, + -1, -1, 93, 94, -1, 0, -1, -1, 281, -1, + 0, 284, 285, 286, 287, 288, 289, -1, 38, 0, + 40, 41, 42, -1, 44, -1, -1, -1, -1, -1, + -1, -1, -1, 124, 125, 0, -1, -1, -1, -1, + -1, -1, 62, 38, -1, 40, 41, 42, 38, 44, + 40, 41, 42, -1, 44, -1, -1, 38, -1, 40, + 41, 42, -1, 44, -1, 123, -1, 62, 126, -1, + -1, 91, 62, 38, -1, 40, 41, 42, -1, 44, + -1, 62, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 33, 91, 62, -1, -1, + 38, 91, 40, -1, 42, 125, -1, 45, -1, -1, + 91, -1, -1, -1, -1, -1, 281, -1, -1, 284, + 285, 286, 287, 288, 289, -1, 91, -1, -1, -1, + 125, -1, -1, -1, 38, 125, 40, 41, 42, -1, + -1, -1, 281, -1, 125, 284, 285, 286, 287, 288, + 289, -1, -1, 281, -1, -1, 284, 285, 286, 287, + 125, 33, -1, -1, -1, -1, 38, -1, 40, -1, + 42, -1, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 123, -1, 91, 126, -1, + 281, -1, -1, 284, 285, 286, 287, -1, -1, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, -1, 272, 273, 274, 275, 276, 277, + 278, 279, 280, -1, 282, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 293, 294, -1, 296, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 269, + -1, 123, -1, -1, 126, -1, 276, 277, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 269, -1, -1, -1, -1, 269, + -1, 276, 277, -1, -1, -1, 276, 277, 269, -1, + -1, -1, -1, -1, -1, 276, 277, -1, -1, -1, + -1, -1, -1, -1, 269, -1, -1, -1, -1, -1, + -1, 276, 277, -1, -1, -1, -1, -1, -1, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, -1, 272, 273, 274, 275, 276, 277, + 278, 279, 280, -1, 282, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 293, 294, 261, 296, 263, + 264, 265, 266, -1, 268, -1, 270, -1, 272, 273, + 274, 275, 276, 277, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, -1, + 272, 273, 274, 275, 276, 277, 278, 279, 280, -1, + 282, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 293, 294, -1, 296, 37, 38, -1, 40, -1, + 42, 43, -1, 45, 46, 47, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 58, -1, 60, 61, + 62, 63, 64, -1, -1, -1, -1, -1, -1, -1, + 37, 38, -1, 40, -1, 42, 43, 42, 45, 46, + 47, -1, -1, -1, -1, -1, -1, -1, -1, 91, + -1, -1, 94, 60, 61, 62, 63, 64, -1, -1, + -1, -1, -1, -1, -1, 37, 38, -1, 40, -1, + 42, 43, -1, 45, 46, 47, 42, -1, -1, -1, + -1, -1, 124, -1, 91, -1, -1, 94, 60, -1, + 62, 63, 64, 37, 38, -1, 40, -1, 42, 43, + -1, 45, 46, 47, 37, 38, -1, 40, -1, 42, + 43, -1, 45, 46, 47, -1, 60, 124, 62, 91, + 64, -1, 94, -1, -1, -1, -1, 60, -1, 62, + -1, 64, 37, 38, -1, 40, -1, 42, 43, -1, + 45, 46, 47, -1, -1, -1, -1, 91, -1, -1, + 94, -1, 124, -1, -1, 60, -1, 62, 91, 64, + -1, 94, -1, -1, -1, 37, 38, -1, 40, -1, + 42, 43, -1, 45, 46, 47, 41, -1, -1, -1, + 124, -1, -1, -1, -1, -1, 91, -1, 60, 94, + 62, 124, 64, -1, -1, -1, -1, -1, -1, -1, + 37, -1, -1, 40, -1, 42, 43, -1, 45, 46, + 47, -1, -1, -1, -1, -1, -1, -1, -1, 91, + -1, -1, -1, 60, -1, 62, -1, 64, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 281, + -1, -1, 284, 285, 286, 287, 288, 289, 290, 291, + -1, 293, 294, 295, 91, 260, 261, 262, 263, 264, + 265, 266, -1, 268, -1, 270, -1, 272, 273, 274, + 275, 276, 277, -1, 281, -1, -1, 284, 285, 286, + 287, 288, 289, 290, 291, -1, 293, 294, 295, -1, + -1, 296, -1, -1, 260, 261, 262, 263, 264, 265, + 266, -1, 268, -1, 270, -1, 272, 273, 274, 275, + 276, 277, 284, 285, 286, 287, 288, 289, 290, 291, + -1, 293, 294, 295, -1, -1, -1, -1, -1, -1, + 296, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 285, 286, 287, 288, 289, 290, 291, -1, 293, + 294, 295, -1, 286, 287, 288, 289, 290, 291, -1, + 293, 294, 295, -1, -1, -1, -1, -1, -1, -1, + 37, -1, -1, 40, -1, 42, 43, -1, 45, 46, + 47, 286, 287, 288, 289, 290, 291, -1, 293, 294, + 295, -1, -1, 60, -1, 62, 261, 64, 263, 264, + 265, 266, -1, 268, -1, 270, -1, 272, 273, 274, + 275, 276, 277, 11, 286, 287, 288, 289, 290, 291, + -1, 293, 294, 295, 91, -1, -1, 25, 26, 27, + 28, 29, -1, -1, 32, 33, -1, -1, -1, -1, + -1, -1, -1, 41, -1, -1, -1, -1, -1, 286, + 287, 288, 289, 290, 291, -1, 293, 294, 295, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, -1, -1, -1, -1, + -1, -1, 110, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 135, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 159, -1, -1, 162, -1, -1, -1, 166, -1, + -1, 169, 170, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 191, -1, -1, -1, 195, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 288, 289, 290, 291, -1, 293, 294, 295, +}; +#define YYFINAL 35 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 296 +#if YYDEBUG +char *c_name[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"'!'",0,0,0,"'%'","'&'",0,"'('","')'","'*'","'+'","','","'-'","'.'","'/'",0,0,0, +0,0,0,0,0,0,0,"':'",0,"'<'","'='","'>'","'?'","'@'",0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,"'['",0,"']'","'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,"'{'","'|'","'}'","'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"INT","FLOAT", +"STRING","NAME","TYPENAME","NAME_OR_INT","STRUCT","CLASS","UNION","ENUM", +"SIZEOF","UNSIGNED","COLONCOLON","TEMPLATE","ERROR","SIGNED_KEYWORD","LONG", +"SHORT","INT_KEYWORD","CONST_KEYWORD","VOLATILE_KEYWORD","LAST","REGNAME", +"VARIABLE","ASSIGN_MODIFY","THIS","ABOVE_COMMA","OROR","ANDAND","EQUAL", +"NOTEQUAL","LEQ","GEQ","LSH","RSH","UNARY","INCREMENT","DECREMENT","ARROW", +"BLOCKNAME", +}; +char *c_rule[] = { +"$accept : start", +"start : exp1", +"start : type_exp", +"type_exp : type", +"exp1 : exp", +"exp1 : exp1 ',' exp", +"exp : '*' exp", +"exp : '&' exp", +"exp : '-' exp", +"exp : '!' exp", +"exp : '~' exp", +"exp : INCREMENT exp", +"exp : DECREMENT exp", +"exp : exp INCREMENT", +"exp : exp DECREMENT", +"exp : SIZEOF exp", +"exp : exp ARROW name", +"exp : exp ARROW qualified_name", +"exp : exp ARROW '*' exp", +"exp : exp '.' name", +"exp : exp '.' qualified_name", +"exp : exp '.' '*' exp", +"exp : exp '[' exp1 ']'", +"$$1 :", +"exp : exp '(' $$1 arglist ')'", +"lcurly : '{'", +"arglist :", +"arglist : exp", +"arglist : arglist ',' exp", +"rcurly : '}'", +"exp : lcurly arglist rcurly", +"exp : lcurly type rcurly exp", +"exp : '(' type ')' exp", +"exp : '(' exp1 ')'", +"exp : exp '@' exp", +"exp : exp '*' exp", +"exp : exp '/' exp", +"exp : exp '%' exp", +"exp : exp '+' exp", +"exp : exp '-' exp", +"exp : exp LSH exp", +"exp : exp RSH exp", +"exp : exp EQUAL exp", +"exp : exp NOTEQUAL exp", +"exp : exp LEQ exp", +"exp : exp GEQ exp", +"exp : exp '<' exp", +"exp : exp '>' exp", +"exp : exp '&' exp", +"exp : exp '^' exp", +"exp : exp '|' exp", +"exp : exp ANDAND exp", +"exp : exp OROR exp", +"exp : exp '?' exp ':' exp", +"exp : exp '=' exp", +"exp : exp ASSIGN_MODIFY exp", +"exp : INT", +"exp : NAME_OR_INT", +"exp : FLOAT", +"exp : variable", +"exp : LAST", +"exp : REGNAME", +"exp : VARIABLE", +"exp : SIZEOF '(' type ')'", +"exp : STRING", +"exp : THIS", +"block : BLOCKNAME", +"block : block COLONCOLON name", +"variable : block COLONCOLON name", +"qualified_name : typebase COLONCOLON name", +"qualified_name : typebase COLONCOLON '~' name", +"variable : qualified_name", +"variable : COLONCOLON name", +"variable : name_not_typename", +"ptype : typebase", +"ptype : typebase CONST_KEYWORD", +"ptype : typebase VOLATILE_KEYWORD", +"ptype : typebase abs_decl", +"ptype : typebase CONST_KEYWORD abs_decl", +"ptype : typebase VOLATILE_KEYWORD abs_decl", +"abs_decl : '*'", +"abs_decl : '*' abs_decl", +"abs_decl : '&'", +"abs_decl : '&' abs_decl", +"abs_decl : direct_abs_decl", +"direct_abs_decl : '(' abs_decl ')'", +"direct_abs_decl : direct_abs_decl array_mod", +"direct_abs_decl : array_mod", +"direct_abs_decl : direct_abs_decl func_mod", +"direct_abs_decl : func_mod", +"array_mod : '[' ']'", +"array_mod : '[' INT ']'", +"func_mod : '(' ')'", +"func_mod : '(' nonempty_typelist ')'", +"type : ptype", +"type : typebase COLONCOLON '*'", +"type : type '(' typebase COLONCOLON '*' ')'", +"type : type '(' typebase COLONCOLON '*' ')' '(' ')'", +"type : type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'", +"typebase : TYPENAME", +"typebase : INT_KEYWORD", +"typebase : LONG", +"typebase : SHORT", +"typebase : LONG INT_KEYWORD", +"typebase : UNSIGNED LONG INT_KEYWORD", +"typebase : LONG LONG", +"typebase : LONG LONG INT_KEYWORD", +"typebase : UNSIGNED LONG LONG", +"typebase : UNSIGNED LONG LONG INT_KEYWORD", +"typebase : SHORT INT_KEYWORD", +"typebase : UNSIGNED SHORT INT_KEYWORD", +"typebase : STRUCT name", +"typebase : CLASS name", +"typebase : UNION name", +"typebase : ENUM name", +"typebase : UNSIGNED typename", +"typebase : UNSIGNED", +"typebase : SIGNED_KEYWORD typename", +"typebase : SIGNED_KEYWORD", +"typebase : TEMPLATE name '<' type '>'", +"typebase : CONST_KEYWORD typebase", +"typebase : VOLATILE_KEYWORD typebase", +"typename : TYPENAME", +"typename : INT_KEYWORD", +"typename : LONG", +"typename : SHORT", +"nonempty_typelist : type", +"nonempty_typelist : nonempty_typelist ',' type", +"name : NAME", +"name : BLOCKNAME", +"name : TYPENAME", +"name : NAME_OR_INT", +"name_not_typename : NAME", +"name_not_typename : BLOCKNAME", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 914 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (p, len, parsed_float, putithere) + register char *p; + register int len; + int parsed_float; + YYSTYPE *putithere; +{ + register LONGEST n = 0; + register LONGEST prevn = 0; + register int i = 0; + register int c; + register int base = input_radix; + int unsigned_p = 0; + int long_p = 0; + unsigned LONGEST high_bit; + struct type *signed_type; + struct type *unsigned_type; + + if (parsed_float) + { + /* It's a float since it contains a point or an exponent. */ + putithere->dval = atof (p); + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 0 */ + if (p[0] == '0') + switch (p[1]) + { + case 'x': + case 'X': + if (len >= 3) + { + p += 2; + base = 16; + len -= 2; + } + break; + + case 't': + case 'T': + case 'd': + case 'D': + if (len >= 3) + { + p += 2; + base = 10; + len -= 2; + } + break; + + default: + base = 8; + break; + } + + while (len-- > 0) + { + c = *p++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != 'l' && c != 'u') + n *= base; + if (c >= '0' && c <= '9') + n += i = c - '0'; + else + { + if (base > 10 && c >= 'a' && c <= 'f') + n += i = c - 'a' + 10; + else if (len == 0 && c == 'l') + long_p = 1; + else if (len == 0 && c == 'u') + unsigned_p = 1; + else + return ERROR; /* Char not a digit */ + } + if (i >= base) + return ERROR; /* Invalid digit in this base */ + + /* Portably test for overflow (only works for nonzero values, so make + a second check for zero). */ + if((prevn >= n) && n != 0) + unsigned_p=1; /* Try something unsigned */ + /* If range checking enabled, portably test for unsigned overflow. */ + if(RANGE_CHECK && n!=0) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + /* If the number is too big to be an int, or it's got an l suffix + then it's a long. Work out if this has to be a long by + shifting right and and seeing if anything remains, and the + target int size is different to the target long size. + + In the expression below, we could have tested + (n >> TARGET_INT_BIT) + to see if it was zero, + but too many compilers warn about that, when ints and longs + are the same size. So we shift it twice, with fewer bits + each time, for the same result. */ + + if ( (TARGET_INT_BIT != TARGET_LONG_BIT + && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */ + || long_p) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); + unsigned_type = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + + putithere->typed_val.val = n; + + /* If the high bit of the worked out type is set then this number + has to be unsigned. */ + + if (unsigned_p || (n & high_bit)) + { + putithere->typed_val.type = unsigned_type; + } + else + { + putithere->typed_val.type = signed_type; + } + + return INT; +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static const struct token tokentab3[] = + { + {">>=", ASSIGN_MODIFY, BINOP_RSH}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH} + }; + +static const struct token tokentab2[] = + { + {"+=", ASSIGN_MODIFY, BINOP_ADD}, + {"-=", ASSIGN_MODIFY, BINOP_SUB}, + {"*=", ASSIGN_MODIFY, BINOP_MUL}, + {"/=", ASSIGN_MODIFY, BINOP_DIV}, + {"%=", ASSIGN_MODIFY, BINOP_REM}, + {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR}, + {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND}, + {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR}, + {"++", INCREMENT, BINOP_END}, + {"--", DECREMENT, BINOP_END}, + {"->", ARROW, BINOP_END}, + {"&&", ANDAND, BINOP_END}, + {"||", OROR, BINOP_END}, + {"::", COLONCOLON, BINOP_END}, + {"<<", LSH, BINOP_END}, + {">>", RSH, BINOP_END}, + {"==", EQUAL, BINOP_END}, + {"!=", NOTEQUAL, BINOP_END}, + {"<=", LEQ, BINOP_END}, + {">=", GEQ, BINOP_END} + }; + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + int c; + int namelen; + unsigned int i; + char *tokstart; + char *tokptr; + int tempbufindex; + static char *tempbuf; + static int tempbufsize; + + retry: + + tokstart = lexptr; + /* See if it is a special token of length 3. */ + for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) + if (STREQN (tokstart, tokentab3[i].operator, 3)) + { + lexptr += 3; + yylval.opcode = tokentab3[i].opcode; + return tokentab3[i].token; + } + + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (STREQN (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + /* We either have a character constant ('0' or '\177' for example) + or we have a quoted symbol reference ('foo(int,int)' in C++ + for example). */ + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + + yylval.typed_val.val = c; + yylval.typed_val.type = builtin_type_char; + + c = *lexptr++; + if (c != '\'') + { + namelen = skip_quoted (tokstart) - tokstart; + if (namelen > 2) + { + lexptr = tokstart + namelen; + if (lexptr[-1] != '\'') + error ("Unmatched single quote."); + namelen -= 2; + tokstart++; + goto tryname; + } + error ("Invalid character constant."); + } + return INT; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] < '0' || lexptr[1] > '9') + goto symbol; /* Nope, must be a symbol. */ + /* FALL THRU into number case. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + /* It's a number. */ + int got_dot = 0, got_e = 0, toktype; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + for (;; ++p) + { + /* This test includes !hex because 'e' is a valid hex digit + and thus does not indicate a floating point number when + the radix is hex. */ + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + /* This test does not include !hex, because a '.' always indicates + a decimal floating point number regardless of the radix. */ + else if (!got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + memcpy (err_copy, tokstart, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + case '+': + case '-': + case '*': + case '/': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + + case '"': + + /* Build the gdb internal form of the input string in tempbuf, + translating any standard C escape forms seen. Note that the + buffer is null byte terminated *only* for the convenience of + debugging gdb itself and printing the buffer contents when + the buffer contains no embedded nulls. Gdb does not depend + upon the buffer being null byte terminated, it uses the length + string instead. This allows gdb to handle C strings (as well + as strings in other languages) with embedded null bytes */ + + tokptr = ++tokstart; + tempbufindex = 0; + + do { + /* Grow the static temp buffer if necessary, including allocating + the first one on demand. */ + if (tempbufindex + 1 >= tempbufsize) + { + tempbuf = (char *) xrealloc (tempbuf, tempbufsize += 64); + } + switch (*tokptr) + { + case '\0': + case '"': + /* Do nothing, loop will terminate. */ + break; + case '\\': + tokptr++; + c = parse_escape (&tokptr); + if (c == -1) + { + continue; + } + tempbuf[tempbufindex++] = c; + break; + default: + tempbuf[tempbufindex++] = *tokptr++; + break; + } + } while ((*tokptr != '"') && (*tokptr != '\0')); + if (*tokptr++ != '"') + { + error ("Unterminated string in expression."); + } + tempbuf[tempbufindex] = '\0'; /* See note above */ + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = tokptr; + return (STRING); + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + tryname: + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && STREQN (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < num_std_regs; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && STREQN (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + /* Catch specific keywords. Should be done with a data structure. */ + switch (namelen) + { + case 8: + if (STREQN (tokstart, "unsigned", 8)) + return UNSIGNED; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "template", 8)) + return TEMPLATE; + if (STREQN (tokstart, "volatile", 8)) + return VOLATILE_KEYWORD; + break; + case 6: + if (STREQN (tokstart, "struct", 6)) + return STRUCT; + if (STREQN (tokstart, "signed", 6)) + return SIGNED_KEYWORD; + if (STREQN (tokstart, "sizeof", 6)) + return SIZEOF; + break; + case 5: + if (current_language->la_language == language_cplus + && STREQN (tokstart, "class", 5)) + return CLASS; + if (STREQN (tokstart, "union", 5)) + return UNION; + if (STREQN (tokstart, "short", 5)) + return SHORT; + if (STREQN (tokstart, "const", 5)) + return CONST_KEYWORD; + break; + case 4: + if (STREQN (tokstart, "enum", 4)) + return ENUM; + if (STREQN (tokstart, "long", 4)) + return LONG; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "this", 4)) + { + static const char this_name[] = + { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; + + if (lookup_symbol (this_name, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL)) + return THIS; + } + break; + case 3: + if (STREQN (tokstart, "int", 3)) + return INT_KEYWORD; + break; + default: + break; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1); + return VARIABLE; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions or symtabs. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + int is_a_field_of_this = 0; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, + current_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) NULL, + (struct symtab **) NULL); + if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) || + lookup_partial_symtab (tmp)) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return BLOCKNAME; + } + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + char *p; + char *namestart; + struct symbol *best_sym; + + /* Look ahead to detect nested types. This probably should be + done in the grammar, but trying seemed to introduce a lot + of shift/reduce and reduce/reduce conflicts. It's possible + that it could be done, though. Or perhaps a non-grammar, but + less ad hoc, approach would work well. */ + + /* Since we do not currently have any way of distinguishing + a nested type from a non-nested one (the stabs don't tell + us whether a type is nested), we just ignore the + containing type. */ + + p = lexptr; + best_sym = sym; + while (1) + { + /* Skip whitespace. */ + while (*p == ' ' || *p == '\t' || *p == '\n') + ++p; + if (*p == ':' && p[1] == ':') + { + /* Skip the `::'. */ + p += 2; + /* Skip whitespace. */ + while (*p == ' ' || *p == '\t' || *p == '\n') + ++p; + namestart = p; + while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9') + || (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z')) + ++p; + if (p != namestart) + { + struct symbol *cur_sym; + /* As big as the whole rest of the expression, which is + at least big enough. */ + char *tmp = alloca (strlen (namestart)); + + memcpy (tmp, namestart, p - namestart); + tmp[p - namestart] = '\0'; + cur_sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (cur_sym) + { + if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF) + { + best_sym = cur_sym; + lexptr = p; + } + else + break; + } + else + break; + } + else + break; + } + else + break; + } + + yylval.tsym.type = SYMBOL_TYPE (best_sym); + return TYPENAME; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* Input names that aren't symbols but ARE valid hex numbers, + when the input radix permits them, can be names or numbers + depending on the parse. Note we support radixes > 16 here. */ + if (!sym && + ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || + (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) + { + YYSTYPE newlval; /* Its value is ignored. */ + hextype = parse_number (tokstart, namelen, 0, &newlval); + if (hextype == INT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_INT; + } + } + + /* Any other kind of symbol */ + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME; + } +} + +void +yyerror (msg) + char *msg; +{ + error (msg ? msg : "Invalid syntax in expression."); +} +#line 1706 "y.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 3: +#line 211 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(yyvsp[0].tval); + write_exp_elt_opcode(OP_TYPE);} +break; +case 5: +#line 219 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_COMMA); } +break; +case 6: +#line 224 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_IND); } +break; +case 7: +#line 227 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_ADDR); } +break; +case 8: +#line 230 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_NEG); } +break; +case 9: +#line 234 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); } +break; +case 10: +#line 238 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_COMPLEMENT); } +break; +case 11: +#line 242 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_PREINCREMENT); } +break; +case 12: +#line 246 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_PREDECREMENT); } +break; +case 13: +#line 250 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_POSTINCREMENT); } +break; +case 14: +#line 254 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_POSTDECREMENT); } +break; +case 15: +#line 258 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); } +break; +case 16: +#line 262 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_PTR); } +break; +case 17: +#line 268 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ /* exp->type::name becomes exp->*(&type::name) */ + /* Note: this doesn't work if name is a + static member! FIXME */ + write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (STRUCTOP_MPTR); } +break; +case 18: +#line 275 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_MPTR); } +break; +case 19: +#line 279 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); } +break; +case 20: +#line 285 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ /* exp.type::name becomes exp.*(&type::name) */ + /* Note: this doesn't work if name is a + static member! FIXME */ + write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (STRUCTOP_MEMBER); } +break; +case 21: +#line 293 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_MEMBER); } +break; +case 22: +#line 297 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_SUBSCRIPT); } +break; +case 23: +#line 303 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ start_arglist (); } +break; +case 24: +#line 305 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } +break; +case 25: +#line 311 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ start_arglist (); } +break; +case 27: +#line 318 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ arglist_len = 1; } +break; +case 28: +#line 322 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ arglist_len++; } +break; +case 29: +#line 326 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.lval = end_arglist () - 1; } +break; +case 30: +#line 329 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_ARRAY); } +break; +case 31: +#line 336 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); } +break; +case 32: +#line 342 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_CAST); } +break; +case 33: +#line 348 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ } +break; +case 34: +#line 354 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_REPEAT); } +break; +case 35: +#line 358 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_MUL); } +break; +case 36: +#line 362 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_DIV); } +break; +case 37: +#line 366 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_REM); } +break; +case 38: +#line 370 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_ADD); } +break; +case 39: +#line 374 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_SUB); } +break; +case 40: +#line 378 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_LSH); } +break; +case 41: +#line 382 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_RSH); } +break; +case 42: +#line 386 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_EQUAL); } +break; +case 43: +#line 390 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); } +break; +case 44: +#line 394 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_LEQ); } +break; +case 45: +#line 398 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_GEQ); } +break; +case 46: +#line 402 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_LESS); } +break; +case 47: +#line 406 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_GTR); } +break; +case 48: +#line 410 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_AND); } +break; +case 49: +#line 414 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_XOR); } +break; +case 50: +#line 418 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_IOR); } +break; +case 51: +#line 422 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_AND); } +break; +case 52: +#line 426 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_OR); } +break; +case 53: +#line 430 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (TERNOP_COND); } +break; +case 54: +#line 434 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); } +break; +case 55: +#line 438 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode (yyvsp[-1].opcode); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } +break; +case 56: +#line 444 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (yyvsp[0].typed_val.type); + write_exp_elt_longcst ((LONGEST)(yyvsp[0].typed_val.val)); + write_exp_elt_opcode (OP_LONG); } +break; +case 57: +#line 451 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ YYSTYPE val; + parse_number (yyvsp[0].ssym.stoken.ptr, yyvsp[0].ssym.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (val.typed_val.type); + write_exp_elt_longcst ((LONGEST)val.typed_val.val); + write_exp_elt_opcode (OP_LONG); + } +break; +case 58: +#line 462 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst (yyvsp[0].dval); + write_exp_elt_opcode (OP_DOUBLE); } +break; +case 60: +#line 472 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LAST); } +break; +case 61: +#line 478 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_REGISTER); } +break; +case 62: +#line 484 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (yyvsp[0].ivar); + write_exp_elt_opcode (OP_INTERNALVAR); } +break; +case 63: +#line 490 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval)); + write_exp_elt_opcode (OP_LONG); } +break; +case 64: +#line 497 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ /* C strings are converted into array constants with + an explicit null byte added at the end. Thus + the array upper bound is the string length. + There is no such thing in C as a completely empty + string. */ + char *sp = yyvsp[0].sval.ptr; int count = yyvsp[0].sval.length; + while (count-- > 0) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST)(*sp++)); + write_exp_elt_opcode (OP_LONG); + } + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST)'\0'); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) (yyvsp[0].sval.length)); + write_exp_elt_opcode (OP_ARRAY); } +break; +case 65: +#line 522 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } +break; +case 66: +#line 529 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + if (yyvsp[0].ssym.sym != 0) + yyval.bval = SYMBOL_BLOCK_VALUE (yyvsp[0].ssym.sym); + else + { + struct symtab *tem = + lookup_symtab (copy_name (yyvsp[0].ssym.stoken)); + if (tem) + yyval.bval = BLOCKVECTOR_BLOCK + (BLOCKVECTOR (tem), STATIC_BLOCK); + else + error ("No file or function \"%s\".", + copy_name (yyvsp[0].ssym.stoken)); + } + } +break; +case 67: +#line 547 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ struct symbol *tem + = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + yyval.bval = SYMBOL_BLOCK_VALUE (tem); } +break; +case 68: +#line 558 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ struct symbol *sym; + sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + + write_exp_elt_opcode (OP_VAR_VALUE); + /* block_found is set by lookup_symbol. */ + write_exp_elt_block (block_found); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } +break; +case 69: +#line 574 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + struct type *type = yyvsp[-2].tval; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_SCOPE); + } +break; +case 70: +#line 587 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + struct type *type = yyvsp[-3].tval; + struct stoken tmp_token; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + if (!STREQ (type_name_no_tag (type), yyvsp[0].sval.ptr)) + error ("invalid destructor `%s::~%s'", + type_name_no_tag (type), yyvsp[0].sval.ptr); + + tmp_token.ptr = (char*) alloca (yyvsp[0].sval.length + 2); + tmp_token.length = yyvsp[0].sval.length + 1; + tmp_token.ptr[0] = '~'; + memcpy (tmp_token.ptr+1, yyvsp[0].sval.ptr, yyvsp[0].sval.length); + tmp_token.ptr[tmp_token.length] = 0; + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string (tmp_token); + write_exp_elt_opcode (OP_SCOPE); + } +break; +case 72: +#line 613 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + char *name = copy_name (yyvsp[0].sval); + struct symbol *sym; + struct minimal_symbol *msymbol; + + sym = + lookup_symbol (name, (const struct block *) NULL, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym) + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + break; + } + + msymbol = lookup_minimal_symbol (name, + (struct objfile *) NULL); + if (msymbol != NULL) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (msymbol -> type == mst_data || + msymbol -> type == mst_bss) + write_exp_elt_type (builtin_type_int); + else if (msymbol -> type == mst_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else + if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", name); + } +break; +case 73: +#line 658 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ struct symbol *sym = yyvsp[0].ssym.sym; + + if (sym) + { + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not + another more inner frame which happens to + be in the same block. */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else if (yyvsp[0].ssym.is_a_field_of_this) + { + /* C++: it hangs off of `this'. Must + not inadvertently convert from a method call + to data ref. */ + if (innermost_block == 0 || + contained_in (block_found, innermost_block)) + innermost_block = block_found; + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string (yyvsp[0].ssym.stoken); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name (yyvsp[0].ssym.stoken); + + msymbol = lookup_minimal_symbol (arg, + (struct objfile *) NULL); + if (msymbol != NULL) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (msymbol -> type == mst_data || + msymbol -> type == mst_bss) + write_exp_elt_type (builtin_type_int); + else if (msymbol -> type == mst_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name (yyvsp[0].ssym.stoken)); + } + } +break; +case 77: +#line 737 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = follow_types (yyvsp[-1].tval); } +break; +case 78: +#line 739 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = follow_types (yyvsp[-2].tval); } +break; +case 79: +#line 741 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = follow_types (yyvsp[-2].tval); } +break; +case 80: +#line 745 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ push_type (tp_pointer); yyval.voidval = 0; } +break; +case 81: +#line 747 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; } +break; +case 82: +#line 749 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ push_type (tp_reference); yyval.voidval = 0; } +break; +case 83: +#line 751 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; } +break; +case 85: +#line 756 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.voidval = yyvsp[-1].voidval; } +break; +case 86: +#line 758 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + push_type_int (yyvsp[0].lval); + push_type (tp_array); + } +break; +case 87: +#line 763 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + push_type_int (yyvsp[0].lval); + push_type (tp_array); + yyval.voidval = 0; + } +break; +case 88: +#line 773 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ push_type (tp_function); } +break; +case 89: +#line 775 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ push_type (tp_function); } +break; +case 90: +#line 779 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.lval = -1; } +break; +case 91: +#line 781 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.lval = yyvsp[-1].typed_val.val; } +break; +case 92: +#line 785 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.voidval = 0; } +break; +case 93: +#line 787 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ free ((PTR)yyvsp[-1].tvec); yyval.voidval = 0; } +break; +case 95: +#line 794 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); } +break; +case 96: +#line 796 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_member_type (yyvsp[-5].tval, yyvsp[-3].tval); } +break; +case 97: +#line 798 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_member_type + (lookup_function_type (yyvsp[-7].tval), yyvsp[-5].tval); } +break; +case 98: +#line 801 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_member_type + (lookup_function_type (yyvsp[-8].tval), yyvsp[-6].tval); + free ((PTR)yyvsp[-1].tvec); } +break; +case 99: +#line 808 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = yyvsp[0].tsym.type; } +break; +case 100: +#line 810 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_int; } +break; +case 101: +#line 812 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_long; } +break; +case 102: +#line 814 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_short; } +break; +case 103: +#line 816 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_long; } +break; +case 104: +#line 818 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_unsigned_long; } +break; +case 105: +#line 820 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_long_long; } +break; +case 106: +#line 822 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_long_long; } +break; +case 107: +#line 824 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_unsigned_long_long; } +break; +case 108: +#line 826 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_unsigned_long_long; } +break; +case 109: +#line 828 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_short; } +break; +case 110: +#line 830 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_unsigned_short; } +break; +case 111: +#line 832 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval), + expression_context_block); } +break; +case 112: +#line 835 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval), + expression_context_block); } +break; +case 113: +#line 838 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_union (copy_name (yyvsp[0].sval), + expression_context_block); } +break; +case 114: +#line 841 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_enum (copy_name (yyvsp[0].sval), + expression_context_block); } +break; +case 115: +#line 844 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_unsigned_typename (TYPE_NAME(yyvsp[0].tsym.type)); } +break; +case 116: +#line 846 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_unsigned_int; } +break; +case 117: +#line 848 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_signed_typename (TYPE_NAME(yyvsp[0].tsym.type)); } +break; +case 118: +#line 850 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = builtin_type_int; } +break; +case 119: +#line 852 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = lookup_template_type(copy_name(yyvsp[-3].sval), yyvsp[-1].tval, + expression_context_block); + } +break; +case 120: +#line 858 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = yyvsp[0].tval; } +break; +case 121: +#line 859 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tval = yyvsp[0].tval; } +break; +case 123: +#line 864 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + yyval.tsym.stoken.ptr = "int"; + yyval.tsym.stoken.length = 3; + yyval.tsym.type = builtin_type_int; + } +break; +case 124: +#line 870 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + yyval.tsym.stoken.ptr = "long"; + yyval.tsym.stoken.length = 4; + yyval.tsym.type = builtin_type_long; + } +break; +case 125: +#line 876 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ + yyval.tsym.stoken.ptr = "short"; + yyval.tsym.stoken.length = 5; + yyval.tsym.type = builtin_type_short; + } +break; +case 126: +#line 885 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.tvec = (struct type **) xmalloc (sizeof (struct type *) * 2); + yyval.ivec[0] = 1; /* Number of types in vector */ + yyval.tvec[1] = yyvsp[0].tval; + } +break; +case 127: +#line 890 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ int len = sizeof (struct type *) * (++(yyvsp[-2].ivec[0]) + 1); + yyval.tvec = (struct type **) xrealloc ((char *) yyvsp[-2].tvec, len); + yyval.tvec[yyval.ivec[0]] = yyvsp[0].tval; + } +break; +case 128: +#line 896 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; } +break; +case 129: +#line 897 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; } +break; +case 130: +#line 898 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.sval = yyvsp[0].tsym.stoken; } +break; +case 131: +#line 899 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; } +break; +#line 2593 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/gnu/usr.bin/gdb/gdb/c-exp.y b/gnu/usr.bin/gdb/gdb/c-exp.y new file mode 100644 index 00000000000..0e7d39ac6c2 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/c-exp.y @@ -0,0 +1,1601 @@ +/* YACC parser for C expressions, for GDB. + Copyright (C) 1986, 1989, 1990, 1991 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. */ + +/* Parse a C expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. + + Note that malloc's and realloc's in this file are transformed to + xmalloc and xrealloc respectively by the same sed command in the + makefile that remaps any other malloc/realloc inserted by the parser + generator. Doing this with #defines and trying to control the interaction + with include files ( and for example) just became + too messy, particularly when such includes can be inserted at random + times by the parser generator. */ + +%{ + +#include "defs.h" +#include "expression.h" +#include "parser-defs.h" +#include "value.h" +#include "language.h" +#include "c-lang.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth c_maxdepth +#define yyparse c_parse +#define yylex c_lex +#define yyerror c_error +#define yylval c_lval +#define yychar c_char +#define yydebug c_debug +#define yypact c_pact +#define yyr1 c_r1 +#define yyr2 c_r2 +#define yydef c_def +#define yychk c_chk +#define yypgo c_pgo +#define yyact c_act +#define yyexca c_exca +#define yyerrflag c_errflag +#define yynerrs c_nerrs +#define yyps c_ps +#define yypv c_pv +#define yys c_s +#define yy_yys c_yys +#define yystate c_state +#define yytmp c_tmp +#define yyv c_v +#define yy_yyv c_yyv +#define yyval c_val +#define yylloc c_lloc +#define yyreds c_reds /* With YYDEBUG defined */ +#define yytoks c_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + LONGEST lval; + struct { + LONGEST val; + struct type *type; + } typed_val; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%{ +/* YYSTYPE gets defined by %union */ +static int +parse_number PARAMS ((char *, int, int, YYSTYPE *)); +%} + +%type exp exp1 type_exp start variable qualified_name lcurly +%type rcurly +%type type typebase +%type nonempty_typelist +/* %type block */ + +/* Fancy type parsing. */ +%type func_mod direct_abs_decl abs_decl +%type ptype +%type array_mod + +%token INT +%token FLOAT + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token STRING +%token NAME /* BLOCKNAME defined below to give it higher precedence. */ +%token TYPENAME +%type name +%type name_not_typename +%type typename + +/* A NAME_OR_INT is a symbol which is not known in the symbol table, + but which would parse as a valid number in the current input radix. + E.g. "c" when input_radix==16. Depending on the parse, it will be + turned into a name or into a number. */ + +%token NAME_OR_INT + +%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON +%token TEMPLATE +%token ERROR + +/* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ +%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD +%token LAST REGNAME + +%token VARIABLE + +%token ASSIGN_MODIFY + +/* C++ */ +%token THIS + +%left ',' +%left ABOVE_COMMA +%right '=' ASSIGN_MODIFY +%right '?' +%left OROR +%left ANDAND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '@' +%left '+' '-' +%left '*' '/' '%' +%right UNARY INCREMENT DECREMENT +%right ARROW '.' '[' '(' +%token BLOCKNAME +%type block +%left COLONCOLON + + +%% + +start : exp1 + | type_exp + ; + +type_exp: type + { write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type($1); + write_exp_elt_opcode(OP_TYPE);} + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { write_exp_elt_opcode (BINOP_COMMA); } + ; + +/* Expressions, not including the comma operator. */ +exp : '*' exp %prec UNARY + { write_exp_elt_opcode (UNOP_IND); } + +exp : '&' exp %prec UNARY + { write_exp_elt_opcode (UNOP_ADDR); } + +exp : '-' exp %prec UNARY + { write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '!' exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + ; + +exp : '~' exp %prec UNARY + { write_exp_elt_opcode (UNOP_COMPLEMENT); } + ; + +exp : INCREMENT exp %prec UNARY + { write_exp_elt_opcode (UNOP_PREINCREMENT); } + ; + +exp : DECREMENT exp %prec UNARY + { write_exp_elt_opcode (UNOP_PREDECREMENT); } + ; + +exp : exp INCREMENT %prec UNARY + { write_exp_elt_opcode (UNOP_POSTINCREMENT); } + ; + +exp : exp DECREMENT %prec UNARY + { write_exp_elt_opcode (UNOP_POSTDECREMENT); } + ; + +exp : SIZEOF exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + +exp : exp ARROW name + { write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_PTR); } + ; + +exp : exp ARROW qualified_name + { /* exp->type::name becomes exp->*(&type::name) */ + /* Note: this doesn't work if name is a + static member! FIXME */ + write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (STRUCTOP_MPTR); } + ; +exp : exp ARROW '*' exp + { write_exp_elt_opcode (STRUCTOP_MPTR); } + ; + +exp : exp '.' name + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : exp '.' qualified_name + { /* exp.type::name becomes exp.*(&type::name) */ + /* Note: this doesn't work if name is a + static member! FIXME */ + write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (STRUCTOP_MEMBER); } + ; + +exp : exp '.' '*' exp + { write_exp_elt_opcode (STRUCTOP_MEMBER); } + ; + +exp : exp '[' exp1 ']' + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec ARROW + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } + ; + +lcurly : '{' + { start_arglist (); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +rcurly : '}' + { $$ = end_arglist () - 1; } + ; +exp : lcurly arglist rcurly %prec ARROW + { write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) $3); + write_exp_elt_opcode (OP_ARRAY); } + ; + +exp : lcurly type rcurly exp %prec UNARY + { write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_MEMVAL); } + ; + +exp : '(' type ')' exp %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : '(' exp1 ')' + { } + ; + +/* Binary operators in order of decreasing precedence. */ + +exp : exp '@' exp + { write_exp_elt_opcode (BINOP_REPEAT); } + ; + +exp : exp '*' exp + { write_exp_elt_opcode (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt_opcode (BINOP_DIV); } + ; + +exp : exp '%' exp + { write_exp_elt_opcode (BINOP_REM); } + ; + +exp : exp '+' exp + { write_exp_elt_opcode (BINOP_ADD); } + ; + +exp : exp '-' exp + { write_exp_elt_opcode (BINOP_SUB); } + ; + +exp : exp LSH exp + { write_exp_elt_opcode (BINOP_LSH); } + ; + +exp : exp RSH exp + { write_exp_elt_opcode (BINOP_RSH); } + ; + +exp : exp EQUAL exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt_opcode (BINOP_LEQ); } + ; + +exp : exp GEQ exp + { write_exp_elt_opcode (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt_opcode (BINOP_GTR); } + ; + +exp : exp '&' exp + { write_exp_elt_opcode (BINOP_BITWISE_AND); } + ; + +exp : exp '^' exp + { write_exp_elt_opcode (BINOP_BITWISE_XOR); } + ; + +exp : exp '|' exp + { write_exp_elt_opcode (BINOP_BITWISE_IOR); } + ; + +exp : exp ANDAND exp + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + ; + +exp : exp OROR exp + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + ; + +exp : exp '?' exp ':' exp %prec '?' + { write_exp_elt_opcode (TERNOP_COND); } + ; + +exp : exp '=' exp + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + +exp : exp ASSIGN_MODIFY exp + { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode ($2); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } + ; + +exp : INT + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type ($1.type); + write_exp_elt_longcst ((LONGEST)($1.val)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : NAME_OR_INT + { YYSTYPE val; + parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (val.typed_val.type); + write_exp_elt_longcst ((LONGEST)val.typed_val.val); + write_exp_elt_opcode (OP_LONG); + } + ; + + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : LAST + { write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LAST); } + ; + +exp : REGNAME + { write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_REGISTER); } + ; + +exp : VARIABLE + { write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); } + ; + +exp : SIZEOF '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : STRING + { /* C strings are converted into array constants with + an explicit null byte added at the end. Thus + the array upper bound is the string length. + There is no such thing in C as a completely empty + string. */ + char *sp = $1.ptr; int count = $1.length; + while (count-- > 0) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST)(*sp++)); + write_exp_elt_opcode (OP_LONG); + } + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST)'\0'); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) ($1.length)); + write_exp_elt_opcode (OP_ARRAY); } + ; + +/* C++. */ +exp : THIS + { write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } + ; + +/* end of C++. */ + +block : BLOCKNAME + { + if ($1.sym != 0) + $$ = SYMBOL_BLOCK_VALUE ($1.sym); + else + { + struct symtab *tem = + lookup_symtab (copy_name ($1.stoken)); + if (tem) + $$ = BLOCKVECTOR_BLOCK + (BLOCKVECTOR (tem), STATIC_BLOCK); + else + error ("No file or function \"%s\".", + copy_name ($1.stoken)); + } + } + ; + +block : block COLONCOLON name + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = SYMBOL_BLOCK_VALUE (tem); } + ; + +variable: block COLONCOLON name + { struct symbol *sym; + sym = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name ($3)); + + write_exp_elt_opcode (OP_VAR_VALUE); + /* block_found is set by lookup_symbol. */ + write_exp_elt_block (block_found); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +qualified_name: typebase COLONCOLON name + { + struct type *type = $1; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string ($3); + write_exp_elt_opcode (OP_SCOPE); + } + | typebase COLONCOLON '~' name + { + struct type *type = $1; + struct stoken tmp_token; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + if (!STREQ (type_name_no_tag (type), $4.ptr)) + error ("invalid destructor `%s::~%s'", + type_name_no_tag (type), $4.ptr); + + tmp_token.ptr = (char*) alloca ($4.length + 2); + tmp_token.length = $4.length + 1; + tmp_token.ptr[0] = '~'; + memcpy (tmp_token.ptr+1, $4.ptr, $4.length); + tmp_token.ptr[tmp_token.length] = 0; + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string (tmp_token); + write_exp_elt_opcode (OP_SCOPE); + } + ; + +variable: qualified_name + | COLONCOLON name + { + char *name = copy_name ($2); + struct symbol *sym; + struct minimal_symbol *msymbol; + + sym = + lookup_symbol (name, (const struct block *) NULL, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym) + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + break; + } + + msymbol = lookup_minimal_symbol (name, + (struct objfile *) NULL); + if (msymbol != NULL) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (msymbol -> type == mst_data || + msymbol -> type == mst_bss) + write_exp_elt_type (builtin_type_int); + else if (msymbol -> type == mst_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else + if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", name); + } + ; + +variable: name_not_typename + { struct symbol *sym = $1.sym; + + if (sym) + { + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not + another more inner frame which happens to + be in the same block. */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else if ($1.is_a_field_of_this) + { + /* C++: it hangs off of `this'. Must + not inadvertently convert from a method call + to data ref. */ + if (innermost_block == 0 || + contained_in (block_found, innermost_block)) + innermost_block = block_found; + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($1.stoken); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name ($1.stoken); + + msymbol = lookup_minimal_symbol (arg, + (struct objfile *) NULL); + if (msymbol != NULL) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (msymbol -> type == mst_data || + msymbol -> type == mst_bss) + write_exp_elt_type (builtin_type_int); + else if (msymbol -> type == mst_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1.stoken)); + } + } + ; + + +/* shift/reduce conflict: "typebase ." and the token is '('. (Shows up + twice, once where qualified_name is a possibility and once where + it is not). */ +/* shift/reduce conflict: "typebase CONST_KEYWORD ." and the token is '('. */ +/* shift/reduce conflict: "typebase VOLATILE_KEYWORD ." and the token is + '('. */ +ptype : typebase + /* "const" and "volatile" are curently ignored. A type qualifier + before the type is currently handled in the typebase rule. */ + | typebase CONST_KEYWORD + | typebase VOLATILE_KEYWORD + | typebase abs_decl + { $$ = follow_types ($1); } + | typebase CONST_KEYWORD abs_decl + { $$ = follow_types ($1); } + | typebase VOLATILE_KEYWORD abs_decl + { $$ = follow_types ($1); } + ; + +abs_decl: '*' + { push_type (tp_pointer); $$ = 0; } + | '*' abs_decl + { push_type (tp_pointer); $$ = $2; } + | '&' + { push_type (tp_reference); $$ = 0; } + | '&' abs_decl + { push_type (tp_reference); $$ = $2; } + | direct_abs_decl + ; + +direct_abs_decl: '(' abs_decl ')' + { $$ = $2; } + | direct_abs_decl array_mod + { + push_type_int ($2); + push_type (tp_array); + } + | array_mod + { + push_type_int ($1); + push_type (tp_array); + $$ = 0; + } + + /* shift/reduce conflict. "direct_abs_decl . func_mod", and the token + is '('. */ + + | direct_abs_decl func_mod + { push_type (tp_function); } + | func_mod + { push_type (tp_function); } + ; + +array_mod: '[' ']' + { $$ = -1; } + | '[' INT ']' + { $$ = $2.val; } + ; + +func_mod: '(' ')' + { $$ = 0; } + | '(' nonempty_typelist ')' + { free ((PTR)$2); $$ = 0; } + ; + +/* shift/reduce conflict: "type '(' typebase COLONCOLON '*' ')' ." and the + token is '('. */ +type : ptype + | typebase COLONCOLON '*' + { $$ = lookup_member_type (builtin_type_int, $1); } + | type '(' typebase COLONCOLON '*' ')' + { $$ = lookup_member_type ($1, $3); } + | type '(' typebase COLONCOLON '*' ')' '(' ')' + { $$ = lookup_member_type + (lookup_function_type ($1), $3); } + | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')' + { $$ = lookup_member_type + (lookup_function_type ($1), $3); + free ((PTR)$8); } + ; + +typebase /* Implements (approximately): (type-qualifier)* type-specifier */ + : TYPENAME + { $$ = $1.type; } + | INT_KEYWORD + { $$ = builtin_type_int; } + | LONG + { $$ = builtin_type_long; } + | SHORT + { $$ = builtin_type_short; } + | LONG INT_KEYWORD + { $$ = builtin_type_long; } + | UNSIGNED LONG INT_KEYWORD + { $$ = builtin_type_unsigned_long; } + | LONG LONG + { $$ = builtin_type_long_long; } + | LONG LONG INT_KEYWORD + { $$ = builtin_type_long_long; } + | UNSIGNED LONG LONG + { $$ = builtin_type_unsigned_long_long; } + | UNSIGNED LONG LONG INT_KEYWORD + { $$ = builtin_type_unsigned_long_long; } + | SHORT INT_KEYWORD + { $$ = builtin_type_short; } + | UNSIGNED SHORT INT_KEYWORD + { $$ = builtin_type_unsigned_short; } + | STRUCT name + { $$ = lookup_struct (copy_name ($2), + expression_context_block); } + | CLASS name + { $$ = lookup_struct (copy_name ($2), + expression_context_block); } + | UNION name + { $$ = lookup_union (copy_name ($2), + expression_context_block); } + | ENUM name + { $$ = lookup_enum (copy_name ($2), + expression_context_block); } + | UNSIGNED typename + { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); } + | UNSIGNED + { $$ = builtin_type_unsigned_int; } + | SIGNED_KEYWORD typename + { $$ = lookup_signed_typename (TYPE_NAME($2.type)); } + | SIGNED_KEYWORD + { $$ = builtin_type_int; } + | TEMPLATE name '<' type '>' + { $$ = lookup_template_type(copy_name($2), $4, + expression_context_block); + } + /* "const" and "volatile" are curently ignored. A type qualifier + after the type is handled in the ptype rule. I think these could + be too. */ + | CONST_KEYWORD typebase { $$ = $2; } + | VOLATILE_KEYWORD typebase { $$ = $2; } + ; + +typename: TYPENAME + | INT_KEYWORD + { + $$.stoken.ptr = "int"; + $$.stoken.length = 3; + $$.type = builtin_type_int; + } + | LONG + { + $$.stoken.ptr = "long"; + $$.stoken.length = 4; + $$.type = builtin_type_long; + } + | SHORT + { + $$.stoken.ptr = "short"; + $$.stoken.length = 5; + $$.type = builtin_type_short; + } + ; + +nonempty_typelist + : type + { $$ = (struct type **) malloc (sizeof (struct type *) * 2); + $$[0] = 1; /* Number of types in vector */ + $$[1] = $1; + } + | nonempty_typelist ',' type + { int len = sizeof (struct type *) * (++($1[0]) + 1); + $$ = (struct type **) realloc ((char *) $1, len); + $$[$$[0]] = $3; + } + ; + +name : NAME { $$ = $1.stoken; } + | BLOCKNAME { $$ = $1.stoken; } + | TYPENAME { $$ = $1.stoken; } + | NAME_OR_INT { $$ = $1.stoken; } + ; + +name_not_typename : NAME + | BLOCKNAME +/* These would be useful if name_not_typename was useful, but it is just + a fake for "variable", so these cause reduce/reduce conflicts because + the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable, + =exp) or just an exp. If name_not_typename was ever used in an lvalue + context where only a name could occur, this might be useful. + | NAME_OR_INT + */ + ; + +%% + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (p, len, parsed_float, putithere) + register char *p; + register int len; + int parsed_float; + YYSTYPE *putithere; +{ + register LONGEST n = 0; + register LONGEST prevn = 0; + register int i = 0; + register int c; + register int base = input_radix; + int unsigned_p = 0; + int long_p = 0; + unsigned LONGEST high_bit; + struct type *signed_type; + struct type *unsigned_type; + + if (parsed_float) + { + /* It's a float since it contains a point or an exponent. */ + putithere->dval = atof (p); + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 0 */ + if (p[0] == '0') + switch (p[1]) + { + case 'x': + case 'X': + if (len >= 3) + { + p += 2; + base = 16; + len -= 2; + } + break; + + case 't': + case 'T': + case 'd': + case 'D': + if (len >= 3) + { + p += 2; + base = 10; + len -= 2; + } + break; + + default: + base = 8; + break; + } + + while (len-- > 0) + { + c = *p++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != 'l' && c != 'u') + n *= base; + if (c >= '0' && c <= '9') + n += i = c - '0'; + else + { + if (base > 10 && c >= 'a' && c <= 'f') + n += i = c - 'a' + 10; + else if (len == 0 && c == 'l') + long_p = 1; + else if (len == 0 && c == 'u') + unsigned_p = 1; + else + return ERROR; /* Char not a digit */ + } + if (i >= base) + return ERROR; /* Invalid digit in this base */ + + /* Portably test for overflow (only works for nonzero values, so make + a second check for zero). */ + if((prevn >= n) && n != 0) + unsigned_p=1; /* Try something unsigned */ + /* If range checking enabled, portably test for unsigned overflow. */ + if(RANGE_CHECK && n!=0) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + /* If the number is too big to be an int, or it's got an l suffix + then it's a long. Work out if this has to be a long by + shifting right and and seeing if anything remains, and the + target int size is different to the target long size. + + In the expression below, we could have tested + (n >> TARGET_INT_BIT) + to see if it was zero, + but too many compilers warn about that, when ints and longs + are the same size. So we shift it twice, with fewer bits + each time, for the same result. */ + + if ( (TARGET_INT_BIT != TARGET_LONG_BIT + && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */ + || long_p) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); + unsigned_type = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + + putithere->typed_val.val = n; + + /* If the high bit of the worked out type is set then this number + has to be unsigned. */ + + if (unsigned_p || (n & high_bit)) + { + putithere->typed_val.type = unsigned_type; + } + else + { + putithere->typed_val.type = signed_type; + } + + return INT; +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static const struct token tokentab3[] = + { + {">>=", ASSIGN_MODIFY, BINOP_RSH}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH} + }; + +static const struct token tokentab2[] = + { + {"+=", ASSIGN_MODIFY, BINOP_ADD}, + {"-=", ASSIGN_MODIFY, BINOP_SUB}, + {"*=", ASSIGN_MODIFY, BINOP_MUL}, + {"/=", ASSIGN_MODIFY, BINOP_DIV}, + {"%=", ASSIGN_MODIFY, BINOP_REM}, + {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR}, + {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND}, + {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR}, + {"++", INCREMENT, BINOP_END}, + {"--", DECREMENT, BINOP_END}, + {"->", ARROW, BINOP_END}, + {"&&", ANDAND, BINOP_END}, + {"||", OROR, BINOP_END}, + {"::", COLONCOLON, BINOP_END}, + {"<<", LSH, BINOP_END}, + {">>", RSH, BINOP_END}, + {"==", EQUAL, BINOP_END}, + {"!=", NOTEQUAL, BINOP_END}, + {"<=", LEQ, BINOP_END}, + {">=", GEQ, BINOP_END} + }; + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + int c; + int namelen; + unsigned int i; + char *tokstart; + char *tokptr; + int tempbufindex; + static char *tempbuf; + static int tempbufsize; + + retry: + + tokstart = lexptr; + /* See if it is a special token of length 3. */ + for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) + if (STREQN (tokstart, tokentab3[i].operator, 3)) + { + lexptr += 3; + yylval.opcode = tokentab3[i].opcode; + return tokentab3[i].token; + } + + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (STREQN (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + /* We either have a character constant ('0' or '\177' for example) + or we have a quoted symbol reference ('foo(int,int)' in C++ + for example). */ + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + + yylval.typed_val.val = c; + yylval.typed_val.type = builtin_type_char; + + c = *lexptr++; + if (c != '\'') + { + namelen = skip_quoted (tokstart) - tokstart; + if (namelen > 2) + { + lexptr = tokstart + namelen; + if (lexptr[-1] != '\'') + error ("Unmatched single quote."); + namelen -= 2; + tokstart++; + goto tryname; + } + error ("Invalid character constant."); + } + return INT; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] < '0' || lexptr[1] > '9') + goto symbol; /* Nope, must be a symbol. */ + /* FALL THRU into number case. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + /* It's a number. */ + int got_dot = 0, got_e = 0, toktype; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + for (;; ++p) + { + /* This test includes !hex because 'e' is a valid hex digit + and thus does not indicate a floating point number when + the radix is hex. */ + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + /* This test does not include !hex, because a '.' always indicates + a decimal floating point number regardless of the radix. */ + else if (!got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + memcpy (err_copy, tokstart, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + case '+': + case '-': + case '*': + case '/': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + + case '"': + + /* Build the gdb internal form of the input string in tempbuf, + translating any standard C escape forms seen. Note that the + buffer is null byte terminated *only* for the convenience of + debugging gdb itself and printing the buffer contents when + the buffer contains no embedded nulls. Gdb does not depend + upon the buffer being null byte terminated, it uses the length + string instead. This allows gdb to handle C strings (as well + as strings in other languages) with embedded null bytes */ + + tokptr = ++tokstart; + tempbufindex = 0; + + do { + /* Grow the static temp buffer if necessary, including allocating + the first one on demand. */ + if (tempbufindex + 1 >= tempbufsize) + { + tempbuf = (char *) realloc (tempbuf, tempbufsize += 64); + } + switch (*tokptr) + { + case '\0': + case '"': + /* Do nothing, loop will terminate. */ + break; + case '\\': + tokptr++; + c = parse_escape (&tokptr); + if (c == -1) + { + continue; + } + tempbuf[tempbufindex++] = c; + break; + default: + tempbuf[tempbufindex++] = *tokptr++; + break; + } + } while ((*tokptr != '"') && (*tokptr != '\0')); + if (*tokptr++ != '"') + { + error ("Unterminated string in expression."); + } + tempbuf[tempbufindex] = '\0'; /* See note above */ + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = tokptr; + return (STRING); + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + tryname: + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && STREQN (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < num_std_regs; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && STREQN (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + /* Catch specific keywords. Should be done with a data structure. */ + switch (namelen) + { + case 8: + if (STREQN (tokstart, "unsigned", 8)) + return UNSIGNED; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "template", 8)) + return TEMPLATE; + if (STREQN (tokstart, "volatile", 8)) + return VOLATILE_KEYWORD; + break; + case 6: + if (STREQN (tokstart, "struct", 6)) + return STRUCT; + if (STREQN (tokstart, "signed", 6)) + return SIGNED_KEYWORD; + if (STREQN (tokstart, "sizeof", 6)) + return SIZEOF; + break; + case 5: + if (current_language->la_language == language_cplus + && STREQN (tokstart, "class", 5)) + return CLASS; + if (STREQN (tokstart, "union", 5)) + return UNION; + if (STREQN (tokstart, "short", 5)) + return SHORT; + if (STREQN (tokstart, "const", 5)) + return CONST_KEYWORD; + break; + case 4: + if (STREQN (tokstart, "enum", 4)) + return ENUM; + if (STREQN (tokstart, "long", 4)) + return LONG; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "this", 4)) + { + static const char this_name[] = + { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; + + if (lookup_symbol (this_name, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL)) + return THIS; + } + break; + case 3: + if (STREQN (tokstart, "int", 3)) + return INT_KEYWORD; + break; + default: + break; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1); + return VARIABLE; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions or symtabs. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + int is_a_field_of_this = 0; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, + current_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) NULL, + (struct symtab **) NULL); + if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) || + lookup_partial_symtab (tmp)) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return BLOCKNAME; + } + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + char *p; + char *namestart; + struct symbol *best_sym; + + /* Look ahead to detect nested types. This probably should be + done in the grammar, but trying seemed to introduce a lot + of shift/reduce and reduce/reduce conflicts. It's possible + that it could be done, though. Or perhaps a non-grammar, but + less ad hoc, approach would work well. */ + + /* Since we do not currently have any way of distinguishing + a nested type from a non-nested one (the stabs don't tell + us whether a type is nested), we just ignore the + containing type. */ + + p = lexptr; + best_sym = sym; + while (1) + { + /* Skip whitespace. */ + while (*p == ' ' || *p == '\t' || *p == '\n') + ++p; + if (*p == ':' && p[1] == ':') + { + /* Skip the `::'. */ + p += 2; + /* Skip whitespace. */ + while (*p == ' ' || *p == '\t' || *p == '\n') + ++p; + namestart = p; + while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9') + || (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z')) + ++p; + if (p != namestart) + { + struct symbol *cur_sym; + /* As big as the whole rest of the expression, which is + at least big enough. */ + char *tmp = alloca (strlen (namestart)); + + memcpy (tmp, namestart, p - namestart); + tmp[p - namestart] = '\0'; + cur_sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (cur_sym) + { + if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF) + { + best_sym = cur_sym; + lexptr = p; + } + else + break; + } + else + break; + } + else + break; + } + else + break; + } + + yylval.tsym.type = SYMBOL_TYPE (best_sym); + return TYPENAME; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* Input names that aren't symbols but ARE valid hex numbers, + when the input radix permits them, can be names or numbers + depending on the parse. Note we support radixes > 16 here. */ + if (!sym && + ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || + (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) + { + YYSTYPE newlval; /* Its value is ignored. */ + hextype = parse_number (tokstart, namelen, 0, &newlval); + if (hextype == INT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_INT; + } + } + + /* Any other kind of symbol */ + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME; + } +} + +void +yyerror (msg) + char *msg; +{ + error (msg ? msg : "Invalid syntax in expression."); +} diff --git a/gnu/usr.bin/gdb/gdb/c-lang.c b/gnu/usr.bin/gdb/gdb/c-lang.c new file mode 100644 index 00000000000..ea0795915f5 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/c-lang.c @@ -0,0 +1,447 @@ +/* C language support routines for GDB, the GNU debugger. + Copyright 1992, 1993 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "c-lang.h" + +/* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing + characters and strings is language specific. */ + +static void +emit_char (c, stream, quoter) + register int c; + FILE *stream; + int quoter; +{ + + c &= 0xFF; /* Avoid sign bit follies */ + + if (PRINT_LITERAL_FORM (c)) + { + if (c == '\\' || c == quoter) + { + fputs_filtered ("\\", stream); + } + fprintf_filtered (stream, "%c", c); + } + else + { + switch (c) + { + case '\n': + fputs_filtered ("\\n", stream); + break; + case '\b': + fputs_filtered ("\\b", stream); + break; + case '\t': + fputs_filtered ("\\t", stream); + break; + case '\f': + fputs_filtered ("\\f", stream); + break; + case '\r': + fputs_filtered ("\\r", stream); + break; + case '\033': + fputs_filtered ("\\e", stream); + break; + case '\007': + fputs_filtered ("\\a", stream); + break; + default: + fprintf_filtered (stream, "\\%.3o", (unsigned int) c); + break; + } + } +} + +static void +c_printchar (c, stream) + int c; + FILE *stream; +{ + fputs_filtered ("'", stream); + emit_char (c, stream, '\''); + fputs_filtered ("'", stream); +} + +/* Print the character string STRING, printing at most LENGTH characters. + Printing stops early if the number hits print_max; repeat counts + are printed as appropriate. Print ellipses at the end if we + had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */ + +static void +c_printstr (stream, string, length, force_ellipses) + FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; + extern int inspect_it; + extern int repeat_count_threshold; + extern int print_max; + + /* If the string was not truncated due to `set print elements', and + the last byte of it is a null, we don't print that, in traditional C + style. */ + if ((!force_ellipses) && length > 0 && string[length-1] == '\0') + length--; + + if (length == 0) + { + fputs_filtered ("\"\"", stdout); + return; + } + + for (i = 0; i < length && things_printed < print_max; ++i) + { + /* Position of the character we are examining + to see whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + QUIT; + + if (need_comma) + { + fputs_filtered (", ", stream); + need_comma = 0; + } + + rep1 = i + 1; + reps = 1; + while (rep1 < length && string[rep1] == string[i]) + { + ++rep1; + ++reps; + } + + if (reps > repeat_count_threshold) + { + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\", ", stream); + else + fputs_filtered ("\", ", stream); + in_quotes = 0; + } + c_printchar (string[i], stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_comma = 1; + } + else + { + if (!in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + in_quotes = 1; + } + emit_char (string[i], stream, '"'); + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + } + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +/* Create a fundamental C type using default reasonable for the current + target machine. + + Some object/debugging file formats (DWARF version 1, COFF, etc) do not + define fundamental types such as "int" or "double". Others (stabs or + DWARF version 2, etc) do define fundamental types. For the formats which + don't provide fundamental types, gdb can create such types using this + function. + + FIXME: Some compilers distinguish explicitly signed integral types + (signed short, signed int, signed long) from "regular" integral types + (short, int, long) in the debugging information. There is some dis- + agreement as to how useful this feature is. In particular, gcc does + not support this. Also, only some debugging formats allow the + distinction to be passed on to a debugger. For now, we always just + use "short", "int", or "long" as the type name, for both the implicit + and explicitly signed types. This also makes life easier for the + gdb test suite since we don't have to account for the differences + in output depending upon what the compiler and debugging format + support. We will probably have to re-examine the issue when gdb + starts taking it's fundamental type information directly from the + debugging information supplied by the compiler. fnf@cygnus.com */ + +static struct type * +c_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "", objfile); + warning ("internal error: no C/C++ fundamental type %d", typeid); + break; + case FT_VOID: + type = init_type (TYPE_CODE_VOID, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "void", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "char", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "signed char", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned char", objfile); + break; + case FT_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); + break; + case FT_SIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "short", objfile); /* FIXME-fnf */ + break; + case FT_UNSIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned short", objfile); + break; + case FT_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", objfile); + break; + case FT_SIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "int", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", objfile); + break; + case FT_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); + break; + case FT_SIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "long", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", objfile); + break; + case FT_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long long", objfile); + break; + case FT_SIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "signed long long", objfile); + break; + case FT_UNSIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "float", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "double", objfile); + break; + case FT_EXT_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long double", objfile); + break; + } + return (type); +} + + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +static const struct op_print c_op_print_tab[] = + { + {",", BINOP_COMMA, PREC_COMMA, 0}, + {"=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0}, + {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0}, + {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0}, + {"==", BINOP_EQUAL, PREC_EQUAL, 0}, + {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {">>", BINOP_RSH, PREC_SHIFT, 0}, + {"<<", BINOP_LSH, PREC_SHIFT, 0}, + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"%", BINOP_REM, PREC_MUL, 0}, + {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0}, + {"*", UNOP_IND, PREC_PREFIX, 0}, + {"&", UNOP_ADDR, PREC_PREFIX, 0}, + {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0}, + {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0}, + {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0}, + /* C++ */ + {"::", BINOP_SCOPE, PREC_PREFIX, 0}, + {NULL, 0, 0, 0} +}; + +struct type ** const (c_builtin_types[]) = +{ + &builtin_type_int, + &builtin_type_long, + &builtin_type_short, + &builtin_type_char, + &builtin_type_float, + &builtin_type_double, + &builtin_type_void, + &builtin_type_long_long, + &builtin_type_signed_char, + &builtin_type_unsigned_char, + &builtin_type_unsigned_short, + &builtin_type_unsigned_int, + &builtin_type_unsigned_long, + &builtin_type_unsigned_long_long, + &builtin_type_long_double, + &builtin_type_complex, + &builtin_type_double_complex, + 0 +}; + +const struct language_defn c_language_defn = { + "c", /* Language name */ + language_c, + c_builtin_types, + range_check_off, + type_check_off, + c_parse, + c_error, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + c_create_fundamental_type, /* Create fundamental type in this language */ + c_print_type, /* Print a type using appropriate syntax */ + c_val_print, /* Print a value using appropriate syntax */ + &BUILTIN_TYPE_LONGEST, /* longest signed integral type */ + &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */ + &builtin_type_double, /* longest floating point type */ /*FIXME*/ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + c_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +const struct language_defn cplus_language_defn = { + "c++", /* Language name */ + language_cplus, + c_builtin_types, + range_check_off, + type_check_off, + c_parse, + c_error, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + c_create_fundamental_type, /* Create fundamental type in this language */ + c_print_type, /* Print a type using appropriate syntax */ + c_val_print, /* Print a value using appropriate syntax */ + &BUILTIN_TYPE_LONGEST, /* longest signed integral type */ + &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */ + &builtin_type_double, /* longest floating point type */ /*FIXME*/ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + c_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +void +_initialize_c_language () +{ + add_language (&c_language_defn); + add_language (&cplus_language_defn); +} diff --git a/gnu/usr.bin/gdb/gdb/c-lang.h b/gnu/usr.bin/gdb/gdb/c-lang.h new file mode 100644 index 00000000000..4c343a9a5aa --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/c-lang.h @@ -0,0 +1,31 @@ +/* C language support definitions for GDB, the GNU debugger. + Copyright 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. */ + +extern int +c_parse PARAMS ((void)); /* Defined in c-exp.y */ + +extern void +c_error PARAMS ((char *)); /* Defined in c-exp.y */ + +extern void /* Defined in c-typeprint.c */ +c_print_type PARAMS ((struct type *, char *, FILE *, int, int)); + +extern int +c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, + int, enum val_prettyprint)); diff --git a/gnu/usr.bin/gdb/gdb/c-typeprint.c b/gnu/usr.bin/gdb/gdb/c-typeprint.c new file mode 100644 index 00000000000..fa4035b00ac --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/c-typeprint.c @@ -0,0 +1,797 @@ +/* Support for printing C and C++ types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "c-lang.h" +#include "typeprint.h" + +#include +#include + +extern int demangle; /* whether to print C++ syms raw or source-form */ + +static void +c_type_print_args PARAMS ((struct type *, FILE *)); + +static void +c_type_print_varspec_suffix PARAMS ((struct type *, FILE *, int, int, int)); + +static void +cp_type_print_derivation_info PARAMS ((FILE *, struct type *)); + +void +c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int)); + +void +c_type_print_base PARAMS ((struct type *, FILE *, int, int)); + + +/* Print a description of a type in the format of a + typedef for the current language. + NEW is the new name for a type TYPE. */ + +void +c_typedef_print (type, new, stream) + struct type *type; + struct symbol *new; + FILE *stream; +{ + switch (current_language->la_language) + { +#ifdef _LANG_c + case language_c: + case language_cplus: + fprintf_filtered(stream, "typedef "); + type_print(type,"",stream,0); + if(TYPE_NAME ((SYMBOL_TYPE (new))) == 0 + || !STREQ (TYPE_NAME ((SYMBOL_TYPE (new))), SYMBOL_NAME (new))) + fprintf_filtered(stream, " %s", SYMBOL_SOURCE_NAME(new)); + break; +#endif +#ifdef _LANG_m2 + case language_m2: + fprintf_filtered(stream, "TYPE "); + if(!TYPE_NAME(SYMBOL_TYPE(new)) || + !STREQ (TYPE_NAME(SYMBOL_TYPE(new)), SYMBOL_NAME(new))) + fprintf_filtered(stream, "%s = ", SYMBOL_SOURCE_NAME(new)); + else + fprintf_filtered(stream, " = "); + type_print(type,"",stream,0); + break; +#endif +#ifdef _LANG_chill + case language_chill: + error ("Missing Chill support in function c_typedef_print."); /*FIXME*/ +#endif + default: + error("Language not supported."); + } + fprintf_filtered(stream, ";\n"); +} + + +/* LEVEL is the depth to indent lines by. */ + +void +c_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + FILE *stream; + int show; + int level; +{ + register enum type_code code; + int demangled_args; + + c_type_print_base (type, stream, show, level); + code = TYPE_CODE (type); + if ((varstring != NULL && *varstring != '\0') + || + /* Need a space if going to print stars or brackets; + but not if we will print just a type name. */ + ((show > 0 || TYPE_NAME (type) == 0) + && + (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC + || code == TYPE_CODE_METHOD + || code == TYPE_CODE_ARRAY + || code == TYPE_CODE_MEMBER + || code == TYPE_CODE_REF))) + fputs_filtered (" ", stream); + c_type_print_varspec_prefix (type, stream, show, 0); + + fputs_filtered (varstring, stream); + + /* For demangled function names, we have the arglist as part of the name, + so don't print an additional pair of ()'s */ + + demangled_args = varstring[strlen(varstring) - 1] == ')'; + c_type_print_varspec_suffix (type, stream, show, 0, demangled_args); + +} + +/* Print the C++ method arguments ARGS to the file STREAM. */ + +void +cp_type_print_method_args (args, prefix, varstring, staticp, stream) + struct type **args; + char *prefix; + char *varstring; + int staticp; + FILE *stream; +{ + int i; + + fprintf_symbol_filtered (stream, prefix, language_cplus, DMGL_ANSI); + fprintf_symbol_filtered (stream, varstring, language_cplus, DMGL_ANSI); + fputs_filtered (" (", stream); + if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID) + { + i = !staticp; /* skip the class variable */ + while (1) + { + type_print (args[i++], "", stream, 0); + if (!args[i]) + { + fprintf_filtered (stream, " ..."); + break; + } + else if (args[i]->code != TYPE_CODE_VOID) + { + fprintf_filtered (stream, ", "); + } + else break; + } + } + fprintf_filtered (stream, ")"); +} + +/* If TYPE is a derived type, then print out derivation information. + Print only the actual base classes of this type, not the base classes + of the base classes. I.E. for the derivation hierarchy: + + class A { int a; }; + class B : public A {int b; }; + class C : public B {int c; }; + + Print the type of class C as: + + class C : public B { + int c; + } + + Not as the following (like gdb used to), which is not legal C++ syntax for + derived types and may be confused with the multiple inheritance form: + + class C : public B : public A { + int c; + } + + In general, gdb should try to print the types as closely as possible to + the form that they appear in the source code. */ + +static void +cp_type_print_derivation_info (stream, type) + FILE *stream; + struct type *type; +{ + char *name; + int i; + + for (i = 0; i < TYPE_N_BASECLASSES (type); i++) + { + fputs_filtered (i == 0 ? ": " : ", ", stream); + fprintf_filtered (stream, "%s%s ", + BASETYPE_VIA_PUBLIC (type, i) ? "public" : "private", + BASETYPE_VIA_VIRTUAL(type, i) ? " virtual" : ""); + name = type_name_no_tag (TYPE_BASECLASS (type, i)); + fprintf_filtered (stream, "%s", name ? name : "(null)"); + } + if (i > 0) + { + fputs_filtered (" ", stream); + } +} + +/* Print any asterisks or open-parentheses needed before the + variable name (to describe its type). + + On outermost call, pass 0 for PASSED_A_PTR. + On outermost call, SHOW > 0 means should ignore + any typename for TYPE and show its details. + SHOW is always zero on recursive calls. */ + +void +c_type_print_varspec_prefix (type, stream, show, passed_a_ptr) + struct type *type; + FILE *stream; + int show; + int passed_a_ptr; +{ + char *name; + if (type == 0) + return; + + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + fprintf_filtered (stream, "*"); + break; + + case TYPE_CODE_MEMBER: + if (passed_a_ptr) + fprintf_filtered (stream, "("); + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + fprintf_filtered (stream, " "); + name = type_name_no_tag (TYPE_DOMAIN_TYPE (type)); + if (name) + fputs_filtered (name, stream); + else + c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr); + fprintf_filtered (stream, "::"); + break; + + case TYPE_CODE_METHOD: + if (passed_a_ptr) + fprintf (stream, "("); + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + { + fprintf_filtered (stream, " "); + c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr); + fprintf_filtered (stream, "::"); + } + break; + + case TYPE_CODE_REF: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + fprintf_filtered (stream, "&"); + break; + + case TYPE_CODE_FUNC: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf_filtered (stream, "("); + break; + + case TYPE_CODE_ARRAY: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf_filtered (stream, "("); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + /* These types need no prefix. They are listed here so that + gcc -Wall will reveal any types that haven't been handled. */ + break; + } +} + +static void +c_type_print_args (type, stream) + struct type *type; + FILE *stream; +{ + int i; + struct type **args; + + fprintf_filtered (stream, "("); + args = TYPE_ARG_TYPES (type); + if (args != NULL) + { + if (args[1] == NULL) + { + fprintf_filtered (stream, "..."); + } + else + { + for (i = 1; + args[i] != NULL && args[i]->code != TYPE_CODE_VOID; + i++) + { + c_print_type (args[i], "", stream, -1, 0); + if (args[i+1] == NULL) + { + fprintf_filtered (stream, "..."); + } + else if (args[i+1]->code != TYPE_CODE_VOID) + { + fprintf_filtered (stream, ","); + wrap_here (" "); + } + } + } + } + fprintf_filtered (stream, ")"); +} + +/* Print any array sizes, function arguments or close parentheses + needed after the variable name (to describe its type). + Args work like c_type_print_varspec_prefix. */ + +static void +c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args) + struct type *type; + FILE *stream; + int show; + int passed_a_ptr; + int demangled_args; +{ + if (type == 0) + return; + + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + + fprintf_filtered (stream, "["); + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + fprintf_filtered (stream, "%d", + (TYPE_LENGTH (type) + / TYPE_LENGTH (TYPE_TARGET_TYPE (type)))); + fprintf_filtered (stream, "]"); + + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + break; + + case TYPE_CODE_MEMBER: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + break; + + case TYPE_CODE_METHOD: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + if (passed_a_ptr) + { + c_type_print_args (type, stream); + } + break; + + case TYPE_CODE_PTR: + case TYPE_CODE_REF: + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1, 0); + break; + + case TYPE_CODE_FUNC: + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr, 0); + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + if (!demangled_args) + fprintf_filtered (stream, "()"); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + /* These types do not need a suffix. They are listed so that + gcc -Wall will report types that may not have been considered. */ + break; + } +} + +/* Print the name of the type (or the ultimate pointer target, + function value or array element), or the description of a + structure or union. + + SHOW positive means print details about the type (e.g. enum values), + and print structure elements passing SHOW - 1 for show. + SHOW zero means just print the type name or struct tag if there is one. + If there is no name, print something sensible but concise like + "struct {...}". + SHOW negative means the same things as SHOW zero. The difference is that + zero is used for printing structure elements and -1 is used for the + "whatis" command. But I don't see any need to distinguish. + + LEVEL is the number of spaces to indent by. + We increase it for some recursive calls. */ + +void +c_type_print_base (type, stream, show, level) + struct type *type; + FILE *stream; + int show; + int level; +{ + register int i; + register int len; + register int lastval; + char *mangled_name; + char *demangled_name; + enum {s_none, s_public, s_private, s_protected} section_type; + QUIT; + + wrap_here (" "); + if (type == NULL) + { + fputs_filtered ("", stream); + return; + } + + /* When SHOW is zero or less, and there is a valid type name, then always + just print the type name directly from the type. */ + /* If we have "typedef struct foo {. . .} bar;" do we want to print it + as "struct foo" or as "bar"? Pick the latter, because C++ folk tend + to expect things like "class5 *foo" rather than "struct class5 *foo". */ + + if (show <= 0 + && TYPE_NAME (type) != NULL) + { + fputs_filtered (TYPE_NAME (type), stream); + return; + } + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + case TYPE_CODE_PTR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_REF: + case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: + c_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_STRUCT: + if (HAVE_CPLUS_STRUCT (type)) + { + fprintf_filtered (stream, "class "); + } + else + { + fprintf_filtered (stream, "struct "); + } + goto struct_union; + + case TYPE_CODE_UNION: + fprintf_filtered (stream, "union "); + + struct_union: + if (TYPE_TAG_NAME (type) != NULL) + { + fputs_filtered (TYPE_TAG_NAME (type), stream); + if (show > 0) + fputs_filtered (" ", stream); + } + wrap_here (" "); + if (show <= 0) + { + /* If we just printed a tag name, no need to print anything else. */ + if (TYPE_TAG_NAME (type) == NULL) + fprintf_filtered (stream, "{...}"); + } + else if (show > 0) + { + check_stub_type (type); + + cp_type_print_derivation_info (stream, type); + + fprintf_filtered (stream, "{\n"); + if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0)) + { + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + fprintfi_filtered (level + 4, stream, "\n"); + else + fprintfi_filtered (level + 4, stream, "\n"); + } + + /* Start off with no specific section type, so we can print + one for the first field we find, and use that section type + thereafter until we find another type. */ + + section_type = s_none; + + /* If there is a base class for this type, + do not print the field that it occupies. */ + + len = TYPE_NFIELDS (type); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + QUIT; + /* Don't print out virtual function table. */ + if ((TYPE_FIELD_NAME (type, i))[5] == CPLUS_MARKER && + !strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5)) + continue; + + /* If this is a C++ class we can print the various C++ section + labels. */ + + if (HAVE_CPLUS_STRUCT (type)) + { + if (TYPE_FIELD_PROTECTED (type, i)) + { + if (section_type != s_protected) + { + section_type = s_protected; + fprintfi_filtered (level + 2, stream, + "protected:\n"); + } + } + else if (TYPE_FIELD_PRIVATE (type, i)) + { + if (section_type != s_private) + { + section_type = s_private; + fprintfi_filtered (level + 2, stream, "private:\n"); + } + } + else + { + if (section_type != s_public) + { + section_type = s_public; + fprintfi_filtered (level + 2, stream, "public:\n"); + } + } + } + + print_spaces_filtered (level + 4, stream); + if (TYPE_FIELD_STATIC (type, i)) + { + fprintf_filtered (stream, "static "); + } + c_print_type (TYPE_FIELD_TYPE (type, i), + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 4); + if (!TYPE_FIELD_STATIC (type, i) + && TYPE_FIELD_PACKED (type, i)) + { + /* It is a bitfield. This code does not attempt + to look at the bitpos and reconstruct filler, + unnamed fields. This would lead to misleading + results if the compiler does not put out fields + for such things (I don't know what it does). */ + fprintf_filtered (stream, " : %d", + TYPE_FIELD_BITSIZE (type, i)); + } + fprintf_filtered (stream, ";\n"); + } + + /* If there are both fields and methods, put a space between. */ + len = TYPE_NFN_FIELDS (type); + if (len && section_type != s_none) + fprintf_filtered (stream, "\n"); + + /* C++: print out the methods */ + + for (i = 0; i < len; i++) + { + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i); + char *method_name = TYPE_FN_FIELDLIST_NAME (type, i); + char *name = type_name_no_tag (type); + int is_constructor = name && STREQ(method_name, name); + for (j = 0; j < len2; j++) + { + QUIT; + if (TYPE_FN_FIELD_PROTECTED (f, j)) + { + if (section_type != s_protected) + { + section_type = s_protected; + fprintfi_filtered (level + 2, stream, + "protected:\n"); + } + } + else if (TYPE_FN_FIELD_PRIVATE (f, j)) + { + if (section_type != s_private) + { + section_type = s_private; + fprintfi_filtered (level + 2, stream, "private:\n"); + } + } + else + { + if (section_type != s_public) + { + section_type = s_public; + fprintfi_filtered (level + 2, stream, "public:\n"); + } + } + + print_spaces_filtered (level + 4, stream); + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + fprintf_filtered (stream, "virtual "); + else if (TYPE_FN_FIELD_STATIC_P (f, j)) + fprintf_filtered (stream, "static "); + if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) == 0) + { + /* Keep GDB from crashing here. */ + fprintf (stream, " %s;\n", + TYPE_FN_FIELD_PHYSNAME (f, j)); + break; + } + else if (!is_constructor) + { + type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), + "", stream, 0); + fputs_filtered (" ", stream); + } + if (TYPE_FN_FIELD_STUB (f, j)) + { + /* Build something we can demangle. */ + mangled_name = gdb_mangle_name (type, i, j); + demangled_name = + cplus_demangle (mangled_name, + DMGL_ANSI | DMGL_PARAMS); + if (demangled_name == NULL) + fprintf_filtered (stream, "", + mangled_name); + else + { + char *demangled_no_class = + strchr (demangled_name, ':'); + + if (demangled_no_class == NULL) + demangled_no_class = demangled_name; + else + { + if (*++demangled_no_class == ':') + ++demangled_no_class; + } + fputs_filtered (demangled_no_class, stream); + free (demangled_name); + } + free (mangled_name); + } + else if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' + && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER) + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, + "~", method_name, 0, stream); + else + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "", + method_name, + TYPE_FN_FIELD_STATIC_P (f, j), + stream); + + fprintf_filtered (stream, ";\n"); + } + } + + fprintfi_filtered (level, stream, "}"); + } + break; + + case TYPE_CODE_ENUM: + fprintf_filtered (stream, "enum "); + if (TYPE_TAG_NAME (type) != NULL) + { + fputs_filtered (TYPE_TAG_NAME (type), stream); + if (show > 0) + fputs_filtered (" ", stream); + } + + wrap_here (" "); + if (show <= 0) + { + /* If we just printed a tag name, no need to print anything else. */ + if (TYPE_TAG_NAME (type) == NULL) + fprintf_filtered (stream, "{...}"); + } + else if (show > 0) + { + fprintf_filtered (stream, "{"); + len = TYPE_NFIELDS (type); + lastval = 0; + for (i = 0; i < len; i++) + { + QUIT; + if (i) fprintf_filtered (stream, ", "); + wrap_here (" "); + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + if (lastval != TYPE_FIELD_BITPOS (type, i)) + { + fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i)); + lastval = TYPE_FIELD_BITPOS (type, i); + } + lastval++; + } + fprintf_filtered (stream, "}"); + } + break; + + case TYPE_CODE_VOID: + fprintf_filtered (stream, "void"); + break; + + case TYPE_CODE_UNDEF: + fprintf_filtered (stream, "struct "); + break; + + case TYPE_CODE_ERROR: + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_RANGE: + /* This should not occur */ + fprintf_filtered (stream, ""); + break; + + default: + /* Handle types not explicitly handled by the other cases, + such as fundamental types. For these, just print whatever + the type name is, as recorded in the type itself. If there + is no type name, then complain. */ + if (TYPE_NAME (type) != NULL) + { + fputs_filtered (TYPE_NAME (type), stream); + } + else + { + /* At least for dump_symtab, it is important that this not be + an error (). */ + fprintf_filtered (stream, "", + TYPE_CODE (type)); + } + break; + } +} + diff --git a/gnu/usr.bin/gdb/gdb/c-valprint.c b/gnu/usr.bin/gdb/gdb/c-valprint.c new file mode 100644 index 00000000000..bcf0a287673 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/c-valprint.c @@ -0,0 +1,416 @@ +/* Support for printing C values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "demangle.h" +#include "valprint.h" +#include "language.h" + +/* BEGIN-FIXME */ + +extern int vtblprint; /* Controls printing of vtbl's */ +extern int demangle; /* whether to print C++ syms raw or src-form */ + +extern void +cp_print_class_member PARAMS ((char *, struct type *, FILE *, char *)); + +extern void +cp_print_class_method PARAMS ((char *, struct type *, FILE *)); + +extern void +cp_print_value_fields PARAMS ((struct type *, char *, FILE *, int, int, + enum val_prettyprint, struct type **)); + +extern int +cp_is_vtbl_ptr_type PARAMS ((struct type *)); + +extern int +cp_is_vtbl_member PARAMS ((struct type *)); + +/* END-FIXME */ + + +/* BEGIN-FIXME: Hooks into c-typeprint.c */ + +extern void +c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int)); + +extern void +cp_type_print_method_args PARAMS ((struct type **, char *, char *, int, + FILE *)); +/* END-FIXME */ + + +extern struct obstack dont_print_obstack; + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter or 0 for natural format). The data at VALADDR is in + target byte order. + + If the data are a string pointer, returns the number of string characters + printed. + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. */ + +int +c_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + register unsigned int i = 0; /* Number of characters printed */ + unsigned len; + struct type *elttype; + unsigned eltlen; + LONGEST val; + CORE_ADDR addr; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + { + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + if (prettyprint_arrays) + { + print_spaces_filtered (2 + 2 * recurse, stream); + } + /* For an array of chars, print with string syntax. */ + if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT + && (format == 0 || format == 's')) + { + LA_PRINT_STRING (stream, valaddr, len, 0); + i = len; + } + else + { + fprintf_filtered (stream, "{"); + /* If this is a virtual function table, print the 0th + entry specially, and the rest of the members normally. */ + if (cp_is_vtbl_ptr_type (elttype)) + { + i = 1; + fprintf_filtered (stream, "%d vtable entries", len - 1); + } + else + { + i = 0; + } + val_print_array_elements (type, valaddr, address, stream, + format, deref_ref, recurse, pretty, i); + fprintf_filtered (stream, "}"); + } + break; + } + /* Array of unspecified length: treat like pointer to first elt. */ + addr = address; + goto print_unpacked_pointer; + + case TYPE_CODE_PTR: + if (format && format != 's') + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD) + { + cp_print_class_method (valaddr, type, stream); + } + else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER) + { + cp_print_class_member (valaddr, + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)), + stream, "&"); + } + else + { + addr = unpack_pointer (type, valaddr); + print_unpacked_pointer: + elttype = TYPE_TARGET_TYPE (type); + + if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) + { + /* Try to print what function it points to. */ + print_address_demangle (addr, stream, demangle); + /* Return value is irrelevant except for string pointers. */ + return (0); + } + + if (addressprint && format != 's') + { + fprintf_filtered (stream, "0x%lx", (unsigned long)addr); + } + + /* For a pointer to char or unsigned char, also print the string + pointed to, unless pointer is null. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_INT + && (format == 0 || format == 's') + && addr != 0) + { + i = val_print_string (addr, 0, stream); + } + else if (cp_is_vtbl_member(type)) + { + /* print vtbl's nicely */ + CORE_ADDR vt_address = unpack_pointer (type, valaddr); + + struct minimal_symbol *msymbol = + lookup_minimal_symbol_by_pc (vt_address); + if ((msymbol != NULL) && + (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) + { + fputs_filtered (" <", stream); + fputs_filtered (SYMBOL_SOURCE_NAME (msymbol), stream); + fputs_filtered (">", stream); + } + if (vtblprint) + { + value vt_val; + struct symbol *wsym = (struct symbol *)NULL; + struct type *wtype; + struct symtab *s; + struct block *block = (struct block *)NULL; + int is_this_fld; + + + wsym = lookup_symbol (SYMBOL_NAME(msymbol), block, + VAR_NAMESPACE, &is_this_fld, &s); + + if (wsym) + { + wtype = SYMBOL_TYPE(wsym); + } + else + { + wtype = TYPE_TARGET_TYPE(type); + } + vt_val = value_at (wtype, vt_address); + val_print (VALUE_TYPE (vt_val), VALUE_CONTENTS (vt_val), + VALUE_ADDRESS (vt_val), stream, format, + deref_ref, recurse + 1, pretty); + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + } + } + + /* Return number of characters printed, plus one for the + terminating null if we have "reached the end". */ + return (i + (print_max && i != print_max)); + } + break; + + case TYPE_CODE_MEMBER: + error ("not implemented: member type in c_val_print"); + break; + + case TYPE_CODE_REF: + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER) + { + cp_print_class_member (valaddr, + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)), + stream, ""); + break; + } + if (addressprint) + { + fprintf_filtered (stream, "@0x%lx", + unpack_long (builtin_type_int, valaddr)); + if (deref_ref) + fputs_filtered (": ", stream); + } + /* De-reference the reference. */ + if (deref_ref) + { + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF) + { + value deref_val = + value_at + (TYPE_TARGET_TYPE (type), + unpack_pointer (lookup_pointer_type (builtin_type_void), + valaddr)); + val_print (VALUE_TYPE (deref_val), + VALUE_CONTENTS (deref_val), + VALUE_ADDRESS (deref_val), stream, format, + deref_ref, recurse + 1, pretty); + } + else + fputs_filtered ("???", stream); + } + break; + + case TYPE_CODE_UNION: + if (recurse && !unionprint) + { + fprintf_filtered (stream, "{...}"); + break; + } + /* Fall through. */ + case TYPE_CODE_STRUCT: + if (vtblprint && cp_is_vtbl_ptr_type(type)) + { + /* Print the unmangled name if desired. */ + print_address_demangle(*((int *) (valaddr + /* FIXME bytesex */ + TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8)), + stream, demangle); + break; + } + cp_print_value_fields (type, valaddr, stream, format, recurse, pretty, + 0); + break; + + case TYPE_CODE_ENUM: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + len = TYPE_NFIELDS (type); + val = unpack_long (type, valaddr); + for (i = 0; i < len; i++) + { + QUIT; + if (val == TYPE_FIELD_BITPOS (type, i)) + { + break; + } + } + if (i < len) + { + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + } + else + { + print_longest (stream, 'd', 0, val); + } + break; + + case TYPE_CODE_FUNC: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + /* FIXME, we should consider, at least for ANSI C language, eliminating + the distinction made between FUNCs and POINTERs to FUNCs. */ + fprintf_filtered (stream, "{"); + type_print (type, "", stream, -1); + fprintf_filtered (stream, "} "); + /* Try to print what function it points to, and its address. */ + print_address_demangle (address, stream, demangle); + break; + + case TYPE_CODE_BOOL: + /* Do something at least vaguely reasonable, for example if the + language is set wrong. */ + + case TYPE_CODE_INT: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + val_print_type_code_int (type, valaddr, stream); + /* C and C++ has no single byte int type, char is used instead. + Since we don't know whether the value is really intended to + be used as an integer or a character, print the character + equivalent as well. */ + if (TYPE_LENGTH (type) == 1) + { + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), + stream); + } + } + break; + + case TYPE_CODE_CHAR: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + fprintf_filtered (stream, TYPE_UNSIGNED (type) ? "%u" : "%d", + unpack_long (type, valaddr)); + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), stream); + } + break; + + case TYPE_CODE_FLT: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + print_floating (valaddr, type, stream); + } + break; + + case TYPE_CODE_VOID: + fprintf_filtered (stream, "void"); + break; + + case TYPE_CODE_ERROR: + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_RANGE: + /* FIXME, we should not ever have to print one of these yet. */ + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_UNDEF: + /* This happens (without TYPE_FLAG_STUB set) on systems which don't use + dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar" + and no complete type for struct foo in that file. */ + fprintf_filtered (stream, ""); + break; + + default: + error ("Invalid C/C++ type code %d in symbol table.", TYPE_CODE (type)); + } + fflush (stream); + return (0); +} diff --git a/gnu/usr.bin/gdb/gdb/call-cmds.h b/gnu/usr.bin/gdb/gdb/call-cmds.h new file mode 100644 index 00000000000..9030d8495cf --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/call-cmds.h @@ -0,0 +1,28 @@ +/* Prototypes for GDB commands that are called internally by other functions. + Copyright 1992 Free Software Foundation, Inc. + +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. */ + +extern void +initialize_all_files PARAMS ((void)); + +extern void +exec_file_command PARAMS ((char *, int)); + +extern void +core_file_command PARAMS ((char *, int)); + +extern void +break_command PARAMS ((char *, int)); diff --git a/gnu/usr.bin/gdb/gdb/ch-exp.tab.c b/gnu/usr.bin/gdb/gdb/ch-exp.tab.c new file mode 100644 index 00000000000..7adab65439f --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ch-exp.tab.c @@ -0,0 +1,2854 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define yyparse ch_parse +#define yylex ch_lex +#define yyerror ch_error +#define yychar ch_char +#define yyval ch_val +#define yylval ch_lval +#define yydebug ch_debug +#define yynerrs ch_nerrs +#define yyerrflag ch_errflag +#define yyss ch_ss +#define yyssp ch_ssp +#define yyvs ch_vs +#define yyvsp ch_vsp +#define yylhs ch_lhs +#define yylen ch_len +#define yydefred ch_defred +#define yydgoto ch_dgoto +#define yysindex ch_sindex +#define yyrindex ch_rindex +#define yygindex ch_gindex +#define yytable ch_table +#define yycheck ch_check +#define yyname ch_name +#define yyrule ch_rule +#define YYPREFIX "ch_" +#line 55 "./ch-exp.y" + +#include "defs.h" +#include +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "ch-lang.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth chill_maxdepth +#define yyparse chill_parse +#define yylex chill_lex +#define yyerror chill_error +#define yylval chill_lval +#define yychar chill_char +#define yydebug chill_debug +#define yypact chill_pact +#define yyr1 chill_r1 +#define yyr2 chill_r2 +#define yydef chill_def +#define yychk chill_chk +#define yypgo chill_pgo +#define yyact chill_act +#define yyexca chill_exca +#define yyerrflag chill_errflag +#define yynerrs chill_nerrs +#define yyps chill_ps +#define yypv chill_pv +#define yys chill_s +#define yy_yys chill_yys +#define yystate chill_state +#define yytmp chill_tmp +#define yyv chill_v +#define yy_yyv chill_yyv +#define yyval chill_val +#define yylloc chill_lloc +#define yyreds chill_reds /* With YYDEBUG defined */ +#define yytoks chill_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#line 120 "./ch-exp.y" +typedef union + { + LONGEST lval; + unsigned LONGEST ulval; + struct { + LONGEST val; + struct type *type; + } typed_val; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } YYSTYPE; +#line 119 "y.tab.c" +#define FIXME_01 257 +#define FIXME_02 258 +#define FIXME_03 259 +#define FIXME_04 260 +#define FIXME_05 261 +#define FIXME_06 262 +#define FIXME_07 263 +#define FIXME_08 264 +#define FIXME_09 265 +#define FIXME_10 266 +#define FIXME_11 267 +#define FIXME_12 268 +#define FIXME_13 269 +#define FIXME_14 270 +#define FIXME_15 271 +#define FIXME_16 272 +#define FIXME_17 273 +#define FIXME_18 274 +#define FIXME_19 275 +#define FIXME_20 276 +#define FIXME_21 277 +#define FIXME_22 278 +#define FIXME_24 279 +#define FIXME_25 280 +#define FIXME_26 281 +#define FIXME_27 282 +#define FIXME_28 283 +#define FIXME_29 284 +#define FIXME_30 285 +#define INTEGER_LITERAL 286 +#define BOOLEAN_LITERAL 287 +#define CHARACTER_LITERAL 288 +#define FLOAT_LITERAL 289 +#define GENERAL_PROCEDURE_NAME 290 +#define LOCATION_NAME 291 +#define SET_LITERAL 292 +#define EMPTINESS_LITERAL 293 +#define CHARACTER_STRING_LITERAL 294 +#define BIT_STRING_LITERAL 295 +#define TYPENAME 296 +#define FIELD_NAME 297 +#define CASE 298 +#define OF 299 +#define ESAC 300 +#define LOGIOR 301 +#define ORIF 302 +#define LOGXOR 303 +#define LOGAND 304 +#define ANDIF 305 +#define NOTEQUAL 306 +#define GTR 307 +#define LEQ 308 +#define IN 309 +#define SLASH_SLASH 310 +#define MOD 311 +#define REM 312 +#define NOT 313 +#define POINTER 314 +#define RECEIVE 315 +#define UP 316 +#define IF 317 +#define THEN 318 +#define ELSE 319 +#define FI 320 +#define ELSIF 321 +#define ILLEGAL_TOKEN 322 +#define NUM 323 +#define PRED 324 +#define SUCC 325 +#define ABS 326 +#define CARD 327 +#define MAX_TOKEN 328 +#define MIN_TOKEN 329 +#define SIZE 330 +#define UPPER 331 +#define LOWER 332 +#define LENGTH 333 +#define GDB_REGNAME 334 +#define GDB_LAST 335 +#define GDB_VARIABLE 336 +#define GDB_ASSIGNMENT 337 +#define YYERRCODE 256 +short ch_lhs[] = { -1, + 0, 0, 20, 20, 21, 1, 1, 2, 2, 2, + 2, 2, 45, 45, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, + 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 8, 9, 9, 62, 10, 11, + 11, 12, 13, 14, 15, 17, 18, 19, 22, 22, + 22, 23, 23, 24, 25, 25, 26, 27, 28, 28, + 28, 28, 29, 29, 29, 30, 30, 30, 30, 30, + 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, + 32, 32, 33, 33, 33, 33, 34, 34, 34, 60, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 49, 49, 49, 49, 61, 50, 50, 51, + 44, 52, 53, 54, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 46, 47, 48, 55, 56, 57, 58, + 59, +}; +short ch_len[] = { 2, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 6, 6, 0, 5, 6, + 6, 2, 2, 1, 1, 1, 1, 3, 1, 1, + 1, 5, 9, 2, 2, 4, 1, 4, 1, 3, + 3, 3, 1, 3, 3, 1, 3, 3, 3, 3, + 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, + 3, 3, 1, 2, 2, 2, 2, 2, 1, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 1, 4, 4, 4, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, +}; +short ch_defred[] = { 0, + 5, 12, 44, 54, 56, 57, 125, 126, 127, 128, + 129, 36, 37, 38, 39, 35, 8, 40, 41, 42, + 43, 117, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 9, 11, 0, 0, 6, 0, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 55, + 27, 28, 0, 1, 4, 3, 61, 0, 0, 0, + 0, 0, 88, 93, 31, 32, 33, 34, 0, 0, + 60, 0, 138, 0, 30, 29, 94, 0, 95, 0, + 0, 141, 98, 0, 137, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 52, 7, + 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 53, 0, 58, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 122, 123, 124, 0, 0, 0, + 0, 0, 0, 118, 0, 0, 0, 120, 0, 100, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 89, 90, 91, 92, 130, + 131, 0, 0, 134, 136, 0, 0, 0, 140, 0, + 0, 139, 64, 0, 0, 0, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 0, 0, 0, 110, 111, + 112, 45, 0, 0, 0, 0, 13, 0, 0, 0, + 65, 0, 62, 0, 0, 0, 133, 0, 132, 0, + 135, 0, 0, 49, 0, 0, 67, 0, 0, 114, + 115, 116, 47, 46, 50, 51, 14, 0, 68, 66, + 0, 63, +}; +short ch_dgoto[] = { 44, + 85, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 137, 196, 238, 190, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 182, + 183, 230, 228, 80, 218, 186, 232, 187, 149, 155, + 159, 150, 151, 152, 96, 84, 193, 191, 93, 81, + 88, 188, +}; +short ch_sindex[] = { 457, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -262, 879, 879, 893, -215, 622, -258, 50, + 51, 52, 53, 56, 57, 58, 67, 72, 73, 75, + 0, 0, 0, 0, -221, 0, -293, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -261, 0, 0, 0, 0, -248, -275, -44, + -30, -33, 0, 0, 0, 0, 0, 0, 88, 91, + 0, 92, 0, -165, 0, 0, 0, 92, 0, 0, + -293, 0, 0, 94, 0, -181, 622, 622, 622, 622, + 622, 622, 622, 636, 622, 622, 622, 457, 0, 0, + 0, 797, 797, 797, 797, 797, 797, 797, 797, 797, + 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, + -233, -270, 0, -137, 0, -132, -272, 112, 118, 119, + 120, 121, 122, 128, 0, 0, 0, 129, 130, 132, + 141, 143, 92, 0, 144, 92, 146, 0, 149, 0, + -275, -275, -275, -44, -44, -30, -30, -30, -30, -30, + -30, -30, -33, -33, -33, 0, 0, 0, 0, 0, + 0, -39, 115, 0, 0, 126, -120, 622, 0, 106, + 142, 0, 0, -132, -258, -110, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 622, 622, 622, 0, 0, + 0, 0, -64, -61, -63, -64, 0, -34, -103, 622, + 0, -181, 0, 174, 181, -22, 0, 182, 0, 184, + 0, 192, 193, 0, 622, 622, 0, 177, -272, 0, + 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, + -55, 0, +}; +short ch_rindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 24, 0, 0, 0, 0, 506, 255, 191, + 145, 95, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 237, 0, 0, 0, 0, 0, 0, 0, 59, + 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 714, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -40, 0, 0, + 0, 0, 205, 0, 0, 206, 0, 0, 0, 0, + 567, 573, 577, 531, 554, 168, 180, 208, 231, 500, + 522, 545, 105, 133, 158, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, +}; +short ch_gindex[] = { 0, + 1230, 0, -23, 0, 0, 185, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 26, 148, + 0, 1162, 0, 31, 15, 22, 0, 0, -56, -104, + -45, -37, -92, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 0, 63, 0, 0, 0, 0, 154, + 0, 0, 0, 0, 71, 0, 87, 0, 0, 0, + 5, 0, +}; +#define YYTABLESIZE 1466 +short ch_table[] = { 30, + 30, 212, 91, 109, 82, 184, 234, 185, 127, 235, + 164, 165, 124, 128, 125, 121, 117, 119, 242, 83, + 110, 235, 95, 29, 12, 13, 14, 15, 115, 116, + 18, 19, 20, 21, 176, 177, 178, 179, 180, 181, + 30, 30, 30, 30, 30, 30, 194, 30, 195, 86, + 86, 86, 112, 113, 114, 161, 162, 163, 97, 30, + 30, 30, 30, 29, 29, 29, 29, 29, 29, 92, + 29, 166, 167, 168, 169, 170, 171, 172, 87, 89, + 91, 99, 29, 29, 29, 29, 173, 174, 175, 97, + 98, 99, 100, 30, 84, 101, 102, 103, 30, 97, + 97, 97, 97, 97, 85, 97, 104, 133, 153, 156, + 156, 105, 106, 133, 107, 108, 29, 97, 97, 97, + 97, 121, 99, 99, 99, 99, 99, 131, 99, 86, + 132, 28, 86, 134, 135, 84, 136, 84, 84, 84, + 99, 99, 99, 99, 76, 85, 189, 85, 85, 85, + 192, 97, 197, 84, 84, 84, 84, 87, 198, 199, + 200, 201, 202, 85, 85, 85, 85, 77, 203, 204, + 205, 206, 214, 86, 99, 86, 86, 86, 133, 78, + 207, 133, 208, 215, 209, 76, 210, 84, 76, 211, + 73, 86, 86, 86, 86, 216, 219, 85, 87, 220, + 87, 87, 87, 76, 76, 76, 76, 79, 77, 223, + 227, 77, 229, 231, 240, 236, 87, 87, 87, 87, + 78, 241, 243, 78, 244, 86, 77, 77, 77, 77, + 80, 73, 245, 246, 73, 249, 2, 76, 78, 78, + 78, 78, 251, 121, 252, 113, 119, 111, 79, 73, + 87, 79, 239, 250, 69, 160, 30, 248, 233, 157, + 77, 118, 120, 122, 123, 222, 79, 79, 79, 79, + 226, 80, 78, 30, 80, 0, 213, 129, 130, 126, + 221, 0, 0, 73, 0, 0, 0, 0, 0, 80, + 80, 80, 80, 0, 0, 69, 0, 30, 69, 0, + 79, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 69, 30, 0, 0, 0, 0, 0, + 29, 0, 0, 80, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, + 0, 0, 0, 0, 0, 30, 0, 0, 0, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 0, 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 0, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 0, 0, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 0, 0, 0, 0, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 0, + 0, 73, 73, 73, 73, 73, 28, 0, 0, 81, + 0, 24, 0, 0, 0, 59, 0, 0, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, + 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, + 74, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 81, 0, 0, 81, 83, 0, 59, 0, 0, 59, + 0, 0, 0, 75, 0, 69, 69, 69, 81, 81, + 81, 81, 82, 0, 59, 82, 70, 0, 0, 0, + 0, 74, 71, 0, 74, 0, 72, 0, 0, 0, + 82, 82, 82, 82, 0, 83, 0, 0, 83, 74, + 0, 0, 81, 0, 75, 0, 0, 75, 59, 0, + 0, 0, 0, 83, 83, 83, 83, 70, 0, 0, + 70, 0, 75, 71, 82, 0, 71, 72, 0, 0, + 72, 0, 0, 74, 0, 70, 0, 0, 0, 0, + 0, 71, 0, 0, 0, 72, 0, 83, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, + 0, 28, 0, 0, 0, 71, 24, 0, 0, 72, + 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 2, 3, 4, 5, 6, + 0, 0, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 48, 23, 0, 0, 0, 48, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, + 26, 27, 0, 29, 0, 0, 0, 0, 0, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 0, 0, 0, 0, 0, 0, 0, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 74, 74, 74, 74, 74, 28, 0, 0, 0, + 0, 24, 0, 0, 0, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 75, 75, 75, 75, 75, 0, + 0, 0, 0, 0, 0, 0, 0, 70, 70, 70, + 0, 0, 0, 71, 71, 71, 0, 72, 72, 72, + 2, 3, 4, 5, 6, 0, 0, 0, 7, 8, + 9, 10, 11, 0, 2, 3, 4, 5, 6, 145, + 146, 147, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 28, 23, + 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 28, 0, 25, 26, 27, 0, 29, 0, + 0, 0, 0, 0, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 48, 48, 48, 48, 48, 0, 0, 0, + 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 48, 48, 48, 0, + 48, 0, 0, 0, 0, 0, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, + 0, 0, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, + 26, 27, 0, 0, 0, 0, 0, 0, 0, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 0, 0, 0, 0, 2, 3, 4, + 5, 6, 0, 0, 0, 7, 8, 9, 10, 11, + 0, 2, 3, 4, 5, 6, 0, 0, 0, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 0, 0, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 94, + 0, 0, 26, 27, 0, 0, 0, 0, 0, 0, + 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 90, 0, 45, 138, 139, + 140, 141, 142, 143, 144, 0, 154, 154, 158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, + 45, 45, 45, 148, 45, 45, 45, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 224, 225, 217, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 237, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 247, 237, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 45, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 45, +}; +short ch_check[] = { 40, + 0, 41, 26, 297, 0, 276, 41, 278, 42, 44, + 115, 116, 43, 47, 45, 60, 61, 62, 41, 282, + 314, 44, 281, 0, 286, 287, 288, 289, 304, 305, + 292, 293, 294, 295, 127, 128, 129, 130, 272, 273, + 40, 41, 42, 43, 44, 45, 319, 47, 321, 24, + 25, 26, 301, 302, 303, 112, 113, 114, 0, 59, + 60, 61, 62, 40, 41, 42, 43, 44, 45, 285, + 47, 117, 118, 119, 120, 121, 122, 123, 24, 25, + 104, 0, 59, 60, 61, 62, 124, 125, 126, 40, + 40, 40, 40, 93, 0, 40, 40, 40, 40, 41, + 42, 43, 44, 45, 0, 47, 40, 82, 104, 105, + 106, 40, 40, 88, 40, 337, 93, 59, 60, 61, + 62, 40, 41, 42, 43, 44, 45, 40, 47, 104, + 40, 40, 0, 299, 41, 41, 318, 43, 44, 45, + 59, 60, 61, 62, 0, 41, 284, 43, 44, 45, + 283, 93, 41, 59, 60, 61, 62, 0, 41, 41, + 41, 41, 41, 59, 60, 61, 62, 0, 41, 41, + 41, 40, 58, 41, 93, 43, 44, 45, 153, 0, + 40, 156, 40, 58, 41, 41, 41, 93, 44, 41, + 0, 59, 60, 61, 62, 316, 91, 93, 41, 58, + 43, 44, 45, 59, 60, 61, 62, 0, 41, 320, + 275, 44, 274, 277, 41, 319, 59, 60, 61, 62, + 41, 41, 41, 44, 41, 93, 59, 60, 61, 62, + 0, 41, 41, 41, 44, 59, 0, 93, 59, 60, + 61, 62, 93, 40, 300, 41, 41, 63, 41, 59, + 93, 44, 222, 239, 0, 108, 297, 236, 216, 106, + 93, 306, 307, 308, 309, 195, 59, 60, 61, 62, + 208, 41, 93, 314, 44, -1, 316, 311, 312, 310, + 194, -1, -1, 93, -1, -1, -1, -1, -1, 59, + 60, 61, 62, -1, -1, 41, -1, 297, 44, -1, + 93, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 59, 314, -1, -1, -1, -1, -1, + 297, -1, -1, 93, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, -1, 314, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, + -1, -1, -1, -1, -1, 297, -1, -1, -1, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, -1, 314, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, -1, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, -1, -1, 301, 302, 303, 304, 305, + 306, 307, 308, 309, -1, -1, -1, -1, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 301, 302, + 303, 304, 305, 306, 307, 308, 309, -1, -1, -1, + 301, 302, 303, 304, 305, 306, 307, 308, 309, -1, + -1, 301, 302, 303, 304, 305, 40, -1, -1, 0, + -1, 45, -1, -1, -1, 0, -1, -1, 301, 302, + 303, 304, 305, 306, 307, 308, 309, -1, -1, -1, + -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 41, -1, -1, 44, 0, -1, 41, -1, -1, 44, + -1, -1, -1, 0, -1, 301, 302, 303, 59, 60, + 61, 62, 41, -1, 59, 44, 0, -1, -1, -1, + -1, 41, 0, -1, 44, -1, 0, -1, -1, -1, + 59, 60, 61, 62, -1, 41, -1, -1, 44, 59, + -1, -1, 93, -1, 41, -1, -1, 44, 93, -1, + -1, -1, -1, 59, 60, 61, 62, 41, -1, -1, + 44, -1, 59, 41, 93, -1, 44, 41, -1, -1, + 44, -1, -1, 93, -1, 59, -1, -1, -1, -1, + -1, 59, -1, -1, -1, 59, -1, 93, -1, -1, + -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, + -1, 40, -1, -1, -1, 93, 45, -1, -1, 93, + -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 257, -1, 259, 260, 261, 262, 263, + -1, -1, -1, 267, 268, 269, 270, 271, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 40, 298, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 313, + 314, 315, -1, 317, -1, -1, -1, -1, -1, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, -1, -1, -1, -1, -1, -1, -1, + 301, 302, 303, 304, 305, 306, 307, 308, 309, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 301, 302, 303, 304, 305, 40, -1, -1, -1, + -1, 45, -1, -1, -1, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 301, 302, 303, 304, 305, -1, + -1, -1, -1, -1, -1, -1, -1, 301, 302, 303, + -1, -1, -1, 301, 302, 303, -1, 301, 302, 303, + 259, 260, 261, 262, 263, -1, -1, -1, 267, 268, + 269, 270, 271, -1, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 40, 298, + -1, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 40, -1, 313, 314, 315, -1, 317, -1, + -1, -1, -1, -1, 323, 324, 325, 326, 327, 328, + 329, 330, 331, 332, 333, 334, 335, 336, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 259, 260, 261, 262, 263, -1, -1, -1, + 267, 268, 269, 270, 271, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + -1, 298, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 313, 314, 315, -1, + 317, -1, -1, -1, -1, -1, 323, 324, 325, 326, + 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + -1, -1, -1, -1, -1, 259, 260, 261, 262, 263, + -1, -1, -1, 267, 268, 269, 270, 271, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 313, + 314, 315, -1, -1, -1, -1, -1, -1, -1, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, -1, -1, -1, -1, 259, 260, 261, + 262, 263, -1, -1, -1, 267, 268, 269, 270, 271, + -1, 259, 260, 261, 262, 263, -1, -1, -1, 267, + 268, 269, 270, 271, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, -1, -1, -1, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 28, + -1, -1, 314, 315, -1, -1, -1, -1, -1, -1, + -1, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, 333, 334, 335, 336, 0, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 26, -1, 28, 97, 98, + 99, 100, 101, 102, 103, -1, 105, 106, 107, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 188, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 206, 207, 208, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 220, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 235, 236, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 188, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 206, 207, 208, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 220, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 235, 236, +}; +#define YYFINAL 44 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 337 +#if YYDEBUG +char *ch_name[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,"'('","')'","'*'","'+'","','","'-'","'.'","'/'",0,0,0,0,0,0,0,0,0,0, +"':'","';'","'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,"'['",0,"']'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,"FIXME_01","FIXME_02","FIXME_03","FIXME_04", +"FIXME_05","FIXME_06","FIXME_07","FIXME_08","FIXME_09","FIXME_10","FIXME_11", +"FIXME_12","FIXME_13","FIXME_14","FIXME_15","FIXME_16","FIXME_17","FIXME_18", +"FIXME_19","FIXME_20","FIXME_21","FIXME_22","FIXME_24","FIXME_25","FIXME_26", +"FIXME_27","FIXME_28","FIXME_29","FIXME_30","INTEGER_LITERAL","BOOLEAN_LITERAL", +"CHARACTER_LITERAL","FLOAT_LITERAL","GENERAL_PROCEDURE_NAME","LOCATION_NAME", +"SET_LITERAL","EMPTINESS_LITERAL","CHARACTER_STRING_LITERAL", +"BIT_STRING_LITERAL","TYPENAME","FIELD_NAME","CASE","OF","ESAC","LOGIOR","ORIF", +"LOGXOR","LOGAND","ANDIF","NOTEQUAL","GTR","LEQ","IN","SLASH_SLASH","MOD","REM", +"NOT","POINTER","RECEIVE","UP","IF","THEN","ELSE","FI","ELSIF","ILLEGAL_TOKEN", +"NUM","PRED","SUCC","ABS","CARD","MAX_TOKEN","MIN_TOKEN","SIZE","UPPER","LOWER", +"LENGTH","GDB_REGNAME","GDB_LAST","GDB_VARIABLE","GDB_ASSIGNMENT", +}; +char *ch_rule[] = { +"$accept : start", +"start : value", +"start : mode_name", +"value : expression", +"value : undefined_value", +"undefined_value : FIXME_01", +"location : access_name", +"location : primitive_value POINTER", +"access_name : LOCATION_NAME", +"access_name : GDB_LAST", +"access_name : GDB_REGNAME", +"access_name : GDB_VARIABLE", +"access_name : FIXME_03", +"expression_list : expression", +"expression_list : expression_list ',' expression", +"primitive_value : location_contents", +"primitive_value : value_name", +"primitive_value : literal", +"primitive_value : tuple", +"primitive_value : value_string_element", +"primitive_value : value_string_slice", +"primitive_value : value_array_element", +"primitive_value : value_array_slice", +"primitive_value : value_structure_field", +"primitive_value : expression_conversion", +"primitive_value : value_procedure_call", +"primitive_value : value_built_in_routine_call", +"primitive_value : start_expression", +"primitive_value : zero_adic_operator", +"primitive_value : parenthesised_expression", +"location_contents : location", +"value_name : synonym_name", +"value_name : value_enumeration_name", +"value_name : value_do_with_name", +"value_name : value_receive_name", +"value_name : GENERAL_PROCEDURE_NAME", +"literal : INTEGER_LITERAL", +"literal : BOOLEAN_LITERAL", +"literal : CHARACTER_LITERAL", +"literal : FLOAT_LITERAL", +"literal : SET_LITERAL", +"literal : EMPTINESS_LITERAL", +"literal : CHARACTER_STRING_LITERAL", +"literal : BIT_STRING_LITERAL", +"tuple : FIXME_04", +"value_string_element : string_primitive_value '(' start_element ')'", +"value_string_slice : string_primitive_value '(' left_element ':' right_element ')'", +"value_string_slice : string_primitive_value '(' start_element UP slice_size ')'", +"$$1 :", +"value_array_element : array_primitive_value '(' $$1 expression_list ')'", +"value_array_slice : array_primitive_value '(' lower_element ':' upper_element ')'", +"value_array_slice : array_primitive_value '(' first_element UP slice_size ')'", +"value_structure_field : primitive_value FIELD_NAME", +"expression_conversion : mode_name parenthesised_expression", +"value_procedure_call : FIXME_05", +"value_built_in_routine_call : chill_value_built_in_routine_call", +"start_expression : FIXME_06", +"zero_adic_operator : FIXME_07", +"parenthesised_expression : '(' expression ')'", +"expression : operand_0", +"expression : single_assignment_action", +"expression : conditional_expression", +"conditional_expression : IF boolean_expression then_alternative else_alternative FI", +"conditional_expression : CASE case_selector_list OF value_case_alternative '[' ELSE sub_expression ']' ESAC", +"then_alternative : THEN subexpression", +"else_alternative : ELSE subexpression", +"else_alternative : ELSIF boolean_expression then_alternative else_alternative", +"sub_expression : expression", +"value_case_alternative : case_label_specification ':' sub_expression ';'", +"operand_0 : operand_1", +"operand_0 : operand_0 LOGIOR operand_1", +"operand_0 : operand_0 ORIF operand_1", +"operand_0 : operand_0 LOGXOR operand_1", +"operand_1 : operand_2", +"operand_1 : operand_1 LOGAND operand_2", +"operand_1 : operand_1 ANDIF operand_2", +"operand_2 : operand_3", +"operand_2 : operand_2 '=' operand_3", +"operand_2 : operand_2 NOTEQUAL operand_3", +"operand_2 : operand_2 '>' operand_3", +"operand_2 : operand_2 GTR operand_3", +"operand_2 : operand_2 '<' operand_3", +"operand_2 : operand_2 LEQ operand_3", +"operand_2 : operand_2 IN operand_3", +"operand_3 : operand_4", +"operand_3 : operand_3 '+' operand_4", +"operand_3 : operand_3 '-' operand_4", +"operand_3 : operand_3 SLASH_SLASH operand_4", +"operand_4 : operand_5", +"operand_4 : operand_4 '*' operand_5", +"operand_4 : operand_4 '/' operand_5", +"operand_4 : operand_4 MOD operand_5", +"operand_4 : operand_4 REM operand_5", +"operand_5 : operand_6", +"operand_5 : '-' operand_6", +"operand_5 : NOT operand_6", +"operand_5 : parenthesised_expression literal", +"operand_6 : POINTER location", +"operand_6 : RECEIVE buffer_location", +"operand_6 : primitive_value", +"single_assignment_action : location GDB_ASSIGNMENT value", +"chill_value_built_in_routine_call : NUM '(' expression ')'", +"chill_value_built_in_routine_call : PRED '(' expression ')'", +"chill_value_built_in_routine_call : SUCC '(' expression ')'", +"chill_value_built_in_routine_call : ABS '(' expression ')'", +"chill_value_built_in_routine_call : CARD '(' expression ')'", +"chill_value_built_in_routine_call : MAX_TOKEN '(' expression ')'", +"chill_value_built_in_routine_call : MIN_TOKEN '(' expression ')'", +"chill_value_built_in_routine_call : SIZE '(' location ')'", +"chill_value_built_in_routine_call : SIZE '(' mode_argument ')'", +"chill_value_built_in_routine_call : UPPER '(' upper_lower_argument ')'", +"chill_value_built_in_routine_call : LOWER '(' upper_lower_argument ')'", +"chill_value_built_in_routine_call : LENGTH '(' length_argument ')'", +"mode_argument : mode_name", +"mode_argument : array_mode_name '(' expression ')'", +"mode_argument : string_mode_name '(' expression ')'", +"mode_argument : variant_structure_mode_name '(' expression_list ')'", +"mode_name : TYPENAME", +"upper_lower_argument : expression", +"upper_lower_argument : mode_name", +"length_argument : expression", +"array_primitive_value : primitive_value", +"array_mode_name : FIXME_08", +"string_mode_name : FIXME_09", +"variant_structure_mode_name : FIXME_10", +"synonym_name : FIXME_11", +"value_enumeration_name : FIXME_12", +"value_do_with_name : FIXME_13", +"value_receive_name : FIXME_14", +"string_primitive_value : FIXME_15", +"start_element : FIXME_16", +"left_element : FIXME_17", +"right_element : FIXME_18", +"slice_size : FIXME_19", +"lower_element : FIXME_20", +"upper_element : FIXME_21", +"first_element : FIXME_22", +"boolean_expression : FIXME_26", +"case_selector_list : FIXME_27", +"subexpression : FIXME_28", +"case_label_specification : FIXME_29", +"buffer_location : FIXME_30", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 994 "./ch-exp.y" + +/* Implementation of a dynamically expandable buffer for processing input + characters acquired through lexptr and building a value to return in + yylval. */ + +static char *tempbuf; /* Current buffer contents */ +static int tempbufsize; /* Size of allocated buffer */ +static int tempbufindex; /* Current index into buffer */ + +#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */ + +#define CHECKBUF(size) \ + do { \ + if (tempbufindex + (size) >= tempbufsize) \ + { \ + growbuf_by_size (size); \ + } \ + } while (0); + +/* Grow the static temp buffer if necessary, including allocating the first one + on demand. */ + +static void +growbuf_by_size (count) + int count; +{ + int growby; + + growby = max (count, GROWBY_MIN_SIZE); + tempbufsize += growby; + if (tempbuf == NULL) + { + tempbuf = (char *) xmalloc (tempbufsize); + } + else + { + tempbuf = (char *) xrealloc (tempbuf, tempbufsize); + } +} + +/* Try to consume a simple name string token. If successful, returns + a pointer to a nullbyte terminated copy of the name that can be used + in symbol table lookups. If not successful, returns NULL. */ + +static char * +match_simple_name_string () +{ + char *tokptr = lexptr; + + if (isalpha (*tokptr)) + { + char *result; + do { + tokptr++; + } while (isalnum (*tokptr) || (*tokptr == '_')); + yylval.sval.ptr = lexptr; + yylval.sval.length = tokptr - lexptr; + lexptr = tokptr; + result = copy_name (yylval.sval); + for (tokptr = result; *tokptr; tokptr++) + if (isupper (*tokptr)) + *tokptr = tolower(*tokptr); + return result; + } + return (NULL); +} + +/* Start looking for a value composed of valid digits as set by the base + in use. Note that '_' characters are valid anywhere, in any quantity, + and are simply ignored. Since we must find at least one valid digit, + or reject this token as an integer literal, we keep track of how many + digits we have encountered. */ + +static int +decode_integer_value (base, tokptrptr, ivalptr) + int base; + char **tokptrptr; + int *ivalptr; +{ + char *tokptr = *tokptrptr; + int temp; + int digits = 0; + + while (*tokptr != '\0') + { + temp = tolower (*tokptr); + tokptr++; + switch (temp) + { + case '_': + continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + temp -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + temp -= 'a'; + temp += 10; + break; + default: + temp = base; + break; + } + if (temp < base) + { + digits++; + *ivalptr *= base; + *ivalptr += temp; + } + else + { + /* Found something not in domain for current base. */ + tokptr--; /* Unconsume what gave us indigestion. */ + break; + } + } + + /* If we didn't find any digits, then we don't have a valid integer + value, so reject the entire token. Otherwise, update the lexical + scan pointer, and return non-zero for success. */ + + if (digits == 0) + { + return (0); + } + else + { + *tokptrptr = tokptr; + return (1); + } +} + +static int +decode_integer_literal (valptr, tokptrptr) + int *valptr; + char **tokptrptr; +{ + char *tokptr = *tokptrptr; + int base = 0; + int ival = 0; + int explicit_base = 0; + + /* Look for an explicit base specifier, which is optional. */ + + switch (*tokptr) + { + case 'd': + case 'D': + explicit_base++; + base = 10; + tokptr++; + break; + case 'b': + case 'B': + explicit_base++; + base = 2; + tokptr++; + break; + case 'h': + case 'H': + explicit_base++; + base = 16; + tokptr++; + break; + case 'o': + case 'O': + explicit_base++; + base = 8; + tokptr++; + break; + default: + base = 10; + break; + } + + /* If we found an explicit base ensure that the character after the + explicit base is a single quote. */ + + if (explicit_base && (*tokptr++ != '\'')) + { + return (0); + } + + /* Attempt to decode whatever follows as an integer value in the + indicated base, updating the token pointer in the process and + computing the value into ival. Also, if we have an explicit + base, then the next character must not be a single quote, or we + have a bitstring literal, so reject the entire token in this case. + Otherwise, update the lexical scan pointer, and return non-zero + for success. */ + + if (!decode_integer_value (base, &tokptr, &ival)) + { + return (0); + } + else if (explicit_base && (*tokptr == '\'')) + { + return (0); + } + else + { + *valptr = ival; + *tokptrptr = tokptr; + return (1); + } +} + +/* If it wasn't for the fact that floating point values can contain '_' + characters, we could just let strtod do all the hard work by letting it + try to consume as much of the current token buffer as possible and + find a legal conversion. Unfortunately we need to filter out the '_' + characters before calling strtod, which we do by copying the other + legal chars to a local buffer to be converted. However since we also + need to keep track of where the last unconsumed character in the input + buffer is, we have transfer only as many characters as may compose a + legal floating point value. */ + +static int +match_float_literal () +{ + char *tokptr = lexptr; + char *buf; + char *copy; + double dval; + extern double strtod (); + + /* Make local buffer in which to build the string to convert. This is + required because underscores are valid in chill floating point numbers + but not in the string passed to strtod to convert. The string will be + no longer than our input string. */ + + copy = buf = (char *) alloca (strlen (tokptr) + 1); + + /* Transfer all leading digits to the conversion buffer, discarding any + underscores. */ + + while (isdigit (*tokptr) || *tokptr == '_') + { + if (*tokptr != '_') + { + *copy++ = *tokptr; + } + tokptr++; + } + + /* Now accept either a '.', or one of [eEdD]. Dot is legal regardless + of whether we found any leading digits, and we simply accept it and + continue on to look for the fractional part and/or exponent. One of + [eEdD] is legal only if we have seen digits, and means that there + is no fractional part. If we find neither of these, then this is + not a floating point number, so return failure. */ + + switch (*tokptr++) + { + case '.': + /* Accept and then look for fractional part and/or exponent. */ + *copy++ = '.'; + break; + + case 'e': + case 'E': + case 'd': + case 'D': + if (copy == buf) + { + return (0); + } + *copy++ = 'e'; + goto collect_exponent; + break; + + default: + return (0); + break; + } + + /* We found a '.', copy any fractional digits to the conversion buffer, up + to the first nondigit, non-underscore character. */ + + while (isdigit (*tokptr) || *tokptr == '_') + { + if (*tokptr != '_') + { + *copy++ = *tokptr; + } + tokptr++; + } + + /* Look for an exponent, which must start with one of [eEdD]. If none + is found, jump directly to trying to convert what we have collected + so far. */ + + switch (*tokptr) + { + case 'e': + case 'E': + case 'd': + case 'D': + *copy++ = 'e'; + tokptr++; + break; + default: + goto convert_float; + break; + } + + /* Accept an optional '-' or '+' following one of [eEdD]. */ + + collect_exponent: + if (*tokptr == '+' || *tokptr == '-') + { + *copy++ = *tokptr++; + } + + /* Now copy an exponent into the conversion buffer. Note that at the + moment underscores are *not* allowed in exponents. */ + + while (isdigit (*tokptr)) + { + *copy++ = *tokptr++; + } + + /* If we transfered any chars to the conversion buffer, try to interpret its + contents as a floating point value. If any characters remain, then we + must not have a valid floating point string. */ + + convert_float: + *copy = '\0'; + if (copy != buf) + { + dval = strtod (buf, ©); + if (*copy == '\0') + { + yylval.dval = dval; + lexptr = tokptr; + return (FLOAT_LITERAL); + } + } + return (0); +} + +/* Recognize a string literal. A string literal is a nonzero sequence + of characters enclosed in matching single or double quotes, except that + a single character inside single quotes is a character literal, which + we reject as a string literal. To embed the terminator character inside + a string, it is simply doubled (I.E. "this""is""one""string") */ + +static int +match_string_literal () +{ + char *tokptr = lexptr; + + for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++) + { + CHECKBUF (1); + if (*tokptr == *lexptr) + { + if (*(tokptr + 1) == *lexptr) + { + tokptr++; + } + else + { + break; + } + } + tempbuf[tempbufindex++] = *tokptr; + } + if (*tokptr == '\0' /* no terminator */ + || tempbufindex == 0 /* no string */ + || (tempbufindex == 1 && *tokptr == '\'')) /* char literal */ + { + return (0); + } + else + { + tempbuf[tempbufindex] = '\0'; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = ++tokptr; + return (CHARACTER_STRING_LITERAL); + } +} + +/* Recognize a character literal. A character literal is single character + or a control sequence, enclosed in single quotes. A control sequence + is a comma separated list of one or more integer literals, enclosed + in parenthesis and introduced with a circumflex character. + + EX: 'a' '^(7)' '^(7,8)' + + As a GNU chill extension, the syntax C'xx' is also recognized as a + character literal, where xx is a hex value for the character. + + Note that more than a single character, enclosed in single quotes, is + a string literal. + + Also note that the control sequence form is not in GNU Chill since it + is ambiguous with the string literal form using single quotes. I.E. + is '^(7)' a character literal or a string literal. In theory it it + possible to tell by context, but GNU Chill doesn't accept the control + sequence form, so neither do we (for now the code is disabled). + + Returns CHARACTER_LITERAL if a match is found. + */ + +static int +match_character_literal () +{ + char *tokptr = lexptr; + int ival = 0; + + if ((tolower (*tokptr) == 'c') && (*(tokptr + 1) == '\'')) + { + /* We have a GNU chill extension form, so skip the leading "C'", + decode the hex value, and then ensure that we have a trailing + single quote character. */ + tokptr += 2; + if (!decode_integer_value (16, &tokptr, &ival) || (*tokptr != '\'')) + { + return (0); + } + tokptr++; + } + else if (*tokptr == '\'') + { + tokptr++; + + /* Determine which form we have, either a control sequence or the + single character form. */ + + if ((*tokptr == '^') && (*(tokptr + 1) == '(')) + { +#if 0 /* Disable, see note above. -fnf */ + /* Match and decode a control sequence. Return zero if we don't + find a valid integer literal, or if the next unconsumed character + after the integer literal is not the trailing ')'. + FIXME: We currently don't handle the multiple integer literal + form. */ + tokptr += 2; + if (!decode_integer_literal (&ival, &tokptr) || (*tokptr++ != ')')) + { + return (0); + } +#else + return (0); +#endif + } + else + { + ival = *tokptr++; + } + + /* The trailing quote has not yet been consumed. If we don't find + it, then we have no match. */ + + if (*tokptr++ != '\'') + { + return (0); + } + } + else + { + /* Not a character literal. */ + return (0); + } + yylval.typed_val.val = ival; + yylval.typed_val.type = builtin_type_chill_char; + lexptr = tokptr; + return (CHARACTER_LITERAL); +} + +/* Recognize an integer literal, as specified in Z.200 sec 5.2.4.2. + Note that according to 5.2.4.2, a single "_" is also a valid integer + literal, however GNU-chill requires there to be at least one "digit" + in any integer literal. */ + +static int +match_integer_literal () +{ + char *tokptr = lexptr; + int ival; + + if (!decode_integer_literal (&ival, &tokptr)) + { + return (0); + } + else + { + yylval.typed_val.val = ival; + yylval.typed_val.type = builtin_type_int; + lexptr = tokptr; + return (INTEGER_LITERAL); + } +} + +/* Recognize a bit-string literal, as specified in Z.200 sec 5.2.4.8 + Note that according to 5.2.4.8, a single "_" is also a valid bit-string + literal, however GNU-chill requires there to be at least one "digit" + in any bit-string literal. */ + +static int +match_bitstring_literal () +{ + char *tokptr = lexptr; + int mask; + int bitoffset = 0; + int bitcount = 0; + int base; + int digit; + + tempbufindex = 0; + + /* Look for the required explicit base specifier. */ + + switch (*tokptr++) + { + case 'b': + case 'B': + base = 2; + break; + case 'o': + case 'O': + base = 8; + break; + case 'h': + case 'H': + base = 16; + break; + default: + return (0); + break; + } + + /* Ensure that the character after the explicit base is a single quote. */ + + if (*tokptr++ != '\'') + { + return (0); + } + + while (*tokptr != '\0' && *tokptr != '\'') + { + digit = tolower (*tokptr); + tokptr++; + switch (digit) + { + case '_': + continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + digit -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + digit -= 'a'; + digit += 10; + break; + default: + return (0); + break; + } + if (digit >= base) + { + /* Found something not in domain for current base. */ + return (0); + } + else + { + /* Extract bits from digit, starting with the msbit appropriate for + the current base, and packing them into the bitstring byte, + starting at the lsbit. */ + for (mask = (base >> 1); mask > 0; mask >>= 1) + { + bitcount++; + CHECKBUF (1); + if (digit & mask) + { + tempbuf[tempbufindex] |= (1 << bitoffset); + } + bitoffset++; + if (bitoffset == HOST_CHAR_BIT) + { + bitoffset = 0; + tempbufindex++; + } + } + } + } + + /* Verify that we consumed everything up to the trailing single quote, + and that we found some bits (IE not just underbars). */ + + if (*tokptr++ != '\'') + { + return (0); + } + else + { + yylval.sval.ptr = tempbuf; + yylval.sval.length = bitcount; + lexptr = tokptr; + return (BIT_STRING_LITERAL); + } +} + +/* Recognize tokens that start with '$'. These include: + + $regname A native register name or a "standard + register name". + Return token GDB_REGNAME. + + $variable A convenience variable with a name chosen + by the user. + Return token GDB_VARIABLE. + + $digits Value history with index , starting + from the first value which has index 1. + Return GDB_LAST. + + $$digits Value history with index relative + to the last value. I.E. $$0 is the last + value, $$1 is the one previous to that, $$2 + is the one previous to $$1, etc. + Return token GDB_LAST. + + $ | $0 | $$0 The last value in the value history. + Return token GDB_LAST. + + $$ An abbreviation for the second to the last + value in the value history, I.E. $$1 + Return token GDB_LAST. + + Note that we currently assume that register names and convenience + variables follow the convention of starting with a letter or '_'. + + */ + +static int +match_dollar_tokens () +{ + char *tokptr; + int regno; + int namelength; + int negate; + int ival; + + /* We will always have a successful match, even if it is just for + a single '$', the abbreviation for $$0. So advance lexptr. */ + + tokptr = ++lexptr; + + if (*tokptr == '_' || isalpha (*tokptr)) + { + /* Look for a match with a native register name, usually something + like "r0" for example. */ + + for (regno = 0; regno < NUM_REGS; regno++) + { + namelength = strlen (reg_names[regno]); + if (STREQN (tokptr, reg_names[regno], namelength) + && !isalnum (tokptr[namelength])) + { + yylval.lval = regno; + lexptr += namelength + 1; + return (GDB_REGNAME); + } + } + + /* Look for a match with a standard register name, usually something + like "pc", which gdb always recognizes as the program counter + regardless of what the native register name is. */ + + for (regno = 0; regno < num_std_regs; regno++) + { + namelength = strlen (std_regs[regno].name); + if (STREQN (tokptr, std_regs[regno].name, namelength) + && !isalnum (tokptr[namelength])) + { + yylval.lval = std_regs[regno].regnum; + lexptr += namelength; + return (GDB_REGNAME); + } + } + + /* Attempt to match against a convenience variable. Note that + this will always succeed, because if no variable of that name + already exists, the lookup_internalvar will create one for us. + Also note that both lexptr and tokptr currently point to the + start of the input string we are trying to match, and that we + have already tested the first character for non-numeric, so we + don't have to treat it specially. */ + + while (*tokptr == '_' || isalnum (*tokptr)) + { + tokptr++; + } + yylval.sval.ptr = lexptr; + yylval.sval.length = tokptr - lexptr; + yylval.ivar = lookup_internalvar (copy_name (yylval.sval)); + lexptr = tokptr; + return (GDB_VARIABLE); + } + + /* Since we didn't match against a register name or convenience + variable, our only choice left is a history value. */ + + if (*tokptr == '$') + { + negate = 1; + ival = 1; + tokptr++; + } + else + { + negate = 0; + ival = 0; + } + + /* Attempt to decode more characters as an integer value giving + the index in the history list. If successful, the value will + overwrite ival (currently 0 or 1), and if not, ival will be + left alone, which is good since it is currently correct for + the '$' or '$$' case. */ + + decode_integer_literal (&ival, &tokptr); + yylval.lval = negate ? -ival : ival; + lexptr = tokptr; + return (GDB_LAST); +} + +struct token +{ + char *operator; + int token; +}; + +static const struct token idtokentab[] = +{ + { "length", LENGTH }, + { "lower", LOWER }, + { "upper", UPPER }, + { "andif", ANDIF }, + { "pred", PRED }, + { "succ", SUCC }, + { "card", CARD }, + { "size", SIZE }, + { "orif", ORIF }, + { "num", NUM }, + { "abs", ABS }, + { "max", MAX_TOKEN }, + { "min", MIN_TOKEN }, + { "mod", MOD }, + { "rem", REM }, + { "not", NOT }, + { "xor", LOGXOR }, + { "and", LOGAND }, + { "in", IN }, + { "or", LOGIOR } +}; + +static const struct token tokentab2[] = +{ + { ":=", GDB_ASSIGNMENT }, + { "//", SLASH_SLASH }, + { "->", POINTER }, + { "/=", NOTEQUAL }, + { "<=", LEQ }, + { ">=", GTR } +}; + +/* Read one token, getting characters through lexptr. */ +/* This is where we will check to make sure that the language and the + operators used are compatible. */ + +static int +yylex () +{ + unsigned int i; + int token; + char *simplename; + struct symbol *sym; + + /* Skip over any leading whitespace. */ + while (isspace (*lexptr)) + { + lexptr++; + } + /* Look for special single character cases which can't be the first + character of some other multicharacter token. */ + switch (*lexptr) + { + case '\0': + return (0); + case ',': + case '=': + case ';': + case '!': + case '+': + case '*': + case '(': + case ')': + case '[': + case ']': + return (*lexptr++); + } + /* Look for characters which start a particular kind of multicharacter + token, such as a character literal, register name, convenience + variable name, string literal, etc. */ + switch (*lexptr) + { + case '\'': + case '\"': + /* First try to match a string literal, which is any nonzero + sequence of characters enclosed in matching single or double + quotes, except that a single character inside single quotes + is a character literal, so we have to catch that case also. */ + token = match_string_literal (); + if (token != 0) + { + return (token); + } + if (*lexptr == '\'') + { + token = match_character_literal (); + if (token != 0) + { + return (token); + } + } + break; + case 'C': + case 'c': + token = match_character_literal (); + if (token != 0) + { + return (token); + } + break; + case '$': + token = match_dollar_tokens (); + if (token != 0) + { + return (token); + } + break; + } + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++) + { + if (STREQN (lexptr, tokentab2[i].operator, 2)) + { + lexptr += 2; + return (tokentab2[i].token); + } + } + /* Look for single character cases which which could be the first + character of some other multicharacter token, but aren't, or we + would already have found it. */ + switch (*lexptr) + { + case '-': + case ':': + case '/': + case '<': + case '>': + return (*lexptr++); + } + /* Look for a float literal before looking for an integer literal, so + we match as much of the input stream as possible. */ + token = match_float_literal (); + if (token != 0) + { + return (token); + } + token = match_bitstring_literal (); + if (token != 0) + { + return (token); + } + token = match_integer_literal (); + if (token != 0) + { + return (token); + } + + /* Try to match a simple name string, and if a match is found, then + further classify what sort of name it is and return an appropriate + token. Note that attempting to match a simple name string consumes + the token from lexptr, so we can't back out if we later find that + we can't classify what sort of name it is. */ + + simplename = match_simple_name_string (); + + if (simplename != NULL) + { + /* See if it is a reserved identifier. */ + for (i = 0; i < sizeof (idtokentab) / sizeof (idtokentab[0]); i++) + { + if (STREQ (simplename, idtokentab[i].operator)) + { + return (idtokentab[i].token); + } + } + + /* Look for other special tokens. */ + if (STREQ (simplename, "true")) + { + yylval.ulval = 1; + return (BOOLEAN_LITERAL); + } + if (STREQ (simplename, "false")) + { + yylval.ulval = 0; + return (BOOLEAN_LITERAL); + } + + sym = lookup_symbol (simplename, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym != NULL) + { + yylval.ssym.stoken.ptr = NULL; + yylval.ssym.stoken.length = 0; + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = 0; /* FIXME, C++'ism */ + switch (SYMBOL_CLASS (sym)) + { + case LOC_BLOCK: + /* Found a procedure name. */ + return (GENERAL_PROCEDURE_NAME); + case LOC_STATIC: + /* Found a global or local static variable. */ + return (LOCATION_NAME); + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + if (innermost_block == NULL + || contained_in (block_found, innermost_block)) + { + innermost_block = block_found; + } + return (LOCATION_NAME); + break; + case LOC_CONST: + case LOC_LABEL: + return (LOCATION_NAME); + break; + case LOC_TYPEDEF: + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + case LOC_UNDEF: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + error ("Symbol \"%s\" names no location.", simplename); + break; + } + } + else if (!have_full_symbols () && !have_partial_symbols ()) + { + error ("No symbol table is loaded. Use the \"file\" command."); + } + else + { + error ("No symbol \"%s\" in current context.", simplename); + } + } + + /* Catch single character tokens which are not part of some + longer token. */ + + switch (*lexptr) + { + case '.': /* Not float for example. */ + lexptr++; + while (isspace (*lexptr)) lexptr++; + simplename = match_simple_name_string (); + if (!simplename) + return '.'; + return FIELD_NAME; + } + + return (ILLEGAL_TOKEN); +} + +void +yyerror (msg) + char *msg; /* unused */ +{ + printf ("Parsing: %s\n", lexptr); + if (yychar < 256) + { + error ("Invalid syntax in expression near character '%c'.", yychar); + } + else + { + error ("Invalid syntax in expression"); + } +} +#line 1836 "y.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 312 "./ch-exp.y" +{ } +break; +case 2: +#line 314 "./ch-exp.y" +{ write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(yyvsp[0].tsym.type); + write_exp_elt_opcode(OP_TYPE);} +break; +case 3: +#line 320 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 4: +#line 324 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 5: +#line 330 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 7: +#line 339 "./ch-exp.y" +{ + write_exp_elt_opcode (UNOP_IND); + } +break; +case 8: +#line 347 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (yyvsp[0].ssym.sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } +break; +case 9: +#line 354 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst (yyvsp[0].lval); + write_exp_elt_opcode (OP_LAST); + } +break; +case 10: +#line 360 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst (yyvsp[0].lval); + write_exp_elt_opcode (OP_REGISTER); + } +break; +case 11: +#line 366 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (yyvsp[0].ivar); + write_exp_elt_opcode (OP_INTERNALVAR); + } +break; +case 12: +#line 372 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 13: +#line 380 "./ch-exp.y" +{ + arglist_len = 1; + } +break; +case 14: +#line 384 "./ch-exp.y" +{ + arglist_len++; + } +break; +case 15: +#line 391 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 16: +#line 395 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 17: +#line 399 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 18: +#line 403 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 19: +#line 407 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 20: +#line 411 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 21: +#line 415 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 22: +#line 419 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 23: +#line 423 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 24: +#line 427 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 25: +#line 431 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 26: +#line 435 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 27: +#line 439 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 28: +#line 443 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 29: +#line 447 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 30: +#line 455 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 31: +#line 463 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 32: +#line 467 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 33: +#line 471 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 34: +#line 475 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 35: +#line 479 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (yyvsp[0].ssym.sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } +break; +case 36: +#line 490 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (yyvsp[0].typed_val.type); + write_exp_elt_longcst ((LONGEST) (yyvsp[0].typed_val.val)); + write_exp_elt_opcode (OP_LONG); + } +break; +case 37: +#line 497 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_BOOL); + } +break; +case 38: +#line 503 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (yyvsp[0].typed_val.type); + write_exp_elt_longcst ((LONGEST) (yyvsp[0].typed_val.val)); + write_exp_elt_opcode (OP_LONG); + } +break; +case 39: +#line 510 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst (yyvsp[0].dval); + write_exp_elt_opcode (OP_DOUBLE); + } +break; +case 40: +#line 517 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 41: +#line 521 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 42: +#line 525 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_STRING); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_STRING); + } +break; +case 43: +#line 531 "./ch-exp.y" +{ + write_exp_elt_opcode (OP_BITSTRING); + write_exp_bitstring (yyvsp[0].sval); + write_exp_elt_opcode (OP_BITSTRING); + } +break; +case 44: +#line 541 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 45: +#line 550 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 46: +#line 558 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 47: +#line 562 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 48: +#line 572 "./ch-exp.y" +{ start_arglist (); } +break; +case 49: +#line 574 "./ch-exp.y" +{ + write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); + } +break; +case 50: +#line 584 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 51: +#line 588 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 52: +#line 596 "./ch-exp.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); + } +break; +case 53: +#line 605 "./ch-exp.y" +{ + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-1].tsym.type); + write_exp_elt_opcode (UNOP_CAST); + } +break; +case 54: +#line 615 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 55: +#line 623 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 56: +#line 631 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 57: +#line 639 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 58: +#line 647 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 59: +#line 655 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 60: +#line 659 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 61: +#line 663 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 62: +#line 669 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 63: +#line 673 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 64: +#line 679 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 65: +#line 685 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 66: +#line 689 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 67: +#line 695 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 68: +#line 701 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 69: +#line 709 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 70: +#line 713 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_BITWISE_IOR); + } +break; +case 71: +#line 717 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 72: +#line 721 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_BITWISE_XOR); + } +break; +case 73: +#line 729 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 74: +#line 733 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_BITWISE_AND); + } +break; +case 75: +#line 737 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 76: +#line 745 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 77: +#line 749 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_EQUAL); + } +break; +case 78: +#line 753 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_NOTEQUAL); + } +break; +case 79: +#line 757 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_GTR); + } +break; +case 80: +#line 761 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_GEQ); + } +break; +case 81: +#line 765 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_LESS); + } +break; +case 82: +#line 769 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_LEQ); + } +break; +case 83: +#line 773 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 84: +#line 782 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 85: +#line 786 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_ADD); + } +break; +case 86: +#line 790 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_SUB); + } +break; +case 87: +#line 794 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_CONCAT); + } +break; +case 88: +#line 802 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 89: +#line 806 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_MUL); + } +break; +case 90: +#line 810 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_DIV); + } +break; +case 91: +#line 814 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_MOD); + } +break; +case 92: +#line 818 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_REM); + } +break; +case 93: +#line 826 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 94: +#line 830 "./ch-exp.y" +{ + write_exp_elt_opcode (UNOP_NEG); + } +break; +case 95: +#line 834 "./ch-exp.y" +{ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } +break; +case 96: +#line 840 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_CONCAT); + } +break; +case 97: +#line 848 "./ch-exp.y" +{ + write_exp_elt_opcode (UNOP_ADDR); + } +break; +case 98: +#line 852 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 99: +#line 856 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 100: +#line 866 "./ch-exp.y" +{ + write_exp_elt_opcode (BINOP_ASSIGN); + } +break; +case 101: +#line 875 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 102: +#line 879 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 103: +#line 883 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 104: +#line 887 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 105: +#line 891 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 106: +#line 895 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 107: +#line 899 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 108: +#line 903 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 109: +#line 907 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 110: +#line 911 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 111: +#line 915 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 112: +#line 919 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 113: +#line 925 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 114: +#line 929 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 115: +#line 933 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 116: +#line 937 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 118: +#line 946 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 119: +#line 950 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 120: +#line 956 "./ch-exp.y" +{ + yyval.voidval = 0; /* FIXME */ + } +break; +case 121: +#line 964 "./ch-exp.y" +{ + yyval.voidval = 0; + } +break; +case 122: +#line 972 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 123: +#line 973 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 124: +#line 974 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 125: +#line 975 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 126: +#line 976 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 127: +#line 977 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 128: +#line 978 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 129: +#line 979 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 130: +#line 980 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 131: +#line 981 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 132: +#line 982 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 133: +#line 983 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 134: +#line 984 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 135: +#line 985 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 136: +#line 986 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 137: +#line 987 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 138: +#line 988 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 139: +#line 989 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 140: +#line 990 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +case 141: +#line 991 "./ch-exp.y" +{ yyval.voidval = 0; } +break; +#line 2799 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/gnu/usr.bin/gdb/gdb/ch-exp.y b/gnu/usr.bin/gdb/gdb/ch-exp.y new file mode 100644 index 00000000000..b6370f3241f --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ch-exp.y @@ -0,0 +1,1997 @@ +/* YACC grammar for Chill expressions, for GDB. + Copyright 1992, 1993 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. */ + +/* Parse a Chill expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. + + Note that malloc's and realloc's in this file are transformed to + xmalloc and xrealloc respectively by the same sed command in the + makefile that remaps any other malloc/realloc inserted by the parser + generator. Doing this with #defines and trying to control the interaction + with include files ( and for example) just became + too messy, particularly when such includes can be inserted at random + times by the parser generator. + + Also note that the language accepted by this parser is more liberal + than the one accepted by an actual Chill compiler. For example, the + language rule that a simple name string can not be one of the reserved + simple name strings is not enforced (e.g "case" is not treated as a + reserved name). Another example is that Chill is a strongly typed + language, and certain expressions that violate the type constraints + may still be evaluated if gdb can do so in a meaningful manner, while + such expressions would be rejected by the compiler. The reason for + this more liberal behavior is the philosophy that the debugger + is intended to be a tool that is used by the programmer when things + go wrong, and as such, it should provide as few artificial barriers + to it's use as possible. If it can do something meaningful, even + something that violates language contraints that are enforced by the + compiler, it should do so without complaint. + + */ + +%{ + +#include "defs.h" +#include +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "ch-lang.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth chill_maxdepth +#define yyparse chill_parse +#define yylex chill_lex +#define yyerror chill_error +#define yylval chill_lval +#define yychar chill_char +#define yydebug chill_debug +#define yypact chill_pact +#define yyr1 chill_r1 +#define yyr2 chill_r2 +#define yydef chill_def +#define yychk chill_chk +#define yypgo chill_pgo +#define yyact chill_act +#define yyexca chill_exca +#define yyerrflag chill_errflag +#define yynerrs chill_nerrs +#define yyps chill_ps +#define yypv chill_pv +#define yys chill_s +#define yy_yys chill_yys +#define yystate chill_state +#define yytmp chill_tmp +#define yyv chill_v +#define yy_yyv chill_yyv +#define yyval chill_val +#define yylloc chill_lloc +#define yyreds chill_reds /* With YYDEBUG defined */ +#define yytoks chill_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + LONGEST lval; + unsigned LONGEST ulval; + struct { + LONGEST val; + struct type *type; + } typed_val; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%token FIXME_01 +%token FIXME_02 +%token FIXME_03 +%token FIXME_04 +%token FIXME_05 +%token FIXME_06 +%token FIXME_07 +%token FIXME_08 +%token FIXME_09 +%token FIXME_10 +%token FIXME_11 +%token FIXME_12 +%token FIXME_13 +%token FIXME_14 +%token FIXME_15 +%token FIXME_16 +%token FIXME_17 +%token FIXME_18 +%token FIXME_19 +%token FIXME_20 +%token FIXME_21 +%token FIXME_22 +%token FIXME_24 +%token FIXME_25 +%token FIXME_26 +%token FIXME_27 +%token FIXME_28 +%token FIXME_29 +%token FIXME_30 + +%token INTEGER_LITERAL +%token BOOLEAN_LITERAL +%token CHARACTER_LITERAL +%token FLOAT_LITERAL +%token GENERAL_PROCEDURE_NAME +%token LOCATION_NAME +%token SET_LITERAL +%token EMPTINESS_LITERAL +%token CHARACTER_STRING_LITERAL +%token BIT_STRING_LITERAL +%token TYPENAME +%token FIELD_NAME + +%token '.' +%token ';' +%token ':' +%token CASE +%token OF +%token ESAC +%token LOGIOR +%token ORIF +%token LOGXOR +%token LOGAND +%token ANDIF +%token '=' +%token NOTEQUAL +%token '>' +%token GTR +%token '<' +%token LEQ +%token IN +%token '+' +%token '-' +%token '*' +%token '/' +%token SLASH_SLASH +%token MOD +%token REM +%token NOT +%token POINTER +%token RECEIVE +%token '[' +%token ']' +%token '(' +%token ')' +%token UP +%token IF +%token THEN +%token ELSE +%token FI +%token ELSIF +%token ILLEGAL_TOKEN +%token NUM +%token PRED +%token SUCC +%token ABS +%token CARD +%token MAX_TOKEN +%token MIN_TOKEN +%token SIZE +%token UPPER +%token LOWER +%token LENGTH + +/* Tokens which are not Chill tokens used in expressions, but rather GDB + specific things that we recognize in the same context as Chill tokens + (register names for example). */ + +%token GDB_REGNAME /* Machine register name */ +%token GDB_LAST /* Value history */ +%token GDB_VARIABLE /* Convenience variable */ +%token GDB_ASSIGNMENT /* Assign value to somewhere */ + +%type location +%type access_name +%type primitive_value +%type location_contents +%type value_name +%type literal +%type tuple +%type value_string_element +%type value_string_slice +%type value_array_element +%type value_array_slice +%type value_structure_field +%type expression_conversion +%type value_procedure_call +%type value_built_in_routine_call +%type chill_value_built_in_routine_call +%type start_expression +%type zero_adic_operator +%type parenthesised_expression +%type value +%type undefined_value +%type expression +%type conditional_expression +%type then_alternative +%type else_alternative +%type sub_expression +%type value_case_alternative +%type operand_0 +%type operand_1 +%type operand_2 +%type operand_3 +%type operand_4 +%type operand_5 +%type operand_6 +%type synonym_name +%type value_enumeration_name +%type value_do_with_name +%type value_receive_name +%type string_primitive_value +%type start_element +%type left_element +%type right_element +%type slice_size +%type array_primitive_value +%type expression_list +%type lower_element +%type upper_element +%type first_element +%type mode_argument +%type upper_lower_argument +%type length_argument +%type array_mode_name +%type string_mode_name +%type variant_structure_mode_name +%type boolean_expression +%type case_selector_list +%type subexpression +%type case_label_specification +%type buffer_location +%type single_assignment_action +%type mode_name + +%% + +/* Z.200, 5.3.1 */ + +start : value { } + | mode_name + { write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type($1.type); + write_exp_elt_opcode(OP_TYPE);} + ; + +value : expression + { + $$ = 0; /* FIXME */ + } + | undefined_value + { + $$ = 0; /* FIXME */ + } + ; + +undefined_value : FIXME_01 + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 4.2.1 */ + +location : access_name + | primitive_value POINTER + { + write_exp_elt_opcode (UNOP_IND); + } + ; + +/* Z.200, 4.2.2 */ + +access_name : LOCATION_NAME + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym ($1.sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + | GDB_LAST /* gdb specific */ + { + write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_LAST); + } + | GDB_REGNAME /* gdb specific */ + { + write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_REGISTER); + } + | GDB_VARIABLE /* gdb specific */ + { + write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); + } + | FIXME_03 + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 4.2.8 */ + +expression_list : expression + { + arglist_len = 1; + } + | expression_list ',' expression + { + arglist_len++; + } + +/* Z.200, 5.2.1 */ + +primitive_value : location_contents + { + $$ = 0; /* FIXME */ + } + | value_name + { + $$ = 0; /* FIXME */ + } + | literal + { + $$ = 0; /* FIXME */ + } + | tuple + { + $$ = 0; /* FIXME */ + } + | value_string_element + { + $$ = 0; /* FIXME */ + } + | value_string_slice + { + $$ = 0; /* FIXME */ + } + | value_array_element + { + $$ = 0; /* FIXME */ + } + | value_array_slice + { + $$ = 0; /* FIXME */ + } + | value_structure_field + { + $$ = 0; /* FIXME */ + } + | expression_conversion + { + $$ = 0; /* FIXME */ + } + | value_procedure_call + { + $$ = 0; /* FIXME */ + } + | value_built_in_routine_call + { + $$ = 0; /* FIXME */ + } + | start_expression + { + $$ = 0; /* FIXME */ + } + | zero_adic_operator + { + $$ = 0; /* FIXME */ + } + | parenthesised_expression + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.2 */ + +location_contents: location + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.3 */ + +value_name : synonym_name + { + $$ = 0; /* FIXME */ + } + | value_enumeration_name + { + $$ = 0; /* FIXME */ + } + | value_do_with_name + { + $$ = 0; /* FIXME */ + } + | value_receive_name + { + $$ = 0; /* FIXME */ + } + | GENERAL_PROCEDURE_NAME + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym ($1.sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + ; + +/* Z.200, 5.2.4.1 */ + +literal : INTEGER_LITERAL + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type ($1.type); + write_exp_elt_longcst ((LONGEST) ($1.val)); + write_exp_elt_opcode (OP_LONG); + } + | BOOLEAN_LITERAL + { + write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); + } + | CHARACTER_LITERAL + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type ($1.type); + write_exp_elt_longcst ((LONGEST) ($1.val)); + write_exp_elt_opcode (OP_LONG); + } + | FLOAT_LITERAL + { + write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); + } + | SET_LITERAL + { + $$ = 0; /* FIXME */ + } + | EMPTINESS_LITERAL + { + $$ = 0; /* FIXME */ + } + | CHARACTER_STRING_LITERAL + { + write_exp_elt_opcode (OP_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_STRING); + } + | BIT_STRING_LITERAL + { + write_exp_elt_opcode (OP_BITSTRING); + write_exp_bitstring ($1); + write_exp_elt_opcode (OP_BITSTRING); + } + ; + +/* Z.200, 5.2.5 */ + +tuple : FIXME_04 + { + $$ = 0; /* FIXME */ + } + ; + + +/* Z.200, 5.2.6 */ + +value_string_element: string_primitive_value '(' start_element ')' + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.7 */ + +value_string_slice: string_primitive_value '(' left_element ':' right_element ')' + { + $$ = 0; /* FIXME */ + } + | string_primitive_value '(' start_element UP slice_size ')' + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.8 */ + +value_array_element: array_primitive_value '(' + /* This is to save the value of arglist_len + being accumulated for each dimension. */ + { start_arglist (); } + expression_list ')' + { + write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); + } + ; + +/* Z.200, 5.2.9 */ + +value_array_slice: array_primitive_value '(' lower_element ':' upper_element ')' + { + $$ = 0; /* FIXME */ + } + | array_primitive_value '(' first_element UP slice_size ')' + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.10 */ + +value_structure_field: primitive_value FIELD_NAME + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($2); + write_exp_elt_opcode (STRUCTOP_STRUCT); + } + ; + +/* Z.200, 5.2.11 */ + +expression_conversion: mode_name parenthesised_expression + { + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($1.type); + write_exp_elt_opcode (UNOP_CAST); + } + ; + +/* Z.200, 5.2.12 */ + +value_procedure_call: FIXME_05 + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.13 */ + +value_built_in_routine_call: chill_value_built_in_routine_call + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.14 */ + +start_expression: FIXME_06 + { + $$ = 0; /* FIXME */ + } /* Not in GNU-Chill */ + ; + +/* Z.200, 5.2.15 */ + +zero_adic_operator: FIXME_07 + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.2.16 */ + +parenthesised_expression: '(' expression ')' + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.3.2 */ + +expression : operand_0 + { + $$ = 0; /* FIXME */ + } + | single_assignment_action + { + $$ = 0; /* FIXME */ + } + | conditional_expression + { + $$ = 0; /* FIXME */ + } + ; + +conditional_expression : IF boolean_expression then_alternative else_alternative FI + { + $$ = 0; /* FIXME */ + } + | CASE case_selector_list OF value_case_alternative '[' ELSE sub_expression ']' ESAC + { + $$ = 0; /* FIXME */ + } + ; + +then_alternative: THEN subexpression + { + $$ = 0; /* FIXME */ + } + ; + +else_alternative: ELSE subexpression + { + $$ = 0; /* FIXME */ + } + | ELSIF boolean_expression then_alternative else_alternative + { + $$ = 0; /* FIXME */ + } + ; + +sub_expression : expression + { + $$ = 0; /* FIXME */ + } + ; + +value_case_alternative: case_label_specification ':' sub_expression ';' + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.3.3 */ + +operand_0 : operand_1 + { + $$ = 0; /* FIXME */ + } + | operand_0 LOGIOR operand_1 + { + write_exp_elt_opcode (BINOP_BITWISE_IOR); + } + | operand_0 ORIF operand_1 + { + $$ = 0; /* FIXME */ + } + | operand_0 LOGXOR operand_1 + { + write_exp_elt_opcode (BINOP_BITWISE_XOR); + } + ; + +/* Z.200, 5.3.4 */ + +operand_1 : operand_2 + { + $$ = 0; /* FIXME */ + } + | operand_1 LOGAND operand_2 + { + write_exp_elt_opcode (BINOP_BITWISE_AND); + } + | operand_1 ANDIF operand_2 + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 5.3.5 */ + +operand_2 : operand_3 + { + $$ = 0; /* FIXME */ + } + | operand_2 '=' operand_3 + { + write_exp_elt_opcode (BINOP_EQUAL); + } + | operand_2 NOTEQUAL operand_3 + { + write_exp_elt_opcode (BINOP_NOTEQUAL); + } + | operand_2 '>' operand_3 + { + write_exp_elt_opcode (BINOP_GTR); + } + | operand_2 GTR operand_3 + { + write_exp_elt_opcode (BINOP_GEQ); + } + | operand_2 '<' operand_3 + { + write_exp_elt_opcode (BINOP_LESS); + } + | operand_2 LEQ operand_3 + { + write_exp_elt_opcode (BINOP_LEQ); + } + | operand_2 IN operand_3 + { + $$ = 0; /* FIXME */ + } + ; + + +/* Z.200, 5.3.6 */ + +operand_3 : operand_4 + { + $$ = 0; /* FIXME */ + } + | operand_3 '+' operand_4 + { + write_exp_elt_opcode (BINOP_ADD); + } + | operand_3 '-' operand_4 + { + write_exp_elt_opcode (BINOP_SUB); + } + | operand_3 SLASH_SLASH operand_4 + { + write_exp_elt_opcode (BINOP_CONCAT); + } + ; + +/* Z.200, 5.3.7 */ + +operand_4 : operand_5 + { + $$ = 0; /* FIXME */ + } + | operand_4 '*' operand_5 + { + write_exp_elt_opcode (BINOP_MUL); + } + | operand_4 '/' operand_5 + { + write_exp_elt_opcode (BINOP_DIV); + } + | operand_4 MOD operand_5 + { + write_exp_elt_opcode (BINOP_MOD); + } + | operand_4 REM operand_5 + { + write_exp_elt_opcode (BINOP_REM); + } + ; + +/* Z.200, 5.3.8 */ + +operand_5 : operand_6 + { + $$ = 0; /* FIXME */ + } + | '-' operand_6 + { + write_exp_elt_opcode (UNOP_NEG); + } + | NOT operand_6 + { + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + | parenthesised_expression literal +/* We require the string operand to be a literal, to avoid some + nasty parsing ambiguities. */ + { + write_exp_elt_opcode (BINOP_CONCAT); + } + ; + +/* Z.200, 5.3.9 */ + +operand_6 : POINTER location + { + write_exp_elt_opcode (UNOP_ADDR); + } + | RECEIVE buffer_location + { + $$ = 0; /* FIXME */ + } + | primitive_value + { + $$ = 0; /* FIXME */ + } + ; + + +/* Z.200, 6.2 */ + +single_assignment_action : + location GDB_ASSIGNMENT value + { + write_exp_elt_opcode (BINOP_ASSIGN); + } + ; + +/* Z.200, 6.20.3 */ + +chill_value_built_in_routine_call : + NUM '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | PRED '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | SUCC '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | ABS '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | CARD '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | MAX_TOKEN '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | MIN_TOKEN '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | SIZE '(' location ')' + { + $$ = 0; /* FIXME */ + } + | SIZE '(' mode_argument ')' + { + $$ = 0; /* FIXME */ + } + | UPPER '(' upper_lower_argument ')' + { + $$ = 0; /* FIXME */ + } + | LOWER '(' upper_lower_argument ')' + { + $$ = 0; /* FIXME */ + } + | LENGTH '(' length_argument ')' + { + $$ = 0; /* FIXME */ + } + ; + +mode_argument : mode_name + { + $$ = 0; /* FIXME */ + } + | array_mode_name '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | string_mode_name '(' expression ')' + { + $$ = 0; /* FIXME */ + } + | variant_structure_mode_name '(' expression_list ')' + { + $$ = 0; /* FIXME */ + } + ; + +mode_name : TYPENAME + ; + +upper_lower_argument : expression + { + $$ = 0; /* FIXME */ + } + | mode_name + { + $$ = 0; /* FIXME */ + } + ; + +length_argument : expression + { + $$ = 0; /* FIXME */ + } + ; + +/* Z.200, 12.4.3 */ + +array_primitive_value : primitive_value + { + $$ = 0; + } + ; + + +/* Things which still need productions... */ + +array_mode_name : FIXME_08 { $$ = 0; } +string_mode_name : FIXME_09 { $$ = 0; } +variant_structure_mode_name: FIXME_10 { $$ = 0; } +synonym_name : FIXME_11 { $$ = 0; } +value_enumeration_name : FIXME_12 { $$ = 0; } +value_do_with_name : FIXME_13 { $$ = 0; } +value_receive_name : FIXME_14 { $$ = 0; } +string_primitive_value : FIXME_15 { $$ = 0; } +start_element : FIXME_16 { $$ = 0; } +left_element : FIXME_17 { $$ = 0; } +right_element : FIXME_18 { $$ = 0; } +slice_size : FIXME_19 { $$ = 0; } +lower_element : FIXME_20 { $$ = 0; } +upper_element : FIXME_21 { $$ = 0; } +first_element : FIXME_22 { $$ = 0; } +boolean_expression : FIXME_26 { $$ = 0; } +case_selector_list : FIXME_27 { $$ = 0; } +subexpression : FIXME_28 { $$ = 0; } +case_label_specification: FIXME_29 { $$ = 0; } +buffer_location : FIXME_30 { $$ = 0; } + +%% + +/* Implementation of a dynamically expandable buffer for processing input + characters acquired through lexptr and building a value to return in + yylval. */ + +static char *tempbuf; /* Current buffer contents */ +static int tempbufsize; /* Size of allocated buffer */ +static int tempbufindex; /* Current index into buffer */ + +#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */ + +#define CHECKBUF(size) \ + do { \ + if (tempbufindex + (size) >= tempbufsize) \ + { \ + growbuf_by_size (size); \ + } \ + } while (0); + +/* Grow the static temp buffer if necessary, including allocating the first one + on demand. */ + +static void +growbuf_by_size (count) + int count; +{ + int growby; + + growby = max (count, GROWBY_MIN_SIZE); + tempbufsize += growby; + if (tempbuf == NULL) + { + tempbuf = (char *) malloc (tempbufsize); + } + else + { + tempbuf = (char *) realloc (tempbuf, tempbufsize); + } +} + +/* Try to consume a simple name string token. If successful, returns + a pointer to a nullbyte terminated copy of the name that can be used + in symbol table lookups. If not successful, returns NULL. */ + +static char * +match_simple_name_string () +{ + char *tokptr = lexptr; + + if (isalpha (*tokptr)) + { + char *result; + do { + tokptr++; + } while (isalnum (*tokptr) || (*tokptr == '_')); + yylval.sval.ptr = lexptr; + yylval.sval.length = tokptr - lexptr; + lexptr = tokptr; + result = copy_name (yylval.sval); + for (tokptr = result; *tokptr; tokptr++) + if (isupper (*tokptr)) + *tokptr = tolower(*tokptr); + return result; + } + return (NULL); +} + +/* Start looking for a value composed of valid digits as set by the base + in use. Note that '_' characters are valid anywhere, in any quantity, + and are simply ignored. Since we must find at least one valid digit, + or reject this token as an integer literal, we keep track of how many + digits we have encountered. */ + +static int +decode_integer_value (base, tokptrptr, ivalptr) + int base; + char **tokptrptr; + int *ivalptr; +{ + char *tokptr = *tokptrptr; + int temp; + int digits = 0; + + while (*tokptr != '\0') + { + temp = tolower (*tokptr); + tokptr++; + switch (temp) + { + case '_': + continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + temp -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + temp -= 'a'; + temp += 10; + break; + default: + temp = base; + break; + } + if (temp < base) + { + digits++; + *ivalptr *= base; + *ivalptr += temp; + } + else + { + /* Found something not in domain for current base. */ + tokptr--; /* Unconsume what gave us indigestion. */ + break; + } + } + + /* If we didn't find any digits, then we don't have a valid integer + value, so reject the entire token. Otherwise, update the lexical + scan pointer, and return non-zero for success. */ + + if (digits == 0) + { + return (0); + } + else + { + *tokptrptr = tokptr; + return (1); + } +} + +static int +decode_integer_literal (valptr, tokptrptr) + int *valptr; + char **tokptrptr; +{ + char *tokptr = *tokptrptr; + int base = 0; + int ival = 0; + int explicit_base = 0; + + /* Look for an explicit base specifier, which is optional. */ + + switch (*tokptr) + { + case 'd': + case 'D': + explicit_base++; + base = 10; + tokptr++; + break; + case 'b': + case 'B': + explicit_base++; + base = 2; + tokptr++; + break; + case 'h': + case 'H': + explicit_base++; + base = 16; + tokptr++; + break; + case 'o': + case 'O': + explicit_base++; + base = 8; + tokptr++; + break; + default: + base = 10; + break; + } + + /* If we found an explicit base ensure that the character after the + explicit base is a single quote. */ + + if (explicit_base && (*tokptr++ != '\'')) + { + return (0); + } + + /* Attempt to decode whatever follows as an integer value in the + indicated base, updating the token pointer in the process and + computing the value into ival. Also, if we have an explicit + base, then the next character must not be a single quote, or we + have a bitstring literal, so reject the entire token in this case. + Otherwise, update the lexical scan pointer, and return non-zero + for success. */ + + if (!decode_integer_value (base, &tokptr, &ival)) + { + return (0); + } + else if (explicit_base && (*tokptr == '\'')) + { + return (0); + } + else + { + *valptr = ival; + *tokptrptr = tokptr; + return (1); + } +} + +/* If it wasn't for the fact that floating point values can contain '_' + characters, we could just let strtod do all the hard work by letting it + try to consume as much of the current token buffer as possible and + find a legal conversion. Unfortunately we need to filter out the '_' + characters before calling strtod, which we do by copying the other + legal chars to a local buffer to be converted. However since we also + need to keep track of where the last unconsumed character in the input + buffer is, we have transfer only as many characters as may compose a + legal floating point value. */ + +static int +match_float_literal () +{ + char *tokptr = lexptr; + char *buf; + char *copy; + double dval; + extern double strtod (); + + /* Make local buffer in which to build the string to convert. This is + required because underscores are valid in chill floating point numbers + but not in the string passed to strtod to convert. The string will be + no longer than our input string. */ + + copy = buf = (char *) alloca (strlen (tokptr) + 1); + + /* Transfer all leading digits to the conversion buffer, discarding any + underscores. */ + + while (isdigit (*tokptr) || *tokptr == '_') + { + if (*tokptr != '_') + { + *copy++ = *tokptr; + } + tokptr++; + } + + /* Now accept either a '.', or one of [eEdD]. Dot is legal regardless + of whether we found any leading digits, and we simply accept it and + continue on to look for the fractional part and/or exponent. One of + [eEdD] is legal only if we have seen digits, and means that there + is no fractional part. If we find neither of these, then this is + not a floating point number, so return failure. */ + + switch (*tokptr++) + { + case '.': + /* Accept and then look for fractional part and/or exponent. */ + *copy++ = '.'; + break; + + case 'e': + case 'E': + case 'd': + case 'D': + if (copy == buf) + { + return (0); + } + *copy++ = 'e'; + goto collect_exponent; + break; + + default: + return (0); + break; + } + + /* We found a '.', copy any fractional digits to the conversion buffer, up + to the first nondigit, non-underscore character. */ + + while (isdigit (*tokptr) || *tokptr == '_') + { + if (*tokptr != '_') + { + *copy++ = *tokptr; + } + tokptr++; + } + + /* Look for an exponent, which must start with one of [eEdD]. If none + is found, jump directly to trying to convert what we have collected + so far. */ + + switch (*tokptr) + { + case 'e': + case 'E': + case 'd': + case 'D': + *copy++ = 'e'; + tokptr++; + break; + default: + goto convert_float; + break; + } + + /* Accept an optional '-' or '+' following one of [eEdD]. */ + + collect_exponent: + if (*tokptr == '+' || *tokptr == '-') + { + *copy++ = *tokptr++; + } + + /* Now copy an exponent into the conversion buffer. Note that at the + moment underscores are *not* allowed in exponents. */ + + while (isdigit (*tokptr)) + { + *copy++ = *tokptr++; + } + + /* If we transfered any chars to the conversion buffer, try to interpret its + contents as a floating point value. If any characters remain, then we + must not have a valid floating point string. */ + + convert_float: + *copy = '\0'; + if (copy != buf) + { + dval = strtod (buf, ©); + if (*copy == '\0') + { + yylval.dval = dval; + lexptr = tokptr; + return (FLOAT_LITERAL); + } + } + return (0); +} + +/* Recognize a string literal. A string literal is a nonzero sequence + of characters enclosed in matching single or double quotes, except that + a single character inside single quotes is a character literal, which + we reject as a string literal. To embed the terminator character inside + a string, it is simply doubled (I.E. "this""is""one""string") */ + +static int +match_string_literal () +{ + char *tokptr = lexptr; + + for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++) + { + CHECKBUF (1); + if (*tokptr == *lexptr) + { + if (*(tokptr + 1) == *lexptr) + { + tokptr++; + } + else + { + break; + } + } + tempbuf[tempbufindex++] = *tokptr; + } + if (*tokptr == '\0' /* no terminator */ + || tempbufindex == 0 /* no string */ + || (tempbufindex == 1 && *tokptr == '\'')) /* char literal */ + { + return (0); + } + else + { + tempbuf[tempbufindex] = '\0'; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = ++tokptr; + return (CHARACTER_STRING_LITERAL); + } +} + +/* Recognize a character literal. A character literal is single character + or a control sequence, enclosed in single quotes. A control sequence + is a comma separated list of one or more integer literals, enclosed + in parenthesis and introduced with a circumflex character. + + EX: 'a' '^(7)' '^(7,8)' + + As a GNU chill extension, the syntax C'xx' is also recognized as a + character literal, where xx is a hex value for the character. + + Note that more than a single character, enclosed in single quotes, is + a string literal. + + Also note that the control sequence form is not in GNU Chill since it + is ambiguous with the string literal form using single quotes. I.E. + is '^(7)' a character literal or a string literal. In theory it it + possible to tell by context, but GNU Chill doesn't accept the control + sequence form, so neither do we (for now the code is disabled). + + Returns CHARACTER_LITERAL if a match is found. + */ + +static int +match_character_literal () +{ + char *tokptr = lexptr; + int ival = 0; + + if ((tolower (*tokptr) == 'c') && (*(tokptr + 1) == '\'')) + { + /* We have a GNU chill extension form, so skip the leading "C'", + decode the hex value, and then ensure that we have a trailing + single quote character. */ + tokptr += 2; + if (!decode_integer_value (16, &tokptr, &ival) || (*tokptr != '\'')) + { + return (0); + } + tokptr++; + } + else if (*tokptr == '\'') + { + tokptr++; + + /* Determine which form we have, either a control sequence or the + single character form. */ + + if ((*tokptr == '^') && (*(tokptr + 1) == '(')) + { +#if 0 /* Disable, see note above. -fnf */ + /* Match and decode a control sequence. Return zero if we don't + find a valid integer literal, or if the next unconsumed character + after the integer literal is not the trailing ')'. + FIXME: We currently don't handle the multiple integer literal + form. */ + tokptr += 2; + if (!decode_integer_literal (&ival, &tokptr) || (*tokptr++ != ')')) + { + return (0); + } +#else + return (0); +#endif + } + else + { + ival = *tokptr++; + } + + /* The trailing quote has not yet been consumed. If we don't find + it, then we have no match. */ + + if (*tokptr++ != '\'') + { + return (0); + } + } + else + { + /* Not a character literal. */ + return (0); + } + yylval.typed_val.val = ival; + yylval.typed_val.type = builtin_type_chill_char; + lexptr = tokptr; + return (CHARACTER_LITERAL); +} + +/* Recognize an integer literal, as specified in Z.200 sec 5.2.4.2. + Note that according to 5.2.4.2, a single "_" is also a valid integer + literal, however GNU-chill requires there to be at least one "digit" + in any integer literal. */ + +static int +match_integer_literal () +{ + char *tokptr = lexptr; + int ival; + + if (!decode_integer_literal (&ival, &tokptr)) + { + return (0); + } + else + { + yylval.typed_val.val = ival; + yylval.typed_val.type = builtin_type_int; + lexptr = tokptr; + return (INTEGER_LITERAL); + } +} + +/* Recognize a bit-string literal, as specified in Z.200 sec 5.2.4.8 + Note that according to 5.2.4.8, a single "_" is also a valid bit-string + literal, however GNU-chill requires there to be at least one "digit" + in any bit-string literal. */ + +static int +match_bitstring_literal () +{ + char *tokptr = lexptr; + int mask; + int bitoffset = 0; + int bitcount = 0; + int base; + int digit; + + tempbufindex = 0; + + /* Look for the required explicit base specifier. */ + + switch (*tokptr++) + { + case 'b': + case 'B': + base = 2; + break; + case 'o': + case 'O': + base = 8; + break; + case 'h': + case 'H': + base = 16; + break; + default: + return (0); + break; + } + + /* Ensure that the character after the explicit base is a single quote. */ + + if (*tokptr++ != '\'') + { + return (0); + } + + while (*tokptr != '\0' && *tokptr != '\'') + { + digit = tolower (*tokptr); + tokptr++; + switch (digit) + { + case '_': + continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + digit -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + digit -= 'a'; + digit += 10; + break; + default: + return (0); + break; + } + if (digit >= base) + { + /* Found something not in domain for current base. */ + return (0); + } + else + { + /* Extract bits from digit, starting with the msbit appropriate for + the current base, and packing them into the bitstring byte, + starting at the lsbit. */ + for (mask = (base >> 1); mask > 0; mask >>= 1) + { + bitcount++; + CHECKBUF (1); + if (digit & mask) + { + tempbuf[tempbufindex] |= (1 << bitoffset); + } + bitoffset++; + if (bitoffset == HOST_CHAR_BIT) + { + bitoffset = 0; + tempbufindex++; + } + } + } + } + + /* Verify that we consumed everything up to the trailing single quote, + and that we found some bits (IE not just underbars). */ + + if (*tokptr++ != '\'') + { + return (0); + } + else + { + yylval.sval.ptr = tempbuf; + yylval.sval.length = bitcount; + lexptr = tokptr; + return (BIT_STRING_LITERAL); + } +} + +/* Recognize tokens that start with '$'. These include: + + $regname A native register name or a "standard + register name". + Return token GDB_REGNAME. + + $variable A convenience variable with a name chosen + by the user. + Return token GDB_VARIABLE. + + $digits Value history with index , starting + from the first value which has index 1. + Return GDB_LAST. + + $$digits Value history with index relative + to the last value. I.E. $$0 is the last + value, $$1 is the one previous to that, $$2 + is the one previous to $$1, etc. + Return token GDB_LAST. + + $ | $0 | $$0 The last value in the value history. + Return token GDB_LAST. + + $$ An abbreviation for the second to the last + value in the value history, I.E. $$1 + Return token GDB_LAST. + + Note that we currently assume that register names and convenience + variables follow the convention of starting with a letter or '_'. + + */ + +static int +match_dollar_tokens () +{ + char *tokptr; + int regno; + int namelength; + int negate; + int ival; + + /* We will always have a successful match, even if it is just for + a single '$', the abbreviation for $$0. So advance lexptr. */ + + tokptr = ++lexptr; + + if (*tokptr == '_' || isalpha (*tokptr)) + { + /* Look for a match with a native register name, usually something + like "r0" for example. */ + + for (regno = 0; regno < NUM_REGS; regno++) + { + namelength = strlen (reg_names[regno]); + if (STREQN (tokptr, reg_names[regno], namelength) + && !isalnum (tokptr[namelength])) + { + yylval.lval = regno; + lexptr += namelength + 1; + return (GDB_REGNAME); + } + } + + /* Look for a match with a standard register name, usually something + like "pc", which gdb always recognizes as the program counter + regardless of what the native register name is. */ + + for (regno = 0; regno < num_std_regs; regno++) + { + namelength = strlen (std_regs[regno].name); + if (STREQN (tokptr, std_regs[regno].name, namelength) + && !isalnum (tokptr[namelength])) + { + yylval.lval = std_regs[regno].regnum; + lexptr += namelength; + return (GDB_REGNAME); + } + } + + /* Attempt to match against a convenience variable. Note that + this will always succeed, because if no variable of that name + already exists, the lookup_internalvar will create one for us. + Also note that both lexptr and tokptr currently point to the + start of the input string we are trying to match, and that we + have already tested the first character for non-numeric, so we + don't have to treat it specially. */ + + while (*tokptr == '_' || isalnum (*tokptr)) + { + tokptr++; + } + yylval.sval.ptr = lexptr; + yylval.sval.length = tokptr - lexptr; + yylval.ivar = lookup_internalvar (copy_name (yylval.sval)); + lexptr = tokptr; + return (GDB_VARIABLE); + } + + /* Since we didn't match against a register name or convenience + variable, our only choice left is a history value. */ + + if (*tokptr == '$') + { + negate = 1; + ival = 1; + tokptr++; + } + else + { + negate = 0; + ival = 0; + } + + /* Attempt to decode more characters as an integer value giving + the index in the history list. If successful, the value will + overwrite ival (currently 0 or 1), and if not, ival will be + left alone, which is good since it is currently correct for + the '$' or '$$' case. */ + + decode_integer_literal (&ival, &tokptr); + yylval.lval = negate ? -ival : ival; + lexptr = tokptr; + return (GDB_LAST); +} + +struct token +{ + char *operator; + int token; +}; + +static const struct token idtokentab[] = +{ + { "length", LENGTH }, + { "lower", LOWER }, + { "upper", UPPER }, + { "andif", ANDIF }, + { "pred", PRED }, + { "succ", SUCC }, + { "card", CARD }, + { "size", SIZE }, + { "orif", ORIF }, + { "num", NUM }, + { "abs", ABS }, + { "max", MAX_TOKEN }, + { "min", MIN_TOKEN }, + { "mod", MOD }, + { "rem", REM }, + { "not", NOT }, + { "xor", LOGXOR }, + { "and", LOGAND }, + { "in", IN }, + { "or", LOGIOR } +}; + +static const struct token tokentab2[] = +{ + { ":=", GDB_ASSIGNMENT }, + { "//", SLASH_SLASH }, + { "->", POINTER }, + { "/=", NOTEQUAL }, + { "<=", LEQ }, + { ">=", GTR } +}; + +/* Read one token, getting characters through lexptr. */ +/* This is where we will check to make sure that the language and the + operators used are compatible. */ + +static int +yylex () +{ + unsigned int i; + int token; + char *simplename; + struct symbol *sym; + + /* Skip over any leading whitespace. */ + while (isspace (*lexptr)) + { + lexptr++; + } + /* Look for special single character cases which can't be the first + character of some other multicharacter token. */ + switch (*lexptr) + { + case '\0': + return (0); + case ',': + case '=': + case ';': + case '!': + case '+': + case '*': + case '(': + case ')': + case '[': + case ']': + return (*lexptr++); + } + /* Look for characters which start a particular kind of multicharacter + token, such as a character literal, register name, convenience + variable name, string literal, etc. */ + switch (*lexptr) + { + case '\'': + case '\"': + /* First try to match a string literal, which is any nonzero + sequence of characters enclosed in matching single or double + quotes, except that a single character inside single quotes + is a character literal, so we have to catch that case also. */ + token = match_string_literal (); + if (token != 0) + { + return (token); + } + if (*lexptr == '\'') + { + token = match_character_literal (); + if (token != 0) + { + return (token); + } + } + break; + case 'C': + case 'c': + token = match_character_literal (); + if (token != 0) + { + return (token); + } + break; + case '$': + token = match_dollar_tokens (); + if (token != 0) + { + return (token); + } + break; + } + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++) + { + if (STREQN (lexptr, tokentab2[i].operator, 2)) + { + lexptr += 2; + return (tokentab2[i].token); + } + } + /* Look for single character cases which which could be the first + character of some other multicharacter token, but aren't, or we + would already have found it. */ + switch (*lexptr) + { + case '-': + case ':': + case '/': + case '<': + case '>': + return (*lexptr++); + } + /* Look for a float literal before looking for an integer literal, so + we match as much of the input stream as possible. */ + token = match_float_literal (); + if (token != 0) + { + return (token); + } + token = match_bitstring_literal (); + if (token != 0) + { + return (token); + } + token = match_integer_literal (); + if (token != 0) + { + return (token); + } + + /* Try to match a simple name string, and if a match is found, then + further classify what sort of name it is and return an appropriate + token. Note that attempting to match a simple name string consumes + the token from lexptr, so we can't back out if we later find that + we can't classify what sort of name it is. */ + + simplename = match_simple_name_string (); + + if (simplename != NULL) + { + /* See if it is a reserved identifier. */ + for (i = 0; i < sizeof (idtokentab) / sizeof (idtokentab[0]); i++) + { + if (STREQ (simplename, idtokentab[i].operator)) + { + return (idtokentab[i].token); + } + } + + /* Look for other special tokens. */ + if (STREQ (simplename, "true")) + { + yylval.ulval = 1; + return (BOOLEAN_LITERAL); + } + if (STREQ (simplename, "false")) + { + yylval.ulval = 0; + return (BOOLEAN_LITERAL); + } + + sym = lookup_symbol (simplename, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym != NULL) + { + yylval.ssym.stoken.ptr = NULL; + yylval.ssym.stoken.length = 0; + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = 0; /* FIXME, C++'ism */ + switch (SYMBOL_CLASS (sym)) + { + case LOC_BLOCK: + /* Found a procedure name. */ + return (GENERAL_PROCEDURE_NAME); + case LOC_STATIC: + /* Found a global or local static variable. */ + return (LOCATION_NAME); + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + if (innermost_block == NULL + || contained_in (block_found, innermost_block)) + { + innermost_block = block_found; + } + return (LOCATION_NAME); + break; + case LOC_CONST: + case LOC_LABEL: + return (LOCATION_NAME); + break; + case LOC_TYPEDEF: + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + case LOC_UNDEF: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + error ("Symbol \"%s\" names no location.", simplename); + break; + } + } + else if (!have_full_symbols () && !have_partial_symbols ()) + { + error ("No symbol table is loaded. Use the \"file\" command."); + } + else + { + error ("No symbol \"%s\" in current context.", simplename); + } + } + + /* Catch single character tokens which are not part of some + longer token. */ + + switch (*lexptr) + { + case '.': /* Not float for example. */ + lexptr++; + while (isspace (*lexptr)) lexptr++; + simplename = match_simple_name_string (); + if (!simplename) + return '.'; + return FIELD_NAME; + } + + return (ILLEGAL_TOKEN); +} + +void +yyerror (msg) + char *msg; /* unused */ +{ + printf ("Parsing: %s\n", lexptr); + if (yychar < 256) + { + error ("Invalid syntax in expression near character '%c'.", yychar); + } + else + { + error ("Invalid syntax in expression"); + } +} diff --git a/gnu/usr.bin/gdb/gdb/ch-lang.c b/gnu/usr.bin/gdb/gdb/ch-lang.c new file mode 100644 index 00000000000..2f7406103d0 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ch-lang.c @@ -0,0 +1,341 @@ +/* Chill language support routines for GDB, the GNU debugger. + Copyright 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "ch-lang.h" + + +/* For now, Chill uses a simple mangling algorithm whereby you simply + discard everything after the occurance of two successive CPLUS_MARKER + characters to derive the demangled form. */ + +char * +chill_demangle (mangled) + const char *mangled; +{ + char *joiner; + char *demangled; + + joiner = strchr (mangled, CPLUS_MARKER); + if (joiner != NULL && *(joiner + 1) == CPLUS_MARKER) + { + demangled = savestring (mangled, joiner - mangled); + } + else + { + demangled = NULL; + } + return (demangled); +} + +static void +chill_printchar (c, stream) + register int c; + FILE *stream; +{ + c &= 0xFF; /* Avoid sign bit follies */ + + if (PRINT_LITERAL_FORM (c)) + { + fprintf_filtered (stream, "'%c'", c); + } + else + { + fprintf_filtered (stream, "C'%.2x'", (unsigned int) c); + } +} + +/* Print the character string STRING, printing at most LENGTH characters. + Printing stops early if the number hits print_max; repeat counts + are printed as appropriate. Print ellipses at the end if we + had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. + Note that gdb maintains the length of strings without counting the + terminating null byte, while chill strings are typically written with + an explicit null byte. So we always assume an implied null byte + until gdb is able to maintain non-null terminated strings as well + as null terminated strings (FIXME). + */ + +static void +chill_printstr (stream, string, length, force_ellipses) + FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_literal_form = 0; + int in_control_form = 0; + int need_slashslash = 0; + unsigned int c; + extern int repeat_count_threshold; + extern int print_max; + + if (length == 0) + { + chill_printchar ('\0', stream); + return; + } + + for (i = 0; i < length && things_printed < print_max; ++i) + { + /* Position of the character we are examining + to see whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + QUIT; + + if (need_slashslash) + { + fputs_filtered ("//", stream); + need_slashslash = 0; + } + + rep1 = i + 1; + reps = 1; + while (rep1 < length && string[rep1] == string[i]) + { + ++rep1; + ++reps; + } + + c = string[i]; + if (reps > repeat_count_threshold) + { + if (in_control_form || in_literal_form) + { + fputs_filtered ("'//", stream); + in_control_form = in_literal_form = 0; + } + chill_printchar (c, stream); + fprintf_filtered (stream, "", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_slashslash = 1; + } + else + { + if (PRINT_LITERAL_FORM (c)) + { + if (!in_literal_form) + { + if (in_control_form) + { + fputs_filtered ("'//", stream); + in_control_form = 0; + } + fputs_filtered ("'", stream); + in_literal_form = 1; + } + fprintf_filtered (stream, "%c", c); + } + else + { + if (!in_control_form) + { + if (in_literal_form) + { + fputs_filtered ("'//", stream); + in_literal_form = 0; + } + fputs_filtered ("c'", stream); + in_control_form = 1; + } + fprintf_filtered (stream, "%.2x", c); + } + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_literal_form || in_control_form) + { + fputs_filtered ("'", stream); + } + if (force_ellipses || (i < length)) + { + fputs_filtered ("...", stream); + } +} + +static struct type * +chill_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, 2, 0, "", objfile); + warning ("internal error: no chill fundamental type %d", typeid); + break; + case FT_VOID: + /* FIXME: Currently the GNU Chill compiler emits some DWARF entries for + typedefs, unrelated to anything directly in the code being compiled, + that have some FT_VOID types. Just fake it for now. */ + type = init_type (TYPE_CODE_VOID, 0, 0, "", objfile); + break; + case FT_BOOLEAN: + type = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED, "BOOL", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED, "CHAR", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_SIGNED, "BYTE", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, "UBYTE", objfile); + break; + case FT_SHORT: /* Chill ints are 2 bytes */ + type = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_SIGNED, "INT", objfile); + break; + case FT_UNSIGNED_SHORT: /* Chill ints are 2 bytes */ + type = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, "UINT", objfile); + break; + case FT_INTEGER: /* FIXME? */ + case FT_SIGNED_INTEGER: /* FIXME? */ + case FT_LONG: /* Chill longs are 4 bytes */ + case FT_SIGNED_LONG: /* Chill longs are 4 bytes */ + type = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_SIGNED, "LONG", objfile); + break; + case FT_UNSIGNED_INTEGER: /* FIXME? */ + case FT_UNSIGNED_LONG: /* Chill longs are 4 bytes */ + type = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, "ULONG", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, 4, 0, "REAL", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, 8, 0, "LONG_REAL", objfile); + break; + } + return (type); +} + + +/* Table of operators and their precedences for printing expressions. */ + +static const struct op_print chill_op_print_tab[] = { + {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"MOD", BINOP_MOD, PREC_MUL, 0}, + {"REM", BINOP_REM, PREC_MUL, 0}, + {":=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"=", BINOP_EQUAL, PREC_EQUAL, 0}, + {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"//", BINOP_CONCAT, PREC_PREFIX, 0}, /* FIXME: precedence? */ + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {NULL, 0, 0, 0} +}; + + +/* The built-in types of Chill. */ + +struct type *builtin_type_chill_bool; +struct type *builtin_type_chill_char; +struct type *builtin_type_chill_long; +struct type *builtin_type_chill_ulong; +struct type *builtin_type_chill_real; + +struct type ** const (chill_builtin_types[]) = +{ + &builtin_type_chill_bool, + &builtin_type_chill_char, + &builtin_type_chill_long, + &builtin_type_chill_ulong, + &builtin_type_chill_real, + 0 +}; + +const struct language_defn chill_language_defn = { + "chill", + language_chill, + chill_builtin_types, + range_check_on, + type_check_on, + chill_parse, /* parser */ + chill_error, /* parser error function */ + chill_printchar, /* print a character constant */ + chill_printstr, /* function to print a string constant */ + chill_create_fundamental_type,/* Create fundamental type in this language */ + chill_print_type, /* Print a type using appropriate syntax */ + chill_val_print, /* Print a value using appropriate syntax */ + &BUILTIN_TYPE_LONGEST, /* longest signed integral type */ + &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */ + &builtin_type_chill_real, /* longest floating point type */ + {"", "B'", "", ""}, /* Binary format info */ + {"O'%lo", "O'", "o", ""}, /* Octal format info */ + {"D'%ld", "D'", "d", ""}, /* Decimal format info */ + {"H'%lx", "H'", "x", ""}, /* Hex format info */ + chill_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +/* Initialization for Chill */ + +void +_initialize_chill_language () +{ + builtin_type_chill_bool = + init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "BOOL", (struct objfile *) NULL); + builtin_type_chill_char = + init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "CHAR", (struct objfile *) NULL); + builtin_type_chill_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, + "LONG", (struct objfile *) NULL); + builtin_type_chill_ulong = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "ULONG", (struct objfile *) NULL); + builtin_type_chill_real = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "LONG_REAL", (struct objfile *) NULL); + + add_language (&chill_language_defn); +} diff --git a/gnu/usr.bin/gdb/gdb/ch-lang.h b/gnu/usr.bin/gdb/gdb/ch-lang.h new file mode 100644 index 00000000000..13579d9d47c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ch-lang.h @@ -0,0 +1,31 @@ +/* Chill language support definitions for GDB, the GNU debugger. + Copyright 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. */ + +extern int +chill_parse PARAMS ((void)); /* Defined in ch-exp.y */ + +extern void +chill_error PARAMS ((char *)); /* Defined in ch-exp.y */ + +extern void /* Defined in ch-typeprint.c */ +chill_print_type PARAMS ((struct type *, char *, FILE *, int, int)); + +extern int +chill_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, + int, enum val_prettyprint)); diff --git a/gnu/usr.bin/gdb/gdb/ch-typeprint.c b/gnu/usr.bin/gdb/gdb/ch-typeprint.c new file mode 100644 index 00000000000..c3cdcd2a188 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ch-typeprint.c @@ -0,0 +1,225 @@ +/* Support for printing Chill types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "ch-lang.h" + +#include +#include + +static void +chill_type_print_base PARAMS ((struct type *, FILE *, int, int)); + +void +chill_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + FILE *stream; + int show; + int level; +{ + if (varstring != NULL && *varstring != '\0') + { + fputs_filtered (varstring, stream); + fputs_filtered (" ", stream); + } + chill_type_print_base (type, stream, show, level); +} + +/* Print the name of the type (or the ultimate pointer target, + function value or array element). + + SHOW nonzero means don't print this type as just its name; + show its real definition even if it has a name. + SHOW zero means print just typename or tag if there is one + SHOW negative means abbreviate structure elements. + SHOW is decremented for printing of structure elements. + + LEVEL is the depth to indent by. + We increase it for some recursive calls. */ + +static void +chill_type_print_base (type, stream, show, level) + struct type *type; + FILE *stream; + int show; + int level; +{ + char *name; + register int len; + register int i; + struct type *index_type; + struct type *range_type; + LONGEST low_bound; + LONGEST high_bound; + + QUIT; + + wrap_here (" "); + if (type == NULL) + { + fputs_filtered ("", stream); + return; + } + + /* When SHOW is zero or less, and there is a valid type name, then always + just print the type name directly from the type. */ + + if ((show <= 0) && (TYPE_NAME (type) != NULL)) + { + fputs_filtered (TYPE_NAME (type), stream); + return; + } + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID) + { + fprintf_filtered (stream, "PTR"); + break; + } + fprintf_filtered (stream, "REF "); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_ARRAY: + range_type = TYPE_FIELD_TYPE (type, 0); + index_type = TYPE_TARGET_TYPE (range_type); + low_bound = TYPE_FIELD_BITPOS (range_type, 0); + high_bound = TYPE_FIELD_BITPOS (range_type, 1); + fputs_filtered ("ARRAY (", stream); + print_type_scalar (index_type, low_bound, stream); + fputs_filtered (":", stream); + print_type_scalar (index_type, high_bound, stream); + fputs_filtered (") ", stream); + chill_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level); + break; + + case TYPE_CODE_STRING: + range_type = TYPE_FIELD_TYPE (type, 0); + index_type = TYPE_TARGET_TYPE (range_type); + high_bound = TYPE_FIELD_BITPOS (range_type, 1); + fputs_filtered ("CHAR (", stream); + print_type_scalar (index_type, high_bound + 1, stream); + fputs_filtered (")", stream); + break; + + case TYPE_CODE_MEMBER: + fprintf_filtered (stream, "MEMBER "); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + case TYPE_CODE_REF: + fprintf_filtered (stream, "/*LOC*/ "); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + case TYPE_CODE_FUNC: + fprintf_filtered (stream, "PROC (?)"); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_STRUCT: + fprintf_filtered (stream, "STRUCT "); + if ((name = type_name_no_tag (type)) != NULL) + { + fputs_filtered (name, stream); + fputs_filtered (" ", stream); + wrap_here (" "); + } + if (show < 0) + { + fprintf_filtered (stream, "(...)"); + } + else + { + check_stub_type (type); + fprintf_filtered (stream, "(\n"); + if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0)) + { + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + fprintfi_filtered (level + 4, stream, "\n"); + } + else + { + fprintfi_filtered (level + 4, stream, "\n"); + } + } + else + { + len = TYPE_NFIELDS (type); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + QUIT; + print_spaces_filtered (level + 4, stream); + chill_print_type (TYPE_FIELD_TYPE (type, i), + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 4); + if (i < (len - 1)) + { + fputs_filtered (",", stream); + } + fputs_filtered ("\n", stream); + } + } + fprintfi_filtered (level, stream, ")"); + } + break; + + case TYPE_CODE_VOID: + case TYPE_CODE_UNDEF: + case TYPE_CODE_ERROR: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + case TYPE_CODE_UNION: + case TYPE_CODE_METHOD: + error ("missing language support in chill_type_print_base"); + break; + + default: + + /* Handle types not explicitly handled by the other cases, + such as fundamental types. For these, just print whatever + the type name is, as recorded in the type itself. If there + is no type name, then complain. */ + + if (TYPE_NAME (type) != NULL) + { + fputs_filtered (TYPE_NAME (type), stream); + } + else + { + error ("Unrecognized type code (%d) in symbol table.", + TYPE_CODE (type)); + } + break; + } +} diff --git a/gnu/usr.bin/gdb/gdb/ch-valprint.c b/gnu/usr.bin/gdb/gdb/ch-valprint.c new file mode 100644 index 00000000000..261b22ee62c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ch-valprint.c @@ -0,0 +1,332 @@ +/* Support for printing Chill values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "valprint.h" +#include "expression.h" +#include "value.h" +#include "language.h" +#include "demangle.h" + +static void +chill_print_value_fields PARAMS ((struct type *, char *, FILE *, int, int, + enum val_prettyprint, struct type **)); + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter or 0 for natural format). The data at VALADDR is in + target byte order. + + If the data are a string pointer, returns the number of string characters + printed. + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. */ + +int +chill_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + LONGEST val; + unsigned int i = 0; /* Number of characters printed. */ + struct type *elttype; + CORE_ADDR addr; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + { + if (prettyprint_arrays) + { + print_spaces_filtered (2 + 2 * recurse, stream); + } + fprintf_filtered (stream, "["); + val_print_array_elements (type, valaddr, address, stream, format, + deref_ref, recurse, pretty, 0); + fprintf_filtered (stream, "]"); + } + else + { + error ("unimplemented in chill_val_print; unspecified array length"); + } + break; + + case TYPE_CODE_INT: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + val_print_type_code_int (type, valaddr, stream); + } + break; + + case TYPE_CODE_CHAR: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), + stream); + } + break; + + case TYPE_CODE_FLT: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + print_floating (valaddr, type, stream); + } + break; + + case TYPE_CODE_BOOL: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + val = unpack_long (builtin_type_chill_bool, valaddr); + fprintf_filtered (stream, val ? "TRUE" : "FALSE"); + } + break; + + case TYPE_CODE_UNDEF: + /* This happens (without TYPE_FLAG_STUB set) on systems which don't use + dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar" + and no complete type for struct foo in that file. */ + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_PTR: + if (format && format != 's') + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + addr = unpack_pointer (type, valaddr); + elttype = TYPE_TARGET_TYPE (type); + + if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) + { + /* Try to print what function it points to. */ + print_address_demangle (addr, stream, demangle); + /* Return value is irrelevant except for string pointers. */ + return (0); + } + if (addressprint && format != 's') + { + fprintf_filtered (stream, "H'%lx", (unsigned long) addr); + } + + /* For a pointer to char or unsigned char, also print the string + pointed to, unless pointer is null. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_CHAR + && (format == 0 || format == 's') + && addr != 0 + && /* If print_max is UINT_MAX, the alloca below will fail. + In that case don't try to print the string. */ + print_max < UINT_MAX) + { + i = val_print_string (addr, 0, stream); + } + /* Return number of characters printed, plus one for the + terminating null if we have "reached the end". */ + return (i + (print_max && i != print_max)); + break; + + case TYPE_CODE_STRING: + if (format && format != 's') + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + if (addressprint && format != 's') + { + /* This used to say `addr', which is unset at this point. + Is `address' what is meant? */ + fprintf_filtered (stream, "H'%lx ", (unsigned long) address); + } + i = TYPE_LENGTH (type); + LA_PRINT_STRING (stream, valaddr, i, 0); + /* Return number of characters printed, plus one for the terminating + null if we have "reached the end". */ + return (i + (print_max && i != print_max)); + break; + + case TYPE_CODE_STRUCT: + chill_print_value_fields (type, valaddr, stream, format, recurse, pretty, + 0); + break; + + case TYPE_CODE_REF: + if (addressprint) + { + fprintf_filtered (stream, "LOC(H'%lx)", + unpack_long (builtin_type_int, valaddr)); + if (deref_ref) + fputs_filtered (": ", stream); + } + /* De-reference the reference. */ + if (deref_ref) + { + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF) + { + value deref_val = + value_at + (TYPE_TARGET_TYPE (type), + unpack_pointer (lookup_pointer_type (builtin_type_void), + valaddr)); + val_print (VALUE_TYPE (deref_val), + VALUE_CONTENTS (deref_val), + VALUE_ADDRESS (deref_val), stream, format, + deref_ref, recurse + 1, pretty); + } + else + fputs_filtered ("???", stream); + } + break; + + case TYPE_CODE_ENUM: + c_val_print (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + break; + + case TYPE_CODE_MEMBER: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_RANGE: + default: + /* Let's derfer printing to the C printer, rather than + print an error message. FIXME! */ + c_val_print (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + } + fflush (stream); + return (0); +} + +/* Mutually recursive subroutines of cplus_print_value and c_val_print to + print out a structure's fields: cp_print_value_fields and cplus_print_value. + + TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the + same meanings as in cplus_print_value and c_val_print. + + DONT_PRINT is an array of baseclass types that we + should not print, or zero if called from top level. */ + +static void +chill_print_value_fields (type, valaddr, stream, format, recurse, pretty, + dont_print) + struct type *type; + char *valaddr; + FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; + struct type **dont_print; +{ + int i, len; + int fields_seen = 0; + + check_stub_type (type); + + fprintf_filtered (stream, "["); + len = TYPE_NFIELDS (type); + if (len == 0) + { + fprintf_filtered (stream, ""); + } + else + { + for (i = 0; i < len; i++) + { + if (fields_seen) + { + fprintf_filtered (stream, ", "); + } + fields_seen = 1; + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + wrap_here (n_spaces (2 + 2 * recurse)); + } + fputs_filtered (".", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_chill, DMGL_NO_OPTS); + fputs_filtered (": ", stream); + if (TYPE_FIELD_PACKED (type, i)) + { + value v; + + /* Bitfields require special handling, especially due to byte + order problems. */ + v = value_from_longest (TYPE_FIELD_TYPE (type, i), + unpack_field_as_long (type, valaddr, i)); + + chill_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0, + stream, format, 0, recurse + 1, pretty); + } + else + { + chill_val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, 0, recurse + 1, pretty); + } + } + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + } + fprintf_filtered (stream, "]"); +} + diff --git a/gnu/usr.bin/gdb/gdb/coff/ecoff.h b/gnu/usr.bin/gdb/gdb/coff/ecoff.h new file mode 100644 index 00000000000..8c7cee243ea --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coff/ecoff.h @@ -0,0 +1,262 @@ +#ifndef ECOFF_H +#define ECOFF_H + +/* Generic ECOFF support. + This does not include symbol information, found in sym.h and + symconst.h. */ + +/* Mips magic numbers used in filehdr. MIPS_MAGIC_LITTLE is used on + little endian machines. MIPS_MAGIC_BIG is used on big endian + machines. Where is MIPS_MAGIC_1 from? */ +#define MIPS_MAGIC_1 0x0180 +#define MIPS_MAGIC_LITTLE 0x0162 +#define MIPS_MAGIC_BIG 0x0160 + +/* These are the magic numbers used for MIPS code compiled at ISA + level 2. */ +#define MIPS_MAGIC_LITTLE2 0x0166 +#define MIPS_MAGIC_BIG2 0x0163 + +/* These are the magic numbers used for MIPS code compiled at ISA + level 3. */ +#define MIPS_MAGIC_LITTLE3 0x142 +#define MIPS_MAGIC_BIG3 0x140 + +/* Alpha magic numbers used in filehdr. */ +#define ALPHA_MAGIC 0x183 + +/* Magic numbers used in a.out header. */ +#define ECOFF_AOUT_OMAGIC 0407 /* not demand paged (ld -N). */ +#define ECOFF_AOUT_ZMAGIC 0413 /* demand load format, eg normal ld output */ + +/* Names of special sections. */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _RDATA ".rdata" +#define _SDATA ".sdata" +#define _SBSS ".sbss" +#define _LIT4 ".lit4" +#define _LIT8 ".lit8" +#define _LIB ".lib" +#define _INIT ".init" +#define _FINI ".fini" + +/* ECOFF uses some additional section flags. */ +#define STYP_RDATA 0x100 +#define STYP_SDATA 0x200 +#define STYP_SBSS 0x400 +#define STYP_ECOFF_FINI 0x1000000 +#define STYP_LIT8 0x8000000 +#define STYP_LIT4 0x10000000 +#define STYP_ECOFF_INIT 0x80000000 +#define STYP_OTHER_LOAD (STYP_ECOFF_INIT | STYP_ECOFF_FINI) + +/* The linker needs a section to hold small common variables while + linking. There is no convenient way to create it when the linker + needs it, so we always create one for each BFD. We then avoid + writing it out. */ +#define SCOMMON ".scommon" + +/* The ECOFF a.out header carries information about register masks and + the gp value. The assembler needs to be able to write out this + information, and objcopy needs to be able to copy it from one file + to another. To handle this in BFD, we use a dummy section to hold + the information. We call this section .reginfo, since MIPS ELF has + a .reginfo section which serves a similar purpose. When BFD + recognizes an ECOFF object, it copies the information into a + private data structure. When the .reginfo section is read, the + information is retrieved from the private data structure. When the + .reginfo section is written, the information in the private data + structure is updated. The contents of the .reginfo section, as + seen by programs outside BFD, is a ecoff_reginfo structure. The + contents of the structure are as seen on the host, so no swapping + issues arise. + + The assembler used to update the private BFD data structures + directly. With this approach, it instead just creates a .reginfo + section and updates that. The real advantage of this approach is + that objcopy works automatically. */ +#define REGINFO ".reginfo" +struct ecoff_reginfo +{ + bfd_vma gp_value; /* GP register value. */ + unsigned long gprmask; /* General registers used. */ + unsigned long cprmask[4]; /* Coprocessor registers used. */ + unsigned long fprmask; /* Floating pointer registers used. */ +}; + +/* If the extern bit in a reloc is 1, then r_symndx is an index into + the external symbol table. If the extern bit is 0, then r_symndx + indicates a section, and is one of the following values. */ +#define RELOC_SECTION_NONE 0 +#define RELOC_SECTION_TEXT 1 +#define RELOC_SECTION_RDATA 2 +#define RELOC_SECTION_DATA 3 +#define RELOC_SECTION_SDATA 4 +#define RELOC_SECTION_SBSS 5 +#define RELOC_SECTION_BSS 6 +#define RELOC_SECTION_INIT 7 +#define RELOC_SECTION_LIT8 8 +#define RELOC_SECTION_LIT4 9 +#define RELOC_SECTION_XDATA 10 +#define RELOC_SECTION_PDATA 11 +#define RELOC_SECTION_FINI 12 +#define RELOC_SECTION_LITA 13 +#define RELOC_SECTION_ABS 14 + +/********************** STABS **********************/ + +/* gcc uses mips-tfile to output type information in special stabs + entries. These must match the corresponding definition in + gcc/config/mips.h. At some point, these should probably go into a + shared include file, but currently gcc and gdb do not share any + directories. */ +#define CODE_MASK 0x8F300 +#define ECOFF_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK) +#define ECOFF_MARK_STAB(code) ((code)+CODE_MASK) +#define ECOFF_UNMARK_STAB(code) ((code)-CODE_MASK) +#define STABS_SYMBOL "@stabs" + +/********************** COFF **********************/ + +/* gcc also uses mips-tfile to output COFF debugging information. + These are the values it uses when outputting the .type directive. + These should also be in a shared include file. */ +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +/********************** AUX **********************/ + +/* The auxiliary type information is the same on all known ECOFF + targets. I can't see any reason that it would ever change, so I am + going to gamble and define the external structures here, in the + target independent ECOFF header file. The internal forms are + defined in coff/sym.h, which was originally donated by MIPS + Computer Systems. */ + +/* Type information external record */ + +struct tir_ext { + unsigned char t_bits1[1]; + unsigned char t_tq45[1]; + unsigned char t_tq01[1]; + unsigned char t_tq23[1]; +}; + +#define TIR_BITS1_FBITFIELD_BIG 0x80 +#define TIR_BITS1_FBITFIELD_LITTLE 0x01 + +#define TIR_BITS1_CONTINUED_BIG 0x40 +#define TIR_BITS1_CONTINUED_LITTLE 0x02 + +#define TIR_BITS1_BT_BIG 0x3F +#define TIR_BITS1_BT_SH_BIG 0 +#define TIR_BITS1_BT_LITTLE 0xFC +#define TIR_BITS1_BT_SH_LITTLE 2 + +#define TIR_BITS_TQ4_BIG 0xF0 +#define TIR_BITS_TQ4_SH_BIG 4 +#define TIR_BITS_TQ5_BIG 0x0F +#define TIR_BITS_TQ5_SH_BIG 0 +#define TIR_BITS_TQ4_LITTLE 0x0F +#define TIR_BITS_TQ4_SH_LITTLE 0 +#define TIR_BITS_TQ5_LITTLE 0xF0 +#define TIR_BITS_TQ5_SH_LITTLE 4 + +#define TIR_BITS_TQ0_BIG 0xF0 +#define TIR_BITS_TQ0_SH_BIG 4 +#define TIR_BITS_TQ1_BIG 0x0F +#define TIR_BITS_TQ1_SH_BIG 0 +#define TIR_BITS_TQ0_LITTLE 0x0F +#define TIR_BITS_TQ0_SH_LITTLE 0 +#define TIR_BITS_TQ1_LITTLE 0xF0 +#define TIR_BITS_TQ1_SH_LITTLE 4 + +#define TIR_BITS_TQ2_BIG 0xF0 +#define TIR_BITS_TQ2_SH_BIG 4 +#define TIR_BITS_TQ3_BIG 0x0F +#define TIR_BITS_TQ3_SH_BIG 0 +#define TIR_BITS_TQ2_LITTLE 0x0F +#define TIR_BITS_TQ2_SH_LITTLE 0 +#define TIR_BITS_TQ3_LITTLE 0xF0 +#define TIR_BITS_TQ3_SH_LITTLE 4 + +/* Relative symbol external record */ + +struct rndx_ext { + unsigned char r_bits[4]; +}; + +#define RNDX_BITS0_RFD_SH_LEFT_BIG 4 +#define RNDX_BITS1_RFD_BIG 0xF0 +#define RNDX_BITS1_RFD_SH_BIG 4 + +#define RNDX_BITS0_RFD_SH_LEFT_LITTLE 0 +#define RNDX_BITS1_RFD_LITTLE 0x0F +#define RNDX_BITS1_RFD_SH_LEFT_LITTLE 8 + +#define RNDX_BITS1_INDEX_BIG 0x0F +#define RNDX_BITS1_INDEX_SH_LEFT_BIG 16 +#define RNDX_BITS2_INDEX_SH_LEFT_BIG 8 +#define RNDX_BITS3_INDEX_SH_LEFT_BIG 0 + +#define RNDX_BITS1_INDEX_LITTLE 0xF0 +#define RNDX_BITS1_INDEX_SH_LITTLE 4 +#define RNDX_BITS2_INDEX_SH_LEFT_LITTLE 4 +#define RNDX_BITS3_INDEX_SH_LEFT_LITTLE 12 + +/* Auxiliary symbol information external record */ + +union aux_ext { + struct tir_ext a_ti; + struct rndx_ext a_rndx; + unsigned char a_dnLow[4]; + unsigned char a_dnHigh[4]; + unsigned char a_isym[4]; + unsigned char a_iss[4]; + unsigned char a_width[4]; + unsigned char a_count[4]; +}; + +#define AUX_GET_ANY(bigend, ax, field) \ + ((bigend) ? bfd_getb32 ((ax)->field) : bfd_getl32 ((ax)->field)) + +#define AUX_GET_DNLOW(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnLow) +#define AUX_GET_DNHIGH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnHigh) +#define AUX_GET_ISYM(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_isym) +#define AUX_GET_ISS(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_iss) +#define AUX_GET_WIDTH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_width) +#define AUX_GET_COUNT(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_count) + +#define AUX_PUT_ANY(bigend, val, ax, field) \ + ((bigend) \ + ? (bfd_putb32 ((bfd_vma) (val), (ax)->field), 0) \ + : (bfd_putl32 ((bfd_vma) (val), (ax)->field), 0)) + +#define AUX_PUT_DNLOW(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_dnLow) +#define AUX_PUT_DNHIGH(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_dnHigh) +#define AUX_PUT_ISYM(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_isym) +#define AUX_PUT_ISS(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_iss) +#define AUX_PUT_WIDTH(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_width) +#define AUX_PUT_COUNT(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_count) + +/* Prototypes for the swapping functions. These require that sym.h be + included before this file. */ + +extern void ecoff_swap_tir_in PARAMS ((int bigend, struct tir_ext *, TIR *)); +extern void ecoff_swap_tir_out PARAMS ((int bigend, TIR *, struct tir_ext *)); +extern void ecoff_swap_rndx_in PARAMS ((int bigend, struct rndx_ext *, + RNDXR *)); +extern void ecoff_swap_rndx_out PARAMS ((int bigend, RNDXR *, + struct rndx_ext *)); + +#endif /* ! defined (ECOFF_H) */ diff --git a/gnu/usr.bin/gdb/gdb/coff/internal.h b/gnu/usr.bin/gdb/gdb/coff/internal.h new file mode 100644 index 00000000000..e8cf98470cf --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coff/internal.h @@ -0,0 +1,538 @@ +/* Internal format of COFF object file data structures, for GNU BFD. + This file is part of BFD, the Binary File Descriptor library. */ + +/* First, make "signed char" work, even on old compilers. */ +#ifndef signed +#ifndef __STDC__ +#define signed /**/ +#endif +#endif + +/********************** FILE HEADER **********************/ +struct internal_filehdr +{ + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + bfd_vma f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR16WR file is 16-bit little-endian + * F_AR32WR file is 32-bit little-endian + * F_AR32W file is 32-bit big-endian + * F_DYNLOAD rs/6000 aix: dynamically loadable w/imports & exports + * F_SHROBJ rs/6000 aix: file is a shared object + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) +#define F_AR16WR (0x0080) +#define F_AR32WR (0x0100) +#define F_AR32W (0x0200) +#define F_DYNLOAD (0x1000) +#define F_SHROBJ (0x2000) + +/********************** AOUT "OPTIONAL HEADER" **********************/ +struct internal_aouthdr +{ + short magic; /* type of file */ + short vstamp; /* version stamp */ + bfd_vma tsize; /* text size in bytes, padded to FW bdry*/ + bfd_vma dsize; /* initialized data " " */ + bfd_vma bsize; /* uninitialized data " " */ + bfd_vma entry; /* entry pt. */ + bfd_vma text_start; /* base of text used for this file */ + bfd_vma data_start; /* base of data used for this file */ + + /* i960 stuff */ + unsigned long tagentries; /* number of tag entries to follow */ + + /* RS/6000 stuff */ + unsigned long o_toc; /* address of TOC */ + short o_snentry; /* section number for entry point */ + short o_sntext; /* section number for text */ + short o_sndata; /* section number for data */ + short o_sntoc; /* section number for toc */ + short o_snloader; /* section number for loader section */ + short o_snbss; /* section number for bss */ + short o_algntext; /* max alignment for text */ + short o_algndata; /* max alignment for data */ + short o_modtype; /* Module type field, 1R,RE,RO */ + unsigned long o_maxstack; /* max stack size allowed. */ + + /* ECOFF stuff */ + bfd_vma bss_start; /* Base of bss section. */ + bfd_vma gp_value; /* GP register value. */ + unsigned long gprmask; /* General registers used. */ + unsigned long cprmask[4]; /* Coprocessor registers used. */ + unsigned long fprmask; /* Floating pointer registers used. */ + + /* Apollo stuff */ + long o_inlib; + long o_sri; + long vid[2]; +}; + +/********************** STORAGE CLASSES **********************/ + +/* This used to be defined as -1, but now n_sclass is unsigned. */ +#define C_EFCN 0xff /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ +#define C_AUTOARG 19 /* auto argument */ +#define C_LASTENT 20 /* dummy entry (end of block) */ +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* line # reformatted as symbol table entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* ext symbol in dmert public lib */ + + /* New storage classes for 80960 */ + +/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */ +#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */ + +#define C_SCALL 107 /* Procedure reachable via system call */ +#define C_LEAFEXT 108 /* External leaf */ +#define C_LEAFSTAT 113 /* Static leaf */ +#define C_OPTVAR 109 /* Optimized variable */ +#define C_DEFINE 110 /* Preprocessor #define */ +#define C_PRAGMA 111 /* Advice to compiler or linker */ +#define C_SEGMENT 112 /* 80960 segment name */ + + /* Storage classes for m88k */ +#define C_SHADOW 107 /* shadow symbol */ +#define C_VERSION 108 /* coff version symbol */ + + /* New storage classes for RS/6000 */ +#define C_HIDEXT 107 /* Un-named external symbol */ +#define C_BINCL 108 /* Marks beginning of include file */ +#define C_EINCL 109 /* Marks ending of include file */ + + /* storage classes for stab symbols for RS/6000 */ +#define C_GSYM (0x80) +#define C_LSYM (0x81) +#define C_PSYM (0x82) +#define C_RSYM (0x83) +#define C_RPSYM (0x84) +#define C_STSYM (0x85) +#define C_TCSYM (0x86) +#define C_BCOMM (0x87) +#define C_ECOML (0x88) +#define C_ECOMM (0x89) +#define C_DECL (0x8c) +#define C_ENTRY (0x8d) +#define C_FUN (0x8e) +#define C_BSTAT (0x8f) +#define C_ESTAT (0x90) + +/********************** SECTION HEADER **********************/ +struct internal_scnhdr +{ + char s_name[8]; /* section name */ + bfd_vma s_paddr; /* physical address, aliased s_nlib */ + bfd_vma s_vaddr; /* virtual address */ + bfd_vma s_size; /* section size */ + bfd_vma s_scnptr; /* file ptr to raw data for section */ + bfd_vma s_relptr; /* file ptr to relocation */ + bfd_vma s_lnnoptr; /* file ptr to line numbers */ + unsigned long s_nreloc; /* number of relocation entries */ + unsigned long s_nlnno; /* number of line number entries*/ + long s_flags; /* flags */ + long s_align; /* used on I960 */ +}; + +/* + * s_flags "type" + */ +#define STYP_REG (0x0000) /* "regular": allocated, relocated, loaded */ +#define STYP_DSECT (0x0001) /* "dummy": relocated only*/ +#define STYP_NOLOAD (0x0002) /* "noload": allocated, relocated, not loaded */ +#define STYP_GROUP (0x0004) /* "grouped": formed of input sections */ +#define STYP_PAD (0x0008) /* "padding": not allocated, not relocated, loaded */ +#define STYP_COPY (0x0010) /* "copy": for decision function used by field update; not allocated, not relocated, + loaded; reloc & lineno entries processed normally */ +#define STYP_TEXT (0x0020) /* section contains text only */ +#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile + will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will + update all process invocations. */ +#define STYP_DATA (0x0040) /* section contains data only */ +#define STYP_BSS (0x0080) /* section contains bss only */ +#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */ +#define STYP_INFO (0x0200) /* comment: not allocated not relocated, not loaded */ +#define STYP_OVER (0x0400) /* overlay: relocated not allocated or loaded */ +#define STYP_LIB (0x0800) /* for .lib: same as INFO */ +#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */ +#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a + + word of contiguous bytes + beginning on a word boundary. */ + +#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */ +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ + +struct internal_lineno +{ + union + { + long l_symndx; /* function name symbol index, iff l_lnno == 0*/ + long l_paddr; /* (physical) address of line number */ + } l_addr; + unsigned long l_lnno; /* line number */ +}; + +/********************** SYMBOLS **********************/ + +#define SYMNMLEN 8 /* # characters in a symbol name */ +#define FILNMLEN 14 /* # characters in a file name */ +#define DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct internal_syment +{ + union + { + char _n_name[SYMNMLEN]; /* old COFF version */ + struct + { + long _n_zeroes; /* new == 0 */ + long _n_offset; /* offset into string table */ + } _n_n; + char *_n_nptr[2]; /* allows for overlaying */ + } _n; + long n_value; /* value of symbol */ + short n_scnum; /* section number */ + unsigned short n_flags; /* copy of flags from filhdr */ + unsigned short n_type; /* type and derived type */ + unsigned char n_sclass; /* storage class */ + char n_numaux; /* number of aux. entries */ +}; + +#define n_name _n._n_name +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + + +/* Relocatable symbols have number of the section in which they are defined, + or one of the following: */ + +#define N_UNDEF ((short)0) /* undefined symbol */ +#define N_ABS ((short)-1) /* value of symbol is absolute */ +#define N_DEBUG ((short)-2) /* debugging symbol -- value is meaningless */ +#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */ +#define P_TV ((short)-4) /* indicates symbol needs postload transfer vector*/ + +/* + * Type of a symbol, in low N bits of the word + */ +#define T_NULL 0 +#define T_VOID 1 /* function argument (only used by compiler) */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration*/ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ +#define T_LNGDBL 16 /* long double */ + +/* + * derived types, in n_type +*/ +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +#define BTYPE(x) ((x) & N_BTMASK) + +#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT)) +#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT)) +#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT)) +#define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG) +#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) + + +union internal_auxent +{ + struct + { + + union + { + long l; /* str, un, or enum tag indx */ + struct coff_ptr_struct *p; + } x_tagndx; + + union + { + struct + { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str/union/array size */ + } x_lnsz; + long x_fsize; /* size of function */ + } x_misc; + + union + { + struct + { /* if ISFCN, tag, or .bb */ + long x_lnnoptr; /* ptr to fcn line # */ + union + { /* entry ndx past block end */ + long l; + struct coff_ptr_struct *p; + } x_endndx; + } x_fcn; + + struct + { /* if ISARY, up to 4 dimen. */ + unsigned short x_dimen[DIMNUM]; + } x_ary; + } x_fcnary; + + unsigned short x_tvndx; /* tv index */ + } x_sym; + + union + { + char x_fname[FILNMLEN]; + struct + { + long x_zeroes; + long x_offset; + } x_n; + } x_file; + + struct + { + long x_scnlen; /* section length */ + unsigned short x_nreloc; /* # relocation entries */ + unsigned short x_nlinno; /* # line numbers */ + } x_scn; + + struct + { + long x_tvfill; /* tv fill value */ + unsigned short x_tvlen; /* length of .tv */ + unsigned short x_tvran[2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + /****************************************** + * RS/6000-specific auxent - last auxent for every external symbol + ******************************************/ + struct + { + long x_scnlen; /* csect length */ + long x_parmhash; /* parm type hash index */ + unsigned short x_snhash; /* sect num with parm hash */ + unsigned char x_smtyp; /* symbol align and type */ + /* 0-4 - Log 2 of alignment */ + /* 5-7 - symbol type */ + unsigned char x_smclas; /* storage mapping class */ + long x_stab; /* dbx stab info index */ + unsigned short x_snstab; /* sect num with dbx stab */ + } x_csect; /* csect definition information */ + +/* x_smtyp values: */ + +#define SMTYP_ALIGN(x) ((x) >> 3) /* log2 of alignment */ +#define SMTYP_SMTYP(x) ((x) & 0x7) /* symbol type */ +/* Symbol type values: */ +#define XTY_ER 0 /* External reference */ +#define XTY_SD 1 /* Csect definition */ +#define XTY_LD 2 /* Label definition */ +#define XTY_CM 3 /* .BSS */ +#define XTY_EM 4 /* Error message */ +#define XTY_US 5 /* "Reserved for internal use" */ + +/* x_smclas values: */ + +#define XMC_PR 0 /* Read-only program code */ +#define XMC_RO 1 /* Read-only constant */ +#define XMC_DB 2 /* Read-only debug dictionary table */ +#define XMC_TC 3 /* Read-write general TOC entry */ +#define XMC_UA 4 /* Read-write unclassified */ +#define XMC_RW 5 /* Read-write data */ +#define XMC_GL 6 /* Read-only global linkage */ +#define XMC_XO 7 /* Read-only extended operation (simulated insn) */ +#define XMC_SV 8 /* Read-only supervisor call */ +#define XMC_BS 9 /* Read-write BSS */ +#define XMC_DS 10 /* Read-write descriptor csect */ +#define XMC_UC 11 /* Read-write unnamed Fortran common */ +#define XMC_TI 12 /* Read-only traceback index csect */ +#define XMC_TB 13 /* Read-only traceback table csect */ +/* 14 ??? */ +#define XMC_TC0 15 /* Read-write TOC anchor for TOC addressability */ + + + /****************************************** + * I960-specific *2nd* aux. entry formats + ******************************************/ + struct + { + /* This is a very old typo that keeps getting propagated. */ +#define x_stdindx x_stindx + long x_stindx; /* sys. table entry */ + } x_sc; /* system call entry */ + + struct + { + unsigned long x_balntry; /* BAL entry point */ + } x_bal; /* BAL-callable function */ + + struct + { + unsigned long x_timestamp; /* time stamp */ + char x_idstring[20]; /* producer identity string */ + } x_ident; /* Producer ident info */ + +}; + +/********************** RELOCATION DIRECTIVES **********************/ + +struct internal_reloc +{ + bfd_vma r_vaddr; /* Virtual address of reference */ + long r_symndx; /* Index into symbol table */ + unsigned short r_type; /* Relocation type */ + unsigned char r_size; /* Used by RS/6000 and ECOFF */ + unsigned char r_extern; /* Used by ECOFF */ + unsigned long r_offset; /* Used by RS/6000 and ECOFF */ +}; + +#define R_RELBYTE 017 +#define R_RELWORD 020 +#define R_PCRBYTE 022 +#define R_PCRWORD 023 +#define R_PCRLONG 024 + +#define R_DIR16 01 +#define R_DIR32 06 +#define R_PCLONG 020 +#define R_RELBYTE 017 +#define R_RELWORD 020 + + + +#define R_PCR16L 128 +#define R_PCR26L 129 +#define R_VRT16 130 +#define R_HVRT16 131 +#define R_LVRT16 132 +#define R_VRT32 133 +#define R_RELLONG (0x11) /* Direct 32-bit relocation */ +#define R_IPRSHORT (0x18) +#define R_IPRMED (0x19) /* 24-bit ip-relative relocation */ +#define R_IPRLONG (0x1a) +#define R_OPTCALL (0x1b) /* 32-bit optimizable call (leafproc/sysproc) */ +#define R_OPTCALLX (0x1c) /* 64-bit optimizable call (leafproc/sysproc) */ +#define R_GETSEG (0x1d) +#define R_GETPA (0x1e) +#define R_TAGWORD (0x1f) +#define R_JUMPTARG 0x20 /* strange 29k 00xx00xx reloc */ + + +#define R_MOVB1 0x41 /* Special h8 16bit or 8 bit reloc for mov.b */ +#define R_MOVB2 0x42 /* Special h8 opcode for 8bit which could be 16 */ +#define R_JMP1 0x43 /* Special h8 16bit jmp which could be pcrel */ +#define R_JMP2 0x44 /* a branch which used to be a jmp */ +#define R_RELLONG_NEG 0x45 + +#define R_JMPL1 0x46 /* Special h8 24bit jmp which could be pcrel */ +#define R_JMPL_B8 0x47 /* a 8 bit pcrel which used to be a jmp */ + +#define R_MOVLB1 0x48 /* Special h8 24bit or 8 bit reloc for mov.b */ +#define R_MOVLB2 0x49 /* Special h8 opcode for 8bit which could be 24 */ + +/* Z8k modes */ +#define R_IMM16 0x01 /* 16 bit abs */ +#define R_JR 0x02 /* jr 8 bit disp */ +#define R_IMM4L 0x23 /* low nibble */ +#define R_IMM8 0x22 /* 8 bit abs */ +#define R_IMM32 R_RELLONG /* 32 bit abs */ +#define R_CALL R_DA /* Absolute address which could be a callr */ +#define R_JP R_DA /* Absolute address which could be a jp */ +#define R_REL16 0x04 /* 16 bit PC rel */ +#define R_CALLR 0x05 /* callr 12 bit disp */ +#define R_SEG 0x10 /* set if in segmented mode */ +#define R_IMM4H 0x24 /* high nibble */ + + +/* H8500 modes */ + +#define R_H8500_IMM8 1 /* 8 bit immediate */ +#define R_H8500_IMM16 2 /* 16 bit immediate */ +#define R_H8500_PCREL8 3 /* 8 bit pcrel */ +#define R_H8500_PCREL16 4 /* 16 bit pcrel */ +#define R_H8500_HIGH8 5 /* high 8 bits of 24 bit address */ +#define R_H8500_LOW16 7 /* low 16 bits of 24 bit immediate */ +#define R_H8500_IMM24 6 /* 24 bit immediate */ +#define R_H8500_IMM32 8 /* 32 bit immediate */ +#define R_H8500_HIGH16 9 /* high 16 bits of 32 bit immediate */ + +/* SH modes */ + +#define R_SH_PCREL8 3 /* 8 bit pcrel */ +#define R_SH_PCREL16 4 /* 16 bit pcrel */ +#define R_SH_HIGH8 5 /* high 8 bits of 24 bit address */ +#define R_SH_LOW16 7 /* low 16 bits of 24 bit immediate */ +#define R_SH_IMM24 6 /* 24 bit immediate */ +#define R_SH_PCDISP8BY4 9 /* PC rel 8 bits *4 +ve */ +#define R_SH_PCDISP8BY2 10 /* PC rel 8 bits *2 +ve */ +#define R_SH_PCDISP8 11 /* 8 bit branch */ +#define R_SH_PCDISP 12 /* 12 bit branch */ +#define R_SH_IMM32 14 /* 32 bit immediate */ +#define R_SH_IMM8 16 +#define R_SH_IMM8BY2 17 +#define R_SH_IMM8BY4 18 +#define R_SH_IMM4 19 +#define R_SH_IMM4BY2 20 +#define R_SH_IMM4BY4 21 +#define R_SH_PCRELIMM8BY2 22 +#define R_SH_PCRELIMM8BY4 23 + + + diff --git a/gnu/usr.bin/gdb/gdb/coff/sym.h b/gnu/usr.bin/gdb/gdb/coff/sym.h new file mode 100644 index 00000000000..990eeacc680 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coff/sym.h @@ -0,0 +1,477 @@ +/* Declarations of internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ +#ifndef _SYM_H +#define _SYM_H + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* + * This file contains the definition of the Third Eye Symbol Table. + * + * Symbols are assumed to be in 'encounter order' - i.e. the order that + * the things they represent were encountered by the compiler/assembler/loader. + * EXCEPT for globals! These are assumed to be bunched together, + * probably right after the last 'normal' symbol. Globals ARE sorted + * in ascending order. + * + * ----------------------------------------------------------------------- + * A brief word about Third Eye naming/use conventions: + * + * All arrays and index's are 0 based. + * All "ifooMax" values are the highest legal value PLUS ONE. This makes + * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". + * + * "isym" Index into the SYMbol table. + * "ipd" Index into the Procedure Descriptor array. + * "ifd" Index into the File Descriptor array. + * "iss" Index into String Space. + * "cb" Count of Bytes. + * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. + * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. + */ + + +/* + * Symbolic Header (HDR) structure. + * As long as all the pointers are set correctly, + * we don't care WHAT order the various sections come out in! + * + * A file produced solely for the use of CDB will probably NOT have + * any instructions or data areas in it, as these are available + * in the original. + */ + +typedef struct { + short magic; /* to verify validity of the table */ + short vstamp; /* version stamp */ + long ilineMax; /* number of line number entries */ + bfd_vma cbLine; /* number of bytes for line number entries */ + bfd_vma cbLineOffset; /* offset to start of line number entries*/ + long idnMax; /* max index into dense number table */ + bfd_vma cbDnOffset; /* offset to start dense number table */ + long ipdMax; /* number of procedures */ + bfd_vma cbPdOffset; /* offset to procedure descriptor table */ + long isymMax; /* number of local symbols */ + bfd_vma cbSymOffset; /* offset to start of local symbols*/ + long ioptMax; /* max index into optimization symbol entries */ + bfd_vma cbOptOffset; /* offset to optimization symbol entries */ + long iauxMax; /* number of auxillary symbol entries */ + bfd_vma cbAuxOffset; /* offset to start of auxillary symbol entries*/ + long issMax; /* max index into local strings */ + bfd_vma cbSsOffset; /* offset to start of local strings */ + long issExtMax; /* max index into external strings */ + bfd_vma cbSsExtOffset; /* offset to start of external strings */ + long ifdMax; /* number of file descriptor entries */ + bfd_vma cbFdOffset; /* offset to file descriptor table */ + long crfd; /* number of relative file descriptor entries */ + bfd_vma cbRfdOffset; /* offset to relative file descriptor table */ + long iextMax; /* max index into external symbols */ + bfd_vma cbExtOffset; /* offset to start of external symbol entries*/ + /* If you add machine dependent fields, add them here */ + } HDRR, *pHDRR; +#define cbHDRR sizeof(HDRR) +#define hdrNil ((pHDRR)0) + +/* + * The FDR and PDR structures speed mapping of address <-> name. + * They are sorted in ascending memory order and are kept in + * memory by CDB at runtime. + */ + +/* + * File Descriptor + * + * There is one of these for EVERY FILE, whether compiled with + * full debugging symbols or not. The name of a file should be + * the path name given to the compiler. This allows the user + * to simply specify the names of the directories where the COMPILES + * were done, and we will be able to find their files. + * A field whose comment starts with "R - " indicates that it will be + * setup at runtime. + */ +typedef struct fdr { + bfd_vma adr; /* memory address of beginning of file */ + long rss; /* file name (of source, if known) */ + long issBase; /* file's string space */ + bfd_vma cbSs; /* number of bytes in the ss */ + long isymBase; /* beginning of symbols */ + long csym; /* count file's of symbols */ + long ilineBase; /* file's line symbols */ + long cline; /* count of file's line symbols */ + long ioptBase; /* file's optimization entries */ + long copt; /* count of file's optimization entries */ + unsigned short ipdFirst;/* start of procedures for this file */ + short cpd; /* count of procedures for this file */ + long iauxBase; /* file's auxiliary entries */ + long caux; /* count of file's auxiliary entries */ + long rfdBase; /* index into the file indirect table */ + long crfd; /* count file indirect entries */ + unsigned lang: 5; /* language for this file */ + unsigned fMerge : 1; /* whether this file can be merged */ + unsigned fReadin : 1; /* true if it was read in (not just created) */ + unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ + /* aux's will be in compile host's sex */ + unsigned glevel : 2; /* level this file was compiled with */ + unsigned reserved : 22; /* reserved for future use */ + bfd_vma cbLineOffset; /* byte offset from header for this file ln's */ + bfd_vma cbLine; /* size of lines for this file */ + } FDR, *pFDR; +#define cbFDR sizeof(FDR) +#define fdNil ((pFDR)0) +#define ifdNil -1 +#define ifdTemp 0 +#define ilnNil -1 + + +/* + * Procedure Descriptor + * + * There is one of these for EVERY TEXT LABEL. + * If a procedure is in a file with full symbols, then isym + * will point to the PROC symbols, else it will point to the + * global symbol for the label. + */ + +typedef struct pdr { + bfd_vma adr; /* memory address of start of procedure */ + long isym; /* start of local symbol entries */ + long iline; /* start of line number entries*/ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long iopt; /* start of optimization symbol entries*/ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long lnLow; /* lowest line in the procedure */ + long lnHigh; /* highest line in the procedure */ + bfd_vma cbLineOffset; /* byte offset for this procedure from the fd base */ + /* These fields are new for 64 bit ECOFF. */ + unsigned gp_prologue : 8; /* byte size of GP prologue */ + unsigned gp_used : 1; /* true if the procedure uses GP */ + unsigned reg_frame : 1; /* true if register frame procedure */ + unsigned reserved : 14; /* reserved: must be zero */ + unsigned localoff : 8; /* offset of local variables from vfp */ + } PDR, *pPDR; +#define cbPDR sizeof(PDR) +#define pdNil ((pPDR) 0) +#define ipdNil -1 + +/* + * The structure of the runtime procedure descriptor created by the loader + * for use by the static exception system. + */ +typedef struct runtime_pdr { + unsigned long adr; /* memory address of start of procedure */ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long irpss; /* index into the runtime string table */ + long reserved; + struct exception_info *exception_info;/* pointer to exception array */ +} RPDR, *pRPDR; +#define cbRPDR sizeof(RPDR) +#define rpdNil ((pRPDR) 0) + +/* + * Line Numbers + * + * Line Numbers are segregated from the normal symbols because they + * are [1] smaller , [2] are of no interest to your + * average loader, and [3] are never needed in the middle of normal + * scanning and therefore slow things down. + * + * By definition, the first LINER for any given procedure will have + * the first line of a procedure and represent the first address. + */ + +typedef long LINER, *pLINER; +#define lineNil ((pLINER)0) +#define cbLINER sizeof(LINER) +#define ilineNil -1 + + + +/* + * The Symbol Structure (GFW, to those who Know!) + */ + +typedef struct { + long iss; /* index into String Space of name */ + long value; /* value of symbol */ + unsigned st : 6; /* symbol type */ + unsigned sc : 5; /* storage class - text, data, etc */ + unsigned reserved : 1; /* reserved */ + unsigned index : 20; /* index into sym/aux table */ + } SYMR, *pSYMR; +#define symNil ((pSYMR)0) +#define cbSYMR sizeof(SYMR) +#define isymNil -1 +#define indexNil 0xfffff +#define issNil -1 +#define issNull 0 + + +/* The following converts a memory resident string to an iss. + * This hack is recognized in SbFIss, in sym.c of the debugger. + */ +#define IssFSb(sb) (0x80000000 | ((unsigned long)(sb))) + +/* E X T E R N A L S Y M B O L R E C O R D + * + * Same as the SYMR except it contains file context to determine where + * the index is. + */ +typedef struct { + unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ + unsigned cobol_main:1; /* symbol is a cobol main procedure */ + unsigned weakext:1; /* symbol is weak external */ + unsigned reserved:13; /* reserved for future use */ + int ifd; /* where the iss and index fields point into */ + SYMR asym; /* symbol for the external */ + } EXTR, *pEXTR; +#define extNil ((pEXTR)0) +#define cbEXTR sizeof(EXTR) + + +/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ + +/* + * Type Information Record + */ +typedef struct { + unsigned fBitfield : 1; /* set if bit width is specified */ + unsigned continued : 1; /* indicates additional TQ info in next AUX */ + unsigned bt : 6; /* basic type */ + unsigned tq4 : 4; + unsigned tq5 : 4; + /* ---- 16 bit boundary ---- */ + unsigned tq0 : 4; + unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + unsigned tq2 : 4; + unsigned tq3 : 4; + } TIR, *pTIR; +#define cbTIR sizeof(TIR) +#define tiNil ((pTIR)0) +#define itqMax 6 + +/* + * Relative symbol record + * + * If the rfd field is 4095, the index field indexes into the global symbol + * table. + */ + +typedef struct { + unsigned rfd : 12; /* index into the file indirect table */ + unsigned index : 20; /* index int sym/aux/iss tables */ + } RNDXR, *pRNDXR; +#define cbRNDXR sizeof(RNDXR) +#define rndxNil ((pRNDXR)0) + +/* dense numbers or sometimes called block numbers are stored in this type, + * a rfd of 0xffffffff is an index into the global table. + */ +typedef struct { + unsigned long rfd; /* index into the file table */ + unsigned long index; /* index int sym/aux/iss tables */ + } DNR, *pDNR; +#define cbDNR sizeof(DNR) +#define dnNil ((pDNR)0) + + + +/* + * Auxillary information occurs only if needed. + * It ALWAYS occurs in this order when present. + + isymMac used by stProc only + TIR type info + TIR additional TQ info (if first TIR was not enough) + rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, + btTypedef): + rsym.index == iaux for btSet or btRange + else rsym.index == isym + dimLow btRange, btSet + dimMac btRange, btSet + rndx0 As many as there are tq arrays + dimLow0 + dimHigh0 + ... + rndxMax-1 + dimLowMax-1 + dimHighMax-1 + width in bits if (bit field), width in bits. + */ +#define cAuxMax (6 + (idimMax*3)) + +/* a union of all possible info in the AUX universe */ +typedef union { + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + long dnLow; /* low dimension */ + long dnHigh; /* high dimension */ + long isym; /* symbol table index (end of proc) */ + long iss; /* index into string space (not used) */ + long width; /* width for non-default sized struc fields */ + long count; /* count of ranges for variant arm */ + } AUXU, *pAUXU; +#define cbAUXU sizeof(AUXU) +#define auxNil ((pAUXU)0) +#define iauxNil -1 + + +/* + * Optimization symbols + * + * Optimization symbols contain some overlap information with the normal + * symbol table. In particular, the proc information + * is somewhat redundant but necessary to easily find the other information + * present. + * + * All of the offsets are relative to the beginning of the last otProc + */ + +typedef struct { + unsigned ot: 8; /* optimization type */ + unsigned value: 24; /* address where we are moving it to */ + RNDXR rndx; /* points to a symbol or opt entry */ + unsigned long offset; /* relative offset this occured */ + } OPTR, *pOPTR; +#define optNil ((pOPTR) 0) +#define cbOPTR sizeof(OPTR) +#define ioptNil -1 + +/* + * File Indirect + * + * When a symbol is referenced across files the following procedure is used: + * 1) use the file index to get the File indirect entry. + * 2) use the file indirect entry to get the File descriptor. + * 3) add the sym index to the base of that file's sym table + * + */ + +typedef long RFDT, *pRFDT; +#define cbRFDT sizeof(RFDT) +#define rfdNil -1 + +/* + * The file indirect table in the mips loader is known as an array of FITs. + * This is done to keep the code in the loader readable in the area where + * these tables are merged. Note this is only a name change. + */ +typedef long FIT, *pFIT; +#define cbFIT sizeof(FIT) +#define ifiNil -1 +#define fiNil ((pFIT) 0) + +#ifdef _LANGUAGE_PASCAL +#define ifdNil -1 +#define ilnNil -1 +#define ipdNil -1 +#define ilineNil -1 +#define isymNil -1 +#define indexNil 16#fffff +#define issNil -1 +#define issNull 0 +#define itqMax 6 +#define iauxNil -1 +#define ioptNil -1 +#define rfdNil -1 +#define ifiNil -1 +#endif /* _LANGUAGE_PASCAL */ + + +/* Dense numbers + * + * Rather than use file index, symbol index pairs to represent symbols + * and globals, we use dense number so that they can be easily embeded + * in intermediate code and the programs that process them can + * use direct access tabls instead of hash table (which would be + * necesary otherwise because of the sparse name space caused by + * file index, symbol index pairs. Dense number are represented + * by RNDXRs. + */ + +/* + * The following table defines the meaning of each SYM field as + * a function of the "st". (scD/B == scData OR scBss) + * + * Note: the value "isymMac" is used by symbols that have the concept + * of enclosing a block of related information. This value is the + * isym of the first symbol AFTER the end associated with the primary + * symbol. For example if a procedure was at isym==90 and had an + * isymMac==155, the associated end would be at isym==154, and the + * symbol at 155 would probably (although not necessarily) be the + * symbol for the next procedure. This allows rapid skipping over + * internal information of various sorts. "stEnd"s ALWAYS have the + * isym of the primary symbol that started the block. + * + +ST SC VALUE INDEX +-------- ------ -------- ------ +stFile scText address isymMac +stLabel scText address --- +stGlobal scD/B address iaux +stStatic scD/B address iaux +stParam scAbs offset iaux +stLocal scAbs offset iaux +stProc scText address iaux (isymMac is first AUX) +stStaticProc scText address iaux (isymMac is first AUX) + +stMember scNil ordinal --- (if member of enum) + (mipsread thinks the case below has a bit, not byte, offset.) +stMember scNil byte offset iaux (if member of struct/union) +stMember scBits bit offset iaux (bit field spec) + +stBlock scText address isymMac (text block) + (the code seems to think that rather than scNil, we see scInfo for + the two cases below.) +stBlock scNil cb isymMac (struct/union member define) +stBlock scNil cMembers isymMac (enum member define) + + (New types added by SGI to simplify things:) +stStruct scInfo cb isymMac (struct type define) +stUnion scInfo cb isymMac (union type define) +stEnum scInfo cMembers isymMac (enum type define) + +stEnd scText address isymStart +stEnd scNil ------- isymStart (struct/union/enum) + +stTypedef scNil ------- iaux +stRegReloc sc??? value old register number +stForward sc??? new address isym to original symbol + +stConstant scInfo value --- (scalar) +stConstant scInfo iss --- (complex, e.g. string) + + * + */ +#endif diff --git a/gnu/usr.bin/gdb/gdb/coff/symconst.h b/gnu/usr.bin/gdb/gdb/coff/symconst.h new file mode 100644 index 00000000000..e4ed620131d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coff/symconst.h @@ -0,0 +1,175 @@ +/* Declarations of constants for internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* glevels for field in FDR */ +#define GLEVEL_0 2 +#define GLEVEL_1 1 +#define GLEVEL_2 0 /* for upward compat reasons. */ +#define GLEVEL_3 3 + +/* magic number fo symheader */ +#define magicSym 0x7009 +/* The Alpha uses this value instead, for some reason. */ +#define magicSym2 0x1992 + +/* Language codes */ +#define langC 0 +#define langPascal 1 +#define langFortran 2 +#define langAssembler 3 /* one Assembley inst might map to many mach */ +#define langMachine 4 +#define langNil 5 +#define langAda 6 +#define langPl1 7 +#define langCobol 8 +#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ +#define langCplusplus 9 /* FIXME: Collides with langStdc */ +#define langCplusplusV2 10 /* SGI addition */ +#define langMax 11 /* maximun allowed 32 -- 5 bits */ + +/* The following are value definitions for the fields in the SYMR */ + +/* + * Storage Classes + */ + +#define scNil 0 +#define scText 1 /* text symbol */ +#define scData 2 /* initialized data symbol */ +#define scBss 3 /* un-initialized data symbol */ +#define scRegister 4 /* value of symbol is register number */ +#define scAbs 5 /* value of symbol is absolute */ +#define scUndefined 6 /* who knows? */ +#define scCdbLocal 7 /* variable's value is IN se->va.?? */ +#define scBits 8 /* this is a bit field */ +#define scCdbSystem 9 /* variable's value is IN CDB's address space */ +#define scDbx 9 /* overlap dbx internal use */ +#define scRegImage 10 /* register value saved on stack */ +#define scInfo 11 /* symbol contains debugger information */ +#define scUserStruct 12 /* address in struct user for current process */ +#define scSData 13 /* load time only small data */ +#define scSBss 14 /* load time only small common */ +#define scRData 15 /* load time only read only data */ +#define scVar 16 /* Var parameter (fortran,pascal) */ +#define scCommon 17 /* common variable */ +#define scSCommon 18 /* small common */ +#define scVarRegister 19 /* Var parameter in a register */ +#define scVariant 20 /* Variant record */ +#define scSUndefined 21 /* small undefined(external) data */ +#define scInit 22 /* .init section symbol */ +#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ +#define scXData 24 /* exception handling data */ +#define scPData 25 /* Procedure section */ +#define scFini 26 /* .fini section */ +#define scMax 32 + + +/* + * Symbol Types + */ + +#define stNil 0 /* Nuthin' special */ +#define stGlobal 1 /* external symbol */ +#define stStatic 2 /* static */ +#define stParam 3 /* procedure argument */ +#define stLocal 4 /* local variable */ +#define stLabel 5 /* label */ +#define stProc 6 /* " " Procedure */ +#define stBlock 7 /* beginnning of block */ +#define stEnd 8 /* end (of anything) */ +#define stMember 9 /* member (of anything - struct/union/enum */ +#define stTypedef 10 /* type definition */ +#define stFile 11 /* file name */ +#define stRegReloc 12 /* register relocation */ +#define stForward 13 /* forwarding address */ +#define stStaticProc 14 /* load time only static procs */ +#define stConstant 15 /* const */ +#define stStaParam 16 /* Fortran static parameters */ + /* These new symbol types have been recently added to SGI machines. */ +#define stStruct 26 /* Beginning of block defining a struct type */ +#define stUnion 27 /* Beginning of block defining a union type */ +#define stEnum 28 /* Beginning of block defining an enum type */ + /* Psuedo-symbols - internal to debugger */ +#define stStr 60 /* string */ +#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ +#define stExpr 62 /* 2+2 vs. 4 */ +#define stType 63 /* post-coersion SER */ +#define stMax 64 + +/* definitions for fields in TIR */ + +/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ +#define tqNil 0 /* bt is what you see */ +#define tqPtr 1 /* pointer */ +#define tqProc 2 /* procedure */ +#define tqArray 3 /* duh */ +#define tqFar 4 /* longer addressing - 8086/8 land */ +#define tqVol 5 /* volatile */ +#define tqConst 6 /* const */ +#define tqMax 8 + +/* basic types as seen in ti.bt */ +#define btNil 0 /* undefined (also, enum members) */ +#define btAdr 1 /* address - integer same size as pointer */ +#define btChar 2 /* character */ +#define btUChar 3 /* unsigned character */ +#define btShort 4 /* short */ +#define btUShort 5 /* unsigned short */ +#define btInt 6 /* int */ +#define btUInt 7 /* unsigned int */ +#define btLong 8 /* long */ +#define btULong 9 /* unsigned long */ +#define btFloat 10 /* float (real) */ +#define btDouble 11 /* Double (real) */ +#define btStruct 12 /* Structure (Record) */ +#define btUnion 13 /* Union (variant) */ +#define btEnum 14 /* Enumerated */ +#define btTypedef 15 /* defined via a typedef, isymRef points */ +#define btRange 16 /* subrange of int */ +#define btSet 17 /* pascal sets */ +#define btComplex 18 /* fortran complex */ +#define btDComplex 19 /* fortran double complex */ +#define btIndirect 20 /* forward or unnamed typedef */ +#define btFixedDec 21 /* Fixed Decimal */ +#define btFloatDec 22 /* Float Decimal */ +#define btString 23 /* Varying Length Character String */ +#define btBit 24 /* Aligned Bit String */ +#define btPicture 25 /* Picture */ +#define btVoid 26 /* void */ +#define btLongLong 27 /* long long */ +#define btULongLong 28 /* unsigned long long */ +#define btMax 64 + +#if (_MFG == _MIPS) +/* optimization type codes */ +#define otNil 0 +#define otReg 1 /* move var to reg */ +#define otBlock 2 /* begin basic block */ +#define otProc 3 /* procedure */ +#define otInline 4 /* inline procedure */ +#define otEnd 5 /* whatever you started */ +#define otMax 6 /* KEEP UP TO DATE */ +#endif /* (_MFG == _MIPS) */ diff --git a/gnu/usr.bin/gdb/gdb/coffread.c b/gnu/usr.bin/gdb/gdb/coffread.c new file mode 100644 index 00000000000..eb0905b867a --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coffread.c @@ -0,0 +1,2071 @@ +/* Read coff symbol tables and convert to internal format, for GDB. + Contributed by David D. Johnson, Brown University (ddj@cs.brown.edu). + Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993 + 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "breakpoint.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "gdb-stabs.h" +#include "complaints.h" +#include + +#include + +#include /* For time_t in libbfd.h. */ +#include /* For time_t, if not in time.h. */ +#include "libbfd.h" /* FIXME secret internal data from BFD */ +#include "coff/internal.h" /* Internal format of COFF symbols in BFD */ +#include "libcoff.h" /* FIXME secret internal data from BFD */ + +struct coff_symfile_info { + file_ptr min_lineno_offset; /* Where in file lowest line#s are */ + file_ptr max_lineno_offset; /* 1+last byte of line#s in file */ + + asection *stabsect; /* Section pointer for .stab section */ + asection *stabstrsect; /* Section pointer for .stab section */ + asection *stabindexsect; /* Section pointer for .stab.index section */ + char *stabstrdata; +}; + +/* Translate an external name string into a user-visible name. */ +#define EXTERNAL_NAME(string, abfd) \ + (string[0] == bfd_get_symbol_leading_char(abfd)? string+1: string) + +/* To be an sdb debug type, type must have at least a basic or primary + derived type. Using this rather than checking against T_NULL is + said to prevent core dumps if we try to operate on Michael Bloom + dbx-in-coff file. */ + +#define SDB_TYPE(type) (BTYPE(type) | (type & N_TMASK)) + +/* + * Convert from an sdb register number to an internal gdb register number. + * This should be defined in tm.h, if REGISTER_NAMES is not set up + * to map one to one onto the sdb register numbers. + */ +#ifndef SDB_REG_TO_REGNUM +# define SDB_REG_TO_REGNUM(value) (value) +#endif + +/* Core address of start and end of text of current source file. + This comes from a ".text" symbol where x_nlinno > 0. */ + +static CORE_ADDR cur_src_start_addr; +static CORE_ADDR cur_src_end_addr; + +/* Core address of the end of the first object file. */ +static CORE_ADDR first_object_file_end; + +/* The addresses of the symbol table stream and number of symbols + of the object file we are reading (as copied into core). */ + +static FILE *nlist_stream_global; +static int nlist_nsyms_global; + +/* Vector of line number information. */ + +static struct linetable *line_vector; + +/* Index of next entry to go in line_vector_index. */ + +static int line_vector_index; + +/* Last line number recorded in the line vector. */ + +static int prev_line_number; + +/* Number of elements allocated for line_vector currently. */ + +static int line_vector_length; + +/* Pointers to scratch storage, used for reading raw symbols and auxents. */ + +static char *temp_sym; +static char *temp_aux; + +/* Local variables that hold the shift and mask values for the + COFF file that we are currently reading. These come back to us + from BFD, and are referenced by their macro names, as well as + internally to the BTYPE, ISPTR, ISFCN, ISARY, ISTAG, and DECREF + macros from ../internalcoff.h . */ + +static unsigned local_n_btmask; +static unsigned local_n_btshft; +static unsigned local_n_tmask; +static unsigned local_n_tshift; + +#define N_BTMASK local_n_btmask +#define N_BTSHFT local_n_btshft +#define N_TMASK local_n_tmask +#define N_TSHIFT local_n_tshift + +/* Local variables that hold the sizes in the file of various COFF structures. + (We only need to know this to read them from the file -- BFD will then + translate the data in them, into `internal_xxx' structs in the right + byte order, alignment, etc.) */ + +static unsigned local_linesz; +static unsigned local_symesz; +static unsigned local_auxesz; + + +/* Chain of typedefs of pointers to empty struct/union types. + They are chained thru the SYMBOL_VALUE_CHAIN. */ + +static struct symbol *opaque_type_chain[HASHSIZE]; + +#if 0 +/* The type of the function we are currently reading in. This is + used by define_symbol to record the type of arguments to a function. */ + +struct type *in_function_type; +#endif + +struct pending_block *pending_blocks; + +/* Complaints about various problems in the file being read */ + +struct complaint ef_complaint = + {"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0}; + +struct complaint bf_no_aux_complaint = + {"`.bf' symbol %d has no aux entry", 0, 0}; + +struct complaint ef_no_aux_complaint = + {"`.ef' symbol %d has no aux entry", 0, 0}; + +struct complaint lineno_complaint = + {"Line number pointer %d lower than start of line numbers", 0, 0}; + +struct complaint unexpected_type_complaint = + {"Unexpected type for symbol %s", 0, 0}; + +struct complaint bad_sclass_complaint = + {"Bad n_sclass for symbol %s", 0, 0}; + +struct complaint misordered_blocks_complaint = + {"Blocks out of order at address %x", 0, 0}; + +struct complaint tagndx_bad_complaint = + {"Symbol table entry for %s has bad tagndx value", 0, 0}; + +struct complaint eb_complaint = + {"Mismatched .eb symbol ignored starting at symnum %d", 0, 0}; + +/* Simplified internal version of coff symbol table information */ + +struct coff_symbol { + char *c_name; + int c_symnum; /* symbol number of this entry */ + int c_naux; /* 0 if syment only, 1 if syment + auxent, etc */ + long c_value; + int c_sclass; + int c_secnum; + unsigned int c_type; +}; + +static struct type * +coff_read_struct_type PARAMS ((int, int, int)); + +static struct type * +decode_base_type PARAMS ((struct coff_symbol *, unsigned int, + union internal_auxent *)); + +static struct type * +decode_type PARAMS ((struct coff_symbol *, unsigned int, + union internal_auxent *)); + +static struct type * +decode_function_type PARAMS ((struct coff_symbol *, unsigned int, + union internal_auxent *)); + +static struct type * +coff_read_enum_type PARAMS ((int, int, int)); + +static struct symbol * +process_coff_symbol PARAMS ((struct coff_symbol *, union internal_auxent *, + struct objfile *)); + +static void +patch_opaque_types PARAMS ((struct symtab *)); + +static void +patch_type PARAMS ((struct type *, struct type *)); + +static void +enter_linenos PARAMS ((long, int, int)); + +static void +free_linetab PARAMS ((void)); + +static int +init_lineno PARAMS ((int, long, int)); + +static char * +getfilename PARAMS ((union internal_auxent *)); + +static char * +getsymname PARAMS ((struct internal_syment *)); + +static void +free_stringtab PARAMS ((void)); + +static int +init_stringtab PARAMS ((int, long)); + +static void +read_one_sym PARAMS ((struct coff_symbol *, struct internal_syment *, + union internal_auxent *)); + +static void +read_coff_symtab PARAMS ((long, int, struct objfile *)); + +static void +find_linenos PARAMS ((bfd *, sec_ptr, PTR)); + +static void +coff_symfile_init PARAMS ((struct objfile *)); + +static void +coff_new_init PARAMS ((struct objfile *)); + +static void +coff_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +coff_symfile_finish PARAMS ((struct objfile *)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type)); + +static void +coff_end_symtab PARAMS ((struct objfile *)); + +static void +complete_symtab PARAMS ((char *, CORE_ADDR, unsigned int)); + +static void +coff_start_symtab PARAMS ((void)); + +static void +coff_record_line PARAMS ((int, CORE_ADDR)); + +static struct type * +coff_alloc_type PARAMS ((int)); + +static struct type ** +coff_lookup_type PARAMS ((int)); + + +static void +coff_locate_sections PARAMS ((bfd *, asection *, PTR)); + +/* We are called once per section from coff_symfile_read. We + need to examine each section we are passed, check to see + if it is something we are interested in processing, and + if so, stash away some access information for the section. + + FIXME: The section names should not be hardwired strings (what + should they be? I don't think most object file formats have enough + section flags to specify what kind of debug section it is + -kingdon). */ + +static void +coff_locate_sections (ignore_abfd, sectp, csip) + bfd *ignore_abfd; + asection *sectp; + PTR csip; +{ + register struct coff_symfile_info *csi; + + csi = (struct coff_symfile_info *) csip; + if (STREQ (sectp->name, ".stab")) + { + csi->stabsect = sectp; + } + else if (STREQ (sectp->name, ".stabstr")) + { + csi->stabstrsect = sectp; + } + else if (STREQ (sectp->name, ".stab.index")) + { + csi->stabindexsect = sectp; + } +} + +/* Look up a coff type-number index. Return the address of the slot + where the type for that index is stored. + The type-number is in INDEX. + + This can be used for finding the type associated with that index + or for associating a new type with the index. */ + +static struct type ** +coff_lookup_type (index) + register int index; +{ + if (index >= type_vector_length) + { + int old_vector_length = type_vector_length; + + type_vector_length *= 2; + if (index /* is still */ >= type_vector_length) { + type_vector_length = index * 2; + } + type_vector = (struct type **) + xrealloc ((char *) type_vector, + type_vector_length * sizeof (struct type *)); + memset (&type_vector[old_vector_length], 0, + (type_vector_length - old_vector_length) * sizeof(struct type *)); + } + return &type_vector[index]; +} + +/* Make sure there is a type allocated for type number index + and return the type object. + This can create an empty (zeroed) type object. */ + +static struct type * +coff_alloc_type (index) + int index; +{ + register struct type **type_addr = coff_lookup_type (index); + register struct type *type = *type_addr; + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (type == NULL) + { + type = alloc_type (current_objfile); + *type_addr = type; + } + return type; +} + +/* Record a line number entry for line LINE at address PC. + FIXME: Use record_line instead. */ + +static void +coff_record_line (line, pc) + int line; + CORE_ADDR pc; +{ + struct linetable_entry *e; + /* Make sure line vector is big enough. */ + + if (line_vector_index + 2 >= line_vector_length) + { + line_vector_length *= 2; + line_vector = (struct linetable *) + xrealloc ((char *) line_vector, sizeof (struct linetable) + + (line_vector_length + * sizeof (struct linetable_entry))); + } + + e = line_vector->item + line_vector_index++; + e->line = line; e->pc = pc; +} + +/* Start a new symtab for a new source file. + This is called when a COFF ".file" symbol is seen; + it indicates the start of data for one original source file. */ + +static void +coff_start_symtab () +{ + start_symtab ( + /* We fill in the filename later. start_symtab + puts this pointer into last_source file and in + coff_end_symtab we assume we can free() it. + FIXME: leaks memory. */ + savestring ("", 0), + /* We never know the directory name for COFF. */ + NULL, + /* The start address is irrelevant, since we set + last_source_start_addr in coff_end_symtab. */ + 0); + + /* Initialize the source file line number information for this file. */ + + if (line_vector) /* Unlikely, but maybe possible? */ + free ((PTR)line_vector); + line_vector_index = 0; + line_vector_length = 1000; + prev_line_number = -2; /* Force first line number to be explicit */ + line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + line_vector_length * sizeof (struct linetable_entry)); +} + +/* Save the vital information from when starting to read a file, + for use when closing off the current file. + NAME is the file name the symbols came from, START_ADDR is the first + text address for the file, and SIZE is the number of bytes of text. */ + +static void +complete_symtab (name, start_addr, size) + char *name; + CORE_ADDR start_addr; + unsigned int size; +{ + last_source_file = savestring (name, strlen (name)); + cur_src_start_addr = start_addr; + cur_src_end_addr = start_addr + size; + + if (current_objfile -> ei.entry_point >= cur_src_start_addr && + current_objfile -> ei.entry_point < cur_src_end_addr) + { + current_objfile -> ei.entry_file_lowpc = cur_src_start_addr; + current_objfile -> ei.entry_file_highpc = cur_src_end_addr; + } +} + +/* Finish the symbol definitions for one main source file, + close off all the lexical contexts for that file + (creating struct block's for them), then make the + struct symtab for that file and put it in the list of all such. */ + +static void +coff_end_symtab (objfile) + struct objfile *objfile; +{ + struct symtab *symtab; + + last_source_start_addr = cur_src_start_addr; + + /* For no good reason, this file stores the number of entries in a + separate variable instead of in line_vector->nitems. Fix it. */ + if (line_vector) + line_vector->nitems = line_vector_index; + + /* For COFF, we only have one subfile, so we can just look at + subfiles and not worry about there being other elements in the + chain. We fill in various fields now because we didn't know them + before (or because doing it now is simply an artifact of how this + file used to be written). */ + subfiles->line_vector = line_vector; + subfiles->name = last_source_file; + + /* sort_pending is needed for amdcoff, at least. + sort_linevec is needed for the SCO compiler. */ + symtab = end_symtab (cur_src_end_addr, 1, 1, objfile, 0); + + if (symtab != NULL) + free_named_symtabs (symtab->filename); + + /* Reinitialize for beginning of new file. */ + line_vector = 0; + line_vector_length = -1; + last_source_file = NULL; +} + +static void +record_minimal_symbol (name, address, type) + char *name; + CORE_ADDR address; + enum minimal_symbol_type type; +{ + /* We don't want TDESC entry points in the minimal symbol table */ + if (name[0] == '@') return; + + prim_record_minimal_symbol (savestring (name, strlen (name)), address, type); +} + +/* coff_symfile_init () + is the coff-specific initialization routine for reading symbols. + It is passed a struct objfile which contains, among other things, + the BFD for the file whose symbols are being read, and a slot for + a pointer to "private data" which we fill with cookies and other + treats for coff_symfile_read (). + + We will only be called if this is a COFF or COFF-like file. + BFD handles figuring out the format of the file, and code in symtab.c + uses BFD's determination to vector to us. + + The ultimate result is a new symtab (or, FIXME, eventually a psymtab). */ + +static int text_bfd_scnum; + +static void +coff_symfile_init (objfile) + struct objfile *objfile; +{ + asection *section, *strsection; + bfd *abfd = objfile->obfd; + + /* Allocate struct to keep track of stab reading. */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + + memset ((PTR) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info)); + + /* Allocate struct to keep track of the symfile */ + objfile -> sym_private = xmmalloc (objfile -> md, + sizeof (struct coff_symfile_info)); + + memset (objfile->sym_private, 0, sizeof (struct coff_symfile_info)); + + init_entry_point_info (objfile); + + /* Save the section number for the text section */ + section = bfd_get_section_by_name (abfd, ".text"); + if (section) + text_bfd_scnum = section->index; + else + text_bfd_scnum = -1; +} + +/* This function is called for every section; it finds the outer limits + of the line table (minimum and maximum file offset) so that the + mainline code can read the whole thing for efficiency. */ + +/* ARGSUSED */ +static void +find_linenos (abfd, asect, vpinfo) + bfd *abfd; + sec_ptr asect; + PTR vpinfo; +{ + struct coff_symfile_info *info; + int size, count; + file_ptr offset, maxoff; + +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + count = asect->lineno_count; +/* End of warning */ + + if (count == 0) + return; + size = count * local_linesz; + + info = (struct coff_symfile_info *)vpinfo; +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + offset = asect->line_filepos; +/* End of warning */ + + if (offset < info->min_lineno_offset || info->min_lineno_offset == 0) + info->min_lineno_offset = offset; + + maxoff = offset + size; + if (maxoff > info->max_lineno_offset) + info->max_lineno_offset = maxoff; +} + + +/* The BFD for this file -- only good while we're actively reading + symbols into a psymtab or a symtab. */ + +static bfd *symfile_bfd; + +/* Read a symbol file, after initialization by coff_symfile_init. */ +/* FIXME! Addr and Mainline are not used yet -- this will not work for + shared libraries or add_file! */ + +/* ARGSUSED */ +static void +coff_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + struct coff_symfile_info *info; + struct dbx_symfile_info *dbxinfo; + bfd *abfd = objfile->obfd; + coff_data_type *cdata = coff_data (abfd); + char *name = bfd_get_filename (abfd); + int desc; + register int val; + int num_symbols; + int symtab_offset; + int stringtab_offset; + struct cleanup *back_to; + int stabsize, stabstrsize; + + info = (struct coff_symfile_info *) objfile -> sym_private; + dbxinfo = (struct dbx_symfile_info *) objfile->sym_stab_info; + symfile_bfd = abfd; /* Kludge for swap routines */ + +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + desc = fileno ((FILE *)(abfd->iostream)); /* File descriptor */ + num_symbols = bfd_get_symcount (abfd); /* How many syms */ + symtab_offset = cdata->sym_filepos; /* Symbol table file offset */ + stringtab_offset = symtab_offset + /* String table file offset */ + num_symbols * cdata->local_symesz; + + /* Set a few file-statics that give us specific information about + the particular COFF file format we're reading. */ + local_linesz = cdata->local_linesz; + local_n_btmask = cdata->local_n_btmask; + local_n_btshft = cdata->local_n_btshft; + local_n_tmask = cdata->local_n_tmask; + local_n_tshift = cdata->local_n_tshift; + local_linesz = cdata->local_linesz; + local_symesz = cdata->local_symesz; + local_auxesz = cdata->local_auxesz; + + /* Allocate space for raw symbol and aux entries, based on their + space requirements as reported by BFD. */ + temp_sym = (char *) xmalloc + (cdata->local_symesz + cdata->local_auxesz); + temp_aux = temp_sym + cdata->local_symesz; + back_to = make_cleanup (free_current_contents, &temp_sym); +/* End of warning */ + + /* Read the line number table, all at once. */ + info->min_lineno_offset = 0; + info->max_lineno_offset = 0; + bfd_map_over_sections (abfd, find_linenos, (PTR) info); + + make_cleanup (free_linetab, 0); + val = init_lineno (desc, info->min_lineno_offset, + info->max_lineno_offset - info->min_lineno_offset); + if (val < 0) + error ("\"%s\": error reading line numbers\n", name); + + /* Now read the string table, all at once. */ + + make_cleanup (free_stringtab, 0); + val = init_stringtab (desc, stringtab_offset); + if (val < 0) + error ("\"%s\": can't get string table", name); + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + read_coff_symtab ((long)symtab_offset, num_symbols, objfile); + + /* Sort symbols alphabetically within each block. */ + + sort_all_symtab_syms (); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + bfd_map_over_sections (abfd, coff_locate_sections, (PTR) info); + + if (info->stabsect) + { + /* FIXME: dubious. Why can't we use something normal like + bfd_get_section_contents? */ + fseek ((FILE *) abfd->iostream, abfd->where, 0); + + stabsize = bfd_section_size (abfd, info->stabsect); + stabstrsize = bfd_section_size (abfd, info->stabstrsect); + + coffstab_build_psymtabs (objfile, + section_offsets, + mainline, + info->stabsect->filepos, stabsize, + info->stabstrsect->filepos, stabstrsize); + } + + do_cleanups (back_to); +} + +static void +coff_new_init (ignore) + struct objfile *ignore; +{ +} + +/* Perform any local cleanups required when we are done with a particular + objfile. I.E, we are in the process of discarding all symbol information + for an objfile, freeing up all memory held for it, and unlinking the + objfile struct from the global list of known objfiles. */ + +static void +coff_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_private != NULL) + { + mfree (objfile -> md, objfile -> sym_private); + } +} + + +/* Given pointers to a symbol table in coff style exec file, + analyze them and create struct symtab's describing the symbols. + NSYMS is the number of symbols in the symbol table. + We read them one at a time using read_one_sym (). */ + +static void +read_coff_symtab (symtab_offset, nsyms, objfile) + long symtab_offset; + int nsyms; + struct objfile *objfile; +{ + FILE *stream; + register struct context_stack *new; + struct coff_symbol coff_symbol; + register struct coff_symbol *cs = &coff_symbol; + static struct internal_syment main_sym; + static union internal_auxent main_aux; + struct coff_symbol fcn_cs_saved; + static struct internal_syment fcn_sym_saved; + static union internal_auxent fcn_aux_saved; + struct symtab *s; + + /* A .file is open. */ + int in_source_file = 0; + int num_object_files = 0; + int next_file_symnum = -1; + + /* Name of the current file. */ + char *filestring = ""; + int depth = 0; + int fcn_first_line = 0; + int fcn_last_line = 0; + int fcn_start_addr = 0; + long fcn_line_ptr = 0; + int val; + + stream = bfd_cache_lookup(objfile->obfd); + if (!stream) + perror_with_name(objfile->name); + + /* Work around a stdio bug in SunOS4.1.1 (this makes me nervous.... + it's hard to know I've really worked around it. The fix should be + harmless, anyway). The symptom of the bug is that the first + fread (in read_one_sym), will (in my example) actually get data + from file offset 268, when the fseek was to 264 (and ftell shows + 264). This causes all hell to break loose. I was unable to + reproduce this on a short test program which operated on the same + file, performing (I think) the same sequence of operations. + + It stopped happening when I put in this rewind(). + + FIXME: Find out if this has been reported to Sun, whether it has + been fixed in a later release, etc. */ + + rewind (stream); + + /* Position to read the symbol table. */ + val = fseek (stream, (long)symtab_offset, 0); + if (val < 0) + perror_with_name (objfile->name); + + current_objfile = objfile; + nlist_stream_global = stream; + nlist_nsyms_global = nsyms; + last_source_file = NULL; + memset (opaque_type_chain, 0, sizeof opaque_type_chain); + + if (type_vector) /* Get rid of previous one */ + free ((PTR)type_vector); + type_vector_length = 160; + type_vector = (struct type **) + xmalloc (type_vector_length * sizeof (struct type *)); + memset (type_vector, 0, type_vector_length * sizeof (struct type *)); + + coff_start_symtab (); + + symnum = 0; + while (symnum < nsyms) + { + QUIT; /* Make this command interruptable. */ + read_one_sym (cs, &main_sym, &main_aux); + +#ifdef SEM + temp_sem_val = cs->c_name[0] << 24 | cs->c_name[1] << 16 | + cs->c_name[2] << 8 | cs->c_name[3]; + if (int_sem_val == temp_sem_val) + last_coffsem = (int) strtol (cs->c_name+4, (char **) NULL, 10); +#endif + + if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) + { + if (last_source_file) + coff_end_symtab (objfile); + + coff_start_symtab (); + complete_symtab ("_globals_", 0, first_object_file_end); + /* done with all files, everything from here on out is globals */ + } + + /* Special case for file with type declarations only, no text. */ + if (!last_source_file && SDB_TYPE (cs->c_type) + && cs->c_secnum == N_DEBUG) + complete_symtab (filestring, 0, 0); + + /* Typedefs should not be treated as symbol definitions. */ + if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF) + { + /* Record all functions -- external and static -- in minsyms. */ + record_minimal_symbol (cs->c_name, cs->c_value, mst_text); + + fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; + fcn_start_addr = cs->c_value; + fcn_cs_saved = *cs; + fcn_sym_saved = main_sym; + fcn_aux_saved = main_aux; + continue; + } + + switch (cs->c_sclass) + { + case C_EFCN: + case C_EXTDEF: + case C_ULABEL: + case C_USTATIC: + case C_LINE: + case C_ALIAS: + case C_HIDDEN: + complain (&bad_sclass_complaint, cs->c_name); + break; + + case C_FILE: + /* + * c_value field contains symnum of next .file entry in table + * or symnum of first global after last .file. + */ + next_file_symnum = cs->c_value; + if (cs->c_naux > 0) + filestring = getfilename (&main_aux); + else + filestring = ""; + + /* + * Complete symbol table for last object file + * containing debugging information. + */ + if (last_source_file) + { + coff_end_symtab (objfile); + coff_start_symtab (); + } + in_source_file = 1; + break; + + case C_STAT: + if (cs->c_name[0] == '.') { + if (STREQ (cs->c_name, ".text")) { + /* FIXME: don't wire in ".text" as section name + or symbol name! */ + if (++num_object_files == 1) { + /* last address of startup file */ + first_object_file_end = cs->c_value + + main_aux.x_scn.x_scnlen; + } + /* Check for in_source_file deals with case of + a file with debugging symbols + followed by a later file with no symbols. */ + if (in_source_file) + complete_symtab (filestring, cs->c_value, + main_aux.x_scn.x_scnlen); + in_source_file = 0; + } + /* flush rest of '.' symbols */ + break; + } + else if (!SDB_TYPE (cs->c_type) + && cs->c_name[0] == 'L' + && (strncmp (cs->c_name, "LI%", 3) == 0 + || strncmp (cs->c_name, "LF%", 3) == 0 + || strncmp (cs->c_name,"LC%",3) == 0 + || strncmp (cs->c_name,"LP%",3) == 0 + || strncmp (cs->c_name,"LPB%",4) == 0 + || strncmp (cs->c_name,"LBB%",4) == 0 + || strncmp (cs->c_name,"LBE%",4) == 0 + || strncmp (cs->c_name,"LPBX%",5) == 0)) + /* At least on a 3b1, gcc generates swbeg and string labels + that look like this. Ignore them. */ + break; + /* fall in for static symbols that don't start with '.' */ + case C_EXT: + /* Record external symbols in minsyms if we don't have debug + info for them. FIXME, this is probably the wrong thing + to do. Why don't we record them even if we do have + debug symbol info? What really belongs in the minsyms + anyway? Fred!?? */ + if (!SDB_TYPE (cs->c_type)) { + /* FIXME: This is BOGUS Will Robinson! + Coff should provide the SEC_CODE flag for executable sections, + then if we could look up sections by section number we + could see if the flags indicate SEC_CODE. If so, then + record this symbol as a function in the minimal symbol table. + But why are absolute syms recorded as functions, anyway? */ + if (cs->c_secnum <= text_bfd_scnum+1) {/* text or abs */ + record_minimal_symbol (cs->c_name, cs->c_value, + mst_text); + break; + } else { + record_minimal_symbol (cs->c_name, cs->c_value, + mst_data); + break; + } + } + process_coff_symbol (cs, &main_aux, objfile); + break; + + case C_FCN: + if (STREQ (cs->c_name, ".bf")) + { + within_function = 1; + + /* value contains address of first non-init type code */ + /* main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains line number of '{' } */ + if (cs->c_naux != 1) + complain (&bf_no_aux_complaint, cs->c_symnum); + fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + + /* Might want to check that locals are 0 and + context_stack_depth is zero, and complain if not. */ + + depth = 0; + new = push_context (depth, fcn_start_addr); + fcn_cs_saved.c_name = getsymname (&fcn_sym_saved); + new->name = process_coff_symbol (&fcn_cs_saved, + &fcn_aux_saved, objfile); + } + else if (STREQ (cs->c_name, ".ef")) + { + /* the value of .ef is the address of epilogue code; + not useful for gdb. */ + /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains number of lines to '}' */ + new = pop_context (); + /* Stack must be empty now. */ + if (context_stack_depth > 0 || new == NULL) + { + complain (&ef_complaint, cs->c_symnum); + within_function = 0; + break; + } + if (cs->c_naux != 1) + { + complain (&ef_no_aux_complaint, cs->c_symnum); + fcn_last_line = 0x7FFFFFFF; + } + else + { + fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + } + enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line); + + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, +#if defined (FUNCTION_EPILOGUE_SIZE) + /* This macro should be defined only on + machines where the + fcn_aux_saved.x_sym.x_misc.x_fsize + field is always zero. + So use the .bf record information that + points to the epilogue and add the size + of the epilogue. */ + cs->c_value + FUNCTION_EPILOGUE_SIZE, +#else + fcn_cs_saved.c_value + + fcn_aux_saved.x_sym.x_misc.x_fsize, +#endif + objfile + ); + within_function = 0; + } + break; + + case C_BLOCK: + if (STREQ (cs->c_name, ".bb")) + { + push_context (++depth, cs->c_value); + } + else if (STREQ (cs->c_name, ".eb")) + { + new = pop_context (); + if (depth-- != new->depth) + { + complain (&eb_complaint, symnum); + break; + } + if (local_symbols && context_stack_depth > 0) + { + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, cs->c_value, objfile); + } + /* Now pop locals of block just finished. */ + local_symbols = new->locals; + } + break; + + default: + process_coff_symbol (cs, &main_aux, objfile); + break; + } + } + + if (last_source_file) + coff_end_symtab (objfile); + + /* Patch up any opaque types (references to types that are not defined + in the file where they are referenced, e.g. "struct foo *bar"). */ + ALL_OBJFILE_SYMTABS (objfile, s) + patch_opaque_types (s); + + current_objfile = NULL; +} + +/* Routines for reading headers and symbols from executable. */ + +#ifdef FIXME +/* Move these XXXMAGIC symbol defns into BFD! */ + +/* Read COFF file header, check magic number, + and return number of symbols. */ +read_file_hdr (chan, file_hdr) + int chan; + FILHDR *file_hdr; +{ + lseek (chan, 0L, 0); + if (myread (chan, (char *)file_hdr, FILHSZ) < 0) + return -1; + + switch (file_hdr->f_magic) + { +#ifdef MC68MAGIC + case MC68MAGIC: +#endif +#ifdef NS32GMAGIC + case NS32GMAGIC: + case NS32SMAGIC: +#endif +#ifdef I386MAGIC + case I386MAGIC: +#endif +#ifdef CLIPPERMAGIC + case CLIPPERMAGIC: +#endif +#if defined (MC68KWRMAGIC) \ + && (!defined (MC68MAGIC) || MC68KWRMAGIC != MC68MAGIC) + case MC68KWRMAGIC: +#endif +#ifdef MC68KROMAGIC + case MC68KROMAGIC: + case MC68KPGMAGIC: +#endif +#ifdef MC88DGMAGIC + case MC88DGMAGIC: +#endif +#ifdef MC88MAGIC + case MC88MAGIC: +#endif +#ifdef I960ROMAGIC + case I960ROMAGIC: /* Intel 960 */ +#endif +#ifdef I960RWMAGIC + case I960RWMAGIC: /* Intel 960 */ +#endif + return file_hdr->f_nsyms; + + default: +#ifdef BADMAG + if (BADMAG(file_hdr)) + return -1; + else + return file_hdr->f_nsyms; +#else + return -1; +#endif + } +} +#endif + +/* Read the next symbol, swap it, and return it in both internal_syment + form, and coff_symbol form. Also return its first auxent, if any, + in internal_auxent form, and skip any other auxents. */ + +static void +read_one_sym (cs, sym, aux) + register struct coff_symbol *cs; + register struct internal_syment *sym; + register union internal_auxent *aux; +{ + int i; + + cs->c_symnum = symnum; + fread (temp_sym, local_symesz, 1, nlist_stream_global); + bfd_coff_swap_sym_in (symfile_bfd, temp_sym, (char *)sym); + cs->c_naux = sym->n_numaux & 0xff; + if (cs->c_naux >= 1) + { + fread (temp_aux, local_auxesz, 1, nlist_stream_global); + bfd_coff_swap_aux_in (symfile_bfd, temp_aux, sym->n_type, sym->n_sclass, + (char *)aux); + /* If more than one aux entry, read past it (only the first aux + is important). */ + for (i = 1; i < cs->c_naux; i++) + fread (temp_aux, local_auxesz, 1, nlist_stream_global); + } + cs->c_name = getsymname (sym); + cs->c_value = sym->n_value; + cs->c_sclass = (sym->n_sclass & 0xff); + cs->c_secnum = sym->n_scnum; + cs->c_type = (unsigned) sym->n_type; + if (!SDB_TYPE (cs->c_type)) + cs->c_type = 0; + + symnum += 1 + cs->c_naux; +} + +/* Support for string table handling */ + +static char *stringtab = NULL; + +static int +init_stringtab (chan, offset) + int chan; + long offset; +{ + long length; + int val; + unsigned char lengthbuf[4]; + + free_stringtab (); + + if (lseek (chan, offset, 0) < 0) + return -1; + + val = myread (chan, (char *)lengthbuf, sizeof lengthbuf); + length = bfd_h_get_32 (symfile_bfd, lengthbuf); + + /* If no string table is needed, then the file may end immediately + after the symbols. Just return with `stringtab' set to null. */ + if (val != sizeof lengthbuf || length < sizeof lengthbuf) + return 0; + + stringtab = (char *) xmalloc (length); + memcpy (stringtab, &length, sizeof length); + if (length == sizeof length) /* Empty table -- just the count */ + return 0; + + val = myread (chan, stringtab + sizeof lengthbuf, length - sizeof lengthbuf); + if (val != length - sizeof lengthbuf || stringtab[length - 1] != '\0') + return -1; + + return 0; +} + +static void +free_stringtab () +{ + if (stringtab) + free (stringtab); + stringtab = NULL; +} + +static char * +getsymname (symbol_entry) + struct internal_syment *symbol_entry; +{ + static char buffer[SYMNMLEN+1]; + char *result; + + if (symbol_entry->_n._n_n._n_zeroes == 0) + { + result = stringtab + symbol_entry->_n._n_n._n_offset; + } + else + { + strncpy (buffer, symbol_entry->_n._n_name, SYMNMLEN); + buffer[SYMNMLEN] = '\0'; + result = buffer; + } + return result; +} + +/* Extract the file name from the aux entry of a C_FILE symbol. Return + only the last component of the name. Result is in static storage and + is only good for temporary use. */ + +static char * +getfilename (aux_entry) + union internal_auxent *aux_entry; +{ + static char buffer[BUFSIZ]; + register char *temp; + char *result; + + if (aux_entry->x_file.x_n.x_zeroes == 0) + strcpy (buffer, stringtab + aux_entry->x_file.x_n.x_offset); + else + { + strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); + buffer[FILNMLEN] = '\0'; + } + result = buffer; + if ((temp = strrchr (result, '/')) != NULL) + result = temp + 1; + return (result); +} + +/* Support for line number handling */ +static char *linetab = NULL; +static long linetab_offset; +static unsigned long linetab_size; + +/* Read in all the line numbers for fast lookups later. Leave them in + external (unswapped) format in memory; we'll swap them as we enter + them into GDB's data structures. */ + +static int +init_lineno (chan, offset, size) + int chan; + long offset; + int size; +{ + int val; + + linetab_offset = offset; + linetab_size = size; + + free_linetab(); + + if (size == 0) + return 0; + + if (lseek (chan, offset, 0) < 0) + return -1; + + /* Allocate the desired table, plus a sentinel */ + linetab = (char *) xmalloc (size + local_linesz); + + val = myread (chan, linetab, size); + if (val != size) + return -1; + + /* Terminate it with an all-zero sentinel record */ + memset (linetab + size, 0, local_linesz); + + return 0; +} + +static void +free_linetab () +{ + if (linetab) + free (linetab); + linetab = NULL; +} + +#if !defined (L_LNNO32) +#define L_LNNO32(lp) ((lp)->l_lnno) +#endif + +static void +enter_linenos (file_offset, first_line, last_line) + long file_offset; + register int first_line; + register int last_line; +{ + register char *rawptr; + struct internal_lineno lptr; + + if (file_offset < linetab_offset) + { + complain (&lineno_complaint, file_offset); + if (file_offset > linetab_size) /* Too big to be an offset? */ + return; + file_offset += linetab_offset; /* Try reading at that linetab offset */ + } + + rawptr = &linetab[file_offset - linetab_offset]; + + /* skip first line entry for each function */ + rawptr += local_linesz; + /* line numbers start at one for the first line of the function */ + first_line--; + + for (;;) { + bfd_coff_swap_lineno_in (symfile_bfd, rawptr, &lptr); + rawptr += local_linesz; + /* The next function, or the sentinel, will have L_LNNO32 zero; we exit. */ + if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line) + coff_record_line (first_line + L_LNNO32 (&lptr), lptr.l_addr.l_paddr); + else + break; + } +} + +static void +patch_type (type, real_type) + struct type *type; + struct type *real_type; +{ + register struct type *target = TYPE_TARGET_TYPE (type); + register struct type *real_target = TYPE_TARGET_TYPE (real_type); + int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field); + + TYPE_LENGTH (target) = TYPE_LENGTH (real_target); + TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target); + TYPE_FIELDS (target) = (struct field *) TYPE_ALLOC (target, field_size); + + memcpy (TYPE_FIELDS (target), TYPE_FIELDS (real_target), field_size); + + if (TYPE_NAME (real_target)) + { + if (TYPE_NAME (target)) + free (TYPE_NAME (target)); + TYPE_NAME (target) = concat (TYPE_NAME (real_target), NULL); + } +} + +/* Patch up all appropriate typedef symbols in the opaque_type_chains + so that they can be used to print out opaque data structures properly. */ + +static void +patch_opaque_types (s) + struct symtab *s; +{ + register struct block *b; + register int i; + register struct symbol *real_sym; + + /* Go through the per-file symbols only */ + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) + { + /* Find completed typedefs to use to fix opaque ones. + Remove syms from the chain when their types are stored, + but search the whole chain, as there may be several syms + from different files with the same name. */ + real_sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF && + SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE && + TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0) + { + register char *name = SYMBOL_NAME (real_sym); + register int hash = hashname (name); + register struct symbol *sym, *prev; + + prev = 0; + for (sym = opaque_type_chain[hash]; sym;) + { + if (name[0] == SYMBOL_NAME (sym)[0] && + STREQ (name + 1, SYMBOL_NAME (sym) + 1)) + { + if (prev) + { + SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym); + } + else + { + opaque_type_chain[hash] = SYMBOL_VALUE_CHAIN (sym); + } + + patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym)); + + if (prev) + { + sym = SYMBOL_VALUE_CHAIN (prev); + } + else + { + sym = opaque_type_chain[hash]; + } + } + else + { + prev = sym; + sym = SYMBOL_VALUE_CHAIN (sym); + } + } + } + } +} + +static struct symbol * +process_coff_symbol (cs, aux, objfile) + register struct coff_symbol *cs; + register union internal_auxent *aux; + struct objfile *objfile; +{ + register struct symbol *sym + = (struct symbol *) obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + char *name; + struct type *temptype; + + memset (sym, 0, sizeof (struct symbol)); + name = cs->c_name; + name = EXTERNAL_NAME (name, objfile->obfd); + SYMBOL_NAME (sym) = obstack_copy0 (&objfile->symbol_obstack, name, + strlen (name)); + + /* default assumptions */ + SYMBOL_VALUE (sym) = cs->c_value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + if (ISFCN (cs->c_type)) + { +#if 0 + /* FIXME: This has NOT been tested. The DBX version has.. */ + /* Generate a template for the type of this function. The + types of the arguments will be added as we read the symbol + table. */ + struct type *new = (struct type *) + obstack_alloc (&objfile->symbol_obstack, sizeof (struct type)); + + memcpy (new, lookup_function_type (decode_function_type (cs, cs->c_type, aux)), + sizeof(struct type)); + SYMBOL_TYPE (sym) = new; + in_function_type = SYMBOL_TYPE(sym); +#else + SYMBOL_TYPE(sym) = + lookup_function_type (decode_function_type (cs, cs->c_type, aux)); +#endif + + SYMBOL_CLASS (sym) = LOC_BLOCK; + if (cs->c_sclass == C_STAT) + add_symbol_to_list (sym, &file_symbols); + else if (cs->c_sclass == C_EXT) + add_symbol_to_list (sym, &global_symbols); + } + else + { + SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux); + switch (cs->c_sclass) + { + case C_NULL: + break; + + case C_AUTO: + SYMBOL_CLASS (sym) = LOC_LOCAL; + add_symbol_to_list (sym, &local_symbols); + break; + + case C_EXT: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; + add_symbol_to_list (sym, &global_symbols); + break; + + case C_STAT: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; + if (within_function) { + /* Static symbol of local scope */ + add_symbol_to_list (sym, &local_symbols); + } + else { + /* Static symbol at top level of file */ + add_symbol_to_list (sym, &file_symbols); + } + break; + +#ifdef C_GLBLREG /* AMD coff */ + case C_GLBLREG: +#endif + case C_REG: + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value); + add_symbol_to_list (sym, &local_symbols); + break; + + case C_LABEL: + break; + + case C_ARG: + SYMBOL_CLASS (sym) = LOC_ARG; +#if 0 + /* FIXME: This has not been tested. */ + /* Add parameter to function. */ + add_param_to_type(&in_function_type,sym); +#endif + add_symbol_to_list (sym, &local_symbols); +#if !defined (BELIEVE_PCC_PROMOTION) && (TARGET_BYTE_ORDER == BIG_ENDIAN) + /* If PCC says a parameter is a short or a char, + aligned on an int boundary, realign it to the "little end" + of the int. */ + temptype = lookup_fundamental_type (current_objfile, FT_INTEGER); + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT + && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (temptype)) + { + SYMBOL_VALUE (sym) += TYPE_LENGTH (temptype) + - TYPE_LENGTH (SYMBOL_TYPE (sym)); + } +#endif + break; + + case C_REGPARM: + SYMBOL_CLASS (sym) = LOC_REGPARM; + SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value); + add_symbol_to_list (sym, &local_symbols); +#if !defined (BELIEVE_PCC_PROMOTION) + /* FIXME: This should retain the current type, since it's just + a register value. gnu@adobe, 26Feb93 */ + /* If PCC says a parameter is a short or a char, + it is really an int. */ + temptype = lookup_fundamental_type (current_objfile, FT_INTEGER); + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT) + { + SYMBOL_TYPE (sym) = TYPE_UNSIGNED (SYMBOL_TYPE (sym)) + ? lookup_fundamental_type (current_objfile, + FT_UNSIGNED_INTEGER) + : temptype; + } +#endif + break; + + case C_TPDEF: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + /* If type has no name, give it one */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) = concat (SYMBOL_NAME (sym), NULL); + + /* Keep track of any type which points to empty structured type, + so it can be filled from a definition from another file. A + simple forward reference (TYPE_CODE_UNDEF) is not an + empty structured type, though; the forward references + work themselves out via the magic of coff_lookup_type. */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0 && + TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) != + TYPE_CODE_UNDEF) + { + register int i = hashname (SYMBOL_NAME (sym)); + + SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i]; + opaque_type_chain[i] = sym; + } + add_symbol_to_list (sym, &file_symbols); + break; + + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + + /* Some compilers try to be helpful by inventing "fake" + names for anonymous enums, structures, and unions, like + "~0fake" or ".0fake". Thanks, but no thanks... */ + if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0) + if (SYMBOL_NAME(sym) != NULL + && *SYMBOL_NAME(sym) != '~' + && *SYMBOL_NAME(sym) != '.') + TYPE_TAG_NAME (SYMBOL_TYPE (sym)) = + concat (SYMBOL_NAME (sym), NULL); + + add_symbol_to_list (sym, &file_symbols); + break; + + default: + break; + } + } + return sym; +} + +/* Decode a coff type specifier; + return the type that is meant. */ + +static +struct type * +decode_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register union internal_auxent *aux; +{ + register struct type *type = 0; + unsigned int new_c_type; + + if (c_type & ~N_BTMASK) + { + new_c_type = DECREF (c_type); + if (ISPTR (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_pointer_type (type); + } + else if (ISFCN (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_function_type (type); + } + else if (ISARY (c_type)) + { + int i, n; + register unsigned short *dim; + struct type *base_type, *index_type, *range_type; + + /* Define an array type. */ + /* auxent refers to array, not base type */ + if (aux->x_sym.x_tagndx.l == 0) + cs->c_naux = 0; + + /* shift the indices down */ + dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0]; + i = 1; + n = dim[0]; + for (i = 0; *dim && i < DIMNUM - 1; i++, dim++) + *dim = *(dim + 1); + *dim = 0; + + base_type = decode_type (cs, new_c_type, aux); + index_type = lookup_fundamental_type (current_objfile, FT_INTEGER); + range_type = + create_range_type ((struct type *) NULL, index_type, 0, n - 1); + type = + create_array_type ((struct type *) NULL, base_type, range_type); + } + return type; + } + + /* Reference to existing type. This only occurs with the + struct, union, and enum types. EPI a29k coff + fakes us out by producing aux entries with a nonzero + x_tagndx for definitions of structs, unions, and enums, so we + have to check the c_sclass field. SCO 3.2v4 cc gets confused + with pointers to pointers to defined structs, and generates + negative x_tagndx fields. */ + if (cs->c_naux > 0 && aux->x_sym.x_tagndx.l != 0) + { + if (cs->c_sclass != C_STRTAG + && cs->c_sclass != C_UNTAG + && cs->c_sclass != C_ENTAG + && aux->x_sym.x_tagndx.l >= 0) + { + type = coff_alloc_type (aux->x_sym.x_tagndx.l); + return type; + } else { + complain (&tagndx_bad_complaint, cs->c_name); + /* And fall through to decode_base_type... */ + } + } + + return decode_base_type (cs, BTYPE (c_type), aux); +} + +/* Decode a coff type specifier for function definition; + return the type that the function returns. */ + +static +struct type * +decode_function_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register union internal_auxent *aux; +{ + if (aux->x_sym.x_tagndx.l == 0) + cs->c_naux = 0; /* auxent refers to function, not base type */ + + return decode_type (cs, DECREF (c_type), aux); +} + +/* basic C types */ + +static +struct type * +decode_base_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register union internal_auxent *aux; +{ + struct type *type; + + switch (c_type) + { + case T_NULL: + /* shows up with "void (*foo)();" structure members */ + return lookup_fundamental_type (current_objfile, FT_VOID); + +#if 0 +/* DGUX actually defines both T_ARG and T_VOID to the same value. */ +#ifdef T_ARG + case T_ARG: + /* Shows up in DGUX, I think. Not sure where. */ + return lookup_fundamental_type (current_objfile, FT_VOID); /* shouldn't show up here */ +#endif +#endif /* 0 */ + +#ifdef T_VOID + case T_VOID: + /* Intel 960 COFF has this symbol and meaning. */ + return lookup_fundamental_type (current_objfile, FT_VOID); +#endif + + case T_CHAR: + return lookup_fundamental_type (current_objfile, FT_CHAR); + + case T_SHORT: + return lookup_fundamental_type (current_objfile, FT_SHORT); + + case T_INT: + return lookup_fundamental_type (current_objfile, FT_INTEGER); + + case T_LONG: + return lookup_fundamental_type (current_objfile, FT_LONG); + + case T_FLOAT: + return lookup_fundamental_type (current_objfile, FT_FLOAT); + + case T_DOUBLE: + return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT); + + case T_STRUCT: + if (cs->c_naux != 1) + { + /* anonymous structure type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NAME (type) = NULL; + /* This used to set the tag to "". But I think setting it + to NULL is right, and the printing code can print it as + "struct {...}". */ + TYPE_TAG_NAME (type) = NULL; + INIT_CPLUS_SPECIFIC(type); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + return type; + + case T_UNION: + if (cs->c_naux != 1) + { + /* anonymous union type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_NAME (type) = NULL; + /* This used to set the tag to "". But I think setting it + to NULL is right, and the printing code can print it as + "union {...}". */ + TYPE_TAG_NAME (type) = NULL; + INIT_CPLUS_SPECIFIC(type); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + TYPE_CODE (type) = TYPE_CODE_UNION; + return type; + + case T_ENUM: + if (cs->c_naux != 1) + { + /* anonymous enum type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NAME (type) = NULL; + /* This used to set the tag to "". But I think setting it + to NULL is right, and the printing code can print it as + "enum {...}". */ + TYPE_TAG_NAME (type) = NULL; + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS(type) = 0; + } + else + { + type = coff_read_enum_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + return type; + + case T_MOE: + /* shouldn't show up here */ + break; + + case T_UCHAR: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR); + + case T_USHORT: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT); + + case T_UINT: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER); + + case T_ULONG: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG); + } + complain (&unexpected_type_complaint, cs->c_name); + return lookup_fundamental_type (current_objfile, FT_VOID); +} + +/* This page contains subroutines of read_type. */ + +/* Read the description of a structure (or union type) + and return an object describing the type. */ + +static struct type * +coff_read_struct_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + struct nextfield + { + struct nextfield *next; + struct field field; + }; + + register struct type *type; + register struct nextfield *list = 0; + struct nextfield *new; + int nfields = 0; + register int n; + char *name; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + struct internal_syment sub_sym; + union internal_auxent sub_aux; + int done = 0; + + type = coff_alloc_type (index); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC(type); + TYPE_LENGTH (type) = length; + + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = EXTERNAL_NAME (name, current_objfile->obfd); + + switch (ms->c_sclass) + { + case C_MOS: + case C_MOU: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = savestring (name, strlen (name)); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = 8 * ms->c_value; + list->field.bitsize = 0; + nfields++; + break; + + case C_FIELD: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = savestring (name, strlen (name)); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = ms->c_value; + list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size; + nfields++; + break; + + case C_EOS: + done = 1; + break; + } + } + /* Now create the vector of fields, and record how big it is. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + + /* Copy the saved-up fields into the field vector. */ + + for (n = nfields; list; list = list->next) + TYPE_FIELD (type, --n) = list->field; + + return type; +} + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +/* ARGSUSED */ +static struct type * +coff_read_enum_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + register struct symbol *sym; + register struct type *type; + int nsyms = 0; + int done = 0; + struct pending **symlist; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + struct internal_syment sub_sym; + union internal_auxent sub_aux; + struct pending *osyms, *syms; + int o_nsyms; + register int n; + char *name; + + type = coff_alloc_type (index); + if (within_function) + symlist = &local_symbols; + else + symlist = &file_symbols; + osyms = *symlist; + o_nsyms = osyms ? osyms->nsyms : 0; + + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = EXTERNAL_NAME (name, current_objfile->obfd); + + switch (ms->c_sclass) + { + case C_MOE: + sym = (struct symbol *) xmalloc (sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + + SYMBOL_NAME (sym) = savestring (name, strlen (name)); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = ms->c_value; + add_symbol_to_list (sym, symlist); + nsyms++; + break; + + case C_EOS: + /* Sometimes the linker (on 386/ix 2.0.2 at least) screws + up the count of how many symbols to read. So stop + on .eos. */ + done = 1; + break; + } + } + + /* Now fill in the fields of the type-structure. */ + + if (length > 0) + TYPE_LENGTH (type) = length; + else + TYPE_LENGTH (type) = TARGET_INT_BIT / TARGET_CHAR_BIT; /* Assume ints */ + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + /* Note that we preserve the order of the enum constants, so + that in something like "enum {FOO, LAST_THING=FOO}" we print + FOO, not LAST_THING. */ + + for (syms = *symlist, n = 0; syms; syms = syms->next) + { + int j = 0; + if (syms == osyms) + j = o_nsyms; + for (; j < syms->nsyms; j++,n++) + { + struct symbol *xsym = syms->symbol[j]; + SYMBOL_TYPE (xsym) = type; + TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym); + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym); + TYPE_FIELD_BITSIZE (type, n) = 0; + } + if (syms == osyms) + break; + } + +#if 0 + /* This screws up perfectly good C programs with enums. FIXME. */ + /* Is this Modula-2's BOOLEAN type? Flag it as such if so. */ + if(TYPE_NFIELDS(type) == 2 && + ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") && + STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) || + (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") && + STREQ(TYPE_FIELD_NAME(type,0),"FALSE")))) + TYPE_CODE(type) = TYPE_CODE_BOOL; +#endif + return type; +} + +struct section_offsets * +coff_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* Register our ability to parse symbols for coff BFD files */ + +static struct sym_fns coff_sym_fns = +{ + "coff", /* sym_name: name or name prefix of BFD target type */ + 4, /* sym_namelen: number of significant sym_name chars */ + coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + coff_symfile_read, /* sym_read: read a symbol file into symtab */ + coff_symfile_finish, /* sym_finish: finished with file, cleanup */ + coff_symfile_offsets, /* sym_offsets: xlate external to internal form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_coffread () +{ + add_symtab_fns(&coff_sym_fns); +} diff --git a/gnu/usr.bin/gdb/gdb/command.c b/gnu/usr.bin/gdb/gdb/command.c new file mode 100644 index 00000000000..abc2d84499c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/command.c @@ -0,0 +1,1310 @@ +/* Handle lists of commands, their decoding and documentation, for GDB. + Copyright 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + +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. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "value.h" +#include +#include + +/* Prototypes for local functions */ + +static void +undef_cmd_error PARAMS ((char *, char *)); + +static void +show_user PARAMS ((char *, int)); + +static void +show_user_1 PARAMS ((struct cmd_list_element *, FILE *)); + +static void +make_command PARAMS ((char *, int)); + +static void +shell_escape PARAMS ((char *, int)); + +static int +parse_binary_operation PARAMS ((char *)); + +static void +print_doc_line PARAMS ((FILE *, char *)); + +/* Add element named NAME. + CLASS is the top level category into which commands are broken down + for "help" purposes. + FUN should be the function to execute the command; + it will get a character string as argument, with leading + and trailing blanks already eliminated. + + DOC is a documentation string for the command. + Its first line should be a complete sentence. + It should start with ? for a command that is an abbreviation + or with * for a command that most users don't need to know about. + + Add this command to command list *LIST. */ + +struct cmd_list_element * +add_cmd (name, class, fun, doc, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + delete_cmd (name, list); + c->next = *list; + c->name = name; + c->class = class; + c->function.cfunc = fun; + c->doc = doc; + c->prefixlist = 0; + c->prefixname = (char *)NULL; + c->allow_unknown = 0; + c->hook = 0; + c->hookee = 0; + c->cmd_pointer = 0; + c->abbrev_flag = 0; + c->type = not_set_cmd; + c->completer = make_symbol_completion_list; + c->var = 0; + c->var_type = var_boolean; + c->user_commands = 0; + *list = c; + return c; +} + +/* Same as above, except that the abbrev_flag is set. */ + +#if 0 /* Currently unused */ + +struct cmd_list_element * +add_abbrev_cmd (name, class, fun, doc, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = add_cmd (name, class, fun, doc, list); + + c->abbrev_flag = 1; + return c; +} + +#endif + +struct cmd_list_element * +add_alias_cmd (name, oldname, class, abbrev_flag, list) + char *name; + char *oldname; + enum command_class class; + int abbrev_flag; + struct cmd_list_element **list; +{ + /* Must do this since lookup_cmd tries to side-effect its first arg */ + char *copied_name; + register struct cmd_list_element *old; + register struct cmd_list_element *c; + copied_name = (char *) alloca (strlen (oldname) + 1); + strcpy (copied_name, oldname); + old = lookup_cmd (&copied_name, *list, "", 1, 1); + + if (old == 0) + { + delete_cmd (name, list); + return 0; + } + + c = add_cmd (name, class, old->function.cfunc, old->doc, list); + c->prefixlist = old->prefixlist; + c->prefixname = old->prefixname; + c->allow_unknown = old->allow_unknown; + c->abbrev_flag = abbrev_flag; + c->cmd_pointer = old; + return c; +} + +/* Like add_cmd but adds an element for a command prefix: + a name that should be followed by a subcommand to be looked up + in another command list. PREFIXLIST should be the address + of the variable containing that list. */ + +struct cmd_list_element * +add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + return c; +} + +/* Like add_prefix_cmd but sets the abbrev_flag on the new command. */ + +struct cmd_list_element * +add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + c->abbrev_flag = 1; + return c; +} + +/* ARGSUSED */ +void +not_just_help_class_command (args, from_tty) + char *args; + int from_tty; +{ +} + +/* Add element named NAME to command list LIST (the list for set + or some sublist thereof). + CLASS is as in add_cmd. + VAR_TYPE is the kind of thing we are setting. + VAR is address of the variable being controlled by this command. + DOC is the documentation string. */ + +struct cmd_list_element * +add_set_cmd (name, class, var_type, var, doc, list) + char *name; + enum command_class class; + var_types var_type; + char *var; + char *doc; + struct cmd_list_element **list; +{ + /* For set/show, we have to call do_setshow_command + differently than an ordinary function (take commandlist as + well as arg), so the function field isn't helpful. However, + function == NULL means that it's a help class, so set the function + to not_just_help_class_command. */ + struct cmd_list_element *c + = add_cmd (name, class, not_just_help_class_command, doc, list); + + c->type = set_cmd; + c->var_type = var_type; + c->var = var; + return c; +} + +/* Where SETCMD has already been added, add the corresponding show + command to LIST and return a pointer to it. */ +struct cmd_list_element * +add_show_from_set (setcmd, list) + struct cmd_list_element *setcmd; + struct cmd_list_element **list; +{ + struct cmd_list_element *showcmd = + (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + memcpy (showcmd, setcmd, sizeof (struct cmd_list_element)); + delete_cmd (showcmd->name, list); + showcmd->type = show_cmd; + + /* Replace "set " at start of docstring with "show ". */ + if (setcmd->doc[0] == 'S' && setcmd->doc[1] == 'e' + && setcmd->doc[2] == 't' && setcmd->doc[3] == ' ') + showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL); + else + fprintf (stderr, "GDB internal error: Bad docstring for set command\n"); + + showcmd->next = *list; + *list = showcmd; + return showcmd; +} + +/* Remove the command named NAME from the command list. */ + +void +delete_cmd (name, list) + char *name; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c; + struct cmd_list_element *p; + + while (*list && STREQ ((*list)->name, name)) + { + if ((*list)->hookee) + (*list)->hookee->hook = 0; /* Hook slips out of its mouth */ + p = (*list)->next; + free ((PTR)*list); + *list = p; + } + + if (*list) + for (c = *list; c->next;) + { + if (STREQ (c->next->name, name)) + { + if (c->next->hookee) + c->next->hookee->hook = 0; /* hooked cmd gets away. */ + p = c->next->next; + free ((PTR)c->next); + c->next = p; + } + else + c = c->next; + } +} + +/* This command really has to deal with two things: + * 1) I want documentation on *this string* (usually called by + * "help commandname"). + * 2) I want documentation on *this list* (usually called by + * giving a command that requires subcommands. Also called by saying + * just "help".) + * + * I am going to split this into two seperate comamnds, help_cmd and + * help_list. + */ + +void +help_cmd (command, stream) + char *command; + FILE *stream; +{ + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; + + if (!command) + { + help_list (cmdlist, "", all_classes, stream); + return; + } + + c = lookup_cmd (&command, cmdlist, "", 0, 0); + + if (c == 0) + return; + + /* There are three cases here. + If c->prefixlist is nonzero, we have a prefix command. + Print its documentation, then list its subcommands. + + If c->function is nonzero, we really have a command. + Print its documentation and return. + + If c->function is zero, we have a class name. + Print its documentation (as if it were a command) + and then set class to the number of this class + so that the commands in the class will be listed. */ + + fputs_filtered (c->doc, stream); + fputs_filtered ("\n", stream); + + if (c->prefixlist == 0 && c->function.cfunc != NULL) + return; + fprintf_filtered (stream, "\n"); + + /* If this is a prefix command, print it's subcommands */ + if (c->prefixlist) + help_list (*c->prefixlist, c->prefixname, all_commands, stream); + + /* If this is a class name, print all of the commands in the class */ + if (c->function.cfunc == NULL) + help_list (cmdlist, "", c->class, stream); + + if (c->hook) + fprintf_filtered (stream, "\nThis command has a hook defined: %s\n", + c->hook->name); +} + +/* + * Get a specific kind of help on a command list. + * + * LIST is the list. + * CMDTYPE is the prefix to use in the title string. + * CLASS is the class with which to list the nodes of this list (see + * documentation for help_cmd_list below), As usual, ALL_COMMANDS for + * everything, ALL_CLASSES for just classes, and non-negative for only things + * in a specific class. + * and STREAM is the output stream on which to print things. + * If you call this routine with a class >= 0, it recurses. + */ +void +help_list (list, cmdtype, class, stream) + struct cmd_list_element *list; + char *cmdtype; + enum command_class class; + FILE *stream; +{ + int len; + char *cmdtype1, *cmdtype2; + + /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */ + len = strlen (cmdtype); + cmdtype1 = (char *) alloca (len + 1); + cmdtype1[0] = 0; + cmdtype2 = (char *) alloca (len + 4); + cmdtype2[0] = 0; + if (len) + { + cmdtype1[0] = ' '; + strncpy (cmdtype1 + 1, cmdtype, len - 1); + cmdtype1[len] = 0; + strncpy (cmdtype2, cmdtype, len - 1); + strcpy (cmdtype2 + len - 1, " sub"); + } + + if (class == all_classes) + fprintf_filtered (stream, "List of classes of %scommands:\n\n", cmdtype2); + else + fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2); + + help_cmd_list (list, class, cmdtype, (int)class >= 0, stream); + + if (class == all_classes) + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by a class name for a list of commands in that class.", + cmdtype1); + + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by %scommand name for full documentation.\n\ +Command name abbreviations are allowed if unambiguous.\n", + cmdtype1, cmdtype2); +} + +/* Print only the first line of STR on STREAM. */ +static void +print_doc_line (stream, str) + FILE *stream; + char *str; +{ + static char *line_buffer = 0; + static int line_size; + register char *p; + + if (!line_buffer) + { + line_size = 80; + line_buffer = (char *) xmalloc (line_size); + } + + p = str; + while (*p && *p != '\n' && *p != '.' && *p != ',') + p++; + if (p - str > line_size - 1) + { + line_size = p - str + 1; + free ((PTR)line_buffer); + line_buffer = (char *) xmalloc (line_size); + } + strncpy (line_buffer, str, p - str); + line_buffer[p - str] = '\0'; + if (islower (line_buffer[0])) + line_buffer[0] = toupper (line_buffer[0]); + fputs_filtered (line_buffer, stream); +} + +/* + * Implement a help command on command list LIST. + * RECURSE should be non-zero if this should be done recursively on + * all sublists of LIST. + * PREFIX is the prefix to print before each command name. + * STREAM is the stream upon which the output should be written. + * CLASS should be: + * A non-negative class number to list only commands in that + * class. + * ALL_COMMANDS to list all commands in list. + * ALL_CLASSES to list all classes in list. + * + * Note that RECURSE will be active on *all* sublists, not just the + * ones selected by the criteria above (ie. the selection mechanism + * is at the low level, not the high-level). + */ +void +help_cmd_list (list, class, prefix, recurse, stream) + struct cmd_list_element *list; + enum command_class class; + char *prefix; + int recurse; + FILE *stream; +{ + register struct cmd_list_element *c; + + for (c = list; c; c = c->next) + { + if (c->abbrev_flag == 0 && + (class == all_commands + || (class == all_classes && c->function.cfunc == NULL) + || (class == c->class && c->function.cfunc != NULL))) + { + fprintf_filtered (stream, "%s%s -- ", prefix, c->name); + print_doc_line (stream, c->doc); + fputs_filtered ("\n", stream); + } + if (recurse + && c->prefixlist != 0 + && c->abbrev_flag == 0) + help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream); + } +} + +/* This routine takes a line of TEXT and a CLIST in which to start the + lookup. When it returns it will have incremented the text pointer past + the section of text it matched, set *RESULT_LIST to point to the list in + which the last word was matched, and will return a pointer to the cmd + list element which the text matches. It will return NULL if no match at + all was possible. It will return -1 (cast appropriately, ick) if ambigous + matches are possible; in this case *RESULT_LIST will be set to point to + the list in which there are ambiguous choices (and *TEXT will be set to + the ambiguous text string). + + If the located command was an abbreviation, this routine returns the base + command of the abbreviation. + + It does no error reporting whatsoever; control will always return + to the superior routine. + + In the case of an ambiguous return (-1), *RESULT_LIST will be set to point + at the prefix_command (ie. the best match) *or* (special case) will be NULL + if no prefix command was ever found. For example, in the case of "info a", + "info" matches without ambiguity, but "a" could be "args" or "address", so + *RESULT_LIST is set to the cmd_list_element for "info". So in this case + RESULT_LIST should not be interpeted as a pointer to the beginning of a + list; it simply points to a specific command. In the case of an ambiguous + return *TEXT is advanced past the last non-ambiguous prefix (e.g. + "info t" can be "info types" or "info target"; upon return *TEXT has been + advanced past "info "). + + If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise + affect the operation). + + This routine does *not* modify the text pointed to by TEXT. + + If IGNORE_HELP_CLASSES is nonzero, ignore any command list elements which + are actually help classes rather than commands (i.e. the function field of + the struct cmd_list_element is NULL). */ + +struct cmd_list_element * +lookup_cmd_1 (text, clist, result_list, ignore_help_classes) + char **text; + struct cmd_list_element *clist, **result_list; + int ignore_help_classes; +{ + char *p, *command; + int len, tmp, nfound; + struct cmd_list_element *found, *c; + + while (**text == ' ' || **text == '\t') + (*text)++; + + /* Treating underscores as part of command words is important + so that "set args_foo()" doesn't get interpreted as + "set args _foo()". */ + for (p = *text; + *p && (isalnum(*p) || *p == '-' || *p == '_'); + p++) + ; + + /* If nothing but whitespace, return 0. */ + if (p == *text) + return 0; + + len = p - *text; + + /* *text and p now bracket the first command word to lookup (and + it's length is len). We copy this into a local temporary, + converting to lower case as we go. */ + + command = (char *) alloca (len + 1); + for (tmp = 0; tmp < len; tmp++) + { + char x = (*text)[tmp]; + command[tmp] = isupper(x) ? tolower(x) : x; + } + command[len] = '\0'; + + /* Look it up. */ + found = 0; + nfound = 0; + for (c = clist; c; c = c->next) + if (!strncmp (command, c->name, len) + && (!ignore_help_classes || c->function.cfunc)) + { + found = c; + nfound++; + if (c->name[len] == '\0') + { + nfound = 1; + break; + } + } + + /* If nothing matches, we have a simple failure. */ + if (nfound == 0) + return 0; + + if (nfound > 1) + { + if (result_list != NULL) + /* Will be modified in calling routine + if we know what the prefix command is. */ + *result_list = 0; + return (struct cmd_list_element *) -1; /* Ambiguous. */ + } + + /* We've matched something on this list. Move text pointer forward. */ + + *text = p; + + /* If this was an abbreviation, use the base command instead. */ + + if (found->cmd_pointer) + found = found->cmd_pointer; + + /* If we found a prefix command, keep looking. */ + + if (found->prefixlist) + { + c = lookup_cmd_1 (text, *found->prefixlist, result_list, + ignore_help_classes); + if (!c) + { + /* Didn't find anything; this is as far as we got. */ + if (result_list != NULL) + *result_list = clist; + return found; + } + else if (c == (struct cmd_list_element *) -1) + { + /* We've gotten this far properley, but the next step + is ambiguous. We need to set the result list to the best + we've found (if an inferior hasn't already set it). */ + if (result_list != NULL) + if (!*result_list) + /* This used to say *result_list = *found->prefixlist + If that was correct, need to modify the documentation + at the top of this function to clarify what is supposed + to be going on. */ + *result_list = found; + return c; + } + else + { + /* We matched! */ + return c; + } + } + else + { + if (result_list != NULL) + *result_list = clist; + return found; + } +} + +/* All this hair to move the space to the front of cmdtype */ + +static void +undef_cmd_error (cmdtype, q) + char *cmdtype, *q; +{ + error ("Undefined %scommand: \"%s\". Try \"help%s%.*s\".", + cmdtype, + q, + *cmdtype? " ": "", + strlen(cmdtype)-1, + cmdtype); +} + +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. + + If INGNORE_HELP_CLASSES is nonzero, ignore any command list + elements which are actually help classes rather than commands (i.e. + the function field of the struct cmd_list_element is 0). */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; + int ignore_help_classes; +{ + struct cmd_list_element *last_list = 0; + struct cmd_list_element *c = + lookup_cmd_1 (line, list, &last_list, ignore_help_classes); + char *ptr = (*line) + strlen (*line) - 1; + + /* Clear off trailing whitespace. */ + while (ptr >= *line && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; + + if (!c) + { + if (!allow_unknown) + { + if (!*line) + error ("Lack of needed %scommand", cmdtype); + else + { + char *p = *line, *q; + + while (isalnum(*p) || *p == '-') + p++; + + q = (char *) alloca (p - *line + 1); + strncpy (q, *line, p - *line); + q[p-*line] = '\0'; + undef_cmd_error (cmdtype, q); + } + } + else + return 0; + } + else if (c == (struct cmd_list_element *) -1) + { + /* Ambigous. Local values should be off prefixlist or called + values. */ + int local_allow_unknown = (last_list ? last_list->allow_unknown : + allow_unknown); + char *local_cmdtype = last_list ? last_list->prefixname : cmdtype; + struct cmd_list_element *local_list = + (last_list ? *(last_list->prefixlist) : list); + + if (local_allow_unknown < 0) + { + if (last_list) + return last_list; /* Found something. */ + else + return 0; /* Found nothing. */ + } + else + { + /* Report as error. */ + int amb_len; + char ambbuf[100]; + + for (amb_len = 0; + ((*line)[amb_len] && (*line)[amb_len] != ' ' + && (*line)[amb_len] != '\t'); + amb_len++) + ; + + ambbuf[0] = 0; + for (c = local_list; c; c = c->next) + if (!strncmp (*line, c->name, amb_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < (int)sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype, + *line, ambbuf); + return 0; /* lint */ + } + } + else + { + /* We've got something. It may still not be what the caller + wants (if this command *needs* a subcommand). */ + while (**line == ' ' || **line == '\t') + (*line)++; + + if (c->prefixlist && **line && !c->allow_unknown) + undef_cmd_error (c->prefixname, *line); + + /* Seems to be what he wants. Return it. */ + return c; + } + return 0; +} + +#if 0 +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; +{ + register char *p; + register struct cmd_list_element *c, *found; + int nfound; + char ambbuf[100]; + char *processed_cmd; + int i, cmd_len; + + /* Skip leading whitespace. */ + + while (**line == ' ' || **line == '\t') + (*line)++; + + /* Clear out trailing whitespace. */ + + p = *line + strlen (*line); + while (p != *line && (p[-1] == ' ' || p[-1] == '\t')) + p--; + *p = 0; + + /* Find end of command name. */ + + p = *line; + while (*p == '-' || isalnum(*p)) + p++; + + /* Look up the command name. + If exact match, keep that. + Otherwise, take command abbreviated, if unique. Note that (in my + opinion) a null string does *not* indicate ambiguity; simply the + end of the argument. */ + + if (p == *line) + { + if (!allow_unknown) + error ("Lack of needed %scommand", cmdtype); + return 0; + } + + /* Copy over to a local buffer, converting to lowercase on the way. + This is in case the command being parsed is a subcommand which + doesn't match anything, and that's ok. We want the original + untouched for the routine of the original command. */ + + processed_cmd = (char *) alloca (p - *line + 1); + for (cmd_len = 0; cmd_len < p - *line; cmd_len++) + { + char x = (*line)[cmd_len]; + if (isupper(x)) + processed_cmd[cmd_len] = tolower(x); + else + processed_cmd[cmd_len] = x; + } + processed_cmd[cmd_len] = '\0'; + + /* Check all possibilities in the current command list. */ + found = 0; + nfound = 0; + for (c = list; c; c = c->next) + { + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + found = c; + nfound++; + if (c->name[cmd_len] == 0) + { + nfound = 1; + break; + } + } + } + + /* Report error for undefined command name. */ + + if (nfound != 1) + { + if (nfound > 1 && allow_unknown >= 0) + { + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", cmdtype, + processed_cmd, ambbuf); + } + else if (!allow_unknown) + error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd); + return 0; + } + + /* Skip whitespace before the argument. */ + + while (*p == ' ' || *p == '\t') p++; + *line = p; + + if (found->prefixlist && *p) + { + c = lookup_cmd (line, *found->prefixlist, found->prefixname, + found->allow_unknown); + if (c) + return c; + } + + return found; +} +#endif + +/* Helper function for SYMBOL_COMPLETION_FUNCTION. */ + +/* Return a vector of char pointers which point to the different + possible completions in LIST of TEXT. + + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. For example, suppose TEXT is "foo" + and we want to complete to "foobar". If WORD is "oo", return + "oobar"; if WORD is "baz/foo", return "baz/foobar". */ + +char ** +complete_on_cmdlist (list, text, word) + struct cmd_list_element *list; + char *text; + char *word; +{ + struct cmd_list_element *ptr; + char **matchlist; + int sizeof_matchlist; + int matches; + int textlen = strlen (text); + + sizeof_matchlist = 10; + matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); + matches = 0; + + for (ptr = list; ptr; ptr = ptr->next) + if (!strncmp (ptr->name, text, textlen) + && !ptr->abbrev_flag + && (ptr->function.cfunc + || ptr->prefixlist)) + { + if (matches == sizeof_matchlist) + { + sizeof_matchlist *= 2; + matchlist = (char **) xrealloc ((char *)matchlist, + (sizeof_matchlist + * sizeof (char *))); + } + + matchlist[matches] = (char *) + xmalloc (strlen (word) + strlen (ptr->name) + 1); + if (word == text) + strcpy (matchlist[matches], ptr->name); + else if (word > text) + { + /* Return some portion of ptr->name. */ + strcpy (matchlist[matches], ptr->name + (word - text)); + } + else + { + /* Return some of text plus ptr->name. */ + strncpy (matchlist[matches], word, text - word); + matchlist[matches][text - word] = '\0'; + strcat (matchlist[matches], ptr->name); + } + ++matches; + } + + if (matches == 0) + { + free ((PTR)matchlist); + matchlist = 0; + } + else + { + matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1) + * sizeof (char *))); + matchlist[matches] = (char *) 0; + } + + return matchlist; +} + +static int +parse_binary_operation (arg) + char *arg; +{ + int length; + + if (!arg || !*arg) + return 1; + + length = strlen (arg); + + while (arg[length - 1] == ' ' || arg[length - 1] == '\t') + length--; + + if (!strncmp (arg, "on", length) + || !strncmp (arg, "1", length) + || !strncmp (arg, "yes", length)) + return 1; + else + if (!strncmp (arg, "off", length) + || !strncmp (arg, "0", length) + || !strncmp (arg, "no", length)) + return 0; + else + { + error ("\"on\" or \"off\" expected."); + return 0; + } +} + +/* Do a "set" or "show" command. ARG is NULL if no argument, or the text + of the argument, and FROM_TTY is nonzero if this command is being entered + directly by the user (i.e. these are just like any other + command). C is the command list element for the command. */ +void +do_setshow_command (arg, from_tty, c) + char *arg; + int from_tty; + struct cmd_list_element *c; +{ + if (c->type == set_cmd) + { + switch (c->var_type) + { + case var_string: + { + char *new; + char *p; + char *q; + int ch; + + if (arg == NULL) + arg = ""; + new = (char *) xmalloc (strlen (arg) + 2); + p = arg; q = new; + while ((ch = *p++) != '\000') + { + if (ch == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + break; + ch = parse_escape (&p); + if (ch == 0) + break; /* C loses */ + else if (ch > 0) + *q++ = ch; + } + else + *q++ = ch; + } + if (*(p - 1) != '\\') + *q++ = ' '; + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **) c->var = new; + } + break; + case var_string_noescape: + if (arg == NULL) + arg = ""; + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **) c->var = savestring (arg, strlen (arg)); + break; + case var_filename: + if (arg == NULL) + error_no_arg ("filename to set it to."); + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **)c->var = tilde_expand (arg); + break; + case var_boolean: + *(int *) c->var = parse_binary_operation (arg); + break; + case var_uinteger: + if (arg == NULL) + error_no_arg ("integer to set it to."); + *(unsigned int *) c->var = parse_and_eval_address (arg); + if (*(unsigned int *) c->var == 0) + *(unsigned int *) c->var = UINT_MAX; + break; + case var_integer: + { + unsigned int val; + if (arg == NULL) + error_no_arg ("integer to set it to."); + val = parse_and_eval_address (arg); + if (val == 0) + *(int *) c->var = INT_MAX; + else if (val >= INT_MAX) + error ("integer %u out of range", val); + else + *(int *) c->var = val; + break; + } + case var_zinteger: + if (arg == NULL) + error_no_arg ("integer to set it to."); + *(int *) c->var = parse_and_eval_address (arg); + break; + default: + error ("gdb internal error: bad var_type in do_setshow_command"); + } + } + else if (c->type == show_cmd) + { + /* Print doc minus "show" at start. */ + print_doc_line (stdout, c->doc + 5); + + fputs_filtered (" is ", stdout); + wrap_here (" "); + switch (c->var_type) + { + case var_string: + { + unsigned char *p; + fputs_filtered ("\"", stdout); + for (p = *(unsigned char **) c->var; *p != '\0'; p++) + gdb_printchar (*p, stdout, '"'); + fputs_filtered ("\"", stdout); + } + break; + case var_string_noescape: + case var_filename: + fputs_filtered ("\"", stdout); + fputs_filtered (*(char **) c->var, stdout); + fputs_filtered ("\"", stdout); + break; + case var_boolean: + fputs_filtered (*(int *) c->var ? "on" : "off", stdout); + break; + case var_uinteger: + if (*(unsigned int *) c->var == UINT_MAX) { + fputs_filtered ("unlimited", stdout); + break; + } + /* else fall through */ + case var_zinteger: + fprintf_filtered (stdout, "%u", *(unsigned int *) c->var); + break; + case var_integer: + if (*(int *) c->var == INT_MAX) + { + fputs_filtered ("unlimited", stdout); + } + else + fprintf_filtered (stdout, "%d", *(int *) c->var); + break; + + default: + error ("gdb internal error: bad var_type in do_setshow_command"); + } + fputs_filtered (".\n", stdout); + } + else + error ("gdb internal error: bad cmd_type in do_setshow_command"); + (*c->function.sfunc) (NULL, from_tty, c); +} + +/* Show all the settings in a list of show commands. */ + +void +cmd_show_list (list, from_tty, prefix) + struct cmd_list_element *list; + int from_tty; + char *prefix; +{ + for (; list != NULL; list = list->next) { + /* If we find a prefix, run its list, prefixing our output by its + prefix (with "show " skipped). */ + if (list->prefixlist && !list->abbrev_flag) + cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5); + if (list->type == show_cmd) + { + fputs_filtered (prefix, stdout); + fputs_filtered (list->name, stdout); + fputs_filtered (": ", stdout); + do_setshow_command ((char *)NULL, from_tty, list); + } + } +} + +/* ARGSUSED */ +static void +shell_escape (arg, from_tty) + char *arg; + int from_tty; +{ +#ifdef CANT_FORK + /* FIXME: what about errors (I don't know how GO32 system() handles + them)? */ + system (arg); +#else /* Can fork. */ + int rc, status, pid; + char *p, *user_shell; + + if ((user_shell = (char *) getenv ("SHELL")) == NULL) + user_shell = "/bin/sh"; + + /* Get the name of the shell for arg0 */ + if ((p = strrchr (user_shell, '/')) == NULL) + p = user_shell; + else + p++; /* Get past '/' */ + + if ((pid = fork()) == 0) + { + if (!arg) + execl (user_shell, p, 0); + else + execl (user_shell, p, "-c", arg, 0); + + fprintf (stderr, "Exec of shell failed\n"); + exit (0); + } + + if (pid != -1) + while ((rc = wait (&status)) != pid && rc != -1) + ; + else + error ("Fork failed"); +#endif /* Can fork. */ +} + +static void +make_command (arg, from_tty) + char *arg; + int from_tty; +{ + char *p; + + if (arg == 0) + p = "make"; + else + { + p = xmalloc (sizeof("make ") + strlen(arg)); + strcpy (p, "make "); + strcpy (p + sizeof("make ")-1, arg); + } + + shell_escape (p, from_tty); +} + +static void +show_user_1 (c, stream) + struct cmd_list_element *c; + FILE *stream; +{ + register struct command_line *cmdlines; + + cmdlines = c->user_commands; + if (!cmdlines) + return; + fputs_filtered ("User command ", stream); + fputs_filtered (c->name, stream); + fputs_filtered (":\n", stream); + while (cmdlines) + { + fputs_filtered (cmdlines->line, stream); + fputs_filtered ("\n", stream); + cmdlines = cmdlines->next; + } + fputs_filtered ("\n", stream); +} + +/* ARGSUSED */ +static void +show_user (args, from_tty) + char *args; + int from_tty; +{ + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; + + if (args) + { + c = lookup_cmd (&args, cmdlist, "", 0, 1); + if (c->class != class_user) + error ("Not a user command."); + show_user_1 (c, stdout); + } + else + { + for (c = cmdlist; c; c = c->next) + { + if (c->class == class_user) + show_user_1 (c, stdout); + } + } +} + +void +_initialize_command () +{ + add_com ("shell", class_support, shell_escape, + "Execute the rest of the line as a shell command. \n\ +With no arguments, run an inferior shell."); + add_com ("make", class_support, make_command, + "Run the ``make'' program using the rest of the line as arguments."); + add_cmd ("user", no_class, show_user, + "Show definitions of user defined commands.\n\ +Argument is the name of the user defined command.\n\ +With no argument, show definitions of all user defined commands.", &showlist); +} diff --git a/gnu/usr.bin/gdb/gdb/command.h b/gnu/usr.bin/gdb/gdb/command.h new file mode 100644 index 00000000000..ee587c30659 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/command.h @@ -0,0 +1,241 @@ +/* Header file for command-reading library command.c. + Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc. + +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. */ + +#if !defined (COMMAND_H) +#define COMMAND_H 1 + +/* Not a set/show command. Note that some commands which begin with + "set" or "show" might be in this category, if their syntax does + not fall into one of the following categories. */ +typedef enum cmd_types { + not_set_cmd, + set_cmd, + show_cmd +} cmd_types; + +/* Types of "set" or "show" command. */ +typedef enum var_types { + /* "on" or "off". *VAR is an integer which is nonzero for on, + zero for off. */ + var_boolean, + /* Unsigned Integer. *VAR is an unsigned int. The user can type 0 + to mean "unlimited", which is stored in *VAR as UINT_MAX. */ + var_uinteger, + + /* Like var_uinteger but signed. *VAR is an int. The user can type 0 + to mean "unlimited", which is stored in *VAR as INT_MAX. */ + var_integer, + + /* String which the user enters with escapes (e.g. the user types \n and + it is a real newline in the stored string). + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_string, + /* String which stores what the user types verbatim. + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_string_noescape, + /* String which stores a filename. + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_filename, + /* ZeroableInteger. *VAR is an int. Like Unsigned Integer except + that zero really means zero. */ + var_zinteger +} var_types; + +/* This structure records one command'd definition. */ + +struct cmd_list_element + { + /* Points to next command in this list. */ + struct cmd_list_element *next; + + /* Name of this command. */ + char *name; + + /* Command class; class values are chosen by application program. */ + enum command_class class; + + /* Function definition of this command. + Zero for command class names and for help topics that + are not really commands. */ + union { + void (*cfunc) PARAMS ((char *args, int from_tty)); + void (*sfunc) PARAMS ((char *args, int from_tty, + struct cmd_list_element *c)); + } function; +# define NO_FUNCTION ((void (*) PARAMS((char *args, int from_tty))) 0) + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, + the full documentation. First line should end with a period. + Entire string should also end with a period, not a newline. */ + char *doc; + + /* Hook for another command to be executed before this command. */ + struct cmd_list_element *hook; + + /* Nonzero identifies a prefix command. For them, the address + of the variable containing the list of subcommands. */ + struct cmd_list_element **prefixlist; + + /* For prefix commands only: + String containing prefix commands to get here: this one + plus any others needed to get to it. Should end in a space. + It is used before the word "command" in describing the + commands reached through this prefix. */ + char *prefixname; + + /* For prefix commands only: + nonzero means do not get an error if subcommand is not + recognized; call the prefix's own function in that case. */ + char allow_unknown; + + /* Nonzero says this is an abbreviation, and should not + be mentioned in lists of commands. + This allows "br" to complete to "break", which it + otherwise wouldn't. */ + char abbrev_flag; + + /* Completion routine for this command. TEXT is the text beyond + what was matched for the command itself (leading whitespace is + skipped). It stops where we are supposed to stop completing + (rl_point) and is '\0' terminated. + + Return value is a malloc'd vector of pointers to possible completions + terminated with NULL. If there are no completions, returning a pointer + to a NULL would work but returning NULL itself is also valid. + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. For example, suppose TEXT is "foo" + and we want to complete to "foobar". If WORD is "oo", return + "oobar"; if WORD is "baz/foo", return "baz/foobar". */ + char ** (*completer) PARAMS ((char *text, char *word)); + + /* Type of "set" or "show" command (or SET_NOT_SET if not "set" + or "show"). */ + cmd_types type; + + /* Pointer to variable affected by "set" and "show". Doesn't matter + if type is not_set. */ + char *var; + + /* What kind of variable is *VAR? */ + var_types var_type; + + /* Pointer to command strings of user-defined commands */ + struct command_line *user_commands; + + /* Pointer to command that is hooked by this one, + so the hook can be removed when this one is deleted. */ + struct cmd_list_element *hookee; + + /* Pointer to command that is aliased by this one, so the + aliased command can be located in case it has been hooked. */ + struct cmd_list_element *cmd_pointer; + }; + +/* Forward-declarations of the entry-points of command.c. */ + +extern struct cmd_list_element * +add_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int), + char *, struct cmd_list_element **)); + +extern struct cmd_list_element * +add_alias_cmd PARAMS ((char *, char *, enum command_class, int, + struct cmd_list_element **)); + +extern struct cmd_list_element * +add_prefix_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int), + char *, struct cmd_list_element **, char *, int, + struct cmd_list_element **)); + +extern struct cmd_list_element * +add_abbrev_prefix_cmd PARAMS ((char *, enum command_class, + void (*fun) (char *, int), char *, + struct cmd_list_element **, char *, int, + struct cmd_list_element **)); + +extern struct cmd_list_element * +lookup_cmd PARAMS ((char **, struct cmd_list_element *, char *, int, int)); + +extern struct cmd_list_element * +lookup_cmd_1 PARAMS ((char **, struct cmd_list_element *, + struct cmd_list_element **, int)); + +extern void +add_com PARAMS ((char *, enum command_class, void (*fun)(char *, int), + char *)); + +extern void +add_com_alias PARAMS ((char *, char *, enum command_class, int)); + +extern void +add_info PARAMS ((char *, void (*fun) (char *, int), char *)); + +extern void +add_info_alias PARAMS ((char *, char *, int)); + +extern char **complete_on_cmdlist PARAMS ((struct cmd_list_element *, + char *, char *)); + +extern void +delete_cmd PARAMS ((char *, struct cmd_list_element **)); + +extern void +help_cmd PARAMS ((char *, FILE *)); + +extern void +help_list PARAMS ((struct cmd_list_element *, char *, enum command_class, + FILE *)); + +extern void +help_cmd_list PARAMS ((struct cmd_list_element *, enum command_class, char *, + int, FILE *)); + +extern struct cmd_list_element * +add_set_cmd PARAMS ((char *, enum command_class, var_types, char *, char *, + struct cmd_list_element **)); + +extern struct cmd_list_element * +add_show_from_set PARAMS ((struct cmd_list_element *, + struct cmd_list_element **)); + +/* Do a "set" or "show" command. ARG is NULL if no argument, or the text + of the argument, and FROM_TTY is nonzero if this command is being entered + directly by the user (i.e. these are just like any other + command). C is the command list element for the command. */ + +extern void +do_setshow_command PARAMS ((char *, int, struct cmd_list_element *)); + +/* Do a "show" command for each thing on a command list. */ + +extern void +cmd_show_list PARAMS ((struct cmd_list_element *, int, char *)); + +extern void +error_no_arg PARAMS ((char *)); + +extern void +dont_repeat PARAMS ((void)); + +/* Used to mark commands that don't do anything. If we just leave the + function field NULL, the command is interpreted as a help topic, or + as a class of commands. */ + +extern void +not_just_help_class_command PARAMS ((char *, int)); + +#endif /* !defined (COMMAND_H) */ diff --git a/gnu/usr.bin/gdb/gdb/complaints.c b/gnu/usr.bin/gdb/gdb/complaints.c new file mode 100644 index 00000000000..079ca5adc64 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/complaints.c @@ -0,0 +1,158 @@ +/* Support for complaint handling during symbol reading in GDB. + Copyright (C) 1990, 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. */ + +#include "defs.h" +#include "complaints.h" +#include "gdbcmd.h" +#include + +/* Structure to manage complaints about symbol file contents. */ + +struct complaint complaint_root[1] = { + { + (char *) NULL, /* Complaint message */ + 0, /* Complaint counter */ + complaint_root /* Next complaint. */ + } +}; + +/* How many complaints about a particular thing should be printed before + we stop whining about it? Default is no whining at all, since so many + systems have ill-constructed symbol files. */ + +static unsigned int stop_whining = 0; + +/* Should each complaint be self explanatory, or should we assume that + a series of complaints is being produced? + case 0: self explanatory message. + case 1: First message of a series that must start off with explanation. + case 2: Subsequent message, when user already knows we are reading + symbols and we can just state our piece. */ + +static int complaint_series = 0; + +/* External variables and functions referenced. */ + +extern int info_verbose; + + +/* Functions to handle complaints during symbol reading. */ + +/* Print a complaint about the input symbols, and link the complaint block + into a chain for later handling. */ + +/* VARARGS */ +void +complain (va_alist) + va_dcl +{ + va_list args; + struct complaint *complaint; + + va_start (args); + complaint = va_arg (args, struct complaint *); + complaint -> counter++; + if (complaint -> next == NULL) + { + complaint -> next = complaint_root -> next; + complaint_root -> next = complaint; + } + if (complaint -> counter > stop_whining) + { + return; + } + wrap_here (""); + + switch (complaint_series + (info_verbose << 1)) + { + + /* Isolated messages, must be self-explanatory. */ + case 0: + begin_line (); + puts_filtered ("During symbol reading, "); + wrap_here (""); + vprintf_filtered (complaint -> message, args); + puts_filtered (".\n"); + break; + + /* First of a series, without `set verbose'. */ + case 1: + begin_line (); + puts_filtered ("During symbol reading..."); + vprintf_filtered (complaint -> message, args); + puts_filtered ("..."); + wrap_here (""); + complaint_series++; + break; + + /* Subsequent messages of a series, or messages under `set verbose'. + (We'll already have produced a "Reading in symbols for XXX..." + message and will clean up at the end with a newline.) */ + default: + vprintf_filtered (complaint -> message, args); + puts_filtered ("..."); + wrap_here (""); + } + /* If GDB dumps core, we'd like to see the complaints first. Presumably + GDB will not be sending so many complaints that this becomes a + performance hog. */ + fflush (stdout); + va_end (args); +} + +/* Clear out all complaint counters that have ever been incremented. + If sym_reading is 1, be less verbose about successive complaints, + since the messages are appearing all together during a command that + reads symbols (rather than scattered around as psymtabs get fleshed + out into symtabs at random times). If noisy is 1, we are in a + noisy symbol reading command, and our caller will print enough + context for the user to figure it out. */ + +void +clear_complaints (sym_reading, noisy) + int sym_reading; + int noisy; +{ + struct complaint *p; + + for (p = complaint_root -> next; p != complaint_root; p = p -> next) + { + p -> counter = 0; + } + + if (!sym_reading && !noisy && complaint_series > 1) + { + /* Terminate previous series, since caller won't. */ + puts_filtered ("\n"); + } + + complaint_series = sym_reading ? 1 + noisy : 0; +} + +void +_initialize_complaints () +{ + add_show_from_set + (add_set_cmd ("complaints", class_support, var_zinteger, + (char *) &stop_whining, + "Set max number of complaints about incorrect symbols.", + &setlist), + &showlist); + +} diff --git a/gnu/usr.bin/gdb/gdb/complaints.h b/gnu/usr.bin/gdb/gdb/complaints.h new file mode 100644 index 00000000000..f7ff5a56814 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/complaints.h @@ -0,0 +1,46 @@ +/* Definitions for complaint handling during symbol reading in GDB. + Copyright (C) 1990, 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. */ + + +/* Support for complaining about things in the symbol file that aren't + catastrophic. + + Each such thing gets a counter. The first time we have the problem, + during a symbol read, we report it. At the end of symbol reading, + if verbose, we report how many of each problem we had. */ + +struct complaint +{ + char *message; + unsigned counter; + struct complaint *next; +}; + +/* Root of the chain of complaints that have at some point been issued. + This is used to reset the counters, and/or report the total counts. */ + +extern struct complaint complaint_root[1]; + +/* Functions that handle complaints. (in complaints.c) */ + +extern void +complain (); + +extern void +clear_complaints PARAMS ((int, int)); diff --git a/gnu/usr.bin/gdb/gdb/copying.c b/gnu/usr.bin/gdb/gdb/copying.c new file mode 100644 index 00000000000..ffc884a6714 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/copying.c @@ -0,0 +1,327 @@ +/* ==> Do not modify this file!! It is created automatically + by copying.awk. Modify copying.awk instead. <== */ + +#include "defs.h" +#include "command.h" +#include "gdbcmd.h" + +static void +show_copying_command PARAMS ((char *, int)); + +static void +show_warranty_command PARAMS ((char *, int)); + +extern int immediate_quit; +static void +show_copying_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + immediate_quit++; + printf_filtered (" GNU GENERAL PUBLIC LICENSE\n"); + printf_filtered (" Version 2, June 1991\n"); + printf_filtered ("\n"); + printf_filtered (" Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n"); + printf_filtered (" 675 Mass Ave, Cambridge, MA 02139, USA\n"); + printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n"); + printf_filtered (" of this license document, but changing it is not allowed.\n"); + printf_filtered ("\n"); + printf_filtered (" Preamble\n"); + printf_filtered ("\n"); + printf_filtered (" The licenses for most software are designed to take away your\n"); + printf_filtered ("freedom to share and change it. By contrast, the GNU General Public\n"); + printf_filtered ("License is intended to guarantee your freedom to share and change free\n"); + printf_filtered ("software--to make sure the software is free for all its users. This\n"); + printf_filtered ("General Public License applies to most of the Free Software\n"); + printf_filtered ("Foundation's software and to any other program whose authors commit to\n"); + printf_filtered ("using it. (Some other Free Software Foundation software is covered by\n"); + printf_filtered ("the GNU Library General Public License instead.) You can apply it to\n"); + printf_filtered ("your programs, too.\n"); + printf_filtered ("\n"); + printf_filtered (" When we speak of free software, we are referring to freedom, not\n"); + printf_filtered ("price. Our General Public Licenses are designed to make sure that you\n"); + printf_filtered ("have the freedom to distribute copies of free software (and charge for\n"); + printf_filtered ("this service if you wish), that you receive source code or can get it\n"); + printf_filtered ("if you want it, that you can change the software or use pieces of it\n"); + printf_filtered ("in new free programs; and that you know you can do these things.\n"); + printf_filtered ("\n"); + printf_filtered (" To protect your rights, we need to make restrictions that forbid\n"); + printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n"); + printf_filtered ("These restrictions translate to certain responsibilities for you if you\n"); + printf_filtered ("distribute copies of the software, or if you modify it.\n"); + printf_filtered ("\n"); + printf_filtered (" For example, if you distribute copies of such a program, whether\n"); + printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n"); + printf_filtered ("you have. You must make sure that they, too, receive or can get the\n"); + printf_filtered ("source code. And you must show them these terms so they know their\n"); + printf_filtered ("rights.\n"); + printf_filtered ("\n"); + printf_filtered (" We protect your rights with two steps: (1) copyright the software, and\n"); + printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n"); + printf_filtered ("distribute and/or modify the software.\n"); + printf_filtered ("\n"); + printf_filtered (" Also, for each author's protection and ours, we want to make certain\n"); + printf_filtered ("that everyone understands that there is no warranty for this free\n"); + printf_filtered ("software. If the software is modified by someone else and passed on, we\n"); + printf_filtered ("want its recipients to know that what they have is not the original, so\n"); + printf_filtered ("that any problems introduced by others will not reflect on the original\n"); + printf_filtered ("authors' reputations.\n"); + printf_filtered ("\n"); + printf_filtered (" Finally, any free program is threatened constantly by software\n"); + printf_filtered ("patents. We wish to avoid the danger that redistributors of a free\n"); + printf_filtered ("program will individually obtain patent licenses, in effect making the\n"); + printf_filtered ("program proprietary. To prevent this, we have made it clear that any\n"); + printf_filtered ("patent must be licensed for everyone's free use or not licensed at all.\n"); + printf_filtered ("\n"); + printf_filtered (" The precise terms and conditions for copying, distribution and\n"); + printf_filtered ("modification follow.\n"); + printf_filtered ("\n"); + printf_filtered (" GNU GENERAL PUBLIC LICENSE\n"); + printf_filtered (" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n"); + printf_filtered ("\n"); + printf_filtered (" 0. This License applies to any program or other work which contains\n"); + printf_filtered ("a notice placed by the copyright holder saying it may be distributed\n"); + printf_filtered ("under the terms of this General Public License. The \"Program\", below,\n"); + printf_filtered ("refers to any such program or work, and a \"work based on the Program\"\n"); + printf_filtered ("means either the Program or any derivative work under copyright law:\n"); + printf_filtered ("that is to say, a work containing the Program or a portion of it,\n"); + printf_filtered ("either verbatim or with modifications and/or translated into another\n"); + printf_filtered ("language. (Hereinafter, translation is included without limitation in\n"); + printf_filtered ("the term \"modification\".) Each licensee is addressed as \"you\".\n"); + printf_filtered ("\n"); + printf_filtered ("Activities other than copying, distribution and modification are not\n"); + printf_filtered ("covered by this License; they are outside its scope. The act of\n"); + printf_filtered ("running the Program is not restricted, and the output from the Program\n"); + printf_filtered ("is covered only if its contents constitute a work based on the\n"); + printf_filtered ("Program (independent of having been made by running the Program).\n"); + printf_filtered ("Whether that is true depends on what the Program does.\n"); + printf_filtered ("\n"); + printf_filtered (" 1. You may copy and distribute verbatim copies of the Program's\n"); + printf_filtered ("source code as you receive it, in any medium, provided that you\n"); + printf_filtered ("conspicuously and appropriately publish on each copy an appropriate\n"); + printf_filtered ("copyright notice and disclaimer of warranty; keep intact all the\n"); + printf_filtered ("notices that refer to this License and to the absence of any warranty;\n"); + printf_filtered ("and give any other recipients of the Program a copy of this License\n"); + printf_filtered ("along with the Program.\n"); + printf_filtered ("\n"); + printf_filtered ("You may charge a fee for the physical act of transferring a copy, and\n"); + printf_filtered ("you may at your option offer warranty protection in exchange for a fee.\n"); + printf_filtered ("\n"); + printf_filtered (" 2. You may modify your copy or copies of the Program or any portion\n"); + printf_filtered ("of it, thus forming a work based on the Program, and copy and\n"); + printf_filtered ("distribute such modifications or work under the terms of Section 1\n"); + printf_filtered ("above, provided that you also meet all of these conditions:\n"); + printf_filtered ("\n"); + printf_filtered (" a) You must cause the modified files to carry prominent notices\n"); + printf_filtered (" stating that you changed the files and the date of any change.\n"); + printf_filtered ("\n"); + printf_filtered (" b) You must cause any work that you distribute or publish, that in\n"); + printf_filtered (" whole or in part contains or is derived from the Program or any\n"); + printf_filtered (" part thereof, to be licensed as a whole at no charge to all third\n"); + printf_filtered (" parties under the terms of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" c) If the modified program normally reads commands interactively\n"); + printf_filtered (" when run, you must cause it, when started running for such\n"); + printf_filtered (" interactive use in the most ordinary way, to print or display an\n"); + printf_filtered (" announcement including an appropriate copyright notice and a\n"); + printf_filtered (" notice that there is no warranty (or else, saying that you provide\n"); + printf_filtered (" a warranty) and that users may redistribute the program under\n"); + printf_filtered (" these conditions, and telling the user how to view a copy of this\n"); + printf_filtered (" License. (Exception: if the Program itself is interactive but\n"); + printf_filtered (" does not normally print such an announcement, your work based on\n"); + printf_filtered (" the Program is not required to print an announcement.)\n"); + printf_filtered ("\n"); + printf_filtered ("These requirements apply to the modified work as a whole. If\n"); + printf_filtered ("identifiable sections of that work are not derived from the Program,\n"); + printf_filtered ("and can be reasonably considered independent and separate works in\n"); + printf_filtered ("themselves, then this License, and its terms, do not apply to those\n"); + printf_filtered ("sections when you distribute them as separate works. But when you\n"); + printf_filtered ("distribute the same sections as part of a whole which is a work based\n"); + printf_filtered ("on the Program, the distribution of the whole must be on the terms of\n"); + printf_filtered ("this License, whose permissions for other licensees extend to the\n"); + printf_filtered ("entire whole, and thus to each and every part regardless of who wrote it.\n"); + printf_filtered ("\n"); + printf_filtered ("Thus, it is not the intent of this section to claim rights or contest\n"); + printf_filtered ("your rights to work written entirely by you; rather, the intent is to\n"); + printf_filtered ("exercise the right to control the distribution of derivative or\n"); + printf_filtered ("collective works based on the Program.\n"); + printf_filtered ("\n"); + printf_filtered ("In addition, mere aggregation of another work not based on the Program\n"); + printf_filtered ("with the Program (or with a work based on the Program) on a volume of\n"); + printf_filtered ("a storage or distribution medium does not bring the other work under\n"); + printf_filtered ("the scope of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 3. You may copy and distribute the Program (or a work based on it,\n"); + printf_filtered ("under Section 2) in object code or executable form under the terms of\n"); + printf_filtered ("Sections 1 and 2 above provided that you also do one of the following:\n"); + printf_filtered ("\n"); + printf_filtered (" a) Accompany it with the complete corresponding machine-readable\n"); + printf_filtered (" source code, which must be distributed under the terms of Sections\n"); + printf_filtered (" 1 and 2 above on a medium customarily used for software interchange; or,\n"); + printf_filtered ("\n"); + printf_filtered (" b) Accompany it with a written offer, valid for at least three\n"); + printf_filtered (" years, to give any third party, for a charge no more than your\n"); + printf_filtered (" cost of physically performing source distribution, a complete\n"); + printf_filtered (" machine-readable copy of the corresponding source code, to be\n"); + printf_filtered (" distributed under the terms of Sections 1 and 2 above on a medium\n"); + printf_filtered (" customarily used for software interchange; or,\n"); + printf_filtered ("\n"); + printf_filtered (" c) Accompany it with the information you received as to the offer\n"); + printf_filtered (" to distribute corresponding source code. (This alternative is\n"); + printf_filtered (" allowed only for noncommercial distribution and only if you\n"); + printf_filtered (" received the program in object code or executable form with such\n"); + printf_filtered (" an offer, in accord with Subsection b above.)\n"); + printf_filtered ("\n"); + printf_filtered ("The source code for a work means the preferred form of the work for\n"); + printf_filtered ("making modifications to it. For an executable work, complete source\n"); + printf_filtered ("code means all the source code for all modules it contains, plus any\n"); + printf_filtered ("associated interface definition files, plus the scripts used to\n"); + printf_filtered ("control compilation and installation of the executable. However, as a\n"); + printf_filtered ("special exception, the source code distributed need not include\n"); + printf_filtered ("anything that is normally distributed (in either source or binary\n"); + printf_filtered ("form) with the major components (compiler, kernel, and so on) of the\n"); + printf_filtered ("operating system on which the executable runs, unless that component\n"); + printf_filtered ("itself accompanies the executable.\n"); + printf_filtered ("\n"); + printf_filtered ("If distribution of executable or object code is made by offering\n"); + printf_filtered ("access to copy from a designated place, then offering equivalent\n"); + printf_filtered ("access to copy the source code from the same place counts as\n"); + printf_filtered ("distribution of the source code, even though third parties are not\n"); + printf_filtered ("compelled to copy the source along with the object code.\n"); + printf_filtered ("\n"); + printf_filtered (" 4. You may not copy, modify, sublicense, or distribute the Program\n"); + printf_filtered ("except as expressly provided under this License. Any attempt\n"); + printf_filtered ("otherwise to copy, modify, sublicense or distribute the Program is\n"); + printf_filtered ("void, and will automatically terminate your rights under this License.\n"); + printf_filtered ("However, parties who have received copies, or rights, from you under\n"); + printf_filtered ("this License will not have their licenses terminated so long as such\n"); + printf_filtered ("parties remain in full compliance.\n"); + printf_filtered ("\n"); + printf_filtered (" 5. You are not required to accept this License, since you have not\n"); + printf_filtered ("signed it. However, nothing else grants you permission to modify or\n"); + printf_filtered ("distribute the Program or its derivative works. These actions are\n"); + printf_filtered ("prohibited by law if you do not accept this License. Therefore, by\n"); + printf_filtered ("modifying or distributing the Program (or any work based on the\n"); + printf_filtered ("Program), you indicate your acceptance of this License to do so, and\n"); + printf_filtered ("all its terms and conditions for copying, distributing or modifying\n"); + printf_filtered ("the Program or works based on it.\n"); + printf_filtered ("\n"); + printf_filtered (" 6. Each time you redistribute the Program (or any work based on the\n"); + printf_filtered ("Program), the recipient automatically receives a license from the\n"); + printf_filtered ("original licensor to copy, distribute or modify the Program subject to\n"); + printf_filtered ("these terms and conditions. You may not impose any further\n"); + printf_filtered ("restrictions on the recipients' exercise of the rights granted herein.\n"); + printf_filtered ("You are not responsible for enforcing compliance by third parties to\n"); + printf_filtered ("this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 7. If, as a consequence of a court judgment or allegation of patent\n"); + printf_filtered ("infringement or for any other reason (not limited to patent issues),\n"); + printf_filtered ("conditions are imposed on you (whether by court order, agreement or\n"); + printf_filtered ("otherwise) that contradict the conditions of this License, they do not\n"); + printf_filtered ("excuse you from the conditions of this License. If you cannot\n"); + printf_filtered ("distribute so as to satisfy simultaneously your obligations under this\n"); + printf_filtered ("License and any other pertinent obligations, then as a consequence you\n"); + printf_filtered ("may not distribute the Program at all. For example, if a patent\n"); + printf_filtered ("license would not permit royalty-free redistribution of the Program by\n"); + printf_filtered ("all those who receive copies directly or indirectly through you, then\n"); + printf_filtered ("the only way you could satisfy both it and this License would be to\n"); + printf_filtered ("refrain entirely from distribution of the Program.\n"); + printf_filtered ("\n"); + printf_filtered ("If any portion of this section is held invalid or unenforceable under\n"); + printf_filtered ("any particular circumstance, the balance of the section is intended to\n"); + printf_filtered ("apply and the section as a whole is intended to apply in other\n"); + printf_filtered ("circumstances.\n"); + printf_filtered ("\n"); + printf_filtered ("It is not the purpose of this section to induce you to infringe any\n"); + printf_filtered ("patents or other property right claims or to contest validity of any\n"); + printf_filtered ("such claims; this section has the sole purpose of protecting the\n"); + printf_filtered ("integrity of the free software distribution system, which is\n"); + printf_filtered ("implemented by public license practices. Many people have made\n"); + printf_filtered ("generous contributions to the wide range of software distributed\n"); + printf_filtered ("through that system in reliance on consistent application of that\n"); + printf_filtered ("system; it is up to the author/donor to decide if he or she is willing\n"); + printf_filtered ("to distribute software through any other system and a licensee cannot\n"); + printf_filtered ("impose that choice.\n"); + printf_filtered ("\n"); + printf_filtered ("This section is intended to make thoroughly clear what is believed to\n"); + printf_filtered ("be a consequence of the rest of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 8. If the distribution and/or use of the Program is restricted in\n"); + printf_filtered ("certain countries either by patents or by copyrighted interfaces, the\n"); + printf_filtered ("original copyright holder who places the Program under this License\n"); + printf_filtered ("may add an explicit geographical distribution limitation excluding\n"); + printf_filtered ("those countries, so that distribution is permitted only in or among\n"); + printf_filtered ("countries not thus excluded. In such case, this License incorporates\n"); + printf_filtered ("the limitation as if written in the body of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 9. The Free Software Foundation may publish revised and/or new versions\n"); + printf_filtered ("of the General Public License from time to time. Such new versions will\n"); + printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n"); + printf_filtered ("address new problems or concerns.\n"); + printf_filtered ("\n"); + printf_filtered ("Each version is given a distinguishing version number. If the Program\n"); + printf_filtered ("specifies a version number of this License which applies to it and \"any\n"); + printf_filtered ("later version\", you have the option of following the terms and conditions\n"); + printf_filtered ("either of that version or of any later version published by the Free\n"); + printf_filtered ("Software Foundation. If the Program does not specify a version number of\n"); + printf_filtered ("this License, you may choose any version ever published by the Free Software\n"); + printf_filtered ("Foundation.\n"); + printf_filtered ("\n"); + printf_filtered (" 10. If you wish to incorporate parts of the Program into other free\n"); + printf_filtered ("programs whose distribution conditions are different, write to the author\n"); + printf_filtered ("to ask for permission. For software which is copyrighted by the Free\n"); + printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n"); + printf_filtered ("make exceptions for this. Our decision will be guided by the two goals\n"); + printf_filtered ("of preserving the free status of all derivatives of our free software and\n"); + printf_filtered ("of promoting the sharing and reuse of software generally.\n"); + printf_filtered ("\n"); + immediate_quit--; +} + +static void +show_warranty_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + immediate_quit++; + printf_filtered (" NO WARRANTY\n"); + printf_filtered ("\n"); + printf_filtered (" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"); + printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"); + printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"); + printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"); + printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"); + printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"); + printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"); + printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"); + printf_filtered ("REPAIR OR CORRECTION.\n"); + printf_filtered ("\n"); + printf_filtered (" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"); + printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"); + printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"); + printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"); + printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"); + printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"); + printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"); + printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"); + printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n"); + printf_filtered ("\n"); + immediate_quit--; +} + +void +_initialize_copying () +{ + add_cmd ("copying", no_class, show_copying_command, + "Conditions for redistributing copies of GDB.", + &showlist); + add_cmd ("warranty", no_class, show_warranty_command, + "Various kinds of warranty you do not have.", + &showlist); + + /* For old-timers, allow "info copying", etc. */ + add_info ("copying", show_copying_command, + "Conditions for redistributing copies of GDB."); + add_info ("warranty", show_warranty_command, + "Various kinds of warranty you do not have."); +} diff --git a/gnu/usr.bin/gdb/gdb/core.c b/gnu/usr.bin/gdb/gdb/core.c new file mode 100644 index 00000000000..36c9ab5e75a --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/core.c @@ -0,0 +1,291 @@ +/* Core dump and executable file functions above target vector, for GDB. + Copyright 1986, 1987, 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. */ + +#include "defs.h" +#include +#include +#include +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "gdbcmd.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" +#include "dis-asm.h" + +extern char registers[]; + +/* Hook for `exec_file_command' command to call. */ + +void (*exec_file_display_hook) PARAMS ((char *)) = NULL; + +/* Binary file diddling handle for the core file. */ + +bfd *core_bfd = NULL; + + +/* Backward compatability with old way of specifying core files. */ + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + struct target_ops *t; + + dont_repeat (); /* Either way, seems bogus. */ + + t = find_core_target (); + if (t != NULL) + if (!filename) + (t->to_detach) (filename, from_tty); + else + (t->to_open) (filename, from_tty); + else + error ("GDB can't read core files on this machine."); +} + + +/* Call this to specify the hook for exec_file_command to call back. + This is called from the x-window display code. */ + +void +specify_exec_file_hook (hook) + void (*hook) PARAMS ((char *)); +{ + exec_file_display_hook = hook; +} + +/* The exec file must be closed before running an inferior. + If it is needed again after the inferior dies, it must + be reopened. */ + +void +close_exec_file () +{ +#ifdef FIXME + if (exec_bfd) + bfd_tempclose (exec_bfd); +#endif +} + +void +reopen_exec_file () +{ +#ifdef FIXME + if (exec_bfd) + bfd_reopen (exec_bfd); +#endif +} + +/* If we have both a core file and an exec file, + print a warning if they don't go together. */ + +void +validate_files () +{ + if (exec_bfd && core_bfd) + { + if (!core_file_matches_executable_p (core_bfd, exec_bfd)) + warning ("core file may not match specified executable file."); + else if (bfd_get_mtime(exec_bfd) > bfd_get_mtime(core_bfd)) + warning ("exec file is newer than core file."); + } +} + +/* Return the name of the executable file as a string. + ERR nonzero means get error if there is none specified; + otherwise return 0 in that case. */ + +char * +get_exec_file (err) + int err; +{ + if (exec_bfd) return bfd_get_filename(exec_bfd); + if (!err) return NULL; + + error ("No executable file specified.\n\ +Use the \"file\" or \"exec-file\" command."); + return NULL; +} + + +/* Report a memory error with error(). */ + +void +memory_error (status, memaddr) + int status; + CORE_ADDR memaddr; +{ + + if (status == EIO) + { + /* Actually, address between memaddr and memaddr + len + was out of bounds. */ + error ("Cannot access memory at address %s.", + local_hex_string((unsigned long) memaddr)); + } + else + { + error ("Error accessing memory address %s: %s.", + local_hex_string ((unsigned long) memaddr), + safe_strerror (status)); + } +} + +/* Same as target_read_memory, but report an error if can't read. */ +void +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + status = target_read_memory (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + +/* Like target_read_memory, but slightly different parameters. */ + +int +dis_asm_read_memory (memaddr, myaddr, len, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int len; + disassemble_info *info; +{ + return target_read_memory (memaddr, (char *) myaddr, len); +} + +/* Like memory_error with slightly different parameters. */ +void +dis_asm_memory_error (status, memaddr, info) + int status; + bfd_vma memaddr; + disassemble_info *info; +{ + memory_error (status, memaddr); +} + +/* Like print_address with slightly different parameters. */ +void +dis_asm_print_address (addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + print_address (addr, info->stream); +} + +/* Same as target_write_memory, but report an error if can't write. */ +void +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + + status = target_write_memory (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + +/* Read an integer from debugged memory, given address and number of bytes. */ + +LONGEST +read_memory_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char buf[sizeof (LONGEST)]; + + read_memory (memaddr, buf, len); + return extract_signed_integer (buf, len); +} + +unsigned LONGEST +read_memory_unsigned_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char buf[sizeof (unsigned LONGEST)]; + + read_memory (memaddr, buf, len); + return extract_unsigned_integer (buf, len); +} + +/* The current default bfd target. Points to storage allocated for + gnutarget_string. */ +char *gnutarget; + +/* Same thing, except it is "auto" not NULL for the default case. */ +static char *gnutarget_string; + +static void set_gnutarget_command + PARAMS ((char *, int, struct cmd_list_element *)); + +static void +set_gnutarget_command (ignore, from_tty, c) + char *ignore; + int from_tty; + struct cmd_list_element *c; +{ + if (STREQ (gnutarget_string, "auto")) + gnutarget = NULL; + else + gnutarget = gnutarget_string; +} + +/* Set the gnutarget. */ +void +set_gnutarget (newtarget) + char *newtarget; +{ + if (gnutarget_string != NULL) + free (gnutarget_string); + gnutarget_string = savestring (newtarget, strlen (newtarget)); + set_gnutarget_command (NULL, 0, NULL); +} + +void +_initialize_core() +{ + struct cmd_list_element *c; + c = add_cmd ("core-file", class_files, core_file_command, + "Use FILE as core dump for examining memory and registers.\n\ +No arg means have no core file. This command has been superseded by the\n\ +`target core' and `detach' commands.", &cmdlist); + c->completer = filename_completer; + + c = add_set_cmd ("gnutarget", class_files, var_string_noescape, + (char *) &gnutarget_string, + "Set the current BFD target.\n\ +Use `set gnutarget auto' to specify automatic detection.", + &setlist); + c->function.sfunc = set_gnutarget_command; + add_show_from_set (c, &showlist); + + if (getenv ("GNUTARGET")) + set_gnutarget (getenv ("GNUTARGET")); + else + set_gnutarget ("auto"); +} diff --git a/gnu/usr.bin/gdb/gdb/coredep.c b/gnu/usr.bin/gdb/gdb/coredep.c new file mode 100644 index 00000000000..d94fd9820c9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coredep.c @@ -0,0 +1,118 @@ +/* Extract registers from a "standard" core file, for GDB. + Copyright (C) 1988-1991 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. */ + +/* core.c is supposed to be the more machine-independent aspects of this; + this file is more machine-specific. */ + +#include "defs.h" +#include +#include +#include "gdbcore.h" + +/* These are needed on various systems to expand REGISTER_U_ADDR. */ +#ifndef USG +#include +#include +#include +#include +#ifndef NO_PTRACE_H +# ifdef PTRACE_IN_WRONG_PLACE +# include +# else /* !PTRACE_IN_WRONG_PLACE */ +# include +# endif /* !PTRACE_IN_WRONG_PLACE */ +#endif /* NO_PTRACE_H */ +#endif + +#ifdef NEED_SYS_CORE_H +#include +#endif + +/* Extract the register values out of the core file and store + them where `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into memory. + CORE_REG_SIZE is the size of that area. + WHICH says which set of registers we are handling (0 = int, 2 = float + on machines where they are discontiguous). + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to + locate the registers in a large upage-plus-stack ".reg" section. + Original upage address X is at location core_reg_sect+x+reg_addr. + */ + +void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned reg_addr; +{ + register int regno; + register unsigned int addr; + int bad_reg = -1; + register reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ + + /* If u.u_ar0 was an absolute address in the core file, relativize it now, + so we can use it as an offset into core_reg_sect. When we're done, + "register 0" will be at core_reg_sect+reg_ptr, and we can use + register_addr to offset to the other registers. If this is a modern + core file without a upage, reg_ptr will be zero and this is all a big + NOP. */ + if (reg_ptr > core_reg_size) + reg_ptr -= KERNEL_U_ADDR; + + for (regno = 0; regno < NUM_REGS; regno++) + { + addr = register_addr (regno, reg_ptr); + if (addr >= core_reg_size) { + if (bad_reg < 0) + bad_reg = regno; + } else { + supply_register (regno, core_reg_sect + addr); + } + } + if (bad_reg >= 0) + { + error ("Register %s not found in core file.", reg_names[bad_reg]); + } +} + + +#ifdef REGISTER_U_ADDR + +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= NUM_REGS) + error ("Invalid register number %d.", regno); + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +#endif /* REGISTER_U_ADDR */ diff --git a/gnu/usr.bin/gdb/gdb/corelow.c b/gnu/usr.bin/gdb/gdb/corelow.c new file mode 100644 index 00000000000..1cebc48985e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/corelow.c @@ -0,0 +1,328 @@ +/* Core dump and executable file functions below target vector, for GDB. + Copyright 1986, 1987, 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. */ + +#include "defs.h" +#include +#include +#include +#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" + +static void +core_files_info PARAMS ((struct target_ops *)); + +#ifdef SOLIB_ADD +static int +solib_add_stub PARAMS ((char *)); +#endif + +static void +core_close PARAMS ((int)); + +static void +get_core_registers PARAMS ((int)); + +/* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + +/* ARGSUSED */ +static void +core_close (quitting) + int quitting; +{ + inferior_pid = 0; /* Avoid confusion from thread stuff */ + + if (core_bfd) { + free (bfd_get_filename (core_bfd)); + bfd_close (core_bfd); + core_bfd = NULL; +#ifdef CLEAR_SOLIB + CLEAR_SOLIB (); +#endif + if (core_ops.to_sections) { + free ((PTR)core_ops.to_sections); + core_ops.to_sections = NULL; + core_ops.to_sections_end = NULL; + } + } +} + +#ifdef SOLIB_ADD +/* Stub function for catch_errors around shared library hacking. */ + +static int +solib_add_stub (from_tty) + char *from_tty; +{ + SOLIB_ADD (NULL, (int)from_tty, &core_ops); + return 0; +} +#endif /* SOLIB_ADD */ + +/* Look for sections whose names start with `.reg/' so that we can extract the + list of threads in a core file. */ + +static void +add_to_thread_list (abfd, asect, reg_sect_arg) + bfd *abfd; + asection *asect; + PTR reg_sect_arg; +{ + int thread_id; + asection *reg_sect = (asection *) reg_sect_arg; + + if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0) + return; + + thread_id = atoi (bfd_section_name (abfd, asect) + 5); + + add_thread (thread_id); + +/* Warning, Will Robinson, looking at BFD private data! */ + + if (asect->filepos == reg_sect->filepos) /* Did we find .reg? */ + inferior_pid = thread_id; /* Yes, make it current */ +} + +/* This routine opens and sets up the core file bfd */ + +void +core_open (filename, from_tty) + char *filename; + int from_tty; +{ + const char *p; + int siggy; + struct cleanup *old_chain; + char *temp; + bfd *temp_bfd; + int ontop; + int scratch_chan; + + target_preopen (from_tty); + if (!filename) + { + error (core_bfd? + "No core file specified. (Use `detach' to stop debugging a core file.)" + : "No core file specified."); + } + + filename = tilde_expand (filename); + if (filename[0] != '/') { + temp = concat (current_directory, "/", filename, NULL); + free (filename); + filename = temp; + } + + old_chain = make_cleanup (free, filename); + + scratch_chan = open (filename, write_files? O_RDWR: O_RDONLY, 0); + if (scratch_chan < 0) + perror_with_name (filename); + + temp_bfd = bfd_fdopenr (filename, gnutarget, scratch_chan); + if (temp_bfd == NULL) + { + perror_with_name (filename); + } + + if (!bfd_check_format (temp_bfd, bfd_core)) + { + /* Do it after the err msg */ + make_cleanup (bfd_close, temp_bfd); + error ("\"%s\" is not a core dump: %s", filename, bfd_errmsg(bfd_error)); + } + + /* Looks semi-reasonable. Toss the old core file and work on the new. */ + + discard_cleanups (old_chain); /* Don't free filename any more */ + unpush_target (&core_ops); + core_bfd = temp_bfd; + old_chain = make_cleanup (core_close, core_bfd); + + validate_files (); + + /* Find the data section */ + if (build_section_table (core_bfd, &core_ops.to_sections, + &core_ops.to_sections_end)) + error ("Can't find sections in `%s': %s", bfd_get_filename(core_bfd), + bfd_errmsg (bfd_error)); + + ontop = !push_target (&core_ops); + discard_cleanups (old_chain); + + p = bfd_core_file_failing_command (core_bfd); + if (p) + printf_filtered ("Core was generated by `%s'.\n", p); + + siggy = bfd_core_file_failing_signal (core_bfd); + if (siggy > 0) + printf_filtered ("Program terminated with signal %d, %s.\n", siggy, + safe_strsignal (siggy)); + + /* Build up thread list from BFD sections. */ + + init_thread_list (); + bfd_map_over_sections (core_bfd, add_to_thread_list, + bfd_get_section_by_name (core_bfd, ".reg")); + + if (ontop) { + /* Fetch all registers from core file */ + target_fetch_registers (-1); + + /* Add symbols and section mappings for any shared libraries */ +#ifdef SOLIB_ADD + catch_errors (solib_add_stub, (char *)from_tty, (char *)0, + RETURN_MASK_ALL); +#endif + + /* Now, set up the frame cache, and print the top of stack */ + 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); + } else { + warning ( +"you won't be able to access this core file until you terminate\n\ +your %s; do ``info files''", current_target->to_longname); + } +} + +void +core_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Too many arguments"); + unpush_target (&core_ops); + reinit_frame_cache (); + if (from_tty) + printf_filtered ("No 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_core_registers (regno) + int regno; +{ + sec_ptr reg_sec; + unsigned size; + char *the_regs; + char secname[10]; + + /* Thread support. If inferior_pid is non-zero, then we have found a core + file with threads (or multiple processes). In that case, we need to + use the appropriate register section, else we just use `.reg'. */ + + /* XXX - same thing needs to be done for floating-point (.reg2) sections. */ + + if (inferior_pid) + sprintf (secname, ".reg/%d", inferior_pid); + else + strcpy (secname, ".reg"); + + reg_sec = bfd_get_section_by_name (core_bfd, secname); + if (!reg_sec) goto cant; + size = bfd_section_size (core_bfd, reg_sec); + the_regs = alloca (size); + if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0, size)) + { + fetch_core_registers (the_regs, size, 0, + (unsigned) bfd_section_vma (abfd,reg_sec)); + } + else + { +cant: + fprintf_filtered (stderr, "Couldn't fetch registers from core file: %s\n", + bfd_errmsg (bfd_error)); + } + + /* Now do it again for the float registers, if they exist. */ + reg_sec = bfd_get_section_by_name (core_bfd, ".reg2"); + if (reg_sec) { + size = bfd_section_size (core_bfd, reg_sec); + the_regs = alloca (size); + if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0, + size)) + { + fetch_core_registers (the_regs, size, 2, + (unsigned) bfd_section_vma (abfd,reg_sec)); + } + else + { + fprintf_filtered (stderr, "Couldn't fetch register set 2 from core file: %s\n", + bfd_errmsg (bfd_error)); + } + } + registers_fetched(); +} + +static void +core_files_info (t) + struct target_ops *t; +{ + print_section_info (t, core_bfd); +} + +/* If mourn is being called in all the right places, this could be say + `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */ + +static int +ignore (addr, contents) + CORE_ADDR addr; + char *contents; +{ +} + +struct target_ops core_ops = { + "core", "Local core dump file", + "Use a core file as a target. Specify the filename of the core file.", + core_open, core_close, + find_default_attach, core_detach, 0, 0, /* resume, wait */ + get_core_registers, + 0, 0, /* store_regs, prepare_to_store */ + xfer_memory, core_files_info, + ignore, ignore, /* core_insert_breakpoint, core_remove_breakpoint, */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, 0, 0, /* kill, load, lookup sym */ + find_default_create_inferior, 0, /* mourn_inferior */ + 0, /* can_run */ + 0, /* notice_signals */ + core_stratum, 0, /* next */ + 0, 1, 1, 1, 0, /* all mem, mem, stack, regs, exec */ + 0, 0, /* section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_corelow() +{ + add_target (&core_ops); +} diff --git a/gnu/usr.bin/gdb/gdb/cp-valprint.c b/gnu/usr.bin/gdb/gdb/cp-valprint.c new file mode 100644 index 00000000000..47b38f803d9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/cp-valprint.c @@ -0,0 +1,484 @@ +/* Support for printing C++ values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "command.h" +#include "gdbcmd.h" +#include "demangle.h" + +int vtblprint; /* Controls printing of vtbl's */ +int objectprint; /* Controls looking up an object's derived type + using what we find in its vtables. */ +struct obstack dont_print_obstack; + +static void +cplus_print_value PARAMS ((struct type *, char *, FILE *, int, int, + enum val_prettyprint, struct type **)); + +/* BEGIN-FIXME: Hooks into typeprint.c, find a better home for prototypes. */ + +extern void +c_type_print_base PARAMS ((struct type *, FILE *, int, int)); + +extern void +c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int)); + +extern void +cp_type_print_method_args PARAMS ((struct type **, char *, char *, int, + FILE *)); + +extern struct obstack dont_print_obstack; + +/* END-FIXME */ + + +/* BEGIN-FIXME: Hooks into c-valprint.c */ + +extern int +c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, int, + enum val_prettyprint)); +/* END-FIXME */ + + +void +cp_print_class_method (valaddr, type, stream) + char *valaddr; + struct type *type; + FILE *stream; +{ + struct type *domain; + struct fn_field *f = NULL; + int j = 0; + int len2; + int offset; + char *kind = ""; + CORE_ADDR addr; + struct symbol *sym; + unsigned len; + unsigned int i; + + check_stub_type (TYPE_TARGET_TYPE (type)); + domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)); + if (domain == (struct type *)NULL) + { + fprintf_filtered (stream, ""); + return; + } + addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr); + if (METHOD_PTR_IS_VIRTUAL (addr)) + { + offset = METHOD_PTR_TO_VOFFSET (addr); + len = TYPE_NFN_FIELDS (domain); + for (i = 0; i < len; i++) + { + f = TYPE_FN_FIELDLIST1 (domain, i); + len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); + + for (j = 0; j < len2; j++) + { + QUIT; + if (TYPE_FN_FIELD_VOFFSET (f, j) == offset) + { + kind = "virtual "; + goto common; + } + } + } + } + else + { + sym = find_pc_function (addr); + if (sym == 0) + { + error ("invalid pointer to member function"); + } + len = TYPE_NFN_FIELDS (domain); + for (i = 0; i < len; i++) + { + f = TYPE_FN_FIELDLIST1 (domain, i); + len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); + + for (j = 0; j < len2; j++) + { + QUIT; + if (TYPE_FN_FIELD_STUB (f, j)) + check_stub_method (domain, i, j); + if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))) + { + goto common; + } + } + } + } + common: + if (i < len) + { + fprintf_filtered (stream, "&"); + c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0); + fprintf (stream, kind); + if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' + && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER) + { + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, "~", + TYPE_FN_FIELDLIST_NAME (domain, i), + 0, stream); + } + else + { + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "", + TYPE_FN_FIELDLIST_NAME (domain, i), + 0, stream); + } + } + else + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") %d", (int) addr >> 3); + } +} + +/* Return truth value for assertion that TYPE is of the type + "pointer to virtual function". */ + +int +cp_is_vtbl_ptr_type(type) + struct type *type; +{ + char *typename = type_name_no_tag (type); + /* This was what it was for gcc 2.4.5 and earlier. */ + static const char vtbl_ptr_name_old[] = + { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 }; + /* It was changed to this after 2.4.5. */ + static const char vtbl_ptr_name[] = + { '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 }; + + return (typename != NULL + && (STREQ (typename, vtbl_ptr_name) + || STREQ (typename, vtbl_ptr_name_old))); +} + +/* Return truth value for the assertion that TYPE is of the type + "pointer to virtual function table". */ + +int +cp_is_vtbl_member(type) + struct type *type; +{ + if (TYPE_CODE (type) == TYPE_CODE_PTR) + type = TYPE_TARGET_TYPE (type); + else + return 0; + + if (TYPE_CODE (type) == TYPE_CODE_ARRAY + && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT) + /* Virtual functions tables are full of pointers to virtual functions. */ + return cp_is_vtbl_ptr_type (TYPE_TARGET_TYPE (type)); + return 0; +} + +/* Mutually recursive subroutines of cplus_print_value and c_val_print to + print out a structure's fields: cp_print_value_fields and cplus_print_value. + + TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the + same meanings as in cplus_print_value and c_val_print. + + DONT_PRINT is an array of baseclass types that we + should not print, or zero if called from top level. */ + +void +cp_print_value_fields (type, valaddr, stream, format, recurse, pretty, + dont_print) + struct type *type; + char *valaddr; + FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; + struct type **dont_print; +{ + int i, len, n_baseclasses; + + check_stub_type (type); + + fprintf_filtered (stream, "{"); + len = TYPE_NFIELDS (type); + n_baseclasses = TYPE_N_BASECLASSES (type); + + /* Print out baseclasses such that we don't print + duplicates of virtual baseclasses. */ + if (n_baseclasses > 0) + cplus_print_value (type, valaddr, stream, format, recurse+1, pretty, + dont_print); + + if (!len && n_baseclasses == 1) + fprintf_filtered (stream, ""); + else + { + extern int inspect_it; + int fields_seen = 0; + + for (i = n_baseclasses; i < len; i++) + { + /* Check if static field */ + if (TYPE_FIELD_STATIC (type, i)) + continue; + if (fields_seen) + fprintf_filtered (stream, ", "); + else if (n_baseclasses > 0) + { + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + fputs_filtered ("members of ", stream); + fputs_filtered (type_name_no_tag (type), stream); + fputs_filtered (": ", stream); + } + } + fields_seen = 1; + + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + wrap_here (n_spaces (2 + 2 * recurse)); + } + if (inspect_it) + { + if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR) + fputs_filtered ("\"( ptr \"", stream); + else + fputs_filtered ("\"( nodef \"", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_cplus, + DMGL_PARAMS | DMGL_ANSI); + fputs_filtered ("\" \"", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_cplus, + DMGL_PARAMS | DMGL_ANSI); + fputs_filtered ("\") \"", stream); + } + else + { + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_cplus, + DMGL_PARAMS | DMGL_ANSI); + fputs_filtered (" = ", stream); + } + if (TYPE_FIELD_PACKED (type, i)) + { + value v; + + /* Bitfields require special handling, especially due to byte + order problems. */ + v = value_from_longest (TYPE_FIELD_TYPE (type, i), + unpack_field_as_long (type, valaddr, i)); + + c_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0, + stream, format, 0, recurse + 1, pretty); + } + else + { + c_val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, 0, recurse + 1, pretty); + } + } + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + } + fprintf_filtered (stream, "}"); +} + +/* Special val_print routine to avoid printing multiple copies of virtual + baseclasses. */ + +static void +cplus_print_value (type, valaddr, stream, format, recurse, pretty, dont_print) + struct type *type; + char *valaddr; + FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; + struct type **dont_print; +{ + struct obstack tmp_obstack; + struct type **last_dont_print + = (struct type **)obstack_next_free (&dont_print_obstack); + int i, n_baseclasses = TYPE_N_BASECLASSES (type); + + if (dont_print == 0) + { + /* If we're at top level, carve out a completely fresh + chunk of the obstack and use that until this particular + invocation returns. */ + tmp_obstack = dont_print_obstack; + /* Bump up the high-water mark. Now alpha is omega. */ + obstack_finish (&dont_print_obstack); + } + + for (i = 0; i < n_baseclasses; i++) + { + char *baddr; + int err; + char *basename = TYPE_NAME (TYPE_BASECLASS (type, i)); + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + struct type **first_dont_print + = (struct type **)obstack_base (&dont_print_obstack); + + int j = (struct type **)obstack_next_free (&dont_print_obstack) + - first_dont_print; + + while (--j >= 0) + if (TYPE_BASECLASS (type, i) == first_dont_print[j]) + goto flush_it; + + obstack_ptr_grow (&dont_print_obstack, TYPE_BASECLASS (type, i)); + } + + /* Fix to use baseclass_offset instead. FIXME */ + baddr = baseclass_addr (type, i, valaddr, 0, &err); + if (err == 0 && baddr == 0) + error ("could not find virtual baseclass %s\n", + basename ? basename : ""); + + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + fputs_filtered ("<", stream); + /* Not sure what the best notation is in the case where there is no + baseclass name. */ + fputs_filtered (basename ? basename : "", stream); + fputs_filtered ("> = ", stream); + if (err != 0) + fprintf_filtered (stream, + "", (unsigned long) baddr); + else + cp_print_value_fields (TYPE_BASECLASS (type, i), baddr, stream, format, + recurse, pretty, + (struct type **) obstack_base (&dont_print_obstack)); + fputs_filtered (", ", stream); + + flush_it: + ; + } + + if (dont_print == 0) + { + /* Free the space used to deal with the printing + of this type from top level. */ + obstack_free (&dont_print_obstack, last_dont_print); + /* Reset watermark so that we can continue protecting + ourselves from whatever we were protecting ourselves. */ + dont_print_obstack = tmp_obstack; + } +} + +void +cp_print_class_member (valaddr, domain, stream, prefix) + char *valaddr; + struct type *domain; + FILE *stream; + char *prefix; +{ + + /* VAL is a byte offset into the structure type DOMAIN. + Find the name of the field for that offset and + print it. */ + int extra = 0; + int bits = 0; + register unsigned int i; + unsigned len = TYPE_NFIELDS (domain); + /* @@ Make VAL into bit offset */ + LONGEST val = unpack_long (builtin_type_int, valaddr) << 3; + for (i = TYPE_N_BASECLASSES (domain); i < len; i++) + { + int bitpos = TYPE_FIELD_BITPOS (domain, i); + QUIT; + if (val == bitpos) + break; + if (val < bitpos && i != 0) + { + /* Somehow pointing into a field. */ + i -= 1; + extra = (val - TYPE_FIELD_BITPOS (domain, i)); + if (extra & 0x7) + bits = 1; + else + extra >>= 3; + break; + } + } + if (i < len) + { + char *name; + fprintf_filtered (stream, prefix); + name = type_name_no_tag (domain); + if (name) + fputs_filtered (name, stream); + else + c_type_print_base (domain, stream, 0, 0); + fprintf_filtered (stream, "::"); + fputs_filtered (TYPE_FIELD_NAME (domain, i), stream); + if (extra) + fprintf_filtered (stream, " + %d bytes", extra); + if (bits) + fprintf_filtered (stream, " (offset in bits)"); + } + else + fprintf_filtered (stream, "%d", val >> 3); +} + +void +_initialize_cp_valprint () +{ + add_show_from_set + (add_set_cmd ("vtbl", class_support, var_boolean, (char *)&vtblprint, + "Set printing of C++ virtual function tables.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("object", class_support, var_boolean, (char *)&objectprint, + "Set printing of object's derived type based on vtable info.", + &setprintlist), + &showprintlist); + + /* Give people the defaults which they are used to. */ + objectprint = 0; + vtblprint = 0; + obstack_begin (&dont_print_obstack, 32 * sizeof (struct type *)); +} diff --git a/gnu/usr.bin/gdb/gdb/dbxread.c b/gnu/usr.bin/gdb/gdb/dbxread.c new file mode 100644 index 00000000000..7f4ef2632ab --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/dbxread.c @@ -0,0 +1,2234 @@ +/* Read dbx symbol tables and convert to internal format, for GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993 + 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. */ + +/* This module provides three functions: dbx_symfile_init, + which initializes to read a symbol file; dbx_new_init, which + discards existing cached information when all symbols are being + discarded; and dbx_symfile_read, which reads a symbol table + from a file. + + dbx_symfile_read only does the minimum work necessary for letting the + user "name" things symbolically; it does not read the entire symtab. + Instead, it reads the external and static symbols and puts them in partial + symbol tables. When more extensive information is requested of a + file, the corresponding partial symbol table is mutated into a full + fledged symbol table by going back and reading the symbols + for real. dbx_psymtab_to_symtab() is the function that does this */ + +#include "defs.h" +#include + +#if defined(USG) || defined(__CYGNUSCLIB__) +#include +#include +#endif + +#include +#include +#ifndef NO_SYS_FILE +#include +#endif +#include +#include +#include "symtab.h" +#include "breakpoint.h" +#include "command.h" +#include "target.h" +#include "gdbcore.h" /* for bfd stuff */ +#include "libbfd.h" /* FIXME Secret internal BFD stuff (bfd_read) */ +#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */ +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "gdb-stabs.h" +#include "demangle.h" +#include "language.h" /* Needed inside partial-stab.h */ +#include "complaints.h" + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" /* We always use GNU stabs, not native, now */ + +#if !defined (SEEK_SET) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#endif + +/* Each partial symbol table entry contains a pointer to private data for the + read_symtab() function to use when expanding a partial symbol table entry + to a full symbol table entry. + + For dbxread this structure contains the offset within the file symbol table + of first local symbol for this file, and length (in bytes) of the section + of the symbol table devoted to this file's symbols (actually, the section + bracketed may contain more than just this file's symbols). It also contains + further information needed to locate the symbols if they are in an ELF file. + + If ldsymlen is 0, the only reason for this thing's existence is the + dependency list. Nothing else will happen when it is read in. */ + +#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff) +#define LDSYMLEN(p) (((struct symloc *)((p)->read_symtab_private))->ldsymlen) +#define SYMLOC(p) ((struct symloc *)((p)->read_symtab_private)) +#define SYMBOL_SIZE(p) (SYMLOC(p)->symbol_size) +#define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset) +#define STRING_OFFSET(p) (SYMLOC(p)->string_offset) +#define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset) + +struct symloc { + int ldsymoff; + int ldsymlen; + int symbol_size; + int symbol_offset; + int string_offset; + int file_string_offset; +}; + +/* Macro to determine which symbols to ignore when reading the first symbol + of a file. Some machines override this definition. */ +#ifndef IGNORE_SYMBOL +/* This code is used on Ultrix systems. Ignore it */ +#define IGNORE_SYMBOL(type) (type == (int)N_NSYMS) +#endif + +/* Macro for name of symbol to indicate a file compiled with gcc. */ +#ifndef GCC_COMPILED_FLAG_SYMBOL +#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled." +#endif + +/* Macro for name of symbol to indicate a file compiled with gcc2. */ +#ifndef GCC2_COMPILED_FLAG_SYMBOL +#define GCC2_COMPILED_FLAG_SYMBOL "gcc2_compiled." +#endif + +/* Define this as 1 if a pcc declaration of a char or short argument + gives the correct address. Otherwise assume pcc gives the + address of the corresponding int, which is not the same on a + big-endian machine. */ + +#ifndef BELIEVE_PCC_PROMOTION +#define BELIEVE_PCC_PROMOTION 0 +#endif + +/* Remember what we deduced to be the source language of this psymtab. */ + +static enum language psymtab_language = language_unknown; + +/* Nonzero means give verbose info on gdb action. From main.c. */ +extern int info_verbose; + +/* The BFD for this file -- implicit parameter to next_symbol_text. */ + +static bfd *symfile_bfd; + +/* The size of each symbol in the symbol file (in external form). + This is set by dbx_symfile_read when building psymtabs, and by + dbx_psymtab_to_symtab when building symtabs. */ + +static unsigned symbol_size; + +/* This is the offset of the symbol table in the executable file */ +static unsigned symbol_table_offset; + +/* This is the offset of the string table in the executable file */ +static unsigned string_table_offset; + +/* For elf+stab executables, the n_strx field is not a simple index + into the string table. Instead, each .o file has a base offset + in the string table, and the associated symbols contain offsets + from this base. The following two variables contain the base + offset for the current and next .o files. */ +static unsigned int file_string_table_offset; +static unsigned int next_file_string_table_offset; + +/* Complaints about the symbols we have encountered. */ + +struct complaint lbrac_complaint = + {"bad block start address patched", 0, 0}; + +struct complaint string_table_offset_complaint = + {"bad string table offset in symbol %d", 0, 0}; + +struct complaint unknown_symtype_complaint = + {"unknown symbol type %s", 0, 0}; + +struct complaint unknown_symchar_complaint = + {"unknown symbol type character `%c'", 0, 0}; + +struct complaint lbrac_rbrac_complaint = + {"block start larger than block end", 0, 0}; + +struct complaint lbrac_unmatched_complaint = + {"unmatched N_LBRAC before symtab pos %d", 0, 0}; + +struct complaint lbrac_mismatch_complaint = + {"N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", 0, 0}; + +struct complaint repeated_header_complaint = + {"\"repeated\" header file not previously seen, at symtab pos %d", 0, 0}; + +struct complaint repeated_header_name_complaint = + {"\"repeated\" header file not previously seen, named %s", 0, 0}; + +/* During initial symbol readin, we need to have a structure to keep + track of which psymtabs have which bincls in them. This structure + is used during readin to setup the list of dependencies within each + partial symbol table. */ + +struct header_file_location +{ + char *name; /* Name of header file */ + int instance; /* See above */ + struct partial_symtab *pst; /* Partial symtab that has the + BINCL/EINCL defs for this file */ +}; + +/* The actual list and controling variables */ +static struct header_file_location *bincl_list, *next_bincl; +static int bincls_allocated; + +/* Local function prototypes */ + +static void +free_header_files PARAMS ((void)); + +static void +init_header_files PARAMS ((void)); + +static void +read_ofile_symtab PARAMS ((struct partial_symtab *)); + +static void +dbx_psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +static void +dbx_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); + +static void +read_dbx_symtab PARAMS ((struct section_offsets *, struct objfile *, + CORE_ADDR, int)); + +static void +free_bincl_list PARAMS ((struct objfile *)); + +static struct partial_symtab * +find_corresponding_bincl_psymtab PARAMS ((char *, int)); + +static void +add_bincl_to_list PARAMS ((struct partial_symtab *, char *, int)); + +static void +init_bincl_list PARAMS ((int, struct objfile *)); + +static void +init_psymbol_list PARAMS ((struct objfile *)); + +static char * +dbx_next_symbol_text PARAMS ((void)); + +static void +fill_symbuf PARAMS ((bfd *)); + +static void +dbx_symfile_init PARAMS ((struct objfile *)); + +static void +dbx_new_init PARAMS ((struct objfile *)); + +static void +dbx_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +dbx_symfile_finish PARAMS ((struct objfile *)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *)); + +static void +add_new_header_file PARAMS ((char *, int)); + +static void +add_old_header_file PARAMS ((char *, int)); + +static void +add_this_object_header_file PARAMS ((int)); + +/* Free up old header file tables */ + +static void +free_header_files () +{ + register int i; + + if (header_files != NULL) + { + for (i = 0; i < n_header_files; i++) + { + free (header_files[i].name); + } + free ((PTR)header_files); + header_files = NULL; + n_header_files = 0; + } + if (this_object_header_files) + { + free ((PTR)this_object_header_files); + this_object_header_files = NULL; + } + n_allocated_header_files = 0; + n_allocated_this_object_header_files = 0; +} + +/* Allocate new header file tables */ + +static void +init_header_files () +{ + n_header_files = 0; + n_allocated_header_files = 10; + header_files = (struct header_file *) + xmalloc (10 * sizeof (struct header_file)); + + n_allocated_this_object_header_files = 10; + this_object_header_files = (int *) xmalloc (10 * sizeof (int)); +} + +/* Add header file number I for this object file + at the next successive FILENUM. */ + +static void +add_this_object_header_file (i) + int i; +{ + if (n_this_object_header_files == n_allocated_this_object_header_files) + { + n_allocated_this_object_header_files *= 2; + this_object_header_files + = (int *) xrealloc ((char *) this_object_header_files, + n_allocated_this_object_header_files * sizeof (int)); + } + + this_object_header_files[n_this_object_header_files++] = i; +} + +/* Add to this file an "old" header file, one already seen in + a previous object file. NAME is the header file's name. + INSTANCE is its instance code, to select among multiple + symbol tables for the same header file. */ + +static void +add_old_header_file (name, instance) + char *name; + int instance; +{ + register struct header_file *p = header_files; + register int i; + + for (i = 0; i < n_header_files; i++) + if (STREQ (p[i].name, name) && instance == p[i].instance) + { + add_this_object_header_file (i); + return; + } + complain (&repeated_header_complaint, symnum); + complain (&repeated_header_name_complaint, name); +} + +/* Add to this file a "new" header file: definitions for its types follow. + NAME is the header file's name. + Most often this happens only once for each distinct header file, + but not necessarily. If it happens more than once, INSTANCE has + a different value each time, and references to the header file + use INSTANCE values to select among them. + + dbx output contains "begin" and "end" markers for each new header file, + but at this level we just need to know which files there have been; + so we record the file when its "begin" is seen and ignore the "end". */ + +static void +add_new_header_file (name, instance) + char *name; + int instance; +{ + register int i; + + /* Make sure there is room for one more header file. */ + + if (n_header_files == n_allocated_header_files) + { + n_allocated_header_files *= 2; + header_files = (struct header_file *) + xrealloc ((char *) header_files, + (n_allocated_header_files * sizeof (struct header_file))); + } + + /* Create an entry for this header file. */ + + i = n_header_files++; + header_files[i].name = savestring (name, strlen(name)); + header_files[i].instance = instance; + header_files[i].length = 10; + header_files[i].vector + = (struct type **) xmalloc (10 * sizeof (struct type *)); + memset (header_files[i].vector, 0, 10 * sizeof (struct type *)); + + add_this_object_header_file (i); +} + +#if 0 +static struct type ** +explicit_lookup_type (real_filenum, index) + int real_filenum, index; +{ + register struct header_file *f = &header_files[real_filenum]; + + if (index >= f->length) + { + f->length *= 2; + f->vector = (struct type **) + xrealloc (f->vector, f->length * sizeof (struct type *)); + memset (&f->vector[f->length / 2], + '\0', f->length * sizeof (struct type *) / 2); + } + return &f->vector[index]; +} +#endif + +static void +record_minimal_symbol (name, address, type, objfile) + char *name; + CORE_ADDR address; + int type; + struct objfile *objfile; +{ + enum minimal_symbol_type ms_type; + + switch (type) + { + case N_TEXT | N_EXT: ms_type = mst_text; break; + case N_DATA | N_EXT: ms_type = mst_data; break; + case N_BSS | N_EXT: ms_type = mst_bss; break; + case N_ABS | N_EXT: ms_type = mst_abs; break; +#ifdef N_SETV + case N_SETV | N_EXT: ms_type = mst_data; break; + case N_SETV: + /* I don't think this type actually exists; since a N_SETV is the result + of going over many .o files, it doesn't make sense to have one + file local. */ + ms_type = mst_file_data; + break; +#endif + case N_TEXT: + /* Don't put gcc_compiled, __gnu_compiled_cplus, and friends into + the minimal symbols, because if there is also another symbol + at the same address (e.g. the first function of the file), + lookup_minimal_symbol_by_pc would have no way of getting the + right one. */ + if (name[0] == 'g' + && (strcmp (name, GCC_COMPILED_FLAG_SYMBOL) == 0 + || strcmp (name, GCC2_COMPILED_FLAG_SYMBOL) == 0)) + return; + + { + char *tempstring = name; + if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd)) + ++tempstring; + if (STREQN (tempstring, "__gnu_compiled", 14)) + return; + } + + case N_NBTEXT: + case N_FN: + case N_FN_SEQ: + ms_type = mst_file_text; + break; + + case N_DATA: + ms_type = mst_file_data; + + /* Check for __DYNAMIC, which is used by Sun shared libraries. + Record it as global even if it's local, not global, so + lookup_minimal_symbol can find it. We don't check symbol_leading_char + because for SunOS4 it always is '_'. */ + if (name[8] == 'C' && STREQ ("__DYNAMIC", name)) + ms_type = mst_data; + + /* Same with virtual function tables, both global and static. */ + { + char *tempstring = name; + if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd)) + ++tempstring; + if (VTBL_PREFIX_P ((tempstring))) + ms_type = mst_data; + } + break; + + case N_BSS: + ms_type = mst_file_bss; + break; + + default: ms_type = mst_unknown; break; + } + + prim_record_minimal_symbol + (obsavestring (name, strlen (name), &objfile -> symbol_obstack), + address, + ms_type); +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to dbx_symfile_init, which + put all the relevant info into a "struct dbx_symfile_info", + hung off the objfile structure. + + SECTION_OFFSETS contains offsets relative to which the symbols in the + various sections are (depending where the sections were actually loaded). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). */ + +static void +dbx_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; /* FIXME comments above */ +{ + bfd *sym_bfd; + int val; + struct cleanup *back_to; + + sym_bfd = objfile->obfd; + val = bfd_seek (objfile->obfd, DBX_SYMTAB_OFFSET (objfile), SEEK_SET); + if (val < 0) + perror_with_name (objfile->name); + + /* If we are reinitializing, or if we have never loaded syms yet, init */ + if (mainline || objfile->global_psymbols.size == 0 || objfile->static_psymbols.size == 0) + init_psymbol_list (objfile); + + symbol_size = DBX_SYMBOL_SIZE (objfile); + symbol_table_offset = DBX_SYMTAB_OFFSET (objfile); + + pending_blocks = 0; + back_to = make_cleanup (really_free_pendings, 0); + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + /* Now that the symbol table data of the executable file are all in core, + process them and define symbols accordingly. */ + + read_dbx_symtab (section_offsets, objfile, + bfd_section_vma (sym_bfd, DBX_TEXT_SECT (objfile)), + bfd_section_size (sym_bfd, DBX_TEXT_SECT (objfile))); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + if (!have_partial_symbols ()) { + wrap_here (""); + printf_filtered ("(no debugging symbols found)..."); + wrap_here (""); + } + + do_cleanups (back_to); +} + +/* Initialize anything that needs initializing when a completely new + symbol file is specified (not just adding some symbols from another + file, e.g. a shared library). */ + +static void +dbx_new_init (ignore) + struct objfile *ignore; +{ + stabsread_new_init (); + buildsym_new_init (); + init_header_files (); +} + + +/* dbx_symfile_init () + is the dbx-specific initialization routine for reading symbols. + It is passed a struct objfile which contains, among other things, + the BFD for the file whose symbols are being read, and a slot for a pointer + to "private data" which we fill with goodies. + + We read the string table into malloc'd space and stash a pointer to it. + + Since BFD doesn't know how to read debug symbols in a format-independent + way (and may never do so...), we have to do it ourselves. We will never + be called unless this is an a.out (or very similar) file. + FIXME, there should be a cleaner peephole into the BFD environment here. */ + +#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */ + +static void +dbx_symfile_init (objfile) + struct objfile *objfile; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + unsigned char size_temp[DBX_STRINGTAB_SIZE_SIZE]; + + /* Allocate struct to keep track of the symfile */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + + /* FIXME POKING INSIDE BFD DATA STRUCTURES */ +#define STRING_TABLE_OFFSET (sym_bfd->origin + obj_str_filepos (sym_bfd)) +#define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_sym_filepos (sym_bfd)) + + /* FIXME POKING INSIDE BFD DATA STRUCTURES */ + + DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL; + DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); + if (!DBX_TEXT_SECT (objfile)) + error ("Can't find .text section in symbol file"); + + DBX_SYMBOL_SIZE (objfile) = obj_symbol_entry_size (sym_bfd); + DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd); + DBX_SYMTAB_OFFSET (objfile) = SYMBOL_TABLE_OFFSET; + + /* Read the string table and stash it away in the psymbol_obstack. It is + only needed as long as we need to expand psymbols into full symbols, + so when we blow away the psymbol the string table goes away as well. + Note that gdb used to use the results of attempting to malloc the + string table, based on the size it read, as a form of sanity check + for botched byte swapping, on the theory that a byte swapped string + table size would be so totally bogus that the malloc would fail. Now + that we put in on the psymbol_obstack, we can't do this since gdb gets + a fatal error (out of virtual memory) if the size is bogus. We can + however at least check to see if the size is less than the size of + the size field itself, or larger than the size of the entire file. + Note that all valid string tables have a size greater than zero, since + the bytes used to hold the size are included in the count. */ + + if (STRING_TABLE_OFFSET == 0) + { + /* It appears that with the existing bfd code, STRING_TABLE_OFFSET + will never be zero, even when there is no string table. This + would appear to be a bug in bfd. */ + DBX_STRINGTAB_SIZE (objfile) = 0; + DBX_STRINGTAB (objfile) = NULL; + } + else + { + val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET); + if (val < 0) + perror_with_name (name); + + memset ((PTR) size_temp, 0, sizeof (size_temp)); + val = bfd_read ((PTR) size_temp, sizeof (size_temp), 1, sym_bfd); + if (val < 0) + { + perror_with_name (name); + } + else if (val == 0) + { + /* With the existing bfd code, STRING_TABLE_OFFSET will be set to + EOF if there is no string table, and attempting to read the size + from EOF will read zero bytes. */ + DBX_STRINGTAB_SIZE (objfile) = 0; + DBX_STRINGTAB (objfile) = NULL; + } + else + { + /* Read some data that would appear to be the string table size. + If there really is a string table, then it is probably the right + size. Byteswap if necessary and validate the size. Note that + the minimum is DBX_STRINGTAB_SIZE_SIZE. If we just read some + random data that happened to be at STRING_TABLE_OFFSET, because + bfd can't tell us there is no string table, the sanity checks may + or may not catch this. */ + DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp); + + if (DBX_STRINGTAB_SIZE (objfile) < sizeof (size_temp) + || DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd)) + error ("ridiculous string table size (%d bytes).", + DBX_STRINGTAB_SIZE (objfile)); + + DBX_STRINGTAB (objfile) = + (char *) obstack_alloc (&objfile -> psymbol_obstack, + DBX_STRINGTAB_SIZE (objfile)); + + /* Now read in the string table in one big gulp. */ + + val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (DBX_STRINGTAB (objfile), DBX_STRINGTAB_SIZE (objfile), 1, + sym_bfd); + if (val != DBX_STRINGTAB_SIZE (objfile)) + perror_with_name (name); + } + } +} + +/* Perform any local cleanups required when we are done with a particular + objfile. I.E, we are in the process of discarding all symbol information + for an objfile, freeing up all memory held for it, and unlinking the + objfile struct from the global list of known objfiles. */ + +static void +dbx_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile->sym_stab_info != NULL) + { + mfree (objfile -> md, objfile->sym_stab_info); + } + free_header_files (); +} + + +/* Buffer for reading the symbol table entries. */ +static struct internal_nlist symbuf[4096]; +static int symbuf_idx; +static int symbuf_end; + +/* Name of last function encountered. Used in Solaris to approximate + object file boundaries. */ +static char *last_function_name; + +/* The address in memory of the string table of the object file we are + reading (which might not be the "main" object file, but might be a + shared library or some other dynamically loaded thing). This is set + by read_dbx_symtab when building psymtabs, and by read_ofile_symtab + when building symtabs, and is used only by next_symbol_text. */ +static char *stringtab_global; + +/* Refill the symbol table input buffer + and set the variables that control fetching entries from it. + Reports an error if no data available. + This function can read past the end of the symbol table + (into the string table) but this does no harm. */ + +static void +fill_symbuf (sym_bfd) + bfd *sym_bfd; +{ + int nbytes = bfd_read ((PTR)symbuf, sizeof (symbuf), 1, sym_bfd); + if (nbytes < 0) + perror_with_name (bfd_get_filename (sym_bfd)); + else if (nbytes == 0) + error ("Premature end of file reading symbol table"); + symbuf_end = nbytes / symbol_size; + symbuf_idx = 0; +} + +#define SWAP_SYMBOL(symp, abfd) \ + { \ + (symp)->n_strx = bfd_h_get_32(abfd, \ + (unsigned char *)&(symp)->n_strx); \ + (symp)->n_desc = bfd_h_get_16 (abfd, \ + (unsigned char *)&(symp)->n_desc); \ + (symp)->n_value = bfd_h_get_32 (abfd, \ + (unsigned char *)&(symp)->n_value); \ + } + +/* Invariant: The symbol pointed to by symbuf_idx is the first one + that hasn't been swapped. Swap the symbol at the same time + that symbuf_idx is incremented. */ + +/* dbx allows the text of a symbol name to be continued into the + next symbol name! When such a continuation is encountered + (a \ at the end of the text of a name) + call this function to get the continuation. */ + +static char * +dbx_next_symbol_text () +{ + if (symbuf_idx == symbuf_end) + fill_symbuf (symfile_bfd); + symnum++; + SWAP_SYMBOL(&symbuf[symbuf_idx], symfile_bfd); + return symbuf[symbuf_idx++].n_strx + stringtab_global + + file_string_table_offset; +} + +/* Initializes storage for all of the partial symbols that will be + created by read_dbx_symtab and subsidiaries. */ + +static void +init_psymbol_list (objfile) + struct objfile *objfile; +{ + /* Free any previously allocated psymbol lists. */ + if (objfile -> global_psymbols.list) + mfree (objfile -> md, (PTR)objfile -> global_psymbols.list); + if (objfile -> static_psymbols.list) + mfree (objfile -> md, (PTR)objfile -> static_psymbols.list); + + /* Current best guess is that there are approximately a twentieth + of the total symbols (in a debugging file) are global or static + oriented symbols */ + objfile -> global_psymbols.size = DBX_SYMCOUNT (objfile) / 10; + objfile -> static_psymbols.size = DBX_SYMCOUNT (objfile) / 10; + objfile -> global_psymbols.next = objfile -> global_psymbols.list = (struct partial_symbol *) + xmmalloc (objfile -> md, objfile -> global_psymbols.size * sizeof (struct partial_symbol)); + objfile -> static_psymbols.next = objfile -> static_psymbols.list = (struct partial_symbol *) + xmmalloc (objfile -> md, objfile -> static_psymbols.size * sizeof (struct partial_symbol)); +} + +/* Initialize the list of bincls to contain none and have some + allocated. */ + +static void +init_bincl_list (number, objfile) + int number; + struct objfile *objfile; +{ + bincls_allocated = number; + next_bincl = bincl_list = (struct header_file_location *) + xmmalloc (objfile -> md, bincls_allocated * sizeof(struct header_file_location)); +} + +/* Add a bincl to the list. */ + +static void +add_bincl_to_list (pst, name, instance) + struct partial_symtab *pst; + char *name; + int instance; +{ + if (next_bincl >= bincl_list + bincls_allocated) + { + int offset = next_bincl - bincl_list; + bincls_allocated *= 2; + bincl_list = (struct header_file_location *) + xmrealloc (pst->objfile->md, (char *)bincl_list, + bincls_allocated * sizeof (struct header_file_location)); + next_bincl = bincl_list + offset; + } + next_bincl->pst = pst; + next_bincl->instance = instance; + next_bincl++->name = name; +} + +/* Given a name, value pair, find the corresponding + bincl in the list. Return the partial symtab associated + with that header_file_location. */ + +static struct partial_symtab * +find_corresponding_bincl_psymtab (name, instance) + char *name; + int instance; +{ + struct header_file_location *bincl; + + for (bincl = bincl_list; bincl < next_bincl; bincl++) + if (bincl->instance == instance + && STREQ (name, bincl->name)) + return bincl->pst; + + return (struct partial_symtab *) 0; +} + +/* Free the storage allocated for the bincl list. */ + +static void +free_bincl_list (objfile) + struct objfile *objfile; +{ + mfree (objfile -> md, (PTR)bincl_list); + bincls_allocated = 0; +} + +/* Given pointers to an a.out symbol table in core containing dbx + style data, setup partial_symtab's describing each source file for + which debugging information is available. + SYMFILE_NAME is the name of the file we are reading from + and SECTION_OFFSETS is the set of offsets for the various sections + of the file (a set of zeros if the mainline program). */ + +static void +read_dbx_symtab (section_offsets, objfile, text_addr, text_size) + struct section_offsets *section_offsets; + struct objfile *objfile; + CORE_ADDR text_addr; + int text_size; +{ + register struct internal_nlist *bufp = 0; /* =0 avoids gcc -Wall glitch */ + register char *namestring; + int nsl; + int past_first_source_file = 0; + CORE_ADDR last_o_file_start = 0; + struct cleanup *back_to; + bfd *abfd; + + /* End of the text segment of the executable file. */ + CORE_ADDR end_of_text_addr; + + /* Current partial symtab */ + struct partial_symtab *pst; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + + /* FIXME. We probably want to change stringtab_global rather than add this + while processing every symbol entry. FIXME. */ + file_string_table_offset = 0; + next_file_string_table_offset = 0; + + stringtab_global = DBX_STRINGTAB (objfile); + + pst = (struct partial_symtab *) 0; + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + /* Init bincl list */ + init_bincl_list (20, objfile); + back_to = make_cleanup (free_bincl_list, objfile); + + last_source_file = NULL; + +#ifdef END_OF_TEXT_DEFAULT + end_of_text_addr = END_OF_TEXT_DEFAULT; +#else + end_of_text_addr = text_addr + section_offsets->offsets[SECT_OFF_TEXT] + + text_size; /* Relocate */ +#endif + + symfile_bfd = objfile->obfd; /* For next_text_symbol */ + abfd = objfile->obfd; + symbuf_end = symbuf_idx = 0; + next_symbol_text_func = dbx_next_symbol_text; + + for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++) + { + /* Get the symbol for this run and pull out some info */ + QUIT; /* allow this to be interruptable */ + if (symbuf_idx == symbuf_end) + fill_symbuf (abfd); + bufp = &symbuf[symbuf_idx++]; + + /* + * Special case to speed up readin. + */ + if (bufp->n_type == (unsigned char)N_SLINE) continue; + + SWAP_SYMBOL (bufp, abfd); + + /* Ok. There is a lot of code duplicated in the rest of this + switch statement (for efficiency reasons). Since I don't + like duplicating code, I will do my penance here, and + describe the code which is duplicated: + + *) The assignment to namestring. + *) The call to strchr. + *) The addition of a partial symbol the the two partial + symbol lists. This last is a large section of code, so + I've imbedded it in the following macro. + */ + +/* Set namestring based on bufp. If the string table index is invalid, + give a fake name, and print a single error message per symbol file read, + rather than abort the symbol reading or flood the user with messages. */ + +/*FIXME: Too many adds and indirections in here for the inner loop. */ +#define SET_NAMESTRING()\ + if (((unsigned)bufp->n_strx + file_string_table_offset) >= \ + DBX_STRINGTAB_SIZE (objfile)) { \ + complain (&string_table_offset_complaint, symnum); \ + namestring = "foo"; \ + } else \ + namestring = bufp->n_strx + file_string_table_offset + \ + DBX_STRINGTAB (objfile) + +#define CUR_SYMBOL_TYPE bufp->n_type +#define CUR_SYMBOL_VALUE bufp->n_value +#define DBXREAD_ONLY +#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\ + start_psymtab(ofile, secoff, fname, low, symoff, global_syms, static_syms) +#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)\ + end_psymtab(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) + +#include "partial-stab.h" + } + + /* If there's stuff to be cleaned up, clean it up. */ + if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */ +/*FIXME, does this have a bug at start address 0? */ + && last_o_file_start + && objfile -> ei.entry_point < bufp->n_value + && objfile -> ei.entry_point >= last_o_file_start) + { + objfile -> ei.entry_file_lowpc = last_o_file_start; + objfile -> ei.entry_file_highpc = bufp->n_value; + } + + if (pst) + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * symbol_size, end_of_text_addr, + dependency_list, dependencies_used); + } + + do_cleanups (back_to); +} + +/* Allocate and partially fill a partial symtab. It will be + completely filled at the end of the symbol list. + + SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR + is the address relative to which its symbols are (incremental) or 0 + (normal). */ + + +struct partial_symtab * +start_psymtab (objfile, section_offsets, + filename, textlow, ldsymoff, global_syms, static_syms) + struct objfile *objfile; + struct section_offsets *section_offsets; + char *filename; + CORE_ADDR textlow; + int ldsymoff; + struct partial_symbol *global_syms; + struct partial_symbol *static_syms; +{ + struct partial_symtab *result = + start_psymtab_common(objfile, section_offsets, + filename, textlow, global_syms, static_syms); + + result->read_symtab_private = (char *) + obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc)); + LDSYMOFF(result) = ldsymoff; + result->read_symtab = dbx_psymtab_to_symtab; + SYMBOL_SIZE(result) = symbol_size; + SYMBOL_OFFSET(result) = symbol_table_offset; + STRING_OFFSET(result) = string_table_offset; + FILE_STRING_OFFSET(result) = file_string_table_offset; + + /* If we're handling an ELF file, drag some section-relocation info + for this source file out of the ELF symbol table, to compensate for + Sun brain death. This replaces the section_offsets in this psymtab, + if successful. */ + elfstab_offset_sections (objfile, result); + + /* Deduce the source language from the filename for this psymtab. */ + psymtab_language = deduce_language_from_filename (filename); + + return result; +} + +/* Close off the current usage of PST. + Returns PST or NULL if the partial symtab was empty and thrown away. + + FIXME: List variables and peculiarities of same. */ + +struct partial_symtab * +end_psymtab (pst, include_list, num_includes, capping_symbol_offset, + capping_text, dependency_list, number_dependencies) + struct partial_symtab *pst; + char **include_list; + int num_includes; + int capping_symbol_offset; + CORE_ADDR capping_text; + struct partial_symtab **dependency_list; + int number_dependencies; +/* struct partial_symbol *capping_global, *capping_static;*/ +{ + int i; + struct partial_symtab *p1; + struct objfile *objfile = pst -> objfile; + + if (capping_symbol_offset != -1) + LDSYMLEN(pst) = capping_symbol_offset - LDSYMOFF(pst); + pst->texthigh = capping_text; + + /* Under Solaris, the N_SO symbols always have a value of 0, + instead of the usual address of the .o file. Therefore, + we have to do some tricks to fill in texthigh and textlow. + The first trick is in partial-stab.h: if we see a static + or global function, and the textlow for the current pst + is still 0, then we use that function's address for + the textlow of the pst. + + Now, to fill in texthigh, we remember the last function seen + in the .o file (also in partial-stab.h). Also, there's a hack in + bfd/elf.c and gdb/elfread.c to pass the ELF st_size field + to here via the misc_info field. Therefore, we can fill in + a reliable texthigh by taking the address plus size of the + last function in the file. + + Unfortunately, that does not cover the case where the last function + in the file is static. See the paragraph below for more comments + on this situation. + + Finally, if we have a valid textlow for the current file, we run + down the partial_symtab_list filling in previous texthighs that + are still unknown. */ + + if (pst->texthigh == 0 && last_function_name) { + char *p; + int n; + struct minimal_symbol *minsym; + + p = strchr (last_function_name, ':'); + if (p == NULL) + p = last_function_name; + n = p - last_function_name; + p = alloca (n + 1); + strncpy (p, last_function_name, n); + p[n] = 0; + + minsym = lookup_minimal_symbol (p, objfile); + + if (minsym) { + pst->texthigh = SYMBOL_VALUE_ADDRESS (minsym) + + (long) MSYMBOL_INFO (minsym); + } else { + /* This file ends with a static function, and it's + difficult to imagine how hard it would be to track down + the elf symbol. Luckily, most of the time no one will notice, + since the next file will likely be compiled with -g, so + the code below will copy the first fuction's start address + back to our texthigh variable. (Also, if this file is the + last one in a dynamically linked program, texthigh already + has the right value.) If the next file isn't compiled + with -g, then the last function in this file winds up owning + all of the text space up to the next -g file, or the end (minus + shared libraries). This only matters for single stepping, + and even then it will still work, except that it will single + step through all of the covered functions, instead of setting + breakpoints around them as it usualy does. This makes it + pretty slow, but at least it doesn't fail. + + We can fix this with a fairly big change to bfd, but we need + to coordinate better with Cygnus if we want to do that. FIXME. */ + } + last_function_name = NULL; + } + + /* this test will be true if the last .o file is only data */ + if (pst->textlow == 0) + pst->textlow = pst->texthigh; + + /* If we know our own starting text address, then walk through all other + psymtabs for this objfile, and if any didn't know their ending text + address, set it to our starting address. Take care to not set our + own ending address to our starting address, nor to set addresses on + `dependency' files that have both textlow and texthigh zero. */ + if (pst->textlow) { + ALL_OBJFILE_PSYMTABS (objfile, p1) { + if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) { + p1->texthigh = pst->textlow; + /* if this file has only data, then make textlow match texthigh */ + if (p1->textlow == 0) + p1->textlow = p1->texthigh; + } + } + } + + /* End of kludge for patching Solaris textlow and texthigh. */ + + + pst->n_global_syms = + objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset); + pst->n_static_syms = + objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset); + + pst->number_of_dependencies = number_dependencies; + if (number_dependencies) + { + pst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + number_dependencies * sizeof (struct partial_symtab *)); + memcpy (pst->dependencies, dependency_list, + number_dependencies * sizeof (struct partial_symtab *)); + } + else + pst->dependencies = 0; + + for (i = 0; i < num_includes; i++) + { + struct partial_symtab *subpst = + allocate_psymtab (include_list[i], objfile); + + subpst->section_offsets = pst->section_offsets; + subpst->read_symtab_private = + (char *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc)); + LDSYMOFF(subpst) = + LDSYMLEN(subpst) = + subpst->textlow = + subpst->texthigh = 0; + + /* We could save slight bits of space by only making one of these, + shared by the entire set of include files. FIXME-someday. */ + subpst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct partial_symtab *)); + subpst->dependencies[0] = pst; + subpst->number_of_dependencies = 1; + + subpst->globals_offset = + subpst->n_global_syms = + subpst->statics_offset = + subpst->n_static_syms = 0; + + subpst->readin = 0; + subpst->symtab = 0; + subpst->read_symtab = pst->read_symtab; + } + + sort_pst_symbols (pst); + + /* If there is already a psymtab or symtab for a file of this name, remove it. + (If there is a symtab, more drastic things also happen.) + This happens in VxWorks. */ + free_named_symtabs (pst->filename); + + if (num_includes == 0 + && number_dependencies == 0 + && pst->n_global_syms == 0 + && pst->n_static_syms == 0) { + /* Throw away this psymtab, it's empty. We can't deallocate it, since + it is on the obstack, but we can forget to chain it on the list. */ + struct partial_symtab *prev_pst; + + /* First, snip it out of the psymtab chain */ + + if (pst->objfile->psymtabs == pst) + pst->objfile->psymtabs = pst->next; + else + for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next) + if (prev_pst->next == pst) + prev_pst->next = pst->next; + + /* Next, put it on a free list for recycling */ + + pst->next = pst->objfile->free_psymtabs; + pst->objfile->free_psymtabs = pst; + + /* Indicate that psymtab was thrown away. */ + pst = (struct partial_symtab *)NULL; + } + return pst; +} + +static void +dbx_psymtab_to_symtab_1 (pst) + struct partial_symtab *pst; +{ + struct cleanup *old_chain; + int i; + + if (!pst) + return; + + if (pst->readin) + { + fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n", + pst->filename); + return; + } + + /* Read in all partial symtabs on which this one is dependent */ + for (i = 0; i < pst->number_of_dependencies; i++) + if (!pst->dependencies[i]->readin) + { + /* Inform about additional files that need to be read in. */ + if (info_verbose) + { + fputs_filtered (" ", stdout); + wrap_here (""); + fputs_filtered ("and ", stdout); + wrap_here (""); + printf_filtered ("%s...", pst->dependencies[i]->filename); + wrap_here (""); /* Flush output */ + fflush (stdout); + } + dbx_psymtab_to_symtab_1 (pst->dependencies[i]); + } + + if (LDSYMLEN(pst)) /* Otherwise it's a dummy */ + { + /* Init stuff necessary for reading in symbols */ + stabsread_init (); + buildsym_init (); + old_chain = make_cleanup (really_free_pendings, 0); + file_string_table_offset = FILE_STRING_OFFSET (pst); + symbol_size = SYMBOL_SIZE (pst); + + /* Read in this file's symbols */ + bfd_seek (pst->objfile->obfd, SYMBOL_OFFSET (pst), SEEK_SET); + read_ofile_symtab (pst); + sort_symtab_syms (pst->symtab); + + do_cleanups (old_chain); + } + + pst->readin = 1; +} + +/* Read in all of the symbols for a given psymtab for real. + Be verbose about it if the user wants that. */ + +static void +dbx_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + bfd *sym_bfd; + + if (!pst) + return; + + if (pst->readin) + { + fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n", + pst->filename); + return; + } + + if (LDSYMLEN(pst) || pst->number_of_dependencies) + { + /* Print the message now, before reading the string table, + to avoid disconcerting pauses. */ + if (info_verbose) + { + printf_filtered ("Reading in symbols for %s...", pst->filename); + fflush (stdout); + } + + sym_bfd = pst->objfile->obfd; + + next_symbol_text_func = dbx_next_symbol_text; + + dbx_psymtab_to_symtab_1 (pst); + + /* Match with global symbols. This only needs to be done once, + after all of the symtabs and dependencies have been read in. */ + scan_file_globals (pst->objfile); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered ("done.\n"); + } +} + +/* Read in a defined section of a specific object file's symbols. */ + +static void +read_ofile_symtab (pst) + struct partial_symtab *pst; +{ + register char *namestring; + register struct internal_nlist *bufp; + unsigned char type; + unsigned max_symnum; + register bfd *abfd; + struct objfile *objfile; + int sym_offset; /* Offset to start of symbols to read */ + int sym_size; /* Size of symbols to read */ + CORE_ADDR text_offset; /* Start of text segment for symbols */ + int text_size; /* Size of text segment for symbols */ + struct section_offsets *section_offsets; + + objfile = pst->objfile; + sym_offset = LDSYMOFF(pst); + sym_size = LDSYMLEN(pst); + text_offset = pst->textlow; + text_size = pst->texthigh - pst->textlow; + section_offsets = pst->section_offsets; + + current_objfile = objfile; + subfile_stack = NULL; + + stringtab_global = DBX_STRINGTAB (objfile); + last_source_file = NULL; + + abfd = objfile->obfd; + symfile_bfd = objfile->obfd; /* Implicit param to next_text_symbol */ + symbuf_end = symbuf_idx = 0; + + /* It is necessary to actually read one symbol *before* the start + of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL + occurs before the N_SO symbol. + + Detecting this in read_dbx_symtab + would slow down initial readin, so we look for it here instead. */ + if (!processing_acc_compilation && sym_offset >= (int)symbol_size) + { + bfd_seek (symfile_bfd, sym_offset - symbol_size, SEEK_CUR); + fill_symbuf (abfd); + bufp = &symbuf[symbuf_idx++]; + SWAP_SYMBOL (bufp, abfd); + + SET_NAMESTRING (); + + processing_gcc_compilation = 0; + if (bufp->n_type == N_TEXT) + { + if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 1; + else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 2; + } + + /* Try to select a C++ demangling based on the compilation unit + producer. */ + + if (processing_gcc_compilation) + { + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + } + } + else + { + /* The N_SO starting this symtab is the first symbol, so we + better not check the symbol before it. I'm not this can + happen, but it doesn't hurt to check for it. */ + bfd_seek (symfile_bfd, sym_offset, SEEK_CUR); + processing_gcc_compilation = 0; + } + + if (symbuf_idx == symbuf_end) + fill_symbuf (abfd); + bufp = &symbuf[symbuf_idx]; + if (bufp->n_type != (unsigned char)N_SO) + error("First symbol in segment of executable not a source symbol"); + + max_symnum = sym_size / symbol_size; + + for (symnum = 0; + symnum < max_symnum; + symnum++) + { + QUIT; /* Allow this to be interruptable */ + if (symbuf_idx == symbuf_end) + fill_symbuf(abfd); + bufp = &symbuf[symbuf_idx++]; + SWAP_SYMBOL (bufp, abfd); + + type = bufp->n_type; + + SET_NAMESTRING (); + + if (type & N_STAB) { + process_one_symbol (type, bufp->n_desc, bufp->n_value, + namestring, section_offsets, objfile); + } + /* We skip checking for a new .o or -l file; that should never + happen in this routine. */ + else if (type == N_TEXT) + { + /* I don't think this code will ever be executed, because + the GCC_COMPILED_FLAG_SYMBOL usually is right before + the N_SO symbol which starts this source file. + However, there is no reason not to accept + the GCC_COMPILED_FLAG_SYMBOL anywhere. */ + + if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 1; + else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 2; + + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + } + else if (type & N_EXT || type == (unsigned char)N_TEXT + || type == (unsigned char)N_NBTEXT + ) { + /* Global symbol: see if we came across a dbx defintion for + a corresponding symbol. If so, store the value. Remove + syms from the chain when their values are stored, but + search the whole chain, as there may be several syms from + different files with the same name. */ + /* This is probably not true. Since the files will be read + in one at a time, each reference to a global symbol will + be satisfied in each file as it appears. So we skip this + section. */ + ; + } + } + + current_objfile = NULL; + + /* In a Solaris elf file, this variable, which comes from the + value of the N_SO symbol, will still be 0. Luckily, text_offset, + which comes from pst->textlow is correct. */ + if (last_source_start_addr == 0) + last_source_start_addr = text_offset; + + pst->symtab = end_symtab (text_offset + text_size, 0, 0, objfile, + SECT_OFF_TEXT); + end_stabs (); +} + + +/* This handles a single symbol from the symbol-file, building symbols + into a GDB symtab. It takes these arguments and an implicit argument. + + TYPE is the type field of the ".stab" symbol entry. + DESC is the desc field of the ".stab" entry. + VALU is the value field of the ".stab" entry. + NAME is the symbol name, in our address space. + SECTION_OFFSETS is a set of amounts by which the sections of this object + file were relocated when it was loaded into memory. + All symbols that refer + to memory locations need to be offset by these amounts. + OBJFILE is the object file from which we are reading symbols. + It is used in end_symtab. */ + +void +process_one_symbol (type, desc, valu, name, section_offsets, objfile) + int type, desc; + CORE_ADDR valu; + char *name; + struct section_offsets *section_offsets; + struct objfile *objfile; +{ +#ifdef SUN_FIXED_LBRAC_BUG + /* If SUN_FIXED_LBRAC_BUG is defined, then it tells us whether we need + to correct the address of N_LBRAC's. If it is not defined, then + we never need to correct the addresses. */ + + /* This records the last pc address we've seen. We depend on there being + an SLINE or FUN or SO before the first LBRAC, since the variable does + not get reset in between reads of different symbol files. */ + static CORE_ADDR last_pc_address; +#endif + + register struct context_stack *new; + /* This remembers the address of the start of a function. It is used + because in Solaris 2, N_LBRAC, N_RBRAC, and N_SLINE entries are + relative to the current function's start address. On systems + other than Solaris 2, this just holds the SECT_OFF_TEXT value, and is + used to relocate these symbol types rather than SECTION_OFFSETS. */ + static CORE_ADDR function_start_offset; + + /* If this is nonzero, N_LBRAC, N_RBRAC, and N_SLINE entries are relative + to the function start address. */ + int block_address_function_relative; + + /* If this is nonzero, we've seen a non-gcc N_OPT symbol for this source + file. Used to detect the SunPRO solaris compiler. */ + static int n_opt_found; + + /* The stab type used for the definition of the last function. + N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers. */ + static int function_stab_type = 0; + + /* This is true for Solaris (and all other stabs-in-elf systems, hopefully, + since it would be silly to do things differently from Solaris), and + false for SunOS4 and other a.out file formats. */ + block_address_function_relative = + 0 == strncmp (bfd_get_target (objfile->obfd), "elf", 3); + + if (!block_address_function_relative) + /* N_LBRAC, N_RBRAC and N_SLINE entries are not relative to the + function start address, so just use the text offset. */ + function_start_offset = ANOFFSET (section_offsets, SECT_OFF_TEXT); + + /* Something is wrong if we see real data before + seeing a source file name. */ + + if (last_source_file == NULL && type != (unsigned char)N_SO) + { + /* Ignore any symbols which appear before an N_SO symbol. Currently + no one puts symbols there, but we should deal gracefully with the + case. A complain()t might be in order (if !IGNORE_SYMBOL (type)), + but this should not be an error (). */ + return; + } + + switch (type) + { + case N_FUN: + case N_FNAME: + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto define_a_symbol; + + case N_LBRAC: + /* This "symbol" just indicates the start of an inner lexical + context within a function. */ + +#if defined(BLOCK_ADDRESS_ABSOLUTE) + /* Relocate for dynamic loading (?). */ + valu += function_start_offset; +#else + if (block_address_function_relative) + /* Relocate for Sun ELF acc fn-relative syms. */ + valu += function_start_offset; + else + /* On most machines, the block addresses are relative to the + N_SO, the linker did not relocate them (sigh). */ + valu += last_source_start_addr; +#endif + +#ifdef SUN_FIXED_LBRAC_BUG + if (!SUN_FIXED_LBRAC_BUG && valu < last_pc_address) { + /* Patch current LBRAC pc value to match last handy pc value */ + complain (&lbrac_complaint); + valu = last_pc_address; + } +#endif + new = push_context (desc, valu); + break; + + case N_RBRAC: + /* This "symbol" just indicates the end of an inner lexical + context that was started with N_LBRAC. */ + +#if defined(BLOCK_ADDRESS_ABSOLUTE) + /* Relocate for dynamic loading (?). */ + valu += function_start_offset; +#else + if (block_address_function_relative) + /* Relocate for Sun ELF acc fn-relative syms. */ + valu += function_start_offset; + else + /* On most machines, the block addresses are relative to the + N_SO, the linker did not relocate them (sigh). */ + valu += last_source_start_addr; +#endif + + new = pop_context(); + if (desc != new->depth) + complain (&lbrac_mismatch_complaint, symnum); + + /* Some compilers put the variable decls inside of an + LBRAC/RBRAC block. This macro should be nonzero if this + is true. DESC is N_DESC from the N_RBRAC symbol. + GCC_P is true if we've detected the GCC_COMPILED_SYMBOL + or the GCC2_COMPILED_SYMBOL. */ +#if !defined (VARIABLES_INSIDE_BLOCK) +#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 0 +#endif + + /* Can only use new->locals as local symbols here if we're in + gcc or on a machine that puts them before the lbrack. */ + if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + local_symbols = new->locals; + + /* If this is not the outermost LBRAC...RBRAC pair in the + function, its local symbols preceded it, and are the ones + just recovered from the context stack. Defined the block for them. + + If this is the outermost LBRAC...RBRAC pair, there is no + need to do anything; leave the symbols that preceded it + to be attached to the function's own block. However, if + it is so, we need to indicate that we just moved outside + of the function. */ + if (local_symbols + && (context_stack_depth + > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))) + { + /* FIXME Muzzle a compiler bug that makes end < start. */ + if (new->start_addr > valu) + { + complain (&lbrac_rbrac_complaint); + new->start_addr = valu; + } + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, valu, objfile); + } + else + { + within_function = 0; + } + if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + /* Now pop locals of block just finished. */ + local_symbols = new->locals; + break; + + case N_FN: + case N_FN_SEQ: + /* This kind of symbol indicates the start of an object file. */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + + case N_SO: + /* This type of symbol indicates the start of data + for one source file. + Finish the symbol table of the previous source file + (if any) and start accumulating a new symbol table. */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + + n_opt_found = 0; + +#ifdef SUN_FIXED_LBRAC_BUG + last_pc_address = valu; /* Save for SunOS bug circumcision */ +#endif + +#ifdef PCC_SOL_BROKEN + /* pcc bug, occasionally puts out SO for SOL. */ + if (context_stack_depth > 0) + { + start_subfile (name, NULL); + break; + } +#endif + if (last_source_file) + { + /* Check if previous symbol was also an N_SO (with some + sanity checks). If so, that one was actually the directory + name, and the current one is the real file name. + Patch things up. */ + if (previous_stab_code == (unsigned char) N_SO) + { + patch_subfile_names (current_subfile, name); + break; /* Ignore repeated SOs */ + } + end_symtab (valu, 0, 0, objfile, SECT_OFF_TEXT); + end_stabs (); + } + start_stabs (); + start_symtab (name, NULL, valu); + break; + + + case N_SOL: + /* This type of symbol indicates the start of data for + a sub-source-file, one whose contents were copied or + included in the compilation of the main source file + (whose name was given in the N_SO symbol.) */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + start_subfile (name, current_subfile->dirname); + break; + + case N_BINCL: + push_subfile (); + add_new_header_file (name, valu); + start_subfile (name, current_subfile->dirname); + break; + + case N_EINCL: + start_subfile (pop_subfile (), current_subfile->dirname); + break; + + case N_EXCL: + add_old_header_file (name, valu); + break; + + case N_SLINE: + /* This type of "symbol" really just records + one line-number -- core-address correspondence. + Enter it in the line list for this symbol table. */ + /* Relocate for dynamic loading and for ELF acc fn-relative syms. */ + valu += function_start_offset; +#ifdef SUN_FIXED_LBRAC_BUG + last_pc_address = valu; /* Save for SunOS bug circumcision */ +#endif + record_line (current_subfile, desc, valu); + break; + + case N_BCOMM: + common_block_start (name, objfile); + break; + + case N_ECOMM: + common_block_end (objfile); + break; + + /* The following symbol types need to have the appropriate offset added + to their value; then we process symbol definitions in the name. */ + + case N_STSYM: /* Static symbol in data seg */ + case N_LCSYM: /* Static symbol in BSS seg */ + case N_ROSYM: /* Static symbol in Read-only data seg */ + /* HORRID HACK DEPT. However, it's Sun's furgin' fault. + Solaris2's stabs-in-elf makes *most* symbols relative + but leaves a few absolute (at least for Solaris 2.1 and version + 2.0.1 of the SunPRO compiler). N_STSYM and friends sit on the fence. + .stab "foo:S...",N_STSYM is absolute (ld relocates it) + .stab "foo:V...",N_STSYM is relative (section base subtracted). + This leaves us no choice but to search for the 'S' or 'V'... + (or pass the whole section_offsets stuff down ONE MORE function + call level, which we really don't want to do). */ + { + char *p; + p = strchr (name, ':'); + if (p != 0 && p[1] == 'S') + { + /* The linker relocated it. There used to be a kludge here + to add the text offset, but that will break if we ever + start using the text offset (currently it is always zero). */ + goto define_a_symbol; + } + /* Since it's not the kludge case, re-dispatch to the right handler. */ + switch (type) { + case N_STSYM: goto case_N_STSYM; + case N_LCSYM: goto case_N_LCSYM; + case N_ROSYM: goto case_N_ROSYM; + default: abort(); + } + } + + case_N_STSYM: /* Static symbol in data seg */ + case N_DSLINE: /* Source line number, data seg */ + valu += ANOFFSET (section_offsets, SECT_OFF_DATA); + goto define_a_symbol; + + case_N_LCSYM: /* Static symbol in BSS seg */ + case N_BSLINE: /* Source line number, bss seg */ + /* N_BROWS: overlaps with N_BSLINE */ + valu += ANOFFSET (section_offsets, SECT_OFF_BSS); + goto define_a_symbol; + + case_N_ROSYM: /* Static symbol in Read-only data seg */ + valu += ANOFFSET (section_offsets, SECT_OFF_RODATA); + goto define_a_symbol; + + case N_ENTRY: /* Alternate entry point */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto define_a_symbol; + + /* The following symbol types we don't know how to process. Handle + them in a "default" way, but complain to people who care. */ + default: + case N_CATCH: /* Exception handler catcher */ + case N_EHDECL: /* Exception handler name */ + case N_PC: /* Global symbol in Pascal */ + case N_M2C: /* Modula-2 compilation unit */ + /* N_MOD2: overlaps with N_EHDECL */ + case N_SCOPE: /* Modula-2 scope information */ + case N_ECOML: /* End common (local name) */ + case N_NBTEXT: /* Gould Non-Base-Register symbols??? */ + case N_NBDATA: + case N_NBBSS: + case N_NBSTS: + case N_NBLCS: + complain (&unknown_symtype_complaint, + local_hex_string((unsigned long) type)); + /* FALLTHROUGH */ + + /* The following symbol types don't need the address field relocated, + since it is either unused, or is absolute. */ + define_a_symbol: + case N_GSYM: /* Global variable */ + case N_NSYMS: /* Number of symbols (ultrix) */ + case N_NOMAP: /* No map? (ultrix) */ + case N_RSYM: /* Register variable */ + case N_DEFD: /* Modula-2 GNU module dependency */ + case N_SSYM: /* Struct or union element */ + case N_LSYM: /* Local symbol in stack */ + case N_PSYM: /* Parameter variable */ + case N_LENG: /* Length of preceding symbol type */ + if (name) + { + int deftype; + char *colon_pos = strchr (name, ':'); + if (colon_pos == NULL) + deftype = '\0'; + else + deftype = colon_pos[1]; + + switch (deftype) + { + case 'f': + case 'F': + function_stab_type = type; + +#ifdef SUN_FIXED_LBRAC_BUG + /* The Sun acc compiler, under SunOS4, puts out + functions with N_GSYM or N_STSYM. The problem is + that the address of the symbol is no good (for N_GSYM + it doesn't even attept an address; for N_STSYM it + puts out an address but then it gets relocated + relative to the data segment, not the text segment). + Currently we can't fix this up later as we do for + some types of symbol in scan_file_globals. + Fortunately we do have a way of finding the address - + we know that the value in last_pc_address is either + the one we want (if we're dealing with the first + function in an object file), or somewhere in the + previous function. This means that we can use the + minimal symbol table to get the address. */ + + /* On solaris up to 2.2, the N_FUN stab gets relocated. + On Solaris 2.3, ld no longer relocates stabs (which + is good), and the N_FUN's value is now always zero. + The following code can't deal with this, because + last_pc_address depends on getting the address from a + N_SLINE or some such and in Solaris those are function + relative. Best fix is probably to create a Ttext.text symbol + and handle this like Ddata.data and so on. */ + + if (type == N_GSYM || type == N_STSYM) + { + struct minimal_symbol *m; + int l = colon_pos - name; + + m = lookup_minimal_symbol_by_pc (last_pc_address); + if (m && STREQN (SYMBOL_NAME (m), name, l)) + /* last_pc_address was in this function */ + valu = SYMBOL_VALUE (m); + else if (m && STREQN (SYMBOL_NAME (m+1), name, l)) + /* last_pc_address was in last function */ + valu = SYMBOL_VALUE (m+1); + else + /* Not found - use last_pc_address (for finish_block) */ + valu = last_pc_address; + } + + last_pc_address = valu; /* Save for SunOS bug circumcision */ +#endif + + if (block_address_function_relative) + /* For Solaris 2.0 compilers, the block addresses and + N_SLINE's are relative to the start of the + function. On normal systems, and when using gcc on + Solaris 2.0, these addresses are just absolute, or + relative to the N_SO, depending on + BLOCK_ADDRESS_ABSOLUTE. */ + function_start_offset = valu; + + within_function = 1; + if (context_stack_depth > 0) + { + new = pop_context (); + /* Make a block for the local symbols within. */ + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, valu, objfile); + } + /* Stack must be empty now. */ + if (context_stack_depth != 0) + complain (&lbrac_unmatched_complaint, symnum); + + new = push_context (0, valu); + new->name = define_symbol (valu, name, desc, type, objfile); + break; + + default: + define_symbol (valu, name, desc, type, objfile); + break; + } + } + break; + + /* We use N_OPT to carry the gcc2_compiled flag. Sun uses it + for a bunch of other flags, too. Someday we may parse their + flags; for now we ignore theirs and hope they'll ignore ours. */ + case N_OPT: /* Solaris 2: Compiler options */ + if (name) + { + if (STREQ (name, GCC2_COMPILED_FLAG_SYMBOL)) + { + processing_gcc_compilation = 2; +#if 1 /* Works, but is experimental. -fnf */ + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } +#endif + } + else + n_opt_found = 1; + } + break; + + /* The following symbol types can be ignored. */ + case N_OBJ: /* Solaris 2: Object file dir and name */ + /* N_UNDF: Solaris 2: file separator mark */ + /* N_UNDF: -- we will never encounter it, since we only process one + file's symbols at once. */ + case N_ENDM: /* Solaris 2: End of module */ + case N_MAIN: /* Name of main routine. */ + break; + } + + previous_stab_code = type; +} + +/* FIXME: The only difference between this and elfstab_build_psymtabs is + the call to install_minimal_symbols for elf. If the differences are + really that small, the code should be shared. */ + +/* Scan and build partial symbols for an coff symbol file. + The coff file has already been processed to get its minimal symbols. + + This routine is the equivalent of dbx_symfile_init and dbx_symfile_read + rolled into one. + + OBJFILE is the object file we are reading symbols from. + ADDR is the address relative to which the symbols are (e.g. + the base address of the text segment). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + STABOFFSET and STABSIZE define the location in OBJFILE where the .stab + section exists. + STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the + .stabstr section exists. + + This routine is mostly copied from dbx_symfile_init and dbx_symfile_read, + adjusted for coff details. */ + +void +coffstab_build_psymtabs (objfile, section_offsets, mainline, + staboffset, stabsize, + stabstroffset, stabstrsize) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + file_ptr staboffset; + unsigned int stabsize; + file_ptr stabstroffset; + unsigned int stabstrsize; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + struct dbx_symfile_info *info; + + /* There is already a dbx_symfile_info allocated by our caller. + It might even contain some info from the coff symtab to help us. */ + info = (struct dbx_symfile_info *) objfile->sym_stab_info; + + DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); + if (!DBX_TEXT_SECT (objfile)) + error ("Can't find .text section in symbol file"); + +#define COFF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */ + DBX_SYMBOL_SIZE (objfile) = COFF_STABS_SYMBOL_SIZE; + DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile); + DBX_STRINGTAB_SIZE (objfile) = stabstrsize; + DBX_SYMTAB_OFFSET (objfile) = staboffset; + + if (stabstrsize > bfd_get_size (sym_bfd)) + error ("ridiculous string table size: %d bytes", stabstrsize); + DBX_STRINGTAB (objfile) = (char *) + obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1); + + /* Now read in the string table in one big gulp. */ + + val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd); + if (val != stabstrsize) + perror_with_name (name); + + stabsread_new_init (); + buildsym_new_init (); + free_header_files (); + init_header_files (); + + processing_acc_compilation = 1; + + /* In a coff file, we've already installed the minimal symbols that came + from the coff (non-stab) symbol table, so always act like an + incremental load here. */ + dbx_symfile_read (objfile, section_offsets, 0); +} + +/* Scan and build partial symbols for an ELF symbol file. + This ELF file has already been processed to get its minimal symbols, + and any DWARF symbols that were in it. + + This routine is the equivalent of dbx_symfile_init and dbx_symfile_read + rolled into one. + + OBJFILE is the object file we are reading symbols from. + ADDR is the address relative to which the symbols are (e.g. + the base address of the text segment). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + STABOFFSET and STABSIZE define the location in OBJFILE where the .stab + section exists. + STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the + .stabstr section exists. + + This routine is mostly copied from dbx_symfile_init and dbx_symfile_read, + adjusted for elf details. */ + +void +elfstab_build_psymtabs (objfile, section_offsets, mainline, + staboffset, stabsize, + stabstroffset, stabstrsize) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + file_ptr staboffset; + unsigned int stabsize; + file_ptr stabstroffset; + unsigned int stabstrsize; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + struct dbx_symfile_info *info; + + /* There is already a dbx_symfile_info allocated by our caller. + It might even contain some info from the ELF symtab to help us. */ + info = (struct dbx_symfile_info *) objfile->sym_stab_info; + + DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); + if (!DBX_TEXT_SECT (objfile)) + error ("Can't find .text section in symbol file"); + +#define ELF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */ + DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE; + DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile); + DBX_STRINGTAB_SIZE (objfile) = stabstrsize; + DBX_SYMTAB_OFFSET (objfile) = staboffset; + + if (stabstrsize > bfd_get_size (sym_bfd)) + error ("ridiculous string table size: %d bytes", stabstrsize); + DBX_STRINGTAB (objfile) = (char *) + obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1); + + /* Now read in the string table in one big gulp. */ + + val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd); + if (val != stabstrsize) + perror_with_name (name); + + stabsread_new_init (); + buildsym_new_init (); + free_header_files (); + init_header_files (); + install_minimal_symbols (objfile); + + processing_acc_compilation = 1; + + /* In an elf file, we've already installed the minimal symbols that came + from the elf (non-stab) symbol table, so always act like an + incremental load here. */ + dbx_symfile_read (objfile, section_offsets, 0); +} + +/* Scan and build partial symbols for a PA symbol file. + This PA file has already been processed to get its minimal symbols. + + OBJFILE is the object file we are reading symbols from. + ADDR is the address relative to which the symbols are (e.g. + the base address of the text segment). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + + */ + +void +pastab_build_psymtabs (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + free_header_files (); + init_header_files (); + + /* In a PA file, we've already installed the minimal symbols that came + from the PA (non-stab) symbol table, so always act like an + incremental load here. */ + + dbx_symfile_read (objfile, section_offsets, mainline); +} + +/* Parse the user's idea of an offset for dynamic linking, into our idea + of how to represent it for fast symbol reading. */ + +static struct section_offsets * +dbx_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* Register our willingness to decode symbols for SunOS and a.out and + NetBSD and b.out files handled by BFD... */ +static struct sym_fns sunos_sym_fns = +{ + "sunOs", /* sym_name: name or name prefix of BFD target type */ + 6, /* sym_namelen: number of significant sym_name chars */ + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +static struct sym_fns aout_sym_fns = +{ + "a.out", /* sym_name: name or name prefix of BFD target type */ + 5, /* sym_namelen: number of significant sym_name chars */ + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +static struct sym_fns bout_sym_fns = +{ + "b.out", /* sym_name: name or name prefix of BFD target type */ + 5, /* sym_namelen: number of significant sym_name chars */ + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_dbxread () +{ + add_symtab_fns(&sunos_sym_fns); + add_symtab_fns(&aout_sym_fns); + add_symtab_fns(&bout_sym_fns); +} diff --git a/gnu/usr.bin/gdb/gdb/dcache.c b/gnu/usr.bin/gdb/gdb/dcache.c new file mode 100644 index 00000000000..aaa01d0fe22 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/dcache.c @@ -0,0 +1,236 @@ +/* Caching code. Typically used by remote back ends for + caching remote memory. + + Copyright 1992, 1993 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. */ + +#include "defs.h" +#include "dcache.h" +#include "gdbcmd.h" + +extern int insque(); +extern int remque(); + +int remote_dcache = 0; + +/* The data cache records all the data read from the remote machine + since the last time it stopped. + + Each cache block holds LINE_SIZE bytes of data + starting at a multiple-of-LINE_SIZE address. */ + +#define LINE_SIZE_MASK ((LINE_SIZE - 1)) /* eg 7*2+1= 111*/ +#define XFORM(x) (((x) & LINE_SIZE_MASK) >> 2) + +/* Free all the data cache blocks, thus discarding all cached data. */ +void +dcache_flush (dcache) + DCACHE *dcache; +{ + register struct dcache_block *db; + + if (remote_dcache > 0) + while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid) + { + remque (db); + insque (db, &dcache->dcache_free); + } + + return; +} + +/* + * If addr is present in the dcache, return the address of the block + * containing it. + */ +static +struct dcache_block * +dcache_hit (dcache, addr) + DCACHE *dcache; + unsigned int addr; +{ + register struct dcache_block *db; + + if (addr & 3 + || remote_dcache == 0) + abort (); + + /* Search all cache blocks for one that is at this address. */ + db = dcache->dcache_valid.next; + while (db != &dcache->dcache_valid) + { + if ((addr & ~LINE_SIZE_MASK) == db->addr) + return db; + db = db->next; + } + + return NULL; +} + +/* Return the int data at address ADDR in dcache block DC. */ +static +int +dcache_value (db, addr) + struct dcache_block *db; + unsigned int addr; +{ + if (addr & 3 + || remote_dcache == 0) + abort (); + return (db->data[XFORM (addr)]); +} + +/* Get a free cache block, put or keep it on the valid list, + and return its address. The caller should store into the block + the address and data that it describes, then remque it from the + free list and insert it into the valid list. This procedure + prevents errors from creeping in if a memory retrieval is + interrupted (which used to put garbage blocks in the valid + list...). */ +static +struct dcache_block * +dcache_alloc (dcache) + DCACHE *dcache; +{ + register struct dcache_block *db; + + if (remote_dcache == 0) + abort(); + + if ((db = dcache->dcache_free.next) == &dcache->dcache_free) + { + /* If we can't get one from the free list, take last valid and put + it on the free list. */ + db = dcache->dcache_valid.last; + remque (db); + insque (db, &dcache->dcache_free); + } + + remque (db); + insque (db, &dcache->dcache_valid); + return (db); +} + +/* Using the data cache DCACHE return the contents of the word at + address ADDR in the remote machine. */ +int +dcache_fetch (dcache, addr) + DCACHE *dcache; + CORE_ADDR addr; +{ + register struct dcache_block *db; + + if (remote_dcache == 0) + { + int i; + + (*dcache->read_memory) (addr, (unsigned char *) &i, 4); + return(i); + } + + db = dcache_hit (dcache, addr); + if (db == 0) + { + db = dcache_alloc (dcache); + immediate_quit++; + (*dcache->read_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE); + immediate_quit--; + db->addr = addr & ~LINE_SIZE_MASK; + remque (db); /* Off the free list */ + insque (db, &dcache->dcache_valid); /* On the valid list */ + } + return (dcache_value (db, addr)); +} + +/* Write the word at ADDR both in the data cache and in the remote machine. */ +void +dcache_poke (dcache, addr, data) + DCACHE *dcache; + CORE_ADDR addr; + int data; +{ + register struct dcache_block *db; + + if (remote_dcache == 0) + { + (*dcache->write_memory) (addr, (unsigned char *) &data, 4); + return; + } + + /* First make sure the word is IN the cache. DB is its cache block. */ + db = dcache_hit (dcache, addr); + if (db == 0) + { + db = dcache_alloc (dcache); + immediate_quit++; + (*dcache->write_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE); + immediate_quit--; + db->addr = addr & ~LINE_SIZE_MASK; + remque (db); /* Off the free list */ + insque (db, &dcache->dcache_valid); /* On the valid list */ + } + + /* Modify the word in the cache. */ + db->data[XFORM (addr)] = data; + + /* Send the changed word. */ + immediate_quit++; + (*dcache->write_memory) (addr, (unsigned char *) &data, 4); + immediate_quit--; +} + +/* Initialize the data cache. */ +DCACHE * +dcache_init (reading, writing) + memxferfunc reading; + memxferfunc writing; +{ + register i; + register struct dcache_block *db; + DCACHE *dcache; + + dcache = (DCACHE *) xmalloc (sizeof (*dcache)); + dcache->read_memory = reading; + dcache->write_memory = writing; + dcache->the_cache = (struct dcache_block *) + xmalloc (sizeof (*dcache->the_cache) * DCACHE_SIZE); + + dcache->dcache_free.next = dcache->dcache_free.last = &dcache->dcache_free; + dcache->dcache_valid.next = dcache->dcache_valid.last = &dcache->dcache_valid; + for (db = dcache->the_cache, i = 0; i < DCACHE_SIZE; i++, db++) + insque (db, &dcache->dcache_free); + + return(dcache); +} + +void +_initialitize_dcache () +{ + add_show_from_set + (add_set_cmd ("remotecache", class_support, var_boolean, + (char *) &remote_dcache, + "\ +Set cache use for remote targets.\n\ +When on, use data caching for remote targets. For many remote targets\n\ +this option can offer better throughput for reading target memory.\n\ +Unfortunately, gdb does not currently know anything about volatile\n\ +registers and thus data caching will produce incorrect results with\n\ +volatile registers are in use. By default, this option is off.", + &setlist), + &showlist); +} diff --git a/gnu/usr.bin/gdb/gdb/dcache.h b/gnu/usr.bin/gdb/gdb/dcache.h new file mode 100644 index 00000000000..bfc0dd7a1e3 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/dcache.h @@ -0,0 +1,83 @@ +/* Declarations for caching. Typically used by remote back ends for + caching remote memory. + + Copyright 1992, 1993 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. */ + +#ifndef DCACHE_H +#define DCACHE_H + +/* The data cache leads to incorrect results because it doesn't know about + volatile variables, thus making it impossible to debug functions which + use hardware registers. Therefore it is #if 0'd out. Effect on + performance is some, for backtraces of functions with a few + arguments each. For functions with many arguments, the stack + frames don't fit in the cache blocks, which makes the cache less + helpful. Disabling the cache is a big performance win for fetching + large structures, because the cache code fetched data in 16-byte + chunks. */ + +#define LINE_SIZE_POWER (4) +/* eg 1<<3 == 8 */ +#define LINE_SIZE (1 << LINE_SIZE_POWER) +/* Number of cache blocks */ +#define DCACHE_SIZE (64) + +struct dcache_block +{ + struct dcache_block *next, *last; + unsigned int addr; /* Address for which data is recorded. */ + int data[LINE_SIZE / sizeof (int)]; +}; + +typedef int (*memxferfunc) PARAMS((CORE_ADDR memaddr, + unsigned char *myaddr, + int len)); + +typedef struct { + /* Function to actually read the target memory. */ + memxferfunc read_memory; + + /* Function to actually write the target memory */ + memxferfunc write_memory; + + /* free list */ + struct dcache_block dcache_free; + + /* in use list */ + struct dcache_block dcache_valid; + + /* The cache itself. */ + struct dcache_block *the_cache; + +} DCACHE; + +/* Using the data cache DCACHE return the contents of the word at + address ADDR in the remote machine. */ +int dcache_fetch PARAMS((DCACHE *dcache, CORE_ADDR addr)); + +/* Flush DCACHE. */ +void dcache_flush PARAMS((DCACHE *dcache)); + +/* Initialize DCACHE. */ +DCACHE *dcache_init PARAMS((memxferfunc reading, memxferfunc writing)); + +/* Write the word at ADDR both in the data cache and in the remote machine. */ +void dcache_poke PARAMS((DCACHE *dcache, CORE_ADDR addr, int data)); + +#endif /* DCACHE_H */ diff --git a/gnu/usr.bin/gdb/gdb/defs.h b/gnu/usr.bin/gdb/gdb/defs.h new file mode 100644 index 00000000000..f65d56ac587 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/defs.h @@ -0,0 +1,901 @@ +/* Basic, host-specific, and target-specific definitions for GDB. + Copyright (C) 1986, 1989, 1991 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. */ + +#if !defined (DEFS_H) +#define DEFS_H 1 + +#include + +/* First include ansidecl.h so we can use the various macro definitions + here and in all subsequent file inclusions. */ + +#include "ansidecl.h" + +/* An address in the program being debugged. Host byte order. */ +#ifndef CORE_ADDR_TYPE +typedef unsigned int CORE_ADDR; +#else +typedef CORE_ADDR_TYPE CORE_ADDR; +#endif + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +/* Gdb does *lots* of string compares. Use macros to speed them up by + avoiding function calls if the first characters are not the same. */ + +#define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b)) +#define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0) +#define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0) + +/* The character GNU C++ uses to build identifiers that must be unique from + the program's identifiers (such as $this and $$vptr). */ +#define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */ + +#include /* System call error return status */ + +extern int quit_flag; +extern int immediate_quit; +extern int sevenbit_strings; + +extern void +quit PARAMS ((void)); + +#define QUIT { if (quit_flag) quit (); } + +/* Command classes are top-level categories into which commands are broken + down for "help" purposes. + Notes on classes: class_alias is for alias commands which are not + abbreviations of the original command. class-pseudo is for commands + which are not really commands nor help topics ("stop"). */ + +enum command_class +{ + /* Special args to help_list */ + all_classes = -2, all_commands = -1, + /* Classes of commands */ + no_class = -1, class_run = 0, class_vars, class_stack, + class_files, class_support, class_info, class_breakpoint, + class_alias, class_obscure, class_user, class_maintenance, + class_pseudo +}; + +/* Languages represented in the symbol table and elsewhere. + This should probably be in language.h, but since enum's can't + be forward declared to satisfy opaque references before their + actual definition, needs to be here. */ + +enum language +{ + language_unknown, /* Language not known */ + language_auto, /* Placeholder for automatic setting */ + language_c, /* C */ + language_cplus, /* C++ */ + language_chill, /* Chill */ + language_m2 /* Modula-2 */ +}; + +/* the cleanup list records things that have to be undone + if an error happens (descriptors to be closed, memory to be freed, etc.) + Each link in the chain records a function to call and an + argument to give it. + + Use make_cleanup to add an element to the cleanup chain. + Use do_cleanups to do all cleanup actions back to a given + point in the chain. Use discard_cleanups to remove cleanups + from the chain back to a given point, not doing them. */ + +struct cleanup +{ + struct cleanup *next; + void (*function) PARAMS ((PTR)); + PTR arg; +}; + +/* From blockframe.c */ + +extern int +inside_entry_func PARAMS ((CORE_ADDR)); + +extern int +inside_entry_file PARAMS ((CORE_ADDR addr)); + +extern int +inside_main_func PARAMS ((CORE_ADDR pc)); + +/* From ch-lang.c, for the moment. (FIXME) */ + +extern char * +chill_demangle PARAMS ((const char *)); + +/* From libiberty.a */ + +extern char * +cplus_demangle PARAMS ((const char *, int)); + +extern char * +cplus_mangle_opname PARAMS ((char *, int)); + +/* From libmmalloc.a (memory mapped malloc library) */ + +extern PTR +mmalloc_attach PARAMS ((int, PTR)); + +extern PTR +mmalloc_detach PARAMS ((PTR)); + +extern PTR +mmalloc PARAMS ((PTR, long)); + +extern PTR +mrealloc PARAMS ((PTR, PTR, long)); + +extern void +mfree PARAMS ((PTR, PTR)); + +extern int +mmalloc_setkey PARAMS ((PTR, int, PTR)); + +extern PTR +mmalloc_getkey PARAMS ((PTR, int)); + +/* From utils.c */ + +extern int +strcmp_iw PARAMS ((const char *, const char *)); + +extern char * +safe_strerror PARAMS ((int)); + +extern char * +safe_strsignal PARAMS ((int)); + +extern void +init_malloc PARAMS ((void *)); + +extern void +request_quit PARAMS ((int)); + +extern void +do_cleanups PARAMS ((struct cleanup *)); + +extern void +discard_cleanups PARAMS ((struct cleanup *)); + +/* The bare make_cleanup function is one of those rare beasts that + takes almost any type of function as the first arg and anything that + will fit in a "void *" as the second arg. + + Should be, once all calls and called-functions are cleaned up: +extern struct cleanup * +make_cleanup PARAMS ((void (*function) (void *), void *)); + + Until then, lint and/or various type-checking compiler options will + complain about make_cleanup calls. It'd be wrong to just cast things, + since the type actually passed when the function is called would be + wrong. */ + +extern struct cleanup * +make_cleanup (); + +extern struct cleanup * +save_cleanups PARAMS ((void)); + +extern void +restore_cleanups PARAMS ((struct cleanup *)); + +extern void +free_current_contents PARAMS ((char **)); + +extern void +null_cleanup PARAMS ((char **)); + +extern int +myread PARAMS ((int, char *, int)); + +extern int +query (); + +extern void +begin_line PARAMS ((void)); + +extern void +wrap_here PARAMS ((char *)); + +extern void +reinitialize_more_filter PARAMS ((void)); + +extern int +print_insn PARAMS ((CORE_ADDR, FILE *)); + +extern void +fputs_filtered PARAMS ((const char *, FILE *)); + +extern void +puts_filtered PARAMS ((char *)); + +extern void +vprintf_filtered (); + +extern void +vfprintf_filtered (); + +extern void +fprintf_filtered (); + +extern void +fprintfi_filtered (); + +extern void +printf_filtered (); + +extern void +printfi_filtered (); + +extern void +print_spaces PARAMS ((int, FILE *)); + +extern void +print_spaces_filtered PARAMS ((int, FILE *)); + +extern char * +n_spaces PARAMS ((int)); + +extern void +gdb_printchar PARAMS ((int, FILE *, int)); + +extern void +fprintf_symbol_filtered PARAMS ((FILE *, char *, enum language, int)); + +extern void +perror_with_name PARAMS ((char *)); + +extern void +print_sys_errmsg PARAMS ((char *, int)); + +/* From regex.c or libc. BSD 4.4 declares this with the argument type as + "const char *" in unistd.h, so we can't declare the argument + as "char *". */ + +extern char * +re_comp PARAMS ((const char *)); + +/* From symfile.c */ + +extern void +symbol_file_command PARAMS ((char *, int)); + +/* From main.c */ + +extern char * +skip_quoted PARAMS ((char *)); + +extern char * +gdb_readline PARAMS ((char *)); + +extern char * +command_line_input PARAMS ((char *, int)); + +extern void +print_prompt PARAMS ((void)); + +extern int +batch_mode PARAMS ((void)); + +extern int +input_from_terminal_p PARAMS ((void)); + +/* From printcmd.c */ + +extern void +set_next_address PARAMS ((CORE_ADDR)); + +extern void +print_address_symbolic PARAMS ((CORE_ADDR, FILE *, int, char *)); + +extern void +print_address PARAMS ((CORE_ADDR, FILE *)); + +/* From source.c */ + +extern int +openp PARAMS ((char *, int, char *, int, int, char **)); + +extern void +mod_path PARAMS ((char *, char **)); + +extern void +directory_command PARAMS ((char *, int)); + +extern void +init_source_path PARAMS ((void)); + +/* From findvar.c */ + +extern int +read_relative_register_raw_bytes PARAMS ((int, char *)); + +/* From readline (but not in any readline .h files). */ + +extern char * +tilde_expand PARAMS ((char *)); + +/* Structure for saved commands lines + (for breakpoints, defined commands, etc). */ + +struct command_line +{ + struct command_line *next; + char *line; +}; + +extern struct command_line * +read_command_lines PARAMS ((void)); + +extern void +free_command_lines PARAMS ((struct command_line **)); + +/* String containing the current directory (what getwd would return). */ + +extern char *current_directory; + +/* Default radixes for input and output. Only some values supported. */ +extern unsigned input_radix; +extern unsigned output_radix; + +/* Possibilities for prettyprint parameters to routines which print + things. Like enum language, this should be in value.h, but needs + to be here for the same reason. FIXME: If we can eliminate this + as an arg to LA_VAL_PRINT, then we can probably move it back to + value.h. */ + +enum val_prettyprint +{ + Val_no_prettyprint = 0, + Val_prettyprint, + /* Use the default setting which the user has specified. */ + Val_pretty_default +}; + + +/* Host machine definition. This will be a symlink to one of the + xm-*.h files, built by the `configure' script. */ + +#include "xm.h" + +/* Native machine support. This will be a symlink to one of the + nm-*.h files, built by the `configure' script. */ + +#include "nm.h" + +/* If the xm.h file did not define the mode string used to open the + files, assume that binary files are opened the same way as text + files */ +#ifndef FOPEN_RB +#include "fopen-same.h" +#endif + +/* + * Allow things in gdb to be declared "const". If compiling ANSI, it + * just works. If compiling with gcc but non-ansi, redefine to __const__. + * If non-ansi, non-gcc, then eliminate "const" entirely, making those + * objects be read-write rather than read-only. + */ + +#ifndef const +#ifndef __STDC__ +# ifdef __GNUC__ +# define const __const__ +# else +# define const /*nothing*/ +# endif /* GNUC */ +#endif /* STDC */ +#endif /* const */ + +#ifndef volatile +#ifndef __STDC__ +# ifdef __GNUC__ +# define volatile __volatile__ +# else +# define volatile /*nothing*/ +# endif /* GNUC */ +#endif /* STDC */ +#endif /* volatile */ + +#if 1 +#define NORETURN /*nothing*/ +#else /* not 1 */ +/* FIXME: This is bogus. Having "volatile void" mean a function doesn't + return is a gcc extension and should be based on #ifdef __GNUC__. + Also, as of Sep 93 I'm told gcc is changing the syntax for ansi + reasons (so declaring exit here as "volatile void" and as "void" in + a system header loses). Using the new "__attributes__ ((noreturn));" + syntax would lose for old versions of gcc; using + typedef void exit_fn_type PARAMS ((int)); + volatile exit_fn_type exit; + would win. */ +/* Some compilers (many AT&T SVR4 compilers for instance), do not accept + declarations of functions that never return (exit for instance) as + "volatile void". For such compilers "NORETURN" can be defined away + to keep them happy */ + +#ifndef NORETURN +# ifdef __lucid +# define NORETURN /*nothing*/ +# else +# define NORETURN volatile +# endif +#endif +#endif /* not 1 */ + +/* Defaults for system-wide constants (if not defined by xm.h, we fake it). */ + +#if !defined (UINT_MAX) +#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */ +#endif + +#if !defined (INT_MAX) +#define INT_MAX ((int)(UINT_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ +#endif + +#if !defined (INT_MIN) +#define INT_MIN (-INT_MAX - 1) /* 0x80000000 for 32-bits */ +#endif + +#if !defined (ULONG_MAX) +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */ +#endif + +#if !defined (LONG_MAX) +#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ +#endif + +/* Number of bits in a char or unsigned char for the target machine. + Just like CHAR_BIT in but describes the target machine. */ +#if !defined (TARGET_CHAR_BIT) +#define TARGET_CHAR_BIT 8 +#endif + +/* Number of bits in a short or unsigned short for the target machine. */ +#if !defined (TARGET_SHORT_BIT) +#define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in an int or unsigned int for the target machine. */ +#if !defined (TARGET_INT_BIT) +#define TARGET_INT_BIT (4 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a long or unsigned long for the target machine. */ +#if !defined (TARGET_LONG_BIT) +#define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a long long or unsigned long long for the target machine. */ +#if !defined (TARGET_LONG_LONG_BIT) +#define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT) +#endif + +/* Number of bits in a float for the target machine. */ +#if !defined (TARGET_FLOAT_BIT) +#define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a double for the target machine. */ +#if !defined (TARGET_DOUBLE_BIT) +#define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a long double for the target machine. */ +#if !defined (TARGET_LONG_DOUBLE_BIT) +#define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT) +#endif + +/* Number of bits in a "complex" for the target machine. */ +#if !defined (TARGET_COMPLEX_BIT) +#define TARGET_COMPLEX_BIT (2 * TARGET_FLOAT_BIT) +#endif + +/* Number of bits in a "double complex" for the target machine. */ +#if !defined (TARGET_DOUBLE_COMPLEX_BIT) +#define TARGET_DOUBLE_COMPLEX_BIT (2 * TARGET_DOUBLE_BIT) +#endif + +/* Number of bits in a pointer for the target machine */ +#if !defined (TARGET_PTR_BIT) +#define TARGET_PTR_BIT TARGET_INT_BIT +#endif + +/* Default to support for "long long" if the host compiler being used is gcc. + Config files must define CC_HAS_LONG_LONG to use other host compilers + that are capable of supporting "long long", and to cause gdb to use that + support. Not defining CC_HAS_LONG_LONG will suppress use of "long long" + regardless of what compiler is used. + + FIXME: For now, automatic selection of "long long" as the default when + gcc is used is disabled, pending further testing. Concerns include the + impact on gdb performance and the universality of bugfree long long + support on platforms that do have gcc. Compiling with FORCE_LONG_LONG + will select "long long" use for testing purposes. -fnf */ + +#ifndef CC_HAS_LONG_LONG +# if defined (__GNUC__) && defined (FORCE_LONG_LONG) /* See FIXME above */ +# define CC_HAS_LONG_LONG 1 +# endif +#endif + +/* LONGEST should not be a typedef, because "unsigned LONGEST" needs to work. + CC_HAS_LONG_LONG is defined if the host compiler supports "long long" + variables and we wish to make use of that support. */ + +#ifndef LONGEST +# ifdef CC_HAS_LONG_LONG +# define LONGEST long long +# else +# define LONGEST long +# endif +#endif + +/* Convert a LONGEST to an int. This is used in contexts (e.g. number of + arguments to a function, number in a value history, register number, etc.) + where the value must not be larger than can fit in an int. */ + +#ifndef longest_to_int +# ifdef CC_HAS_LONG_LONG +# define longest_to_int(x) (((x) > INT_MAX || (x) < INT_MIN) \ + ? (error ("Value out of range."),0) : (int) (x)) +# else + /* Assume sizeof (int) == sizeof (long). */ +# define longest_to_int(x) ((int) (x)) +# endif +#endif + +/* If we picked up a copy of CHAR_BIT from a configuration file + (which may get it by including ) then use it to set + the number of bits in a host char. If not, use the same size + as the target. */ + +#if defined (CHAR_BIT) +#define HOST_CHAR_BIT CHAR_BIT +#else +#define HOST_CHAR_BIT TARGET_CHAR_BIT +#endif + +/* Assorted functions we can declare, now that const and volatile are + defined. */ + +extern char * +savestring PARAMS ((const char *, int)); + +extern char * +msavestring PARAMS ((void *, const char *, int)); + +extern char * +strsave PARAMS ((const char *)); + +extern char * +mstrsave PARAMS ((void *, const char *)); + +extern char * +concat PARAMS ((char *, ...)); + +extern PTR +xmalloc PARAMS ((long)); + +extern PTR +xrealloc PARAMS ((PTR, long)); + +extern PTR +xmmalloc PARAMS ((PTR, long)); + +extern PTR +xmrealloc PARAMS ((PTR, PTR, long)); + +extern PTR +mmalloc PARAMS ((PTR, long)); + +extern PTR +mrealloc PARAMS ((PTR, PTR, long)); + +extern void +mfree PARAMS ((PTR, PTR)); + +extern int +mmcheck PARAMS ((PTR, void (*) (void))); + +extern int +mmtrace PARAMS ((void)); + +extern int +parse_escape PARAMS ((char **)); + +extern const char * const reg_names[]; + +extern NORETURN void /* Does not return to the caller. */ +error (); + +extern NORETURN void /* Does not return to the caller. */ +fatal (); + +extern NORETURN void /* Not specified as volatile in ... */ +exit PARAMS ((int)); /* 4.10.4.3 */ + +extern NORETURN void /* Does not return to the caller. */ +nomem PARAMS ((long)); + +/* Reasons for calling return_to_top_level. */ +enum return_reason { + /* User interrupt. */ + RETURN_QUIT, + + /* Any other error. */ + RETURN_ERROR +}; + +#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT) +#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR) +#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR) +typedef int return_mask; + +extern NORETURN void /* Does not return to the caller. */ +return_to_top_level PARAMS ((enum return_reason)); + +extern int catch_errors PARAMS ((int (*) (char *), void *, char *, + return_mask)); + +extern void +warning_setup PARAMS ((void)); + +extern void +warning (); + +/* Global functions from other, non-gdb GNU thingies (libiberty for + instance) */ + +extern char * +basename PARAMS ((char *)); + +extern char * +getenv PARAMS ((const char *)); + +extern char ** +buildargv PARAMS ((char *)); + +extern void +freeargv PARAMS ((char **)); + +extern char * +strerrno PARAMS ((int)); + +extern char * +strsigno PARAMS ((int)); + +extern int +errno_max PARAMS ((void)); + +extern int +signo_max PARAMS ((void)); + +extern int +strtoerrno PARAMS ((char *)); + +extern int +strtosigno PARAMS ((char *)); + +extern char * +strsignal PARAMS ((int)); + +/* From other system libraries */ + +#ifndef PSIGNAL_IN_SIGNAL_H +extern void +psignal PARAMS ((unsigned, const char *)); +#endif + +/* For now, we can't include because it conflicts with + "../include/getopt.h". (FIXME) + + However, if a function is defined in the ANSI C standard and a prototype + for that function is defined and visible in any header file in an ANSI + conforming environment, then that prototype must match the definition in + the ANSI standard. So we can just duplicate them here without conflict, + since they must be the same in all conforming ANSI environments. If + these cause problems, then the environment is not ANSI conformant. */ + +#ifdef __STDC__ +#include +#endif + +extern int +fclose PARAMS ((FILE *stream)); /* 4.9.5.1 */ + +extern void +perror PARAMS ((const char *)); /* 4.9.10.4 */ + +extern double +atof PARAMS ((const char *nptr)); /* 4.10.1.1 */ + +extern int +atoi PARAMS ((const char *)); /* 4.10.1.2 */ + +#ifndef MALLOC_INCOMPATIBLE + +extern PTR +malloc PARAMS ((size_t size)); /* 4.10.3.3 */ + +extern PTR +realloc PARAMS ((void *ptr, size_t size)); /* 4.10.3.4 */ + +extern void +free PARAMS ((void *)); /* 4.10.3.2 */ + +#endif /* MALLOC_INCOMPATIBLE */ + +extern void +qsort PARAMS ((void *base, size_t nmemb, /* 4.10.5.2 */ + size_t size, + int (*comp)(const void *, const void *))); + +#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */ +extern PTR +memcpy PARAMS ((void *, const void *, size_t)); /* 4.11.2.1 */ + +extern int +memcmp PARAMS ((const void *, const void *, size_t)); /* 4.11.4.1 */ +#endif + +extern char * +strchr PARAMS ((const char *, int)); /* 4.11.5.2 */ + +extern char * +strrchr PARAMS ((const char *, int)); /* 4.11.5.5 */ + +extern char * +strstr PARAMS ((const char *, const char *)); /* 4.11.5.7 */ + +extern char * +strtok PARAMS ((char *, const char *)); /* 4.11.5.8 */ + +#ifndef MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */ +extern PTR +memset PARAMS ((void *, int, size_t)); /* 4.11.6.1 */ +#endif + +extern char * +strerror PARAMS ((int)); /* 4.11.6.2 */ + +/* Various possibilities for alloca. */ +#ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else +# ifdef sparc +# include /* NOTE: Doesn't declare alloca() */ +# endif +# ifdef __STDC__ + extern void *alloca (size_t); +# else /* __STDC__ */ + extern char *alloca (); +# endif +# endif +#endif + +/* TARGET_BYTE_ORDER and HOST_BYTE_ORDER must be defined to one of these. */ + +#if !defined (BIG_ENDIAN) +#define BIG_ENDIAN 4321 +#endif + +#if !defined (LITTLE_ENDIAN) +#define LITTLE_ENDIAN 1234 +#endif + +/* Target-system-dependent parameters for GDB. */ + +/* Target machine definition. This will be a symlink to one of the + tm-*.h files, built by the `configure' script. */ + +#include "tm.h" + +/* The bit byte-order has to do just with numbering of bits in + debugging symbols and such. Conceptually, it's quite separate + from byte/word byte order. */ + +#if !defined (BITS_BIG_ENDIAN) +#if TARGET_BYTE_ORDER == BIG_ENDIAN +#define BITS_BIG_ENDIAN 1 +#endif /* Big endian. */ + +#if TARGET_BYTE_ORDER == LITTLE_ENDIAN +#define BITS_BIG_ENDIAN 0 +#endif /* Little endian. */ +#endif /* BITS_BIG_ENDIAN not defined. */ + +/* Swap LEN bytes at BUFFER between target and host byte-order. This is + the wrong way to do byte-swapping because it assumes that you have a way + to have a host variable of exactly the right size. + extract_* are the right way. */ +#if TARGET_BYTE_ORDER == HOST_BYTE_ORDER +#define SWAP_TARGET_AND_HOST(buffer,len) +#else /* Target and host byte order differ. */ +#define SWAP_TARGET_AND_HOST(buffer,len) \ + { \ + char tmp; \ + char *p = (char *)(buffer); \ + char *q = ((char *)(buffer)) + len - 1; \ + for (; p < q; p++, q--) \ + { \ + tmp = *q; \ + *q = *p; \ + *p = tmp; \ + } \ + } +#endif /* Target and host byte order differ. */ + +/* In findvar.c. */ +LONGEST extract_signed_integer PARAMS ((void *, int)); +unsigned LONGEST extract_unsigned_integer PARAMS ((void *, int)); +CORE_ADDR extract_address PARAMS ((void *, int)); + +void store_signed_integer PARAMS ((void *, int, LONGEST)); +void store_unsigned_integer PARAMS ((void *, int, unsigned LONGEST)); +void store_address PARAMS ((void *, int, CORE_ADDR)); + +/* On some machines there are bits in addresses which are not really + part of the address, but are used by the kernel, the hardware, etc. + for special purposes. ADDR_BITS_REMOVE takes out any such bits + so we get a "real" address such as one would find in a symbol + table. This is used only for addresses of instructions, and even then + I'm not sure it's used in all contexts. It exists to deal with there + being a few stray bits in the PC which would mislead us, not as some sort + of generic thing to handle alignment or segmentation (it's possible it + should be in TARGET_READ_PC instead). */ +#if !defined (ADDR_BITS_REMOVE) +#define ADDR_BITS_REMOVE(addr) (addr) +#endif /* No ADDR_BITS_REMOVE. */ + +/* From valops.c */ + +extern CORE_ADDR +push_bytes PARAMS ((CORE_ADDR, char *, int)); + +/* In some modules, we don't have a definition of REGISTER_TYPE yet, so we + must avoid prototyping this function for now. FIXME. Should be: +extern CORE_ADDR +push_word PARAMS ((CORE_ADDR, REGISTER_TYPE)); + */ +extern CORE_ADDR +push_word (); + +/* Some parts of gdb might be considered optional, in the sense that they + are not essential for being able to build a working, usable debugger + for a specific environment. For example, the maintenance commands + are there for the benefit of gdb maintainers. As another example, + some environments really don't need gdb's that are able to read N + different object file formats. In order to make it possible (but + not necessarily recommended) to build "stripped down" versions of + gdb, the following defines control selective compilation of those + parts of gdb which can be safely left out when necessary. Note that + the default is to include everything. */ + +#ifndef MAINTENANCE_CMDS +#define MAINTENANCE_CMDS 1 +#endif + +#endif /* !defined (DEFS_H) */ diff --git a/gnu/usr.bin/gdb/gdb/demangle.c b/gnu/usr.bin/gdb/gdb/demangle.c new file mode 100644 index 00000000000..a134bb70ad9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/demangle.c @@ -0,0 +1,190 @@ +/* Basic C++ demangling support for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. + +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. */ + + +/* This file contains support code for C++ demangling that is common + to a styles of demangling, and GDB specific. */ + +#include "defs.h" +#include "command.h" +#include "gdbcmd.h" +#include "demangle.h" +#include + +/* Select the default C++ demangling style to use. The default is "auto", + which allows gdb to attempt to pick an appropriate demangling style for + the executable it has loaded. It can be set to a specific style ("gnu", + "lucid", "arm", etc.) in which case gdb will never attempt to do auto + selection of the style unless you do an explicit "set demangle auto". + To select one of these as the default, set DEFAULT_DEMANGLING_STYLE in + the appropriate target configuration file. */ + +#ifndef DEFAULT_DEMANGLING_STYLE +# define DEFAULT_DEMANGLING_STYLE AUTO_DEMANGLING_STYLE_STRING +#endif + +/* String name for the current demangling style. Set by the "set demangling" + command, printed as part of the output by the "show demangling" command. */ + +static char *current_demangling_style_string; + +/* List of supported demangling styles. Contains the name of the style as + seen by the user, and the enum value that corresponds to that style. */ + +static const struct demangler +{ + char *demangling_style_name; + enum demangling_styles demangling_style; + char *demangling_style_doc; +} demanglers [] = +{ + {AUTO_DEMANGLING_STYLE_STRING, + auto_demangling, + "Automatic selection based on executable"}, + {GNU_DEMANGLING_STYLE_STRING, + gnu_demangling, + "GNU (g++) style demangling"}, + {LUCID_DEMANGLING_STYLE_STRING, + lucid_demangling, + "Lucid (lcc) style demangling"}, + {ARM_DEMANGLING_STYLE_STRING, + arm_demangling, + "ARM style demangling"}, + {NULL, unknown_demangling, NULL} +}; + +/* show current demangling style. */ + +static void +show_demangling_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + /* done automatically by show command. */ +} + + +/* set current demangling style. called by the "set demangling" command + after it has updated the current_demangling_style_string to match + what the user has entered. + + if the user has entered a string that matches a known demangling style + name in the demanglers[] array then just leave the string alone and update + the current_demangling_style enum value to match. + + if the user has entered a string that doesn't match, including an empty + string, then print a list of the currently known styles and restore + the current_demangling_style_string to match the current_demangling_style + enum value. + + Note: Assumes that current_demangling_style_string always points to + a malloc'd string, even if it is a null-string. */ + +static void +set_demangling_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + const struct demangler *dem; + + /* First just try to match whatever style name the user supplied with + one of the known ones. Don't bother special casing for an empty + name, we just treat it as any other style name that doesn't match. + If we match, update the current demangling style enum. */ + + for (dem = demanglers; dem -> demangling_style_name != NULL; dem++) + { + if (STREQ (current_demangling_style_string, + dem -> demangling_style_name)) + { + current_demangling_style = dem -> demangling_style; + break; + } + } + + /* Check to see if we found a match. If not, gripe about any non-empty + style name and supply a list of valid ones. FIXME: This should + probably be done with some sort of completion and with help. */ + + if (dem -> demangling_style_name == NULL) + { + if (*current_demangling_style_string != '\0') + { + printf ("Unknown demangling style `%s'.\n", + current_demangling_style_string); + } + printf ("The currently understood settings are:\n\n"); + for (dem = demanglers; dem -> demangling_style_name != NULL; dem++) + { + printf ("%-10s %s\n", dem -> demangling_style_name, + dem -> demangling_style_doc); + if (dem -> demangling_style == current_demangling_style) + { + free (current_demangling_style_string); + current_demangling_style_string = + strdup (dem -> demangling_style_name); + } + } + if (current_demangling_style == unknown_demangling) + { + /* This can happen during initialization if gdb is compiled with + a DEMANGLING_STYLE value that is unknown, so pick the first + one as the default. */ + current_demangling_style = demanglers[0].demangling_style; + current_demangling_style_string = + strdup (demanglers[0].demangling_style_name); + warning ("`%s' style demangling chosen as the default.\n", + current_demangling_style_string); + } + } +} + +/* Fake a "set demangling" command. */ + +void +set_demangling_style (style) + char *style; +{ + if (current_demangling_style_string != NULL) + { + free (current_demangling_style_string); + } + current_demangling_style_string = strdup (style); + set_demangling_command ((char *) NULL, 0); +} + +void +_initialize_demangler () +{ + struct cmd_list_element *set, *show; + + set = add_set_cmd ("demangle-style", class_support, var_string_noescape, + (char *) ¤t_demangling_style_string, + "Set the current C++ demangling style.\n\ +Use `set demangle-style' without arguments for a list of demangling styles.", + &setlist); + show = add_show_from_set (set, &showlist); + set -> function.cfunc = set_demangling_command; + show -> function.cfunc = show_demangling_command; + + /* Set the default demangling style chosen at compilation time. */ + set_demangling_style (DEFAULT_DEMANGLING_STYLE); + set_cplus_marker_for_demangling (CPLUS_MARKER); +} diff --git a/gnu/usr.bin/gdb/gdb/demangle.h b/gnu/usr.bin/gdb/gdb/demangle.h new file mode 100644 index 00000000000..4f191a2e1ad --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/demangle.h @@ -0,0 +1,77 @@ +/* Defs for interface to demanglers. + Copyright 1992 Free Software Foundation, Inc. + + 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, 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. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#include + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM) + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM) + +extern char * +cplus_demangle PARAMS ((CONST char *mangled, int options)); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling PARAMS ((int ch)); + +#endif /* DEMANGLE_H */ diff --git a/gnu/usr.bin/gdb/gdb/dis-asm.h b/gnu/usr.bin/gdb/gdb/dis-asm.h new file mode 100644 index 00000000000..e7f106c318c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/dis-asm.h @@ -0,0 +1,176 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +#include +#include "bfd.h" + +typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2, /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + FILE *stream; + PTR application_data; + + /* For use by the disassembler. */ + int flags; + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + int buffer_length; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + +} disassemble_info; + + + + + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); + + + + + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +#define INIT_DISASSEMBLE_INFO(INFO, STREAM) \ + (INFO).fprintf_func = (fprintf_ftype)fprintf, \ + (INFO).stream = (STREAM), \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).insn_info_valid = 0 + + + + +/* This block of definitions is for calling the instruction decoders + from GDB. */ + +/* GDB--Like target_read_memory, but slightly different parameters. */ +extern int +dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int len, + disassemble_info *info)); + +/* GDB--Like memory_error with slightly different parameters. */ +extern void +dis_asm_memory_error + PARAMS ((int status, bfd_vma memaddr, disassemble_info *info)); + +/* GDB--Like print_address with slightly different parameters. */ +extern void +dis_asm_print_address PARAMS ((bfd_vma addr, disassemble_info *info)); + +#define GDB_INIT_DISASSEMBLE_INFO(INFO, STREAM) \ + (INFO).fprintf_func = (fprintf_ftype)fprintf_filtered, \ + (INFO).stream = (STREAM), \ + (INFO).read_memory_func = dis_asm_read_memory, \ + (INFO).memory_error_func = dis_asm_memory_error, \ + (INFO).print_address_func = dis_asm_print_address, \ + (INFO).insn_info_valid = 0 diff --git a/gnu/usr.bin/gdb/gdb/dis-buf.c b/gnu/usr.bin/gdb/gdb/dis-buf.c new file mode 100644 index 00000000000..d07da6fcff3 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/dis-buf.c @@ -0,0 +1,69 @@ +/* Disassemble from a buffer, for GNU. + Copyright (C) 1993 Free Software Foundation, Inc. + +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. */ + +#include "dis-asm.h" +#include + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +buffer_read_memory (memaddr, myaddr, length, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int length; + struct disassemble_info *info; +{ + if (memaddr < info->buffer_vma + || memaddr + length > info->buffer_vma + info->buffer_length) + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (status, memaddr, info) + int status; + bfd_vma memaddr; + struct disassemble_info *info; +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%x is out of bounds.\n", memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + (*info->fprintf_func) (info->stream, "0x%x", addr); +} diff --git a/gnu/usr.bin/gdb/gdb/dwarfread.c b/gnu/usr.bin/gdb/gdb/dwarfread.c new file mode 100644 index 00000000000..5d19bf8d0b0 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/dwarfread.c @@ -0,0 +1,3866 @@ +/* DWARF debugging format support for GDB. + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. Portions based on dbxread.c, + mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port. + +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. */ + +/* + +FIXME: Do we need to generate dependencies in partial symtabs? +(Perhaps we don't need to). + +FIXME: Resolve minor differences between what information we put in the +partial symbol table and what dbxread puts in. For example, we don't yet +put enum constants there. And dbxread seems to invent a lot of typedefs +we never see. Use the new printpsym command to see the partial symbol table +contents. + +FIXME: Figure out a better way to tell gdb about the name of the function +contain the user's entry point (I.E. main()) + +FIXME: See other FIXME's and "ifdef 0" scattered throughout the code for +other things to work on, if you get bored. :-) + +*/ + +#include "defs.h" +#include "bfd.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "symfile.h" +#include "objfiles.h" +#include /* For time_t in libbfd.h. */ +#include /* For time_t, if not in time.h. */ +#include "libbfd.h" /* FIXME Secret Internal BFD stuff (bfd_read) */ +#include "elf/dwarf.h" +#include "buildsym.h" +#include "demangle.h" +#include "expression.h" /* Needed for enum exp_opcode in language.h, sigh... */ +#include "language.h" +#include "complaints.h" + +#include +#include +#include + +#ifndef NO_SYS_FILE +#include +#endif + +/* FIXME -- convert this to SEEK_SET a la POSIX, move to config files. */ +#ifndef L_SET +#define L_SET 0 +#endif + +/* Some macros to provide DIE info for complaints. */ + +#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0) +#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : "" + +/* Complaints that can be issued during DWARF debug info reading. */ + +struct complaint no_bfd_get_N = +{ + "DIE @ 0x%x \"%s\", no bfd support for %d byte data object", 0, 0 +}; + +struct complaint malformed_die = +{ + "DIE @ 0x%x \"%s\", malformed DIE, bad length (%d bytes)", 0, 0 +}; + +struct complaint bad_die_ref = +{ + "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit", 0, 0 +}; + +struct complaint unknown_attribute_form = +{ + "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", 0, 0 +}; + +struct complaint unknown_attribute_length = +{ + "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes", 0, 0 +}; + +struct complaint unexpected_fund_type = +{ + "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x", 0, 0 +}; + +struct complaint unknown_type_modifier = +{ + "DIE @ 0x%x \"%s\", unknown type modifier %u", 0, 0 +}; + +struct complaint volatile_ignored = +{ + "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored", 0, 0 +}; + +struct complaint const_ignored = +{ + "DIE @ 0x%x \"%s\", type modifier 'const' ignored", 0, 0 +}; + +struct complaint botched_modified_type = +{ + "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)", 0, 0 +}; + +struct complaint op_deref2 = +{ + "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%x not handled", 0, 0 +}; + +struct complaint op_deref4 = +{ + "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%x not handled", 0, 0 +}; + +struct complaint basereg_not_handled = +{ + "DIE @ 0x%x \"%s\", BASEREG %d not handled", 0, 0 +}; + +struct complaint dup_user_type_allocation = +{ + "DIE @ 0x%x \"%s\", internal error: duplicate user type allocation", 0, 0 +}; + +struct complaint dup_user_type_definition = +{ + "DIE @ 0x%x \"%s\", internal error: duplicate user type definition", 0, 0 +}; + +struct complaint missing_tag = +{ + "DIE @ 0x%x \"%s\", missing class, structure, or union tag", 0, 0 +}; + +struct complaint bad_array_element_type = +{ + "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", 0, 0 +}; + +struct complaint subscript_data_items = +{ + "DIE @ 0x%x \"%s\", can't decode subscript data items", 0, 0 +}; + +struct complaint unhandled_array_subscript_format = +{ + "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet", 0, 0 +}; + +struct complaint unknown_array_subscript_format = +{ + "DIE @ 0x%x \"%s\", unknown array subscript format %x", 0, 0 +}; + +struct complaint not_row_major = +{ + "DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0 +}; + +typedef unsigned int DIE_REF; /* Reference to a DIE */ + +#ifndef GCC_PRODUCER +#define GCC_PRODUCER "GNU C " +#endif + +#ifndef GPLUS_PRODUCER +#define GPLUS_PRODUCER "GNU C++ " +#endif + +#ifndef LCC_PRODUCER +#define LCC_PRODUCER "NCR C/C++" +#endif + +#ifndef CHILL_PRODUCER +#define CHILL_PRODUCER "GNU Chill " +#endif + +/* Flags to target_to_host() that tell whether or not the data object is + expected to be signed. Used, for example, when fetching a signed + integer in the target environment which is used as a signed integer + in the host environment, and the two environments have different sized + ints. In this case, *somebody* has to sign extend the smaller sized + int. */ + +#define GET_UNSIGNED 0 /* No sign extension required */ +#define GET_SIGNED 1 /* Sign extension required */ + +/* Defines for things which are specified in the document "DWARF Debugging + Information Format" published by UNIX International, Programming Languages + SIG. These defines are based on revision 1.0.0, Jan 20, 1992. */ + +#define SIZEOF_DIE_LENGTH 4 +#define SIZEOF_DIE_TAG 2 +#define SIZEOF_ATTRIBUTE 2 +#define SIZEOF_FORMAT_SPECIFIER 1 +#define SIZEOF_FMT_FT 2 +#define SIZEOF_LINETBL_LENGTH 4 +#define SIZEOF_LINETBL_LINENO 4 +#define SIZEOF_LINETBL_STMT 2 +#define SIZEOF_LINETBL_DELTA 4 +#define SIZEOF_LOC_ATOM_CODE 1 + +#define FORM_FROM_ATTR(attr) ((attr) & 0xF) /* Implicitly specified */ + +/* Macros that return the sizes of various types of data in the target + environment. + + FIXME: Currently these are just compile time constants (as they are in + other parts of gdb as well). They need to be able to get the right size + either from the bfd or possibly from the DWARF info. It would be nice if + the DWARF producer inserted DIES that describe the fundamental types in + the target environment into the DWARF info, similar to the way dbx stabs + producers produce information about their fundamental types. */ + +#define TARGET_FT_POINTER_SIZE(objfile) (TARGET_PTR_BIT / TARGET_CHAR_BIT) +#define TARGET_FT_LONG_SIZE(objfile) (TARGET_LONG_BIT / TARGET_CHAR_BIT) + +/* The Amiga SVR4 header file defines AT_element_list as a + FORM_BLOCK2, and this is the value emitted by the AT&T compiler. + However, the Issue 2 DWARF specification from AT&T defines it as + a FORM_BLOCK4, as does the latest specification from UI/PLSIG. + For backwards compatibility with the AT&T compiler produced executables + we define AT_short_element_list for this variant. */ + +#define AT_short_element_list (0x00f0|FORM_BLOCK2) + +/* External variables referenced. */ + +extern int info_verbose; /* From main.c; nonzero => verbose */ +extern char *warning_pre_print; /* From utils.c */ + +/* The DWARF debugging information consists of two major pieces, + one is a block of DWARF Information Entries (DIE's) and the other + is a line number table. The "struct dieinfo" structure contains + the information for a single DIE, the one currently being processed. + + In order to make it easier to randomly access the attribute fields + of the current DIE, which are specifically unordered within the DIE, + each DIE is scanned and an instance of the "struct dieinfo" + structure is initialized. + + Initialization is done in two levels. The first, done by basicdieinfo(), + just initializes those fields that are vital to deciding whether or not + to use this DIE, how to skip past it, etc. The second, done by the + function completedieinfo(), fills in the rest of the information. + + Attributes which have block forms are not interpreted at the time + the DIE is scanned, instead we just save pointers to the start + of their value fields. + + Some fields have a flag _p that is set when the value of the + field is valid (I.E. we found a matching attribute in the DIE). Since + we may want to test for the presence of some attributes in the DIE, + such as AT_low_pc, without restricting the values of the field, + we need someway to note that we found such an attribute. + + */ + +typedef char BLOCK; + +struct dieinfo { + char * die; /* Pointer to the raw DIE data */ + unsigned long die_length; /* Length of the raw DIE data */ + DIE_REF die_ref; /* Offset of this DIE */ + unsigned short die_tag; /* Tag for this DIE */ + unsigned long at_padding; + unsigned long at_sibling; + BLOCK * at_location; + char * at_name; + unsigned short at_fund_type; + BLOCK * at_mod_fund_type; + unsigned long at_user_def_type; + BLOCK * at_mod_u_d_type; + unsigned short at_ordering; + BLOCK * at_subscr_data; + unsigned long at_byte_size; + unsigned short at_bit_offset; + unsigned long at_bit_size; + BLOCK * at_element_list; + unsigned long at_stmt_list; + unsigned long at_low_pc; + unsigned long at_high_pc; + unsigned long at_language; + unsigned long at_member; + unsigned long at_discr; + BLOCK * at_discr_value; + BLOCK * at_string_length; + char * at_comp_dir; + char * at_producer; + unsigned long at_start_scope; + unsigned long at_stride_size; + unsigned long at_src_info; + char * at_prototyped; + unsigned int has_at_low_pc:1; + unsigned int has_at_stmt_list:1; + unsigned int has_at_byte_size:1; + unsigned int short_element_list:1; +}; + +static int diecount; /* Approximate count of dies for compilation unit */ +static struct dieinfo *curdie; /* For warnings and such */ + +static char *dbbase; /* Base pointer to dwarf info */ +static int dbsize; /* Size of dwarf info in bytes */ +static int dbroff; /* Relative offset from start of .debug section */ +static char *lnbase; /* Base pointer to line section */ +static int isreg; /* Kludge to identify register variables */ +/* Kludge to identify basereg references. Nonzero if we have an offset + relative to a basereg. */ +static int offreg; +/* Which base register is it relative to? */ +static int basereg; + +/* This value is added to each symbol value. FIXME: Generalize to + the section_offsets structure used by dbxread (once this is done, + pass the appropriate section number to end_symtab). */ +static CORE_ADDR baseaddr; /* Add to each symbol value */ + +/* The section offsets used in the current psymtab or symtab. FIXME, + only used to pass one value (baseaddr) at the moment. */ +static struct section_offsets *base_section_offsets; + +/* Each partial symbol table entry contains a pointer to private data for the + read_symtab() function to use when expanding a partial symbol table entry + to a full symbol table entry. For DWARF debugging info, this data is + contained in the following structure and macros are provided for easy + access to the members given a pointer to a partial symbol table entry. + + dbfoff Always the absolute file offset to the start of the ".debug" + section for the file containing the DIE's being accessed. + + dbroff Relative offset from the start of the ".debug" access to the + first DIE to be accessed. When building the partial symbol + table, this value will be zero since we are accessing the + entire ".debug" section. When expanding a partial symbol + table entry, this value will be the offset to the first + DIE for the compilation unit containing the symbol that + triggers the expansion. + + dblength The size of the chunk of DIE's being examined, in bytes. + + lnfoff The absolute file offset to the line table fragment. Ignored + when building partial symbol tables, but used when expanding + them, and contains the absolute file offset to the fragment + of the ".line" section containing the line numbers for the + current compilation unit. + */ + +struct dwfinfo { + file_ptr dbfoff; /* Absolute file offset to start of .debug section */ + int dbroff; /* Relative offset from start of .debug section */ + int dblength; /* Size of the chunk of DIE's being examined */ + file_ptr lnfoff; /* Absolute file offset to line table fragment */ +}; + +#define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff) +#define DBROFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbroff) +#define DBLENGTH(p) (((struct dwfinfo *)((p)->read_symtab_private))->dblength) +#define LNFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->lnfoff) + +/* The generic symbol table building routines have separate lists for + file scope symbols and all all other scopes (local scopes). So + we need to select the right one to pass to add_symbol_to_list(). + We do it by keeping a pointer to the correct list in list_in_scope. + + FIXME: The original dwarf code just treated the file scope as the first + local scope, and all other local scopes as nested local scopes, and worked + fine. Check to see if we really need to distinguish these in buildsym.c */ + +struct pending **list_in_scope = &file_symbols; + +/* DIES which have user defined types or modified user defined types refer to + other DIES for the type information. Thus we need to associate the offset + of a DIE for a user defined type with a pointer to the type information. + + Originally this was done using a simple but expensive algorithm, with an + array of unsorted structures, each containing an offset/type-pointer pair. + This array was scanned linearly each time a lookup was done. The result + was that gdb was spending over half it's startup time munging through this + array of pointers looking for a structure that had the right offset member. + + The second attempt used the same array of structures, but the array was + sorted using qsort each time a new offset/type was recorded, and a binary + search was used to find the type pointer for a given DIE offset. This was + even slower, due to the overhead of sorting the array each time a new + offset/type pair was entered. + + The third attempt uses a fixed size array of type pointers, indexed by a + value derived from the DIE offset. Since the minimum DIE size is 4 bytes, + we can divide any DIE offset by 4 to obtain a unique index into this fixed + size array. Since each element is a 4 byte pointer, it takes exactly as + much memory to hold this array as to hold the DWARF info for a given + compilation unit. But it gets freed as soon as we are done with it. + This has worked well in practice, as a reasonable tradeoff between memory + consumption and speed, without having to resort to much more complicated + algorithms. */ + +static struct type **utypes; /* Pointer to array of user type pointers */ +static int numutypes; /* Max number of user type pointers */ + +/* Maintain an array of referenced fundamental types for the current + compilation unit being read. For DWARF version 1, we have to construct + the fundamental types on the fly, since no information about the + fundamental types is supplied. Each such fundamental type is created by + calling a language dependent routine to create the type, and then a + pointer to that type is then placed in the array at the index specified + by it's FT_ value. The array has a fixed size set by the + FT_NUM_MEMBERS compile time constant, which is the number of predefined + fundamental types gdb knows how to construct. */ + +static struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */ + +/* Record the language for the compilation unit which is currently being + processed. We know it once we have seen the TAG_compile_unit DIE, + and we need it while processing the DIE's for that compilation unit. + It is eventually saved in the symtab structure, but we don't finalize + the symtab struct until we have processed all the DIE's for the + compilation unit. We also need to get and save a pointer to the + language struct for this language, so we can call the language + dependent routines for doing things such as creating fundamental + types. */ + +static enum language cu_language; +static const struct language_defn *cu_language_defn; + +/* Forward declarations of static functions so we don't have to worry + about ordering within this file. */ + +static int +attribute_size PARAMS ((unsigned int)); + +static unsigned long +target_to_host PARAMS ((char *, int, int, struct objfile *)); + +static void +add_enum_psymbol PARAMS ((struct dieinfo *, struct objfile *)); + +static void +handle_producer PARAMS ((char *)); + +static void +read_file_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static void +read_func_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static void +read_lexical_block_scope PARAMS ((struct dieinfo *, char *, char *, + struct objfile *)); + +static void +scan_partial_symbols PARAMS ((char *, char *, struct objfile *)); + +static void +scan_compilation_units PARAMS ((char *, char *, file_ptr, + file_ptr, struct objfile *)); + +static void +add_partial_symbol PARAMS ((struct dieinfo *, struct objfile *)); + +static void +init_psymbol_list PARAMS ((struct objfile *, int)); + +static void +basicdieinfo PARAMS ((struct dieinfo *, char *, struct objfile *)); + +static void +completedieinfo PARAMS ((struct dieinfo *, struct objfile *)); + +static void +dwarf_psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +static void +psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); + +static void +read_ofile_symtab PARAMS ((struct partial_symtab *)); + +static void +process_dies PARAMS ((char *, char *, struct objfile *)); + +static void +read_structure_scope PARAMS ((struct dieinfo *, char *, char *, + struct objfile *)); + +static struct type * +decode_array_element_type PARAMS ((char *)); + +static struct type * +decode_subscript_data_item PARAMS ((char *, char *)); + +static void +dwarf_read_array_type PARAMS ((struct dieinfo *)); + +static void +read_tag_pointer_type PARAMS ((struct dieinfo *dip)); + +static void +read_tag_string_type PARAMS ((struct dieinfo *dip)); + +static void +read_subroutine_type PARAMS ((struct dieinfo *, char *, char *)); + +static void +read_enumeration PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static struct type * +struct_type PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static struct type * +enum_type PARAMS ((struct dieinfo *, struct objfile *)); + +static void +decode_line_numbers PARAMS ((char *)); + +static struct type * +decode_die_type PARAMS ((struct dieinfo *)); + +static struct type * +decode_mod_fund_type PARAMS ((char *)); + +static struct type * +decode_mod_u_d_type PARAMS ((char *)); + +static struct type * +decode_modified_type PARAMS ((char *, unsigned int, int)); + +static struct type * +decode_fund_type PARAMS ((unsigned int)); + +static char * +create_name PARAMS ((char *, struct obstack *)); + +static struct type * +lookup_utype PARAMS ((DIE_REF)); + +static struct type * +alloc_utype PARAMS ((DIE_REF, struct type *)); + +static struct symbol * +new_symbol PARAMS ((struct dieinfo *, struct objfile *)); + +static void +synthesize_typedef PARAMS ((struct dieinfo *, struct objfile *, + struct type *)); + +static int +locval PARAMS ((char *)); + +static void +set_cu_language PARAMS ((struct dieinfo *)); + +static struct type * +dwarf_fundamental_type PARAMS ((struct objfile *, int)); + + +/* + +LOCAL FUNCTION + + dwarf_fundamental_type -- lookup or create a fundamental type + +SYNOPSIS + + struct type * + dwarf_fundamental_type (struct objfile *objfile, int typeid) + +DESCRIPTION + + DWARF version 1 doesn't supply any fundamental type information, + so gdb has to construct such types. It has a fixed number of + fundamental types that it knows how to construct, which is the + union of all types that it knows how to construct for all languages + that it knows about. These are enumerated in gdbtypes.h. + + As an example, assume we find a DIE that references a DWARF + fundamental type of FT_integer. We first look in the ftypes + array to see if we already have such a type, indexed by the + gdb internal value of FT_INTEGER. If so, we simply return a + pointer to that type. If not, then we ask an appropriate + language dependent routine to create a type FT_INTEGER, using + defaults reasonable for the current target machine, and install + that type in ftypes for future reference. + +RETURNS + + Pointer to a fundamental type. + +*/ + +static struct type * +dwarf_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + if (typeid < 0 || typeid >= FT_NUM_MEMBERS) + { + error ("internal error - invalid fundamental type id %d", typeid); + } + + /* Look for this particular type in the fundamental type vector. If one is + not found, create and install one appropriate for the current language + and the current target machine. */ + + if (ftypes[typeid] == NULL) + { + ftypes[typeid] = cu_language_defn -> la_fund_type(objfile, typeid); + } + + return (ftypes[typeid]); +} + +/* + +LOCAL FUNCTION + + set_cu_language -- set local copy of language for compilation unit + +SYNOPSIS + + void + set_cu_language (struct dieinfo *dip) + +DESCRIPTION + + Decode the language attribute for a compilation unit DIE and + remember what the language was. We use this at various times + when processing DIE's for a given compilation unit. + +RETURNS + + No return value. + + */ + +static void +set_cu_language (dip) + struct dieinfo *dip; +{ + switch (dip -> at_language) + { + case LANG_C89: + case LANG_C: + cu_language = language_c; + break; + case LANG_C_PLUS_PLUS: + cu_language = language_cplus; + break; + case LANG_CHILL: + cu_language = language_chill; + break; + case LANG_MODULA2: + cu_language = language_m2; + break; + case LANG_ADA83: + case LANG_COBOL74: + case LANG_COBOL85: + case LANG_FORTRAN77: + case LANG_FORTRAN90: + case LANG_PASCAL83: + /* We don't know anything special about these yet. */ + cu_language = language_unknown; + break; + default: + /* If no at_language, try to deduce one from the filename */ + cu_language = deduce_language_from_filename (dip -> at_name); + break; + } + cu_language_defn = language_def (cu_language); +} + +/* + +GLOBAL FUNCTION + + dwarf_build_psymtabs -- build partial symtabs from DWARF debug info + +SYNOPSIS + + void dwarf_build_psymtabs (struct objfile *objfile, + struct section_offsets *section_offsets, + int mainline, file_ptr dbfoff, unsigned int dbfsize, + file_ptr lnoffset, unsigned int lnsize) + +DESCRIPTION + + This function is called upon to build partial symtabs from files + containing DIE's (Dwarf Information Entries) and DWARF line numbers. + + It is passed a bfd* containing the DIES + and line number information, the corresponding filename for that + file, a base address for relocating the symbols, a flag indicating + whether or not this debugging information is from a "main symbol + table" rather than a shared library or dynamically linked file, + and file offset/size pairs for the DIE information and line number + information. + +RETURNS + + No return value. + + */ + +void +dwarf_build_psymtabs (objfile, section_offsets, mainline, dbfoff, dbfsize, + lnoffset, lnsize) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + file_ptr dbfoff; + unsigned int dbfsize; + file_ptr lnoffset; + unsigned int lnsize; +{ + bfd *abfd = objfile->obfd; + struct cleanup *back_to; + + current_objfile = objfile; + dbsize = dbfsize; + dbbase = xmalloc (dbsize); + dbroff = 0; + if ((bfd_seek (abfd, dbfoff, L_SET) != 0) || + (bfd_read (dbbase, dbsize, 1, abfd) != dbsize)) + { + free (dbbase); + error ("can't read DWARF data from '%s'", bfd_get_filename (abfd)); + } + back_to = make_cleanup (free, dbbase); + + /* If we are reinitializing, or if we have never loaded syms yet, init. + Since we have no idea how many DIES we are looking at, we just guess + some arbitrary value. */ + + if (mainline || objfile -> global_psymbols.size == 0 || + objfile -> static_psymbols.size == 0) + { + init_psymbol_list (objfile, 1024); + } + + /* Save the relocation factor where everybody can see it. */ + + base_section_offsets = section_offsets; + baseaddr = ANOFFSET (section_offsets, 0); + + /* Follow the compilation unit sibling chain, building a partial symbol + table entry for each one. Save enough information about each compilation + unit to locate the full DWARF information later. */ + + scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile); + + do_cleanups (back_to); + current_objfile = NULL; +} + +/* + +LOCAL FUNCTION + + read_lexical_block_scope -- process all dies in a lexical block + +SYNOPSIS + + static void read_lexical_block_scope (struct dieinfo *dip, + char *thisdie, char *enddie) + +DESCRIPTION + + Process all the DIES contained within a lexical block scope. + Start a new scope, process the dies, and then close the scope. + + */ + +static void +read_lexical_block_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + register struct context_stack *new; + + push_context (0, dip -> at_low_pc); + process_dies (thisdie + dip -> die_length, enddie, objfile); + new = pop_context (); + if (local_symbols != NULL) + { + finish_block (0, &local_symbols, new -> old_blocks, new -> start_addr, + dip -> at_high_pc, objfile); + } + local_symbols = new -> locals; +} + +/* + +LOCAL FUNCTION + + lookup_utype -- look up a user defined type from die reference + +SYNOPSIS + + static type *lookup_utype (DIE_REF die_ref) + +DESCRIPTION + + Given a DIE reference, lookup the user defined type associated with + that DIE, if it has been registered already. If not registered, then + return NULL. Alloc_utype() can be called to register an empty + type for this reference, which will be filled in later when the + actual referenced DIE is processed. + */ + +static struct type * +lookup_utype (die_ref) + DIE_REF die_ref; +{ + struct type *type = NULL; + int utypeidx; + + utypeidx = (die_ref - dbroff) / 4; + if ((utypeidx < 0) || (utypeidx >= numutypes)) + { + complain (&bad_die_ref, DIE_ID, DIE_NAME); + } + else + { + type = *(utypes + utypeidx); + } + return (type); +} + + +/* + +LOCAL FUNCTION + + alloc_utype -- add a user defined type for die reference + +SYNOPSIS + + static type *alloc_utype (DIE_REF die_ref, struct type *utypep) + +DESCRIPTION + + Given a die reference DIE_REF, and a possible pointer to a user + defined type UTYPEP, register that this reference has a user + defined type and either use the specified type in UTYPEP or + make a new empty type that will be filled in later. + + We should only be called after calling lookup_utype() to verify that + there is not currently a type registered for DIE_REF. + */ + +static struct type * +alloc_utype (die_ref, utypep) + DIE_REF die_ref; + struct type *utypep; +{ + struct type **typep; + int utypeidx; + + utypeidx = (die_ref - dbroff) / 4; + typep = utypes + utypeidx; + if ((utypeidx < 0) || (utypeidx >= numutypes)) + { + utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + complain (&bad_die_ref, DIE_ID, DIE_NAME); + } + else if (*typep != NULL) + { + utypep = *typep; + complain (&dup_user_type_allocation, DIE_ID, DIE_NAME); + } + else + { + if (utypep == NULL) + { + utypep = alloc_type (current_objfile); + } + *typep = utypep; + } + return (utypep); +} + +/* + +LOCAL FUNCTION + + decode_die_type -- return a type for a specified die + +SYNOPSIS + + static struct type *decode_die_type (struct dieinfo *dip) + +DESCRIPTION + + Given a pointer to a die information structure DIP, decode the + type of the die and return a pointer to the decoded type. All + dies without specific types default to type int. + */ + +static struct type * +decode_die_type (dip) + struct dieinfo *dip; +{ + struct type *type = NULL; + + if (dip -> at_fund_type != 0) + { + type = decode_fund_type (dip -> at_fund_type); + } + else if (dip -> at_mod_fund_type != NULL) + { + type = decode_mod_fund_type (dip -> at_mod_fund_type); + } + else if (dip -> at_user_def_type) + { + if ((type = lookup_utype (dip -> at_user_def_type)) == NULL) + { + type = alloc_utype (dip -> at_user_def_type, NULL); + } + } + else if (dip -> at_mod_u_d_type) + { + type = decode_mod_u_d_type (dip -> at_mod_u_d_type); + } + else + { + type = dwarf_fundamental_type (current_objfile, FT_INTEGER); + } + return (type); +} + +/* + +LOCAL FUNCTION + + struct_type -- compute and return the type for a struct or union + +SYNOPSIS + + static struct type *struct_type (struct dieinfo *dip, char *thisdie, + char *enddie, struct objfile *objfile) + +DESCRIPTION + + Given pointer to a die information structure for a die which + defines a union or structure (and MUST define one or the other), + and pointers to the raw die data that define the range of dies which + define the members, compute and return the user defined type for the + structure or union. + */ + +static struct type * +struct_type (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct type *type; + struct nextfield { + struct nextfield *next; + struct field field; + }; + struct nextfield *list = NULL; + struct nextfield *new; + int nfields = 0; + int n; + struct dieinfo mbr; + char *nextdie; +#if !BITS_BIG_ENDIAN + int anonymous_size; +#endif + + if ((type = lookup_utype (dip -> die_ref)) == NULL) + { + /* No forward references created an empty type, so install one now */ + type = alloc_utype (dip -> die_ref, NULL); + } + INIT_CPLUS_SPECIFIC(type); + switch (dip -> die_tag) + { + case TAG_class_type: + TYPE_CODE (type) = TYPE_CODE_CLASS; + break; + case TAG_structure_type: + TYPE_CODE (type) = TYPE_CODE_STRUCT; + break; + case TAG_union_type: + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + default: + /* Should never happen */ + TYPE_CODE (type) = TYPE_CODE_UNDEF; + complain (&missing_tag, DIE_ID, DIE_NAME); + break; + } + /* Some compilers try to be helpful by inventing "fake" names for + anonymous enums, structures, and unions, like "~0fake" or ".0fake". + Thanks, but no thanks... */ + if (dip -> at_name != NULL + && *dip -> at_name != '~' + && *dip -> at_name != '.') + { + TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack, + "", "", dip -> at_name); + } + /* Use whatever size is known. Zero is a valid size. We might however + wish to check has_at_byte_size to make sure that some byte size was + given explicitly, but DWARF doesn't specify that explicit sizes of + zero have to present, so complaining about missing sizes should + probably not be the default. */ + TYPE_LENGTH (type) = dip -> at_byte_size; + thisdie += dip -> die_length; + while (thisdie < enddie) + { + basicdieinfo (&mbr, thisdie, objfile); + completedieinfo (&mbr, objfile); + if (mbr.die_length <= SIZEOF_DIE_LENGTH) + { + break; + } + else if (mbr.at_sibling != 0) + { + nextdie = dbbase + mbr.at_sibling - dbroff; + } + else + { + nextdie = thisdie + mbr.die_length; + } + switch (mbr.die_tag) + { + case TAG_member: + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new -> next = list; + list = new; + /* Save the data. */ + list -> field.name = + obsavestring (mbr.at_name, strlen (mbr.at_name), + &objfile -> type_obstack); + list -> field.type = decode_die_type (&mbr); + list -> field.bitpos = 8 * locval (mbr.at_location); + /* Handle bit fields. */ + list -> field.bitsize = mbr.at_bit_size; +#if BITS_BIG_ENDIAN + /* For big endian bits, the at_bit_offset gives the additional + bit offset from the MSB of the containing anonymous object to + the MSB of the field. We don't have to do anything special + since we don't need to know the size of the anonymous object. */ + list -> field.bitpos += mbr.at_bit_offset; +#else + /* For little endian bits, we need to have a non-zero at_bit_size, + so that we know we are in fact dealing with a bitfield. Compute + the bit offset to the MSB of the anonymous object, subtract off + the number of bits from the MSB of the field to the MSB of the + object, and then subtract off the number of bits of the field + itself. The result is the bit offset of the LSB of the field. */ + if (mbr.at_bit_size > 0) + { + if (mbr.has_at_byte_size) + { + /* The size of the anonymous object containing the bit field + is explicit, so use the indicated size (in bytes). */ + anonymous_size = mbr.at_byte_size; + } + else + { + /* The size of the anonymous object containing the bit field + matches the size of an object of the bit field's type. + DWARF allows at_byte_size to be left out in such cases, + as a debug information size optimization. */ + anonymous_size = TYPE_LENGTH (list -> field.type); + } + list -> field.bitpos += + anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size; + } +#endif + nfields++; + break; + default: + process_dies (thisdie, nextdie, objfile); + break; + } + thisdie = nextdie; + } + /* Now create the vector of fields, and record how big it is. We may + not even have any fields, if this DIE was generated due to a reference + to an anonymous structure or union. In this case, TYPE_FLAG_STUB is + set, which clues gdb in to the fact that it needs to search elsewhere + for the full structure definition. */ + if (nfields == 0) + { + TYPE_FLAGS (type) |= TYPE_FLAG_STUB; + } + else + { + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + /* Copy the saved-up fields into the field vector. */ + for (n = nfields; list; list = list -> next) + { + TYPE_FIELD (type, --n) = list -> field; + } + } + return (type); +} + +/* + +LOCAL FUNCTION + + read_structure_scope -- process all dies within struct or union + +SYNOPSIS + + static void read_structure_scope (struct dieinfo *dip, + char *thisdie, char *enddie, struct objfile *objfile) + +DESCRIPTION + + Called when we find the DIE that starts a structure or union + scope (definition) to process all dies that define the members + of the structure or union. DIP is a pointer to the die info + struct for the DIE that names the structure or union. + +NOTES + + Note that we need to call struct_type regardless of whether or not + the DIE has an at_name attribute, since it might be an anonymous + structure or union. This gets the type entered into our set of + user defined types. + + However, if the structure is incomplete (an opaque struct/union) + then suppress creating a symbol table entry for it since gdb only + wants to find the one with the complete definition. Note that if + it is complete, we just call new_symbol, which does it's own + checking about whether the struct/union is anonymous or not (and + suppresses creating a symbol table entry itself). + + */ + +static void +read_structure_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct type *type; + struct symbol *sym; + + type = struct_type (dip, thisdie, enddie, objfile); + if (!(TYPE_FLAGS (type) & TYPE_FLAG_STUB)) + { + sym = new_symbol (dip, objfile); + if (sym != NULL) + { + SYMBOL_TYPE (sym) = type; + if (cu_language == language_cplus) + { + synthesize_typedef (dip, objfile, type); + } + } + } +} + +/* + +LOCAL FUNCTION + + decode_array_element_type -- decode type of the array elements + +SYNOPSIS + + static struct type *decode_array_element_type (char *scan, char *end) + +DESCRIPTION + + As the last step in decoding the array subscript information for an + array DIE, we need to decode the type of the array elements. We are + passed a pointer to this last part of the subscript information and + must return the appropriate type. If the type attribute is not + recognized, just warn about the problem and return type int. + */ + +static struct type * +decode_array_element_type (scan) + char *scan; +{ + struct type *typep; + DIE_REF die_ref; + unsigned short attribute; + unsigned short fundtype; + int nbytes; + + attribute = target_to_host (scan, SIZEOF_ATTRIBUTE, GET_UNSIGNED, + current_objfile); + scan += SIZEOF_ATTRIBUTE; + if ((nbytes = attribute_size (attribute)) == -1) + { + complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute); + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + } + else + { + switch (attribute) + { + case AT_fund_type: + fundtype = target_to_host (scan, nbytes, GET_UNSIGNED, + current_objfile); + typep = decode_fund_type (fundtype); + break; + case AT_mod_fund_type: + typep = decode_mod_fund_type (scan); + break; + case AT_user_def_type: + die_ref = target_to_host (scan, nbytes, GET_UNSIGNED, + current_objfile); + if ((typep = lookup_utype (die_ref)) == NULL) + { + typep = alloc_utype (die_ref, NULL); + } + break; + case AT_mod_u_d_type: + typep = decode_mod_u_d_type (scan); + break; + default: + complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute); + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + break; + } + } + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_subscript_data_item -- decode array subscript item + +SYNOPSIS + + static struct type * + decode_subscript_data_item (char *scan, char *end) + +DESCRIPTION + + The array subscripts and the data type of the elements of an + array are described by a list of data items, stored as a block + of contiguous bytes. There is a data item describing each array + dimension, and a final data item describing the element type. + The data items are ordered the same as their appearance in the + source (I.E. leftmost dimension first, next to leftmost second, + etc). + + The data items describing each array dimension consist of four + parts: (1) a format specifier, (2) type type of the subscript + index, (3) a description of the low bound of the array dimension, + and (4) a description of the high bound of the array dimension. + + The last data item is the description of the type of each of + the array elements. + + We are passed a pointer to the start of the block of bytes + containing the remaining data items, and a pointer to the first + byte past the data. This function recursively decodes the + remaining data items and returns a type. + + If we somehow fail to decode some data, we complain about it + and return a type "array of int". + +BUGS + FIXME: This code only implements the forms currently used + by the AT&T and GNU C compilers. + + The end pointer is supplied for error checking, maybe we should + use it for that... + */ + +static struct type * +decode_subscript_data_item (scan, end) + char *scan; + char *end; +{ + struct type *typep = NULL; /* Array type we are building */ + struct type *nexttype; /* Type of each element (may be array) */ + struct type *indextype; /* Type of this index */ + struct type *rangetype; + unsigned int format; + unsigned short fundtype; + unsigned long lowbound; + unsigned long highbound; + int nbytes; + + format = target_to_host (scan, SIZEOF_FORMAT_SPECIFIER, GET_UNSIGNED, + current_objfile); + scan += SIZEOF_FORMAT_SPECIFIER; + switch (format) + { + case FMT_ET: + typep = decode_array_element_type (scan); + break; + case FMT_FT_C_C: + fundtype = target_to_host (scan, SIZEOF_FMT_FT, GET_UNSIGNED, + current_objfile); + indextype = decode_fund_type (fundtype); + scan += SIZEOF_FMT_FT; + nbytes = TARGET_FT_LONG_SIZE (current_objfile); + lowbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile); + scan += nbytes; + highbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile); + scan += nbytes; + nexttype = decode_subscript_data_item (scan, end); + if (nexttype == NULL) + { + /* Munged subscript data or other problem, fake it. */ + complain (&subscript_data_items, DIE_ID, DIE_NAME); + nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + } + rangetype = create_range_type ((struct type *) NULL, indextype, + lowbound, highbound); + typep = create_array_type ((struct type *) NULL, nexttype, rangetype); + break; + case FMT_FT_C_X: + case FMT_FT_X_C: + case FMT_FT_X_X: + case FMT_UT_C_C: + case FMT_UT_C_X: + case FMT_UT_X_C: + case FMT_UT_X_X: + complain (&unhandled_array_subscript_format, DIE_ID, DIE_NAME, format); + nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0); + typep = create_array_type ((struct type *) NULL, nexttype, rangetype); + break; + default: + complain (&unknown_array_subscript_format, DIE_ID, DIE_NAME, format); + nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0); + typep = create_array_type ((struct type *) NULL, nexttype, rangetype); + break; + } + return (typep); +} + +/* + +LOCAL FUNCTION + + dwarf_read_array_type -- read TAG_array_type DIE + +SYNOPSIS + + static void dwarf_read_array_type (struct dieinfo *dip) + +DESCRIPTION + + Extract all information from a TAG_array_type DIE and add to + the user defined type vector. + */ + +static void +dwarf_read_array_type (dip) + struct dieinfo *dip; +{ + struct type *type; + struct type *utype; + char *sub; + char *subend; + unsigned short blocksz; + int nbytes; + + if (dip -> at_ordering != ORD_row_major) + { + /* FIXME: Can gdb even handle column major arrays? */ + complain (¬_row_major, DIE_ID, DIE_NAME); + } + if ((sub = dip -> at_subscr_data) != NULL) + { + nbytes = attribute_size (AT_subscr_data); + blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile); + subend = sub + nbytes + blocksz; + sub += nbytes; + type = decode_subscript_data_item (sub, subend); + if ((utype = lookup_utype (dip -> die_ref)) == NULL) + { + /* Install user defined type that has not been referenced yet. */ + alloc_utype (dip -> die_ref, type); + } + else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF) + { + /* Ick! A forward ref has already generated a blank type in our + slot, and this type probably already has things pointing to it + (which is what caused it to be created in the first place). + If it's just a place holder we can plop our fully defined type + on top of it. We can't recover the space allocated for our + new type since it might be on an obstack, but we could reuse + it if we kept a list of them, but it might not be worth it + (FIXME). */ + *utype = *type; + } + else + { + /* Double ick! Not only is a type already in our slot, but + someone has decorated it. Complain and leave it alone. */ + complain (&dup_user_type_definition, DIE_ID, DIE_NAME); + } + } +} + +/* + +LOCAL FUNCTION + + read_tag_pointer_type -- read TAG_pointer_type DIE + +SYNOPSIS + + static void read_tag_pointer_type (struct dieinfo *dip) + +DESCRIPTION + + Extract all information from a TAG_pointer_type DIE and add to + the user defined type vector. + */ + +static void +read_tag_pointer_type (dip) + struct dieinfo *dip; +{ + struct type *type; + struct type *utype; + + type = decode_die_type (dip); + if ((utype = lookup_utype (dip -> die_ref)) == NULL) + { + utype = lookup_pointer_type (type); + alloc_utype (dip -> die_ref, utype); + } + else + { + TYPE_TARGET_TYPE (utype) = type; + TYPE_POINTER_TYPE (type) = utype; + + /* We assume the machine has only one representation for pointers! */ + /* FIXME: This confuses host<->target data representations, and is a + poor assumption besides. */ + + TYPE_LENGTH (utype) = sizeof (char *); + TYPE_CODE (utype) = TYPE_CODE_PTR; + } +} + +/* + +LOCAL FUNCTION + + read_tag_string_type -- read TAG_string_type DIE + +SYNOPSIS + + static void read_tag_string_type (struct dieinfo *dip) + +DESCRIPTION + + Extract all information from a TAG_string_type DIE and add to + the user defined type vector. It isn't really a user defined + type, but it behaves like one, with other DIE's using an + AT_user_def_type attribute to reference it. + */ + +static void +read_tag_string_type (dip) + struct dieinfo *dip; +{ + struct type *utype; + struct type *indextype; + struct type *rangetype; + unsigned long lowbound = 0; + unsigned long highbound; + + if (dip -> has_at_byte_size) + { + /* A fixed bounds string */ + highbound = dip -> at_byte_size - 1; + } + else + { + /* A varying length string. Stub for now. (FIXME) */ + highbound = 1; + } + indextype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + rangetype = create_range_type ((struct type *) NULL, indextype, lowbound, + highbound); + + utype = lookup_utype (dip -> die_ref); + if (utype == NULL) + { + /* No type defined, go ahead and create a blank one to use. */ + utype = alloc_utype (dip -> die_ref, (struct type *) NULL); + } + else + { + /* Already a type in our slot due to a forward reference. Make sure it + is a blank one. If not, complain and leave it alone. */ + if (TYPE_CODE (utype) != TYPE_CODE_UNDEF) + { + complain (&dup_user_type_definition, DIE_ID, DIE_NAME); + return; + } + } + + /* Create the string type using the blank type we either found or created. */ + utype = create_string_type (utype, rangetype); +} + +/* + +LOCAL FUNCTION + + read_subroutine_type -- process TAG_subroutine_type dies + +SYNOPSIS + + static void read_subroutine_type (struct dieinfo *dip, char thisdie, + char *enddie) + +DESCRIPTION + + Handle DIES due to C code like: + + struct foo { + int (*funcp)(int a, long l); (Generates TAG_subroutine_type DIE) + int b; + }; + +NOTES + + The parameter DIES are currently ignored. See if gdb has a way to + include this info in it's type system, and decode them if so. Is + this what the type structure's "arg_types" field is for? (FIXME) + */ + +static void +read_subroutine_type (dip, thisdie, enddie) + struct dieinfo *dip; + char *thisdie; + char *enddie; +{ + struct type *type; /* Type that this function returns */ + struct type *ftype; /* Function that returns above type */ + + /* Decode the type that this subroutine returns */ + + type = decode_die_type (dip); + + /* Check to see if we already have a partially constructed user + defined type for this DIE, from a forward reference. */ + + if ((ftype = lookup_utype (dip -> die_ref)) == NULL) + { + /* This is the first reference to one of these types. Make + a new one and place it in the user defined types. */ + ftype = lookup_function_type (type); + alloc_utype (dip -> die_ref, ftype); + } + else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF) + { + /* We have an existing partially constructed type, so bash it + into the correct type. */ + TYPE_TARGET_TYPE (ftype) = type; + TYPE_FUNCTION_TYPE (type) = ftype; + TYPE_LENGTH (ftype) = 1; + TYPE_CODE (ftype) = TYPE_CODE_FUNC; + } + else + { + complain (&dup_user_type_definition, DIE_ID, DIE_NAME); + } +} + +/* + +LOCAL FUNCTION + + read_enumeration -- process dies which define an enumeration + +SYNOPSIS + + static void read_enumeration (struct dieinfo *dip, char *thisdie, + char *enddie, struct objfile *objfile) + +DESCRIPTION + + Given a pointer to a die which begins an enumeration, process all + the dies that define the members of the enumeration. + +NOTES + + Note that we need to call enum_type regardless of whether or not we + have a symbol, since we might have an enum without a tag name (thus + no symbol for the tagname). + */ + +static void +read_enumeration (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct type *type; + struct symbol *sym; + + type = enum_type (dip, objfile); + sym = new_symbol (dip, objfile); + if (sym != NULL) + { + SYMBOL_TYPE (sym) = type; + if (cu_language == language_cplus) + { + synthesize_typedef (dip, objfile, type); + } + } +} + +/* + +LOCAL FUNCTION + + enum_type -- decode and return a type for an enumeration + +SYNOPSIS + + static type *enum_type (struct dieinfo *dip, struct objfile *objfile) + +DESCRIPTION + + Given a pointer to a die information structure for the die which + starts an enumeration, process all the dies that define the members + of the enumeration and return a type pointer for the enumeration. + + At the same time, for each member of the enumeration, create a + symbol for it with namespace VAR_NAMESPACE and class LOC_CONST, + and give it the type of the enumeration itself. + +NOTES + + Note that the DWARF specification explicitly mandates that enum + constants occur in reverse order from the source program order, + for "consistency" and because this ordering is easier for many + compilers to generate. (Draft 6, sec 3.8.5, Enumeration type + Entries). Because gdb wants to see the enum members in program + source order, we have to ensure that the order gets reversed while + we are processing them. + */ + +static struct type * +enum_type (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + struct type *type; + struct nextfield { + struct nextfield *next; + struct field field; + }; + struct nextfield *list = NULL; + struct nextfield *new; + int nfields = 0; + int n; + char *scan; + char *listend; + unsigned short blocksz; + struct symbol *sym; + int nbytes; + + if ((type = lookup_utype (dip -> die_ref)) == NULL) + { + /* No forward references created an empty type, so install one now */ + type = alloc_utype (dip -> die_ref, NULL); + } + TYPE_CODE (type) = TYPE_CODE_ENUM; + /* Some compilers try to be helpful by inventing "fake" names for + anonymous enums, structures, and unions, like "~0fake" or ".0fake". + Thanks, but no thanks... */ + if (dip -> at_name != NULL + && *dip -> at_name != '~' + && *dip -> at_name != '.') + { + TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack, + "", "", dip -> at_name); + } + if (dip -> at_byte_size != 0) + { + TYPE_LENGTH (type) = dip -> at_byte_size; + } + if ((scan = dip -> at_element_list) != NULL) + { + if (dip -> short_element_list) + { + nbytes = attribute_size (AT_short_element_list); + } + else + { + nbytes = attribute_size (AT_element_list); + } + blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile); + listend = scan + nbytes + blocksz; + scan += nbytes; + while (scan < listend) + { + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new -> next = list; + list = new; + list -> field.type = NULL; + list -> field.bitsize = 0; + list -> field.bitpos = + target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED, + objfile); + scan += TARGET_FT_LONG_SIZE (objfile); + list -> field.name = obsavestring (scan, strlen (scan), + &objfile -> type_obstack); + scan += strlen (scan) + 1; + nfields++; + /* Handcraft a new symbol for this enum member. */ + sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = create_name (list -> field.name, + &objfile->symbol_obstack); + SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = type; + SYMBOL_VALUE (sym) = list -> field.bitpos; + add_symbol_to_list (sym, list_in_scope); + } + /* Now create the vector of fields, and record how big it is. This is + where we reverse the order, by pulling the members off the list in + reverse order from how they were inserted. If we have no fields + (this is apparently possible in C++) then skip building a field + vector. */ + if (nfields > 0) + { + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (&objfile->symbol_obstack, sizeof (struct field) * nfields); + /* Copy the saved-up fields into the field vector. */ + for (n = 0; (n < nfields) && (list != NULL); list = list -> next) + { + TYPE_FIELD (type, n++) = list -> field; + } + } + } + return (type); +} + +/* + +LOCAL FUNCTION + + read_func_scope -- process all dies within a function scope + +DESCRIPTION + + Process all dies within a given function scope. We are passed + a die information structure pointer DIP for the die which + starts the function scope, and pointers into the raw die data + that define the dies within the function scope. + + For now, we ignore lexical block scopes within the function. + The problem is that AT&T cc does not define a DWARF lexical + block scope for the function itself, while gcc defines a + lexical block scope for the function. We need to think about + how to handle this difference, or if it is even a problem. + (FIXME) + */ + +static void +read_func_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + register struct context_stack *new; + + if (objfile -> ei.entry_point >= dip -> at_low_pc && + objfile -> ei.entry_point < dip -> at_high_pc) + { + objfile -> ei.entry_func_lowpc = dip -> at_low_pc; + objfile -> ei.entry_func_highpc = dip -> at_high_pc; + } + if (STREQ (dip -> at_name, "main")) /* FIXME: hardwired name */ + { + objfile -> ei.main_func_lowpc = dip -> at_low_pc; + objfile -> ei.main_func_highpc = dip -> at_high_pc; + } + new = push_context (0, dip -> at_low_pc); + new -> name = new_symbol (dip, objfile); + list_in_scope = &local_symbols; + process_dies (thisdie + dip -> die_length, enddie, objfile); + new = pop_context (); + /* Make a block for the local symbols within. */ + finish_block (new -> name, &local_symbols, new -> old_blocks, + new -> start_addr, dip -> at_high_pc, objfile); + list_in_scope = &file_symbols; +} + + +/* + +LOCAL FUNCTION + + handle_producer -- process the AT_producer attribute + +DESCRIPTION + + Perform any operations that depend on finding a particular + AT_producer attribute. + + */ + +static void +handle_producer (producer) + char *producer; +{ + + /* If this compilation unit was compiled with g++ or gcc, then set the + processing_gcc_compilation flag. */ + + processing_gcc_compilation = + STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)) + || STREQN (producer, CHILL_PRODUCER, strlen (CHILL_PRODUCER)) + || STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER)); + + /* Select a demangling style if we can identify the producer and if + the current style is auto. We leave the current style alone if it + is not auto. We also leave the demangling style alone if we find a + gcc (cc1) producer, as opposed to a g++ (cc1plus) producer. */ + + if (AUTO_DEMANGLING) + { + if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER))) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER))) + { + set_demangling_style (LUCID_DEMANGLING_STYLE_STRING); + } + } +} + + +/* + +LOCAL FUNCTION + + read_file_scope -- process all dies within a file scope + +DESCRIPTION + + Process all dies within a given file scope. We are passed a + pointer to the die information structure for the die which + starts the file scope, and pointers into the raw die data which + mark the range of dies within the file scope. + + When the partial symbol table is built, the file offset for the line + number table for each compilation unit is saved in the partial symbol + table entry for that compilation unit. As the symbols for each + compilation unit are read, the line number table is read into memory + and the variable lnbase is set to point to it. Thus all we have to + do is use lnbase to access the line number table for the current + compilation unit. + */ + +static void +read_file_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct cleanup *back_to; + struct symtab *symtab; + + if (objfile -> ei.entry_point >= dip -> at_low_pc && + objfile -> ei.entry_point < dip -> at_high_pc) + { + objfile -> ei.entry_file_lowpc = dip -> at_low_pc; + objfile -> ei.entry_file_highpc = dip -> at_high_pc; + } + set_cu_language (dip); + if (dip -> at_producer != NULL) + { + handle_producer (dip -> at_producer); + } + numutypes = (enddie - thisdie) / 4; + utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *)); + back_to = make_cleanup (free, utypes); + memset (utypes, 0, numutypes * sizeof (struct type *)); + memset (ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *)); + start_symtab (dip -> at_name, dip -> at_comp_dir, dip -> at_low_pc); + decode_line_numbers (lnbase); + process_dies (thisdie + dip -> die_length, enddie, objfile); + + symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile, 0); + if (symtab != NULL) + { + symtab -> language = cu_language; + } + do_cleanups (back_to); + utypes = NULL; + numutypes = 0; +} + +/* + +LOCAL FUNCTION + + process_dies -- process a range of DWARF Information Entries + +SYNOPSIS + + static void process_dies (char *thisdie, char *enddie, + struct objfile *objfile) + +DESCRIPTION + + Process all DIE's in a specified range. May be (and almost + certainly will be) called recursively. + */ + +static void +process_dies (thisdie, enddie, objfile) + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + char *nextdie; + struct dieinfo di; + + while (thisdie < enddie) + { + basicdieinfo (&di, thisdie, objfile); + if (di.die_length < SIZEOF_DIE_LENGTH) + { + break; + } + else if (di.die_tag == TAG_padding) + { + nextdie = thisdie + di.die_length; + } + else + { + completedieinfo (&di, objfile); + if (di.at_sibling != 0) + { + nextdie = dbbase + di.at_sibling - dbroff; + } + else + { + nextdie = thisdie + di.die_length; + } + switch (di.die_tag) + { + case TAG_compile_unit: + read_file_scope (&di, thisdie, nextdie, objfile); + break; + case TAG_global_subroutine: + case TAG_subroutine: + if (di.has_at_low_pc) + { + read_func_scope (&di, thisdie, nextdie, objfile); + } + break; + case TAG_lexical_block: + read_lexical_block_scope (&di, thisdie, nextdie, objfile); + break; + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + read_structure_scope (&di, thisdie, nextdie, objfile); + break; + case TAG_enumeration_type: + read_enumeration (&di, thisdie, nextdie, objfile); + break; + case TAG_subroutine_type: + read_subroutine_type (&di, thisdie, nextdie); + break; + case TAG_array_type: + dwarf_read_array_type (&di); + break; + case TAG_pointer_type: + read_tag_pointer_type (&di); + break; + case TAG_string_type: + read_tag_string_type (&di); + break; + default: + new_symbol (&di, objfile); + break; + } + } + thisdie = nextdie; + } +} + +/* + +LOCAL FUNCTION + + decode_line_numbers -- decode a line number table fragment + +SYNOPSIS + + static void decode_line_numbers (char *tblscan, char *tblend, + long length, long base, long line, long pc) + +DESCRIPTION + + Translate the DWARF line number information to gdb form. + + The ".line" section contains one or more line number tables, one for + each ".line" section from the objects that were linked. + + The AT_stmt_list attribute for each TAG_source_file entry in the + ".debug" section contains the offset into the ".line" section for the + start of the table for that file. + + The table itself has the following structure: + + + 4 bytes 4 bytes 10 bytes + + The table length is the total size of the table, including the 4 bytes + for the length information. + + The base address is the address of the first instruction generated + for the source file. + + Each source statement entry has the following structure: + +
+ 4 bytes 2 bytes 4 bytes + + The line number is relative to the start of the file, starting with + line 1. + + The statement position either -1 (0xFFFF) or the number of characters + from the beginning of the line to the beginning of the statement. + + The address delta is the difference between the base address and + the address of the first instruction for the statement. + + Note that we must copy the bytes from the packed table to our local + variables before attempting to use them, to avoid alignment problems + on some machines, particularly RISC processors. + +BUGS + + Does gdb expect the line numbers to be sorted? They are now by + chance/luck, but are not required to be. (FIXME) + + The line with number 0 is unused, gdb apparently can discover the + span of the last line some other way. How? (FIXME) + */ + +static void +decode_line_numbers (linetable) + char *linetable; +{ + char *tblscan; + char *tblend; + unsigned long length; + unsigned long base; + unsigned long line; + unsigned long pc; + + if (linetable != NULL) + { + tblscan = tblend = linetable; + length = target_to_host (tblscan, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED, + current_objfile); + tblscan += SIZEOF_LINETBL_LENGTH; + tblend += length; + base = target_to_host (tblscan, TARGET_FT_POINTER_SIZE (objfile), + GET_UNSIGNED, current_objfile); + tblscan += TARGET_FT_POINTER_SIZE (objfile); + base += baseaddr; + while (tblscan < tblend) + { + line = target_to_host (tblscan, SIZEOF_LINETBL_LINENO, GET_UNSIGNED, + current_objfile); + tblscan += SIZEOF_LINETBL_LINENO + SIZEOF_LINETBL_STMT; + pc = target_to_host (tblscan, SIZEOF_LINETBL_DELTA, GET_UNSIGNED, + current_objfile); + tblscan += SIZEOF_LINETBL_DELTA; + pc += base; + if (line != 0) + { + record_line (current_subfile, line, pc); + } + } + } +} + +/* + +LOCAL FUNCTION + + locval -- compute the value of a location attribute + +SYNOPSIS + + static int locval (char *loc) + +DESCRIPTION + + Given pointer to a string of bytes that define a location, compute + the location and return the value. + + When computing values involving the current value of the frame pointer, + the value zero is used, which results in a value relative to the frame + pointer, rather than the absolute value. This is what GDB wants + anyway. + + When the result is a register number, the global isreg flag is set, + otherwise it is cleared. This is a kludge until we figure out a better + way to handle the problem. Gdb's design does not mesh well with the + DWARF notion of a location computing interpreter, which is a shame + because the flexibility goes unused. + +NOTES + + Note that stack[0] is unused except as a default error return. + Note that stack overflow is not yet handled. + */ + +static int +locval (loc) + char *loc; +{ + unsigned short nbytes; + unsigned short locsize; + auto long stack[64]; + int stacki; + char *end; + int loc_atom_code; + int loc_value_size; + + nbytes = attribute_size (AT_location); + locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile); + loc += nbytes; + end = loc + locsize; + stacki = 0; + stack[stacki] = 0; + isreg = 0; + offreg = 0; + loc_value_size = TARGET_FT_LONG_SIZE (current_objfile); + while (loc < end) + { + loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED, + current_objfile); + loc += SIZEOF_LOC_ATOM_CODE; + switch (loc_atom_code) + { + case 0: + /* error */ + loc = end; + break; + case OP_REG: + /* push register (number) */ + stack[++stacki] = target_to_host (loc, loc_value_size, + GET_UNSIGNED, current_objfile); + loc += loc_value_size; + isreg = 1; + break; + case OP_BASEREG: + /* push value of register (number) */ + /* Actually, we compute the value as if register has 0, so the + value ends up being the offset from that register. */ + offreg = 1; + basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED, + current_objfile); + loc += loc_value_size; + stack[++stacki] = 0; + break; + case OP_ADDR: + /* push address (relocated address) */ + stack[++stacki] = target_to_host (loc, loc_value_size, + GET_UNSIGNED, current_objfile); + loc += loc_value_size; + break; + case OP_CONST: + /* push constant (number) FIXME: signed or unsigned! */ + stack[++stacki] = target_to_host (loc, loc_value_size, + GET_SIGNED, current_objfile); + loc += loc_value_size; + break; + case OP_DEREF2: + /* pop, deref and push 2 bytes (as a long) */ + complain (&op_deref2, DIE_ID, DIE_NAME, stack[stacki]); + break; + case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */ + complain (&op_deref4, DIE_ID, DIE_NAME, stack[stacki]); + break; + case OP_ADD: /* pop top 2 items, add, push result */ + stack[stacki - 1] += stack[stacki]; + stacki--; + break; + } + } + return (stack[stacki]); +} + +/* + +LOCAL FUNCTION + + read_ofile_symtab -- build a full symtab entry from chunk of DIE's + +SYNOPSIS + + static void read_ofile_symtab (struct partial_symtab *pst) + +DESCRIPTION + + When expanding a partial symbol table entry to a full symbol table + entry, this is the function that gets called to read in the symbols + for the compilation unit. A pointer to the newly constructed symtab, + which is now the new first one on the objfile's symtab list, is + stashed in the partial symbol table entry. + */ + +static void +read_ofile_symtab (pst) + struct partial_symtab *pst; +{ + struct cleanup *back_to; + unsigned long lnsize; + file_ptr foffset; + bfd *abfd; + char lnsizedata[SIZEOF_LINETBL_LENGTH]; + + abfd = pst -> objfile -> obfd; + current_objfile = pst -> objfile; + + /* Allocate a buffer for the entire chunk of DIE's for this compilation + unit, seek to the location in the file, and read in all the DIE's. */ + + diecount = 0; + dbsize = DBLENGTH (pst); + dbbase = xmalloc (dbsize); + dbroff = DBROFF(pst); + foffset = DBFOFF(pst) + dbroff; + base_section_offsets = pst->section_offsets; + baseaddr = ANOFFSET (pst->section_offsets, 0); + if (bfd_seek (abfd, foffset, L_SET) || + (bfd_read (dbbase, dbsize, 1, abfd) != dbsize)) + { + free (dbbase); + error ("can't read DWARF data"); + } + back_to = make_cleanup (free, dbbase); + + /* If there is a line number table associated with this compilation unit + then read the size of this fragment in bytes, from the fragment itself. + Allocate a buffer for the fragment and read it in for future + processing. */ + + lnbase = NULL; + if (LNFOFF (pst)) + { + if (bfd_seek (abfd, LNFOFF (pst), L_SET) || + (bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) != + sizeof (lnsizedata))) + { + error ("can't read DWARF line number table size"); + } + lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH, + GET_UNSIGNED, pst -> objfile); + lnbase = xmalloc (lnsize); + if (bfd_seek (abfd, LNFOFF (pst), L_SET) || + (bfd_read (lnbase, lnsize, 1, abfd) != lnsize)) + { + free (lnbase); + error ("can't read DWARF line numbers"); + } + make_cleanup (free, lnbase); + } + + process_dies (dbbase, dbbase + dbsize, pst -> objfile); + do_cleanups (back_to); + current_objfile = NULL; + pst -> symtab = pst -> objfile -> symtabs; +} + +/* + +LOCAL FUNCTION + + psymtab_to_symtab_1 -- do grunt work for building a full symtab entry + +SYNOPSIS + + static void psymtab_to_symtab_1 (struct partial_symtab *pst) + +DESCRIPTION + + Called once for each partial symbol table entry that needs to be + expanded into a full symbol table entry. + +*/ + +static void +psymtab_to_symtab_1 (pst) + struct partial_symtab *pst; +{ + int i; + struct cleanup *old_chain; + + if (pst != NULL) + { + if (pst->readin) + { + warning ("psymtab for %s already read in. Shouldn't happen.", + pst -> filename); + } + else + { + /* Read in all partial symtabs on which this one is dependent */ + for (i = 0; i < pst -> number_of_dependencies; i++) + { + if (!pst -> dependencies[i] -> readin) + { + /* Inform about additional files that need to be read in. */ + if (info_verbose) + { + fputs_filtered (" ", stdout); + wrap_here (""); + fputs_filtered ("and ", stdout); + wrap_here (""); + printf_filtered ("%s...", + pst -> dependencies[i] -> filename); + wrap_here (""); + fflush (stdout); /* Flush output */ + } + psymtab_to_symtab_1 (pst -> dependencies[i]); + } + } + if (DBLENGTH (pst)) /* Otherwise it's a dummy */ + { + buildsym_init (); + old_chain = make_cleanup (really_free_pendings, 0); + read_ofile_symtab (pst); + if (info_verbose) + { + printf_filtered ("%d DIE's, sorting...", diecount); + wrap_here (""); + fflush (stdout); + } + sort_symtab_syms (pst -> symtab); + do_cleanups (old_chain); + } + pst -> readin = 1; + } + } +} + +/* + +LOCAL FUNCTION + + dwarf_psymtab_to_symtab -- build a full symtab entry from partial one + +SYNOPSIS + + static void dwarf_psymtab_to_symtab (struct partial_symtab *pst) + +DESCRIPTION + + This is the DWARF support entry point for building a full symbol + table entry from a partial symbol table entry. We are passed a + pointer to the partial symbol table entry that needs to be expanded. + +*/ + +static void +dwarf_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + + if (pst != NULL) + { + if (pst -> readin) + { + warning ("psymtab for %s already read in. Shouldn't happen.", + pst -> filename); + } + else + { + if (DBLENGTH (pst) || pst -> number_of_dependencies) + { + /* Print the message now, before starting serious work, to avoid + disconcerting pauses. */ + if (info_verbose) + { + printf_filtered ("Reading in symbols for %s...", + pst -> filename); + fflush (stdout); + } + + psymtab_to_symtab_1 (pst); + +#if 0 /* FIXME: Check to see what dbxread is doing here and see if + we need to do an equivalent or is this something peculiar to + stabs/a.out format. + Match with global symbols. This only needs to be done once, + after all of the symtabs and dependencies have been read in. + */ + scan_file_globals (pst -> objfile); +#endif + + /* Finish up the verbose info message. */ + if (info_verbose) + { + printf_filtered ("done.\n"); + fflush (stdout); + } + } + } + } +} + +/* + +LOCAL FUNCTION + + init_psymbol_list -- initialize storage for partial symbols + +SYNOPSIS + + static void init_psymbol_list (struct objfile *objfile, int total_symbols) + +DESCRIPTION + + Initializes storage for all of the partial symbols that will be + created by dwarf_build_psymtabs and subsidiaries. + */ + +static void +init_psymbol_list (objfile, total_symbols) + struct objfile *objfile; + int total_symbols; +{ + /* Free any previously allocated psymbol lists. */ + + if (objfile -> global_psymbols.list) + { + mfree (objfile -> md, (PTR)objfile -> global_psymbols.list); + } + if (objfile -> static_psymbols.list) + { + mfree (objfile -> md, (PTR)objfile -> static_psymbols.list); + } + + /* Current best guess is that there are approximately a twentieth + of the total symbols (in a debugging file) are global or static + oriented symbols */ + + objfile -> global_psymbols.size = total_symbols / 10; + objfile -> static_psymbols.size = total_symbols / 10; + objfile -> global_psymbols.next = + objfile -> global_psymbols.list = (struct partial_symbol *) + xmmalloc (objfile -> md, objfile -> global_psymbols.size + * sizeof (struct partial_symbol)); + objfile -> static_psymbols.next = + objfile -> static_psymbols.list = (struct partial_symbol *) + xmmalloc (objfile -> md, objfile -> static_psymbols.size + * sizeof (struct partial_symbol)); +} + +/* + +LOCAL FUNCTION + + add_enum_psymbol -- add enumeration members to partial symbol table + +DESCRIPTION + + Given pointer to a DIE that is known to be for an enumeration, + extract the symbolic names of the enumeration members and add + partial symbols for them. +*/ + +static void +add_enum_psymbol (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + char *scan; + char *listend; + unsigned short blocksz; + int nbytes; + + if ((scan = dip -> at_element_list) != NULL) + { + if (dip -> short_element_list) + { + nbytes = attribute_size (AT_short_element_list); + } + else + { + nbytes = attribute_size (AT_element_list); + } + blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile); + scan += nbytes; + listend = scan + blocksz; + while (scan < listend) + { + scan += TARGET_FT_LONG_SIZE (objfile); + ADD_PSYMBOL_TO_LIST (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST, + objfile -> static_psymbols, 0, cu_language, + objfile); + scan += strlen (scan) + 1; + } + } +} + +/* + +LOCAL FUNCTION + + add_partial_symbol -- add symbol to partial symbol table + +DESCRIPTION + + Given a DIE, if it is one of the types that we want to + add to a partial symbol table, finish filling in the die info + and then add a partial symbol table entry for it. + +NOTES + + The caller must ensure that the DIE has a valid name attribute. +*/ + +static void +add_partial_symbol (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + switch (dip -> die_tag) + { + case TAG_global_subroutine: + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_BLOCK, + objfile -> global_psymbols, + dip -> at_low_pc, cu_language, objfile); + break; + case TAG_global_variable: + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_STATIC, + objfile -> global_psymbols, + 0, cu_language, objfile); + break; + case TAG_subroutine: + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_BLOCK, + objfile -> static_psymbols, + dip -> at_low_pc, cu_language, objfile); + break; + case TAG_local_variable: + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_STATIC, + objfile -> static_psymbols, + 0, cu_language, objfile); + break; + case TAG_typedef: + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_TYPEDEF, + objfile -> static_psymbols, + 0, cu_language, objfile); + break; + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + case TAG_enumeration_type: + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + STRUCT_NAMESPACE, LOC_TYPEDEF, + objfile -> static_psymbols, + 0, cu_language, objfile); + if (cu_language == language_cplus) + { + /* For C++, these implicitly act as typedefs as well. */ + ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_TYPEDEF, + objfile -> static_psymbols, + 0, cu_language, objfile); + } + break; + } +} + +/* + +LOCAL FUNCTION + + scan_partial_symbols -- scan DIE's within a single compilation unit + +DESCRIPTION + + Process the DIE's within a single compilation unit, looking for + interesting DIE's that contribute to the partial symbol table entry + for this compilation unit. + +NOTES + + There are some DIE's that may appear both at file scope and within + the scope of a function. We are only interested in the ones at file + scope, and the only way to tell them apart is to keep track of the + scope. For example, consider the test case: + + static int i; + main () { int j; } + + for which the relevant DWARF segment has the structure: + + 0x51: + 0x23 global subrtn sibling 0x9b + name main + fund_type FT_integer + low_pc 0x800004cc + high_pc 0x800004d4 + + 0x74: + 0x23 local var sibling 0x97 + name j + fund_type FT_integer + location OP_BASEREG 0xe + OP_CONST 0xfffffffc + OP_ADD + 0x97: + 0x4 + + 0x9b: + 0x1d local var sibling 0xb8 + name i + fund_type FT_integer + location OP_ADDR 0x800025dc + + 0xb8: + 0x4 + + We want to include the symbol 'i' in the partial symbol table, but + not the symbol 'j'. In essence, we want to skip all the dies within + the scope of a TAG_global_subroutine DIE. + + Don't attempt to add anonymous structures or unions since they have + no name. Anonymous enumerations however are processed, because we + want to extract their member names (the check for a tag name is + done later). + + Also, for variables and subroutines, check that this is the place + where the actual definition occurs, rather than just a reference + to an external. + */ + +static void +scan_partial_symbols (thisdie, enddie, objfile) + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + char *nextdie; + char *temp; + struct dieinfo di; + + while (thisdie < enddie) + { + basicdieinfo (&di, thisdie, objfile); + if (di.die_length < SIZEOF_DIE_LENGTH) + { + break; + } + else + { + nextdie = thisdie + di.die_length; + /* To avoid getting complete die information for every die, we + only do it (below) for the cases we are interested in. */ + switch (di.die_tag) + { + case TAG_global_subroutine: + case TAG_subroutine: + completedieinfo (&di, objfile); + if (di.at_name && (di.has_at_low_pc || di.at_location)) + { + add_partial_symbol (&di, objfile); + /* If there is a sibling attribute, adjust the nextdie + pointer to skip the entire scope of the subroutine. + Apply some sanity checking to make sure we don't + overrun or underrun the range of remaining DIE's */ + if (di.at_sibling != 0) + { + temp = dbbase + di.at_sibling - dbroff; + if ((temp < thisdie) || (temp >= enddie)) + { + complain (&bad_die_ref, DIE_ID, DIE_NAME, + di.at_sibling); + } + else + { + nextdie = temp; + } + } + } + break; + case TAG_global_variable: + case TAG_local_variable: + completedieinfo (&di, objfile); + if (di.at_name && (di.has_at_low_pc || di.at_location)) + { + add_partial_symbol (&di, objfile); + } + break; + case TAG_typedef: + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + completedieinfo (&di, objfile); + if (di.at_name) + { + add_partial_symbol (&di, objfile); + } + break; + case TAG_enumeration_type: + completedieinfo (&di, objfile); + if (di.at_name) + { + add_partial_symbol (&di, objfile); + } + add_enum_psymbol (&di, objfile); + break; + } + } + thisdie = nextdie; + } +} + +/* + +LOCAL FUNCTION + + scan_compilation_units -- build a psymtab entry for each compilation + +DESCRIPTION + + This is the top level dwarf parsing routine for building partial + symbol tables. + + It scans from the beginning of the DWARF table looking for the first + TAG_compile_unit DIE, and then follows the sibling chain to locate + each additional TAG_compile_unit DIE. + + For each TAG_compile_unit DIE it creates a partial symtab structure, + calls a subordinate routine to collect all the compilation unit's + global DIE's, file scope DIEs, typedef DIEs, etc, and then links the + new partial symtab structure into the partial symbol table. It also + records the appropriate information in the partial symbol table entry + to allow the chunk of DIE's and line number table for this compilation + unit to be located and re-read later, to generate a complete symbol + table entry for the compilation unit. + + Thus it effectively partitions up a chunk of DIE's for multiple + compilation units into smaller DIE chunks and line number tables, + and associates them with a partial symbol table entry. + +NOTES + + If any compilation unit has no line number table associated with + it for some reason (a missing at_stmt_list attribute, rather than + just one with a value of zero, which is valid) then we ensure that + the recorded file offset is zero so that the routine which later + reads line number table fragments knows that there is no fragment + to read. + +RETURNS + + Returns no value. + + */ + +static void +scan_compilation_units (thisdie, enddie, dbfoff, lnoffset, objfile) + char *thisdie; + char *enddie; + file_ptr dbfoff; + file_ptr lnoffset; + struct objfile *objfile; +{ + char *nextdie; + struct dieinfo di; + struct partial_symtab *pst; + int culength; + int curoff; + file_ptr curlnoffset; + + while (thisdie < enddie) + { + basicdieinfo (&di, thisdie, objfile); + if (di.die_length < SIZEOF_DIE_LENGTH) + { + break; + } + else if (di.die_tag != TAG_compile_unit) + { + nextdie = thisdie + di.die_length; + } + else + { + completedieinfo (&di, objfile); + set_cu_language (&di); + if (di.at_sibling != 0) + { + nextdie = dbbase + di.at_sibling - dbroff; + } + else + { + nextdie = thisdie + di.die_length; + } + curoff = thisdie - dbbase; + culength = nextdie - thisdie; + curlnoffset = di.has_at_stmt_list ? lnoffset + di.at_stmt_list : 0; + + /* First allocate a new partial symbol table structure */ + + pst = start_psymtab_common (objfile, base_section_offsets, + di.at_name, di.at_low_pc, + objfile -> global_psymbols.next, + objfile -> static_psymbols.next); + + pst -> texthigh = di.at_high_pc; + pst -> read_symtab_private = (char *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct dwfinfo)); + DBFOFF (pst) = dbfoff; + DBROFF (pst) = curoff; + DBLENGTH (pst) = culength; + LNFOFF (pst) = curlnoffset; + pst -> read_symtab = dwarf_psymtab_to_symtab; + + /* Now look for partial symbols */ + + scan_partial_symbols (thisdie + di.die_length, nextdie, objfile); + + pst -> n_global_syms = objfile -> global_psymbols.next - + (objfile -> global_psymbols.list + pst -> globals_offset); + pst -> n_static_syms = objfile -> static_psymbols.next - + (objfile -> static_psymbols.list + pst -> statics_offset); + sort_pst_symbols (pst); + /* If there is already a psymtab or symtab for a file of this name, + remove it. (If there is a symtab, more drastic things also + happen.) This happens in VxWorks. */ + free_named_symtabs (pst -> filename); + } + thisdie = nextdie; + } +} + +/* + +LOCAL FUNCTION + + new_symbol -- make a symbol table entry for a new symbol + +SYNOPSIS + + static struct symbol *new_symbol (struct dieinfo *dip, + struct objfile *objfile) + +DESCRIPTION + + Given a pointer to a DWARF information entry, figure out if we need + to make a symbol table entry for it, and if so, create a new entry + and return a pointer to it. + */ + +static struct symbol * +new_symbol (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + struct symbol *sym = NULL; + + if (dip -> at_name != NULL) + { + sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack, + sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = create_name (dip -> at_name, + &objfile->symbol_obstack); + /* default assumptions */ + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_TYPE (sym) = decode_die_type (dip); + + /* If this symbol is from a C++ compilation, then attempt to cache the + demangled form for future reference. This is a typical time versus + space tradeoff, that was decided in favor of time because it sped up + C++ symbol lookups by a factor of about 20. */ + + SYMBOL_LANGUAGE (sym) = cu_language; + SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile -> symbol_obstack); + switch (dip -> die_tag) + { + case TAG_label: + SYMBOL_VALUE (sym) = dip -> at_low_pc; + SYMBOL_CLASS (sym) = LOC_LABEL; + break; + case TAG_global_subroutine: + case TAG_subroutine: + SYMBOL_VALUE (sym) = dip -> at_low_pc; + SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym)); + SYMBOL_CLASS (sym) = LOC_BLOCK; + if (dip -> die_tag == TAG_global_subroutine) + { + add_symbol_to_list (sym, &global_symbols); + } + else + { + add_symbol_to_list (sym, list_in_scope); + } + break; + case TAG_global_variable: + if (dip -> at_location != NULL) + { + SYMBOL_VALUE (sym) = locval (dip -> at_location); + add_symbol_to_list (sym, &global_symbols); + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) += baseaddr; + } + break; + case TAG_local_variable: + if (dip -> at_location != NULL) + { + SYMBOL_VALUE (sym) = locval (dip -> at_location); + add_symbol_to_list (sym, list_in_scope); + if (isreg) + { + SYMBOL_CLASS (sym) = LOC_REGISTER; + } + else if (offreg) + { + SYMBOL_CLASS (sym) = LOC_BASEREG; + SYMBOL_BASEREG (sym) = basereg; + } + else + { + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) += baseaddr; + } + } + break; + case TAG_formal_parameter: + if (dip -> at_location != NULL) + { + SYMBOL_VALUE (sym) = locval (dip -> at_location); + } + add_symbol_to_list (sym, list_in_scope); + if (isreg) + { + SYMBOL_CLASS (sym) = LOC_REGPARM; + } + else if (offreg) + { + SYMBOL_CLASS (sym) = LOC_BASEREG_ARG; + SYMBOL_BASEREG (sym) = basereg; + } + else + { + SYMBOL_CLASS (sym) = LOC_ARG; + } + break; + case TAG_unspecified_parameters: + /* From varargs functions; gdb doesn't seem to have any interest in + this information, so just ignore it for now. (FIXME?) */ + break; + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + case TAG_enumeration_type: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + add_symbol_to_list (sym, list_in_scope); + break; + case TAG_typedef: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, list_in_scope); + break; + default: + /* Not a tag we recognize. Hopefully we aren't processing trash + data, but since we must specifically ignore things we don't + recognize, there is nothing else we should do at this point. */ + break; + } + } + return (sym); +} + +/* + +LOCAL FUNCTION + + synthesize_typedef -- make a symbol table entry for a "fake" typedef + +SYNOPSIS + + static void synthesize_typedef (struct dieinfo *dip, + struct objfile *objfile, + struct type *type); + +DESCRIPTION + + Given a pointer to a DWARF information entry, synthesize a typedef + for the name in the DIE, using the specified type. + + This is used for C++ class, structs, unions, and enumerations to + set up the tag name as a type. + + */ + +static void +synthesize_typedef (dip, objfile, type) + struct dieinfo *dip; + struct objfile *objfile; + struct type *type; +{ + struct symbol *sym = NULL; + + if (dip -> at_name != NULL) + { + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = create_name (dip -> at_name, + &objfile->symbol_obstack); + SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language); + SYMBOL_TYPE (sym) = type; + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, list_in_scope); + } +} + +/* + +LOCAL FUNCTION + + decode_mod_fund_type -- decode a modified fundamental type + +SYNOPSIS + + static struct type *decode_mod_fund_type (char *typedata) + +DESCRIPTION + + Decode a block of data containing a modified fundamental + type specification. TYPEDATA is a pointer to the block, + which starts with a length containing the size of the rest + of the block. At the end of the block is a fundmental type + code value that gives the fundamental type. Everything + in between are type modifiers. + + We simply compute the number of modifiers and call the general + function decode_modified_type to do the actual work. +*/ + +static struct type * +decode_mod_fund_type (typedata) + char *typedata; +{ + struct type *typep = NULL; + unsigned short modcount; + int nbytes; + + /* Get the total size of the block, exclusive of the size itself */ + + nbytes = attribute_size (AT_mod_fund_type); + modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile); + typedata += nbytes; + + /* Deduct the size of the fundamental type bytes at the end of the block. */ + + modcount -= attribute_size (AT_fund_type); + + /* Now do the actual decoding */ + + typep = decode_modified_type (typedata, modcount, AT_mod_fund_type); + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_mod_u_d_type -- decode a modified user defined type + +SYNOPSIS + + static struct type *decode_mod_u_d_type (char *typedata) + +DESCRIPTION + + Decode a block of data containing a modified user defined + type specification. TYPEDATA is a pointer to the block, + which consists of a two byte length, containing the size + of the rest of the block. At the end of the block is a + four byte value that gives a reference to a user defined type. + Everything in between are type modifiers. + + We simply compute the number of modifiers and call the general + function decode_modified_type to do the actual work. +*/ + +static struct type * +decode_mod_u_d_type (typedata) + char *typedata; +{ + struct type *typep = NULL; + unsigned short modcount; + int nbytes; + + /* Get the total size of the block, exclusive of the size itself */ + + nbytes = attribute_size (AT_mod_u_d_type); + modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile); + typedata += nbytes; + + /* Deduct the size of the reference type bytes at the end of the block. */ + + modcount -= attribute_size (AT_user_def_type); + + /* Now do the actual decoding */ + + typep = decode_modified_type (typedata, modcount, AT_mod_u_d_type); + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_modified_type -- decode modified user or fundamental type + +SYNOPSIS + + static struct type *decode_modified_type (char *modifiers, + unsigned short modcount, int mtype) + +DESCRIPTION + + Decode a modified type, either a modified fundamental type or + a modified user defined type. MODIFIERS is a pointer to the + block of bytes that define MODCOUNT modifiers. Immediately + following the last modifier is a short containing the fundamental + type or a long containing the reference to the user defined + type. Which one is determined by MTYPE, which is either + AT_mod_fund_type or AT_mod_u_d_type to indicate what modified + type we are generating. + + We call ourself recursively to generate each modified type,` + until MODCOUNT reaches zero, at which point we have consumed + all the modifiers and generate either the fundamental type or + user defined type. When the recursion unwinds, each modifier + is applied in turn to generate the full modified type. + +NOTES + + If we find a modifier that we don't recognize, and it is not one + of those reserved for application specific use, then we issue a + warning and simply ignore the modifier. + +BUGS + + We currently ignore MOD_const and MOD_volatile. (FIXME) + + */ + +static struct type * +decode_modified_type (modifiers, modcount, mtype) + char *modifiers; + unsigned int modcount; + int mtype; +{ + struct type *typep = NULL; + unsigned short fundtype; + DIE_REF die_ref; + char modifier; + int nbytes; + + if (modcount == 0) + { + switch (mtype) + { + case AT_mod_fund_type: + nbytes = attribute_size (AT_fund_type); + fundtype = target_to_host (modifiers, nbytes, GET_UNSIGNED, + current_objfile); + typep = decode_fund_type (fundtype); + break; + case AT_mod_u_d_type: + nbytes = attribute_size (AT_user_def_type); + die_ref = target_to_host (modifiers, nbytes, GET_UNSIGNED, + current_objfile); + if ((typep = lookup_utype (die_ref)) == NULL) + { + typep = alloc_utype (die_ref, NULL); + } + break; + default: + complain (&botched_modified_type, DIE_ID, DIE_NAME, mtype); + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + break; + } + } + else + { + modifier = *modifiers++; + typep = decode_modified_type (modifiers, --modcount, mtype); + switch (modifier) + { + case MOD_pointer_to: + typep = lookup_pointer_type (typep); + break; + case MOD_reference_to: + typep = lookup_reference_type (typep); + break; + case MOD_const: + complain (&const_ignored, DIE_ID, DIE_NAME); /* FIXME */ + break; + case MOD_volatile: + complain (&volatile_ignored, DIE_ID, DIE_NAME); /* FIXME */ + break; + default: + if (!(MOD_lo_user <= (unsigned char) modifier + && (unsigned char) modifier <= MOD_hi_user)) + { + complain (&unknown_type_modifier, DIE_ID, DIE_NAME, modifier); + } + break; + } + } + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_fund_type -- translate basic DWARF type to gdb base type + +DESCRIPTION + + Given an integer that is one of the fundamental DWARF types, + translate it to one of the basic internal gdb types and return + a pointer to the appropriate gdb type (a "struct type *"). + +NOTES + + For robustness, if we are asked to translate a fundamental + type that we are unprepared to deal with, we return int so + callers can always depend upon a valid type being returned, + and so gdb may at least do something reasonable by default. + If the type is not in the range of those types defined as + application specific types, we also issue a warning. +*/ + +static struct type * +decode_fund_type (fundtype) + unsigned int fundtype; +{ + struct type *typep = NULL; + + switch (fundtype) + { + + case FT_void: + typep = dwarf_fundamental_type (current_objfile, FT_VOID); + break; + + case FT_boolean: /* Was FT_set in AT&T version */ + typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN); + break; + + case FT_pointer: /* (void *) */ + typep = dwarf_fundamental_type (current_objfile, FT_VOID); + typep = lookup_pointer_type (typep); + break; + + case FT_char: + typep = dwarf_fundamental_type (current_objfile, FT_CHAR); + break; + + case FT_signed_char: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR); + break; + + case FT_unsigned_char: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR); + break; + + case FT_short: + typep = dwarf_fundamental_type (current_objfile, FT_SHORT); + break; + + case FT_signed_short: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT); + break; + + case FT_unsigned_short: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT); + break; + + case FT_integer: + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + break; + + case FT_signed_integer: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER); + break; + + case FT_unsigned_integer: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER); + break; + + case FT_long: + typep = dwarf_fundamental_type (current_objfile, FT_LONG); + break; + + case FT_signed_long: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG); + break; + + case FT_unsigned_long: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG); + break; + + case FT_long_long: + typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG); + break; + + case FT_signed_long_long: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG); + break; + + case FT_unsigned_long_long: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG); + break; + + case FT_float: + typep = dwarf_fundamental_type (current_objfile, FT_FLOAT); + break; + + case FT_dbl_prec_float: + typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT); + break; + + case FT_ext_prec_float: + typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT); + break; + + case FT_complex: + typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX); + break; + + case FT_dbl_prec_complex: + typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX); + break; + + case FT_ext_prec_complex: + typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX); + break; + + } + + if (typep == NULL) + { + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user)) + { + complain (&unexpected_fund_type, DIE_ID, DIE_NAME, fundtype); + } + } + + return (typep); +} + +/* + +LOCAL FUNCTION + + create_name -- allocate a fresh copy of a string on an obstack + +DESCRIPTION + + Given a pointer to a string and a pointer to an obstack, allocates + a fresh copy of the string on the specified obstack. + +*/ + +static char * +create_name (name, obstackp) + char *name; + struct obstack *obstackp; +{ + int length; + char *newname; + + length = strlen (name) + 1; + newname = (char *) obstack_alloc (obstackp, length); + strcpy (newname, name); + return (newname); +} + +/* + +LOCAL FUNCTION + + basicdieinfo -- extract the minimal die info from raw die data + +SYNOPSIS + + void basicdieinfo (char *diep, struct dieinfo *dip, + struct objfile *objfile) + +DESCRIPTION + + Given a pointer to raw DIE data, and a pointer to an instance of a + die info structure, this function extracts the basic information + from the DIE data required to continue processing this DIE, along + with some bookkeeping information about the DIE. + + The information we absolutely must have includes the DIE tag, + and the DIE length. If we need the sibling reference, then we + will have to call completedieinfo() to process all the remaining + DIE information. + + Note that since there is no guarantee that the data is properly + aligned in memory for the type of access required (indirection + through anything other than a char pointer), and there is no + guarantee that it is in the same byte order as the gdb host, + we call a function which deals with both alignment and byte + swapping issues. Possibly inefficient, but quite portable. + + We also take care of some other basic things at this point, such + as ensuring that the instance of the die info structure starts + out completely zero'd and that curdie is initialized for use + in error reporting if we have a problem with the current die. + +NOTES + + All DIE's must have at least a valid length, thus the minimum + DIE size is SIZEOF_DIE_LENGTH. In order to have a valid tag, the + DIE size must be at least SIZEOF_DIE_TAG larger, otherwise they + are forced to be TAG_padding DIES. + + Padding DIES must be at least SIZEOF_DIE_LENGTH in length, implying + that if a padding DIE is used for alignment and the amount needed is + less than SIZEOF_DIE_LENGTH, then the padding DIE has to be big + enough to align to the next alignment boundry. + + We do some basic sanity checking here, such as verifying that the + length of the die would not cause it to overrun the recorded end of + the buffer holding the DIE info. If we find a DIE that is either + too small or too large, we force it's length to zero which should + cause the caller to take appropriate action. + */ + +static void +basicdieinfo (dip, diep, objfile) + struct dieinfo *dip; + char *diep; + struct objfile *objfile; +{ + curdie = dip; + memset (dip, 0, sizeof (struct dieinfo)); + dip -> die = diep; + dip -> die_ref = dbroff + (diep - dbbase); + dip -> die_length = target_to_host (diep, SIZEOF_DIE_LENGTH, GET_UNSIGNED, + objfile); + if ((dip -> die_length < SIZEOF_DIE_LENGTH) || + ((diep + dip -> die_length) > (dbbase + dbsize))) + { + complain (&malformed_die, DIE_ID, DIE_NAME, dip -> die_length); + dip -> die_length = 0; + } + else if (dip -> die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG)) + { + dip -> die_tag = TAG_padding; + } + else + { + diep += SIZEOF_DIE_LENGTH; + dip -> die_tag = target_to_host (diep, SIZEOF_DIE_TAG, GET_UNSIGNED, + objfile); + } +} + +/* + +LOCAL FUNCTION + + completedieinfo -- finish reading the information for a given DIE + +SYNOPSIS + + void completedieinfo (struct dieinfo *dip, struct objfile *objfile) + +DESCRIPTION + + Given a pointer to an already partially initialized die info structure, + scan the raw DIE data and finish filling in the die info structure + from the various attributes found. + + Note that since there is no guarantee that the data is properly + aligned in memory for the type of access required (indirection + through anything other than a char pointer), and there is no + guarantee that it is in the same byte order as the gdb host, + we call a function which deals with both alignment and byte + swapping issues. Possibly inefficient, but quite portable. + +NOTES + + Each time we are called, we increment the diecount variable, which + keeps an approximate count of the number of dies processed for + each compilation unit. This information is presented to the user + if the info_verbose flag is set. + + */ + +static void +completedieinfo (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + char *diep; /* Current pointer into raw DIE data */ + char *end; /* Terminate DIE scan here */ + unsigned short attr; /* Current attribute being scanned */ + unsigned short form; /* Form of the attribute */ + int nbytes; /* Size of next field to read */ + + diecount++; + diep = dip -> die; + end = diep + dip -> die_length; + diep += SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG; + while (diep < end) + { + attr = target_to_host (diep, SIZEOF_ATTRIBUTE, GET_UNSIGNED, objfile); + diep += SIZEOF_ATTRIBUTE; + if ((nbytes = attribute_size (attr)) == -1) + { + complain (&unknown_attribute_length, DIE_ID, DIE_NAME); + diep = end; + continue; + } + switch (attr) + { + case AT_fund_type: + dip -> at_fund_type = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_ordering: + dip -> at_ordering = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_bit_offset: + dip -> at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_sibling: + dip -> at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_stmt_list: + dip -> at_stmt_list = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> has_at_stmt_list = 1; + break; + case AT_low_pc: + dip -> at_low_pc = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> at_low_pc += baseaddr; + dip -> has_at_low_pc = 1; + break; + case AT_high_pc: + dip -> at_high_pc = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> at_high_pc += baseaddr; + break; + case AT_language: + dip -> at_language = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_user_def_type: + dip -> at_user_def_type = target_to_host (diep, nbytes, + GET_UNSIGNED, objfile); + break; + case AT_byte_size: + dip -> at_byte_size = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> has_at_byte_size = 1; + break; + case AT_bit_size: + dip -> at_bit_size = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_member: + dip -> at_member = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_discr: + dip -> at_discr = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_location: + dip -> at_location = diep; + break; + case AT_mod_fund_type: + dip -> at_mod_fund_type = diep; + break; + case AT_subscr_data: + dip -> at_subscr_data = diep; + break; + case AT_mod_u_d_type: + dip -> at_mod_u_d_type = diep; + break; + case AT_element_list: + dip -> at_element_list = diep; + dip -> short_element_list = 0; + break; + case AT_short_element_list: + dip -> at_element_list = diep; + dip -> short_element_list = 1; + break; + case AT_discr_value: + dip -> at_discr_value = diep; + break; + case AT_string_length: + dip -> at_string_length = diep; + break; + case AT_name: + dip -> at_name = diep; + break; + case AT_comp_dir: + /* For now, ignore any "hostname:" portion, since gdb doesn't + know how to deal with it. (FIXME). */ + dip -> at_comp_dir = strrchr (diep, ':'); + if (dip -> at_comp_dir != NULL) + { + dip -> at_comp_dir++; + } + else + { + dip -> at_comp_dir = diep; + } + break; + case AT_producer: + dip -> at_producer = diep; + break; + case AT_start_scope: + dip -> at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_stride_size: + dip -> at_stride_size = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_src_info: + dip -> at_src_info = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_prototyped: + dip -> at_prototyped = diep; + break; + default: + /* Found an attribute that we are unprepared to handle. However + it is specifically one of the design goals of DWARF that + consumers should ignore unknown attributes. As long as the + form is one that we recognize (so we know how to skip it), + we can just ignore the unknown attribute. */ + break; + } + form = FORM_FROM_ATTR (attr); + switch (form) + { + case FORM_DATA2: + diep += 2; + break; + case FORM_DATA4: + case FORM_REF: + diep += 4; + break; + case FORM_DATA8: + diep += 8; + break; + case FORM_ADDR: + diep += TARGET_FT_POINTER_SIZE (objfile); + break; + case FORM_BLOCK2: + diep += 2 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile); + break; + case FORM_BLOCK4: + diep += 4 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile); + break; + case FORM_STRING: + diep += strlen (diep) + 1; + break; + default: + complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form); + diep = end; + break; + } + } +} + +/* + +LOCAL FUNCTION + + target_to_host -- swap in target data to host + +SYNOPSIS + + target_to_host (char *from, int nbytes, int signextend, + struct objfile *objfile) + +DESCRIPTION + + Given pointer to data in target format in FROM, a byte count for + the size of the data in NBYTES, a flag indicating whether or not + the data is signed in SIGNEXTEND, and a pointer to the current + objfile in OBJFILE, convert the data to host format and return + the converted value. + +NOTES + + FIXME: If we read data that is known to be signed, and expect to + use it as signed data, then we need to explicitly sign extend the + result until the bfd library is able to do this for us. + + */ + +static unsigned long +target_to_host (from, nbytes, signextend, objfile) + char *from; + int nbytes; + int signextend; /* FIXME: Unused */ + struct objfile *objfile; +{ + unsigned long rtnval; + + switch (nbytes) + { + case 8: + rtnval = bfd_get_64 (objfile -> obfd, (bfd_byte *) from); + break; + case 4: + rtnval = bfd_get_32 (objfile -> obfd, (bfd_byte *) from); + break; + case 2: + rtnval = bfd_get_16 (objfile -> obfd, (bfd_byte *) from); + break; + case 1: + rtnval = bfd_get_8 (objfile -> obfd, (bfd_byte *) from); + break; + default: + complain (&no_bfd_get_N, DIE_ID, DIE_NAME, nbytes); + rtnval = 0; + break; + } + return (rtnval); +} + +/* + +LOCAL FUNCTION + + attribute_size -- compute size of data for a DWARF attribute + +SYNOPSIS + + static int attribute_size (unsigned int attr) + +DESCRIPTION + + Given a DWARF attribute in ATTR, compute the size of the first + piece of data associated with this attribute and return that + size. + + Returns -1 for unrecognized attributes. + + */ + +static int +attribute_size (attr) + unsigned int attr; +{ + int nbytes; /* Size of next data for this attribute */ + unsigned short form; /* Form of the attribute */ + + form = FORM_FROM_ATTR (attr); + switch (form) + { + case FORM_STRING: /* A variable length field is next */ + nbytes = 0; + break; + case FORM_DATA2: /* Next 2 byte field is the data itself */ + case FORM_BLOCK2: /* Next 2 byte field is a block length */ + nbytes = 2; + break; + case FORM_DATA4: /* Next 4 byte field is the data itself */ + case FORM_BLOCK4: /* Next 4 byte field is a block length */ + case FORM_REF: /* Next 4 byte field is a DIE offset */ + nbytes = 4; + break; + case FORM_DATA8: /* Next 8 byte field is the data itself */ + nbytes = 8; + break; + case FORM_ADDR: /* Next field size is target sizeof(void *) */ + nbytes = TARGET_FT_POINTER_SIZE (objfile); + break; + default: + complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form); + nbytes = -1; + break; + } + return (nbytes); +} diff --git a/gnu/usr.bin/gdb/gdb/elf/common.h b/gnu/usr.bin/gdb/gdb/elf/common.h new file mode 100644 index 00000000000..cd708f1489c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/elf/common.h @@ -0,0 +1,216 @@ +/* ELF support for BFD. + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that are common to both the internal and external representations. + For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory) + and external (in-file) representations. */ + + +/* Fields in e_ident[] */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7F /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encoding */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 /* File version */ + +#define EI_PAD 7 /* Start of padding bytes */ + + +/* Values for e_type, which identifies the object file type */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOPROC 0xFF00 /* Processor-specific */ +#define ET_HIPROC 0xFFFF /* Processor-specific */ + +/* Values for e_machine, which identifies the architecture */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 */ +#define EM_HPPA 9 /* HP PA-RISC */ + + +/* Values for e_version */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ + +/* Values for program header, p_type field */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_LOPROC 0x70000000 /* Processor-specific */ +#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */ + +/* Program segment permissions, in program header p_flags field */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */ + +/* Values for section header, sh_type field */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program specific (private) data */ +#define SHT_SYMTAB 2 /* Link editing symbol table */ +#define SHT_STRTAB 3 /* A string table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* A symbol hash table */ +#define SHT_DYNAMIC 6 /* Information for dynamic linking */ +#define SHT_NOTE 7 /* Information that marks file */ +#define SHT_NOBITS 8 /* Section occupies no space in file */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Dynamic linking symbol table */ +#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */ +#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */ +#define SHT_LOUSER 0x80000000 /* Application-specific semantics */ +#define SHT_HIUSER 0x8FFFFFFF /* Application-specific semantics */ + +/* Values for section header, sh_flags field */ + +#define SHF_WRITE (1 << 0) /* Writable data during execution */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */ +#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */ + +/* Values of note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ + +/* Values of note segment descriptor types for object files. */ +/* (Only for hppa right now. Should this be moved elsewhere?) */ + +#define NT_VERSION 1 /* Contains a version string. */ + +/* These three macros disassemble and assemble a symbol table st_info field, + which contains the symbol binding and symbol type. The STB_ and STT_ + defines identify the binding and type. */ + +#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4) +#define ELF_ST_TYPE(val) ((val) & 0xF) +#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF)) + +#define STN_UNDEF 0 /* undefined symbol index */ + +#define STB_LOCAL 0 /* Symbol not visible outside obj */ +#define STB_GLOBAL 1 /* Symbol visible outside obj */ +#define STB_WEAK 2 /* Like globals, lower precedence */ +#define STB_LOPROC 13 /* Application-specific semantics */ +#define STB_HIPROC 15 /* Application-specific semantics */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol gives a file name */ +#define STT_LOPROC 13 /* Application-specific semantics */ +#define STT_HIPROC 15 /* Application-specific semantics */ + +/* Special section indices, which may show up in st_shndx fields, among + other places. */ + +#define SHN_UNDEF 0 /* Undefined section reference */ +#define SHN_LORESERV 0xFF00 /* Begin range of reserved indices */ +#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */ +#define SHN_HIPROC 0xFF1F /* End range of appl-specific */ +#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */ +#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */ + +/* relocation info handling macros */ + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((Elf64_Word)(i)) +#define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+(Elf64_Xword)(t)) + +/* Dynamic section tags */ + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff diff --git a/gnu/usr.bin/gdb/gdb/elf/dwarf.h b/gnu/usr.bin/gdb/gdb/elf/dwarf.h new file mode 100644 index 00000000000..bc9723ae04a --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/elf/dwarf.h @@ -0,0 +1,314 @@ +/* Declarations and definitions of codes relating to the DWARF symbolic + debugging information format. + + Written by Ron Guilmette (rfg@ncd.com) + +Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 1.0.1 (April 8, 1992) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. +*/ + +/* Tag names and codes. */ + +enum dwarf_tag { + TAG_padding = 0x0000, + TAG_array_type = 0x0001, + TAG_class_type = 0x0002, + TAG_entry_point = 0x0003, + TAG_enumeration_type = 0x0004, + TAG_formal_parameter = 0x0005, + TAG_global_subroutine = 0x0006, + TAG_global_variable = 0x0007, + /* 0x0008 -- reserved */ + /* 0x0009 -- reserved */ + TAG_label = 0x000a, + TAG_lexical_block = 0x000b, + TAG_local_variable = 0x000c, + TAG_member = 0x000d, + /* 0x000e -- reserved */ + TAG_pointer_type = 0x000f, + TAG_reference_type = 0x0010, + TAG_compile_unit = 0x0011, + TAG_string_type = 0x0012, + TAG_structure_type = 0x0013, + TAG_subroutine = 0x0014, + TAG_subroutine_type = 0x0015, + TAG_typedef = 0x0016, + TAG_union_type = 0x0017, + TAG_unspecified_parameters = 0x0018, + TAG_variant = 0x0019, + TAG_common_block = 0x001a, + TAG_common_inclusion = 0x001b, + TAG_inheritance = 0x001c, + TAG_inlined_subroutine = 0x001d, + TAG_module = 0x001e, + TAG_ptr_to_member_type = 0x001f, + TAG_set_type = 0x0020, + TAG_subrange_type = 0x0021, + TAG_with_stmt = 0x0022, + + /* GNU extensions */ + + TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */ + TAG_namelist = 0x8001, /* For Fortran 90 */ + TAG_function_template = 0x8002, /* for C++ */ + TAG_class_template = 0x8003 /* for C++ */ +}; + +#define TAG_lo_user 0x8000 /* implementation-defined range start */ +#define TAG_hi_user 0xffff /* implementation-defined range end */ +#define TAG_source_file TAG_compile_unit /* for backward compatibility */ + +/* Form names and codes. */ + +enum dwarf_form { + FORM_ADDR = 0x1, + FORM_REF = 0x2, + FORM_BLOCK2 = 0x3, + FORM_BLOCK4 = 0x4, + FORM_DATA2 = 0x5, + FORM_DATA4 = 0x6, + FORM_DATA8 = 0x7, + FORM_STRING = 0x8 +}; + +/* Attribute names and codes. */ + +enum dwarf_attribute { + AT_sibling = (0x0010|FORM_REF), + AT_location = (0x0020|FORM_BLOCK2), + AT_name = (0x0030|FORM_STRING), + AT_fund_type = (0x0050|FORM_DATA2), + AT_mod_fund_type = (0x0060|FORM_BLOCK2), + AT_user_def_type = (0x0070|FORM_REF), + AT_mod_u_d_type = (0x0080|FORM_BLOCK2), + AT_ordering = (0x0090|FORM_DATA2), + AT_subscr_data = (0x00a0|FORM_BLOCK2), + AT_byte_size = (0x00b0|FORM_DATA4), + AT_bit_offset = (0x00c0|FORM_DATA2), + AT_bit_size = (0x00d0|FORM_DATA4), + /* (0x00e0|FORM_xxxx) -- reserved */ + AT_element_list = (0x00f0|FORM_BLOCK4), + AT_stmt_list = (0x0100|FORM_DATA4), + AT_low_pc = (0x0110|FORM_ADDR), + AT_high_pc = (0x0120|FORM_ADDR), + AT_language = (0x0130|FORM_DATA4), + AT_member = (0x0140|FORM_REF), + AT_discr = (0x0150|FORM_REF), + AT_discr_value = (0x0160|FORM_BLOCK2), + /* (0x0170|FORM_xxxx) -- reserved */ + /* (0x0180|FORM_xxxx) -- reserved */ + AT_string_length = (0x0190|FORM_BLOCK2), + AT_common_reference = (0x01a0|FORM_REF), + AT_comp_dir = (0x01b0|FORM_STRING), + AT_const_value_string = (0x01c0|FORM_STRING), + AT_const_value_data2 = (0x01c0|FORM_DATA2), + AT_const_value_data4 = (0x01c0|FORM_DATA4), + AT_const_value_data8 = (0x01c0|FORM_DATA8), + AT_const_value_block2 = (0x01c0|FORM_BLOCK2), + AT_const_value_block4 = (0x01c0|FORM_BLOCK4), + AT_containing_type = (0x01d0|FORM_REF), + AT_default_value_addr = (0x01e0|FORM_ADDR), + AT_default_value_data2 = (0x01e0|FORM_DATA2), + AT_default_value_data4 = (0x01e0|FORM_DATA4), + AT_default_value_data8 = (0x01e0|FORM_DATA8), + AT_default_value_string = (0x01e0|FORM_STRING), + AT_friends = (0x01f0|FORM_BLOCK2), + AT_inline = (0x0200|FORM_STRING), + AT_is_optional = (0x0210|FORM_STRING), + AT_lower_bound_ref = (0x0220|FORM_REF), + AT_lower_bound_data2 = (0x0220|FORM_DATA2), + AT_lower_bound_data4 = (0x0220|FORM_DATA4), + AT_lower_bound_data8 = (0x0220|FORM_DATA8), + AT_private = (0x0240|FORM_STRING), + AT_producer = (0x0250|FORM_STRING), + AT_program = (0x0230|FORM_STRING), + AT_protected = (0x0260|FORM_STRING), + AT_prototyped = (0x0270|FORM_STRING), + AT_public = (0x0280|FORM_STRING), + AT_pure_virtual = (0x0290|FORM_STRING), + AT_return_addr = (0x02a0|FORM_BLOCK2), + AT_abstract_origin = (0x02b0|FORM_REF), + AT_start_scope = (0x02c0|FORM_DATA4), + AT_stride_size = (0x02e0|FORM_DATA4), + AT_upper_bound_ref = (0x02f0|FORM_REF), + AT_upper_bound_data2 = (0x02f0|FORM_DATA2), + AT_upper_bound_data4 = (0x02f0|FORM_DATA4), + AT_upper_bound_data8 = (0x02f0|FORM_DATA8), + AT_virtual = (0x0300|FORM_STRING), + + /* GNU extensions. */ + + AT_sf_names = (0x8000|FORM_DATA4), + AT_src_info = (0x8010|FORM_DATA4), + AT_mac_info = (0x8020|FORM_DATA4), + AT_src_coords = (0x8030|FORM_DATA4), + AT_body_begin = (0x8040|FORM_ADDR), + AT_body_end = (0x8050|FORM_ADDR) +}; + +#define AT_lo_user 0x8000 /* implementation-defined range start */ +#define AT_hi_user 0xffff /* implementation-defined range end */ + +/* Location atom names and codes. */ + +enum dwarf_location_atom { + OP_REG = 0x01, + OP_BASEREG = 0x02, + OP_ADDR = 0x03, + OP_CONST = 0x04, + OP_DEREF2 = 0x05, + OP_DEREF4 = 0x06, + OP_ADD = 0x07 +}; + +#define OP_LO_USER 0x80 /* implementation-defined range start */ +#define OP_HI_USER 0xff /* implementation-defined range end */ + +/* Fundamental type names and codes. */ + +enum dwarf_fundamental_type { + FT_char = 0x0001, + FT_signed_char = 0x0002, + FT_unsigned_char = 0x0003, + FT_short = 0x0004, + FT_signed_short = 0x0005, + FT_unsigned_short = 0x0006, + FT_integer = 0x0007, + FT_signed_integer = 0x0008, + FT_unsigned_integer = 0x0009, + FT_long = 0x000a, + FT_signed_long = 0x000b, + FT_unsigned_long = 0x000c, + FT_pointer = 0x000d, /* an alias for (void *) */ + FT_float = 0x000e, + FT_dbl_prec_float = 0x000f, + FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */ + FT_complex = 0x0011, /* breaks "classic" svr4 SDB */ + FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */ + /* 0x0013 -- reserved */ + FT_void = 0x0014, + FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */ + FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */ + FT_label = 0x0017, + + /* GNU extensions + The low order byte must indicate the size (in bytes) for the type. + All of these types will probably break "classic" svr4 SDB */ + + FT_long_long = 0x8008, + FT_signed_long_long = 0x8108, + FT_unsigned_long_long = 0x8208, + + FT_int8 = 0x9001, + FT_signed_int8 = 0x9101, + FT_unsigned_int8 = 0x9201, + FT_int16 = 0x9302, + FT_signed_int16 = 0x9402, + FT_unsigned_int16 = 0x9502, + FT_int32 = 0x9604, + FT_signed_int32 = 0x9704, + FT_unsigned_int32 = 0x9804, + FT_int64 = 0x9908, + FT_signed_int64 = 0x9a08, + FT_unsigned_int64 = 0x9b08, + + FT_real32 = 0xa004, + FT_real64 = 0xa108, + FT_real96 = 0xa20c, + FT_real128 = 0xa310 +}; + +#define FT_lo_user 0x8000 /* implementation-defined range start */ +#define FT_hi_user 0xffff /* implementation defined range end */ + +/* Type modifier names and codes. */ + +enum dwarf_type_modifier { + MOD_pointer_to = 0x01, + MOD_reference_to = 0x02, + MOD_const = 0x03, + MOD_volatile = 0x04 +}; + +#define MOD_lo_user 0x80 /* implementation-defined range start */ +#define MOD_hi_user 0xff /* implementation-defined range end */ + +/* Array ordering names and codes. */ + +enum dwarf_array_dim_ordering { + ORD_row_major = 0, + ORD_col_major = 1 +}; + +/* Array subscript format names and codes. */ + +enum dwarf_subscr_data_formats { + FMT_FT_C_C = 0x0, + FMT_FT_C_X = 0x1, + FMT_FT_X_C = 0x2, + FMT_FT_X_X = 0x3, + FMT_UT_C_C = 0x4, + FMT_UT_C_X = 0x5, + FMT_UT_X_C = 0x6, + FMT_UT_X_X = 0x7, + FMT_ET = 0x8 +}; + +/* Derived from above for ease of use. */ + +#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \ + (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \ + | ((_UB_CONST_P) ? 0 : 2) \ + | ((_LB_CONST_P) ? 0 : 1)) + +/* Source language names and codes. */ + +enum dwarf_source_language { + LANG_C89 = 0x00000001, + LANG_C = 0x00000002, + LANG_ADA83 = 0x00000003, + LANG_C_PLUS_PLUS = 0x00000004, + LANG_COBOL74 = 0x00000005, + LANG_COBOL85 = 0x00000006, + LANG_FORTRAN77 = 0x00000007, + LANG_FORTRAN90 = 0x00000008, + LANG_PASCAL83 = 0x00000009, + LANG_MODULA2 = 0x0000000a, + + /* GNU extensions */ + + LANG_CHILL = 0x00009af3 /* random value for GNU Chill */ +}; + +#define LANG_lo_user 0x00008000 /* implementation-defined range start */ +#define LANG_hi_user 0x0000ffff /* implementation-defined range end */ + +/* Names and codes for GNU "macinfo" extension. */ + +enum dwarf_macinfo_record_type { + MACINFO_start = 's', + MACINFO_resume = 'r', + MACINFO_define = 'd', + MACINFO_undef = 'u' +}; diff --git a/gnu/usr.bin/gdb/gdb/elf/external.h b/gnu/usr.bin/gdb/gdb/elf/external.h new file mode 100644 index 00000000000..f2ab63e1ede --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/elf/external.h @@ -0,0 +1,190 @@ +/* ELF support for BFD. + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that describe how ELF is represented externally by the BFD library. + I.E. it describes the in-file representation of ELF. It requires + the elf-common.h file which contains the portions that are common to + both the internal and external representations. */ + +/* The 64-bit stuff is kind of random. Perhaps someone will publish a + spec someday. */ + +/* ELF Header (32-bit implementations) */ + +typedef struct { + unsigned char e_ident[16]; /* ELF "magic number" */ + unsigned char e_type[2]; /* Identifies object file type */ + unsigned char e_machine[2]; /* Specifies required architecture */ + unsigned char e_version[4]; /* Identifies object file version */ + unsigned char e_entry[4]; /* Entry point virtual address */ + unsigned char e_phoff[4]; /* Program header table file offset */ + unsigned char e_shoff[4]; /* Section header table file offset */ + unsigned char e_flags[4]; /* Processor-specific flags */ + unsigned char e_ehsize[2]; /* ELF header size in bytes */ + unsigned char e_phentsize[2]; /* Program header table entry size */ + unsigned char e_phnum[2]; /* Program header table entry count */ + unsigned char e_shentsize[2]; /* Section header table entry size */ + unsigned char e_shnum[2]; /* Section header table entry count */ + unsigned char e_shstrndx[2]; /* Section header string table index */ +} Elf32_External_Ehdr; + +typedef struct { + unsigned char e_ident[16]; /* ELF "magic number" */ + unsigned char e_type[2]; /* Identifies object file type */ + unsigned char e_machine[2]; /* Specifies required architecture */ + unsigned char e_version[4]; /* Identifies object file version */ + unsigned char e_entry[8]; /* Entry point virtual address */ + unsigned char e_phoff[8]; /* Program header table file offset */ + unsigned char e_shoff[8]; /* Section header table file offset */ + unsigned char e_flags[4]; /* Processor-specific flags */ + unsigned char e_ehsize[2]; /* ELF header size in bytes */ + unsigned char e_phentsize[2]; /* Program header table entry size */ + unsigned char e_phnum[2]; /* Program header table entry count */ + unsigned char e_shentsize[2]; /* Section header table entry size */ + unsigned char e_shnum[2]; /* Section header table entry count */ + unsigned char e_shstrndx[2]; /* Section header string table index */ +} Elf64_External_Ehdr; + +/* Program header */ + +typedef struct { + unsigned char p_type[4]; /* Identifies program segment type */ + unsigned char p_offset[4]; /* Segment file offset */ + unsigned char p_vaddr[4]; /* Segment virtual address */ + unsigned char p_paddr[4]; /* Segment physical address */ + unsigned char p_filesz[4]; /* Segment size in file */ + unsigned char p_memsz[4]; /* Segment size in memory */ + unsigned char p_flags[4]; /* Segment flags */ + unsigned char p_align[4]; /* Segment alignment, file & memory */ +} Elf32_External_Phdr; + +typedef struct { + unsigned char p_type[4]; /* Identifies program segment type */ + unsigned char p_flags[4]; /* Segment flags */ + unsigned char p_offset[8]; /* Segment file offset */ + unsigned char p_vaddr[8]; /* Segment virtual address */ + unsigned char p_paddr[8]; /* Segment physical address */ + unsigned char p_filesz[8]; /* Segment size in file */ + unsigned char p_memsz[8]; /* Segment size in memory */ + unsigned char p_align[8]; /* Segment alignment, file & memory */ +} Elf64_External_Phdr; + +/* Section header */ + +typedef struct { + unsigned char sh_name[4]; /* Section name, index in string tbl */ + unsigned char sh_type[4]; /* Type of section */ + unsigned char sh_flags[4]; /* Miscellaneous section attributes */ + unsigned char sh_addr[4]; /* Section virtual addr at execution */ + unsigned char sh_offset[4]; /* Section file offset */ + unsigned char sh_size[4]; /* Size of section in bytes */ + unsigned char sh_link[4]; /* Index of another section */ + unsigned char sh_info[4]; /* Additional section information */ + unsigned char sh_addralign[4]; /* Section alignment */ + unsigned char sh_entsize[4]; /* Entry size if section holds table */ +} Elf32_External_Shdr; + +typedef struct { + unsigned char sh_name[4]; /* Section name, index in string tbl */ + unsigned char sh_type[4]; /* Type of section */ + unsigned char sh_flags[8]; /* Miscellaneous section attributes */ + unsigned char sh_addr[8]; /* Section virtual addr at execution */ + unsigned char sh_offset[8]; /* Section file offset */ + unsigned char sh_size[8]; /* Size of section in bytes */ + unsigned char sh_link[4]; /* Index of another section */ + unsigned char sh_info[4]; /* Additional section information */ + unsigned char sh_addralign[8]; /* Section alignment */ + unsigned char sh_entsize[8]; /* Entry size if section holds table */ +} Elf64_External_Shdr; + +/* Symbol table entry */ + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_value[4]; /* Value of the symbol */ + unsigned char st_size[4]; /* Associated symbol size */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ +} Elf32_External_Sym; + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ + unsigned char st_value[8]; /* Value of the symbol */ + unsigned char st_size[8]; /* Associated symbol size */ +} Elf64_External_Sym; + +/* Note segments */ + +typedef struct { + unsigned char namesz[4]; /* Size of entry's owner string */ + unsigned char descsz[4]; /* Size of the note descriptor */ + unsigned char type[4]; /* Interpretation of the descriptor */ + char name[1]; /* Start of the name+desc data */ +} Elf_External_Note; + +/* Relocation Entries */ +typedef struct { + unsigned char r_offset[4]; /* Location at which to apply the action */ + unsigned char r_info[4]; /* index and type of relocation */ +} Elf32_External_Rel; + +typedef struct { + unsigned char r_offset[4]; /* Location at which to apply the action */ + unsigned char r_info[4]; /* index and type of relocation */ + unsigned char r_addend[4]; /* Constant addend used to compute value */ +} Elf32_External_Rela; + +typedef struct { + unsigned char r_offset[8]; /* Location at which to apply the action */ + unsigned char r_info[8]; /* index and type of relocation */ +} Elf64_External_Rel; + +typedef struct { + unsigned char r_offset[8]; /* Location at which to apply the action */ + unsigned char r_info[8]; /* index and type of relocation */ + unsigned char r_addend[8]; /* Constant addend used to compute value */ +} Elf64_External_Rela; + +/* dynamic section structure */ + +typedef struct { + unsigned char d_tag[4]; /* entry tag value */ + union { + unsigned char d_val[4]; + unsigned char d_ptr[4]; + } d_un; +} Elf32_External_Dyn; + +typedef struct { + unsigned char d_tag[8]; /* entry tag value */ + union { + unsigned char d_val[8]; + unsigned char d_ptr[8]; + } d_un; +} Elf64_External_Dyn; diff --git a/gnu/usr.bin/gdb/gdb/elf/internal.h b/gnu/usr.bin/gdb/gdb/elf/internal.h new file mode 100644 index 00000000000..ae4bdada5ea --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/elf/internal.h @@ -0,0 +1,195 @@ +/* ELF support for BFD. + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +This file is part of BFD, the Binary File Descriptor library. + +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. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that describe how ELF is represented internally in the BFD library. + I.E. it describes the in-memory representation of ELF. It requires + the elf-common.h file which contains the portions that are common to + both the internal and external representations. */ + +/* Types used by various structures, functions, etc. */ + +typedef unsigned long Elf32_Addr; /* Unsigned program address */ +typedef unsigned long Elf32_Off; /* Unsigned file offset */ +typedef long Elf32_Sword; /* Signed large integer */ +typedef unsigned long Elf32_Word; /* Unsigned large integer */ +typedef unsigned short Elf32_Half; /* Unsigned medium integer */ +typedef unsigned char Elf32_Char; /* Unsigned tiny integer */ + +#ifdef HOST_64_BIT +typedef unsigned HOST_64_BIT Elf64_Addr; +typedef unsigned HOST_64_BIT Elf64_Off; +typedef HOST_64_BIT Elf64_Sxword; +typedef unsigned HOST_64_BIT Elf64_Xword; +#endif +typedef long Elf64_Sword; +typedef unsigned long Elf64_Word; +typedef unsigned short Elf64_Half; + +/* NOTE that these structures are not kept in the same order as they appear + in the object file. In some cases they've been reordered for more optimal + packing under various circumstances. */ + +/* ELF Header */ + +#define EI_NIDENT 16 /* Size of e_ident[] */ + +typedef struct elf_internal_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + bfd_vma e_entry; /* Entry point virtual address */ + bfd_signed_vma e_phoff; /* Program header table file offset */ + bfd_signed_vma e_shoff; /* Section header table file offset */ + unsigned long e_version; /* Identifies object file version */ + unsigned long e_flags; /* Processor-specific flags */ + unsigned short e_type; /* Identifies object file type */ + unsigned short e_machine; /* Specifies required architecture */ + unsigned short e_ehsize; /* ELF header size in bytes */ + unsigned short e_phentsize; /* Program header table entry size */ + unsigned short e_phnum; /* Program header table entry count */ + unsigned short e_shentsize; /* Section header table entry size */ + unsigned short e_shnum; /* Section header table entry count */ + unsigned short e_shstrndx; /* Section header string table index */ +} Elf_Internal_Ehdr; + +#define elf32_internal_ehdr elf_internal_ehdr +#define Elf32_Internal_Ehdr Elf_Internal_Ehdr +#define elf64_internal_ehdr elf_internal_ehdr +#define Elf64_Internal_Ehdr Elf_Internal_Ehdr + +/* Program header */ + +struct elf_internal_phdr { + unsigned long p_type; /* Identifies program segment type */ + unsigned long p_flags; /* Segment flags */ + bfd_vma p_offset; /* Segment file offset */ + bfd_vma p_vaddr; /* Segment virtual address */ + bfd_vma p_paddr; /* Segment physical address */ + bfd_vma p_filesz; /* Segment size in file */ + bfd_vma p_memsz; /* Segment size in memory */ + bfd_vma p_align; /* Segment alignment, file & memory */ +}; + +typedef struct elf_internal_phdr Elf_Internal_Phdr; +#define elf32_internal_phdr elf_internal_phdr +#define Elf32_Internal_Phdr Elf_Internal_Phdr +#define elf64_internal_phdr elf_internal_phdr +#define Elf64_Internal_Phdr Elf_Internal_Phdr + +/* Section header */ + +typedef struct elf_internal_shdr { + unsigned int sh_name; /* Section name, index in string tbl */ + unsigned int sh_type; /* Type of section */ + bfd_vma sh_flags; /* Miscellaneous section attributes */ + bfd_vma sh_addr; /* Section virtual addr at execution */ + bfd_size_type sh_size; /* Size of section in bytes */ + bfd_size_type sh_entsize; /* Entry size if section holds table */ + unsigned long sh_link; /* Index of another section */ + unsigned long sh_info; /* Additional section information */ + file_ptr sh_offset; /* Section file offset */ + unsigned int sh_addralign; /* Section alignment */ + + /* The internal rep also has some cached info associated with it. */ + void *rawdata; /* null if unused... */ + void *contents; /* null if unused... */ + bfd_vma size; /* size of contents (0 if unused) */ +} Elf_Internal_Shdr; + +#define elf32_internal_shdr elf_internal_shdr +#define Elf32_Internal_Shdr Elf_Internal_Shdr +#define elf64_internal_shdr elf_internal_shdr +#define Elf64_Internal_Shdr Elf_Internal_Shdr + +/* Symbol table entry */ + +struct elf_internal_sym { + bfd_vma st_value; /* Value of the symbol */ + bfd_vma st_size; /* Associated symbol size */ + unsigned long st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + unsigned short st_shndx; /* Associated section index */ +}; + +typedef struct elf_internal_sym Elf_Internal_Sym; + +#define elf32_internal_sym elf_internal_sym +#define elf64_internal_sym elf_internal_sym +#define Elf32_Internal_Sym Elf_Internal_Sym +#define Elf64_Internal_Sym Elf_Internal_Sym + +/* Note segments */ + +typedef struct elf_internal_note { + unsigned long namesz; /* Size of entry's owner string */ + unsigned long descsz; /* Size of the note descriptor */ + unsigned long type; /* Interpretation of the descriptor */ + char name[1]; /* Start of the name+desc data */ +} Elf_Internal_Note; +#define Elf32_Internal_Note Elf_Internal_Note +#define elf32_internal_note elf_internal_note + +/* Relocation Entries */ + +typedef struct elf_internal_rel { + bfd_vma r_offset; /* Location at which to apply the action */ + /* This needs to support 64-bit values in elf64. */ + bfd_vma r_info; /* index and type of relocation */ +} Elf_Internal_Rel; + +#define elf32_internal_rel elf_internal_rel +#define Elf32_Internal_Rel Elf_Internal_Rel +#define elf64_internal_rel elf_internal_rel +#define Elf64_Internal_Rel Elf_Internal_Rel + +typedef struct elf_internal_rela { + bfd_vma r_offset; /* Location at which to apply the action */ + bfd_vma r_info; /* Index and Type of relocation */ + bfd_signed_vma r_addend; /* Constant addend used to compute value */ +} Elf_Internal_Rela; + +#define elf32_internal_rela elf_internal_rela +#define elf64_internal_rela elf_internal_rela +#define Elf32_Internal_Rela Elf_Internal_Rela +#define Elf64_Internal_Rela Elf_Internal_Rela + +/* dynamic section structure */ + +typedef struct { + Elf32_Sword d_tag; /* entry tag value */ + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Internal_Dyn; + +#ifdef HOST_64_BIT +typedef struct { + Elf64_Xword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Internal_Dyn; +#endif diff --git a/gnu/usr.bin/gdb/gdb/elfread.c b/gnu/usr.bin/gdb/gdb/elfread.c new file mode 100644 index 00000000000..230afecefb2 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/elfread.c @@ -0,0 +1,729 @@ +/* Read ELF (Executable and Linking Format) object files for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. + +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. */ + +#include "defs.h" +#include "bfd.h" +#include /* For time_t in libbfd.h. */ +#include /* For time_t, if not in time.h. */ +#include "libbfd.h" /* For bfd_elf_find_section */ +#include "libelf.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "gdb-stabs.h" +#include "complaints.h" +#include +#include "demangle.h" + +/* The struct elfinfo is available only during ELF symbol table and + psymtab reading. It is destroyed at the complation of psymtab-reading. + It's local to elf_symfile_read. */ + +struct elfinfo { + file_ptr dboffset; /* Offset to dwarf debug section */ + unsigned int dbsize; /* Size of dwarf debug section */ + file_ptr lnoffset; /* Offset to dwarf line number section */ + unsigned int lnsize; /* Size of dwarf line number section */ + asection *stabsect; /* Section pointer for .stab section */ + asection *stabindexsect; /* Section pointer for .stab.index section */ +}; + +/* Various things we might complain about... */ + +struct complaint section_info_complaint = + {"elf/stab section information %s without a preceding file symbol", 0, 0}; + +struct complaint section_info_dup_complaint = + {"duplicated elf/stab section information for %s", 0, 0}; + +struct complaint stab_info_mismatch_complaint = + {"elf/stab section information missing for %s", 0, 0}; + +struct complaint stab_info_questionable_complaint = + {"elf/stab section information questionable for %s", 0, 0}; + +static void +elf_symfile_init PARAMS ((struct objfile *)); + +static void +elf_new_init PARAMS ((struct objfile *)); + +static void +elf_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +elf_symfile_finish PARAMS ((struct objfile *)); + +static void +elf_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *)); + +static void +free_elfinfo PARAMS ((void *)); + +static struct section_offsets * +elf_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +record_minimal_symbol_and_info PARAMS ((char *, CORE_ADDR, + enum minimal_symbol_type, char *, + struct objfile *)); + +static void +elf_locate_sections PARAMS ((bfd *, asection *, void *)); + +/* We are called once per section from elf_symfile_read. We + need to examine each section we are passed, check to see + if it is something we are interested in processing, and + if so, stash away some access information for the section. + + For now we recognize the dwarf debug information sections and + line number sections from matching their section names. The + ELF definition is no real help here since it has no direct + knowledge of DWARF (by design, so any debugging format can be + used). + + We also recognize the ".stab" sections used by the Sun compilers + released with Solaris 2. + + FIXME: The section names should not be hardwired strings (what + should they be? I don't think most object file formats have enough + section flags to specify what kind of debug section it is + -kingdon). */ + +static void +elf_locate_sections (ignore_abfd, sectp, eip) + bfd *ignore_abfd; + asection *sectp; + PTR eip; +{ + register struct elfinfo *ei; + + ei = (struct elfinfo *) eip; + if (STREQ (sectp -> name, ".debug")) + { + ei -> dboffset = sectp -> filepos; + ei -> dbsize = bfd_get_section_size_before_reloc (sectp); + } + else if (STREQ (sectp -> name, ".line")) + { + ei -> lnoffset = sectp -> filepos; + ei -> lnsize = bfd_get_section_size_before_reloc (sectp); + } + else if (STREQ (sectp -> name, ".stab")) + { + ei -> stabsect = sectp; + } + else if (STREQ (sectp -> name, ".stab.index")) + { + ei -> stabindexsect = sectp; + } +} + +#if 0 /* Currently unused */ + +char * +elf_interpreter (abfd) + bfd *abfd; +{ + sec_ptr interp_sec; + unsigned size; + char *interp = NULL; + + interp_sec = bfd_get_section_by_name (abfd, ".interp"); + if (interp_sec) + { + size = bfd_section_size (abfd, interp_sec); + interp = alloca (size); + if (bfd_get_section_contents (abfd, interp_sec, interp, (file_ptr)0, + size)) + { + interp = savestring (interp, size - 1); + } + else + { + interp = NULL; + } + } + return (interp); +} + +#endif + +static void +record_minimal_symbol_and_info (name, address, ms_type, info, objfile) + char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + char *info; /* FIXME, is this really char *? */ + struct objfile *objfile; +{ + int section; + + /* Guess the section from the type. This is likely to be wrong in + some cases. */ + switch (ms_type) + { + case mst_text: + case mst_file_text: + section = SECT_OFF_TEXT; + break; + case mst_data: + case mst_file_data: + section = SECT_OFF_DATA; + break; + case mst_bss: + case mst_file_bss: + section = SECT_OFF_BSS; + break; + default: + section = -1; + break; + } + + name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); + prim_record_minimal_symbol_and_info (name, address, ms_type, info, section); +} + +/* + +LOCAL FUNCTION + + elf_symtab_read -- read the symbol table of an ELF file + +SYNOPSIS + + void elf_symtab_read (bfd *abfd, CORE_ADDR addr, + struct objfile *objfile) + +DESCRIPTION + + Given an open bfd, a base address to relocate symbols to, and a + flag that specifies whether or not this bfd is for an executable + or not (may be shared library for example), add all the global + function and data symbols to the minimal symbol table. + + In stabs-in-ELF, as implemented by Sun, there are some local symbols + defined in the ELF symbol table, which can be used to locate + the beginnings of sections from each ".o" file that was linked to + form the executable objfile. We gather any such info and record it + in data structures hung off the objfile's private data. + +*/ + +static void +elf_symtab_read (abfd, addr, objfile) + bfd *abfd; + CORE_ADDR addr; + struct objfile *objfile; +{ + unsigned int storage_needed; + asymbol *sym; + asymbol **symbol_table; + unsigned int number_of_symbols; + unsigned int i; + int index; + struct cleanup *back_to; + CORE_ADDR symaddr; + enum minimal_symbol_type ms_type; + /* If sectinfo is nonNULL, it contains section info that should end up + filed in the objfile. */ + struct stab_section_info *sectinfo = NULL; + /* If filesym is nonzero, it points to a file symbol, but we haven't + seen any section info for it yet. */ + asymbol *filesym = 0; + struct dbx_symfile_info *dbx = (struct dbx_symfile_info *) + objfile->sym_stab_info; + unsigned long size; + + storage_needed = get_symtab_upper_bound (abfd); + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + for (i = 0; i < number_of_symbols; i++) + { + sym = symbol_table[i]; + if (sym -> name == NULL || *sym -> name == '\0') + { + /* Skip names that don't exist (shouldn't happen), or names + that are null strings (may happen). */ + continue; + } + if (sym -> flags & BSF_FILE) + { + /* STT_FILE debugging symbol that helps stabs-in-elf debugging. + Chain any old one onto the objfile; remember new sym. */ + if (sectinfo != NULL) + { + sectinfo -> next = dbx -> stab_section_info; + dbx -> stab_section_info = sectinfo; + sectinfo = NULL; + } + filesym = sym; + } + else if (sym -> flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK)) + { + /* Select global/local/weak symbols. Note that bfd puts abs + symbols in their own section, so all symbols we are + interested in will have a section. */ + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate all non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + { + symaddr += addr; + } + /* For non-absolute symbols, use the type of the section + they are relative to, to intuit text/data. Bfd provides + no way of figuring this out for absolute symbols. */ + if (sym -> section == &bfd_abs_section) + { + ms_type = mst_abs; + } + else if (sym -> section -> flags & SEC_CODE) + { + if (sym -> flags & BSF_GLOBAL) + { + ms_type = mst_text; + } + else if (sym->name[0] == '.' && sym->name[1] == 'L') + /* Looks like a compiler-generated label. Skip it. + The assembler should be skipping these (to keep + executables small), but apparently with gcc on the + delta m88k SVR4, it loses. So to have us check too + should be harmless (but I encourage people to fix this + in the assembler instead of adding checks here). */ + continue; + else + { + ms_type = mst_file_text; + } + } + else if (sym -> section -> flags & SEC_ALLOC) + { + if (sym -> flags & BSF_GLOBAL) + { + if (sym -> section -> flags & SEC_LOAD) + { + ms_type = mst_data; + } + else + { + ms_type = mst_bss; + } + } + else if (sym -> flags & BSF_LOCAL) + { + /* Named Local variable in a Data section. Check its + name for stabs-in-elf. The STREQ macro checks the + first character inline, so we only actually do a + strcmp function call on names that start with 'B' + or 'D' */ + index = SECT_OFF_MAX; + if (STREQ ("Bbss.bss", sym -> name)) + { + index = SECT_OFF_BSS; + } + else if (STREQ ("Ddata.data", sym -> name)) + { + index = SECT_OFF_DATA; + } + else if (STREQ ("Drodata.rodata", sym -> name)) + { + index = SECT_OFF_RODATA; + } + if (index != SECT_OFF_MAX) + { + /* Found a special local symbol. Allocate a + sectinfo, if needed, and fill it in. */ + if (sectinfo == NULL) + { + sectinfo = (struct stab_section_info *) + xmmalloc (objfile -> md, sizeof (*sectinfo)); + memset ((PTR) sectinfo, 0, sizeof (*sectinfo)); + if (filesym == NULL) + { + complain (§ion_info_complaint, + sym -> name); + } + else + { + sectinfo -> filename = + (char *) filesym -> name; + } + } + if (sectinfo -> sections[index] != 0) + { + complain (§ion_info_dup_complaint, + sectinfo -> filename); + } + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + { + symaddr += addr; + } + sectinfo -> sections[index] = symaddr; + /* The special local symbols don't go in the + minimal symbol table, so ignore this one. */ + continue; + } + /* Not a special stabs-in-elf symbol, do regular + symbol processing. */ + if (sym -> section -> flags & SEC_LOAD) + { + ms_type = mst_file_data; + } + else + { + ms_type = mst_file_bss; + } + } + else + { + ms_type = mst_unknown; + } + } + else + { + /* FIXME: Solaris2 shared libraries include lots of + odd "absolute" and "undefined" symbols, that play + hob with actions like finding what function the PC + is in. Ignore them if they aren't text, data, or bss. */ + /* ms_type = mst_unknown; */ + continue; /* Skip this symbol. */ + } + /* Pass symbol size field in via BFD. FIXME!!! */ + size = ((elf_symbol_type *) sym) -> internal_elf_sym.st_size; + record_minimal_symbol_and_info ((char *) sym -> name, symaddr, + ms_type, (PTR) size, objfile); + } + } + do_cleanups (back_to); + } +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to elf_symfile_init, which + currently does nothing. + + SECTION_OFFSETS is a set of offsets to apply to relocate the symbols + in each section. We simplify it down to a single offset for all + symbols. FIXME. + + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + + This function only does the minimum work necessary for letting the + user "name" things symbolically; it does not read the entire symtab. + Instead, it reads the external and static symbols and puts them in partial + symbol tables. When more extensive information is requested of a + file, the corresponding partial symbol table is mutated into a full + fledged symbol table by going back and reading the symbols + for real. + + We look for sections with specific names, to tell us what debug + format to look for: FIXME!!! + + dwarf_build_psymtabs() builds psymtabs for DWARF symbols; + elfstab_build_psymtabs() handles STABS symbols. + + Note that ELF files have a "minimal" symbol table, which looks a lot + like a COFF symbol table, but has only the minimal information necessary + for linking. We process this also, and use the information to + build gdb's minimal symbol table. This gives us some minimal debugging + capability even for files compiled without -g. */ + +static void +elf_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + bfd *abfd = objfile->obfd; + struct elfinfo ei; + struct cleanup *back_to; + CORE_ADDR offset; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + memset ((char *) &ei, 0, sizeof (ei)); + + /* Allocate struct to keep track of the symfile */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + memset ((char *) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info)); + make_cleanup (free_elfinfo, (PTR) objfile); + + /* Process the normal ELF symbol table first. This may write some + chain of info into the dbx_symfile_info in objfile->sym_stab_info, + which can later be used by elfstab_offset_sections. */ + + /* FIXME, should take a section_offsets param, not just an offset. */ + offset = ANOFFSET (section_offsets, 0); + elf_symtab_read (abfd, offset, objfile); + + /* Now process debugging information, which is contained in + special ELF sections. We first have to find them... */ + + bfd_map_over_sections (abfd, elf_locate_sections, (PTR) &ei); + if (ei.dboffset && ei.lnoffset) + { + /* DWARF sections */ + dwarf_build_psymtabs (objfile, + section_offsets, mainline, + ei.dboffset, ei.dbsize, + ei.lnoffset, ei.lnsize); + } + if (ei.stabsect) + { + /* STABS sections */ + + /* FIXME: Sun didn't really know how to implement this well. + They made .stab sections that don't point to the .stabstr + section with the sh_link field. BFD doesn't make string table + sections visible to the caller. So we have to search the + ELF section table, not the BFD section table, for the string + table. */ + struct elf32_internal_shdr *elf_sect; + + elf_sect = bfd_elf_find_section (abfd, ".stabstr"); + if (elf_sect) + elfstab_build_psymtabs (objfile, + section_offsets, + mainline, + ei.stabsect->filepos, /* .stab offset */ + bfd_get_section_size_before_reloc (ei.stabsect),/* .stab size */ + (file_ptr) elf_sect->sh_offset, /* .stabstr offset */ + elf_sect->sh_size); /* .stabstr size */ + } + + if (!have_partial_symbols ()) + { + wrap_here (""); + printf_filtered ("(no debugging symbols found)..."); + wrap_here (""); + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + +/* This cleans up the objfile's sym_stab_info pointer, and the chain of + stab_section_info's, that might be dangling from it. */ + +static void +free_elfinfo (objp) + PTR objp; +{ + struct objfile *objfile = (struct objfile *)objp; + struct dbx_symfile_info *dbxinfo = (struct dbx_symfile_info *) + objfile->sym_stab_info; + struct stab_section_info *ssi, *nssi; + + ssi = dbxinfo->stab_section_info; + while (ssi) + { + nssi = ssi->next; + mfree (objfile->md, ssi); + ssi = nssi; + } + + dbxinfo->stab_section_info = 0; /* Just say No mo info about this. */ +} + + +/* Initialize anything that needs initializing when a completely new symbol + file is specified (not just adding some symbols from another file, e.g. a + shared library). + + We reinitialize buildsym, since we may be reading stabs from an ELF file. */ + +static void +elf_new_init (ignore) + struct objfile *ignore; +{ + stabsread_new_init (); + buildsym_new_init (); +} + +/* Perform any local cleanups required when we are done with a particular + objfile. I.E, we are in the process of discarding all symbol information + for an objfile, freeing up all memory held for it, and unlinking the + objfile struct from the global list of known objfiles. */ + +static void +elf_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_stab_info != NULL) + { + mfree (objfile -> md, objfile -> sym_stab_info); + } +} + +/* ELF specific initialization routine for reading symbols. + + It is passed a pointer to a struct sym_fns which contains, among other + things, the BFD for the file whose symbols are being read, and a slot for + a pointer to "private data" which we can fill with goodies. + + For now at least, we have nothing in particular to do, so this function is + just a stub. */ + +static void +elf_symfile_init (ignore) + struct objfile *ignore; +{ +} + +/* ELF specific parsing routine for section offsets. + + Plain and simple for now. */ + +static +struct section_offsets * +elf_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* When handling an ELF file that contains Sun STABS debug info, + some of the debug info is relative to the particular chunk of the + section that was generated in its individual .o file. E.g. + offsets to static variables are relative to the start of the data + segment *for that module before linking*. This information is + painfully squirreled away in the ELF symbol table as local symbols + with wierd names. Go get 'em when needed. */ + +void +elfstab_offset_sections (objfile, pst) + struct objfile *objfile; + struct partial_symtab *pst; +{ + char *filename = pst->filename; + struct dbx_symfile_info *dbx = (struct dbx_symfile_info *) + objfile->sym_stab_info; + struct stab_section_info *maybe = dbx->stab_section_info; + struct stab_section_info *questionable = 0; + int i; + char *p; + + /* The ELF symbol info doesn't include path names, so strip the path + (if any) from the psymtab filename. */ + while (0 != (p = strchr (filename, '/'))) + filename = p+1; + + /* FIXME: This linear search could speed up significantly + if it was chained in the right order to match how we search it, + and if we unchained when we found a match. */ + for (; maybe; maybe = maybe->next) + { + if (filename[0] == maybe->filename[0] + && STREQ (filename, maybe->filename)) + { + /* We found a match. But there might be several source files + (from different directories) with the same name. */ + if (0 == maybe->found) + break; + questionable = maybe; /* Might use it later. */ + } + } + + if (maybe == 0 && questionable != 0) + { + complain (&stab_info_questionable_complaint, filename); + maybe = questionable; + } + + if (maybe) + { + /* Found it! Allocate a new psymtab struct, and fill it in. */ + maybe->found++; + pst->section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (pst->section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (pst->section_offsets, i) = maybe->sections[i]; + return; + } + + /* We were unable to find any offsets for this file. Complain. */ + if (dbx->stab_section_info) /* If there *is* any info, */ + complain (&stab_info_mismatch_complaint, filename); +} + +/* Register that we are able to handle ELF object file formats and DWARF + debugging formats. + + Unlike other object file formats, where the debugging information format + is implied by the object file format, the ELF object file format and the + DWARF debugging information format are two distinct, and potentially + separate entities. I.E. it is perfectly possible to have ELF objects + with debugging formats other than DWARF. And it is conceivable that the + DWARF debugging format might be used with another object file format, + like COFF, by simply using COFF's custom section feature. + + GDB, and to a lesser extent BFD, should support the notion of separate + object file formats and debugging information formats. For now, we just + use "elf" in the same sense as "a.out" or "coff", to imply both the ELF + object file format and the DWARF debugging format. */ + +static struct sym_fns elf_sym_fns = +{ + "elf", /* sym_name: name or name prefix of BFD target type */ + 3, /* sym_namelen: number of significant sym_name chars */ + elf_new_init, /* sym_new_init: init anything gbl to entire symtab */ + elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + elf_symfile_read, /* sym_read: read a symbol file into symtab */ + elf_symfile_finish, /* sym_finish: finished with file, cleanup */ + elf_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_elfread () +{ + add_symtab_fns (&elf_sym_fns); +} diff --git a/gnu/usr.bin/gdb/gdb/environ.c b/gnu/usr.bin/gdb/gdb/environ.c new file mode 100644 index 00000000000..4089212e5ad --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/environ.c @@ -0,0 +1,198 @@ +/* environ.c -- library for manipulating environments for GNU. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +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. */ + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#include "defs.h" +#include "environ.h" +#include +#include "defs.h" /* For strsave(). */ + + +/* Return a new environment object. */ + +struct environ * +make_environ () +{ + register struct environ *e; + + e = (struct environ *) xmalloc (sizeof (struct environ)); + + e->allocated = 10; + e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *)); + e->vector[0] = 0; + return e; +} + +/* Free an environment and all the strings in it. */ + +void +free_environ (e) + register struct environ *e; +{ + register char **vector = e->vector; + + while (*vector) + free (*vector++); + + free (e); +} + +/* Copy the environment given to this process into E. + Also copies all the strings in it, so we can be sure + that all strings in these environments are safe to free. */ + +void +init_environ (e) + register struct environ *e; +{ + extern char **environ; + register int i; + + for (i = 0; environ[i]; i++) /*EMPTY*/; + + if (e->allocated < i) + { + e->allocated = max (i, e->allocated + 10); + e->vector = (char **) xrealloc ((char *)e->vector, + (e->allocated + 1) * sizeof (char *)); + } + + memcpy (e->vector, environ, (i + 1) * sizeof (char *)); + + while (--i >= 0) + { + register int len = strlen (e->vector[i]); + register char *new = (char *) xmalloc (len + 1); + memcpy (new, e->vector[i], len + 1); + e->vector[i] = new; + } +} + +/* Return the vector of environment E. + This is used to get something to pass to execve. */ + +char ** +environ_vector (e) + struct environ *e; +{ + return e->vector; +} + +/* Return the value in environment E of variable VAR. */ + +char * +get_in_environ (e, var) + const struct environ *e; + const char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; (s = *vector) != NULL; vector++) + if (STREQN (s, var, len) && s[len] == '=') + return &s[len + 1]; + + return 0; +} + +/* Store the value in E of VAR as VALUE. */ + +void +set_in_environ (e, var, value) + struct environ *e; + const char *var; + const char *value; +{ + register int i; + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (i = 0; (s = vector[i]) != NULL; i++) + if (STREQN (s, var, len) && s[len] == '=') + break; + + if (s == 0) + { + if (i == e->allocated) + { + e->allocated += 10; + vector = (char **) xrealloc ((char *)vector, + (e->allocated + 1) * sizeof (char *)); + e->vector = vector; + } + vector[i + 1] = 0; + } + else + free (s); + + s = (char *) xmalloc (len + strlen (value) + 2); + strcpy (s, var); + strcat (s, "="); + strcat (s, value); + vector[i] = s; + + /* Certain variables get exported back to the parent (e.g. our) + environment, too. FIXME: this is a hideous hack and should not be + allowed to live. What if we want to change the environment we pass to + the program without affecting GDB's behavior? */ + if (STREQ(var, "PATH")) /* Object file location */ + { + putenv (strsave (s)); + } + + /* This is a compatibility hack, since GDB 4.10 and older didn't have + `set gnutarget'. Eventually it should go away, so that (for example) + you can debug objdump's handling of GNUTARGET without affecting GDB's + behavior. */ + if (STREQ (var, "GNUTARGET")) + { + set_gnutarget (value); + } + return; +} + +/* Remove the setting for variable VAR from environment E. */ + +void +unset_in_environ (e, var) + struct environ *e; + char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; (s = *vector) != NULL; vector++) + { + if (STREQN (s, var, len) && s[len] == '=') + { + free (s); + /* Walk through the vector, shuffling args down by one, including + the NULL terminator. Can't use memcpy() here since the regions + overlap, and memmove() might not be available. */ + while ((vector[0] = vector[1]) != NULL) + { + vector++; + } + break; + } + } +} diff --git a/gnu/usr.bin/gdb/gdb/environ.h b/gnu/usr.bin/gdb/gdb/environ.h new file mode 100644 index 00000000000..6c9fd03e362 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/environ.h @@ -0,0 +1,58 @@ +/* Header for environment manipulation library. + Copyright 1989, 1992 Free Software Foundation. + +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. */ + +#if !defined (ENVIRON_H) +#define ENVIRON_H 1 + +/* We manipulate environments represented as these structures. */ + +struct environ +{ + /* Number of usable slots allocated in VECTOR. + VECTOR always has one slot not counted here, + to hold the terminating zero. */ + int allocated; + /* A vector of slots, ALLOCATED + 1 of them. + The first few slots contain strings "VAR=VALUE" + and the next one contains zero. + Then come some unused slots. */ + char **vector; +}; + +extern struct environ * +make_environ PARAMS ((void)); + +extern void +free_environ PARAMS ((struct environ *)); + +extern void +init_environ PARAMS ((struct environ *)); + +extern char * +get_in_environ PARAMS ((const struct environ *, const char *)); + +extern void +set_in_environ PARAMS ((struct environ *, const char *, + const char *)); + +extern void +unset_in_environ PARAMS ((struct environ *, char *)); + +extern char ** +environ_vector PARAMS ((struct environ *)); + +#endif /* defined (ENVIRON_H) */ diff --git a/gnu/usr.bin/gdb/gdb/eval.c b/gnu/usr.bin/gdb/gdb/eval.c new file mode 100644 index 00000000000..f641a65f95a --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/eval.c @@ -0,0 +1,1213 @@ +/* Evaluate expressions for GDB. + Copyright 1986, 1987, 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "expression.h" +#include "target.h" +#include "frame.h" +#include "language.h" /* For CAST_IS_CONVERSION */ + +/* Values of NOSIDE argument to eval_subexp. */ +enum noside +{ EVAL_NORMAL, + EVAL_SKIP, /* Only effect is to increment pos. */ + EVAL_AVOID_SIDE_EFFECTS /* Don't modify any variables or + call any functions. The value + returned will have the correct + type, and will have an + approximately correct lvalue + type (inaccuracy: anything that is + listed as being in a register in + the function in which it was + declared will be lval_register). */ +}; + +/* Prototypes for local functions. */ + +static value +evaluate_subexp_for_sizeof PARAMS ((struct expression *, int *)); + +static value +evaluate_subexp_with_coercion PARAMS ((struct expression *, int *, + enum noside)); + +static value +evaluate_subexp_for_address PARAMS ((struct expression *, int *, + enum noside)); + +static value +evaluate_subexp PARAMS ((struct type *, struct expression *, int *, + enum noside)); + + +/* Parse the string EXP as a C expression, evaluate it, + and return the result as a number. */ + +CORE_ADDR +parse_and_eval_address (exp) + char *exp; +{ + struct expression *expr = parse_expression (exp); + register CORE_ADDR addr; + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + addr = value_as_pointer (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +/* Like parse_and_eval_address but takes a pointer to a char * variable + and advanced that variable across the characters parsed. */ + +CORE_ADDR +parse_and_eval_address_1 (expptr) + char **expptr; +{ + struct expression *expr = parse_exp_1 (expptr, (struct block *)0, 0); + register CORE_ADDR addr; + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + addr = value_as_pointer (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +value +parse_and_eval (exp) + char *exp; +{ + struct expression *expr = parse_expression (exp); + register value val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Parse up to a comma (or to a closeparen) + in the string EXPP as an expression, evaluate it, and return the value. + EXPP is advanced to point to the comma. */ + +value +parse_to_comma_and_eval (expp) + char **expp; +{ + struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1); + register value val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Evaluate an expression in internal prefix form + such as is constructed by parse.y. + + See expression.h for info on the format of an expression. */ + +static value evaluate_subexp (); +static value evaluate_subexp_for_address (); +static value evaluate_subexp_for_sizeof (); +static value evaluate_subexp_with_coercion (); + +value +evaluate_expression (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); +} + +/* Evaluate an expression, avoiding all memory references + and getting a value whose type alone is correct. */ + +value +evaluate_type (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS); +} + +static value +evaluate_subexp (expect_type, exp, pos, noside) + struct type *expect_type; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + int tem, tem2, tem3; + register int pc, pc2 = 0, oldpos; + register value arg1 = NULL, arg2 = NULL, arg3; + struct type *type; + int nargs; + value *argvec; + + pc = (*pos)++; + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_SCOPE: + tem = longest_to_int (exp->elts[pc + 2].longconst); + (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = value_struct_elt_for_reference (exp->elts[pc + 1].type, + 0, + exp->elts[pc + 1].type, + &exp->elts[pc + 3].string, + expect_type); + if (arg1 == NULL) + error ("There is no field named %s", &exp->elts[pc + 3].string); + return arg1; + + case OP_LONG: + (*pos) += 3; + return value_from_longest (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst); + + case OP_DOUBLE: + (*pos) += 3; + return value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst); + + case OP_VAR_VALUE: + (*pos) += 3; + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct symbol * sym = exp->elts[pc + 2].symbol; + enum lval_type lv; + + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_LABEL: + case LOC_CONST_BYTES: + lv = not_lval; + break; + + case LOC_REGISTER: + case LOC_REGPARM: + lv = lval_register; + break; + + default: + lv = lval_memory; + break; + } + + return value_zero (SYMBOL_TYPE (sym), lv); + } + else + return value_of_variable (exp->elts[pc + 2].symbol, + exp->elts[pc + 1].block); + + case OP_LAST: + (*pos) += 2; + return + access_value_history (longest_to_int (exp->elts[pc + 1].longconst)); + + case OP_REGISTER: + (*pos) += 2; + return value_of_register (longest_to_int (exp->elts[pc + 1].longconst)); + + case OP_BOOL: + (*pos) += 2; + return value_from_longest (builtin_type_chill_bool, + exp->elts[pc + 1].longconst); + + case OP_INTERNALVAR: + (*pos) += 2; + return value_of_internalvar (exp->elts[pc + 1].internalvar); + + case OP_STRING: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + if (noside == EVAL_SKIP) + goto nosideret; + return value_string (&exp->elts[pc + 2].string, tem); + + case OP_BITSTRING: + error ("support for OP_BITSTRING unimplemented"); + break; + + case OP_ARRAY: + (*pos) += 3; + tem2 = longest_to_int (exp->elts[pc + 1].longconst); + tem3 = longest_to_int (exp->elts[pc + 2].longconst); + nargs = tem3 - tem2 + 1; + argvec = (value *) alloca (sizeof (value) * nargs); + for (tem = 0; tem < nargs; tem++) + { + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + } + if (noside == EVAL_SKIP) + goto nosideret; + return (value_array (tem2, tem3, argvec)); + break; + + case TERNOP_COND: + /* Skip third and second args to evaluate the first one. */ + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (value_logical_not (arg1)) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + return arg2; + } + + case OP_FUNCALL: + (*pos) += 2; + op = exp->elts[*pos].opcode; + if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { + int fnptr; + + nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + + if (noside == EVAL_SKIP) + goto nosideret; + + if (op == STRUCTOP_MEMBER) + { + arg2 = evaluate_subexp_for_address (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + + /* If the function is a virtual function, then the + aggregate value (providing the structure) plays + its part by providing the vtable. Otherwise, + it is just along for the ride: call the function + directly. */ + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + + fnptr = longest_to_int (value_as_long (arg1)); + + if (METHOD_PTR_IS_VIRTUAL(fnptr)) + { + int fnoffset = METHOD_PTR_TO_VOFFSET(fnptr); + struct type *basetype; + struct type *domain_type = + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); + int i, j; + basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); + if (domain_type != basetype) + arg2 = value_cast(lookup_pointer_type (domain_type), arg2); + basetype = TYPE_VPTR_BASETYPE (domain_type); + for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--) + { + struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i); + /* If one is virtual, then all are virtual. */ + if (TYPE_FN_FIELD_VIRTUAL_P (f, 0)) + for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j) + if (TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset) + { + value temp = value_ind (arg2); + arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0); + arg2 = value_addr (temp); + goto got_it; + } + } + if (i < 0) + error ("virtual function at index %d not found", fnoffset); + } + else + { + VALUE_TYPE (arg1) = lookup_pointer_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); + } + got_it: + + /* Now, say which argument to start evaluating from */ + tem = 2; + } + else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { + /* Hair for method invocations */ + int tem2; + + nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + tem2 = longest_to_int (exp->elts[pc2 + 1].longconst); + *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1); + if (noside == EVAL_SKIP) + goto nosideret; + + if (op == STRUCTOP_STRUCT) + { + /* If v is a variable in a register, and the user types + v.method (), this will produce an error, because v has + no address. + + A possible way around this would be to allocate a + copy of the variable on the stack, copy in the + contents, call the function, and copy out the + contents. I.e. convert this from call by reference + to call by copy-return (or whatever it's called). + However, this does not work because it is not the + same: the method being called could stash a copy of + the address, and then future uses through that address + (after the method returns) would be expected to + use the variable itself, not some copy of it. */ + arg2 = evaluate_subexp_for_address (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + /* Now, say which argument to start evaluating from */ + tem = 2; + } + else + { + nargs = longest_to_int (exp->elts[pc + 1].longconst); + tem = 0; + } + /* Allocate arg vector, including space for the function to be + called in argvec[0] and a terminating NULL */ + argvec = (value *) alloca (sizeof (value) * (nargs + 2)); + for (; tem <= nargs; tem++) + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + + /* signal end of arglist */ + argvec[tem] = 0; + + if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { + int static_memfuncp; + value temp = arg2; + + argvec[1] = arg2; + argvec[0] = + value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 2].string, + &static_memfuncp, + op == STRUCTOP_STRUCT + ? "structure" : "structure pointer"); + arg2 = value_from_longest (lookup_pointer_type (VALUE_TYPE (temp)), + VALUE_ADDRESS (temp)+VALUE_OFFSET (temp)); + argvec[1] = arg2; + if (static_memfuncp) + { + argvec[1] = argvec[0]; + nargs--; + argvec++; + } + } + else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { + argvec[1] = arg2; + argvec[0] = arg1; + } + + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the return type doesn't look like a function type, call an + error. This can happen if somebody tries to turn a variable into + a function call. This is here because people often want to + call, eg, strcmp, which gdb doesn't know is a function. If + gdb isn't asked for it's opinion (ie. through "whatis"), + it won't offer it. */ + + struct type *ftype = + TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])); + + if (ftype) + return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]))); + else + error ("Expression of type other than \"Function returning ...\" used as function"); + } + return call_function_by_hand (argvec[0], nargs, argvec + 1); + + case STRUCTOP_STRUCT: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0), + lval_memory); + else + { + value temp = arg1; + return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string, + (int *) 0, "structure"); + } + + case STRUCTOP_PTR: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0), + lval_memory); + else + { + value temp = arg1; + return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string, + (int *) 0, "structure pointer"); + } + + case STRUCTOP_MEMBER: + arg1 = evaluate_subexp_for_address (exp, pos, noside); + goto handle_pointer_to_member; + case STRUCTOP_MPTR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + handle_pointer_to_member: + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR) + goto bad_pointer_to_member; + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); + if (TYPE_CODE (type) == TYPE_CODE_METHOD) + error ("not implemented: pointer-to-method in pointer-to-member construct"); + if (TYPE_CODE (type) != TYPE_CODE_MEMBER) + goto bad_pointer_to_member; + /* Now, convert these values to an address. */ + arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg1); + arg3 = value_from_longest (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + value_as_long (arg1) + value_as_long (arg2)); + return value_ind (arg3); + bad_pointer_to_member: + error("non-pointer-to-member value used in pointer-to-member construct"); + + case BINOP_CONCAT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_concat (arg1, arg2); + + case BINOP_ASSIGN: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_assign (arg1, arg2); + + case BINOP_ASSIGN_MODIFY: + (*pos) += 2; + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + op = exp->elts[pc + 1].opcode; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op); + else if (op == BINOP_ADD) + arg2 = value_add (arg1, arg2); + else if (op == BINOP_SUB) + arg2 = value_sub (arg1, arg2); + else + arg2 = value_binop (arg1, arg2, op); + return value_assign (arg1, arg2); + + case BINOP_ADD: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_add (arg1, arg2); + + case BINOP_SUB: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_sub (arg1, arg2); + + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_MOD: + case BINOP_LSH: + case BINOP_RSH: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + if (noside == EVAL_AVOID_SIDE_EFFECTS + && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD)) + return value_zero (VALUE_TYPE (arg1), not_lval); + else + return value_binop (arg1, arg2, op); + + case BINOP_SUBSCRIPT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + if (type) + return value_zero (type, VALUE_LVAL (arg1)); + else + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } + + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_subscript (arg1, arg2); + + case MULTI_SUBSCRIPT: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + while (nargs-- > 0) + { + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + /* FIXME: EVAL_SKIP handling may not be correct. */ + if (noside == EVAL_SKIP) + { + if (nargs > 0) + { + continue; + } + else + { + goto nosideret; + } + } + /* FIXME: EVAL_AVOID_SIDE_EFFECTS handling may not be correct. */ + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + if (type != NULL) + { + arg1 = value_zero (type, VALUE_LVAL (arg1)); + noside = EVAL_SKIP; + continue; + } + else + { + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } + } + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg1 = value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + arg1 = value_subscript (arg1, arg2); + } + } + return (arg1); + + case BINOP_LOGICAL_AND: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_logical_not (arg1); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, + (tem ? EVAL_SKIP : noside)); + return value_from_longest (builtin_type_int, + (LONGEST) (!tem && !value_logical_not (arg2))); + } + + case BINOP_LOGICAL_OR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_logical_not (arg1); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, + (!tem ? EVAL_SKIP : noside)); + return value_from_longest (builtin_type_int, + (LONGEST) (!tem || !value_logical_not (arg2))); + } + + case BINOP_EQUAL: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_NOTEQUAL: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) ! tem); + } + + case BINOP_LESS: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_GTR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg2, arg1); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_GEQ: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg2, arg1) || value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_LEQ: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg1, arg2) || value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_REPEAT: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT) + error ("Non-integral right operand for \"@\" operator."); + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return allocate_repeat_value (VALUE_TYPE (arg1), + longest_to_int (value_as_long (arg2))); + else + return value_repeat (arg1, longest_to_int (value_as_long (arg2))); + + case BINOP_COMMA: + evaluate_subexp (NULL_TYPE, exp, pos, noside); + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_NEG: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op); + else + return value_neg (arg1); + + case UNOP_COMPLEMENT: + /* C++: check for and handle destructor names. */ + op = exp->elts[*pos].opcode; + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (UNOP_COMPLEMENT, arg1)) + return value_x_unop (arg1, UNOP_COMPLEMENT); + else + return value_complement (arg1); + + case UNOP_LOGICAL_NOT: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op); + else + return value_from_longest (builtin_type_int, + (LONGEST) value_logical_not (arg1)); + + case UNOP_IND: + if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR) + expect_type = TYPE_TARGET_TYPE (expect_type); + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF + /* In C you can dereference an array to get the 1st elt. */ + || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY + ) + return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + lval_memory); + else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT) + /* GDB allows dereferencing an int. */ + return value_zero (builtin_type_int, lval_memory); + else + error ("Attempt to take contents of a non-pointer value."); + } + return value_ind (arg1); + + case UNOP_ADDR: + /* C++: check for and handle pointer to members. */ + + op = exp->elts[*pos].opcode; + + if (noside == EVAL_SKIP) + { + if (op == OP_SCOPE) + { + int temm = longest_to_int (exp->elts[pc+3].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1); + } + else + evaluate_subexp (expect_type, exp, pos, EVAL_SKIP); + goto nosideret; + } + + return evaluate_subexp_for_address (exp, pos, noside); + + case UNOP_SIZEOF: + if (noside == EVAL_SKIP) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_sizeof (exp, pos); + + case UNOP_CAST: + (*pos) += 2; + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_cast (exp->elts[pc + 1].type, arg1); + + case UNOP_MEMVAL: + (*pos) += 2; + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (exp->elts[pc + 1].type, lval_memory); + else + return value_at_lazy (exp->elts[pc + 1].type, + value_as_pointer (arg1)); + + case UNOP_PREINCREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_add (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + return value_assign (arg1, arg2); + } + + case UNOP_PREDECREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_sub (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + return value_assign (arg1, arg2); + } + + case UNOP_POSTINCREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_add (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + value_assign (arg1, arg2); + return arg1; + } + + case UNOP_POSTDECREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_sub (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + value_assign (arg1, arg2); + return arg1; + } + + case OP_THIS: + (*pos) += 1; + return value_of_this (1); + + case OP_TYPE: + error ("Attempt to use a type name as an expression"); + + default: + /* Removing this case and compiling with gcc -Wall reveals that + a lot of cases are hitting this case. Some of these should + probably be removed from expression.h (e.g. do we need a BINOP_SCOPE + and an OP_SCOPE?); others are legitimate expressions which are + (apparently) not fully implemented. + + If there are any cases landing here which mean a user error, + then they should be separate cases, with more descriptive + error messages. */ + + error ("\ +GDB does not (yet) know how to evaluated that kind of expression"); + } + + nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return the address of that subexpression. + Advance *POS over the subexpression. + If the subexpression isn't an lvalue, get an error. + NOSIDE may be EVAL_AVOID_SIDE_EFFECTS; + then only the type of the result need be correct. */ + +static value +evaluate_subexp_for_address (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + register int pc; + struct symbol *var; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case UNOP_IND: + (*pos)++; + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), + evaluate_subexp (NULL_TYPE, exp, pos, noside)); + + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; + + /* C++: The "address" of a reference should yield the address + * of the object pointed to. Let value_addr() deal with it. */ + if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_REF) + goto default_case; + + (*pos) += 4; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct type *type = + lookup_pointer_type (SYMBOL_TYPE (var)); + enum address_class sym_class = SYMBOL_CLASS (var); + + if (sym_class == LOC_CONST + || sym_class == LOC_CONST_BYTES + || sym_class == LOC_REGISTER + || sym_class == LOC_REGPARM) + error ("Attempt to take address of register or constant."); + + return + value_zero (type, not_lval); + } + else + return + locate_var_value + (var, + block_innermost_frame (exp->elts[pc + 1].block)); + + default: + default_case: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + value x = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (VALUE_LVAL (x) == lval_memory) + return value_zero (lookup_pointer_type (VALUE_TYPE (x)), + not_lval); + else + error ("Attempt to take address of non-lval"); + } + return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + } +} + +/* Evaluate like `evaluate_subexp' except coercing arrays to pointers. + When used in contexts where arrays will be coerced anyway, this is + equivalent to `evaluate_subexp' but much faster because it avoids + actually fetching array contents (perhaps obsolete now that we have + VALUE_LAZY). + + Note that we currently only do the coercion for C expressions, where + arrays are zero based and the coercion is correct. For other languages, + with nonzero based arrays, coercion loses. Use CAST_IS_CONVERSION + to decide if coercion is appropriate. + + */ + +static value +evaluate_subexp_with_coercion (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + register enum exp_opcode op; + register int pc; + register value val; + struct symbol *var; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; + if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_ARRAY + && CAST_IS_CONVERSION) + { + (*pos) += 4; + val = + locate_var_value + (var, block_innermost_frame (exp->elts[pc + 1].block)); + return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (var))), + val); + } + /* FALLTHROUGH */ + + default: + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return a value for the size of that subexpression. + Advance *POS over the subexpression. */ + +static value +evaluate_subexp_for_sizeof (exp, pos) + register struct expression *exp; + register int *pos; +{ + enum exp_opcode op; + register int pc; + value val; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + /* This case is handled specially + so that we avoid creating a value for the result type. + If the result type is very big, it's desirable not to + create a value unnecessarily. */ + case UNOP_IND: + (*pos)++; + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_longest (builtin_type_int, (LONGEST) + TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val)))); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_from_longest (builtin_type_int, + (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type)); + + case OP_VAR_VALUE: + (*pos) += 4; + return + value_from_longest + (builtin_type_int, + (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 2].symbol))); + + default: + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_longest (builtin_type_int, + (LONGEST) TYPE_LENGTH (VALUE_TYPE (val))); + } +} + +/* Parse a type expression in the string [P..P+LENGTH). */ + +struct type * +parse_and_eval_type (p, length) + char *p; + int length; +{ + char *tmp = (char *)alloca (length + 4); + struct expression *expr; + tmp[0] = '('; + memcpy (tmp+1, p, length); + tmp[length+1] = ')'; + tmp[length+2] = '0'; + tmp[length+3] = '\0'; + expr = parse_expression (tmp); + if (expr->elts[0].opcode != UNOP_CAST) + error ("Internal error in eval_type."); + return expr->elts[1].type; +} diff --git a/gnu/usr.bin/gdb/gdb/exec.c b/gnu/usr.bin/gdb/gdb/exec.c new file mode 100644 index 00000000000..f66a33c2cdc --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/exec.c @@ -0,0 +1,489 @@ +/* Work with executable files, 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. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "gdbcmd.h" + +#ifdef USG +#include +#endif + +#include +#include +#include + +#include "gdbcore.h" + +#include +#include +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* Prototypes for local functions */ + +static void +add_to_section_table PARAMS ((bfd *, sec_ptr, PTR)); + +static void +exec_close PARAMS ((int)); + +static void +file_command PARAMS ((char *, int)); + +static void +set_section_command PARAMS ((char *, int)); + +static void +exec_files_info PARAMS ((struct target_ops *)); + +extern int info_verbose; + +/* The Binary File Descriptor handle for the executable file. */ + +bfd *exec_bfd = NULL; + +/* Whether to open exec and core files read-only or read-write. */ + +int write_files = 0; + +/* Text start and end addresses (KLUDGE) if needed */ + +#ifdef NEED_TEXT_START_END +CORE_ADDR text_start = 0; +CORE_ADDR text_end = 0; +#endif + +/* Forward decl */ + +extern struct target_ops exec_ops; + +/* ARGSUSED */ +static void +exec_close (quitting) + int quitting; +{ + if (exec_bfd) { + char *name = bfd_get_filename (exec_bfd); + bfd_close (exec_bfd); + free (name); + exec_bfd = NULL; + } + if (exec_ops.to_sections) { + free ((PTR)exec_ops.to_sections); + exec_ops.to_sections = NULL; + exec_ops.to_sections_end = NULL; + } +} + +/* Process the first arg in ARGS as the new exec file. + + Note that we have to explicitly ignore additional args, since we can + be called from file_command(), which also calls symbol_file_command() + which can take multiple args. */ + +void +exec_file_command (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + char *filename; + + target_preopen (from_tty); + + /* Remove any previous exec file. */ + unpush_target (&exec_ops); + + /* Now open and digest the file the user requested, if any. */ + + if (args) + { + char *scratch_pathname; + int scratch_chan; + + /* Scan through the args and pick up the first non option arg + as the filename. */ + + if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + make_cleanup (freeargv, (char *) argv); + + for (; (*argv != NULL) && (**argv == '-'); argv++) {;} + if (*argv == NULL) + { + error ("no exec file name was specified"); + } + + filename = tilde_expand (*argv); + make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, + write_files? O_RDWR|O_BINARY: O_RDONLY|O_BINARY, 0, + &scratch_pathname); + if (scratch_chan < 0) + perror_with_name (filename); + + exec_bfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!exec_bfd) + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_error)); + if (!bfd_check_format (exec_bfd, bfd_object)) + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_error)); + + if (build_section_table (exec_bfd, &exec_ops.to_sections, + &exec_ops.to_sections_end)) + error ("Can't find the file sections in `%s': %s", + exec_bfd->filename, bfd_errmsg (bfd_error)); + +#ifdef NEED_TEXT_START_END + + /* text_end is sometimes used for where to put call dummies. A + few ports use these for other purposes too. */ + + { + struct section_table *p; + + /* Set text_start to the lowest address of the start of any + readonly code section and set text_end to the highest + address of the end of any readonly code section. */ + + text_start = ~(CORE_ADDR)0; + text_end = (CORE_ADDR)0; + for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) + if (bfd_get_section_flags (p->bfd, p->sec_ptr) + & (SEC_CODE | SEC_READONLY)) + { + if (text_start > p->addr) + text_start = p->addr; + if (text_end < p->endaddr) + text_end = p->endaddr; + } + } +#endif + + validate_files (); + + push_target (&exec_ops); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); + } + else if (from_tty) + printf ("No exec file now.\n"); +} + +/* Set both the exec file and the symbol file, in one command. + What a novelty. Why did GDB go through four major releases before this + command was added? */ + +static void +file_command (arg, from_tty) + char *arg; + int from_tty; +{ + /* FIXME, if we lose on reading the symbol file, we should revert + the exec file, but that's rough. */ + exec_file_command (arg, from_tty); + symbol_file_command (arg, from_tty); +} + + +/* Locate all mappable sections of a BFD file. + table_pp_char is a char * to get it through bfd_map_over_sections; + we cast it back to its proper type. */ + +static void +add_to_section_table (abfd, asect, table_pp_char) + bfd *abfd; + sec_ptr asect; + PTR table_pp_char; +{ + struct section_table **table_pp = (struct section_table **)table_pp_char; + flagword aflag; + + aflag = bfd_get_section_flags (abfd, asect); + /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */ + if (!(aflag & SEC_LOAD)) + return; + if (0 == bfd_section_size (abfd, asect)) + return; + (*table_pp)->bfd = abfd; + (*table_pp)->sec_ptr = asect; + (*table_pp)->addr = bfd_section_vma (abfd, asect); + (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect); + (*table_pp)++; +} + +/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. + Returns 0 if OK, 1 on error. */ + +int +build_section_table (some_bfd, start, end) + bfd *some_bfd; + struct section_table **start, **end; +{ + unsigned count; + + count = bfd_count_sections (some_bfd); + if (*start) + free ((PTR)*start); + *start = (struct section_table *) xmalloc (count * sizeof (**start)); + *end = *start; + bfd_map_over_sections (some_bfd, add_to_section_table, (char *)end); + if (*end > *start + count) + abort(); + /* We could realloc the table, but it probably loses for most files. */ + return 0; +} + +/* Read or write the exec file. + + Args are address within a BFD file, address within gdb address-space, + length, and a flag indicating whether to read or write. + + Result is a length: + + 0: We cannot handle this address and length. + > 0: We have handled N bytes starting at this address. + (If N == length, we did it all.) We might be able + to handle more bytes beyond this length, but no + promises. + < 0: We cannot handle this address, but if somebody + else handles (-N) bytes, we can start from there. + + The same routine is used to handle both core and exec files; + we just tail-call it with more arguments to select between them. */ + +int +xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + boolean res; + struct section_table *p; + CORE_ADDR nextsectaddr, memend; + boolean (*xfer_fn) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + + if (len <= 0) + abort(); + + memend = memaddr + len; + xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents; + nextsectaddr = memend; + + for (p = target->to_sections; p < target->to_sections_end; p++) + { + if (p->addr <= memaddr) + if (p->endaddr >= memend) + { + /* Entire transfer is within this section. */ + res = xfer_fn (p->bfd, p->sec_ptr, myaddr, memaddr - p->addr, len); + return (res != false)? len: 0; + } + else if (p->endaddr <= memaddr) + { + /* This section ends before the transfer starts. */ + continue; + } + else + { + /* This section overlaps the transfer. Just do half. */ + len = p->endaddr - memaddr; + res = xfer_fn (p->bfd, p->sec_ptr, myaddr, memaddr - p->addr, len); + return (res != false)? len: 0; + } + else if (p->addr < nextsectaddr) + nextsectaddr = p->addr; + } + + if (nextsectaddr >= memend) + return 0; /* We can't help */ + else + return - (nextsectaddr - memaddr); /* Next boundary where we can help */ +} + +#ifdef FIXME +#ifdef REG_STACK_SEGMENT +/* MOVE TO BFD... */ + /* Pyramids and AM29000s have an extra segment in the virtual address space + for the (control) stack of register-window frames. The AM29000 folk + call it the "register stack" rather than the "memory stack". */ + else if (memaddr >= reg_stack_start && memaddr < reg_stack_end) + { + i = min (len, reg_stack_end - memaddr); + fileptr = memaddr - reg_stack_start + reg_stack_offset; + wanna_xfer = coredata; + } +#endif /* REG_STACK_SEGMENT */ +#endif /* FIXME */ + +void +print_section_info (t, abfd) + struct target_ops *t; + bfd *abfd; +{ + struct section_table *p; + + printf_filtered ("\t`%s', ", bfd_get_filename(abfd)); + wrap_here (" "); + printf_filtered ("file type %s.\n", bfd_get_target(abfd)); + printf_filtered ("\tEntry point: %s\n", + local_hex_string ((unsigned long) bfd_get_start_address (exec_bfd))); + for (p = t->to_sections; p < t->to_sections_end; p++) { + printf_filtered ("\t%s", local_hex_string_custom ((unsigned long) p->addr, "08l")); + printf_filtered (" - %s", local_hex_string_custom ((unsigned long) p->endaddr, "08l")); + if (info_verbose) + printf_filtered (" @ %s", + local_hex_string_custom ((unsigned long) p->sec_ptr->filepos, "08l")); + printf_filtered (" is %s", bfd_section_name (p->bfd, p->sec_ptr)); + if (p->bfd != abfd) { + printf_filtered (" in %s", bfd_get_filename (p->bfd)); + } + printf_filtered ("\n"); + } +} + +static void +exec_files_info (t) + struct target_ops *t; +{ + print_section_info (t, exec_bfd); +} + +static void +set_section_command (args, from_tty) + char *args; + int from_tty; +{ + struct section_table *p; + char *secname; + unsigned seclen; + unsigned long secaddr; + char secprint[100]; + long offset; + + if (args == 0) + error ("Must specify section name and its virtual address"); + + /* Parse out section name */ + for (secname = args; !isspace(*args); args++) ; + seclen = args - secname; + + /* Parse out new virtual address */ + secaddr = parse_and_eval_address (args); + + for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) { + if (!strncmp (secname, bfd_section_name (exec_bfd, p->sec_ptr), seclen) + && bfd_section_name (exec_bfd, p->sec_ptr)[seclen] == '\0') { + offset = secaddr - p->addr; + p->addr += offset; + p->endaddr += offset; + if (from_tty) + exec_files_info(&exec_ops); + return; + } + } + if (seclen >= sizeof (secprint)) + seclen = sizeof (secprint) - 1; + strncpy (secprint, secname, seclen); + secprint[seclen] = '\0'; + error ("Section %s not found", secprint); +} + +/* If mourn is being called in all the right places, this could be say + `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */ + +static int +ignore (addr, contents) + CORE_ADDR addr; + char *contents; +{ + return 0; +} + +struct target_ops exec_ops = { + "exec", "Local exec file", + "Use an executable file as a target.\n\ +Specify the filename of the executable file.", + exec_file_command, exec_close, /* open, close */ + find_default_attach, 0, 0, 0, /* attach, detach, resume, wait, */ + 0, 0, /* fetch_registers, store_registers, */ + 0, /* prepare_to_store, */ + xfer_memory, exec_files_info, + ignore, ignore, /* insert_breakpoint, remove_breakpoint, */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, 0, /* kill, load */ + 0, /* lookup sym */ + find_default_create_inferior, + 0, /* mourn_inferior */ + 0, /* can_run */ + 0, /* notice_signals */ + file_stratum, 0, /* next */ + 0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + 0, 0, /* section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_exec() +{ + struct cmd_list_element *c; + + c = add_cmd ("file", class_files, file_command, + "Use FILE as program to be debugged.\n\ +It is read for its symbols, for getting the contents of pure memory,\n\ +and it is the program executed when you use the `run' command.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +($PATH) is searched for a command of that name.\n\ +No arg means to have no executable file and no symbols.", &cmdlist); + c->completer = filename_completer; + + c = add_cmd ("exec-file", class_files, exec_file_command, + "Use FILE as program for getting contents of pure memory.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +is searched for a command of that name.\n\ +No arg means have no executable file.", &cmdlist); + c->completer = filename_completer; + + add_com ("section", class_files, set_section_command, + "Change the base address of section SECTION of the exec file to ADDR.\n\ +This can be used if the exec file does not contain section addresses,\n\ +(such as in the a.out format), or when the addresses specified in the\n\ +file itself are wrong. Each section must be changed separately. The\n\ +``info files'' command lists all the sections and their addresses."); + + add_show_from_set + (add_set_cmd ("write", class_support, var_boolean, (char *)&write_files, + "Set writing into executable and core files.", + &setlist), + &showlist); + + add_target (&exec_ops); +} diff --git a/gnu/usr.bin/gdb/gdb/expprint.c b/gnu/usr.bin/gdb/gdb/expprint.c new file mode 100644 index 00000000000..607b3df7037 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/expprint.c @@ -0,0 +1,623 @@ +/* Print in infix form a struct expression. + Copyright (C) 1986, 1989, 1991 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "language.h" +#include "parser-defs.h" + +/* Prototypes for local functions */ + +static void +print_subexp PARAMS ((struct expression *, int *, FILE *, enum precedence)); + +static void +print_simple_m2_func PARAMS ((char *, struct expression *, int *, FILE *)); + +void +print_expression (exp, stream) + struct expression *exp; + FILE *stream; +{ + int pc = 0; + print_subexp (exp, &pc, stream, PREC_NULL); +} + +/* Print the subexpression of EXP that starts in position POS, on STREAM. + PREC is the precedence of the surrounding operator; + if the precedence of the main operator of this subexpression is less, + parentheses are needed here. */ + +static void +print_subexp (exp, pos, stream, prec) + register struct expression *exp; + register int *pos; + FILE *stream; + enum precedence prec; +{ + register unsigned tem; + register const struct op_print *op_print_tab; + register int pc; + unsigned nargs; + register char *op_str; + int assign_modify = 0; + enum exp_opcode opcode; + enum precedence myprec = PREC_NULL; + /* Set to 1 for a right-associative operator. */ + int assoc = 0; + value val; + char *tempstr = NULL; + + op_print_tab = exp->language_defn->la_op_print_tab; + pc = (*pos)++; + opcode = exp->elts[pc].opcode; + switch (opcode) + { + /* Common ops */ + + case OP_SCOPE: + myprec = PREC_PREFIX; + assoc = 0; + fputs_filtered (type_name_no_tag (exp->elts[pc + 1].type), stream); + fputs_filtered ("::", stream); + nargs = longest_to_int (exp->elts[pc + 2].longconst); + (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1); + fputs_filtered (&exp->elts[pc + 3].string, stream); + return; + + case OP_LONG: + (*pos) += 3; + value_print (value_from_longest (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst), + stream, 0, Val_no_prettyprint); + return; + + case OP_DOUBLE: + (*pos) += 3; + value_print (value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst), + stream, 0, Val_no_prettyprint); + return; + + case OP_VAR_VALUE: + { + struct block *b; + (*pos) += 3; + b = exp->elts[pc + 1].block; + if (b != NULL + && BLOCK_FUNCTION (b) != NULL + && SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)) != NULL) + { + fputs_filtered (SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)), stream); + fputs_filtered ("::", stream); + } + fputs_filtered (SYMBOL_SOURCE_NAME (exp->elts[pc + 2].symbol), stream); + } + return; + + case OP_LAST: + (*pos) += 2; + fprintf_filtered (stream, "$%d", + longest_to_int (exp->elts[pc + 1].longconst)); + return; + + case OP_REGISTER: + (*pos) += 2; + fprintf_filtered (stream, "$%s", + reg_names[longest_to_int (exp->elts[pc + 1].longconst)]); + return; + + case OP_BOOL: + (*pos) += 2; + fprintf_filtered (stream, "%s", + longest_to_int (exp->elts[pc + 1].longconst) + ? "TRUE" : "FALSE"); + return; + + case OP_INTERNALVAR: + (*pos) += 2; + fprintf_filtered (stream, "$%s", + internalvar_name (exp->elts[pc + 1].internalvar)); + return; + + case OP_FUNCALL: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered (" (", stream); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + fputs_filtered (", ", stream); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fputs_filtered (")", stream); + return; + + case OP_STRING: + nargs = longest_to_int (exp -> elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1); + /* LA_PRINT_STRING will print using the current repeat count threshold. + If necessary, we can temporarily set it to zero, or pass it as an + additional parameter to LA_PRINT_STRING. -fnf */ + LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 0); + return; + + case OP_BITSTRING: + error ("support for OP_BITSTRING unimplemented"); + break; + + case OP_ARRAY: + (*pos) += 3; + nargs = longest_to_int (exp->elts[pc + 2].longconst); + nargs -= longest_to_int (exp->elts[pc + 1].longconst); + nargs++; + tem = 0; + if (exp->elts[pc + 4].opcode == OP_LONG + && exp->elts[pc + 5].type == builtin_type_char + && exp->language_defn->la_language == language_c) + { + /* Attempt to print C character arrays using string syntax. + Walk through the args, picking up one character from each + of the OP_LONG expression elements. If any array element + does not match our expection of what we should find for + a simple string, revert back to array printing. Note that + the last expression element is an explicit null terminator + byte, which doesn't get printed. */ + tempstr = alloca (nargs); + pc += 4; + while (tem < nargs) + { + if (exp->elts[pc].opcode != OP_LONG + || exp->elts[pc + 1].type != builtin_type_char) + { + /* Not a simple array of char, use regular array printing. */ + tem = 0; + break; + } + else + { + tempstr[tem++] = + longest_to_int (exp->elts[pc + 2].longconst); + pc += 4; + } + } + } + if (tem > 0) + { + LA_PRINT_STRING (stream, tempstr, nargs - 1, 0); + (*pos) = pc; + } + else + { + fputs_filtered (" {", stream); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + { + fputs_filtered (", ", stream); + } + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fputs_filtered ("}", stream); + } + return; + + case TERNOP_COND: + if ((int) prec > (int) PREC_COMMA) + fputs_filtered ("(", stream); + /* Print the subexpressions, forcing parentheses + around any binary operations within them. + This is more parentheses than are strictly necessary, + but it looks clearer. */ + print_subexp (exp, pos, stream, PREC_HYPER); + fputs_filtered (" ? ", stream); + print_subexp (exp, pos, stream, PREC_HYPER); + fputs_filtered (" : ", stream); + print_subexp (exp, pos, stream, PREC_HYPER); + if ((int) prec > (int) PREC_COMMA) + fputs_filtered (")", stream); + return; + + case STRUCTOP_STRUCT: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered (".", stream); + fputs_filtered (&exp->elts[pc + 2].string, stream); + return; + + /* Will not occur for Modula-2 */ + case STRUCTOP_PTR: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("->", stream); + fputs_filtered (&exp->elts[pc + 2].string, stream); + return; + + case BINOP_SUBSCRIPT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("[", stream); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + fputs_filtered ("]", stream); + return; + + case UNOP_POSTINCREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("++", stream); + return; + + case UNOP_POSTDECREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("--", stream); + return; + + case UNOP_CAST: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered ("(", stream); + fputs_filtered ("(", stream); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered (") ", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered (")", stream); + return; + + case UNOP_MEMVAL: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered ("(", stream); + if (exp->elts[pc + 1].type->code == TYPE_CODE_FUNC && + exp->elts[pc + 3].opcode == OP_LONG) { + /* We have a minimal symbol fn, probably. It's encoded + as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address). + Swallow the OP_LONG (including both its opcodes); ignore + its type; print the value in the type of the MEMVAL. */ + (*pos) += 4; + val = value_at_lazy (exp->elts[pc + 1].type, + (CORE_ADDR) exp->elts[pc + 5].longconst); + value_print (val, stream, 0, Val_no_prettyprint); + } else { + fputs_filtered ("{", stream); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered ("} ", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + } + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered (")", stream); + return; + + case BINOP_ASSIGN_MODIFY: + opcode = exp->elts[pc + 1].opcode; + (*pos) += 2; + myprec = PREC_ASSIGN; + assoc = 1; + assign_modify = 1; + op_str = "???"; + for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + break; + } + if (op_print_tab[tem].opcode != opcode) + /* Not found; don't try to keep going because we don't know how + to interpret further elements. */ + error ("Invalid expression"); + break; + + /* C++ ops */ + + case OP_THIS: + ++(*pos); + fputs_filtered ("this", stream); + return; + + /* Modula-2 ops */ + + case MULTI_SUBSCRIPT: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, " ["); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + fprintf (stream, ", "); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fprintf (stream, "]"); + return; + + case BINOP_VAL: + (*pos)+=2; + fprintf(stream,"VAL("); + type_print(exp->elts[pc+1].type,"",stream,0); + fprintf(stream,","); + print_subexp(exp,pos,stream,PREC_PREFIX); + fprintf(stream,")"); + return; + + case UNOP_CAP: + print_simple_m2_func("CAP",exp,pos,stream); + return; + + case UNOP_CHR: + print_simple_m2_func("CHR",exp,pos,stream); + return; + + case UNOP_ORD: + print_simple_m2_func("ORD",exp,pos,stream); + return; + + case UNOP_ABS: + print_simple_m2_func("ABS",exp,pos,stream); + return; + + case UNOP_FLOAT: + print_simple_m2_func("FLOAT",exp,pos,stream); + return; + + case UNOP_HIGH: + print_simple_m2_func("HIGH",exp,pos,stream); + return; + + case UNOP_MAX: + print_simple_m2_func("MAX",exp,pos,stream); + return; + + case UNOP_MIN: + print_simple_m2_func("MIN",exp,pos,stream); + return; + + case UNOP_ODD: + print_simple_m2_func("ODD",exp,pos,stream); + return; + + case UNOP_TRUNC: + print_simple_m2_func("TRUNC",exp,pos,stream); + return; + + case BINOP_INCL: + case BINOP_EXCL: + error("print_subexp: Not implemented."); + + /* Default ops */ + + default: + op_str = "???"; + for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + myprec = op_print_tab[tem].precedence; + assoc = op_print_tab[tem].right_assoc; + break; + } + if (op_print_tab[tem].opcode != opcode) + /* Not found; don't try to keep going because we don't know how + to interpret further elements. For example, this happens + if opcode is OP_TYPE. */ + error ("Invalid expression"); + } + + if ((int) myprec < (int) prec) + fputs_filtered ("(", stream); + if ((int) opcode > (int) BINOP_END) + { + /* Unary prefix operator. */ + fputs_filtered (op_str, stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + } + else + { + /* Binary operator. */ + /* Print left operand. + If operator is right-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, + (enum precedence) ((int) myprec + assoc)); + /* Print the operator itself. */ + if (assign_modify) + fprintf_filtered (stream, " %s= ", op_str); + else if (op_str[0] == ',') + fprintf_filtered (stream, "%s ", op_str); + else + fprintf_filtered (stream, " %s ", op_str); + /* Print right operand. + If operator is left-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, + (enum precedence) ((int) myprec + !assoc)); + } + + if ((int) myprec < (int) prec) + fputs_filtered (")", stream); +} + +/* Print out something of the form (). + This is used to print out some builtin Modula-2 + functions. + FIXME: There is probably some way to get the precedence + rules to do this (print a unary operand with parens around it). */ +static void +print_simple_m2_func(s,exp,pos,stream) + char *s; + register struct expression *exp; + register int *pos; + FILE *stream; +{ + fprintf(stream,"%s(",s); + print_subexp(exp,pos,stream,PREC_PREFIX); + fprintf(stream,")"); +} + +/* Return the operator corresponding to opcode OP as + a string. NULL indicates that the opcode was not found in the + current language table. */ +char * +op_string(op) + enum exp_opcode op; +{ + int tem; + register const struct op_print *op_print_tab; + + op_print_tab = current_language->la_op_print_tab; + for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++) + if (op_print_tab[tem].opcode == op) + return op_print_tab[tem].string; + return NULL; +} + +#ifdef DEBUG_EXPRESSIONS + +/* Support for dumping the raw data from expressions in a human readable + form. */ + +void +dump_expression (exp, stream, note) + struct expression *exp; + FILE *stream; + char *note; +{ + int elt; + char *opcode_name; + char *eltscan; + int eltsize; + + fprintf_filtered (stream, "Dump of expression @ 0x%lx, %s:\n", + (unsigned long) exp, note); + fprintf_filtered (stream, "\tLanguage %s, %d elements, %d bytes each.\n", + exp->language_defn->la_name, exp -> nelts, + sizeof (union exp_element)); + fprintf_filtered (stream, "\t%5s %20s %16s %s\n", "Index", "Opcode", + "Hex Value", "String Value"); + for (elt = 0; elt < exp -> nelts; elt++) + { + fprintf_filtered (stream, "\t%5d ", elt); + switch (exp -> elts[elt].opcode) + { + default: opcode_name = ""; break; + case OP_NULL: opcode_name = "OP_NULL"; break; + case BINOP_ADD: opcode_name = "BINOP_ADD"; break; + case BINOP_SUB: opcode_name = "BINOP_SUB"; break; + case BINOP_MUL: opcode_name = "BINOP_MUL"; break; + case BINOP_DIV: opcode_name = "BINOP_DIV"; break; + case BINOP_REM: opcode_name = "BINOP_REM"; break; + case BINOP_MOD: opcode_name = "BINOP_MOD"; break; + case BINOP_LSH: opcode_name = "BINOP_LSH"; break; + case BINOP_RSH: opcode_name = "BINOP_RSH"; break; + case BINOP_LOGICAL_AND: opcode_name = "BINOP_LOGICAL_AND"; break; + case BINOP_LOGICAL_OR: opcode_name = "BINOP_LOGICAL_OR"; break; + case BINOP_BITWISE_AND: opcode_name = "BINOP_BITWISE_AND"; break; + case BINOP_BITWISE_IOR: opcode_name = "BINOP_BITWISE_IOR"; break; + case BINOP_BITWISE_XOR: opcode_name = "BINOP_BITWISE_XOR"; break; + case BINOP_EQUAL: opcode_name = "BINOP_EQUAL"; break; + case BINOP_NOTEQUAL: opcode_name = "BINOP_NOTEQUAL"; break; + case BINOP_LESS: opcode_name = "BINOP_LESS"; break; + case BINOP_GTR: opcode_name = "BINOP_GTR"; break; + case BINOP_LEQ: opcode_name = "BINOP_LEQ"; break; + case BINOP_GEQ: opcode_name = "BINOP_GEQ"; break; + case BINOP_REPEAT: opcode_name = "BINOP_REPEAT"; break; + case BINOP_ASSIGN: opcode_name = "BINOP_ASSIGN"; break; + case BINOP_COMMA: opcode_name = "BINOP_COMMA"; break; + case BINOP_SUBSCRIPT: opcode_name = "BINOP_SUBSCRIPT"; break; + case MULTI_SUBSCRIPT: opcode_name = "MULTI_SUBSCRIPT"; break; + case BINOP_EXP: opcode_name = "BINOP_EXP"; break; + case BINOP_MIN: opcode_name = "BINOP_MIN"; break; + case BINOP_MAX: opcode_name = "BINOP_MAX"; break; + case BINOP_SCOPE: opcode_name = "BINOP_SCOPE"; break; + case STRUCTOP_MEMBER: opcode_name = "STRUCTOP_MEMBER"; break; + case STRUCTOP_MPTR: opcode_name = "STRUCTOP_MPTR"; break; + case BINOP_INTDIV: opcode_name = "BINOP_INTDIV"; break; + case BINOP_ASSIGN_MODIFY: opcode_name = "BINOP_ASSIGN_MODIFY"; break; + case BINOP_VAL: opcode_name = "BINOP_VAL"; break; + case BINOP_INCL: opcode_name = "BINOP_INCL"; break; + case BINOP_EXCL: opcode_name = "BINOP_EXCL"; break; + case BINOP_CONCAT: opcode_name = "BINOP_CONCAT"; break; + case BINOP_END: opcode_name = "BINOP_END"; break; + case TERNOP_COND: opcode_name = "TERNOP_COND"; break; + case OP_LONG: opcode_name = "OP_LONG"; break; + case OP_DOUBLE: opcode_name = "OP_DOUBLE"; break; + case OP_VAR_VALUE: opcode_name = "OP_VAR_VALUE"; break; + case OP_LAST: opcode_name = "OP_LAST"; break; + case OP_REGISTER: opcode_name = "OP_REGISTER"; break; + case OP_INTERNALVAR: opcode_name = "OP_INTERNALVAR"; break; + case OP_FUNCALL: opcode_name = "OP_FUNCALL"; break; + case OP_STRING: opcode_name = "OP_STRING"; break; + case OP_BITSTRING: opcode_name = "OP_BITSTRING"; break; + case OP_ARRAY: opcode_name = "OP_ARRAY"; break; + case UNOP_CAST: opcode_name = "UNOP_CAST"; break; + case UNOP_MEMVAL: opcode_name = "UNOP_MEMVAL"; break; + case UNOP_NEG: opcode_name = "UNOP_NEG"; break; + case UNOP_LOGICAL_NOT: opcode_name = "UNOP_LOGICAL_NOT"; break; + case UNOP_COMPLEMENT: opcode_name = "UNOP_COMPLEMENT"; break; + case UNOP_IND: opcode_name = "UNOP_IND"; break; + case UNOP_ADDR: opcode_name = "UNOP_ADDR"; break; + case UNOP_PREINCREMENT: opcode_name = "UNOP_PREINCREMENT"; break; + case UNOP_POSTINCREMENT: opcode_name = "UNOP_POSTINCREMENT"; break; + case UNOP_PREDECREMENT: opcode_name = "UNOP_PREDECREMENT"; break; + case UNOP_POSTDECREMENT: opcode_name = "UNOP_POSTDECREMENT"; break; + case UNOP_SIZEOF: opcode_name = "UNOP_SIZEOF"; break; + case UNOP_PLUS: opcode_name = "UNOP_PLUS"; break; + case UNOP_CAP: opcode_name = "UNOP_CAP"; break; + case UNOP_CHR: opcode_name = "UNOP_CHR"; break; + case UNOP_ORD: opcode_name = "UNOP_ORD"; break; + case UNOP_ABS: opcode_name = "UNOP_ABS"; break; + case UNOP_FLOAT: opcode_name = "UNOP_FLOAT"; break; + case UNOP_HIGH: opcode_name = "UNOP_HIGH"; break; + case UNOP_MAX: opcode_name = "UNOP_MAX"; break; + case UNOP_MIN: opcode_name = "UNOP_MIN"; break; + case UNOP_ODD: opcode_name = "UNOP_ODD"; break; + case UNOP_TRUNC: opcode_name = "UNOP_TRUNC"; break; + case OP_BOOL: opcode_name = "OP_BOOL"; break; + case OP_M2_STRING: opcode_name = "OP_M2_STRING"; break; + case STRUCTOP_STRUCT: opcode_name = "STRUCTOP_STRUCT"; break; + case STRUCTOP_PTR: opcode_name = "STRUCTOP_PTR"; break; + case OP_THIS: opcode_name = "OP_THIS"; break; + case OP_SCOPE: opcode_name = "OP_SCOPE"; break; + case OP_TYPE: opcode_name = "OP_TYPE"; break; + } + fprintf_filtered (stream, "%20s ", opcode_name); + fprintf_filtered (stream, +#if defined (PRINTF_HAS_LONG_LONG) + "%ll16x ", +#else + "%l16x ", +#endif + exp -> elts[elt].longconst); + + for (eltscan = (char *) &exp->elts[elt], + eltsize = sizeof (union exp_element) ; + eltsize-- > 0; + eltscan++) + { + fprintf_filtered (stream, "%c", + isprint (*eltscan) ? (*eltscan & 0xFF) : '.'); + } + fprintf_filtered (stream, "\n"); + } +} + +#endif /* DEBUG_EXPRESSIONS */ diff --git a/gnu/usr.bin/gdb/gdb/expression.h b/gnu/usr.bin/gdb/gdb/expression.h new file mode 100644 index 00000000000..521c25cb45a --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/expression.h @@ -0,0 +1,313 @@ +/* Definitions for expressions stored in reversed prefix form, for GDB. + Copyright 1986, 1989, 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. */ + +#if !defined (EXPRESSION_H) +#define EXPRESSION_H 1 + +#ifdef __STDC__ +struct block; /* Forward declaration for prototypes */ +#endif + +/* Definitions for saved C expressions. */ + +/* An expression is represented as a vector of union exp_element's. + Each exp_element is an opcode, except that some opcodes cause + the following exp_element to be treated as a long or double constant + or as a variable. The opcodes are obeyed, using a stack for temporaries. + The value is left on the temporary stack at the end. */ + +/* When it is necessary to include a string, + it can occupy as many exp_elements as it needs. + We find the length of the string using strlen, + divide to find out how many exp_elements are used up, + and skip that many. Strings, like numbers, are indicated + by the preceding opcode. */ + +enum exp_opcode +{ + /* Used when it's necessary to pass an opcode which will be ignored, + or to catch uninitialized values. */ + OP_NULL, + +/* BINOP_... operate on two values computed by following subexpressions, + replacing them by one result value. They take no immediate arguments. */ + BINOP_ADD, /* + */ + BINOP_SUB, /* - */ + BINOP_MUL, /* * */ + BINOP_DIV, /* / */ + BINOP_REM, /* % */ + BINOP_MOD, /* mod (Knuth 1.2.4) */ + BINOP_LSH, /* << */ + BINOP_RSH, /* >> */ + BINOP_LOGICAL_AND, /* && */ + BINOP_LOGICAL_OR, /* || */ + BINOP_BITWISE_AND, /* & */ + BINOP_BITWISE_IOR, /* | */ + BINOP_BITWISE_XOR, /* ^ */ + BINOP_EQUAL, /* == */ + BINOP_NOTEQUAL, /* != */ + BINOP_LESS, /* < */ + BINOP_GTR, /* > */ + BINOP_LEQ, /* <= */ + BINOP_GEQ, /* >= */ + BINOP_REPEAT, /* @ */ + BINOP_ASSIGN, /* = */ + BINOP_COMMA, /* , */ + BINOP_SUBSCRIPT, /* x[y] */ + BINOP_EXP, /* Exponentiation */ + +/* C++. */ + BINOP_MIN, /* ? */ + BINOP_SCOPE, /* :: */ + + /* STRUCTOP_MEMBER is used for pointer-to-member constructs. + X . * Y translates into X STRUCTOP_MEMBER Y. */ + STRUCTOP_MEMBER, + /* STRUCTOP_MPTR is used for pointer-to-member constructs + when X is a pointer instead of an aggregate. */ + STRUCTOP_MPTR, +/* end of C++. */ + + /* For Modula-2 integer division DIV */ + BINOP_INTDIV, + + BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on. + The following exp_element is another opcode, + a BINOP_, saying how to modify. + Then comes another BINOP_ASSIGN_MODIFY, + making three exp_elements in total. */ + + /* Modula-2 standard (binary) procedures*/ + BINOP_VAL, + BINOP_INCL, + BINOP_EXCL, + + /* Concatenate two operands, such as character strings or bitstrings. + If the first operand is a integer expression, then it means concatenate + the second operand with itself that many times. */ + BINOP_CONCAT, + + /* This must be the highest BINOP_ value, for expprint.c. */ + BINOP_END, + +/* Operates on three values computed by following subexpressions. */ + TERNOP_COND, /* ?: */ + +/* Multidimensional subscript operator, such as Modula-2 x[a,b,...]. + The dimensionality is encoded in the operator, like the number of + function arguments in OP_FUNCALL, I.E. . + The value of the first following subexpression is subscripted + by each of the next following subexpressions, one per dimension. */ + + MULTI_SUBSCRIPT, + +/* The OP_... series take immediate following arguments. + After the arguments come another OP_... (the same one) + so that the grouping can be recognized from the end. */ + +/* OP_LONG is followed by a type pointer in the next exp_element + and the long constant value in the following exp_element. + Then comes another OP_LONG. + Thus, the operation occupies four exp_elements. */ + + OP_LONG, +/* OP_DOUBLE is similar but takes a double constant instead of a long one. */ + OP_DOUBLE, + + /* OP_VAR_VALUE takes one struct block * in the following element, + and one struct symbol * in the following exp_element, followed by + another OP_VAR_VALUE, making four exp_elements. If the block is + non-NULL, evaluate the symbol relative to the innermost frame + executing in that block; if the block is NULL use the selected frame. */ + + OP_VAR_VALUE, + +/* OP_LAST is followed by an integer in the next exp_element. + The integer is zero for the last value printed, + or it is the absolute number of a history element. + With another OP_LAST at the end, this makes three exp_elements. */ + OP_LAST, +/* OP_REGISTER is followed by an integer in the next exp_element. + This is the number of a register to fetch (as an int). + With another OP_REGISTER at the end, this makes three exp_elements. */ + OP_REGISTER, +/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element. + With another OP_INTERNALVAR at the end, this makes three exp_elements. */ + OP_INTERNALVAR, +/* OP_FUNCALL is followed by an integer in the next exp_element. + The integer is the number of args to the function call. + That many plus one values from following subexpressions + are used, the first one being the function. + The integer is followed by a repeat of OP_FUNCALL, + making three exp_elements. */ + OP_FUNCALL, +/* OP_STRING represents a string constant. + Its format is the same as that of a STRUCTOP, but the string + data is just made into a string constant when the operation + is executed. */ + OP_STRING, +/* OP_BITSTRING represents a packed bitstring constant. + Its format is the same as that of a STRUCTOP, but the bitstring + data is just made into a bitstring constant when the operation + is executed. */ + OP_BITSTRING, +/* OP_ARRAY creates an array constant out of the following subexpressions. + It is followed by two exp_elements, the first containing an integer + that is the lower bound of the array and the second containing another + integer that is the upper bound of the array. The second integer is + followed by a repeat of OP_ARRAY, making four exp_elements total. + The bounds are used to compute the number of following subexpressions + to consume, as well as setting the bounds in the created array constant. + The type of the elements is taken from the type of the first subexp, + and they must all match. */ + OP_ARRAY, + +/* UNOP_CAST is followed by a type pointer in the next exp_element. + With another UNOP_CAST at the end, this makes three exp_elements. + It casts the value of the following subexpression. */ + UNOP_CAST, +/* UNOP_MEMVAL is followed by a type pointer in the next exp_element + With another UNOP_MEMVAL at the end, this makes three exp_elements. + It casts the contents of the word addressed by the value of the + following subexpression. */ + UNOP_MEMVAL, +/* UNOP_... operate on one value from a following subexpression + and replace it with a result. They take no immediate arguments. */ + UNOP_NEG, /* Unary - */ + UNOP_LOGICAL_NOT, /* Unary ! */ + UNOP_COMPLEMENT, /* Unary ~ */ + UNOP_IND, /* Unary * */ + UNOP_ADDR, /* Unary & */ + UNOP_PREINCREMENT, /* ++ before an expression */ + UNOP_POSTINCREMENT, /* ++ after an expression */ + UNOP_PREDECREMENT, /* -- before an expression */ + UNOP_POSTDECREMENT, /* -- after an expression */ + UNOP_SIZEOF, /* Unary sizeof (followed by expression) */ + + UNOP_PLUS, /* Unary plus */ + + UNOP_CAP, /* Modula-2 standard (unary) procedures */ + UNOP_CHR, + UNOP_ORD, + UNOP_ABS, + UNOP_FLOAT, + UNOP_HIGH, + UNOP_MAX, + UNOP_MIN, + UNOP_ODD, + UNOP_TRUNC, + + OP_BOOL, /* Modula-2 builtin BOOLEAN type */ + OP_M2_STRING, /* Modula-2 string constants */ + +/* STRUCTOP_... operate on a value from a following subexpression + by extracting a structure component specified by a string + that appears in the following exp_elements (as many as needed). + STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->". + They differ only in the error message given in case the value is + not suitable or the structure component specified is not found. + + The length of the string follows the opcode, followed by + BYTES_TO_EXP_ELEM(length) elements containing the data of the + string, followed by the length again and the opcode again. */ + + STRUCTOP_STRUCT, + STRUCTOP_PTR, + +/* C++ */ + /* OP_THIS is just a placeholder for the class instance variable. + It just comes in a tight (OP_THIS, OP_THIS) pair. */ + OP_THIS, + + /* OP_SCOPE surrounds a type name and a field name. The type + name is encoded as one element, but the field name stays as + a string, which, of course, is variable length. */ + OP_SCOPE, + + /* OP_TYPE is for parsing types, and used with the "ptype" command + so we can look up types that are qualified by scope, either with + the GDB "::" operator, or the Modula-2 '.' operator. */ + OP_TYPE +}; + +union exp_element +{ + enum exp_opcode opcode; + struct symbol *symbol; + LONGEST longconst; + double doubleconst; + /* Really sizeof (union exp_element) characters (or less for the last + element of a string). */ + char string; + struct type *type; + struct internalvar *internalvar; + struct block *block; +}; + +struct expression +{ + const struct language_defn *language_defn; /* language it was entered in */ + int nelts; + union exp_element elts[1]; +}; + +/* Macros for converting between number of expression elements and bytes + to store that many expression elements. */ + +#define EXP_ELEM_TO_BYTES(elements) \ + ((elements) * sizeof (union exp_element)) +#define BYTES_TO_EXP_ELEM(bytes) \ + (((bytes) + sizeof (union exp_element) - 1) / sizeof (union exp_element)) + +/* From parse.c */ + +extern struct expression * +parse_expression PARAMS ((char *)); + +extern struct expression * +parse_exp_1 PARAMS ((char **, struct block *, int)); + +/* The innermost context required by the stack and register variables + we've encountered so far. To use this, set it to NULL, then call + parse_, then look at it. */ +extern struct block *innermost_block; + +/* From expprint.c */ + +extern void +print_expression PARAMS ((struct expression *, FILE *)); + +extern char * +op_string PARAMS ((enum exp_opcode)); + +/* To enable dumping of all parsed expressions in a human readable + form, define DEBUG_EXPRESSIONS. This is a compile time constant + at the moment, since it's not clear that this feature is important + enough to include by default. */ + +#ifdef DEBUG_EXPRESSIONS +extern void +dump_expression PARAMS ((struct expression *, FILE *, char *)); +#define DUMP_EXPRESSION(exp,file,note) dump_expression ((exp), (file), (note)) +#else +#define DUMP_EXPRESSION(exp,file,note) /* Null expansion */ +#endif /* DEBUG_EXPRESSIONS */ + +#endif /* !defined (EXPRESSION_H) */ diff --git a/gnu/usr.bin/gdb/gdb/findvar.c b/gnu/usr.bin/gdb/gdb/findvar.c new file mode 100644 index 00000000000..bf50e1f0454 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/findvar.c @@ -0,0 +1,971 @@ +/* Find a variable's value in memory, for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "frame.h" +#include "value.h" +#include "gdbcore.h" +#include "inferior.h" +#include "target.h" + +/* Basic byte-swapping routines. GDB has needed these for a long time... + All extract a target-format integer at ADDR which is LEN bytes long. */ + +#if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8 + /* 8 bit characters are a pretty safe assumption these days, so we + assume it throughout all these swapping routines. If we had to deal with + 9 bit characters, we would need to make len be in bits and would have + to re-write these routines... */ + you lose +#endif + +LONGEST +extract_signed_integer (addr, len) + PTR addr; + int len; +{ + LONGEST retval; + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + if (len > sizeof (LONGEST)) + error ("\ +That operation is not available on integers of more than %d bytes.", + sizeof (LONGEST)); + + /* Start at the most significant end of the integer, and work towards + the least significant. */ +#if TARGET_BYTE_ORDER == BIG_ENDIAN + p = startaddr; +#else + p = endaddr - 1; +#endif + /* Do the sign extension once at the start. */ + retval = ((LONGEST)*p ^ 0x80) - 0x80; +#if TARGET_BYTE_ORDER == BIG_ENDIAN + for (++p; p < endaddr; ++p) +#else + for (--p; p >= startaddr; --p) +#endif + { + retval = (retval << 8) | *p; + } + return retval; +} + +unsigned LONGEST +extract_unsigned_integer (addr, len) + PTR addr; + int len; +{ + unsigned LONGEST retval; + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + if (len > sizeof (unsigned LONGEST)) + error ("\ +That operation is not available on integers of more than %d bytes.", + sizeof (unsigned LONGEST)); + + /* Start at the most significant end of the integer, and work towards + the least significant. */ + retval = 0; +#if TARGET_BYTE_ORDER == BIG_ENDIAN + for (p = startaddr; p < endaddr; ++p) +#else + for (p = endaddr - 1; p >= startaddr; --p) +#endif + { + retval = (retval << 8) | *p; + } + return retval; +} + +CORE_ADDR +extract_address (addr, len) + PTR addr; + int len; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + return extract_unsigned_integer (addr, len); +} + +void +store_signed_integer (addr, len, val) + PTR addr; + int len; + LONGEST val; +{ + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + /* Start at the least significant end of the integer, and work towards + the most significant. */ +#if TARGET_BYTE_ORDER == BIG_ENDIAN + for (p = endaddr - 1; p >= startaddr; --p) +#else + for (p = startaddr; p < endaddr; ++p) +#endif + { + *p = val & 0xff; + val >>= 8; + } +} + +void +store_unsigned_integer (addr, len, val) + PTR addr; + int len; + unsigned LONGEST val; +{ + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + /* Start at the least significant end of the integer, and work towards + the most significant. */ +#if TARGET_BYTE_ORDER == BIG_ENDIAN + for (p = endaddr - 1; p >= startaddr; --p) +#else + for (p = startaddr; p < endaddr; ++p) +#endif + { + *p = val & 0xff; + val >>= 8; + } +} + +void +store_address (addr, len, val) + PTR addr; + int len; + CORE_ADDR val; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + store_unsigned_integer (addr, len, (LONGEST)val); +} + +#if !defined (GET_SAVED_REGISTER) + +/* Return the address in which frame FRAME's value of register REGNUM + has been saved in memory. Or return zero if it has not been saved. + If REGNUM specifies the SP, the value we return is actually + the SP value, not an address where it was saved. */ + +CORE_ADDR +find_saved_register (frame, regnum) + FRAME frame; + int regnum; +{ + struct frame_info *fi; + struct frame_saved_regs saved_regs; + + register FRAME frame1 = 0; + register CORE_ADDR addr = 0; + + if (frame == 0) /* No regs saved if want current frame */ + return 0; + +#ifdef HAVE_REGISTER_WINDOWS + /* We assume that a register in a register window will only be saved + in one place (since the name changes and/or disappears as you go + towards inner frames), so we only call get_frame_saved_regs on + the current frame. This is directly in contradiction to the + usage below, which assumes that registers used in a frame must be + saved in a lower (more interior) frame. This change is a result + of working on a register window machine; get_frame_saved_regs + always returns the registers saved within a frame, within the + context (register namespace) of that frame. */ + + /* However, note that we don't want this to return anything if + nothing is saved (if there's a frame inside of this one). Also, + callers to this routine asking for the stack pointer want the + stack pointer saved for *this* frame; this is returned from the + next frame. */ + + + if (REGISTER_IN_WINDOW_P(regnum)) + { + frame1 = get_next_frame (frame); + if (!frame1) return 0; /* Registers of this frame are + active. */ + + /* Get the SP from the next frame in; it will be this + current frame. */ + if (regnum != SP_REGNUM) + frame1 = frame; + + fi = get_frame_info (frame1); + get_frame_saved_regs (fi, &saved_regs); + return saved_regs.regs[regnum]; /* ... which might be zero */ + } +#endif /* HAVE_REGISTER_WINDOWS */ + + /* Note that this next routine assumes that registers used in + frame x will be saved only in the frame that x calls and + frames interior to it. This is not true on the sparc, but the + above macro takes care of it, so we should be all right. */ + while (1) + { + QUIT; + frame1 = get_prev_frame (frame1); + if (frame1 == 0 || frame1 == frame) + break; + fi = get_frame_info (frame1); + get_frame_saved_regs (fi, &saved_regs); + if (saved_regs.regs[regnum]) + addr = saved_regs.regs[regnum]; + } + + return addr; +} + +/* Find register number REGNUM relative to FRAME and put its (raw, + target format) contents in *RAW_BUFFER. Set *OPTIMIZED if the + variable was optimized out (and thus can't be fetched). Set *LVAL + to lval_memory, lval_register, or not_lval, depending on whether + the value was fetched from memory, from a register, or in a strange + and non-modifiable way (e.g. a frame pointer which was calculated + rather than fetched). Set *ADDRP to the address, either in memory + on as a REGISTER_BYTE offset into the registers array. + + Note that this implementation never sets *LVAL to not_lval. But + it can be replaced by defining GET_SAVED_REGISTER and supplying + your own. + + The argument RAW_BUFFER must point to aligned memory. */ + +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + FRAME frame; + int regnum; + enum lval_type *lval; +{ + CORE_ADDR addr; + /* Normal systems don't optimize out things with register numbers. */ + if (optimized != NULL) + *optimized = 0; + addr = find_saved_register (frame, regnum); + if (addr != 0) + { + if (lval != NULL) + *lval = lval_memory; + if (regnum == SP_REGNUM) + { + if (raw_buffer != NULL) + { + /* Put it back in target format. */ + store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr); + } + if (addrp != NULL) + *addrp = 0; + return; + } + if (raw_buffer != NULL) + read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); + } + else + { + if (lval != NULL) + *lval = lval_register; + addr = REGISTER_BYTE (regnum); + if (raw_buffer != NULL) + read_register_gen (regnum, raw_buffer); + } + if (addrp != NULL) + *addrp = addr; +} +#endif /* GET_SAVED_REGISTER. */ + +/* Copy the bytes of register REGNUM, relative to the current stack frame, + into our memory at MYADDR, in target byte order. + The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). + + Returns 1 if could not be read, 0 if could. */ + +int +read_relative_register_raw_bytes (regnum, myaddr) + int regnum; + char *myaddr; +{ + int optim; + if (regnum == FP_REGNUM && selected_frame) + { + /* Put it back in target format. */ + store_address (myaddr, REGISTER_RAW_SIZE(FP_REGNUM), + FRAME_FP(selected_frame)); + return 0; + } + + get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, selected_frame, + regnum, (enum lval_type *)NULL); + return optim; +} + +/* Return a `value' with the contents of register REGNUM + in its virtual format, with the type specified by + REGISTER_VIRTUAL_TYPE. */ + +value +value_of_register (regnum) + int regnum; +{ + CORE_ADDR addr; + int optim; + register value val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + enum lval_type lval; + + get_saved_register (raw_buffer, &optim, &addr, + selected_frame, regnum, &lval); + + REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer); + val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); + memcpy (VALUE_CONTENTS_RAW (val), virtual_buffer, + REGISTER_VIRTUAL_SIZE (regnum)); + VALUE_LVAL (val) = lval; + VALUE_ADDRESS (val) = addr; + VALUE_REGNO (val) = regnum; + VALUE_OPTIMIZED_OUT (val) = optim; + return val; +} + +/* Low level examining and depositing of registers. + + The caller is responsible for making + sure that the inferior is stopped before calling the fetching routines, + or it will get garbage. (a change from GDB version 3, in which + the caller got the value from the last stop). */ + +/* Contents of the registers in target byte order. + We allocate some extra slop since we do a lot of memcpy's around `registers', + and failing-soft is better than failing hard. */ +char registers[REGISTER_BYTES + /* SLOP */ 256]; + +/* Nonzero if that register has been fetched. */ +char register_valid[NUM_REGS]; + +/* Indicate that registers may have changed, so invalidate the cache. */ +void +registers_changed () +{ + int i; + for (i = 0; i < NUM_REGS; i++) + register_valid[i] = 0; +} + +/* Indicate that all registers have been fetched, so mark them all valid. */ +void +registers_fetched () +{ + int i; + for (i = 0; i < NUM_REGS; i++) + register_valid[i] = 1; +} + +/* Copy LEN bytes of consecutive data from registers + starting with the REGBYTE'th byte of register data + into memory at MYADDR. */ + +void +read_register_bytes (regbyte, myaddr, len) + int regbyte; + char *myaddr; + int len; +{ + /* Fetch all registers. */ + int i; + for (i = 0; i < NUM_REGS; i++) + if (!register_valid[i]) + { + target_fetch_registers (-1); + break; + } + if (myaddr != NULL) + memcpy (myaddr, ®isters[regbyte], len); +} + +/* Read register REGNO into memory at MYADDR, which must be large enough + for REGISTER_RAW_BYTES (REGNO). Target byte-order. + If the register is known to be the size of a CORE_ADDR or smaller, + read_register can be used instead. */ +void +read_register_gen (regno, myaddr) + int regno; + char *myaddr; +{ + if (!register_valid[regno]) + target_fetch_registers (regno); + memcpy (myaddr, ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno)); +} + +/* Copy LEN bytes of consecutive data from memory at MYADDR + into registers starting with the REGBYTE'th byte of register data. */ + +void +write_register_bytes (regbyte, myaddr, len) + int regbyte; + char *myaddr; + int len; +{ + /* Make sure the entire registers array is valid. */ + read_register_bytes (0, (char *)NULL, REGISTER_BYTES); + memcpy (®isters[regbyte], myaddr, len); + target_store_registers (-1); +} + +/* Return the raw contents of register REGNO, regarding it as an integer. */ +/* This probably should be returning LONGEST rather than CORE_ADDR. */ + +CORE_ADDR +read_register (regno) + int regno; +{ + if (!register_valid[regno]) + target_fetch_registers (regno); + + return extract_address (®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE(regno)); +} + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +/* Store VALUE, into the raw contents of register number REGNO. */ +/* FIXME: The val arg should probably be a LONGEST. */ + +void +write_register (regno, val) + int regno; + LONGEST val; +{ + PTR buf; + int size; + + /* On the sparc, writing %g0 is a no-op, so we don't even want to change + the registers array if something writes to this register. */ + if (CANNOT_STORE_REGISTER (regno)) + return; + + size = REGISTER_RAW_SIZE(regno); + buf = alloca (size); + store_signed_integer (buf, size, (LONGEST) val); + + /* If we have a valid copy of the register, and new value == old value, + then don't bother doing the actual store. */ + + if (register_valid [regno]) + { + if (memcmp (®isters[REGISTER_BYTE (regno)], buf, size) == 0) + return; + } + + target_prepare_to_store (); + + memcpy (®isters[REGISTER_BYTE (regno)], buf, size); + + register_valid [regno] = 1; + + target_store_registers (regno); +} + +/* Record that register REGNO contains VAL. + This is used when the value is obtained from the inferior or core dump, + so there is no need to store the value there. */ + +void +supply_register (regno, val) + int regno; + char *val; +{ + register_valid[regno] = 1; + memcpy (®isters[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno)); + + /* On some architectures, e.g. HPPA, there are a few stray bits in some + registers, that the rest of the code would like to ignore. */ +#ifdef CLEAN_UP_REGISTER_VALUE + CLEAN_UP_REGISTER_VALUE(regno, ®isters[REGISTER_BYTE(regno)]); +#endif +} + +/* Will calling read_var_value or locate_var_value on SYM end + up caring what frame it is being evaluated relative to? SYM must + be non-NULL. */ +int +symbol_read_needs_frame (sym) + struct symbol *sym; +{ + switch (SYMBOL_CLASS (sym)) + { + /* All cases listed explicitly so that gcc -Wall will detect it if + we failed to consider one. */ + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + return 1; + + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_TYPEDEF: + + case LOC_LABEL: + /* Getting the address of a label can be done independently of the block, + even if some *uses* of that address wouldn't work so well without + the right frame. */ + + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + return 0; + } +} + +/* Given a struct symbol for a variable, + and a stack frame id, read the value of the variable + and return a (pointer to a) struct value containing the value. + If the variable cannot be found, return a zero pointer. + If FRAME is NULL, use the selected_frame. */ + +value +read_var_value (var, frame) + register struct symbol *var; + FRAME frame; +{ + register value v; + struct frame_info *fi; + struct type *type = SYMBOL_TYPE (var); + CORE_ADDR addr; + register int len; + + v = allocate_value (type); + VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ + len = TYPE_LENGTH (type); + + if (frame == 0) frame = selected_frame; + + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: + /* Put the constant back in target format. */ + store_signed_integer (VALUE_CONTENTS_RAW (v), len, + (LONGEST) SYMBOL_VALUE (var)); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_LABEL: + /* Put the constant back in target format. */ + store_address (VALUE_CONTENTS_RAW (v), len, SYMBOL_VALUE_ADDRESS (var)); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_CONST_BYTES: + { + char *bytes_addr; + bytes_addr = SYMBOL_VALUE_BYTES (var); + memcpy (VALUE_CONTENTS_RAW (v), bytes_addr, len); + VALUE_LVAL (v) = not_lval; + return v; + } + + case LOC_STATIC: + addr = SYMBOL_VALUE_ADDRESS (var); + break; + + case LOC_ARG: + fi = get_frame_info (frame); + if (fi == NULL) + return 0; + addr = FRAME_ARGS_ADDRESS (fi); + if (!addr) + { + return 0; + } + addr += SYMBOL_VALUE (var); + break; + + case LOC_REF_ARG: + fi = get_frame_info (frame); + if (fi == NULL) + return 0; + addr = FRAME_ARGS_ADDRESS (fi); + if (!addr) + { + return 0; + } + addr += SYMBOL_VALUE (var); + addr = read_memory_unsigned_integer + (addr, TARGET_PTR_BIT / TARGET_CHAR_BIT); + break; + + case LOC_LOCAL: + case LOC_LOCAL_ARG: + fi = get_frame_info (frame); + if (fi == NULL) + return 0; + addr = FRAME_LOCALS_ADDRESS (fi); + addr += SYMBOL_VALUE (var); + break; + + case LOC_BASEREG: + case LOC_BASEREG_ARG: + { + char buf[MAX_REGISTER_RAW_SIZE]; + get_saved_register (buf, NULL, NULL, frame, SYMBOL_BASEREG (var), + NULL); + addr = extract_address (buf, REGISTER_RAW_SIZE (SYMBOL_BASEREG (var))); + addr += SYMBOL_VALUE (var); + break; + } + + case LOC_TYPEDEF: + error ("Cannot look up value of a typedef"); + break; + + case LOC_BLOCK: + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + return v; + + case LOC_REGISTER: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + { + struct block *b; + + if (frame == NULL) + return 0; + b = get_frame_block (frame); + + v = value_from_register (type, SYMBOL_VALUE (var), frame); + + if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR) + { + addr = *(CORE_ADDR *)VALUE_CONTENTS (v); + VALUE_LVAL (v) = lval_memory; + } + else + return v; + } + break; + + case LOC_OPTIMIZED_OUT: + VALUE_LVAL (v) = not_lval; + VALUE_OPTIMIZED_OUT (v) = 1; + return v; + + default: + error ("Cannot look up value of a botched symbol."); + break; + } + + VALUE_ADDRESS (v) = addr; + VALUE_LAZY (v) = 1; + return v; +} + +/* Return a value of type TYPE, stored in register REGNUM, in frame + FRAME. */ + +value +value_from_register (type, regnum, frame) + struct type *type; + int regnum; + FRAME frame; +{ + char raw_buffer [MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + CORE_ADDR addr; + int optim; + value v = allocate_value (type); + int len = TYPE_LENGTH (type); + char *value_bytes = 0; + int value_bytes_copied = 0; + int num_storage_locs; + enum lval_type lval; + + VALUE_REGNO (v) = regnum; + + num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ? + ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 : + 1); + + if (num_storage_locs > 1 +#ifdef GDB_TARGET_IS_H8500 + || TYPE_CODE (type) == TYPE_CODE_PTR +#endif + ) + { + /* Value spread across multiple storage locations. */ + + int local_regnum; + int mem_stor = 0, reg_stor = 0; + int mem_tracking = 1; + CORE_ADDR last_addr = 0; + CORE_ADDR first_addr = 0; + + value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE); + + /* Copy all of the data out, whereever it may be. */ + +#ifdef GDB_TARGET_IS_H8500 +/* This piece of hideosity is required because the H8500 treats registers + differently depending upon whether they are used as pointers or not. As a + pointer, a register needs to have a page register tacked onto the front. + An alternate way to do this would be to have gcc output different register + numbers for the pointer & non-pointer form of the register. But, it + doesn't, so we're stuck with this. */ + + if (TYPE_CODE (type) == TYPE_CODE_PTR + && len > 2) + { + int page_regnum; + + switch (regnum) + { + case R0_REGNUM: case R1_REGNUM: case R2_REGNUM: case R3_REGNUM: + page_regnum = SEG_D_REGNUM; + break; + case R4_REGNUM: case R5_REGNUM: + page_regnum = SEG_E_REGNUM; + break; + case R6_REGNUM: case R7_REGNUM: + page_regnum = SEG_T_REGNUM; + break; + } + + value_bytes[0] = 0; + get_saved_register (value_bytes + 1, + &optim, + &addr, + frame, + page_regnum, + &lval); + + if (lval == lval_register) + reg_stor++; + else + mem_stor++; + first_addr = addr; + last_addr = addr; + + get_saved_register (value_bytes + 2, + &optim, + &addr, + frame, + regnum, + &lval); + + if (lval == lval_register) + reg_stor++; + else + { + mem_stor++; + mem_tracking = mem_tracking && (addr == last_addr); + } + last_addr = addr; + } + else +#endif /* GDB_TARGET_IS_H8500 */ + for (local_regnum = regnum; + value_bytes_copied < len; + (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum), + ++local_regnum)) + { + get_saved_register (value_bytes + value_bytes_copied, + &optim, + &addr, + frame, + local_regnum, + &lval); + + if (regnum == local_regnum) + first_addr = addr; + if (lval == lval_register) + reg_stor++; + else + { + mem_stor++; + + mem_tracking = + (mem_tracking + && (regnum == local_regnum + || addr == last_addr)); + } + last_addr = addr; + } + + if ((reg_stor && mem_stor) + || (mem_stor && !mem_tracking)) + /* Mixed storage; all of the hassle we just went through was + for some good purpose. */ + { + VALUE_LVAL (v) = lval_reg_frame_relative; + VALUE_FRAME (v) = FRAME_FP (frame); + VALUE_FRAME_REGNUM (v) = regnum; + } + else if (mem_stor) + { + VALUE_LVAL (v) = lval_memory; + VALUE_ADDRESS (v) = first_addr; + } + else if (reg_stor) + { + VALUE_LVAL (v) = lval_register; + VALUE_ADDRESS (v) = first_addr; + } + else + fatal ("value_from_register: Value not stored anywhere!"); + + VALUE_OPTIMIZED_OUT (v) = optim; + + /* Any structure stored in more than one register will always be + an integral number of registers. Otherwise, you'd need to do + some fiddling with the last register copied here for little + endian machines. */ + + /* Copy into the contents section of the value. */ + memcpy (VALUE_CONTENTS_RAW (v), value_bytes, len); + + /* Finally do any conversion necessary when extracting this + type from more than one register. */ +#ifdef REGISTER_CONVERT_TO_TYPE + REGISTER_CONVERT_TO_TYPE(regnum, type, VALUE_CONTENTS_RAW(v)); +#endif + return v; + } + + /* Data is completely contained within a single register. Locate the + register's contents in a real register or in core; + read the data in raw format. */ + + get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval); + VALUE_OPTIMIZED_OUT (v) = optim; + VALUE_LVAL (v) = lval; + VALUE_ADDRESS (v) = addr; + + /* Convert the raw contents to virtual contents. + (Just copy them if the formats are the same.) */ + + REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer); + + if (REGISTER_CONVERTIBLE (regnum)) + { + /* When the raw and virtual formats differ, the virtual format + corresponds to a specific data type. If we want that type, + copy the data into the value. + Otherwise, do a type-conversion. */ + + if (type != REGISTER_VIRTUAL_TYPE (regnum)) + { + /* eg a variable of type `float' in a 68881 register + with raw type `extended' and virtual type `double'. + Fetch it as a `double' and then convert to `float'. */ + /* FIXME: This value will be not_lval, which means we can't assign + to it. Probably the right fix is to do the cast on a temporary + value, and just copy the VALUE_CONTENTS over. */ + v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); + memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer, + REGISTER_VIRTUAL_SIZE (regnum)); + v = value_cast (type, v); + } + else + memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer, len); + } + else + { + /* Raw and virtual formats are the same for this register. */ + +#if TARGET_BYTE_ORDER == BIG_ENDIAN + if (len < REGISTER_RAW_SIZE (regnum)) + { + /* Big-endian, and we want less than full size. */ + VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len; + } +#endif + + memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer + VALUE_OFFSET (v), len); + } + + return v; +} + +/* Given a struct symbol for a variable or function, + and a stack frame id, + return a (pointer to a) struct value containing the properly typed + address. */ + +value +locate_var_value (var, frame) + register struct symbol *var; + FRAME frame; +{ + CORE_ADDR addr = 0; + struct type *type = SYMBOL_TYPE (var); + value lazy_value; + + /* Evaluate it first; if the result is a memory address, we're fine. + Lazy evaluation pays off here. */ + + lazy_value = read_var_value (var, frame); + if (lazy_value == 0) + error ("Address of \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var)); + + if (VALUE_LAZY (lazy_value) + || TYPE_CODE (type) == TYPE_CODE_FUNC) + { + addr = VALUE_ADDRESS (lazy_value); + return value_from_longest (lookup_pointer_type (type), (LONGEST) addr); + } + + /* Not a memory address; check what the problem was. */ + switch (VALUE_LVAL (lazy_value)) + { + case lval_register: + case lval_reg_frame_relative: + error ("Address requested for identifier \"%s\" which is in a register.", + SYMBOL_SOURCE_NAME (var)); + break; + + default: + error ("Can't take address of \"%s\" which isn't an lvalue.", + SYMBOL_SOURCE_NAME (var)); + break; + } + return 0; /* For lint -- never reached */ +} diff --git a/gnu/usr.bin/gdb/gdb/fopen-same.h b/gnu/usr.bin/gdb/gdb/fopen-same.h new file mode 100644 index 00000000000..0f37529d33e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/fopen-same.h @@ -0,0 +1,27 @@ +/* Macros for the 'type' part of an fopen, freopen or fdopen. + + [Update] + + This version is for "same" systems, where text and binary files are + the same. An example is Unix. Many Unix systems could also add a + "b" to the string, indicating binary files, but some reject this + (and thereby don't conform to ANSI C, but what else is new?). + + This file is designed for inclusion by host-dependent .h files. No + user application should include it directly, since that would make + the application unable to be configured for both "same" and "binary" + variant systems. */ + +#define FOPEN_RB "r" +#define FOPEN_WB "w" +#define FOPEN_AB "a" +#define FOPEN_RUB "r+" +#define FOPEN_WUB "w+" +#define FOPEN_AUB "a+" + +#define FOPEN_RT "r" +#define FOPEN_WT "w" +#define FOPEN_AT "a" +#define FOPEN_RUT "r+" +#define FOPEN_WUT "w+" +#define FOPEN_AUT "a+" diff --git a/gnu/usr.bin/gdb/gdb/fork-child.c b/gnu/usr.bin/gdb/gdb/fork-child.c new file mode 100644 index 00000000000..3c01b6021eb --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/fork-child.c @@ -0,0 +1,310 @@ +/* Fork a Unix child process, and set up to debug it, for GDB. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +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. */ + +#include "defs.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "gdbcore.h" +#include "terminal.h" + +#include + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include + +extern int original_stack_limit; +#endif /* SET_STACK_LIMIT_HUGE */ + +extern char **environ; + +/* Start an inferior Unix child process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). */ + +#ifndef SHELL_FILE +#define SHELL_FILE "/bin/sh" +#endif + +void +fork_inferior (exec_file, allargs, env, traceme_fun, init_trace_fun) + char *exec_file; + char *allargs; + char **env; + void (*traceme_fun) PARAMS ((void)); + void (*init_trace_fun) PARAMS ((int)); +{ + int pid; + char *shell_command; + char *shell_file; + static char default_shell_file[] = SHELL_FILE; + int len; + int pending_execs; + int terminal_initted; + /* Set debug_fork then attach to the child while it sleeps, to debug. */ + static int debug_fork = 0; + /* This is set to the result of setpgrp, which if vforked, will be visible + to you in the parent process. It's only used by humans for debugging. */ + static int debug_setpgrp = 657473; + char **save_our_env; + + /* If no exec file handed to us, get it from the exec-file command -- with + a good, common error message if none is specified. */ + if (exec_file == 0) + exec_file = get_exec_file(1); + + /* The user might want tilde-expansion, and in general probably wants + the program to behave the same way as if run from + his/her favorite shell. So we let the shell run it for us. + FIXME, this should probably search the local environment (as + modified by the setenv command), not the env gdb inherited. */ + shell_file = getenv ("SHELL"); + if (shell_file == NULL) + shell_file = default_shell_file; + + /* Multiplying the length of exec_file by 4 is to account for the fact + that it may expand when quoted; it is a worst-case number based on + every character being '. */ + len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop*/ 12; + /* If desired, concat something onto the front of ALLARGS. + SHELL_COMMAND is the result. */ +#ifdef SHELL_COMMAND_CONCAT + shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len); + strcpy (shell_command, SHELL_COMMAND_CONCAT); +#else + shell_command = (char *) alloca (len); + shell_command[0] = '\0'; +#endif + strcat (shell_command, "exec "); + + /* Now add exec_file, quoting as necessary. */ + { + char *p; + int need_to_quote; + + /* Quoting in this style is said to work with all shells. But csh + on IRIX 4.0.1 can't deal with it. So we only quote it if we need + to. */ + p = exec_file; + while (1) + { + switch (*p) + { + case '\'': + case '"': + case '(': + case ')': + case '$': + case '&': + case ';': + case '<': + case '>': + case ' ': + case '\n': + case '\t': + need_to_quote = 1; + goto end_scan; + + case '\0': + need_to_quote = 0; + goto end_scan; + + default: + break; + } + ++p; + } + end_scan: + if (need_to_quote) + { + strcat (shell_command, "'"); + for (p = exec_file; *p != '\0'; ++p) + { + if (*p == '\'') + strcat (shell_command, "'\\''"); + else + strncat (shell_command, p, 1); + } + strcat (shell_command, "'"); + } + else + strcat (shell_command, exec_file); + } + + strcat (shell_command, " "); + strcat (shell_command, allargs); + + /* exec is said to fail if the executable is open. */ + close_exec_file (); + + /* Retain a copy of our environment variables, since the child will + replace the value of environ and if we're vforked, we have to + restore it. */ + save_our_env = environ; + + /* Tell the terminal handling subsystem what tty we plan to run on; + it will just record the information for later. */ + + new_tty_prefork (inferior_io_terminal); + + /* It is generally good practice to flush any possible pending stdio + output prior to doing a fork, to avoid the possibility of both the + parent and child flushing the same data after the fork. */ + + fflush (stdout); + fflush (stderr); + +#if defined(USG) && !defined(HAVE_VFORK) + pid = fork (); +#else + if (debug_fork) + pid = fork (); + else + pid = vfork (); +#endif + + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + if (debug_fork) + sleep (debug_fork); + + /* Run inferior in a separate process group. */ + debug_setpgrp = gdb_setpgid (); + if (debug_setpgrp == -1) + perror("setpgrp failed in child"); + +#ifdef SET_STACK_LIMIT_HUGE + /* Reset the stack limit back to what it was. */ + { + struct rlimit rlim; + + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = original_stack_limit; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* SET_STACK_LIMIT_HUGE */ + + /* Ask the tty subsystem to switch to the one we specified earlier + (or to share the current terminal, if none was specified). */ + + new_tty (); + + /* Changing the signal handlers for the inferior after + a vfork can also change them for the superior, so we don't mess + with signals here. See comments in + initialize_signals for how we get the right signal handlers + for the inferior. */ + + /* "Trace me, Dr. Memory!" */ + (*traceme_fun) (); + + /* There is no execlpe call, so we have to set the environment + for our child in the global variable. If we've vforked, this + clobbers the parent, but environ is restored a few lines down + in the parent. By the way, yes we do need to look down the + path to find $SHELL. Rich Pixley says so, and I agree. */ + environ = env; + execlp (shell_file, shell_file, "-c", shell_command, (char *)0); + + fprintf (stderr, "Cannot exec %s: %s.\n", shell_file, + safe_strerror (errno)); + fflush (stderr); + _exit (0177); + } + + /* Restore our environment in case a vforked child clob'd it. */ + environ = save_our_env; + + init_thread_list(); + + /* Now that we have a child process, make it our target, and + initialize anything target-vector-specific that needs initializing. */ + (*init_trace_fun)(pid); + + /* The process was started by the fork that created it, + but it will have stopped one instruction after execing the shell. + Here we must get it up to actual execution of the real program. */ + + inferior_pid = pid; /* Needed for wait_for_inferior stuff below */ + + clear_proceed_status (); + + /* We will get a trace trap after one instruction. + Continue it automatically. Eventually (after shell does an exec) + it will get another trace trap. Then insert breakpoints and continue. */ + +#ifdef START_INFERIOR_TRAPS_EXPECTED + pending_execs = START_INFERIOR_TRAPS_EXPECTED; +#else + pending_execs = 2; +#endif + + init_wait_for_inferior (); + + terminal_initted = 0; + + while (1) + { + stop_soon_quietly = 1; /* Make wait_for_inferior be quiet */ + wait_for_inferior (); + if (stop_signal != SIGTRAP) + { + /* Let shell child handle its own signals in its own way */ + /* FIXME, what if child has exit()ed? Must exit loop somehow */ + resume (0, stop_signal); + } + else + { + /* We handle SIGTRAP, however; it means child did an exec. */ + if (!terminal_initted) + { + /* Now that the child has exec'd we know it has already set its + process group. On POSIX systems, tcsetpgrp will fail with + EPERM if we try it before the child's setpgid. */ + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + terminal_initted = 1; + } + if (0 == --pending_execs) + break; + resume (0, 0); /* Just make it go on */ + } + } + stop_soon_quietly = 0; + + /* We are now in the child process of interest, having exec'd the + correct program, and are poised at the first instruction of the + new program. */ +#ifdef SOLIB_CREATE_INFERIOR_HOOK + SOLIB_CREATE_INFERIOR_HOOK (pid); +#endif +} diff --git a/gnu/usr.bin/gdb/gdb/frame.h b/gnu/usr.bin/gdb/gdb/frame.h new file mode 100644 index 00000000000..1fe6fb6a49b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/frame.h @@ -0,0 +1,238 @@ +/* Definitions for dealing with stack frames, for GDB, the GNU debugger. + Copyright 1986, 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. */ + +#if !defined (FRAME_H) +#define FRAME_H 1 + +/* A FRAME identifies a specific stack frame. It is not constant over + calls to the inferior (frame addresses are, see below). + + This is implemented as a "struct frame_info *". This file and + blockframe.c are the only places which are allowed to use the + equivalence between FRAME and struct frame_info *. Exception: + Prototypes in other files use "struct frame_info *" because this + file might not be included. + + The distinction between a FRAME and a "struct frame_info *" is made + with the idea of maybe someday changing a FRAME to be something else, + but seems to me that a "struct frame_info *" is fully general (since + any necessarily fields can be added; changing the meaning of existing + fields is not helped by the FRAME distinction), and this distinction + merely creates unnecessary hair. -kingdon, 18 May 93. */ +typedef struct frame_info *FRAME; + +/* Convert from a "struct frame_info *" into a FRAME. */ +#define FRAME_INFO_ID(f) (f) + +/* Convert from a FRAME into a "struct frame_info *". */ +extern struct frame_info * +get_frame_info PARAMS ((FRAME)); + +/* Type of the address of a frame. It is widely assumed (at least in + prototypes in headers which might not include this header) that + this is the same as CORE_ADDR, and no one can think of a case in + which it wouldn't be, so it might be best to remove this typedef. */ +typedef CORE_ADDR FRAME_ADDR; + +/* Convert from a FRAME into a frame address. Except in the + machine-dependent *FRAME* macros, a frame address has no defined + meaning other than as a magic cookie which identifies a frame over + calls to the inferior. The only known exception is inferior.h + (PC_IN_CALL_DUMMY) [ON_STACK]; see comments there. You cannot + assume that a frame address contains enough information to + reconstruct the frame; if you want more than just to identify the + frame (e.g. be able to fetch variables relative to that frame), + then save the whole struct frame_info (and the next struct + frame_info, since the latter is used for fetching variables on some + machines). */ + +#define FRAME_FP(fr) ((fr)->frame) + +/* We keep a cache of stack frames, each of which is a "struct + frame_info". The innermost one gets allocated (in + wait_for_inferior) each time the inferior stops; current_frame + points to it. Additional frames get allocated (in + get_prev_frame_info) as needed, and are chained through the next + and prev fields. Any time that the frame cache becomes invalid + (most notably when we execute something, but also if we change how + we interpret the frames (e.g. "set heuristic-fence-post" in + mips-tdep.c, or anything which reads new symbols)), we should call + reinit_frame_cache. */ + +struct frame_info + { + /* Nominal address of the frame described. See comments at FRAME_FP + about what this means outside the *FRAME* macros; in the *FRAME* + macros, it can mean whatever makes most sense for this machine. */ + FRAME_ADDR frame; + + /* Address at which execution is occurring in this frame. + For the innermost frame, it's the current pc. + For other frames, it is a pc saved in the next frame. */ + CORE_ADDR pc; + + /* Nonzero if this is a frame associated with calling a signal handler. + + Set by machine-dependent code. On some machines, if + the machine-dependent code fails to check for this, the backtrace + will look relatively normal. For example, on the i386 + #3 0x158728 in sighold () + On other machines (e.g. rs6000), the machine-dependent code better + set this to prevent us from trying to print it like a normal frame. */ + int signal_handler_caller; + + /* Anything extra for this structure that may have been defined + in the machine dependent files. */ +#ifdef EXTRA_FRAME_INFO + EXTRA_FRAME_INFO +#endif + + /* We should probably also store a "struct frame_saved_regs" here. + This is already done by some machines (e.g. config/m88k/tm-m88k.h) + but there is no reason it couldn't be general. */ + + /* Pointers to the next and previous frame_info's in the frame cache. */ + FRAME next, prev; + }; + +/* Describe the saved registers of a frame. */ + +struct frame_saved_regs + { + + /* For each register, address of where it was saved on entry to + the frame, or zero if it was not saved on entry to this frame. + This includes special registers such as pc and fp saved in + special ways in the stack frame. The SP_REGNUM is even more + special, the address here is the sp for the next frame, not the + address where the sp was saved. */ + + CORE_ADDR regs[NUM_REGS]; + }; + +/* Define a default FRAME_CHAIN_VALID, in the form that is suitable for most + targets. If FRAME_CHAIN_VALID returns zero it means that the given frame + is the outermost one and has no caller. + + If a particular target needs a different definition, then it can override + the definition here by providing one in the tm file. */ + +#if !defined (FRAME_CHAIN_VALID) + +#if defined (FRAME_CHAIN_VALID_ALTERNATE) + +/* Use the alternate method of avoiding running up off the end of the frame + chain or following frames back into the startup code. See the comments + in objfiles.h. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + ((chain) != 0 \ + && !inside_main_func ((thisframe) -> pc) \ + && !inside_entry_func ((thisframe) -> pc)) + +#else + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + ((chain) != 0 \ + && !inside_entry_file (FRAME_SAVED_PC (thisframe))) + +#endif /* FRAME_CHAIN_VALID_ALTERNATE */ + +#endif /* FRAME_CHAIN_VALID */ + +/* The stack frame that the user has specified for commands to act on. + Note that one cannot assume this is the address of valid data. */ + +extern FRAME selected_frame; + +/* Level of the selected frame: + 0 for innermost, 1 for its caller, ... + or -1 for frame specified by address with no defined level. */ + +extern int selected_frame_level; + +extern struct frame_info * +get_prev_frame_info PARAMS ((FRAME)); + +extern FRAME +create_new_frame PARAMS ((FRAME_ADDR, CORE_ADDR)); + +extern void +flush_cached_frames PARAMS ((void)); + +extern void +reinit_frame_cache PARAMS ((void)); + +extern void +get_frame_saved_regs PARAMS ((struct frame_info *, struct frame_saved_regs *)); + +extern void +set_current_frame PARAMS ((FRAME)); + +extern FRAME +get_prev_frame PARAMS ((FRAME)); + +extern FRAME +get_current_frame PARAMS ((void)); + +extern FRAME +get_next_frame PARAMS ((FRAME)); + +extern struct block * +get_frame_block PARAMS ((FRAME)); + +extern struct block * +get_current_block PARAMS ((void)); + +extern struct block * +get_selected_block PARAMS ((void)); + +extern struct symbol * +get_frame_function PARAMS ((FRAME)); + +extern CORE_ADDR +get_frame_pc PARAMS ((FRAME)); + +extern CORE_ADDR +get_pc_function_start PARAMS ((CORE_ADDR)); + +extern struct block * block_for_pc PARAMS ((CORE_ADDR)); + +extern int frameless_look_for_prologue PARAMS ((FRAME)); + +extern void print_frame_args PARAMS ((struct symbol *, struct frame_info *, + int, FILE *)); + +extern FRAME find_relative_frame PARAMS ((FRAME, int*)); + +extern void print_stack_frame PARAMS ((FRAME, int, int)); + +extern void select_frame PARAMS ((FRAME, int)); + +extern void record_selected_frame PARAMS ((FRAME_ADDR *, int *)); + +extern void print_frame_info PARAMS ((struct frame_info *, int, int, int)); + +extern CORE_ADDR find_saved_register PARAMS ((FRAME, int)); + +extern FRAME block_innermost_frame PARAMS ((struct block *)); + +extern CORE_ADDR sigtramp_saved_pc PARAMS ((FRAME)); + +#endif /* !defined (FRAME_H) */ diff --git a/gnu/usr.bin/gdb/gdb/freebsd-nat.c b/gnu/usr.bin/gdb/gdb/freebsd-nat.c new file mode 100644 index 00000000000..deb68ebb945 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/freebsd-nat.c @@ -0,0 +1,323 @@ +/* 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. */ + +#include "defs.h" +#include + +/* this table must line up with REGISTER_NAMES in tm-i386.h */ +/* symbols like 'tEAX' come from */ +static int tregmap[] = +{ + tEAX, tECX, tEDX, tEBX, + tESP, tEBP, tESI, tEDI, + tEIP, tEFLAGS, tCS, tSS +}; +#ifdef sEAX +static int sregmap[] = +{ + sEAX, sECX, sEDX, sEBX, + sESP, sEBP, sESI, sEDI, + sEIP, sEFLAGS, sCS, sSS +}; +#endif +/* 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; +{ + /* The following condition is a kludge to get at the proper register map + depending upon the state of pcb_flag. + The proper condition would be + if (u.u_pcb.pcb_flag & FM_TRAP) + but that would require a ptrace call here and wouldn't work + for corefiles. */ + +#ifdef sEAX + if (blockend < 0x1fcc) + return (blockend + 4 * tregmap[regnum]); + else + return (blockend + 4 * sregmap[regnum]); +#else + return (blockend + 4 * tregmap[regnum]); +#endif +} + +#ifdef FLOAT_INFO +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ +#include +#undef curpcb +#include +#include +#include + +#define fpstate save87 +#define U_FPSTATE(u) u.u_pcb.pcb_savefpu + +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 */ +} + +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"); +} + +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]; +}; + +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); +} + +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 +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 ("last exception: "); + 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 `p->regs. + */ + st_regno = (fpreg + 8 - top) & 0x7; + + 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); + } +} + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in */ + 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 + { + printf("float info: can't do a core file (yet)\n"); + + return; +#if 0 + 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 + } + + print_387_status (0, (struct env387 *)buf); +} + +#endif diff --git a/gnu/usr.bin/gdb/gdb/freebsd-solib.c b/gnu/usr.bin/gdb/gdb/freebsd-solib.c new file mode 100644 index 00000000000..5b6e4c07309 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/freebsd-solib.c @@ -0,0 +1,1469 @@ +/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger. + Copyright 1990, 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. */ +/* modified for FreeBSD, since the names in link.h are totally different! + 6.1.94 */ + +#include "defs.h" + +#include +#include +#include +#ifndef SVR4_SHARED_LIBS + /* SunOS shared libs need the nlist structure. */ +#include +#endif +#include +#include +#include + +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" +#include "command.h" +#include "target.h" +#include "frame.h" +#include "regex.h" +#include "inferior.h" +#include "language.h" + +#define MAX_PATH_SIZE 256 /* FIXME: Should be dynamic */ + +/* On SVR4 systems, for the initial implementation, use some runtime startup + symbol as the "startup mapping complete" breakpoint address. The models + for SunOS and SVR4 dynamic linking debugger support are different in that + SunOS hits one breakpoint when all mapping is complete while using the SVR4 + debugger support takes two breakpoint hits for each file mapped, and + there is no way to know when the "last" one is hit. Both these + mechanisms should be tied to a "breakpoint service routine" that + gets automatically executed whenever one of the breakpoints indicating + a change in mapping is hit. This is a future enhancement. (FIXME) */ + +#define BKPT_AT_SYMBOL 1 + +#if defined (BKPT_AT_SYMBOL) && defined (SVR4_SHARED_LIBS) +static char *bkpt_names[] = { +#ifdef SOLIB_BKPT_NAME + SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */ +#endif + "_start", + "main", + NULL +}; +#endif + +/* local data declarations */ + +#ifndef SVR4_SHARED_LIBS + +#define DEBUG_BASE "_DYNAMIC" +#ifdef OLD_FreeBSD_LD +#define LM_ADDR(so) ((so) -> lm.lm_addr) +#define LM_NEXT(so) ((so) -> lm.lm_next) +#define LM_NAME(so) ((so) -> lm.lm_name) +static struct link_dynamic dynamic_copy; +static struct link_dynamic_2 ld_2_copy; +static struct ld_debug debug_copy; +#else +#define LM_ADDR(so) ((so) -> lm.som_addr) +#define LM_NEXT(so) ((so) -> lm.som_next) +#define LM_NAME(so) ((so) -> lm.som_path) +static struct _dynamic dynamic_copy; +static struct section_dispatch_table ld_2_copy; +static struct so_debug debug_copy; +#endif +static CORE_ADDR debug_addr; +static CORE_ADDR flag_addr; + +#else /* SVR4_SHARED_LIBS */ + +#define DEBUG_BASE "_r_debug" +#define LM_ADDR(so) ((so) -> lm.l_addr) +#define LM_NEXT(so) ((so) -> lm.l_next) +#define LM_NAME(so) ((so) -> lm.l_name) +static struct r_debug debug_copy; +char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ + +#endif /* !SVR4_SHARED_LIBS */ + +struct so_list { + struct so_list *next; /* next structure in linked list */ +#ifdef OLD_FreeBSD_LD + struct link_map lm; /* copy of link map from inferior */ + struct link_map *lmaddr; /* addr in inferior lm was read from */ +#else + struct so_map lm; /* copy of link map from inferior */ + struct so_map *lmaddr; /* addr in inferior lm was read from */ +#endif + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; + struct section_table *textsection; + bfd *abfd; +}; + +static struct so_list *so_list_head; /* List of known shared objects */ +static CORE_ADDR debug_base; /* Base of dynamic linker structures */ +static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ + +extern int +fdmatch PARAMS ((int, int)); /* In libiberty */ + +/* Local function prototypes */ + +static void +special_symbol_handling PARAMS ((struct so_list *)); + +static void +sharedlibrary_command PARAMS ((char *, int)); + +static int +enable_break PARAMS ((void)); + +static int +disable_break PARAMS ((void)); + +static void +info_sharedlibrary_command PARAMS ((char *, int)); + +static int +symbol_add_stub PARAMS ((char *)); + +static struct so_list * +find_solib PARAMS ((struct so_list *)); + +#ifdef OLD_FreeBSD_LD +static struct link_map * +#else +static struct so_map * +#endif +first_link_map_member PARAMS ((void)); + +static CORE_ADDR +locate_base PARAMS ((void)); + +static void +solib_map_sections PARAMS ((struct so_list *)); + +#ifdef SVR4_SHARED_LIBS + +static int +look_for_base PARAMS ((int, CORE_ADDR)); + +static CORE_ADDR +bfd_lookup_symbol PARAMS ((bfd *, char *)); + +#else + +static void +solib_add_common_symbols PARAMS ((struct rt_symbol *, struct objfile *)); + +#endif + +/* + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + +static void +solib_map_sections (so) + struct so_list *so; +{ + char *filename; + char *scratch_pathname; + int scratch_chan; + struct section_table *p; + struct cleanup *old_chain; + bfd *abfd; + + filename = tilde_expand (so -> so_name); + old_chain = make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &scratch_pathname); + if (scratch_chan < 0) + { + scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, + O_RDONLY, 0, &scratch_pathname); + } + if (scratch_chan < 0) + { + perror_with_name (filename); + } + /* Leave scratch_pathname allocated. abfd->name will point to it. */ + + abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!abfd) + { + close (scratch_chan); + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_error)); + } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ + so -> abfd = abfd; + abfd -> cacheable = true; + + if (!bfd_check_format (abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_error)); + } + if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + bfd_get_filename (exec_bfd), bfd_errmsg (bfd_error)); + } + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the base address to which the object was actually + mapped. */ + p -> addr += (CORE_ADDR) LM_ADDR (so); + p -> endaddr += (CORE_ADDR) LM_ADDR (so); + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + if (STREQ (p -> sec_ptr -> name, ".text")) + { + so -> textsection = p; + } + } + + /* Free the file names, close the file now. */ + do_cleanups (old_chain); +} + +/* Read all dynamically loaded common symbol definitions from the inferior + and add them to the minimal symbol table for the shared library objfile. */ + +#ifndef SVR4_SHARED_LIBS + +/* In GDB 4.9 this routine was a real performance hog. According to + some gprof data which mtranle@paris.IntelliCorp.COM (Minh Tran-Le) + sent, almost all the time spend in solib_add (up to 20 minutes with + 35 shared libraries) was spent here, with 5/6 in + lookup_minimal_symbol and 1/6 in read_memory. + + To fix this, we moved the call to special_symbol_handling out of the + loop in solib_add, so this only gets called once, rather than once + for every shared library, and also removed the call to lookup_minimal_symbol + in this routine. */ + +static void +solib_add_common_symbols (rtc_symp, objfile) + struct rt_symbol *rtc_symp; + struct objfile *objfile; +{ + struct rt_symbol inferior_rtc_symb; + struct nzlist inferior_rtc_nzlist; + int len; + char *name; + char *origname; + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + while (rtc_symp) + { + read_memory ((CORE_ADDR) rtc_symp, + (char *) &inferior_rtc_symb, + sizeof (inferior_rtc_symb)); + read_memory ((CORE_ADDR) inferior_rtc_symb.rt_sp, + (char *) &inferior_rtc_nzlist, + sizeof(inferior_rtc_nzlist)); + if (inferior_rtc_nzlist.nz_type == N_COMM) + { + /* FIXME: The length of the symbol name is not available, but in the + current implementation the common symbol is allocated immediately + behind the name of the symbol. */ + len = inferior_rtc_nzlist.nz_value - inferior_rtc_nzlist.nz_strx; + + origname = name = xmalloc (len); + read_memory ((CORE_ADDR) inferior_rtc_nzlist.nz_name, name, len); + + /* Don't enter the symbol twice if the target is re-run. */ + + if (name[0] == bfd_get_symbol_leading_char (objfile->obfd)) + { + name++; + } + +#if 0 + /* I think this is unnecessary, GDB can probably deal with + duplicate minimal symbols, more or less. And the duplication + which used to happen because this was called for each shared + library is gone now that we are just called once. */ + /* FIXME: Do we really want to exclude symbols which happen + to match symbols for other locations in the inferior's + address space, even when they are in different linkage units? */ + if (lookup_minimal_symbol (name, (struct objfile *) NULL) == NULL) +#endif + { + name = obsavestring (name, strlen (name), + &objfile -> symbol_obstack); + prim_record_minimal_symbol (name, inferior_rtc_nzlist.nz_value, + mst_bss); + } + free (origname); + } + rtc_symp = inferior_rtc_symb.rt_next; + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); +} + +#endif /* SVR4_SHARED_LIBS */ + +#ifdef SVR4_SHARED_LIBS + +/* + +LOCAL FUNCTION + + bfd_lookup_symbol -- lookup the value for a specific symbol + +SYNOPSIS + + CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) + +DESCRIPTION + + An expensive way to lookup the value of a single symbol for + bfd's that are only temporary anyway. This is used by the + shared library support to find the address of the debugger + interface structures in the shared library. + + Note that 0 is specifically allowed as an error return (no + such symbol). + + FIXME: See if there is a less "expensive" way of doing this. + Also see if there is already another bfd or gdb function + that specifically does this, and if so, use it. +*/ + +static CORE_ADDR +bfd_lookup_symbol (abfd, symname) + bfd *abfd; + char *symname; +{ + unsigned int storage_needed; + asymbol *sym; + asymbol **symbol_table; + unsigned int number_of_symbols; + unsigned int i; + struct cleanup *back_to; + CORE_ADDR symaddr = 0; + + storage_needed = get_symtab_upper_bound (abfd); + + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, (PTR)symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + + for (i = 0; i < number_of_symbols; i++) + { + sym = *symbol_table++; + if (STREQ (sym -> name, symname)) + { + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + break; + } + } + do_cleanups (back_to); + } + return (symaddr); +} + +/* + +LOCAL FUNCTION + + look_for_base -- examine file for each mapped address segment + +SYNOPSYS + + static int look_for_base (int fd, CORE_ADDR baseaddr) + +DESCRIPTION + + This function is passed to proc_iterate_over_mappings, which + causes it to get called once for each mapped address space, with + an open file descriptor for the file mapped to that space, and the + base address of that mapped space. + + Our job is to find the symbol DEBUG_BASE in the file that this + fd is open on, if it exists, and if so, initialize the dynamic + linker structure base address debug_base. + + Note that this is a computationally expensive proposition, since + we basically have to open a bfd on every call, so we specifically + avoid opening the exec file. + */ + +static int +look_for_base (fd, baseaddr) + int fd; + CORE_ADDR baseaddr; +{ + bfd *interp_bfd; + CORE_ADDR address; + + /* If the fd is -1, then there is no file that corresponds to this + mapped memory segment, so skip it. Also, if the fd corresponds + to the exec file, skip it as well. */ + + if ((fd == -1) || fdmatch (fileno ((FILE *)(exec_bfd -> iostream)), fd)) + { + return (0); + } + + /* Try to open whatever random file this fd corresponds to. Note that + we have no way currently to find the filename. Don't gripe about + any problems we might have, just fail. */ + + if ((interp_bfd = bfd_fdopenr ("unnamed", gnutarget, fd)) == NULL) + { + return (0); + } + if (!bfd_check_format (interp_bfd, bfd_object)) + { + bfd_close (interp_bfd); + return (0); + } + + /* Now try to find our DEBUG_BASE symbol in this file, which we at + least know to be a valid ELF executable or shared library. */ + + if ((address = bfd_lookup_symbol (interp_bfd, DEBUG_BASE)) == 0) + { + bfd_close (interp_bfd); + return (0); + } + + /* Eureka! We found the symbol. But now we may need to relocate it + by the base address. If the symbol's value is less than the base + address of the shared library, then it hasn't yet been relocated + by the dynamic linker, and we have to do it ourself. FIXME: Note + that we make the assumption that the first segment that corresponds + to the shared library has the base address to which the library + was relocated. */ + + if (address < baseaddr) + { + address += baseaddr; + } + debug_base = address; + bfd_close (interp_bfd); + return (1); +} + +#endif + +/* + +LOCAL FUNCTION + + locate_base -- locate the base address of dynamic linker structs + +SYNOPSIS + + CORE_ADDR locate_base (void) + +DESCRIPTION + + For both the SunOS and SVR4 shared library implementations, if the + inferior executable has been linked dynamically, there is a single + address somewhere in the inferior's data space which is the key to + locating all of the dynamic linker's runtime structures. This + address is the value of the symbol defined by the macro DEBUG_BASE. + The job of this function is to find and return that address, or to + return 0 if there is no such address (the executable is statically + linked for example). + + For SunOS, the job is almost trivial, since the dynamic linker and + all of it's structures are statically linked to the executable at + link time. Thus the symbol for the address we are looking for has + already been added to the minimal symbol table for the executable's + objfile at the time the symbol file's symbols were read, and all we + have to do is look it up there. Note that we explicitly do NOT want + to find the copies in the shared library. + + The SVR4 version is much more complicated because the dynamic linker + and it's structures are located in the shared C library, which gets + run as the executable's "interpreter" by the kernel. We have to go + to a lot more work to discover the address of DEBUG_BASE. Because + of this complexity, we cache the value we find and return that value + on subsequent invocations. Note there is no copy in the executable + symbol tables. + + Note that we can assume nothing about the process state at the time + we need to find this address. We may be stopped on the first instruc- + tion of the interpreter (C shared library), the first instruction of + the executable itself, or somewhere else entirely (if we attached + to the process for example). + + */ + +static CORE_ADDR +locate_base () +{ + +#ifndef SVR4_SHARED_LIBS + + struct minimal_symbol *msymbol; + CORE_ADDR address = 0; + + /* For SunOS, we want to limit the search for DEBUG_BASE to the executable + being debugged, since there is a duplicate named symbol in the shared + library. We don't want the shared library versions. */ + + msymbol = lookup_minimal_symbol (DEBUG_BASE, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + address = SYMBOL_VALUE_ADDRESS (msymbol); + } + return (address); + +#else /* SVR4_SHARED_LIBS */ + + /* Check to see if we have a currently valid address, and if so, avoid + doing all this work again and just return the cached address. If + we have no cached address, ask the /proc support interface to iterate + over the list of mapped address segments, calling look_for_base() for + each segment. When we are done, we will have either found the base + address or not. */ + + if (debug_base == 0) + { + proc_iterate_over_mappings (look_for_base); + } + return (debug_base); + +#endif /* !SVR4_SHARED_LIBS */ + +} + +/* + +LOCAL FUNCTION + + first_link_map_member -- locate first member in dynamic linker's map + +SYNOPSIS + + static struct link_map *first_link_map_member (void) + +DESCRIPTION + + Read in a copy of the first member in the inferior's dynamic + link map from the inferior's dynamic linker structures, and return + a pointer to the copy in our address space. +*/ + +#ifdef OLD_FreeBSD_LD +static struct link_map * +#else +static struct so_map * +#endif +first_link_map_member () +{ +#ifdef OLD_FreeBSD_LD + struct link_map *lm = NULL; +#else + struct so_map *lm = NULL; +#endif + +#ifndef SVR4_SHARED_LIBS + + read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy)); +#ifdef OLD_FreeBSD_LD + if (dynamic_copy.ld_version >= 2) + { + /* It is a version that we can deal with, so read in the secondary + structure and find the address of the link map list from it. */ + read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, (char *) &ld_2_copy, + sizeof (struct link_dynamic_2)); + lm = ld_2_copy.ld_loaded; + } +#else + if (dynamic_copy.d_version >= 2) + { + /* It is a version that we can deal with, so read in the secondary + structure and find the address of the link map list from it. */ + read_memory ((CORE_ADDR) dynamic_copy.d_un.d_sdt, (char *) &ld_2_copy, + sizeof (struct section_dispatch_table)); + lm = ld_2_copy.sdt_loaded; + } +#endif +#else /* SVR4_SHARED_LIBS */ + + read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug)); + /* FIXME: Perhaps we should validate the info somehow, perhaps by + checking r_version for a known version number, or r_state for + RT_CONSISTENT. */ + lm = debug_copy.r_map; + +#endif /* !SVR4_SHARED_LIBS */ + + return (lm); +} + +/* + +LOCAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. + + The arg and return value are "struct link_map" pointers, as defined + in . + */ + +static struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; +#ifdef OLD_FreeBSD_LD + struct link_map *lm = NULL; +#else + struct so_map *lm = NULL; +#endif + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* We have not already read in the dynamic linking structures + from the inferior, lookup the address of the base structure. */ + debug_base = locate_base (); + if (debug_base != 0) + { + /* Read the base structure in and find the address of the first + link map list member. */ + lm = first_link_map_member (); + } + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + if ((lm = LM_NEXT (so_list_ptr)) == NULL) + { + /* We have hit the end of the list, so check to see if any were + added, but be quiet if we can't read from the target any more. */ + int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr, + (char *) &(so_list_ptr -> lm), +#ifdef OLD_FreeBSD_LD + sizeof (struct link_map)); +#else + sizeof (struct so_map)); +#endif + if (status == 0) + { + lm = LM_NEXT (so_list_ptr); + } + else + { + lm = NULL; + } + } + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *) new, 0, sizeof (struct so_list)); + new -> lmaddr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + read_memory ((CORE_ADDR) lm, (char *) &(new -> lm), +#ifdef OLD_FreeBSD_LD + sizeof (struct link_map)); +#else + sizeof (struct so_map)); +#endif + /* For the SVR4 version, there is one entry that has no name + (for the inferior executable) since it is not a shared object. */ + if (LM_NAME (new) != 0) + { + if (!target_read_string((CORE_ADDR) LM_NAME (new), new -> so_name, + MAX_PATH_SIZE - 1)) + error ("find_solib: Can't read pathname for load map\n"); + new -> so_name[MAX_PATH_SIZE - 1] = 0; + solib_map_sections (new); + } + } + return (so_list_next); +} + +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ + +static int +symbol_add_stub (arg) + char *arg; +{ + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + so -> objfile = symbol_file_add (so -> so_name, so -> from_tty, + (unsigned int) so -> textsection -> addr, + 0, 0, 0); + return (1); +} + +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + register struct so_list *so = NULL; /* link map state variable */ + + /* Last shared library that we read. */ + struct so_list *so_last = NULL; + + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && re_exec (so -> so_name)) + { + so -> from_tty = from_tty; + if (so -> symbols_loaded) + { + if (from_tty) + { + printf ("Symbols already loaded for %s\n", so -> so_name); + } + } + else if (catch_errors + (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + so_last = so; + so -> symbols_loaded = 1; + } + } + } + + /* Now add the shared library sections to the section table of the + specified target, if any. */ + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + /* Reallocate the target's section table including the new size. */ + if (target -> to_sections) + { + old = target -> to_sections_end - target -> to_sections; + target -> to_sections = (struct section_table *) + xrealloc ((char *)target -> to_sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * count); + } + target -> to_sections_end = target -> to_sections + (count + old); + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count = so -> sections_end - so -> sections; + memcpy ((char *) (target -> to_sections + old), + so -> sections, + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } + + /* Calling this once at the end means that we put all the minimal + symbols for commons into the objfile for the last shared library. + Since they are in common, this should not be a problem. If we + delete the objfile with the minimal symbols, we can put all the + symbols into a new objfile (and will on the next call to solib_add). + + An alternate approach would be to create an objfile just for + common minsyms, thus not needing any objfile argument to + solib_add_common_symbols. */ + + if (so_last) + special_symbol_handling (so_last); +} + +/* + +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION + + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if (!header_done) + { + printf("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + printf ("%-12s", + local_hex_string_custom ((unsigned long) LM_ADDR (so), + "08l")); + printf ("%-12s", + local_hex_string_custom ((unsigned long) so -> lmend, + "08l")); + printf ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf ("%s\n", so -> so_name); + } + } + if (so_list_head == NULL) + { + printf ("No shared libraries loaded at this time.\n"); + } +} + +/* + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + int solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + +int +solib_address (address) + CORE_ADDR address; +{ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if ((address >= (CORE_ADDR) LM_ADDR (so)) && + (address < (CORE_ADDR) so -> lmend)) + { + return (1); + } + } + } + return (0); +} + +/* Called by free_all_symtabs */ + +void +clear_solib() +{ + struct so_list *next; + char *bfd_filename; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free ((PTR)so_list_head -> sections); + } + if (so_list_head -> abfd) + { + bfd_filename = bfd_get_filename (so_list_head -> abfd); + bfd_close (so_list_head -> abfd); + } + else + /* This happens for the executable on SVR4. */ + bfd_filename = NULL; + + next = so_list_head -> next; + if (bfd_filename) + free ((PTR)bfd_filename); + free ((PTR)so_list_head); + so_list_head = next; + } + debug_base = 0; +} + +/* + +LOCAL FUNCTION + + disable_break -- remove the "mapping changed" breakpoint + +SYNOPSIS + + static int disable_break () + +DESCRIPTION + + Removes the breakpoint that gets hit when the dynamic linker + completes a mapping change. + +*/ + +static int +disable_break () +{ + int status = 1; + +#ifndef SVR4_SHARED_LIBS + + int in_debugger = 0; + + /* Read the debugger structure from the inferior to retrieve the + address of the breakpoint and the original contents of the + breakpoint address. Remove the breakpoint by writing the original + contents back. */ + + read_memory (debug_addr, (char *) &debug_copy, sizeof (debug_copy)); + + /* Set `in_debugger' to zero now. */ + + write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); + +#ifdef OLD_FreeBSD_LD + breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr; + write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst, + sizeof (debug_copy.ldd_bp_inst)); +#else + breakpoint_addr = (CORE_ADDR) debug_copy.dd_bpt_addr; + write_memory (breakpoint_addr, (char *) &debug_copy.dd_bpt_shadow, + sizeof (debug_copy.dd_bpt_shadow)); +#endif + +#else /* SVR4_SHARED_LIBS */ + + /* Note that breakpoint address and original contents are in our address + space, so we just need to write the original contents back. */ + + if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) + { + status = 0; + } + +#endif /* !SVR4_SHARED_LIBS */ + + /* For the SVR4 version, we always know the breakpoint address. For the + SunOS version we don't know it until the above code is executed. + Grumble if we are stopped anywhere besides the breakpoint address. */ + + if (stop_pc != breakpoint_addr) + { + warning ("stopped at unknown breakpoint while handling shared libraries"); + } + + return (status); +} + +/* + +LOCAL FUNCTION + + enable_break -- arrange for dynamic linker to hit breakpoint + +SYNOPSIS + + int enable_break (void) + +DESCRIPTION + + Both the SunOS and the SVR4 dynamic linkers have, as part of their + debugger interface, support for arranging for the inferior to hit + a breakpoint after mapping in the shared libraries. This function + enables that breakpoint. + + For SunOS, there is a special flag location (in_debugger) which we + set to 1. When the dynamic linker sees this flag set, it will set + a breakpoint at a location known only to itself, after saving the + original contents of that place and the breakpoint address itself, + in it's own internal structures. When we resume the inferior, it + will eventually take a SIGTRAP when it runs into the breakpoint. + We handle this (in a different place) by restoring the contents of + the breakpointed location (which is only known after it stops), + chasing around to locate the shared libraries that have been + loaded, then resuming. + + For SVR4, the debugger interface structure contains a member (r_brk) + which is statically initialized at the time the shared library is + built, to the offset of a function (_r_debug_state) which is guaran- + teed to be called once before mapping in a library, and again when + the mapping is complete. At the time we are examining this member, + it contains only the unrelocated offset of the function, so we have + to do our own relocation. Later, when the dynamic linker actually + runs, it relocates r_brk to be the actual address of _r_debug_state(). + + The debugger interface structure also contains an enumeration which + is set to either RT_ADD or RT_DELETE prior to changing the mapping, + depending upon whether or not the library is being mapped or unmapped, + and then set to RT_CONSISTENT after the library is mapped/unmapped. +*/ + +static int +enable_break () +{ + int success = 0; + +#ifndef SVR4_SHARED_LIBS + + int j; + int in_debugger; + + /* Get link_dynamic structure */ + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return (0); + } + + /* Calc address of debugger interface structure */ + +#ifdef OLD_FreeBSD_LD + debug_addr = (CORE_ADDR) dynamic_copy.ldd; +#else + debug_addr = (CORE_ADDR) dynamic_copy.d_debug; +#endif + + /* Calc address of `in_debugger' member of debugger interface structure */ + +#ifdef OLD_FreeBSD_LD + flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger - + (char *) &debug_copy); +#else + flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.dd_in_debugger - + (char *) &debug_copy); +#endif + + /* Write a value of 1 to this member. */ + + in_debugger = 1; + write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); + success = 1; + +#else /* SVR4_SHARED_LIBS */ + +#ifdef BKPT_AT_SYMBOL + + struct minimal_symbol *msymbol; + char **bkpt_namep; + CORE_ADDR bkpt_addr; + + /* Scan through the list of symbols, trying to look up the symbol and + set a breakpoint there. Terminate loop when we/if we succeed. */ + + breakpoint_addr = 0; + for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) + { + msymbol = lookup_minimal_symbol (*bkpt_namep, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + bkpt_addr = SYMBOL_VALUE_ADDRESS (msymbol); + if (target_insert_breakpoint (bkpt_addr, shadow_contents) == 0) + { + breakpoint_addr = bkpt_addr; + success = 1; + break; + } + } + } + +#else /* !BKPT_AT_SYMBOL */ + + struct symtab_and_line sal; + + /* Read the debugger interface structure directly. */ + + read_memory (debug_base, (char *) &debug_copy, sizeof (debug_copy)); + + /* Set breakpoint at the debugger interface stub routine that will + be called just prior to each mapping change and again after the + mapping change is complete. Set up the (nonexistent) handler to + deal with hitting these breakpoints. (FIXME). */ + + warning ("'%s': line %d: missing SVR4 support code", __FILE__, __LINE__); + success = 1; + +#endif /* BKPT_AT_SYMBOL */ + +#endif /* !SVR4_SHARED_LIBS */ + + return (success); +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + + For SunOS executables, this first instruction is typically the + one at "_start", or a similar text label, regardless of whether + the executable is statically or dynamically linked. The runtime + startup code takes care of dynamically linking in any shared + libraries, once gdb allows the inferior to continue. + + For SVR4 executables, this first instruction is either the first + instruction in the dynamic linker (for dynamically linked + executables) or the instruction at "start" for statically linked + executables. For dynamically linked executables, the system + first exec's /lib/libc.so.N, which contains the dynamic linker, + and starts it running. The dynamic linker maps in any needed + shared libraries, maps in the actual user executable, and then + jumps to "start" in the user executable. + + For both SunOS shared libraries, and SVR4 shared libraries, we + can arrange to cooperate with the dynamic linker to discover the + names of shared libraries that are dynamically linked, and the + base addresses to which they are linked. + + This function is responsible for discovering those names and + addresses, and saving sufficient information about them to allow + their symbols to be read at a later time. + +FIXME + + Between enable_break() and disable_break(), this code does not + properly handle hitting breakpoints which the user might have + set in the startup code or in the dynamic linker itself. Proper + handling will probably have to wait until the implementation is + changed to use the "breakpoint handler function" method. + + Also, what if child has exit()ed? Must exit loop somehow. + */ + +void +solib_create_inferior_hook() +{ + /* If we are using the BKPT_AT_SYMBOL code, then we don't need the base + yet. In fact, in the case of a SunOS4 executable being run on + Solaris, we can't get it yet. find_solib will get it when it needs + it. */ +#if !(defined (SVR4_SHARED_LIBS) && defined (BKPT_AT_SYMBOL)) + if ((debug_base = locate_base ()) == 0) + { + /* Can't find the symbol or the executable is statically linked. */ + return; + } +#endif + + if (!enable_break ()) + { + warning ("shared library handler failed to enable breakpoint"); + return; + } + + /* Now run the target. It will eventually hit the breakpoint, at + which point all of the libraries will have been mapped in and we + can go groveling around in the dynamic linker structures to find + out what we need to know about them. */ + + clear_proceed_status (); + stop_soon_quietly = 1; + stop_signal = 0; + do + { + target_resume (-1, 0, stop_signal); + wait_for_inferior (); + } + while (stop_signal != SIGTRAP); + stop_soon_quietly = 0; + + /* We are now either at the "mapping complete" breakpoint (or somewhere + else, a condition we aren't prepared to deal with anyway), so adjust + the PC as necessary after a breakpoint, disable the breakpoint, and + add any shared libraries that were mapped in. */ + + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + } + + if (!disable_break ()) + { + warning ("shared library handler failed to disable breakpoint"); + } + + solib_add ((char *) 0, 0, (struct target_ops *) 0); +} + +/* + +LOCAL FUNCTION + + special_symbol_handling -- additional shared library symbol handling + +SYNOPSIS + + void special_symbol_handling (struct so_list *so) + +DESCRIPTION + + Once the symbols from a shared object have been loaded in the usual + way, we are called to do any system specific symbol handling that + is needed. + + For Suns, this consists of grunging around in the dynamic linkers + structures to find symbol definitions for "common" symbols and + adding them to the minimal symbol table for the corresponding + objfile. + +*/ + +static void +special_symbol_handling (so) +struct so_list *so; +{ +#ifndef SVR4_SHARED_LIBS + int j; + + if (debug_addr == 0) + { + /* Get link_dynamic structure */ + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return; + } + + /* Calc address of debugger interface structure */ + /* FIXME, this needs work for cross-debugging of core files + (byteorder, size, alignment, etc). */ + +#ifdef OLD_FreeBSD_LD + debug_addr = (CORE_ADDR) dynamic_copy.ldd; +#else + debug_addr = (CORE_ADDR) dynamic_copy.d_debug; +#endif + } + + /* Read the debugger structure from the inferior, just to make sure + we have a current copy. */ + + j = target_read_memory (debug_addr, (char *) &debug_copy, + sizeof (debug_copy)); + if (j) + return; /* unreadable */ + + /* Get common symbol definitions for the loaded object. */ + +#ifdef OLD_FreeBSD_LD + if (debug_copy.ldd_cp) + { + solib_add_common_symbols (debug_copy.ldd_cp, so -> objfile); + } +#else + if (debug_copy.dd_cc) + { + solib_add_common_symbols (debug_copy.dd_cc, so -> objfile); + } +#endif + +#endif /* !SVR4_SHARED_LIBS */ +} + + +/* + +LOCAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + static void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +sharedlibrary_command (args, from_tty) +char *args; +int from_tty; +{ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); +} + +void +_initialize_solib() +{ + + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); +} diff --git a/gnu/usr.bin/gdb/gdb/gdb-stabs.h b/gnu/usr.bin/gdb/gdb/gdb-stabs.h new file mode 100644 index 00000000000..c1e0253842e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdb-stabs.h @@ -0,0 +1,76 @@ +/* Definitions for symbol-reading containing "stabs", for GDB. + Copyright 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +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. */ + +/* This file exists to hold the common definitions required of most of + the symbol-readers that end up using stabs. The common use of + these `symbol-type-specific' customizations of the generic data + structures makes the stabs-oriented symbol readers able to call + each others' functions as required. */ + +#if !defined (GDBSTABS_H) +#define GDBSTABS_H + +/* Offsets in the psymtab's section_offsets array for various kinds of + stabs symbols. Every psymtab built from stabs will have these offsets + filled in by these guidelines, so that when actually reading symbols, the + proper offset can simply be selected and added to the symbol value. */ + +#define SECT_OFF_TEXT 0 +#define SECT_OFF_DATA 1 +#define SECT_OFF_BSS 2 +#define SECT_OFF_RODATA 3 +#define SECT_OFF_MAX 4 /* Count of possible values */ + +/* The stab_section_info chain remembers info from the ELF symbol table, + while psymtabs are being built for the other symbol tables in the + objfile. It is destroyed at the complation of psymtab-reading. + Any info that was used from it has been copied into psymtabs. */ + +struct stab_section_info { + char *filename; + CORE_ADDR sections[SECT_OFF_MAX]; + struct stab_section_info *next; + int found; /* Count of times it's found in searching */ +}; + +/* Information is passed among various dbxread routines for accessing + symbol files. A pointer to this structure is kept in the sym_stab_info + field of the objfile struct. */ + +struct dbx_symfile_info { + asection *text_sect; /* Text section accessor */ + int symcount; /* How many symbols are there in the file */ + char *stringtab; /* The actual string table */ + int stringtab_size; /* Its size */ + file_ptr symtab_offset; /* Offset in file to symbol table */ + int symbol_size; /* Bytes in a single symbol */ + struct stab_section_info *stab_section_info; /* section starting points + of the original .o files before linking. */ +}; + +#define DBX_SYMFILE_INFO(o) ((struct dbx_symfile_info *)((o)->sym_stab_info)) +#define DBX_TEXT_SECT(o) (DBX_SYMFILE_INFO(o)->text_sect) +#define DBX_SYMCOUNT(o) (DBX_SYMFILE_INFO(o)->symcount) +#define DBX_STRINGTAB(o) (DBX_SYMFILE_INFO(o)->stringtab) +#define DBX_STRINGTAB_SIZE(o) (DBX_SYMFILE_INFO(o)->stringtab_size) +#define DBX_SYMTAB_OFFSET(o) (DBX_SYMFILE_INFO(o)->symtab_offset) +#define DBX_SYMBOL_SIZE(o) (DBX_SYMFILE_INFO(o)->symbol_size) + +#endif /* GDBSTABS_H */ diff --git a/gnu/usr.bin/gdb/gdb/gdb.1 b/gnu/usr.bin/gdb/gdb/gdb.1 new file mode 100644 index 00000000000..ccb216ee88f --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdb.1 @@ -0,0 +1,371 @@ +.\" Copyright (c) 1991 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.\" $Id: gdb.1,v 1.1.1.1 1993/10/30 21:59:13 jkh Exp $ +.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 "[\|" \-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 \-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/gdb/gdb/gdbcmd.h b/gnu/usr.bin/gdb/gdb/gdbcmd.h new file mode 100644 index 00000000000..88f323c7360 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdbcmd.h @@ -0,0 +1,101 @@ +/* Header file for GDB-specific command-line stuff. + Copyright 1986, 1989, 1990, 1992 Free Software Foundation, Inc. + +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. */ + +#if !defined (GDBCMD_H) +#define GDBCMD_H 1 + +#include "command.h" + +/* Chain containing all defined commands. */ + +extern struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +extern struct cmd_list_element *infolist; + +/* Chain containing all defined enable subcommands. */ + +extern struct cmd_list_element *enablelist; + +/* Chain containing all defined disable subcommands. */ + +extern struct cmd_list_element *disablelist; + +/* Chain containing all defined delete subcommands. */ + +extern struct cmd_list_element *deletelist; + +/* Chain containing all defined "enable breakpoint" subcommands. */ + +extern struct cmd_list_element *enablebreaklist; + +/* Chain containing all defined set subcommands */ + +extern struct cmd_list_element *setlist; + +/* Chain containing all defined unset subcommands */ + +extern struct cmd_list_element *unsetlist; + +/* Chain containing all defined show subcommands. */ + +extern struct cmd_list_element *showlist; + +/* Chain containing all defined \"set history\". */ + +extern struct cmd_list_element *sethistlist; + +/* Chain containing all defined \"show history\". */ + +extern struct cmd_list_element *showhistlist; + +/* Chain containing all defined \"unset history\". */ + +extern struct cmd_list_element *unsethistlist; + +/* Chain containing all defined maintenance subcommands. */ + +extern struct cmd_list_element *maintenancelist; + +/* Chain containing all defined "maintenance info" subcommands. */ + +extern struct cmd_list_element *maintenanceinfolist; + +/* Chain containing all defined "maintenance print" subcommands. */ + +extern struct cmd_list_element *maintenanceprintlist; + +extern struct cmd_list_element *setprintlist; + +extern struct cmd_list_element *showprintlist; + +extern struct cmd_list_element *setchecklist; + +extern struct cmd_list_element *showchecklist; + +extern void +execute_user_command PARAMS ((struct cmd_list_element *, char *)); + +extern void +execute_command PARAMS ((char *, int)); + +extern char **noop_completer PARAMS ((char *, char *)); + +extern char **filename_completer PARAMS ((char *, char *)); + +#endif /* !defined (GDBCMD_H) */ diff --git a/gnu/usr.bin/gdb/gdb/gdbcore.h b/gnu/usr.bin/gdb/gdb/gdbcore.h new file mode 100644 index 00000000000..ec0f1b5a950 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdbcore.h @@ -0,0 +1,129 @@ +/* Machine independent variables that describe the core file under GDB. + Copyright 1986, 1987, 1989, 1990, 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. */ + +/* Interface routines for core, executable, etc. */ + +#if !defined (GDBCORE_H) +#define GDBCORE_H 1 + +#include "bfd.h" /* Binary File Description */ + +/* Return the name of the executable file as a string. + ERR nonzero means get error if there is none specified; + otherwise return 0 in that case. */ + +extern char * +get_exec_file PARAMS ((int err)); + +/* Nonzero if there is a core file. */ + +extern int +have_core_file_p PARAMS ((void)); + +/* Read "memory data" from whatever target or inferior we have. + Returns zero if successful, errno value if not. EIO is used + for address out of bounds. If breakpoints are inserted, returns + shadow contents, not the breakpoints themselves. From breakpoint.c. */ + +extern int +read_memory_nobpt PARAMS ((CORE_ADDR memaddr, char *myaddr, unsigned len)); + +/* Report a memory error with error(). */ + +extern void +memory_error PARAMS ((int status, CORE_ADDR memaddr)); + +/* Like target_read_memory, but report an error if can't read. */ + +extern void +read_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +/* Read an integer from debugged memory, given address and number of bytes. */ + +extern LONGEST +read_memory_integer PARAMS ((CORE_ADDR memaddr, int len)); + +/* Read an unsigned integer from debugged memory, given address and number of bytes. */ + +extern unsigned LONGEST +read_memory_unsigned_integer PARAMS ((CORE_ADDR memaddr, int len)); + +/* If this is prototyped, need to deal with void* vs. char*. */ + +extern void +write_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) PARAMS ((char *filename)); + +extern void +specify_exec_file_hook PARAMS ((void (*hook) (char *filename))); + +/* Binary File Diddlers for the exec and core files */ +extern bfd *core_bfd; +extern bfd *exec_bfd; + +/* Whether to open exec and core files read-only or read-write. */ + +extern int write_files; + +extern void +core_file_command PARAMS ((char *filename, int from_tty)); + +extern void +exec_file_command PARAMS ((char *filename, int from_tty)); + +extern void +validate_files PARAMS ((void)); + +extern unsigned int +register_addr PARAMS ((int regno, int blockend)); + +extern int +xfer_core_file PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +extern void +fetch_core_registers PARAMS ((char *core_reg_sect, unsigned core_reg_size, + int which, unsigned int reg_addr)); + +extern void +registers_fetched PARAMS ((void)); + +#if !defined (KERNEL_U_ADDR) +extern CORE_ADDR kernel_u_addr; +#define KERNEL_U_ADDR kernel_u_addr +#endif + +/* The target vector for core files */ +extern struct target_ops core_ops; + + /* target vector functions called directly from elsewhere */ +void +core_open PARAMS ((char *, int)); + +void +core_detach PARAMS ((char *, int)); + +/* The current default bfd target. */ +extern char *gnutarget; + +extern void set_gnutarget PARAMS ((char *)); + +#endif /* !defined (GDBCORE_H) */ diff --git a/gnu/usr.bin/gdb/gdb/gdbtypes.c b/gnu/usr.bin/gdb/gdb/gdbtypes.c new file mode 100644 index 00000000000..f34646935aa --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdbtypes.c @@ -0,0 +1,1440 @@ +/* Support routines for manipulating internal types for GDB. + Copyright (C) 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +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. */ + +#include "defs.h" +#include +#include "bfd.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbtypes.h" +#include "expression.h" +#include "language.h" +#include "target.h" +#include "value.h" +#include "demangle.h" +#include "complaints.h" + +/* These variables point to the objects + representing the predefined C data types. */ + +struct type *builtin_type_void; +struct type *builtin_type_char; +struct type *builtin_type_short; +struct type *builtin_type_int; +struct type *builtin_type_long; +struct type *builtin_type_long_long; +struct type *builtin_type_signed_char; +struct type *builtin_type_unsigned_char; +struct type *builtin_type_unsigned_short; +struct type *builtin_type_unsigned_int; +struct type *builtin_type_unsigned_long; +struct type *builtin_type_unsigned_long_long; +struct type *builtin_type_float; +struct type *builtin_type_double; +struct type *builtin_type_long_double; +struct type *builtin_type_complex; +struct type *builtin_type_double_complex; +struct type *builtin_type_string; + +/* Alloc a new type structure and fill it with some defaults. If + OBJFILE is non-NULL, then allocate the space for the type structure + in that objfile's type_obstack. */ + +struct type * +alloc_type (objfile) + struct objfile *objfile; +{ + register struct type *type; + + /* Alloc the structure and start off with all fields zeroed. */ + + if (objfile == NULL) + { + type = (struct type *) xmalloc (sizeof (struct type)); + } + else + { + type = (struct type *) obstack_alloc (&objfile -> type_obstack, + sizeof (struct type)); + } + memset ((char *) type, 0, sizeof (struct type)); + + /* Initialize the fields that might not be zero. */ + + TYPE_CODE (type) = TYPE_CODE_UNDEF; + TYPE_OBJFILE (type) = objfile; + TYPE_VPTR_FIELDNO (type) = -1; + + return (type); +} + +/* Lookup a pointer to a type TYPE. TYPEPTR, if nonzero, points + to a pointer to memory where the pointer type should be stored. + If *TYPEPTR is zero, update it to point to the pointer type we return. + We allocate new memory if needed. */ + +struct type * +make_pointer_type (type, typeptr) + struct type *type; + struct type **typeptr; +{ + register struct type *ntype; /* New type */ + struct objfile *objfile; + + ntype = TYPE_POINTER_TYPE (type); + + if (ntype) + if (typeptr == 0) + return ntype; /* Don't care about alloc, and have new type. */ + else if (*typeptr == 0) + { + *typeptr = ntype; /* Tracking alloc, and we have new type. */ + return ntype; + } + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { + ntype = alloc_type (TYPE_OBJFILE (type)); + if (typeptr) + *typeptr = ntype; + } + else /* We have storage, but need to reset it. */ + { + ntype = *typeptr; + objfile = TYPE_OBJFILE (ntype); + memset ((char *) ntype, 0, sizeof (struct type)); + TYPE_OBJFILE (ntype) = objfile; + } + + TYPE_TARGET_TYPE (ntype) = type; + TYPE_POINTER_TYPE (type) = ntype; + + /* FIXME! Assume the machine has only one representation for pointers! */ + + TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT; + TYPE_CODE (ntype) = TYPE_CODE_PTR; + + /* pointers are unsigned */ + TYPE_FLAGS (ntype) |= TYPE_FLAG_UNSIGNED; + + if (!TYPE_POINTER_TYPE (type)) /* Remember it, if don't have one. */ + TYPE_POINTER_TYPE (type) = ntype; + + return ntype; +} + +/* Given a type TYPE, return a type of pointers to that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_pointer_type (type) + struct type *type; +{ + return make_pointer_type (type, (struct type **)0); +} + +/* Lookup a C++ `reference' to a type TYPE. TYPEPTR, if nonzero, points + to a pointer to memory where the reference type should be stored. + If *TYPEPTR is zero, update it to point to the reference type we return. + We allocate new memory if needed. */ + +struct type * +make_reference_type (type, typeptr) + struct type *type; + struct type **typeptr; +{ + register struct type *ntype; /* New type */ + struct objfile *objfile; + + ntype = TYPE_REFERENCE_TYPE (type); + + if (ntype) + if (typeptr == 0) + return ntype; /* Don't care about alloc, and have new type. */ + else if (*typeptr == 0) + { + *typeptr = ntype; /* Tracking alloc, and we have new type. */ + return ntype; + } + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { + ntype = alloc_type (TYPE_OBJFILE (type)); + if (typeptr) + *typeptr = ntype; + } + else /* We have storage, but need to reset it. */ + { + ntype = *typeptr; + objfile = TYPE_OBJFILE (ntype); + memset ((char *) ntype, 0, sizeof (struct type)); + TYPE_OBJFILE (ntype) = objfile; + } + + TYPE_TARGET_TYPE (ntype) = type; + TYPE_REFERENCE_TYPE (type) = ntype; + + /* FIXME! Assume the machine has only one representation for references, + and that it matches the (only) representation for pointers! */ + + TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT; + TYPE_CODE (ntype) = TYPE_CODE_REF; + + if (!TYPE_REFERENCE_TYPE (type)) /* Remember it, if don't have one. */ + TYPE_REFERENCE_TYPE (type) = ntype; + + return ntype; +} + +/* Same as above, but caller doesn't care about memory allocation details. */ + +struct type * +lookup_reference_type (type) + struct type *type; +{ + return make_reference_type (type, (struct type **)0); +} + +/* Lookup a function type that returns type TYPE. TYPEPTR, if nonzero, points + to a pointer to memory where the function type should be stored. + If *TYPEPTR is zero, update it to point to the function type we return. + We allocate new memory if needed. */ + +struct type * +make_function_type (type, typeptr) + struct type *type; + struct type **typeptr; +{ + register struct type *ntype; /* New type */ + struct objfile *objfile; + + ntype = TYPE_FUNCTION_TYPE (type); + + if (ntype) + if (typeptr == 0) + return ntype; /* Don't care about alloc, and have new type. */ + else if (*typeptr == 0) + { + *typeptr = ntype; /* Tracking alloc, and we have new type. */ + return ntype; + } + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { + ntype = alloc_type (TYPE_OBJFILE (type)); + if (typeptr) + *typeptr = ntype; + } + else /* We have storage, but need to reset it. */ + { + ntype = *typeptr; + objfile = TYPE_OBJFILE (ntype); + memset ((char *) ntype, 0, sizeof (struct type)); + TYPE_OBJFILE (ntype) = objfile; + } + + TYPE_TARGET_TYPE (ntype) = type; + TYPE_FUNCTION_TYPE (type) = ntype; + + TYPE_LENGTH (ntype) = 1; + TYPE_CODE (ntype) = TYPE_CODE_FUNC; + + if (!TYPE_FUNCTION_TYPE (type)) /* Remember it, if don't have one. */ + TYPE_FUNCTION_TYPE (type) = ntype; + + return ntype; +} + + +/* Given a type TYPE, return a type of functions that return that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_function_type (type) + struct type *type; +{ + return make_function_type (type, (struct type **)0); +} + +/* Implement direct support for MEMBER_TYPE in GNU C++. + May need to construct such a type if this is the first use. + The TYPE is the type of the member. The DOMAIN is the type + of the aggregate that the member belongs to. */ + +struct type * +lookup_member_type (type, domain) + struct type *type; + struct type *domain; +{ + register struct type *mtype; + + mtype = alloc_type (TYPE_OBJFILE (type)); + smash_to_member_type (mtype, domain, type); + return (mtype); +} + +/* Allocate a stub method whose return type is TYPE. + This apparently happens for speed of symbol reading, since parsing + out the arguments to the method is cpu-intensive, the way we are doing + it. So, we will fill in arguments later. + This always returns a fresh type. */ + +struct type * +allocate_stub_method (type) + struct type *type; +{ + struct type *mtype; + + mtype = alloc_type (TYPE_OBJFILE (type)); + TYPE_TARGET_TYPE (mtype) = type; + /* _DOMAIN_TYPE (mtype) = unknown yet */ + /* _ARG_TYPES (mtype) = unknown yet */ + TYPE_FLAGS (mtype) = TYPE_FLAG_STUB; + TYPE_CODE (mtype) = TYPE_CODE_METHOD; + TYPE_LENGTH (mtype) = 1; + return (mtype); +} + +/* Create a range type using either a blank type supplied in RESULT_TYPE, + or creating a new type, inheriting the objfile from INDEX_TYPE. + + Indices will be of type INDEX_TYPE, and will range from LOW_BOUND to + HIGH_BOUND, inclusive. + + FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make + sure it is TYPE_CODE_UNDEF before we bash it into a range type? */ + +struct type * +create_range_type (result_type, index_type, low_bound, high_bound) + struct type *result_type; + struct type *index_type; + int low_bound; + int high_bound; +{ + if (result_type == NULL) + { + result_type = alloc_type (TYPE_OBJFILE (index_type)); + } + TYPE_CODE (result_type) = TYPE_CODE_RANGE; + TYPE_TARGET_TYPE (result_type) = index_type; + TYPE_LENGTH (result_type) = TYPE_LENGTH (index_type); + TYPE_NFIELDS (result_type) = 2; + TYPE_FIELDS (result_type) = (struct field *) + TYPE_ALLOC (result_type, 2 * sizeof (struct field)); + memset (TYPE_FIELDS (result_type), 0, 2 * sizeof (struct field)); + TYPE_FIELD_BITPOS (result_type, 0) = low_bound; + TYPE_FIELD_BITPOS (result_type, 1) = high_bound; + TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int; /* FIXME */ + TYPE_FIELD_TYPE (result_type, 1) = builtin_type_int; /* FIXME */ + + return (result_type); +} + + +/* Create an array type using either a blank type supplied in RESULT_TYPE, + or creating a new type, inheriting the objfile from RANGE_TYPE. + + Elements will be of type ELEMENT_TYPE, the indices will be of type + RANGE_TYPE. + + FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make + sure it is TYPE_CODE_UNDEF before we bash it into an array type? */ + +struct type * +create_array_type (result_type, element_type, range_type) + struct type *result_type; + struct type *element_type; + struct type *range_type; +{ + int low_bound; + int high_bound; + + if (TYPE_CODE (range_type) != TYPE_CODE_RANGE) + { + /* FIXME: We only handle range types at the moment. Complain and + create a dummy range type to use. */ + warning ("internal error: array index type must be a range type"); + range_type = lookup_fundamental_type (TYPE_OBJFILE (range_type), + FT_INTEGER); + range_type = create_range_type ((struct type *) NULL, range_type, 0, 0); + } + if (result_type == NULL) + { + result_type = alloc_type (TYPE_OBJFILE (range_type)); + } + TYPE_CODE (result_type) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (result_type) = element_type; + low_bound = TYPE_FIELD_BITPOS (range_type, 0); + high_bound = TYPE_FIELD_BITPOS (range_type, 1); + TYPE_LENGTH (result_type) = + TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); + TYPE_NFIELDS (result_type) = 1; + TYPE_FIELDS (result_type) = + (struct field *) TYPE_ALLOC (result_type, sizeof (struct field)); + memset (TYPE_FIELDS (result_type), 0, sizeof (struct field)); + TYPE_FIELD_TYPE (result_type, 0) = range_type; + TYPE_VPTR_FIELDNO (result_type) = -1; + + return (result_type); +} + +/* Create a string type using either a blank type supplied in RESULT_TYPE, + or creating a new type. String types are similar enough to array of + char types that we can use create_array_type to build the basic type + and then bash it into a string type. + + For fixed length strings, the range type contains 0 as the lower + bound and the length of the string minus one as the upper bound. + + FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make + sure it is TYPE_CODE_UNDEF before we bash it into a string type? */ + +struct type * +create_string_type (result_type, range_type) + struct type *result_type; + struct type *range_type; +{ + result_type = create_array_type (result_type, builtin_type_char, range_type); + TYPE_CODE (result_type) = TYPE_CODE_STRING; + return (result_type); +} + +/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE. + A MEMBER is a wierd thing -- it amounts to a typed offset into + a struct, e.g. "an int at offset 8". A MEMBER TYPE doesn't + include the offset (that's the value of the MEMBER itself), but does + include the structure type into which it points (for some reason). + + When "smashing" the type, we preserve the objfile that the + old type pointed to, since we aren't changing where the type is actually + allocated. */ + +void +smash_to_member_type (type, domain, to_type) + struct type *type; + struct type *domain; + struct type *to_type; +{ + struct objfile *objfile; + + objfile = TYPE_OBJFILE (type); + + memset ((char *) type, 0, sizeof (struct type)); + TYPE_OBJFILE (type) = objfile; + TYPE_TARGET_TYPE (type) = to_type; + TYPE_DOMAIN_TYPE (type) = domain; + TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */ + TYPE_CODE (type) = TYPE_CODE_MEMBER; +} + +/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE. + METHOD just means `function that gets an extra "this" argument'. + + When "smashing" the type, we preserve the objfile that the + old type pointed to, since we aren't changing where the type is actually + allocated. */ + +void +smash_to_method_type (type, domain, to_type, args) + struct type *type; + struct type *domain; + struct type *to_type; + struct type **args; +{ + struct objfile *objfile; + + objfile = TYPE_OBJFILE (type); + + memset ((char *) type, 0, sizeof (struct type)); + TYPE_OBJFILE (type) = objfile; + TYPE_TARGET_TYPE (type) = to_type; + TYPE_DOMAIN_TYPE (type) = domain; + TYPE_ARG_TYPES (type) = args; + TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */ + TYPE_CODE (type) = TYPE_CODE_METHOD; +} + +/* Return a typename for a struct/union/enum type without "struct ", + "union ", or "enum ". If the type has a NULL name, return NULL. */ + +char * +type_name_no_tag (type) + register const struct type *type; +{ + if (TYPE_TAG_NAME (type) != NULL) + return TYPE_TAG_NAME (type); + + /* Is there code which expects this to return the name if there is no + tag name? My guess is that this is mainly used for C++ in cases where + the two will always be the same. */ + return TYPE_NAME (type); +} + +/* Lookup a primitive type named NAME. + Return zero if NAME is not a primitive type.*/ + +struct type * +lookup_primitive_typename (name) + char *name; +{ + struct type ** const *p; + + for (p = current_language -> la_builtin_type_vector; *p != NULL; p++) + { + if (STREQ ((**p) -> name, name)) + { + return (**p); + } + } + return (NULL); +} + +/* Lookup a typedef or primitive type named NAME, + visible in lexical block BLOCK. + If NOERR is nonzero, return zero if NAME is not suitably defined. */ + +struct type * +lookup_typename (name, block, noerr) + char *name; + struct block *block; + int noerr; +{ + register struct symbol *sym; + register struct type *tmp; + + sym = lookup_symbol (name, block, VAR_NAMESPACE, 0, (struct symtab **) NULL); + if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF) + { + tmp = lookup_primitive_typename (name); + if (tmp) + { + return (tmp); + } + else if (!tmp && noerr) + { + return (NULL); + } + else + { + error ("No type named %s.", name); + } + } + return (SYMBOL_TYPE (sym)); +} + +struct type * +lookup_unsigned_typename (name) + char *name; +{ + char *uns = alloca (strlen (name) + 10); + + strcpy (uns, "unsigned "); + strcpy (uns + 9, name); + return (lookup_typename (uns, (struct block *) NULL, 0)); +} + +struct type * +lookup_signed_typename (name) + char *name; +{ + struct type *t; + char *uns = alloca (strlen (name) + 8); + + strcpy (uns, "signed "); + strcpy (uns + 7, name); + t = lookup_typename (uns, (struct block *) NULL, 1); + /* If we don't find "signed FOO" just try again with plain "FOO". */ + if (t != NULL) + return t; + return lookup_typename (name, (struct block *) NULL, 0); +} + +/* Lookup a structure type named "struct NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_struct (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym; + + sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + + if (sym == NULL) + { + error ("No struct type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) + { + error ("This context has class, union or enum %s, not a struct.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Lookup a union type named "union NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_union (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym; + + sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + + if (sym == NULL) + { + error ("No union type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION) + { + error ("This context has class, struct or enum %s, not a union.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Lookup an enum type named "enum NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_enum (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym; + + sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + if (sym == NULL) + { + error ("No enum type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM) + { + error ("This context has class, struct or union %s, not an enum.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Lookup a template type named "template NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_template_type (name, type, block) + char *name; + struct type *type; + struct block *block; +{ + struct symbol *sym; + char *nam = (char*) alloca(strlen(name) + strlen(type->name) + 4); + strcpy (nam, name); + strcat (nam, "<"); + strcat (nam, type->name); + strcat (nam, " >"); /* FIXME, extra space still introduced in gcc? */ + + sym = lookup_symbol (nam, block, VAR_NAMESPACE, 0, (struct symtab **)NULL); + + if (sym == NULL) + { + error ("No template type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) + { + error ("This context has class, union or enum %s, not a struct.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Given a type TYPE, lookup the type of the component of type named NAME. + + TYPE can be either a struct or union, or a pointer or reference to a struct or + union. If it is a pointer or reference, its target type is automatically used. + Thus '.' and '->' are interchangable, as specified for the definitions of the + expression element types STRUCTOP_STRUCT and STRUCTOP_PTR. + + If NOERR is nonzero, return zero if NAME is not suitably defined. + If NAME is the name of a baseclass type, return that type. */ + +struct type * +lookup_struct_elt_type (type, name, noerr) + struct type *type; + char *name; + int noerr; +{ + int i; + + if (TYPE_CODE (type) == TYPE_CODE_PTR || + TYPE_CODE (type) == TYPE_CODE_REF) + type = TYPE_TARGET_TYPE (type); + + if (TYPE_CODE (type) != TYPE_CODE_STRUCT && + TYPE_CODE (type) != TYPE_CODE_UNION) + { + target_terminal_ours (); + fflush (stdout); + fprintf (stderr, "Type "); + type_print (type, "", stderr, -1); + error (" is not a structure or union type."); + } + + check_stub_type (type); + +#if 0 + /* FIXME: This change put in by Michael seems incorrect for the case where + the structure tag name is the same as the member name. I.E. when doing + "ptype bell->bar" for "struct foo { int bar; int foo; } bell;" + Disabled by fnf. */ + { + char *typename; + + typename = type_name_no_tag (type); + if (typename != NULL && STREQ (typename, name)) + return type; + } +#endif + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name && STREQ (t_field_name, name)) + { + return TYPE_FIELD_TYPE (type, i); + } + } + + /* OK, it's not in this class. Recursively check the baseclasses. */ + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + struct type *t; + + t = lookup_struct_elt_type (TYPE_BASECLASS (type, i), name, noerr); + if (t != NULL) + { + return t; + } + } + + if (noerr) + { + return NULL; + } + + target_terminal_ours (); + fflush (stdout); + fprintf (stderr, "Type "); + type_print (type, "", stderr, -1); + fprintf (stderr, " has no component named "); + fputs_filtered (name, stderr); + error ("."); + return (struct type *)-1; /* For lint */ +} + +/* If possible, make the vptr_fieldno and vptr_basetype fields of TYPE + valid. Callers should be aware that in some cases (for example, + the type or one of its baseclasses is a stub type and we are + debugging a .o file), this function will not be able to find the virtual + function table pointer, and vptr_fieldno will remain -1 and vptr_basetype + will remain NULL. */ + +void +fill_in_vptr_fieldno (type) + struct type *type; +{ + check_stub_type (type); + + if (TYPE_VPTR_FIELDNO (type) < 0) + { + int i; + + /* We must start at zero in case the first (and only) baseclass is + virtual (and hence we cannot share the table pointer). */ + for (i = 0; i < TYPE_N_BASECLASSES (type); i++) + { + fill_in_vptr_fieldno (TYPE_BASECLASS (type, i)); + if (TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)) >= 0) + { + TYPE_VPTR_FIELDNO (type) + = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)); + TYPE_VPTR_BASETYPE (type) + = TYPE_VPTR_BASETYPE (TYPE_BASECLASS (type, i)); + break; + } + } + } +} + +/* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989. + + If this is a stubbed struct (i.e. declared as struct foo *), see if + we can find a full definition in some other file. If so, copy this + definition, so we can use it in future. If not, set a flag so we + don't waste too much time in future. (FIXME, this doesn't seem + to be happening...) + + This used to be coded as a macro, but I don't think it is called + often enough to merit such treatment. +*/ + +struct complaint stub_noname_complaint = + {"stub type has NULL name", 0, 0}; + +void +check_stub_type (type) + struct type *type; +{ + if (TYPE_FLAGS(type) & TYPE_FLAG_STUB) + { + char* name = type_name_no_tag (type); + /* FIXME: shouldn't we separately check the TYPE_NAME and the + TYPE_TAG_NAME, and look in STRUCT_NAMESPACE and/or VAR_NAMESPACE + as appropriate? (this code was written before TYPE_NAME and + TYPE_TAG_NAME were separate). */ + struct symbol *sym; + if (name == NULL) + { + complain (&stub_noname_complaint); + return; + } + sym = lookup_symbol (name, 0, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + if (sym) + { + memcpy ((char *)type, (char *)SYMBOL_TYPE(sym), sizeof (struct type)); + } + } +} + +/* Ugly hack to convert method stubs into method types. + + He ain't kiddin'. This demangles the name of the method into a string + including argument types, parses out each argument type, generates + a string casting a zero to that type, evaluates the string, and stuffs + the resulting type into an argtype vector!!! Then it knows the type + of the whole function (including argument types for overloading), + which info used to be in the stab's but was removed to hack back + the space required for them. */ + +void +check_stub_method (type, i, j) + struct type *type; + int i; + int j; +{ + struct fn_field *f; + char *mangled_name = gdb_mangle_name (type, i, j); + char *demangled_name = cplus_demangle (mangled_name, + DMGL_PARAMS | DMGL_ANSI); + char *argtypetext, *p; + int depth = 0, argcount = 1; + struct type **argtypes; + struct type *mtype; + + if (demangled_name == NULL) + { + error ("Internal: Cannot demangle mangled name `%s'.", mangled_name); + } + + /* Now, read in the parameters that define this type. */ + argtypetext = strchr (demangled_name, '(') + 1; + p = argtypetext; + while (*p) + { + if (*p == '(') + { + depth += 1; + } + else if (*p == ')') + { + depth -= 1; + } + else if (*p == ',' && depth == 0) + { + argcount += 1; + } + + p += 1; + } + + /* We need two more slots: one for the THIS pointer, and one for the + NULL [...] or void [end of arglist]. */ + + argtypes = (struct type **) + TYPE_ALLOC (type, (argcount + 2) * sizeof (struct type *)); + p = argtypetext; + argtypes[0] = lookup_pointer_type (type); + argcount = 1; + + if (*p != ')') /* () means no args, skip while */ + { + depth = 0; + while (*p) + { + if (depth <= 0 && (*p == ',' || *p == ')')) + { + argtypes[argcount] = + parse_and_eval_type (argtypetext, p - argtypetext); + argcount += 1; + argtypetext = p + 1; + } + + if (*p == '(') + { + depth += 1; + } + else if (*p == ')') + { + depth -= 1; + } + + p += 1; + } + } + + if (p[-2] != '.') /* Not '...' */ + { + argtypes[argcount] = builtin_type_void; /* List terminator */ + } + else + { + argtypes[argcount] = NULL; /* Ellist terminator */ + } + + free (demangled_name); + + f = TYPE_FN_FIELDLIST1 (type, i); + TYPE_FN_FIELD_PHYSNAME (f, j) = mangled_name; + + /* Now update the old "stub" type into a real type. */ + mtype = TYPE_FN_FIELD_TYPE (f, j); + TYPE_DOMAIN_TYPE (mtype) = type; + TYPE_ARG_TYPES (mtype) = argtypes; + TYPE_FLAGS (mtype) &= ~TYPE_FLAG_STUB; + TYPE_FN_FIELD_STUB (f, j) = 0; +} + +const struct cplus_struct_type cplus_struct_default; + +void +allocate_cplus_struct_type (type) + struct type *type; +{ + if (!HAVE_CPLUS_STRUCT (type)) + { + TYPE_CPLUS_SPECIFIC (type) = (struct cplus_struct_type *) + TYPE_ALLOC (type, sizeof (struct cplus_struct_type)); + *(TYPE_CPLUS_SPECIFIC(type)) = cplus_struct_default; + } +} + +/* Helper function to initialize the standard scalar types. + + If NAME is non-NULL and OBJFILE is non-NULL, then we make a copy + of the string pointed to by name in the type_obstack for that objfile, + and initialize the type name to that copy. There are places (mipsread.c + in particular, where init_type is called with a NULL value for NAME). */ + +struct type * +init_type (code, length, flags, name, objfile) + enum type_code code; + int length; + int flags; + char *name; + struct objfile *objfile; +{ + register struct type *type; + + type = alloc_type (objfile); + TYPE_CODE (type) = code; + TYPE_LENGTH (type) = length; + TYPE_FLAGS (type) |= flags; + if ((name != NULL) && (objfile != NULL)) + { + TYPE_NAME (type) = + obsavestring (name, strlen (name), &objfile -> type_obstack); + } + else + { + TYPE_NAME (type) = name; + } + + /* C++ fancies. */ + + if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) + { + INIT_CPLUS_SPECIFIC (type); + } + return (type); +} + +/* Look up a fundamental type for the specified objfile. + May need to construct such a type if this is the first use. + + Some object file formats (ELF, COFF, etc) do not define fundamental + types such as "int" or "double". Others (stabs for example), do + define fundamental types. + + For the formats which don't provide fundamental types, gdb can create + such types, using defaults reasonable for the current language and + the current target machine. + + NOTE: This routine is obsolescent. Each debugging format reader + should manage it's own fundamental types, either creating them from + suitable defaults or reading them from the debugging information, + whichever is appropriate. The DWARF reader has already been + fixed to do this. Once the other readers are fixed, this routine + will go away. Also note that fundamental types should be managed + on a compilation unit basis in a multi-language environment, not + on a linkage unit basis as is done here. */ + + +struct type * +lookup_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type **typep; + register int nbytes; + + if (typeid < 0 || typeid >= FT_NUM_MEMBERS) + { + error ("internal error - invalid fundamental type id %d", typeid); + } + + /* If this is the first time we need a fundamental type for this objfile + then we need to initialize the vector of type pointers. */ + + if (objfile -> fundamental_types == NULL) + { + nbytes = FT_NUM_MEMBERS * sizeof (struct type *); + objfile -> fundamental_types = (struct type **) + obstack_alloc (&objfile -> type_obstack, nbytes); + memset ((char *) objfile -> fundamental_types, 0, nbytes); + } + + /* Look for this particular type in the fundamental type vector. If one is + not found, create and install one appropriate for the current language. */ + + typep = objfile -> fundamental_types + typeid; + if (*typep == NULL) + { + *typep = create_fundamental_type (objfile, typeid); + } + + return (*typep); +} + +#if MAINTENANCE_CMDS + +static void +print_bit_vector (bits, nbits) + B_TYPE *bits; + int nbits; +{ + int bitno; + + for (bitno = 0; bitno < nbits; bitno++) + { + if ((bitno % 8) == 0) + { + puts_filtered (" "); + } + if (B_TST (bits, bitno)) + { + printf_filtered ("1"); + } + else + { + printf_filtered ("0"); + } + } +} + +/* The args list is a strange beast. It is either terminated by a NULL + pointer for varargs functions, or by a pointer to a TYPE_CODE_VOID + type for normal fixed argcount functions. (FIXME someday) + Also note the first arg should be the "this" pointer, we may not want to + include it since we may get into a infinitely recursive situation. */ + +static void +print_arg_types (args, spaces) + struct type **args; + int spaces; +{ + if (args != NULL) + { + while (*args != NULL) + { + recursive_dump_type (*args, spaces + 2); + if ((*args++) -> code == TYPE_CODE_VOID) + { + break; + } + } + } +} + +static void +dump_fn_fieldlists (type, spaces) + struct type *type; + int spaces; +{ + int method_idx; + int overload_idx; + struct fn_field *f; + + printfi_filtered (spaces, "fn_fieldlists 0x%lx\n", + (unsigned long) TYPE_FN_FIELDLISTS (type)); + for (method_idx = 0; method_idx < TYPE_NFN_FIELDS (type); method_idx++) + { + f = TYPE_FN_FIELDLIST1 (type, method_idx); + printfi_filtered (spaces + 2, "[%d] name '%s' (0x%lx) length %d\n", + method_idx, + TYPE_FN_FIELDLIST_NAME (type, method_idx), + (unsigned long) TYPE_FN_FIELDLIST_NAME (type, method_idx), + TYPE_FN_FIELDLIST_LENGTH (type, method_idx)); + for (overload_idx = 0; + overload_idx < TYPE_FN_FIELDLIST_LENGTH (type, method_idx); + overload_idx++) + { + printfi_filtered (spaces + 4, "[%d] physname '%s' (0x%lx)\n", + overload_idx, + TYPE_FN_FIELD_PHYSNAME (f, overload_idx), + (unsigned long) TYPE_FN_FIELD_PHYSNAME (f, overload_idx)); + printfi_filtered (spaces + 8, "type 0x%lx\n", + (unsigned long) TYPE_FN_FIELD_TYPE (f, overload_idx)); + recursive_dump_type (TYPE_FN_FIELD_TYPE (f, overload_idx), + spaces + 8 + 2); + printfi_filtered (spaces + 8, "args 0x%lx\n", + (unsigned long) TYPE_FN_FIELD_ARGS (f, overload_idx)); + print_arg_types (TYPE_FN_FIELD_ARGS (f, overload_idx), spaces); + printfi_filtered (spaces + 8, "fcontext 0x%lx\n", + (unsigned long) TYPE_FN_FIELD_FCONTEXT (f, overload_idx)); + printfi_filtered (spaces + 8, "is_const %d\n", + TYPE_FN_FIELD_CONST (f, overload_idx)); + printfi_filtered (spaces + 8, "is_volatile %d\n", + TYPE_FN_FIELD_VOLATILE (f, overload_idx)); + printfi_filtered (spaces + 8, "is_private %d\n", + TYPE_FN_FIELD_PRIVATE (f, overload_idx)); + printfi_filtered (spaces + 8, "is_protected %d\n", + TYPE_FN_FIELD_PROTECTED (f, overload_idx)); + printfi_filtered (spaces + 8, "is_stub %d\n", + TYPE_FN_FIELD_STUB (f, overload_idx)); + printfi_filtered (spaces + 8, "voffset %u\n", + TYPE_FN_FIELD_VOFFSET (f, overload_idx)); + } + } +} + +static void +print_cplus_stuff (type, spaces) + struct type *type; + int spaces; +{ + printfi_filtered (spaces, "n_baseclasses %d\n", + TYPE_N_BASECLASSES (type)); + printfi_filtered (spaces, "nfn_fields %d\n", + TYPE_NFN_FIELDS (type)); + printfi_filtered (spaces, "nfn_fields_total %d\n", + TYPE_NFN_FIELDS_TOTAL (type)); + if (TYPE_N_BASECLASSES (type) > 0) + { + printfi_filtered (spaces, "virtual_field_bits (%d bits at *0x%lx)", + TYPE_N_BASECLASSES (type), + (unsigned long) TYPE_FIELD_VIRTUAL_BITS (type)); + print_bit_vector (TYPE_FIELD_VIRTUAL_BITS (type), + TYPE_N_BASECLASSES (type)); + puts_filtered ("\n"); + } + if (TYPE_NFIELDS (type) > 0) + { + if (TYPE_FIELD_PRIVATE_BITS (type) != NULL) + { + printfi_filtered (spaces, "private_field_bits (%d bits at *0x%lx)", + TYPE_NFIELDS (type), + (unsigned long) TYPE_FIELD_PRIVATE_BITS (type)); + print_bit_vector (TYPE_FIELD_PRIVATE_BITS (type), + TYPE_NFIELDS (type)); + puts_filtered ("\n"); + } + if (TYPE_FIELD_PROTECTED_BITS (type) != NULL) + { + printfi_filtered (spaces, "protected_field_bits (%d bits at *0x%lx)", + TYPE_NFIELDS (type), + (unsigned long) TYPE_FIELD_PROTECTED_BITS (type)); + print_bit_vector (TYPE_FIELD_PROTECTED_BITS (type), + TYPE_NFIELDS (type)); + puts_filtered ("\n"); + } + } + if (TYPE_NFN_FIELDS (type) > 0) + { + dump_fn_fieldlists (type, spaces); + } +} + +void +recursive_dump_type (type, spaces) + struct type *type; + int spaces; +{ + int idx; + + printfi_filtered (spaces, "type node 0x%lx\n", (unsigned long)type); + printfi_filtered (spaces, "name '%s' (0x%lx)\n", + TYPE_NAME (type) ? TYPE_NAME (type) : "", + (unsigned long)TYPE_NAME (type)); + if (TYPE_TAG_NAME (type) != NULL) + printfi_filtered (spaces, "tagname '%s' (0x%lx)\n", + TYPE_TAG_NAME (type), + (unsigned long)TYPE_TAG_NAME (type)); + printfi_filtered (spaces, "code 0x%x ", TYPE_CODE (type)); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_UNDEF: + printf_filtered ("(TYPE_CODE_UNDEF)"); + break; + case TYPE_CODE_PTR: + printf_filtered ("(TYPE_CODE_PTR)"); + break; + case TYPE_CODE_ARRAY: + printf_filtered ("(TYPE_CODE_ARRAY)"); + break; + case TYPE_CODE_STRUCT: + printf_filtered ("(TYPE_CODE_STRUCT)"); + break; + case TYPE_CODE_UNION: + printf_filtered ("(TYPE_CODE_UNION)"); + break; + case TYPE_CODE_ENUM: + printf_filtered ("(TYPE_CODE_ENUM)"); + break; + case TYPE_CODE_FUNC: + printf_filtered ("(TYPE_CODE_FUNC)"); + break; + case TYPE_CODE_INT: + printf_filtered ("(TYPE_CODE_INT)"); + break; + case TYPE_CODE_FLT: + printf_filtered ("(TYPE_CODE_FLT)"); + break; + case TYPE_CODE_VOID: + printf_filtered ("(TYPE_CODE_VOID)"); + break; + case TYPE_CODE_SET: + printf_filtered ("(TYPE_CODE_SET)"); + break; + case TYPE_CODE_RANGE: + printf_filtered ("(TYPE_CODE_RANGE)"); + break; + case TYPE_CODE_STRING: + printf_filtered ("(TYPE_CODE_STRING)"); + break; + case TYPE_CODE_ERROR: + printf_filtered ("(TYPE_CODE_ERROR)"); + break; + case TYPE_CODE_MEMBER: + printf_filtered ("(TYPE_CODE_MEMBER)"); + break; + case TYPE_CODE_METHOD: + printf_filtered ("(TYPE_CODE_METHOD)"); + break; + case TYPE_CODE_REF: + printf_filtered ("(TYPE_CODE_REF)"); + break; + case TYPE_CODE_CHAR: + printf_filtered ("(TYPE_CODE_CHAR)"); + break; + case TYPE_CODE_BOOL: + printf_filtered ("(TYPE_CODE_BOOL)"); + break; + default: + printf_filtered ("(UNKNOWN TYPE CODE)"); + break; + } + puts_filtered ("\n"); + printfi_filtered (spaces, "length %d\n", TYPE_LENGTH (type)); + printfi_filtered (spaces, "objfile 0x%lx\n", + (unsigned long) TYPE_OBJFILE (type)); + printfi_filtered (spaces, "target_type 0x%lx\n", + (unsigned long) TYPE_TARGET_TYPE (type)); + if (TYPE_TARGET_TYPE (type) != NULL) + { + recursive_dump_type (TYPE_TARGET_TYPE (type), spaces + 2); + } + printfi_filtered (spaces, "pointer_type 0x%lx\n", + (unsigned long) TYPE_POINTER_TYPE (type)); + printfi_filtered (spaces, "reference_type 0x%lx\n", + (unsigned long) TYPE_REFERENCE_TYPE (type)); + printfi_filtered (spaces, "function_type 0x%lx\n", + (unsigned long) TYPE_FUNCTION_TYPE (type)); + printfi_filtered (spaces, "flags 0x%x", TYPE_FLAGS (type)); + if (TYPE_FLAGS (type) & TYPE_FLAG_UNSIGNED) + { + puts_filtered (" TYPE_FLAG_UNSIGNED"); + } + if (TYPE_FLAGS (type) & TYPE_FLAG_SIGNED) + { + puts_filtered (" TYPE_FLAG_SIGNED"); + } + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + puts_filtered (" TYPE_FLAG_STUB"); + } + puts_filtered ("\n"); + printfi_filtered (spaces, "nfields %d 0x%lx\n", TYPE_NFIELDS (type), + (unsigned long) TYPE_FIELDS (type)); + for (idx = 0; idx < TYPE_NFIELDS (type); idx++) + { + printfi_filtered (spaces + 2, + "[%d] bitpos %d bitsize %d type 0x%lx name '%s' (0x%lx)\n", + idx, TYPE_FIELD_BITPOS (type, idx), + TYPE_FIELD_BITSIZE (type, idx), + (unsigned long) TYPE_FIELD_TYPE (type, idx), + TYPE_FIELD_NAME (type, idx) != NULL + ? TYPE_FIELD_NAME (type, idx) + : "", + (unsigned long) TYPE_FIELD_NAME (type, idx)); + if (TYPE_FIELD_TYPE (type, idx) != NULL) + { + recursive_dump_type (TYPE_FIELD_TYPE (type, idx), spaces + 4); + } + } + printfi_filtered (spaces, "vptr_basetype 0x%lx\n", + (unsigned long) TYPE_VPTR_BASETYPE (type)); + if (TYPE_VPTR_BASETYPE (type) != NULL) + { + recursive_dump_type (TYPE_VPTR_BASETYPE (type), spaces + 2); + } + printfi_filtered (spaces, "vptr_fieldno %d\n", TYPE_VPTR_FIELDNO (type)); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_METHOD: + case TYPE_CODE_FUNC: + printfi_filtered (spaces, "arg_types 0x%lx\n", + (unsigned long) TYPE_ARG_TYPES (type)); + print_arg_types (TYPE_ARG_TYPES (type), spaces); + break; + + case TYPE_CODE_STRUCT: + printfi_filtered (spaces, "cplus_stuff 0x%lx\n", + (unsigned long) TYPE_CPLUS_SPECIFIC (type)); + print_cplus_stuff (type, spaces); + break; + + default: + /* We have to pick one of the union types to be able print and test + the value. Pick cplus_struct_type, even though we know it isn't + any particular one. */ + printfi_filtered (spaces, "type_specific 0x%lx", + (unsigned long) TYPE_CPLUS_SPECIFIC (type)); + if (TYPE_CPLUS_SPECIFIC (type) != NULL) + { + printf_filtered (" (unknown data form)"); + } + printf_filtered ("\n"); + break; + + } +} + +#endif /* MAINTENANCE_CMDS */ + +void +_initialize_gdbtypes () +{ + builtin_type_void = + init_type (TYPE_CODE_VOID, 1, + 0, + "void", (struct objfile *) NULL); + builtin_type_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "char", (struct objfile *) NULL); + builtin_type_signed_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, + "signed char", (struct objfile *) NULL); + builtin_type_unsigned_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned char", (struct objfile *) NULL); + builtin_type_short = + init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, + "short", (struct objfile *) NULL); + builtin_type_unsigned_short = + init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned short", (struct objfile *) NULL); + builtin_type_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "int", (struct objfile *) NULL); + builtin_type_unsigned_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned int", (struct objfile *) NULL); + builtin_type_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, + "long", (struct objfile *) NULL); + builtin_type_unsigned_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned long", (struct objfile *) NULL); + builtin_type_long_long = + init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, + "long long", (struct objfile *) NULL); + builtin_type_unsigned_long_long = + init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned long long", (struct objfile *) NULL); + builtin_type_float = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "float", (struct objfile *) NULL); + builtin_type_double = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "double", (struct objfile *) NULL); + builtin_type_long_double = + init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "long double", (struct objfile *) NULL); + builtin_type_complex = + init_type (TYPE_CODE_FLT, TARGET_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, + "complex", (struct objfile *) NULL); + builtin_type_double_complex = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, + "double complex", (struct objfile *) NULL); + builtin_type_string = + init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "string", (struct objfile *) NULL); +} diff --git a/gnu/usr.bin/gdb/gdb/gdbtypes.h b/gnu/usr.bin/gdb/gdb/gdbtypes.h new file mode 100644 index 00000000000..89cad6cbbe5 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdbtypes.h @@ -0,0 +1,704 @@ +/* Internal type definitions for GDB. + Copyright (C) 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +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. */ + +#if !defined (GDBTYPES_H) +#define GDBTYPES_H 1 + +/* When gdb creates fundamental types, it uses one of the following + type identifiers. The identifiers are used to index a vector of + pointers to any types that are created. */ + +#define FT_VOID 0 +#define FT_BOOLEAN 1 +#define FT_CHAR 2 +#define FT_SIGNED_CHAR 3 +#define FT_UNSIGNED_CHAR 4 +#define FT_SHORT 5 +#define FT_SIGNED_SHORT 6 +#define FT_UNSIGNED_SHORT 7 +#define FT_INTEGER 8 +#define FT_SIGNED_INTEGER 9 +#define FT_UNSIGNED_INTEGER 10 +#define FT_LONG 11 +#define FT_SIGNED_LONG 12 +#define FT_UNSIGNED_LONG 13 +#define FT_LONG_LONG 14 +#define FT_SIGNED_LONG_LONG 15 +#define FT_UNSIGNED_LONG_LONG 16 +#define FT_FLOAT 17 +#define FT_DBL_PREC_FLOAT 18 +#define FT_EXT_PREC_FLOAT 19 +#define FT_COMPLEX 20 +#define FT_DBL_PREC_COMPLEX 21 +#define FT_EXT_PREC_COMPLEX 22 +#define FT_STRING 23 +#define FT_FIXED_DECIMAL 24 +#define FT_FLOAT_DECIMAL 25 +#define FT_BYTE 26 +#define FT_UNSIGNED_BYTE 27 + +#define FT_NUM_MEMBERS 28 /* Highest FT_* above, plus one. */ + +/* Some macros for char-based bitfields. */ + +#define B_SET(a,x) ((a)[(x)>>3] |= (1 << ((x)&7))) +#define B_CLR(a,x) ((a)[(x)>>3] &= ~(1 << ((x)&7))) +#define B_TST(a,x) ((a)[(x)>>3] & (1 << ((x)&7))) +#define B_TYPE unsigned char +#define B_BYTES(x) ( 1 + ((x)>>3) ) +#define B_CLRALL(a,x) memset ((a), 0, B_BYTES(x)) + +/* Different kinds of data types are distinguished by the `code' field. */ + +enum type_code +{ + TYPE_CODE_UNDEF, /* Not used; catches errors */ + TYPE_CODE_PTR, /* Pointer type */ + TYPE_CODE_ARRAY, /* Array type with lower & upper bounds. */ + TYPE_CODE_STRUCT, /* C struct or Pascal record */ + TYPE_CODE_UNION, /* C union or Pascal variant part */ + TYPE_CODE_ENUM, /* Enumeration type */ + TYPE_CODE_FUNC, /* Function type */ + TYPE_CODE_INT, /* Integer type */ + + /* Floating type. This is *NOT* a complex type. Complex types, when + we have them, will have their own type code (or TYPE_CODE_ERROR if + we can parse a complex type but not manipulate it). There are parts + of GDB which bogusly assume that TYPE_CODE_FLT can mean complex. */ + TYPE_CODE_FLT, + + /* Void type (values zero length; the length field is ignored). */ + TYPE_CODE_VOID, + + TYPE_CODE_SET, /* Pascal sets */ + TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */ + TYPE_CODE_STRING, /* String types, distinct from array of char */ + TYPE_CODE_BITSTRING, /* String of bits, distinct from bool array */ + + /* Unknown type. The length field is valid if we were able to + deduce that much about the type, or 0 if we don't even know that. */ + TYPE_CODE_ERROR, + + /* C++ */ + TYPE_CODE_MEMBER, /* Member type */ + TYPE_CODE_METHOD, /* Method type */ + TYPE_CODE_REF, /* C++ Reference types */ + + /* Modula-2 */ + TYPE_CODE_CHAR, /* *real* character type */ + TYPE_CODE_BOOL /* BOOLEAN type */ +}; + +/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an + alias for TYPE_CODE_STRUCT. Eventually these should probably be + officially distinct types within gdb. */ + +#define TYPE_CODE_CLASS TYPE_CODE_STRUCT + +/* Some bits for the type's flags word. */ + +/* Explicitly unsigned integer type */ + +#define TYPE_FLAG_UNSIGNED (1 << 0) + +/* Explicitly signed integer type */ + +#define TYPE_FLAG_SIGNED (1 << 1) + +/* This appears in a type's flags word if it is a stub type (e.g., if + someone referenced a type that wasn't defined in a source file + via (struct sir_not_appearing_in_this_film *)). */ + +#define TYPE_FLAG_STUB (1 << 2) + + +struct type +{ + + /* Code for kind of type */ + + enum type_code code; + + /* Name of this type, or NULL if none. + + This is used for printing only, except by poorly designed C++ code. + For looking up a name, look for a symbol in the VAR_NAMESPACE. */ + + char *name; + + /* Tag name for this type, or NULL if none. This means that the + name of the type consists of a keyword followed by the tag name. + Which keyword is determined by the type code ("struct" for + TYPE_CODE_STRUCT, etc.). As far as I know C/C++ are the only languages + with this feature. + + This is used for printing only, except by poorly designed C++ code. + For looking up a name, look for a symbol in the STRUCT_NAMESPACE. + One more legitimate use is that if TYPE_FLAG_STUB is set, this is + the name to use to look for definitions in other files. */ + + char *tag_name; + + /* Length, in units of TARGET_CHAR_BIT bits, + of storage for a value of this type */ + + unsigned length; + + /* Every type is now associated with a particular objfile, and the + type is allocated on the type_obstack for that objfile. One problem + however, is that there are times when gdb allocates new types while + it is not in the process of reading symbols from a particular objfile. + Fortunately, these happen when the type being created is a derived + type of an existing type, such as in lookup_pointer_type(). So + we can just allocate the new type using the same objfile as the + existing type, but to do this we need a backpointer to the objfile + from the existing type. Yes this is somewhat ugly, but without + major overhaul of the internal type system, it can't be avoided + for now. */ + + struct objfile *objfile; + + /* For a pointer type, describes the type of object pointed to. + For an array type, describes the type of the elements. + For a function or method type, describes the type of the return value. + For a range type, describes the type of the full range. + Unused otherwise. */ + + struct type *target_type; + + /* Type that is a pointer to this type. + NULL if no such pointer-to type is known yet. + The debugger may add the address of such a type + if it has to construct one later. */ + + struct type *pointer_type; + + /* C++: also need a reference type. */ + + struct type *reference_type; + + /* Type that is a function returning this type. + NULL if no such function type is known here. + The debugger may add the address of such a type + if it has to construct one later. */ + + struct type *function_type; + + /* Flags about this type. */ + + short flags; + + /* Number of fields described for this type */ + + short nfields; + + /* For structure and union types, a description of each field. + For set and pascal array types, there is one "field", + whose type is the domain type of the set or array. + For range types, there are two "fields", + the minimum and maximum values (both inclusive). + For enum types, each possible value is described by one "field". + For C++ classes, there is one field for each base class (if it is + a derived class) plus one field for each class data member. Member + functions are recorded elsewhere. + + Using a pointer to a separate array of fields + allows all types to have the same size, which is useful + because we can allocate the space for a type before + we know what to put in it. */ + + struct field + { + + /* Position of this field, counting in bits from start of + containing structure. For a function type, this is the + position in the argument list of this argument. + For a range bound or enum value, this is the value itself. + (FIXME: What about ranges larger than host int size?) + For BITS_BIG_ENDIAN=1 targets, it is the bit offset to the MSB. + For BITS_BIG_ENDIAN=0 targets, it is the bit offset to the LSB. */ + + int bitpos; + + /* Size of this field, in bits, or zero if not packed. + For an unpacked field, the field's type's length + says how many bytes the field occupies. */ + /* FIXME: This is abused by TYPE_FIELD_STATIC_PHYSNAME to contain + a pointer, so it has to be long. */ + + long bitsize; + + /* In a struct or enum type, type of this field. + In a function type, type of this argument. + In an array type, the domain-type of the array. */ + + struct type *type; + + /* Name of field, value or argument. + NULL for range bounds and array domains. */ + + char *name; + + } *fields; + + /* For types with virtual functions, VPTR_BASETYPE is the base class which + defined the virtual function table pointer. + + For types that are pointer to member types, VPTR_BASETYPE + is the type that this pointer is a member of. + + Unused otherwise. */ + + struct type *vptr_basetype; + + /* Field number of the virtual function table pointer in + VPTR_BASETYPE. If -1, we were unable to find the virtual + function table pointer in initial symbol reading, and + fill_in_vptr_fieldno should be called to find it if possible. + + Unused if this type does not have virtual functions. */ + + int vptr_fieldno; + + /* Slot to point to additional language-specific fields of this type. */ + + union type_specific + { + + /* ARG_TYPES is for TYPE_CODE_METHOD and TYPE_CODE_FUNC. */ + + struct type **arg_types; + + /* CPLUS_STUFF is for TYPE_CODE_STRUCT. It is initialized to point to + cplus_struct_default, a default static instance of a struct + cplus_struct_type. */ + + struct cplus_struct_type *cplus_stuff; + + } type_specific; +}; + +#define NULL_TYPE ((struct type *) 0) + +/* C++ language-specific information for TYPE_CODE_STRUCT and TYPE_CODE_UNION + nodes. */ + +struct cplus_struct_type +{ + /* Number of base classes this type derives from. The baseclasses are + stored in the first N_BASECLASSES fields (i.e. the `fields' field of + the struct type). I think only the `type' field of such a field has + any meaning. */ + + short n_baseclasses; + + /* Number of methods with unique names. All overloaded methods with + the same name count only once. */ + + short nfn_fields; + + /* Number of methods described for this type plus all the + methods that it derives from. */ + + int nfn_fields_total; + + /* For derived classes, the number of base classes is given by n_baseclasses + and virtual_field_bits is a bit vector containing one bit per base class. + If the base class is virtual, the corresponding bit will be set. + I.E, given: + + class A{}; + class B{}; + class C : public B, public virtual A {}; + + B is a baseclass of C; A is a virtual baseclass for C. + This is a C++ 2.0 language feature. */ + + B_TYPE *virtual_field_bits; + + /* For classes with private fields, the number of fields is given by + nfields and private_field_bits is a bit vector containing one bit + per field. + If the field is private, the corresponding bit will be set. */ + + B_TYPE *private_field_bits; + + /* For classes with protected fields, the number of fields is given by + nfields and protected_field_bits is a bit vector containing one bit + per field. + If the field is private, the corresponding bit will be set. */ + + B_TYPE *protected_field_bits; + + /* For classes, structures, and unions, a description of each field, + which consists of an overloaded name, followed by the types of + arguments that the method expects, and then the name after it + has been renamed to make it distinct. + + fn_fieldlists points to an array of nfn_fields of these. */ + + struct fn_fieldlist + { + + /* The overloaded name. */ + + char *name; + + /* The number of methods with this name. */ + + int length; + + /* The list of methods. */ + + struct fn_field + { + + /* If is_stub is clear, this is the mangled name which we can + look up to find the address of the method (FIXME: it would + be cleaner to have a pointer to the struct symbol here + instead). */ + + /* If is_stub is set, this is the portion of the mangled + name which specifies the arguments. For example, "ii", + if there are two int arguments, or "" if there are no + arguments. See gdb_mangle_name for the conversion from this + format to the one used if is_stub is clear. */ + + char *physname; + + /* The return value of the method */ + + struct type *type; + + /* The argument list. Only valid if is_stub is clear. Contains + the type of each argument, including `this', and ending with + a NULL pointer after the last argument. */ + + struct type **args; + + /* For virtual functions. + First baseclass that defines this virtual function. */ + + struct type *fcontext; + + /* Attributes. */ + + unsigned int is_const : 1; + unsigned int is_volatile : 1; + unsigned int is_private : 1; + unsigned int is_protected : 1; + + /* A stub method only has some fields valid (but they are enough + to reconstruct the rest of the fields). */ + unsigned int is_stub : 1; + + /* Unused. */ + unsigned int dummy : 3; + + /* Index into that baseclass's virtual function table, + minus 2; else if static: VOFFSET_STATIC; else: 0. */ + + unsigned int voffset : 24; + +# define VOFFSET_STATIC 1 + + } *fn_fields; + + } *fn_fieldlists; + +}; + +/* The default value of TYPE_CPLUS_SPECIFIC(T) points to the + this shared static structure. */ + +extern const struct cplus_struct_type cplus_struct_default; + +extern void +allocate_cplus_struct_type PARAMS ((struct type *)); + +#define INIT_CPLUS_SPECIFIC(type) \ + (TYPE_CPLUS_SPECIFIC(type)=(struct cplus_struct_type*)&cplus_struct_default) +#define ALLOCATE_CPLUS_STRUCT_TYPE(type) allocate_cplus_struct_type (type) +#define HAVE_CPLUS_STRUCT(type) \ + (TYPE_CPLUS_SPECIFIC(type) != &cplus_struct_default) + +#define TYPE_NAME(thistype) (thistype)->name +#define TYPE_TAG_NAME(type) ((type)->tag_name) +#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type +#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type +#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type +#define TYPE_FUNCTION_TYPE(thistype) (thistype)->function_type +#define TYPE_LENGTH(thistype) (thistype)->length +#define TYPE_OBJFILE(thistype) (thistype)->objfile +#define TYPE_FLAGS(thistype) (thistype)->flags +#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED) +#define TYPE_CODE(thistype) (thistype)->code +#define TYPE_NFIELDS(thistype) (thistype)->nfields +#define TYPE_FIELDS(thistype) (thistype)->fields + +/* C++ */ + +#define TYPE_VPTR_BASETYPE(thistype) (thistype)->vptr_basetype +#define TYPE_DOMAIN_TYPE(thistype) (thistype)->vptr_basetype +#define TYPE_VPTR_FIELDNO(thistype) (thistype)->vptr_fieldno +#define TYPE_FN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fields +#define TYPE_NFN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields +#define TYPE_NFN_FIELDS_TOTAL(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields_total +#define TYPE_TYPE_SPECIFIC(thistype) (thistype)->type_specific +#define TYPE_ARG_TYPES(thistype) (thistype)->type_specific.arg_types +#define TYPE_CPLUS_SPECIFIC(thistype) (thistype)->type_specific.cplus_stuff +#define TYPE_BASECLASS(thistype,index) (thistype)->fields[index].type +#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses +#define TYPE_BASECLASS_NAME(thistype,index) (thistype)->fields[index].name +#define TYPE_BASECLASS_BITPOS(thistype,index) (thistype)->fields[index].bitpos +#define BASETYPE_VIA_PUBLIC(thistype, index) (!TYPE_FIELD_PRIVATE(thistype, index)) +#define BASETYPE_VIA_VIRTUAL(thistype, index) \ + B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)) + +#define TYPE_FIELD(thistype, n) (thistype)->fields[n] +#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type +#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name +#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type) +#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos +#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize +#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize + +#define TYPE_FIELD_PRIVATE_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits +#define TYPE_FIELD_PROTECTED_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits +#define TYPE_FIELD_VIRTUAL_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits +#define SET_TYPE_FIELD_PRIVATE(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n)) +#define SET_TYPE_FIELD_PROTECTED(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n)) +#define SET_TYPE_FIELD_VIRTUAL(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n)) +#define TYPE_FIELD_PRIVATE(thistype, n) \ + (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits == NULL ? 0 \ + : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n))) +#define TYPE_FIELD_PROTECTED(thistype, n) \ + (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits == NULL ? 0 \ + : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n))) +#define TYPE_FIELD_VIRTUAL(thistype, n) \ + B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n)) + +#define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1) +#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize) + +#define TYPE_FN_FIELDLISTS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists +#define TYPE_FN_FIELDLIST(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n] +#define TYPE_FN_FIELDLIST1(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].fn_fields +#define TYPE_FN_FIELDLIST_NAME(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].name +#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].length + +#define TYPE_FN_FIELD(thisfn, n) (thisfn)[n] +#define TYPE_FN_FIELD_PHYSNAME(thisfn, n) (thisfn)[n].physname +#define TYPE_FN_FIELD_TYPE(thisfn, n) (thisfn)[n].type +#define TYPE_FN_FIELD_ARGS(thisfn, n) TYPE_ARG_TYPES ((thisfn)[n].type) +#define TYPE_FN_FIELD_CONST(thisfn, n) ((thisfn)[n].is_const) +#define TYPE_FN_FIELD_VOLATILE(thisfn, n) ((thisfn)[n].is_volatile) +#define TYPE_FN_FIELD_PRIVATE(thisfn, n) ((thisfn)[n].is_private) +#define TYPE_FN_FIELD_PROTECTED(thisfn, n) ((thisfn)[n].is_protected) +#define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub) +#define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext) +#define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2) +#define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1) +#define TYPE_FN_FIELD_STATIC_P(thisfn, n) ((thisfn)[n].voffset == VOFFSET_STATIC) + +extern struct type *builtin_type_void; +extern struct type *builtin_type_char; +extern struct type *builtin_type_short; +extern struct type *builtin_type_int; +extern struct type *builtin_type_long; +extern struct type *builtin_type_signed_char; +extern struct type *builtin_type_unsigned_char; +extern struct type *builtin_type_unsigned_short; +extern struct type *builtin_type_unsigned_int; +extern struct type *builtin_type_unsigned_long; +extern struct type *builtin_type_float; +extern struct type *builtin_type_double; +extern struct type *builtin_type_long_double; +extern struct type *builtin_type_complex; +extern struct type *builtin_type_double_complex; +extern struct type *builtin_type_string; + +/* This type represents a type that was unrecognized in symbol + read-in. */ + +extern struct type *builtin_type_error; + +extern struct type *builtin_type_long_long; +extern struct type *builtin_type_unsigned_long_long; + +/* Modula-2 types */ + +extern struct type *builtin_type_m2_char; +extern struct type *builtin_type_m2_int; +extern struct type *builtin_type_m2_card; +extern struct type *builtin_type_m2_real; +extern struct type *builtin_type_m2_bool; + +/* Chill types */ + +extern struct type *builtin_type_chill_bool; +extern struct type *builtin_type_chill_char; +extern struct type *builtin_type_chill_long; +extern struct type *builtin_type_chill_ulong; +extern struct type *builtin_type_chill_real; + +/* CC_HAS_LONG_LONG is defined if the host has "long long". */ + +#ifdef CC_HAS_LONG_LONG + +#define BUILTIN_TYPE_LONGEST builtin_type_long_long +#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long + +#else /* not CC_HAS_LONG_LONG. */ + +#define BUILTIN_TYPE_LONGEST builtin_type_long +#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long + +#endif /* not CC_HAS_LONG_LONG. */ + +/* Maximum and minimum values of built-in types */ + +#define MAX_OF_TYPE(t) \ + TYPE_UNSIGNED(t) ? UMAX_OF_SIZE(TYPE_LENGTH(t)) \ + : MAX_OF_SIZE(TYPE_LENGTH(t)) + +#define MIN_OF_TYPE(t) \ + TYPE_UNSIGNED(t) ? UMIN_OF_SIZE(TYPE_LENGTH(t)) \ + : MIN_OF_SIZE(TYPE_LENGTH(t)) + +/* Allocate space for storing data associated with a particular type. + We ensure that the space is allocated using the same mechanism that + was used to allocate the space for the type structure itself. I.E. + if the type is on an objfile's type_obstack, then the space for data + associated with that type will also be allocated on the type_obstack. + If the type is not associated with any particular objfile (such as + builtin types), then the data space will be allocated with xmalloc, + the same as for the type structure. */ + +#define TYPE_ALLOC(t,size) \ + (TYPE_OBJFILE (t) != NULL \ + ? obstack_alloc (&TYPE_OBJFILE (t) -> type_obstack, size) \ + : xmalloc (size)) + +extern struct type * +alloc_type PARAMS ((struct objfile *)); + +extern struct type * +init_type PARAMS ((enum type_code, int, int, char *, struct objfile *)); + +extern struct type * +lookup_reference_type PARAMS ((struct type *)); + +extern struct type * +make_reference_type PARAMS ((struct type *, struct type **)); + +extern struct type * +lookup_member_type PARAMS ((struct type *, struct type *)); + +extern void +smash_to_method_type PARAMS ((struct type *, struct type *, struct type *, + struct type **)); + +extern void +smash_to_member_type PARAMS ((struct type *, struct type *, struct type *)); + +extern struct type * +allocate_stub_method PARAMS ((struct type *)); + +extern char * +type_name_no_tag PARAMS ((const struct type *)); + +extern struct type * +lookup_struct_elt_type PARAMS ((struct type *, char *, int)); + +extern struct type * +make_pointer_type PARAMS ((struct type *, struct type **)); + +extern struct type * +lookup_pointer_type PARAMS ((struct type *)); + +extern struct type * +make_function_type PARAMS ((struct type *, struct type **)); + +extern struct type * +lookup_function_type PARAMS ((struct type *)); + +extern struct type * +create_range_type PARAMS ((struct type *, struct type *, int, int)); + +extern struct type * +create_array_type PARAMS ((struct type *, struct type *, struct type *)); + +extern struct type * +create_string_type PARAMS ((struct type *, struct type *)); + +extern struct type * +lookup_unsigned_typename PARAMS ((char *)); + +extern struct type * +lookup_signed_typename PARAMS ((char *)); + +extern void +check_stub_type PARAMS ((struct type *)); + +extern void +check_stub_method PARAMS ((struct type *, int, int)); + +extern struct type * +lookup_primitive_typename PARAMS ((char *)); + +extern char * +gdb_mangle_name PARAMS ((struct type *, int, int)); + +extern struct type * +builtin_type PARAMS ((char **)); + +extern struct type * +lookup_typename PARAMS ((char *, struct block *, int)); + +extern struct type * +lookup_template_type PARAMS ((char *, struct type *, struct block *)); + +extern struct type * +lookup_fundamental_type PARAMS ((struct objfile *, int)); + +extern void +fill_in_vptr_fieldno PARAMS ((struct type *)); + +#if MAINTENANCE_CMDS +extern void recursive_dump_type PARAMS ((struct type *, int)); +#endif + +/* printcmd.c */ + +extern void +print_scalar_formatted PARAMS ((char *, struct type *, int, int, FILE *)); + +#if MAINTENANCE_CMDS +extern void maintenance_print_type PARAMS ((char *, int)); +#endif + +#endif /* GDBTYPES_H */ diff --git a/gnu/usr.bin/gdb/gdb/getopt.h b/gnu/usr.bin/gdb/gdb/getopt.h new file mode 100644 index 00000000000..1b546b2e330 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/getopt.h @@ -0,0 +1,129 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if __STDC__ +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/gnu/usr.bin/gdb/gdb/i386-dis.c b/gnu/usr.bin/gdb/gdb/i386-dis.c new file mode 100644 index 00000000000..3e4bbb225e6 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/i386-dis.c @@ -0,0 +1,1952 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 1989, 1991 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. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include "dis-asm.h" + +#define MAXLEN 20 + +#include + +struct private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct private *priv = (struct private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define ONE OP_ONE, 0 +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG(); +int OP_J(), OP_SEG(); +int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C(); +int OP_D(), OP_T(), OP_rm(); + +static void dofloat (), putop (), append_prefix (), set_op (); +static int get16 (), get32 (); + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + int (*op1)(); + int bytemode1; + int (*op2)(); + int bytemode2; + int (*op3)(); + int bytemode3; +}; + +struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushl", es }, + { "popl", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushl", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushl", ss }, + { "popl", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushl", ds }, + { "popl", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushl", sIb }, /* push of byte really pushes 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movw", Ew, Sw }, + { "leaS", Gv, M }, + { "movw", Sw, Ew }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cwtl" }, + { "cltd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Xb }, + { "scasS", eAX, Xv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "invd" }, + { "wbinvd" }, + { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 48 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 68 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 70 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushl", fs }, + { "popl", fs }, + { "(bad)" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushl", gs }, + { "popl", gs }, + { "(bad)" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "cmpxchgb", Eb, Gb }, + { "cmpxchgS", Ev, Gv }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "(bad)" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "xaddb", Eb, Gb }, + { "xaddS", Ev, Gv }, + { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* c8 */ + { "bswap", eAX }, + { "bswap", eCX }, + { "bswap", eDX }, + { "bswap", eBX }, + { "bswap", eSP }, + { "bswap", eBP }, + { "bswap", eSI }, + { "bswap", eDI }, + /* d0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static void oappend (); + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; + +struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "invlpg", Ew }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +static void +ckprefix () +{ + prefixes = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static int dflag; +static int aflag; + +static char op1out[100], op2out[100], op3out[100]; +static int op_address[3], op_ad, op_index[3]; +static int start_pc; + + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + struct dis386 *dp; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + + struct private priv; + bfd_byte *inbuf = priv.the_buffer; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + FETCH_DATA (info, codep + 1); + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + (*info->fprintf_func) (info->stream, "fwait"); + return (1); + } + + /* these would be initialized to 0 if disassembling for 8086 or 286 */ + dflag = 1; + aflag = 1; + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + oappend ("addr16 "); + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + dp = &dis386_twobyte[*++codep]; + } + else + dp = &dis386[*codep]; + codep++; + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + (*info->print_address_func) (op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1) + (*info->print_address_func) (op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1) + (*info->print_address_func) (op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + return (codep - inbuf); +} + +char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 +int OP_ST(), OP_STi(); + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdb_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, +}; + + +char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat () +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg]); + obufp = op1out; + OP_E (v_mode); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm]); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf + && FETCH_DATA (the_info, codep + 1) + && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + } +} + +/* ARGSUSED */ +int +OP_ST (ignore) + int ignore; +{ + oappend ("%st"); + return (0); +} + +/* ARGSUSED */ +int +OP_STi (ignore) + int ignore; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); + return (0); +} + + +/* capital letters in template are macros */ +static void +putop (template) + char *template; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag == 0) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + } + } + *obufp = 0; +} + +static void +oappend (s) + char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +static void +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +int +OP_indirE (bytemode) + int bytemode; +{ + oappend ("*"); + OP_E (bytemode); + return (0); +} + +int +OP_E (bytemode) + int bytemode; +{ + int disp; + int havesib; + int base; + int index; + int scale; + int havebase; + + /* skip mod/rm byte */ + codep++; + + havesib = 0; + havebase = 0; + disp = 0; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend (""); + break; + } + return (0); + } + + append_prefix (); + if (rm == 4) + { + havesib = 1; + havebase = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + switch (rm) + { + case 4: + /* implies havesib and havebase */ + if (base == 5) { + havebase = 0; + disp = get32 (); + } + break; + case 5: + disp = get32 (); + break; + default: + havebase = 1; + base = rm; + break; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *(char *)codep++; + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + case 2: + disp = get32 (); + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + } + + if (mod != 0 || rm == 5 || (havesib && base == 5)) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || havesib) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } + return (0); +} + +int +OP_G (bytemode) + int bytemode; +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend (""); + break; + } + return (0); +} + +static int +get32 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +static void +set_op (op) + int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +int +OP_REG (code) + int code; +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = ""; + break; + } + oappend (s); + return (0); +} + +int +OP_I (bytemode) + int bytemode; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +int +OP_sI (bytemode) + int bytemode; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *(char *)codep++; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = (short)get16(); + break; + case w_mode: + op = (short)get16 (); + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +int +OP_J (bytemode) + int bytemode; +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *(char *)codep++; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = (short)get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend (""); + return (0); + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_SEG (dummy) + int dummy; +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); + return (0); +} + +int +OP_DIR (size) + int size; +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + offset = (short)get16 (); + + offset = start_pc + codep - start_codep + offset; + set_op (offset); + sprintf (scratchbuf, "0x%x", offset); + oappend (scratchbuf); + break; + default: + oappend (""); + break; + } + return (0); +} + +/* ARGSUSED */ +int +OP_OFF (bytemode) + int bytemode; +{ + int off; + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_ESDI (dummy) + int dummy; +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); + return (0); +} + +/* ARGSUSED */ +int +OP_DSSI (dummy) + int dummy; +{ + oappend ("%ds:("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); + return (0); +} + +/* ARGSUSED */ +int +OP_ONE (dummy) + int dummy; +{ + oappend ("1"); + return (0); +} + +/* ARGSUSED */ +int +OP_C (dummy) + int dummy; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_D (dummy) + int dummy; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_T (dummy) + int dummy; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); + return (0); +} + +int +OP_rm (bytemode) + int bytemode; +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } + return (0); +} diff --git a/gnu/usr.bin/gdb/gdb/i386-pinsn.c b/gnu/usr.bin/gdb/gdb/i386-pinsn.c new file mode 100644 index 00000000000..b6d7fe91e39 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/i386-pinsn.c @@ -0,0 +1,37 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 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. */ + +#include "defs.h" +#include "dis-asm.h" + + +/* Print the instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + disassemble_info info; + + GDB_INIT_DISASSEMBLE_INFO(info, stream); + + return print_insn_i386 (memaddr, &info); +} diff --git a/gnu/usr.bin/gdb/gdb/i386-tdep.c b/gnu/usr.bin/gdb/gdb/i386-tdep.c new file mode 100644 index 00000000000..3c64d7224cf --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/i386-tdep.c @@ -0,0 +1,595 @@ +/* Intel 386 target-dependent stuff. + Copyright (C) 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" + +static long +i386_get_frame_setup PARAMS ((int)); + +static void +i386_follow_jump PARAMS ((void)); + +static void +codestream_read PARAMS ((unsigned char *, int)); + +static void +codestream_seek PARAMS ((int)); + +static unsigned char +codestream_fill PARAMS ((int)); + +/* helper functions for tm-i386.h */ + +/* Stdio style buffering was used to minimize calls to ptrace, but this + buffering did not take into account that the code section being accessed + may not be an even number of buffers long (even if the buffer is only + sizeof(int) long). In cases where the code section size happened to + be a non-integral number of buffers long, attempting to read the last + buffer would fail. Simply using target_read_memory and ignoring errors, + rather than read_memory, is not the correct solution, since legitimate + access errors would then be totally ignored. To properly handle this + situation and continue to use buffering would require that this code + be able to determine the minimum code section size granularity (not the + alignment of the section itself, since the actual failing case that + pointed out this problem had a section alignment of 4 but was not a + multiple of 4 bytes long), on a target by target basis, and then + adjust it's buffer size accordingly. This is messy, but potentially + feasible. It probably needs the bfd library's help and support. For + now, the buffer size is set to 1. (FIXME -fnf) */ + +#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */ +static CORE_ADDR codestream_next_addr; +static CORE_ADDR codestream_addr; +static unsigned char codestream_buf[CODESTREAM_BUFSIZ]; +static int codestream_off; +static int codestream_cnt; + +#define codestream_tell() (codestream_addr + codestream_off) +#define codestream_peek() (codestream_cnt == 0 ? \ + codestream_fill(1): codestream_buf[codestream_off]) +#define codestream_get() (codestream_cnt-- == 0 ? \ + codestream_fill(0) : codestream_buf[codestream_off++]) + +static unsigned char +codestream_fill (peek_flag) + int peek_flag; +{ + codestream_addr = codestream_next_addr; + codestream_next_addr += CODESTREAM_BUFSIZ; + codestream_off = 0; + codestream_cnt = CODESTREAM_BUFSIZ; + read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ); + + if (peek_flag) + return (codestream_peek()); + else + return (codestream_get()); +} + +static void +codestream_seek (place) + int place; +{ + codestream_next_addr = place / CODESTREAM_BUFSIZ; + codestream_next_addr *= CODESTREAM_BUFSIZ; + codestream_cnt = 0; + codestream_fill (1); + while (codestream_tell() != place) + codestream_get (); +} + +static void +codestream_read (buf, count) + unsigned char *buf; + int count; +{ + unsigned char *p; + int i; + p = buf; + for (i = 0; i < count; i++) + *p++ = codestream_get (); +} + +/* next instruction is a jump, move to target */ + +static void +i386_follow_jump () +{ + unsigned char buf[4]; + long delta; + + int data16; + CORE_ADDR pos; + + pos = codestream_tell (); + + data16 = 0; + if (codestream_peek () == 0x66) + { + codestream_get (); + data16 = 1; + } + + switch (codestream_get ()) + { + case 0xe9: + /* relative jump: if data16 == 0, disp32, else disp16 */ + if (data16) + { + codestream_read (buf, 2); + delta = extract_signed_integer (buf, 2); + + /* include size of jmp inst (including the 0x66 prefix). */ + pos += delta + 4; + } + else + { + codestream_read (buf, 4); + delta = extract_signed_integer (buf, 4); + + pos += delta + 5; + } + break; + case 0xeb: + /* relative jump, disp8 (ignore data16) */ + codestream_read (buf, 1); + /* Sign-extend it. */ + delta = extract_signed_integer (buf, 1); + + pos += delta + 2; + break; + } + codestream_seek (pos); +} + +/* + * find & return amound a local space allocated, and advance codestream to + * first register push (if any) + * + * if entry sequence doesn't make sense, return -1, and leave + * codestream pointer random + */ + +static long +i386_get_frame_setup (pc) + int pc; +{ + unsigned char op; + + codestream_seek (pc); + + i386_follow_jump (); + + op = codestream_get (); + + if (op == 0x58) /* popl %eax */ + { + /* + * this function must start with + * + * popl %eax 0x58 + * xchgl %eax, (%esp) 0x87 0x04 0x24 + * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 + * + * (the system 5 compiler puts out the second xchg + * inst, and the assembler doesn't try to optimize it, + * so the 'sib' form gets generated) + * + * this sequence is used to get the address of the return + * buffer for a function that returns a structure + */ + int pos; + unsigned char buf[4]; + static unsigned char proto1[3] = { 0x87,0x04,0x24 }; + static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; + pos = codestream_tell (); + codestream_read (buf, 4); + if (memcmp (buf, proto1, 3) == 0) + pos += 3; + else if (memcmp (buf, proto2, 4) == 0) + pos += 4; + + codestream_seek (pos); + op = codestream_get (); /* update next opcode */ + } + + if (op == 0x55) /* pushl %ebp */ + { + /* check for movl %esp, %ebp - can be written two ways */ + switch (codestream_get ()) + { + case 0x8b: + if (codestream_get () != 0xec) + return (-1); + break; + case 0x89: + if (codestream_get () != 0xe5) + return (-1); + break; + default: + return (-1); + } + /* check for stack adjustment + * + * subl $XXX, %esp + * + * note: you can't subtract a 16 bit immediate + * from a 32 bit reg, so we don't have to worry + * about a data16 prefix + */ + op = codestream_peek (); + if (op == 0x83) + { + /* subl with 8 bit immed */ + codestream_get (); + if (codestream_get () != 0xec) + /* Some instruction starting with 0x83 other than subl. */ + { + codestream_seek (codestream_tell () - 2); + return 0; + } + /* subl with signed byte immediate + * (though it wouldn't make sense to be negative) + */ + return (codestream_get()); + } + else if (op == 0x81) + { + char buf[4]; + /* Maybe it is subl with 32 bit immedediate. */ + codestream_get(); + if (codestream_get () != 0xec) + /* Some instruction starting with 0x81 other than subl. */ + { + codestream_seek (codestream_tell () - 2); + return 0; + } + /* It is subl with 32 bit immediate. */ + codestream_read ((unsigned char *)buf, 4); + return extract_signed_integer (buf, 4); + } + else + { + return (0); + } + } + else if (op == 0xc8) + { + char buf[2]; + /* enter instruction: arg is 16 bit unsigned immed */ + codestream_read ((unsigned char *)buf, 2); + codestream_get (); /* flush final byte of enter instruction */ + return extract_unsigned_integer (buf, 2); + } + return (-1); +} + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +int +i386_frame_num_args (fi) + struct frame_info *fi; +{ +#if 1 + return -1; +#else + /* This loses because not only might the compiler not be popping the + args right after the function call, it might be popping args from both + this call and a previous one, and we would say there are more args + than there really are. */ + + int retpc; + unsigned char op; + struct frame_info *pfi; + + /* on the 386, the instruction following the call could be: + popl %ecx - one arg + addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits + anything else - zero args */ + + int frameless; + + FRAMELESS_FUNCTION_INVOCATION (fi, frameless); + if (frameless) + /* In the absence of a frame pointer, GDB doesn't get correct values + for nameless arguments. Return -1, so it doesn't print any + nameless arguments. */ + return -1; + + pfi = get_prev_frame_info (fi); + if (pfi == 0) + { + /* Note: this can happen if we are looking at the frame for + main, because FRAME_CHAIN_VALID won't let us go into + start. If we have debugging symbols, that's not really + a big deal; it just means it will only show as many arguments + to main as are declared. */ + return -1; + } + else + { + retpc = pfi->pc; + op = read_memory_integer (retpc, 1); + if (op == 0x59) + /* pop %ecx */ + return 1; + else if (op == 0x83) + { + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $, %esp */ + return (read_memory_integer (retpc+2,1)&0xff)/4; + else + return 0; + } + else if (op == 0x81) + { /* add with 32 bit immediate */ + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $, %esp */ + return read_memory_integer (retpc+2, 4) / 4; + else + return 0; + } + else + { + return 0; + } + } +#endif +} + +/* + * parse the first few instructions of the function to see + * what registers were stored. + * + * We handle these cases: + * + * The startup sequence can be at the start of the function, + * or the function can start with a branch to startup code at the end. + * + * %ebp can be set up with either the 'enter' instruction, or + * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, + * but was once used in the sys5 compiler) + * + * Local space is allocated just below the saved %ebp by either the + * 'enter' instruction, or by 'subl $, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +void +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + long locals; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + memset (fsrp, 0, sizeof *fsrp); + + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH; + + /* check if the PC is in the stack, in a dummy frame */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + { + /* all regs were saved by push_call_dummy () */ + adr = fip->frame; + for (i = 0; i < NUM_REGS; i++) + { + adr -= REGISTER_RAW_SIZE (i); + fsrp->regs[i] = adr; + } + return; + } + + locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); + + if (locals >= 0) + { + adr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; + fsrp->regs[op - 0x50] = adr; + adr -= 4; + } + } + + fsrp->regs[PC_REGNUM] = fip->frame + 4; + fsrp->regs[FP_REGNUM] = fip->frame; +} + +/* return pc of first real instruction */ + +int +i386_skip_prologue (pc) + int pc; +{ + unsigned char op; + int i; + + if (i386_get_frame_setup (pc) < 0) + return (pc); + + /* found valid frame setup - codestream now points to + * start of push instructions for saving registers + */ + + /* skip over register saves */ + for (i = 0; i < 8; i++) + { + op = codestream_peek (); + /* break if not pushl inst */ + if (op < 0x50 || op > 0x57) + break; + codestream_get (); + } + + i386_follow_jump (); + + return (codestream_tell ()); +} + +void +i386_push_dummy_frame () +{ + CORE_ADDR sp = read_register (SP_REGNUM); + int regnum; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + sp = push_word (sp, read_register (PC_REGNUM)); + sp = push_word (sp, read_register (FP_REGNUM)); + write_register (FP_REGNUM, sp); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + read_register_gen (regnum, regbuf); + sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum)); + } + write_register (SP_REGNUM, sp); +} + +void +i386_pop_frame () +{ + FRAME frame = get_current_frame (); + CORE_ADDR fp; + int regnum; + struct frame_saved_regs fsr; + struct frame_info *fi; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + fi = get_frame_info (frame); + fp = fi->frame; + get_frame_saved_regs (fi, &fsr); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + CORE_ADDR adr; + adr = fsr.regs[regnum]; + if (adr) + { + read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum)); + write_register_bytes (REGISTER_BYTE (regnum), regbuf, + REGISTER_RAW_SIZE (regnum)); + } + } + write_register (FP_REGNUM, read_memory_integer (fp, 4)); + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); + write_register (SP_REGNUM, fp + 8); + flush_cached_frames (); + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); +} + +#ifdef GET_LONGJMP_TARGET + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target(pc) + CORE_ADDR *pc; +{ + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + CORE_ADDR sp, jb_addr; + + sp = read_register (SP_REGNUM); + + if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */ + buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + return 1; +} + +#endif /* GET_LONGJMP_TARGET */ + +#ifdef I386_AIX_TARGET +/* On AIX, floating point values are returned in floating point registers. */ + +void +i386_extract_return_value(type, regbuf, valbuf) + struct type *type; + char regbuf[REGISTER_BYTES]; + char *valbuf; +{ + if (TYPE_CODE_FLT == TYPE_CODE(type)) + { + extern struct ext_format ext_format_i387; + double d; + /* 387 %st(0), gcc uses this */ + ieee_extended_to_double (&ext_format_i387, + ®buf[REGISTER_BYTE(FP0_REGNUM)], + &d); + switch (TYPE_LENGTH(type)) + { + case 4: /* float */ + { + float f = (float) d; + memcpy (valbuf, &f, 4); + break; + } + case 8: /* double */ + memcpy (valbuf, &d, 8); + break; + default: + error("Unknown floating point size"); + break; + } + } + else + { + memcpy (valbuf, regbuf, TYPE_LENGTH (type)); + } +} +#endif /* I386_AIX_TARGET */ diff --git a/gnu/usr.bin/gdb/gdb/infcmd.c b/gnu/usr.bin/gdb/gdb/infcmd.c new file mode 100644 index 00000000000..5859ed269f8 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/infcmd.c @@ -0,0 +1,1423 @@ +/* Memory-access and commands for "inferior" (child) process, for GDB. + Copyright 1986, 1987, 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. */ + +#include "defs.h" +#include +#include +#include +#include "symtab.h" +#include "gdbtypes.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "target.h" + +static void +continue_command PARAMS ((char *, int)); + +static void +until_next_command PARAMS ((int)); + +static void +until_command PARAMS ((char *, int)); + +static void +path_info PARAMS ((char *, int)); + +static void +path_command PARAMS ((char *, int)); + +static void +unset_command PARAMS ((char *, int)); + +static void +float_info PARAMS ((char *, int)); + +static void +detach_command PARAMS ((char *, int)); + +static void +nofp_registers_info PARAMS ((char *, int)); + +static void +all_registers_info PARAMS ((char *, int)); + +static void +registers_info PARAMS ((char *, int)); + +static void +do_registers_info PARAMS ((int, int)); + +static void +unset_environment_command PARAMS ((char *, int)); + +static void +set_environment_command PARAMS ((char *, int)); + +static void +environment_info PARAMS ((char *, int)); + +static void +program_info PARAMS ((char *, int)); + +static void +finish_command PARAMS ((char *, int)); + +static void +signal_command PARAMS ((char *, int)); + +static void +jump_command PARAMS ((char *, int)); + +static void +step_1 PARAMS ((int, int, char *)); + +static void +nexti_command PARAMS ((char *, int)); + +static void +stepi_command PARAMS ((char *, int)); + +static void +next_command PARAMS ((char *, int)); + +static void +step_command PARAMS ((char *, int)); + +static void +run_command PARAMS ((char *, int)); + +#define ERROR_NO_INFERIOR \ + if (!target_has_execution) error ("The program is not being run."); + +/* String containing arguments to give to the program, separated by spaces. + Empty string (pointer to '\0') means no args. */ + +static char *inferior_args; + +/* File name for default use for standard in/out in the inferior. */ + +char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. + Since various parts of infrun.c test this to see whether there is a program + being debugged it should be nonzero (currently 3 is used) for remote + debugging. */ + +int inferior_pid; + +/* Last signal that the inferior received (why it stopped). */ + +int stop_signal; + +/* Address at which inferior stopped. */ + +CORE_ADDR stop_pc; + +/* Stack frame when program stopped. */ + +FRAME_ADDR stop_frame_address; + +/* Chain containing status of breakpoint(s) that we have stopped at. */ + +bpstat stop_bpstat; + +/* Flag indicating that a command has proceeded the inferior past the + current breakpoint. */ + +int breakpoint_proceeded; + +/* Nonzero if stopped due to a step command. */ + +int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +int stop_stack_dummy; + +/* Nonzero if stopped due to a random (unexpected) signal in inferior + process. */ + +int stopped_by_random_signal; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. */ + +CORE_ADDR step_range_start; /* Inclusive */ +CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +FRAME_ADDR step_frame_address; + +/* 1 means step over all subroutine calls. + 0 means don't step over calls (used by stepi). + -1 means step over calls to undebuggable functions. */ + +int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +int step_multi; + +/* Environment to use for running inferior, + in format described in environ.h. */ + +struct environ *inferior_environ; + + +/* ARGSUSED */ +void +tty_command (file, from_tty) + char *file; + int from_tty; +{ + if (file == 0) + error_no_arg ("terminal name for running target process"); + + inferior_io_terminal = savestring (file, strlen (file)); +} + +static void +run_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + + dont_repeat (); + + /* Shouldn't this be target_has_execution? FIXME. */ + if (inferior_pid) + { + if ( + !query ("The program being debugged has been started already.\n\ +Start it from the beginning? ")) + error ("Program not restarted."); + target_kill (); + } + + exec_file = (char *) get_exec_file (0); + + /* The exec file is re-read every time we do a generic_mourn_inferior, so + we just have to worry about the symbol file. */ + reread_symbols (); + + if (args) + { + char *cmd; + cmd = concat ("set args ", args, NULL); + make_cleanup (free, cmd); + execute_command (cmd, from_tty); + } + + if (from_tty) + { + puts_filtered("Starting program: "); + if (exec_file) + puts_filtered(exec_file); + puts_filtered(" "); + puts_filtered(inferior_args); + puts_filtered("\n"); + fflush (stdout); + } + + target_create_inferior (exec_file, inferior_args, + environ_vector (inferior_environ)); +} + +static void +continue_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + ERROR_NO_INFERIOR; + + /* If have argument, set proceed count of breakpoint we stopped at. */ + + if (proc_count_exp != NULL) + { + bpstat bs = stop_bpstat; + int num = bpstat_num (&bs); + if (num == 0 && from_tty) + { + printf_filtered + ("Not stopped at any breakpoint; argument ignored.\n"); + } + while (num != 0) + { + set_ignore_count (num, + parse_and_eval_address (proc_count_exp) - 1, + from_tty); + /* set_ignore_count prints a message ending with a period. + So print two spaces before "Continuing.". */ + if (from_tty) + printf_filtered (" "); + num = bpstat_num (&bs); + } + } + + if (from_tty) + printf_filtered ("Continuing.\n"); + + clear_proceed_status (); + + proceed ((CORE_ADDR) -1, -1, 0); +} + +/* Step until outside of current statement. */ + +/* ARGSUSED */ +static void +step_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (0, 0, count_string); +} + +/* Likewise, but skip over subroutine calls as if single instructions. */ + +/* ARGSUSED */ +static void +next_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (1, 0, count_string); +} + +/* Likewise, but step only one instruction. */ + +/* ARGSUSED */ +static void +stepi_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (0, 1, count_string); +} + +/* ARGSUSED */ +static void +nexti_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (1, 1, count_string); +} + +static void +step_1 (skip_subroutines, single_inst, count_string) + int skip_subroutines; + int single_inst; + char *count_string; +{ + register int count = 1; + FRAME fr; + struct cleanup *cleanups = 0; + + ERROR_NO_INFERIOR; + count = count_string ? parse_and_eval_address (count_string) : 1; + + if (!single_inst || skip_subroutines) /* leave si command alone */ + { + enable_longjmp_breakpoint(); + cleanups = make_cleanup(disable_longjmp_breakpoint, 0); + } + + for (; count > 0; count--) + { + clear_proceed_status (); + + fr = get_current_frame (); + if (!fr) /* Avoid coredump here. Why tho? */ + error ("No current frame"); + step_frame_address = FRAME_FP (fr); + + if (! single_inst) + { + find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end); + if (step_range_end == 0) + { + char *name; + if (find_pc_partial_function (stop_pc, &name, &step_range_start, + &step_range_end) == 0) + error ("Cannot find bounds of current function"); + + target_terminal_ours (); + printf_filtered ("\ +Single stepping until exit from function %s, \n\ +which has no line number information.\n", name); + fflush (stdout); + } + } + else + { + /* Say we are stepping, but stop after one insn whatever it does. */ + step_range_start = step_range_end = 1; + if (!skip_subroutines) + /* It is stepi. + Don't step over function calls, not even to functions lacking + line numbers. */ + step_over_calls = 0; + } + + if (skip_subroutines) + step_over_calls = 1; + + step_multi = (count > 1); + proceed ((CORE_ADDR) -1, -1, 1); + if (! stop_step) + break; + + /* FIXME: On nexti, this may have already been done (when we hit the + step resume break, I think). Probably this should be moved to + wait_for_inferior (near the top). */ +#if defined (SHIFT_INST_REGS) + SHIFT_INST_REGS(); +#endif + } + + if (!single_inst || skip_subroutines) + do_cleanups(cleanups); +} + +/* Continue program at specified address. */ + +static void +jump_command (arg, from_tty) + char *arg; + int from_tty; +{ + register CORE_ADDR addr; + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct symbol *fn; + struct symbol *sfn; + + ERROR_NO_INFERIOR; + + if (!arg) + error_no_arg ("starting address"); + + sals = decode_line_spec_1 (arg, 1); + if (sals.nelts != 1) + { + error ("Unreasonable jump request"); + } + + sal = sals.sals[0]; + free ((PTR)sals.sals); + + if (sal.symtab == 0 && sal.pc == 0) + error ("No source file has been specified."); + + resolve_sal_pc (&sal); /* May error out */ + + /* See if we are trying to jump to another function. */ + fn = get_frame_function (get_current_frame ()); + sfn = find_pc_function (sal.pc); + if (fn != NULL && sfn != fn) + { + if (!query ("Line %d is not in `%s'. Jump anyway? ", sal.line, + SYMBOL_SOURCE_NAME (fn))) + { + error ("Not confirmed."); + /* NOTREACHED */ + } + } + + addr = sal.pc; + + if (from_tty) + printf_filtered ("Continuing at %s.\n", + local_hex_string((unsigned long) addr)); + + clear_proceed_status (); + proceed (addr, 0, 0); +} + +/* Continue program giving it specified signal. */ + +static void +signal_command (signum_exp, from_tty) + char *signum_exp; + int from_tty; +{ + register int signum; + + dont_repeat (); /* Too dangerous. */ + ERROR_NO_INFERIOR; + + if (!signum_exp) + error_no_arg ("signal number"); + + /* It would be even slicker to make signal names be valid expressions, + (the type could be "enum $signal" or some such), then the user could + assign them to convenience variables. */ + signum = strtosigno (signum_exp); + + if (signum == 0) + /* Not found as a name, try it as an expression. */ + signum = parse_and_eval_address (signum_exp); + + if (from_tty) + { + char *signame = strsigno (signum); + printf_filtered ("Continuing with signal "); + if (signame == NULL || signum == 0) + printf_filtered ("%d.\n", signum); + else + /* Do we need to print the number as well as the name? */ + printf_filtered ("%s (%d).\n", signame, signum); + } + + clear_proceed_status (); + proceed (stop_pc, signum, 0); +} + +/* Call breakpoint_auto_delete on the current contents of the bpstat + pointed to by arg (which is really a bpstat *). */ +void +breakpoint_auto_delete_contents (arg) + PTR arg; +{ + breakpoint_auto_delete (*(bpstat *)arg); +} + +/* Execute a "stack dummy", a piece of code stored in the stack + by the debugger to be executed in the inferior. + + To call: first, do PUSH_DUMMY_FRAME. + Then push the contents of the dummy. It should end with a breakpoint insn. + Then call here, passing address at which to start the dummy. + + The contents of all registers are saved before the dummy frame is popped + and copied into the buffer BUFFER. + + The dummy's frame is automatically popped whenever that break is hit. + If that is the first time the program stops, run_stack_dummy + returns to its caller with that frame already gone and returns 0. + Otherwise, run_stack-dummy returns 1 (the frame will eventually be popped + when we do hit that breakpoint). */ + +/* DEBUG HOOK: 4 => return instead of letting the stack dummy run. */ + +static int stack_dummy_testing = 0; + +int +run_stack_dummy (addr, buffer) + CORE_ADDR addr; + char buffer[REGISTER_BYTES]; +{ + struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0); + + /* Now proceed, having reached the desired place. */ + clear_proceed_status (); + if (stack_dummy_testing & 4) + { + POP_FRAME; + return(0); + } +#ifdef CALL_DUMMY_BREAKPOINT_OFFSET + { + struct breakpoint *bpt; + struct symtab_and_line sal; + +#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT + sal.pc = addr - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET; +#else + sal.pc = entry_point_address (); +#endif + sal.symtab = NULL; + sal.line = 0; + + /* Set up a FRAME for the dummy frame so we can pass it to + set_momentary_breakpoint. We need to give the breakpoint a + frame in case there is only one copy of the dummy (e.g. + CALL_DUMMY_LOCATION == AFTER_TEXT_END). */ + flush_cached_frames (); + set_current_frame (create_new_frame (read_fp (), sal.pc)); + + /* If defined, CALL_DUMMY_BREAKPOINT_OFFSET is where we need to put + a breakpoint instruction. If not, the call dummy already has the + breakpoint instruction in it. + + addr is the address of the call dummy plus the CALL_DUMMY_START_OFFSET, + so we need to subtract the CALL_DUMMY_START_OFFSET. */ + bpt = set_momentary_breakpoint (sal, + get_current_frame (), + bp_call_dummy); + bpt->disposition = delete; + + /* If all error()s out of proceed ended up calling normal_stop (and + perhaps they should; it already does in the special case of error + out of resume()), then we wouldn't need this. */ + make_cleanup (breakpoint_auto_delete_contents, &stop_bpstat); + } +#endif /* CALL_DUMMY_BREAKPOINT_OFFSET. */ + + proceed_to_finish = 1; /* We want stop_registers, please... */ + proceed (addr, 0, 0); + + discard_cleanups (old_cleanups); + + if (!stop_stack_dummy) + return 1; + + /* On return, the stack dummy has been popped already. */ + + memcpy (buffer, stop_registers, sizeof stop_registers); + return 0; +} + +/* Proceed until we reach a different source line with pc greater than + our current one or exit the function. We skip calls in both cases. + + Note that eventually this command should probably be changed so + that only source lines are printed out when we hit the breakpoint + we set. I'm going to postpone this until after a hopeful rewrite + of wait_for_inferior and the proceed status code. -- randy */ + +/* ARGSUSED */ +static void +until_next_command (from_tty) + int from_tty; +{ + FRAME frame; + CORE_ADDR pc; + struct symbol *func; + struct symtab_and_line sal; + + clear_proceed_status (); + + frame = get_current_frame (); + + /* Step until either exited from this function or greater + than the current line (if in symbolic section) or pc (if + not). */ + + pc = read_pc (); + func = find_pc_function (pc); + + if (!func) + { + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc); + + if (msymbol == NULL) + error ("Execution is not within a known function."); + + step_range_start = SYMBOL_VALUE_ADDRESS (msymbol); + step_range_end = pc; + } + else + { + sal = find_pc_line (pc, 0); + + step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func)); + step_range_end = sal.end; + } + + step_over_calls = 1; + step_frame_address = FRAME_FP (frame); + + step_multi = 0; /* Only one call to proceed */ + + proceed ((CORE_ADDR) -1, -1, 1); +} + +static void +until_command (arg, from_tty) + char *arg; + int from_tty; +{ + if (!target_has_execution) + error ("The program is not running."); + if (arg) + until_break_command (arg, from_tty); + else + until_next_command (from_tty); +} + +/* "finish": Set a temporary breakpoint at the place + the selected frame will return to, then continue. */ + +static void +finish_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal; + register FRAME frame; + struct frame_info *fi; + register struct symbol *function; + struct breakpoint *breakpoint; + struct cleanup *old_chain; + + if (arg) + error ("The \"finish\" command does not take any arguments."); + if (!target_has_execution) + error ("The program is not running."); + if (selected_frame == NULL) + error ("No selected frame."); + + frame = get_prev_frame (selected_frame); + if (frame == 0) + error ("\"finish\" not meaningful in the outermost frame."); + + clear_proceed_status (); + + fi = get_frame_info (frame); + sal = find_pc_line (fi->pc, 0); + sal.pc = fi->pc; + + breakpoint = set_momentary_breakpoint (sal, frame, bp_finish); + + old_chain = make_cleanup(delete_breakpoint, breakpoint); + + /* Find the function we will return from. */ + + fi = get_frame_info (selected_frame); + function = find_pc_function (fi->pc); + + /* Print info on the selected frame, including level number + but not source. */ + if (from_tty) + { + printf_filtered ("Run till exit from "); + print_stack_frame (selected_frame, selected_frame_level, 0); + } + + proceed_to_finish = 1; /* We want stop_registers, please... */ + proceed ((CORE_ADDR) -1, -1, 0); + + /* Did we stop at our breakpoint? */ + if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL + && function != 0) + { + struct type *value_type; + register value val; + CORE_ADDR funcaddr; + + value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (!value_type) + fatal ("internal: finish_command: function has no target type"); + + if (TYPE_CODE (value_type) == TYPE_CODE_VOID) + return; + + funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function)); + + val = value_being_returned (value_type, stop_registers, + using_struct_return (value_of_variable (function, NULL), + funcaddr, + value_type, + BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function)))); + + printf_filtered ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, stdout, 0, Val_no_prettyprint); + printf_filtered ("\n"); + } + do_cleanups(old_chain); +} + +/* ARGSUSED */ +static void +program_info (args, from_tty) + char *args; + int from_tty; +{ + bpstat bs = stop_bpstat; + int num = bpstat_num (&bs); + + if (!target_has_execution) + { + printf_filtered ("The program being debugged is not being run.\n"); + return; + } + + target_files_info (); + printf_filtered ("Program stopped at %s.\n", + local_hex_string((unsigned long) stop_pc)); + if (stop_step) + printf_filtered ("It stopped after being stepped.\n"); + else if (num != 0) + { + /* There may be several breakpoints in the same place, so this + isn't as strange as it seems. */ + while (num != 0) + { + if (num < 0) + printf_filtered ("It stopped at a breakpoint that has since been deleted.\n"); + else + printf_filtered ("It stopped at breakpoint %d.\n", num); + num = bpstat_num (&bs); + } + } + else if (stop_signal) + { +#ifdef PRINT_RANDOM_SIGNAL + PRINT_RANDOM_SIGNAL (stop_signal); +#else + char *signame = strsigno (stop_signal); + printf_filtered ("It stopped with signal "); + if (signame == NULL) + printf_filtered ("%d", stop_signal); + else + /* Do we need to print the number as well as the name? */ + printf_filtered ("%s (%d)", signame, stop_signal); + printf_filtered (", %s.\n", safe_strsignal (stop_signal)); +#endif + } + + if (!from_tty) + printf_filtered ("Type \"info stack\" or \"info registers\" for more information.\n"); +} + +static void +environment_info (var, from_tty) + char *var; + int from_tty; +{ + if (var) + { + register char *val = get_in_environ (inferior_environ, var); + if (val) + { + puts_filtered (var); + puts_filtered (" = "); + puts_filtered (val); + puts_filtered ("\n"); + } + else + { + puts_filtered ("Environment variable \""); + puts_filtered (var); + puts_filtered ("\" not defined.\n"); + } + } + else + { + register char **vector = environ_vector (inferior_environ); + while (*vector) + { + puts_filtered (*vector++); + puts_filtered ("\n"); + } + } +} + +static void +set_environment_command (arg, from_tty) + char *arg; + int from_tty; +{ + register char *p, *val, *var; + int nullset = 0; + + if (arg == 0) + error_no_arg ("environment variable and value"); + + /* Find seperation between variable name and value */ + p = (char *) strchr (arg, '='); + val = (char *) strchr (arg, ' '); + + if (p != 0 && val != 0) + { + /* We have both a space and an equals. If the space is before the + equals, walk forward over the spaces til we see a nonspace + (possibly the equals). */ + if (p > val) + while (*val == ' ') + val++; + + /* Now if the = is after the char following the spaces, + take the char following the spaces. */ + if (p > val) + p = val - 1; + } + else if (val != 0 && p == 0) + p = val; + + if (p == arg) + error_no_arg ("environment variable to set"); + + if (p == 0 || p[1] == 0) + { + nullset = 1; + if (p == 0) + p = arg + strlen (arg); /* So that savestring below will work */ + } + else + { + /* Not setting variable value to null */ + val = p + 1; + while (*val == ' ' || *val == '\t') + val++; + } + + while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--; + + var = savestring (arg, p - arg); + if (nullset) + { + printf_filtered ("Setting environment variable \"%s\" to null value.\n", var); + set_in_environ (inferior_environ, var, ""); + } + else + set_in_environ (inferior_environ, var, val); + free (var); +} + +static void +unset_environment_command (var, from_tty) + char *var; + int from_tty; +{ + if (var == 0) + { + /* If there is no argument, delete all environment variables. + Ask for confirmation if reading from the terminal. */ + if (!from_tty || query ("Delete all environment variables? ")) + { + free_environ (inferior_environ); + inferior_environ = make_environ (); + } + } + else + unset_in_environ (inferior_environ, var); +} + +/* Handle the execution path (PATH variable) */ + +static const char path_var_name[] = "PATH"; + +/* ARGSUSED */ +static void +path_info (args, from_tty) + char *args; + int from_tty; +{ + puts_filtered ("Executable and object file path: "); + puts_filtered (get_in_environ (inferior_environ, path_var_name)); + puts_filtered ("\n"); +} + +/* Add zero or more directories to the front of the execution path. */ + +static void +path_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + char *exec_path; + + dont_repeat (); + exec_path = strsave (get_in_environ (inferior_environ, path_var_name)); + mod_path (dirname, &exec_path); + set_in_environ (inferior_environ, path_var_name, exec_path); + free (exec_path); + if (from_tty) + path_info ((char *)NULL, from_tty); +} + +/* This routine is getting awfully cluttered with #if's. It's probably + time to turn this into READ_PC and define it in the tm.h file. + Ditto for write_pc. */ + +CORE_ADDR +read_pc () +{ +#ifdef TARGET_READ_PC + return TARGET_READ_PC (); +#else + return ADDR_BITS_REMOVE ((CORE_ADDR) read_register (PC_REGNUM)); +#endif +} + +void +write_pc (val) + CORE_ADDR val; +{ +#ifdef TARGET_WRITE_PC + TARGET_WRITE_PC (val); +#else + write_register (PC_REGNUM, (long) val); +#ifdef NPC_REGNUM + write_register (NPC_REGNUM, (long) val + 4); +#ifdef NNPC_REGNUM + write_register (NNPC_REGNUM, (long) val + 8); +#endif +#endif +#endif +} + +/* Cope with strage ways of getting to the stack and frame pointers */ + +CORE_ADDR +read_sp () +{ +#ifdef TARGET_READ_SP + return TARGET_READ_SP (); +#else + return read_register (SP_REGNUM); +#endif +} + +void +write_sp (val) + CORE_ADDR val; +{ +#ifdef TARGET_WRITE_SP + TARGET_WRITE_SP (val); +#else + write_register (SP_REGNUM, val); +#endif +} + + +CORE_ADDR +read_fp () +{ +#ifdef TARGET_READ_FP + return TARGET_READ_FP (); +#else + return read_register (FP_REGNUM); +#endif +} + +void +write_fp (val) + CORE_ADDR val; +{ +#ifdef TARGET_WRITE_FP + TARGET_WRITE_FP (val); +#else + write_register (FP_REGNUM, val); +#endif +} + +const char * const reg_names[] = REGISTER_NAMES; + +/* Print out the machine register regnum. If regnum is -1, + print all registers (fpregs == 1) or all non-float registers + (fpregs == 0). + + For most machines, having all_registers_info() print the + register(s) one per line is good enough. If a different format + is required, (eg, for MIPS or Pyramid 90x, which both have + lots of regs), or there is an existing convention for showing + all the registers, define the macro DO_REGISTERS_INFO(regnum, fp) + to provide that format. */ + +#if !defined (DO_REGISTERS_INFO) +#define DO_REGISTERS_INFO(regnum, fp) do_registers_info(regnum, fp) +static void +do_registers_info (regnum, fpregs) + int regnum; + int fpregs; +{ + register int i; + + for (i = 0; i < NUM_REGS; i++) + { + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + + /* Decide between printing all regs, nonfloat regs, or specific reg. */ + if (regnum == -1) { + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT && !fpregs) + continue; + } else { + if (i != regnum) + continue; + } + + fputs_filtered (reg_names[i], stdout); + print_spaces_filtered (15 - strlen (reg_names[i]), stdout); + + /* Get the data in raw format, then convert also to virtual format. */ + if (read_relative_register_raw_bytes (i, raw_buffer)) + { + printf_filtered ("Invalid register contents\n"); + continue; + } + + REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer); + + /* If virtual format is floating, print it that way, and in raw hex. */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT + && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i))) + { + register int j; + + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, + stdout, 0, 1, 0, Val_pretty_default); + + printf_filtered ("\t(raw 0x"); + for (j = 0; j < REGISTER_RAW_SIZE (i); j++) + printf_filtered ("%02x", (unsigned char)raw_buffer[j]); + printf_filtered (")"); + } + +/* FIXME! val_print probably can handle all of these cases now... */ + + /* Else if virtual format is too long for printf, + print in hex a byte at a time. */ + else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long)) + { + register int j; + printf_filtered ("0x"); + for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++) + printf_filtered ("%02x", (unsigned char)virtual_buffer[j]); + } + /* Else print as integer in hex and in decimal. */ + else + { + val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0, + stdout, 'x', 1, 0, Val_pretty_default); + printf_filtered ("\t"); + val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0, + stdout, 0, 1, 0, Val_pretty_default); + } + + /* The SPARC wants to print even-numbered float regs as doubles + in addition to printing them as floats. */ +#ifdef PRINT_REGISTER_HOOK + PRINT_REGISTER_HOOK (i); +#endif + + printf_filtered ("\n"); + } +} +#endif /* no DO_REGISTERS_INFO. */ + +static void +registers_info (addr_exp, fpregs) + char *addr_exp; + int fpregs; +{ + int regnum; + register char *end; + + if (!target_has_registers) + error ("The program has no registers now."); + + if (!addr_exp) + { + DO_REGISTERS_INFO(-1, fpregs); + return; + } + + do + { + if (addr_exp[0] == '$') + addr_exp++; + end = addr_exp; + while (*end != '\0' && *end != ' ' && *end != '\t') + ++end; + for (regnum = 0; regnum < NUM_REGS; regnum++) + if (!strncmp (addr_exp, reg_names[regnum], end - addr_exp) + && strlen (reg_names[regnum]) == end - addr_exp) + goto found; + if (*addr_exp >= '0' && *addr_exp <= '9') + regnum = atoi (addr_exp); /* Take a number */ + if (regnum >= NUM_REGS) /* Bad name, or bad number */ + error ("%.*s: invalid register", end - addr_exp, addr_exp); + +found: + DO_REGISTERS_INFO(regnum, fpregs); + + addr_exp = end; + while (*addr_exp == ' ' || *addr_exp == '\t') + ++addr_exp; + } while (*addr_exp != '\0'); +} + +static void +all_registers_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ + registers_info (addr_exp, 1); +} + +static void +nofp_registers_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ + registers_info (addr_exp, 0); +} + +/* + * TODO: + * Should save/restore the tty state since it might be that the + * program to be debugged was started on this tty and it wants + * the tty in some state other than what we want. If it's running + * on another terminal or without a terminal, then saving and + * restoring the tty state is a harmless no-op. + * This only needs to be done if we are attaching to a process. + */ + +/* + attach_command -- + takes a program started up outside of gdb and ``attaches'' to it. + This stops it cold in its tracks and allows us to start debugging it. + and wait for the trace-trap that results from attaching. */ + +void +attach_command (args, from_tty) + char *args; + int from_tty; +{ + dont_repeat (); /* Not for the faint of heart */ + + if (target_has_execution) + { + if (query ("A program is being debugged already. Kill it? ")) + target_kill (); + else + error ("Not killed."); + } + + target_attach (args, from_tty); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* Set up execution context to know that we should return from + wait_for_inferior as soon as the target reports a stop. */ + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + + wait_for_inferior (); + +#ifdef SOLIB_ADD + /* Add shared library symbols from the newly attached process, if any. */ + SOLIB_ADD ((char *)0, from_tty, (struct target_ops *)0); +#endif + + normal_stop (); +} + +/* + * detach_command -- + * takes a program previously attached to and detaches it. + * The program resumes execution and will no longer stop + * on signals, etc. We better not have left any breakpoints + * in the program or it'll die when it hits one. For this + * to work, it may be necessary for the process to have been + * previously attached. It *might* work if the program was + * started via the normal ptrace (PTRACE_TRACEME). + */ + +static void +detach_command (args, from_tty) + char *args; + int from_tty; +{ + dont_repeat (); /* Not for the faint of heart */ + target_detach (args, from_tty); +} + +/* ARGSUSED */ +static void +float_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ +#ifdef FLOAT_INFO + FLOAT_INFO; +#else + printf_filtered ("No floating point info available for this processor.\n"); +#endif +} + +/* ARGSUSED */ +static void +unset_command (args, from_tty) + char *args; + int from_tty; +{ + printf_filtered ("\"unset\" must be followed by the name of an unset subcommand.\n"); + help_list (unsetlist, "unset ", -1, stdout); +} + +void +_initialize_infcmd () +{ + struct cmd_list_element *c; + + add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); + + add_show_from_set + (add_set_cmd ("args", class_run, var_string_noescape, (char *)&inferior_args, + +"Set arguments to give program being debugged when it is started.\n\ +Follow this command with any number of args, to be passed to the program.", + &setlist), + &showlist); + + c = add_cmd + ("environment", no_class, environment_info, + "The environment to give the program, or one variable's value.\n\ +With an argument VAR, prints the value of environment variable VAR to\n\ +give the program being debugged. With no arguments, prints the entire\n\ +environment to be given to the program.", &showlist); + c->completer = noop_completer; + + add_prefix_cmd ("unset", no_class, unset_command, + "Complement to certain \"set\" commands", + &unsetlist, "unset ", 0, &cmdlist); + + c = add_cmd ("environment", class_run, unset_environment_command, + "Cancel environment variable VAR for the program.\n\ +This does not affect the program until the next \"run\" command.", + &unsetlist); + c->completer = noop_completer; + + c = add_cmd ("environment", class_run, set_environment_command, + "Set environment variable value to give the program.\n\ +Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\ +VALUES of environment variables are uninterpreted strings.\n\ +This does not affect the program until the next \"run\" command.", + &setlist); + c->completer = noop_completer; + + add_com ("path", class_files, path_command, + "Add directory DIR(s) to beginning of search path for object files.\n\ +$cwd in the path means the current working directory.\n\ +This path is equivalent to the $PATH shell variable. It is a list of\n\ +directories, separated by colons. These directories are searched to find\n\ +fully linked executable files and separately compiled object files as needed."); + + c = add_cmd ("paths", no_class, path_info, + "Current search path for finding object files.\n\ +$cwd in the path means the current working directory.\n\ +This path is equivalent to the $PATH shell variable. It is a list of\n\ +directories, separated by colons. These directories are searched to find\n\ +fully linked executable files and separately compiled object files as needed.", &showlist); + c->completer = noop_completer; + + add_com ("attach", class_run, attach_command, + "Attach to a process or file outside of GDB.\n\ +This command attaches to another target, of the same type as your last\n\ +`target' command (`info files' will show your target stack).\n\ +The command may take as argument a process id or a device file.\n\ +For a process id, you must have permission to send the process a signal,\n\ +and it must have the same effective uid as the debugger.\n\ +When using \"attach\", you should use the \"file\" command to specify\n\ +the program running in the process, and to load its symbol table."); + + add_com ("detach", class_run, detach_command, + "Detach a process or file previously attached.\n\ +If a process, it is no longer traced, and it continues its execution. If you\n\ +were debugging a file, the file is closed and gdb no longer accesses it."); + + add_com ("signal", class_run, signal_command, + "Continue program giving it signal number SIGNUMBER."); + + add_com ("stepi", class_run, stepi_command, + "Step one instruction exactly.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("si", "stepi", class_alias, 0); + + add_com ("nexti", class_run, nexti_command, + "Step one instruction, but proceed through subroutine calls.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("ni", "nexti", class_alias, 0); + + add_com ("finish", class_run, finish_command, + "Execute until selected stack frame returns.\n\ +Upon return, the value returned is printed and put in the value history."); + + add_com ("next", class_run, next_command, + "Step program, proceeding through subroutine calls.\n\ +Like the \"step\" command as long as subroutine calls do not happen;\n\ +when they do, the call is treated as one instruction.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("n", "next", class_run, 1); + + add_com ("step", class_run, step_command, + "Step program until it reaches a different source line.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("s", "step", class_run, 1); + + add_com ("until", class_run, until_command, + "Execute until the program reaches a source line greater than the current\n\ +or a specified line or address or function (same args as break command).\n\ +Execution will also stop upon exit from the current stack frame."); + add_com_alias ("u", "until", class_run, 1); + + add_com ("jump", class_run, jump_command, + "Continue program being debugged at specified line or address.\n\ +Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ +for an address to start at."); + + add_com ("continue", class_run, continue_command, + "Continue program being debugged, after signal or breakpoint.\n\ +If proceeding from breakpoint, a number N may be used as an argument,\n\ +which means to set the ignore count of that breakpoint to N - 1 (so that\n\ +the breakpoint won't break until the Nth time it is reached)."); + add_com_alias ("c", "cont", class_run, 1); + add_com_alias ("fg", "cont", class_run, 1); + + add_com ("run", class_run, run_command, + "Start debugged program. You may specify arguments to give it.\n\ +Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\ +Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\ +With no arguments, uses arguments last specified (with \"run\" or \"set args\").\n\ +To cancel previous arguments and run with no arguments,\n\ +use \"set args\" without arguments."); + add_com_alias ("r", "run", class_run, 1); + + add_info ("registers", nofp_registers_info, + "List of integer registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("all-registers", all_registers_info, +"List of all registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("program", program_info, + "Execution status of the program."); + + add_info ("float", float_info, + "Print the status of the floating point unit\n"); + + inferior_args = savestring ("", 1); /* Initially no args */ + inferior_environ = make_environ (); + init_environ (inferior_environ); +} diff --git a/gnu/usr.bin/gdb/gdb/inferior.h b/gnu/usr.bin/gdb/gdb/inferior.h new file mode 100644 index 00000000000..0f5499a3c6b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/inferior.h @@ -0,0 +1,401 @@ +/* Variables that describe the inferior process running under GDB: + Where it is, why it stopped, and how to step it. + Copyright 1986, 1989, 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. */ + +#if !defined (INFERIOR_H) +#define INFERIOR_H 1 + +/* For bpstat. */ +#include "breakpoint.h" + +/* For FRAME_ADDR. */ +#include "frame.h" + +/* + * Structure in which to save the status of the inferior. Save + * through "save_inferior_status", restore through + * "restore_inferior_status". + * This pair of routines should be called around any transfer of + * control to the inferior which you don't want showing up in your + * control variables. + */ +struct inferior_status { + int stop_signal; + CORE_ADDR stop_pc; + FRAME_ADDR stop_frame_address; + bpstat stop_bpstat; + int stop_step; + int stop_stack_dummy; + int stopped_by_random_signal; + int trap_expected; + CORE_ADDR step_range_start; + CORE_ADDR step_range_end; + FRAME_ADDR step_frame_address; + int step_over_calls; + CORE_ADDR step_resume_break_address; + int stop_after_trap; + int stop_soon_quietly; + FRAME_ADDR selected_frame_address; + int selected_level; + char stop_registers[REGISTER_BYTES]; + + /* These are here because if call_function_by_hand has written some + registers and then decides to call error(), we better not have changed + any registers. */ + char registers[REGISTER_BYTES]; + + int breakpoint_proceeded; + int restore_stack_info; + int proceed_to_finish; +}; + +extern void +save_inferior_status PARAMS ((struct inferior_status *, int)); + +extern void +restore_inferior_status PARAMS ((struct inferior_status *)); + +/* File name for default use for standard in/out in the inferior. */ + +extern char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. */ + +extern int inferior_pid; + +/* Character array containing an image of the inferior programs' registers. */ + +extern char registers[]; + +/* Array of validity bits (one per register). Nonzero at position XXX_REGNUM + means that `registers' contains a valid copy of inferior register XXX. */ + +extern char register_valid[NUM_REGS]; + +extern void +clear_proceed_status PARAMS ((void)); + +extern void +proceed PARAMS ((CORE_ADDR, int, int)); + +extern void +kill_inferior PARAMS ((void)); + +extern void +generic_mourn_inferior PARAMS ((void)); + +extern void +terminal_ours PARAMS ((void)); + +extern int run_stack_dummy PARAMS ((CORE_ADDR, char [REGISTER_BYTES])); + +extern CORE_ADDR +read_pc PARAMS ((void)); + +extern void +write_pc PARAMS ((CORE_ADDR)); + +extern CORE_ADDR +read_sp PARAMS ((void)); + +extern void +write_sp PARAMS ((CORE_ADDR)); + +extern CORE_ADDR +read_fp PARAMS ((void)); + +extern void +write_fp PARAMS ((CORE_ADDR)); + +extern void +wait_for_inferior PARAMS ((void)); + +extern void +init_wait_for_inferior PARAMS ((void)); + +extern void +close_exec_file PARAMS ((void)); + +extern void +reopen_exec_file PARAMS ((void)); + +/* The `resume' routine should only be called in special circumstances. + Normally, use `proceed', which handles a lot of bookkeeping. */ +extern void +resume PARAMS ((int, int)); + +/* From misc files */ + +extern void +store_inferior_registers PARAMS ((int)); + +extern void +fetch_inferior_registers PARAMS ((int)); + +extern void +solib_create_inferior_hook PARAMS ((void)); + +extern void +child_terminal_info PARAMS ((char *, int)); + +extern void +term_info PARAMS ((char *, int)); + +extern void +terminal_ours_for_output PARAMS ((void)); + +extern void +terminal_inferior PARAMS ((void)); + +extern void +terminal_init_inferior PARAMS ((void)); + +/* From infptrace.c */ + +extern int +attach PARAMS ((int)); + +void +detach PARAMS ((int)); + +extern void +child_resume PARAMS ((int, int, int)); + +#ifndef PTRACE_ARG3_TYPE +#define PTRACE_ARG3_TYPE int /* Correct definition for most systems. */ +#endif + +extern int +call_ptrace PARAMS ((int, int, PTRACE_ARG3_TYPE, int)); + +/* From procfs.c */ + +extern int +proc_iterate_over_mappings PARAMS ((int (*) (int, CORE_ADDR))); + +/* From fork-child.c */ + +extern void +fork_inferior PARAMS ((char *, char *, char **, + void (*) (void), + void (*) (int))); + +/* From inflow.c */ + +extern void +new_tty_prefork PARAMS ((char *)); + +extern int gdb_has_a_terminal PARAMS ((void)); + +/* From infrun.c */ + +extern void +start_remote PARAMS ((void)); + +extern void +normal_stop PARAMS ((void)); + +extern int +signal_stop_state PARAMS ((int)); + +extern int +signal_print_state PARAMS ((int)); + +extern int +signal_pass_state PARAMS ((int)); + +/* From infcmd.c */ + +extern void +tty_command PARAMS ((char *, int)); + +extern void +attach_command PARAMS ((char *, int)); + +/* Last signal that the inferior received (why it stopped). */ + +extern int stop_signal; + +/* Address at which inferior stopped. */ + +extern CORE_ADDR stop_pc; + +/* Stack frame when program stopped. */ + +extern FRAME_ADDR stop_frame_address; + +/* Chain containing status of breakpoint(s) that we have stopped at. */ + +extern bpstat stop_bpstat; + +/* Flag indicating that a command has proceeded the inferior past the + current breakpoint. */ + +extern int breakpoint_proceeded; + +/* Nonzero if stopped due to a step command. */ + +extern int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +extern int stop_stack_dummy; + +/* Nonzero if program stopped due to a random (unexpected) signal in + inferior process. */ + +extern int stopped_by_random_signal; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. + + If step_range_start and step_range_end are both 1, it means to step for + a single instruction (FIXME: it might clean up wait_for_inferior in a + minor way if this were changed to the address of the instruction and + that address plus one. But maybe not.). */ + +extern CORE_ADDR step_range_start; /* Inclusive */ +extern CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +extern FRAME_ADDR step_frame_address; + +/* 1 means step over all subroutine calls. + -1 means step over calls to undebuggable functions. */ + +extern int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +extern int step_multi; + +/* Nonzero means expecting a trap and caller will handle it themselves. + It is used after attach, due to attaching to a process; + when running in the shell before the child program has been exec'd; + and when running some kinds of remote stuff (FIXME?). */ + +extern int stop_soon_quietly; + +/* Nonzero if proceed is being used for a "finish" command or a similar + situation when stop_registers should be saved. */ + +extern int proceed_to_finish; + +/* Save register contents here when about to pop a stack dummy frame, + if-and-only-if proceed_to_finish is set. + Thus this contains the return value from the called function (assuming + values are returned in a register). */ + +extern char stop_registers[REGISTER_BYTES]; + +/* Nonzero if the child process in inferior_pid was attached rather + than forked. */ + +extern int attach_flag; + +/* Sigtramp is a routine that the kernel calls (which then calls the + signal handler). On most machines it is a library routine that + is linked into the executable. + + This macro, given a program counter value and the name of the + function in which that PC resides (which can be null if the + name is not known), returns nonzero if the PC and name show + that we are in sigtramp. + + On most machines just see if the name is sigtramp (and if we have + no name, assume we are not in sigtramp). */ +#if !defined (IN_SIGTRAMP) +# if defined (SIGTRAMP_START) +# define IN_SIGTRAMP(pc, name) \ + ((pc) >= SIGTRAMP_START \ + && (pc) < SIGTRAMP_END \ + ) +# else +# define IN_SIGTRAMP(pc, name) \ + (name && STREQ ("_sigtramp", name)) +# endif +#endif + +/* Possible values for CALL_DUMMY_LOCATION. */ +#define ON_STACK 1 +#define BEFORE_TEXT_END 2 +#define AFTER_TEXT_END 3 +#define AT_ENTRY_POINT 4 + +#if !defined (CALL_DUMMY_LOCATION) +#define CALL_DUMMY_LOCATION ON_STACK +#endif /* No CALL_DUMMY_LOCATION. */ + +/* Are we in a call dummy? The code below which allows DECR_PC_AFTER_BREAK + below is for infrun.c, which may give the macro a pc without that + subtracted out. */ +#if !defined (PC_IN_CALL_DUMMY) +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END +extern CORE_ADDR text_end; +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= text_end - CALL_DUMMY_LENGTH \ + && (pc) <= text_end + DECR_PC_AFTER_BREAK) +#endif /* Before text_end. */ + +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END +extern CORE_ADDR text_end; +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= text_end \ + && (pc) <= text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK) +#endif /* After text_end. */ + +#if CALL_DUMMY_LOCATION == ON_STACK +/* Is the PC in a call dummy? SP and FRAME_ADDRESS are the bottom and + top of the stack frame which we are checking, where "bottom" and + "top" refer to some section of memory which contains the code for + the call dummy. Calls to this macro assume that the contents of + SP_REGNUM and FP_REGNUM (or the saved values thereof), respectively, + are the things to pass. + + This won't work on the 29k, where SP_REGNUM and FP_REGNUM don't + have that meaning, but the 29k doesn't use ON_STACK. This could be + fixed by generalizing this scheme, perhaps by passing in a frame + and adding a few fields, at least on machines which need them for + PC_IN_CALL_DUMMY. + + Something simpler, like checking for the stack segment, doesn't work, + since various programs (threads implementations, gcc nested function + stubs, etc) may either allocate stack frames in another segment, or + allocate other kinds of code on the stack. */ + +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((sp) INNER_THAN (pc) && (frame_address != 0) && (pc) INNER_THAN (frame_address)) +#endif /* On stack. */ + +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT +extern CORE_ADDR +entry_point_address PARAMS ((void)); +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= entry_point_address () \ + && (pc) <= (entry_point_address () + DECR_PC_AFTER_BREAK)) +#endif /* At entry point. */ +#endif /* No PC_IN_CALL_DUMMY. */ + +#endif /* !defined (INFERIOR_H) */ diff --git a/gnu/usr.bin/gdb/gdb/inflow.c b/gnu/usr.bin/gdb/gdb/inflow.c new file mode 100644 index 00000000000..be0b43ba672 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/inflow.c @@ -0,0 +1,662 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright 1986, 1987, 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. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "command.h" +#include "signals.h" +#include "serial.h" +#include "terminal.h" +#include "target.h" + +#include +#include + +#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY) && !defined (__GO32__) +#define HAVE_SGTTY +#endif + +#if defined (HAVE_TERMIOS) +#include +#include +#endif + +#ifdef HAVE_TERMIOS +#define PROCESS_GROUP_TYPE pid_t +#endif + +#ifdef HAVE_SGTTY +#ifdef SHORT_PGRP +/* This is only used for the ultra. Does it have pid_t? */ +#define PROCESS_GROUP_TYPE short +#else +#define PROCESS_GROUP_TYPE int +#endif +#endif /* sgtty */ + +static void +kill_command PARAMS ((char *, int)); + +static void +terminal_ours_1 PARAMS ((int)); + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +int attach_flag; + + +/* Record terminal status separately for debugger and inferior. */ + +static serial_t stdin_serial; + +/* TTY state for the inferior. We save it whenever the inferior stops, and + restore it when it resumes. */ +static serial_ttystate inferior_ttystate; + +/* Our own tty state, which we restore every time we need to deal with the + terminal. We only set it once, when GDB first starts. The settings of + flags which readline saves and restores and unimportant. */ +static serial_ttystate our_ttystate; + +/* fcntl flags for us and the inferior. Saved and restored just like + {our,inferior}_ttystate. */ +static int tflags_inferior; +static int tflags_ours; + +#ifdef PROCESS_GROUP_TYPE +/* Process group for us and the inferior. Saved and restored just like + {our,inferior}_ttystate. */ +PROCESS_GROUP_TYPE our_process_group; +PROCESS_GROUP_TYPE inferior_process_group; +#endif + +/* While the inferior is running, we want SIGINT and SIGQUIT to go to the + inferior only. If we have job control, that takes care of it. If not, + we save our handlers in these two variables and set SIGINT and SIGQUIT + to SIG_IGN. */ +static void (*sigint_ours) (); +static void (*sigquit_ours) (); + +/* The name of the tty (from the `tty' command) that we gave to the inferior + when it was last started. */ + +static char *inferior_thisrun_terminal; + +/* Nonzero if our terminal settings are in effect. Zero if the + inferior's settings are in effect. Ignored if !gdb_has_a_terminal + (). */ + +static int terminal_is_ours; + +enum {yes, no, have_not_checked} gdb_has_a_terminal_flag = have_not_checked; + +/* Does GDB have a terminal (on stdin)? */ +int +gdb_has_a_terminal () +{ + switch (gdb_has_a_terminal_flag) + { + case yes: + return 1; + case no: + return 0; + case have_not_checked: + /* Get all the current tty settings (including whether we have a tty at + all!). Can't do this in _initialize_inflow because SERIAL_FDOPEN + won't work until the serial_ops_list is initialized. */ + +#ifdef F_GETFL + tflags_ours = fcntl (0, F_GETFL, 0); +#endif + + gdb_has_a_terminal_flag = no; + stdin_serial = SERIAL_FDOPEN (0); + if (stdin_serial != NULL) + { + our_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); + + if (our_ttystate != NULL) + { + gdb_has_a_terminal_flag = yes; +#ifdef HAVE_TERMIOS + our_process_group = tcgetpgrp (0); +#endif +#ifdef HAVE_SGTTY + ioctl (0, TIOCGPGRP, &our_process_group); +#endif + } + } + + return gdb_has_a_terminal_flag == yes; + } +} + +/* Macro for printing errors from ioctl operations */ + +#define OOPSY(what) \ + if (result == -1) \ + fprintf(stderr, "[%s failed in terminal_inferior: %s]\n", \ + what, strerror (errno)) + +static void terminal_ours_1 PARAMS ((int)); + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +void +terminal_init_inferior () +{ + if (gdb_has_a_terminal ()) + { + /* We could just as well copy our_ttystate (if we felt like adding + a new function SERIAL_COPY_TTY_STATE). */ + if (inferior_ttystate) + free (inferior_ttystate); + inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); +#ifdef PROCESS_GROUP_TYPE + inferior_process_group = inferior_pid; +#endif + + /* Make sure that next time we call terminal_inferior (which will be + before the program runs, as it needs to be), we install the new + process group. */ + terminal_is_ours = 1; + } +} + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +void +terminal_inferior () +{ + if (gdb_has_a_terminal () && terminal_is_ours + && inferior_thisrun_terminal == 0) + { + int result; + +#ifdef F_GETFL + /* Is there a reason this is being done twice? It happens both + places we use F_SETFL, so I'm inclined to think perhaps there + is some reason, however perverse. Perhaps not though... */ + result = fcntl (0, F_SETFL, tflags_inferior); + result = fcntl (0, F_SETFL, tflags_inferior); + OOPSY ("fcntl F_SETFL"); +#endif + + /* Because we were careful to not change in or out of raw mode in + terminal_ours, we will not change in our out of raw mode with + this call, so we don't flush any input. */ + result = SERIAL_SET_TTY_STATE (stdin_serial, inferior_ttystate); + OOPSY ("setting tty state"); + + if (!job_control) + { + sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN); + sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN); + } + + /* If attach_flag is set, we don't know whether we are sharing a + terminal with the inferior or not. (attaching a process + without a terminal is one case where we do not; attaching a + process which we ran from the same shell as GDB via `&' is + one case where we do, I think (but perhaps this is not + `sharing' in the sense that we need to save and restore tty + state)). I don't know if there is any way to tell whether we + are sharing a terminal. So what we do is to go through all + the saving and restoring of the tty state, but ignore errors + setting the process group, which will happen if we are not + sharing a terminal). */ + + if (job_control) + { +#ifdef HAVE_TERMIOS + result = tcsetpgrp (0, inferior_process_group); + if (!attach_flag) + OOPSY ("tcsetpgrp"); +#endif + +#ifdef HAVE_SGTTY + result = ioctl (0, TIOCSPGRP, &inferior_process_group); + if (!attach_flag) + OOPSY ("TIOCSPGRP"); +#endif + } + + } + terminal_is_ours = 0; +} + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +void +terminal_ours_for_output () +{ + terminal_ours_1 (1); +} + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +void +terminal_ours () +{ + terminal_ours_1 (0); +} + +/* output_only is not used, and should not be used unless we introduce + separate terminal_is_ours and terminal_is_ours_for_output + flags. */ + +static void +terminal_ours_1 (output_only) + int output_only; +{ + /* Checking inferior_thisrun_terminal is necessary so that + if GDB is running in the background, it won't block trying + to do the ioctl()'s below. Checking gdb_has_a_terminal + avoids attempting all the ioctl's when running in batch. */ + if (inferior_thisrun_terminal != 0 || gdb_has_a_terminal () == 0) + return; + + if (!terminal_is_ours) + { + /* Ignore this signal since it will happen when we try to set the + pgrp. */ + void (*osigttou) (); + int result; + + terminal_is_ours = 1; + +#ifdef SIGTTOU + if (job_control) + osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN); +#endif + + if (inferior_ttystate) + free (inferior_ttystate); + inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); +#ifdef HAVE_TERMIOS + inferior_process_group = tcgetpgrp (0); +#endif +#ifdef HAVE_SGTTY + ioctl (0, TIOCGPGRP, &inferior_process_group); +#endif + + /* Here we used to set ICANON in our ttystate, but I believe this + was an artifact from before when we used readline. Readline sets + the tty state when it needs to. */ + + /* Set tty state to our_ttystate. We don't change in our out of raw + mode, to avoid flushing input. We need to do the same thing + regardless of output_only, because we don't have separate + terminal_is_ours and terminal_is_ours_for_output flags. It's OK, + though, since readline will deal with raw mode when/if it needs to. + */ + SERIAL_NOFLUSH_SET_TTY_STATE (stdin_serial, our_ttystate, + inferior_ttystate); + + if (job_control) + { +#ifdef HAVE_TERMIOS + result = tcsetpgrp (0, our_process_group); +#if 0 + /* This fails on Ultrix with EINVAL if you run the testsuite + in the background with nohup, and then log out. GDB never + used to check for an error here, so perhaps there are other + such situations as well. */ + if (result == -1) + fprintf (stderr, "[tcsetpgrp failed in terminal_ours: %s]\n", + strerror (errno)); +#endif +#endif /* termios */ + +#ifdef HAVE_SGTTY + result = ioctl (0, TIOCSPGRP, &our_process_group); +#endif + } + +#ifdef SIGTTOU + if (job_control) + signal (SIGTTOU, osigttou); +#endif + + if (!job_control) + { + signal (SIGINT, sigint_ours); + signal (SIGQUIT, sigquit_ours); + } + +#ifdef F_GETFL + tflags_inferior = fcntl (0, F_GETFL, 0); + + /* Is there a reason this is being done twice? It happens both + places we use F_SETFL, so I'm inclined to think perhaps there + is some reason, however perverse. Perhaps not though... */ + result = fcntl (0, F_SETFL, tflags_ours); + result = fcntl (0, F_SETFL, tflags_ours); +#endif + + result = result; /* lint */ + } +} + +/* ARGSUSED */ +void +term_info (arg, from_tty) + char *arg; + int from_tty; +{ + target_terminal_info (arg, from_tty); +} + +/* ARGSUSED */ +void +child_terminal_info (args, from_tty) + char *args; + int from_tty; +{ + if (!gdb_has_a_terminal ()) + { + printf_filtered ("This GDB does not control a terminal.\n"); + return; + } + + printf_filtered ("Inferior's terminal status (currently saved by GDB):\n"); + + /* First the fcntl flags. */ + { + int flags; + + flags = tflags_inferior; + + printf_filtered ("File descriptor flags = "); + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (flags & (O_ACCMODE)) + { + case O_RDONLY: printf_filtered ("O_RDONLY"); break; + case O_WRONLY: printf_filtered ("O_WRONLY"); break; + case O_RDWR: printf_filtered ("O_RDWR"); break; + } + flags &= ~(O_ACCMODE); + +#ifdef O_NONBLOCK + if (flags & O_NONBLOCK) + printf_filtered (" | O_NONBLOCK"); + flags &= ~O_NONBLOCK; +#endif + +#if defined (O_NDELAY) + /* If O_NDELAY and O_NONBLOCK are defined to the same thing, we will + print it as O_NONBLOCK, which is good cause that is what POSIX + has, and the flag will already be cleared by the time we get here. */ + if (flags & O_NDELAY) + printf_filtered (" | O_NDELAY"); + flags &= ~O_NDELAY; +#endif + + if (flags & O_APPEND) + printf_filtered (" | O_APPEND"); + flags &= ~O_APPEND; + +#if defined (O_BINARY) + if (flags & O_BINARY) + printf_filtered (" | O_BINARY"); + flags &= ~O_BINARY; +#endif + + if (flags) + printf_filtered (" | 0x%x", flags); + printf_filtered ("\n"); + } + +#ifdef PROCESS_GROUP_TYPE + printf_filtered ("Process group = %d\n", inferior_process_group); +#endif + + SERIAL_PRINT_TTY_STATE (stdin_serial, inferior_ttystate); +} + +/* NEW_TTY_PREFORK is called before forking a new child process, + so we can record the state of ttys in the child to be formed. + TTYNAME is null if we are to share the terminal with gdb; + or points to a string containing the name of the desired tty. + + NEW_TTY is called in new child processes under Unix, which will + become debugger target processes. This actually switches to + the terminal specified in the NEW_TTY_PREFORK call. */ + +void +new_tty_prefork (ttyname) + char *ttyname; +{ + /* Save the name for later, for determining whether we and the child + are sharing a tty. */ + inferior_thisrun_terminal = ttyname; +} + +void +new_tty () +{ + register int tty; + + if (inferior_thisrun_terminal == 0) + return; +#if !defined(__GO32__) +#ifdef TIOCNOTTY + /* Disconnect the child process from our controlling terminal. On some + systems (SVR4 for example), this may cause a SIGTTOU, so temporarily + ignore SIGTTOU. */ + tty = open("/dev/tty", O_RDWR); + if (tty > 0) + { + void (*osigttou) (); + + osigttou = (void (*)()) signal(SIGTTOU, SIG_IGN); + ioctl(tty, TIOCNOTTY, 0); + close(tty); + signal(SIGTTOU, osigttou); + } +#endif + + /* Now open the specified new terminal. */ + +#ifdef USE_O_NOCTTY + tty = open(inferior_thisrun_terminal, O_RDWR | O_NOCTTY); +#else + tty = open(inferior_thisrun_terminal, O_RDWR); +#endif + if (tty == -1) + { + print_sys_errmsg (inferior_thisrun_terminal, errno); + _exit(1); + } + + /* Avoid use of dup2; doesn't exist on all systems. */ + if (tty != 0) + { close (0); dup (tty); } + if (tty != 1) + { close (1); dup (tty); } + if (tty != 2) + { close (2); dup (tty); } + if (tty > 2) + close(tty); +#endif /* !go32 */ +} + +/* Kill the inferior process. Make us have no inferior. */ + +/* ARGSUSED */ +static void +kill_command (arg, from_tty) + char *arg; + int from_tty; +{ + /* Shouldn't this be target_has_execution? FIXME. */ + if (inferior_pid == 0) + error ("The program is not being run."); + if (!query ("Kill the program being debugged? ")) + error ("Not confirmed."); + target_kill (); + + init_thread_list(); /* Destroy thread info */ + + /* Killing off the inferior can leave us with a core file. If so, + print the state we are left in. */ + if (target_has_stack) { + printf_filtered ("In %s,\n", current_target->to_longname); + if (selected_frame == NULL) + fputs_filtered ("No selected stack frame.\n", stdout); + else + print_stack_frame (selected_frame, selected_frame_level, 1); + } +} + +/* The inferior process has died. Long live the inferior! */ + +void +generic_mourn_inferior () +{ + inferior_pid = 0; + attach_flag = 0; + breakpoint_init_inferior (); + registers_changed (); + +#ifdef CLEAR_DEFERRED_STORES + /* Delete any pending stores to the inferior... */ + CLEAR_DEFERRED_STORES; +#endif + + reopen_exec_file (); + reinit_frame_cache (); + + /* It is confusing to the user for ignore counts to stick around + from previous runs of the inferior. So clear them. */ + breakpoint_clear_ignore_counts (); +} + +/* Call set_sigint_trap when you need to pass a signal on to an attached + process when handling SIGINT */ + +/* ARGSUSED */ +static void +pass_signal (signo) + int signo; +{ + kill (inferior_pid, SIGINT); +} + +static void (*osig)(); + +void +set_sigint_trap() +{ + osig = (void (*) ()) signal (SIGINT, pass_signal); +} + +void +clear_sigint_trap() +{ + signal (SIGINT, osig); +} + + +int job_control; + +/* This is here because this is where we figure out whether we (probably) + have job control. Just using job_control only does part of it because + setpgid or setpgrp might not exist on a system without job control. + It might be considered misplaced (on the other hand, process groups and + job control are closely related to ttys). + + For a more clean implementation, in libiberty, put a setpgid which merely + calls setpgrp and a setpgrp which does nothing (any system with job control + will have one or the other). */ +int +gdb_setpgid () +{ + int retval = 0; + if (job_control) + { +#if defined (NEED_POSIX_SETPGID) || defined (HAVE_TERMIOS) + /* Do all systems with termios have setpgid? I hope so. */ + /* setpgid (0, 0) is supposed to work and mean the same thing as + this, but on Ultrix 4.2A it fails with EPERM (and + setpgid (getpid (), getpid ()) succeeds). */ + retval = setpgid (getpid (), getpid ()); +#else +#if defined (TIOCGPGRP) +#if defined(USG) && !defined(SETPGRP_ARGS) + retval = setpgrp (); +#else + retval = setpgrp (getpid (), getpid ()); +#endif /* USG */ +#endif /* TIOCGPGRP. */ +#endif /* NEED_POSIX_SETPGID */ + } + return retval; +} + +void +_initialize_inflow () +{ + add_info ("terminal", term_info, + "Print inferior's saved terminal status."); + + add_com ("kill", class_run, kill_command, + "Kill execution of program being debugged."); + + inferior_pid = 0; + + terminal_is_ours = 1; + + /* OK, figure out whether we have job control. If neither termios nor + sgtty (i.e. termio or go32), leave job_control 0. */ + +#if defined (HAVE_TERMIOS) + /* Do all systems with termios have the POSIX way of identifying job + control? I hope so. */ +#ifdef _POSIX_JOB_CONTROL + job_control = 1; +#else + job_control = sysconf (_SC_JOB_CONTROL); +#endif +#endif /* termios */ + +#ifdef HAVE_SGTTY +#ifdef TIOCGPGRP + job_control = 1; +#else + job_control = 0; +#endif /* TIOCGPGRP */ +#endif /* sgtty */ +} diff --git a/gnu/usr.bin/gdb/gdb/infptrace.c b/gnu/usr.bin/gdb/gdb/infptrace.c new file mode 100644 index 00000000000..a152d673a5d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/infptrace.c @@ -0,0 +1,436 @@ +/* Low level Unix child interface to ptrace, for GDB when running under Unix. + Copyright 1988, 1989, 1990, 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. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#ifndef NO_PTRACE_H +#ifdef PTRACE_IN_WRONG_PLACE +#include +#else +#include +#endif +#endif /* NO_PTRACE_H */ + +#if !defined (PT_KILL) +#define PT_KILL 8 +#endif + +#if !defined (PT_STEP) +#define PT_STEP 9 +#define PT_CONTINUE 7 +#define PT_READ_U 3 +#define PT_WRITE_U 6 +#define PT_READ_I 1 +#define PT_READ_D 2 +#define PT_WRITE_I 4 +#define PT_WRITE_D 5 +#endif /* No PT_STEP. */ + +#ifndef PT_ATTACH +#define PT_ATTACH PTRACE_ATTACH +#endif +#ifndef PT_DETACH +#define PT_DETACH PTRACE_DETACH +#endif + +#include "gdbcore.h" +#ifndef NO_SYS_FILE +#include +#endif +#if 0 +/* Don't think this is used anymore. On the sequent (not sure whether it's + dynix or ptx or both), it is included unconditionally by sys/user.h and + not protected against multiple inclusion. */ +#include +#endif + +#if !defined (FETCH_INFERIOR_REGISTERS) +#include /* Probably need to poke the user structure */ +#if defined (KERNEL_U_ADDR_BSD) +#include /* For struct nlist */ +#endif /* KERNEL_U_ADDR_BSD. */ +#endif /* !FETCH_INFERIOR_REGISTERS */ + + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, addr, data) + int request, pid; + PTRACE_ARG3_TYPE addr; + int data; +{ + return ptrace (request, pid, addr, data +#if defined (FIVE_ARG_PTRACE) + /* Deal with HPUX 8.0 braindamage. We never use the + calls which require the fifth argument. */ + , 0 +#endif + ); +} + +#if defined (DEBUG_PTRACE) || defined (FIVE_ARG_PTRACE) +/* For the rest of the file, use an extra level of indirection */ +/* This lets us breakpoint usefully on call_ptrace. */ +#define ptrace call_ptrace +#endif + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + /* ptrace PT_KILL only works if process is stopped!!! So stop it with + a real signal first, if we can. */ + kill (inferior_pid, SIGKILL); + ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0); + wait ((int *)0); + target_mourn_inferior (); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +child_resume (pid, step, signal) + int pid; + int step; + int signal; +{ + errno = 0; + + if (pid == -1) + pid = inferior_pid; + + /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where + it was. (If GDB wanted it to start some other way, we have already + written a new PC value to the child.) + + If this system does not support PT_STEP, a higher level function will + have called single_step() to transmute the step request into a + continue request (by setting breakpoints on all possible successor + instructions), so we don't have to worry about that here. */ + + if (step) + ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, signal); + else + ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1, signal); + + if (errno) + perror_with_name ("ptrace"); +} + +#ifdef ATTACH_DETACH +/* Start debugging the process whose number is PID. */ +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +/* Default the type of the ptrace transfer to int. */ +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif + +#if !defined (FETCH_INFERIOR_REGISTERS) + +/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#if defined (KERNEL_U_ADDR_BSD) +/* Get kernel_u_addr using BSD-style nlist(). */ +CORE_ADDR kernel_u_addr; + +void +_initialize_kernel_u_addr () +{ + struct nlist names[2]; + + names[0].n_un.n_name = "_u"; + names[1].n_un.n_name = NULL; + if (nlist ("/vmunix", names) == 0) + kernel_u_addr = names[0].n_value; + else + fatal ("Unable to get kernel u area address."); +} +#endif /* KERNEL_U_ADDR_BSD. */ + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ + - KERNEL_U_ADDR +#endif + +/* Registers we shouldn't try to fetch. */ +#if !defined (CANNOT_FETCH_REGISTER) +#define CANNOT_FETCH_REGISTER(regno) 0 +#endif + +/* Fetch one register. */ + +static void +fetch_register (regno) + int regno; +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + char mess[128]; /* For messages */ + register int i; + + /* Offset of registers within the u area. */ + unsigned int offset; + + if (CANNOT_FETCH_REGISTER (regno)) + { + memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + supply_register (regno, buf); + return; + } + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} + + +/* Fetch all registers, or just one, from the child process. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + if (regno == -1) + for (regno = 0; regno < NUM_REGS; regno++) + fetch_register (regno); + else + fetch_register (regno); +} + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + register int i; + + unsigned int offset = U_REGS_OFFSET; + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(PTRACE_XFER_TYPE); + } + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + if (CANNOT_STORE_REGISTER (regno)) + continue; + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(PTRACE_XFER_TYPE); + } + } + } +} +#endif /* !defined (FETCH_INFERIOR_REGISTERS). */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. + + Returns the length copied, which is either the LEN argument or zero. + This xfer function does not do partial moves, since child_ops + doesn't allow memory operations to cross below us in the target stack + anyway. */ + +int +child_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE); + /* Allocate buffer of that many longwords. */ + register PTRACE_XFER_TYPE *buffer + = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, + 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_READ_I, inferior_pid, + ((PTRACE_ARG3_TYPE) + (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))), + 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + myaddr, + len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + } + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + buffer[i] = ptrace (PT_READ_I, inferior_pid, + (PTRACE_ARG3_TYPE) addr, 0); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, + (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + len); + } + return len; +} diff --git a/gnu/usr.bin/gdb/gdb/infrun.c b/gnu/usr.bin/gdb/gdb/infrun.c new file mode 100644 index 00000000000..9266c31caf1 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/infrun.c @@ -0,0 +1,1848 @@ +/* Target-struct-independent code to start (run) and stop an inferior process. + Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993 + 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. */ + +#include "defs.h" +#include +#include +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "breakpoint.h" +#include "wait.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "target.h" + +#include + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include +#else +#include +#endif + +/* Prototypes for local functions */ + +static void +signals_info PARAMS ((char *, int)); + +static void +handle_command PARAMS ((char *, int)); + +static void +sig_print_info PARAMS ((int)); + +static void +sig_print_header PARAMS ((void)); + +static void +resume_cleanups PARAMS ((int)); + +static int +hook_stop_stub PARAMS ((char *)); + +/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the + program. It needs to examine the jmp_buf argument and extract the PC + from it. The return value is non-zero on success, zero otherwise. */ +#ifndef GET_LONGJMP_TARGET +#define GET_LONGJMP_TARGET(PC_ADDR) 0 +#endif + + +/* Some machines have trampoline code that sits between function callers + and the actual functions themselves. If this machine doesn't have + such things, disable their processing. */ +#ifndef SKIP_TRAMPOLINE_CODE +#define SKIP_TRAMPOLINE_CODE(pc) 0 +#endif + +/* For SVR4 shared libraries, each call goes through a small piece of + trampoline code in the ".init" section. IN_SOLIB_TRAMPOLINE evaluates + to nonzero if we are current stopped in one of these. */ +#ifndef IN_SOLIB_TRAMPOLINE +#define IN_SOLIB_TRAMPOLINE(pc,name) 0 +#endif + +/* On some systems, the PC may be left pointing at an instruction that won't + actually be executed. This is usually indicated by a bit in the PSW. If + we find ourselves in such a state, then we step the target beyond the + nullified instruction before returning control to the user so as to avoid + confusion. */ + +#ifndef INSTRUCTION_NULLIFIED +#define INSTRUCTION_NULLIFIED 0 +#endif + +/* Tables of how to react to signals; the user sets them. */ + +static unsigned char *signal_stop; +static unsigned char *signal_print; +static unsigned char *signal_program; + +#define SET_SIGS(nsigs,sigs,flags) \ + do { \ + int signum = (nsigs); \ + while (signum-- > 0) \ + if ((sigs)[signum]) \ + (flags)[signum] = 1; \ + } while (0) + +#define UNSET_SIGS(nsigs,sigs,flags) \ + do { \ + int signum = (nsigs); \ + while (signum-- > 0) \ + if ((sigs)[signum]) \ + (flags)[signum] = 0; \ + } while (0) + + +/* Command list pointer for the "stop" placeholder. */ + +static struct cmd_list_element *stop_command; + +/* Nonzero if breakpoints are now inserted in the inferior. */ + +static int breakpoints_inserted; + +/* Function inferior was in as of last step command. */ + +static struct symbol *step_start_function; + +/* Nonzero if we are expecting a trace trap and should proceed from it. */ + +static int trap_expected; + +/* Nonzero if the next time we try to continue the inferior, it will + step one instruction and generate a spurious trace trap. + This is used to compensate for a bug in HP-UX. */ + +static int trap_expected_after_continue; + +/* Nonzero means expecting a trace trap + and should stop the inferior and return silently when it happens. */ + +int stop_after_trap; + +/* Nonzero means expecting a trap and caller will handle it themselves. + It is used after attach, due to attaching to a process; + when running in the shell before the child program has been exec'd; + and when running some kinds of remote stuff (FIXME?). */ + +int stop_soon_quietly; + +/* Nonzero if proceed is being used for a "finish" command or a similar + situation when stop_registers should be saved. */ + +int proceed_to_finish; + +/* Save register contents here when about to pop a stack dummy frame, + if-and-only-if proceed_to_finish is set. + Thus this contains the return value from the called function (assuming + values are returned in a register). */ + +char stop_registers[REGISTER_BYTES]; + +/* Nonzero if program stopped due to error trying to insert breakpoints. */ + +static int breakpoints_failed; + +/* Nonzero after stop if current stack frame should be printed. */ + +static int stop_print_frame; + +#ifdef NO_SINGLE_STEP +extern int one_stepped; /* From machine dependent code */ +extern void single_step (); /* Same. */ +#endif /* NO_SINGLE_STEP */ + + +/* Things to clean up if we QUIT out of resume (). */ +/* ARGSUSED */ +static void +resume_cleanups (arg) + int arg; +{ + normal_stop (); +} + +/* Resume the inferior, but allow a QUIT. This is useful if the user + wants to interrupt some lengthy single-stepping operation + (for child processes, the SIGINT goes to the inferior, and so + we get a SIGINT random_signal, but for remote debugging and perhaps + other targets, that's not true). + + STEP nonzero if we should step (zero to continue instead). + SIG is the signal to give the inferior (zero for none). */ +void +resume (step, sig) + int step; + int sig; +{ + struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); + QUIT; + +#ifdef CANNOT_STEP_BREAKPOINT + /* Most targets can step a breakpoint instruction, thus executing it + normally. But if this one cannot, just continue and we will hit + it anyway. */ + if (step && breakpoints_inserted && breakpoint_here_p (read_pc ())) + step = 0; +#endif + +#ifdef NO_SINGLE_STEP + if (step) { + single_step(sig); /* Do it the hard way, w/temp breakpoints */ + step = 0; /* ...and don't ask hardware to do it. */ + } +#endif + + /* Handle any optimized stores to the inferior NOW... */ +#ifdef DO_DEFERRED_STORES + DO_DEFERRED_STORES; +#endif + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + target_resume (-1, step, sig); + discard_cleanups (old_cleanups); +} + + +/* Clear out all variables saying what to do when inferior is continued. + First do this, then set the ones you want, then call `proceed'. */ + +void +clear_proceed_status () +{ + trap_expected = 0; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + step_over_calls = -1; + stop_after_trap = 0; + stop_soon_quietly = 0; + proceed_to_finish = 0; + breakpoint_proceeded = 1; /* We're about to proceed... */ + + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&stop_bpstat); +} + +/* Basic routine for continuing the program in various fashions. + + ADDR is the address to resume at, or -1 for resume where stopped. + SIGGNAL is the signal to give it, or 0 for none, + or -1 for act according to how it stopped. + STEP is nonzero if should trap after one instruction. + -1 means return after that and print nothing. + You should probably set various step_... variables + before calling here, if you are stepping. + + You should call clear_proceed_status before calling proceed. */ + +void +proceed (addr, siggnal, step) + CORE_ADDR addr; + int siggnal; + int step; +{ + int oneproc = 0; + + if (step > 0) + step_start_function = find_pc_function (read_pc ()); + if (step < 0) + stop_after_trap = 1; + + if (addr == (CORE_ADDR)-1) + { + /* If there is a breakpoint at the address we will resume at, + step one instruction before inserting breakpoints + so that we do not stop right away. */ + + if (breakpoint_here_p (read_pc ())) + oneproc = 1; + } + else + write_pc (addr); + + if (trap_expected_after_continue) + { + /* If (step == 0), a trap will be automatically generated after + the first instruction is executed. Force step one + instruction to clear this condition. This should not occur + if step is nonzero, but it is harmless in that case. */ + oneproc = 1; + trap_expected_after_continue = 0; + } + + if (oneproc) + /* We will get a trace trap after one instruction. + Continue it automatically and insert breakpoints then. */ + trap_expected = 1; + else + { + int temp = insert_breakpoints (); + if (temp) + { + print_sys_errmsg ("ptrace", temp); + error ("Cannot insert breakpoints.\n\ +The same program may be running in another process."); + } + breakpoints_inserted = 1; + } + + if (siggnal >= 0) + stop_signal = siggnal; + /* If this signal should not be seen by program, + give it zero. Used for debugging signals. */ + else if (stop_signal < NSIG && !signal_program[stop_signal]) + stop_signal= 0; + + /* Resume inferior. */ + resume (oneproc || step || bpstat_should_step (), stop_signal); + + /* Wait for it to stop (if not standalone) + and in any case decode why it stopped, and act accordingly. */ + + wait_for_inferior (); + normal_stop (); +} + +/* Record the pc and sp of the program the last time it stopped. + These are just used internally by wait_for_inferior, but need + to be preserved over calls to it and cleared when the inferior + is started. */ +static CORE_ADDR prev_pc; +static CORE_ADDR prev_sp; +static CORE_ADDR prev_func_start; +static char *prev_func_name; + + +/* Start remote-debugging of a machine over a serial link. */ + +void +start_remote () +{ + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + trap_expected = 0; + wait_for_inferior (); + normal_stop (); +} + +/* Initialize static vars when a new inferior begins. */ + +void +init_wait_for_inferior () +{ + /* These are meaningless until the first time through wait_for_inferior. */ + prev_pc = 0; + prev_sp = 0; + prev_func_start = 0; + prev_func_name = NULL; + + trap_expected_after_continue = 0; + breakpoints_inserted = 0; + breakpoint_init_inferior (); + stop_signal = 0; /* Don't confuse first call to proceed(). */ +} + +static void +delete_breakpoint_current_contents (arg) + PTR arg; +{ + struct breakpoint **breakpointp = (struct breakpoint **)arg; + if (*breakpointp != NULL) + delete_breakpoint (*breakpointp); +} + +/* Wait for control to return from inferior to debugger. + If inferior gets a signal, we may decide to start it up again + instead of returning. That is why there is a loop in this function. + When this function actually returns it means the inferior + should be left stopped and GDB should read more commands. */ + +void +wait_for_inferior () +{ + struct cleanup *old_cleanups; + WAITTYPE w; + int another_trap; + int random_signal; + CORE_ADDR stop_sp = 0; + CORE_ADDR stop_func_start; + char *stop_func_name; + CORE_ADDR prologue_pc = 0, tmp; + struct symtab_and_line sal; + int remove_breakpoints_on_following_step = 0; + int current_line; + int handling_longjmp = 0; /* FIXME */ + struct breakpoint *step_resume_breakpoint = NULL; + int pid; + + old_cleanups = make_cleanup (delete_breakpoint_current_contents, + &step_resume_breakpoint); + sal = find_pc_line(prev_pc, 0); + current_line = sal.line; + + /* Are we stepping? */ +#define CURRENTLY_STEPPING() ((step_resume_breakpoint == NULL \ + && !handling_longjmp \ + && (step_range_end \ + || trap_expected)) \ + || bpstat_should_step ()) + + while (1) + { + /* Clean up saved state that will become invalid. */ + flush_cached_frames (); + registers_changed (); + + pid = target_wait (-1, &w); + +#ifdef SIGTRAP_STOP_AFTER_LOAD + + /* Somebody called load(2), and it gave us a "trap signal after load". + Ignore it gracefully. */ + + SIGTRAP_STOP_AFTER_LOAD (w); +#endif + + /* See if the process still exists; clean up if it doesn't. */ + if (WIFEXITED (w)) + { + target_terminal_ours (); /* Must do this before mourn anyway */ + if (WEXITSTATUS (w)) + printf_filtered ("\nProgram exited with code 0%o.\n", + (unsigned int)WEXITSTATUS (w)); + else + if (!batch_mode()) + printf_filtered ("\nProgram exited normally.\n"); + fflush (stdout); + target_mourn_inferior (); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + stop_print_frame = 0; + break; + } + else if (!WIFSTOPPED (w)) + { + char *signame; + + stop_print_frame = 0; + stop_signal = WTERMSIG (w); + target_terminal_ours (); /* Must do this before mourn anyway */ + target_kill (); /* kill mourns as well */ +#ifdef PRINT_RANDOM_SIGNAL + printf_filtered ("\nProgram terminated: "); + PRINT_RANDOM_SIGNAL (stop_signal); +#else + printf_filtered ("\nProgram terminated with signal "); + signame = strsigno (stop_signal); + if (signame == NULL) + printf_filtered ("%d", stop_signal); + else + /* Do we need to print the number in addition to the name? */ + printf_filtered ("%s (%d)", signame, stop_signal); + printf_filtered (", %s\n", safe_strsignal (stop_signal)); +#endif + printf_filtered ("The program no longer exists.\n"); + fflush (stdout); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + break; + } + + stop_signal = WSTOPSIG (w); + + if (pid != inferior_pid) + { + int save_pid = inferior_pid; + + inferior_pid = pid; /* Setup for target memory/regs */ + registers_changed (); + stop_pc = read_pc (); + inferior_pid = save_pid; + registers_changed (); + } + else + stop_pc = read_pc (); + + if (stop_signal == SIGTRAP + && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) + if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid)) + { + /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ + if (breakpoints_inserted) + { + remove_breakpoints (); + target_resume (pid, 1, 0); /* Single step */ + /* FIXME: What if a signal arrives instead of the single-step + happening? */ + target_wait (pid, NULL); + insert_breakpoints (); + } + target_resume (-1, 0, 0); + continue; + } + else + if (pid != inferior_pid) + goto switch_thread; + + if (pid != inferior_pid) + { + int printed = 0; + + if (!in_thread_list (pid)) + { + fprintf (stderr, "[New %s]\n", target_pid_to_str (pid)); + add_thread (pid); + + target_resume (-1, 0, 0); + continue; + } + else + { + if (stop_signal >= NSIG || signal_print[stop_signal]) + { + char *signame; + + printed = 1; + target_terminal_ours_for_output (); + printf_filtered ("\nProgram received signal "); + signame = strsigno (stop_signal); + if (signame == NULL) + printf_filtered ("%d", stop_signal); + else + printf_filtered ("%s (%d)", signame, stop_signal); + printf_filtered (", %s\n", safe_strsignal (stop_signal)); + + fflush (stdout); + } + + if (stop_signal == SIGTRAP + || stop_signal >= NSIG + || signal_stop[stop_signal]) + { +switch_thread: + inferior_pid = pid; + printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); + + flush_cached_frames (); + registers_changed (); + trap_expected = 0; + if (step_resume_breakpoint) + { + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; + } + prev_pc = 0; + prev_sp = 0; + prev_func_name = NULL; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + handling_longjmp = 0; + another_trap = 0; + } + else + { + if (printed) + target_terminal_inferior (); + + /* Clear the signal if it should not be passed. */ + if (signal_program[stop_signal] == 0) + stop_signal = 0; + + target_resume (-1, 0, stop_signal); + continue; + } + } + } + +same_pid: + +#ifdef NO_SINGLE_STEP + if (one_stepped) + single_step (0); /* This actually cleans up the ss */ +#endif /* NO_SINGLE_STEP */ + +/* If PC is pointing at a nullified instruction, then step beyond it so that + the user won't be confused when GDB appears to be ready to execute it. */ + + if (INSTRUCTION_NULLIFIED) + { + resume (1, 0); + continue; + } + + set_current_frame ( create_new_frame (read_fp (), stop_pc)); + + stop_frame_address = FRAME_FP (get_current_frame ()); + stop_sp = read_sp (); + stop_func_start = 0; + stop_func_name = 0; + /* Don't care about return value; stop_func_start and stop_func_name + will both be 0 if it doesn't work. */ + find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start, + NULL); + stop_func_start += FUNCTION_START_OFFSET; + another_trap = 0; + bpstat_clear (&stop_bpstat); + stop_step = 0; + stop_stack_dummy = 0; + stop_print_frame = 1; + random_signal = 0; + stopped_by_random_signal = 0; + breakpoints_failed = 0; + + /* Look at the cause of the stop, and decide what to do. + The alternatives are: + 1) break; to really stop and return to the debugger, + 2) drop through to start up again + (set another_trap to 1 to single step once) + 3) set random_signal to 1, and the decision between 1 and 2 + will be made according to the signal handling tables. */ + + /* First, distinguish signals caused by the debugger from signals + that have to do with the program's own actions. + Note that breakpoint insns may cause SIGTRAP or SIGILL + or SIGEMT, depending on the operating system version. + Here we detect when a SIGILL or SIGEMT is really a breakpoint + and change it to SIGTRAP. */ + + if (stop_signal == SIGTRAP + || (breakpoints_inserted && + (stop_signal == SIGILL +#ifdef SIGEMT + || stop_signal == SIGEMT +#endif + )) + || stop_soon_quietly) + { + if (stop_signal == SIGTRAP && stop_after_trap) + { + stop_print_frame = 0; + break; + } + if (stop_soon_quietly) + break; + + /* Don't even think about breakpoints + if just proceeded over a breakpoint. + + However, if we are trying to proceed over a breakpoint + and end up in sigtramp, then step_resume_breakpoint + will be set and we should check whether we've hit the + step breakpoint. */ + if (stop_signal == SIGTRAP && trap_expected + && step_resume_breakpoint == NULL) + bpstat_clear (&stop_bpstat); + else + { + /* See if there is a breakpoint at the current PC. */ + stop_bpstat = bpstat_stop_status + (&stop_pc, stop_frame_address, +#if DECR_PC_AFTER_BREAK + /* Notice the case of stepping through a jump + that lands just after a breakpoint. + Don't confuse that with hitting the breakpoint. + What we check for is that 1) stepping is going on + and 2) the pc before the last insn does not match + the address of the breakpoint before the current pc. */ + (prev_pc != stop_pc - DECR_PC_AFTER_BREAK + && CURRENTLY_STEPPING ()) +#else /* DECR_PC_AFTER_BREAK zero */ + 0 +#endif /* DECR_PC_AFTER_BREAK zero */ + ); + /* Following in case break condition called a + function. */ + stop_print_frame = 1; + } + + if (stop_signal == SIGTRAP) + random_signal + = !(bpstat_explains_signal (stop_bpstat) + || trap_expected +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + || (step_range_end && step_resume_breakpoint == NULL)); + else + { + random_signal + = !(bpstat_explains_signal (stop_bpstat) + /* End of a stack dummy. Some systems (e.g. Sony + news) give another signal besides SIGTRAP, + so check here as well as above. */ +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + ); + if (!random_signal) + stop_signal = SIGTRAP; + } + } + else + random_signal = 1; + + /* For the program's own signals, act according to + the signal handling tables. */ + + if (random_signal) + { + /* Signal not for debugging purposes. */ + int printed = 0; + + stopped_by_random_signal = 1; + + if (stop_signal >= NSIG + || signal_print[stop_signal]) + { + char *signame; + printed = 1; + target_terminal_ours_for_output (); +#ifdef PRINT_RANDOM_SIGNAL + PRINT_RANDOM_SIGNAL (stop_signal); +#else + printf_filtered ("\nProgram received signal "); + signame = strsigno (stop_signal); + if (signame == NULL) + printf_filtered ("%d", stop_signal); + else + /* Do we need to print the number as well as the name? */ + printf_filtered ("%s (%d)", signame, stop_signal); + printf_filtered (", %s\n", safe_strsignal (stop_signal)); +#endif /* PRINT_RANDOM_SIGNAL */ + fflush (stdout); + } + if (stop_signal >= NSIG + || signal_stop[stop_signal]) + break; + /* If not going to stop, give terminal back + if we took it away. */ + else if (printed) + target_terminal_inferior (); + + /* Clear the signal if it should not be passed. */ + if (signal_program[stop_signal] == 0) + stop_signal = 0; + + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + goto check_sigtramp2; + } + + /* Handle cases caused by hitting a breakpoint. */ + { + CORE_ADDR jmp_buf_pc; + struct bpstat_what what; + + what = bpstat_what (stop_bpstat); + + if (what.call_dummy) + { + stop_stack_dummy = 1; +#ifdef HP_OS_BUG + trap_expected_after_continue = 1; +#endif + } + + switch (what.main_action) + { + case BPSTAT_WHAT_SET_LONGJMP_RESUME: + /* If we hit the breakpoint at longjmp, disable it for the + duration of this command. Then, install a temporary + breakpoint at the target of the jmp_buf. */ + disable_longjmp_breakpoint(); + remove_breakpoints (); + breakpoints_inserted = 0; + if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going; + + /* Need to blow away step-resume breakpoint, as it + interferes with us */ + if (step_resume_breakpoint != NULL) + { + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; + what.step_resume = 0; + } + +#if 0 + /* FIXME - Need to implement nested temporary breakpoints */ + if (step_over_calls > 0) + set_longjmp_resume_breakpoint(jmp_buf_pc, + get_current_frame()); + else +#endif /* 0 */ + set_longjmp_resume_breakpoint(jmp_buf_pc, NULL); + handling_longjmp = 1; /* FIXME */ + goto keep_going; + + case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: + case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE: + remove_breakpoints (); + breakpoints_inserted = 0; +#if 0 + /* FIXME - Need to implement nested temporary breakpoints */ + if (step_over_calls + && (stop_frame_address + INNER_THAN step_frame_address)) + { + another_trap = 1; + goto keep_going; + } +#endif /* 0 */ + disable_longjmp_breakpoint(); + handling_longjmp = 0; /* FIXME */ + if (what.main_action == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME) + break; + /* else fallthrough */ + + case BPSTAT_WHAT_SINGLE: + if (breakpoints_inserted) + remove_breakpoints (); + breakpoints_inserted = 0; + another_trap = 1; + /* Still need to check other stuff, at least the case + where we are stepping and step out of the right range. */ + break; + + case BPSTAT_WHAT_STOP_NOISY: + stop_print_frame = 1; + /* We are about to nuke the step_resume_breakpoint via the + cleanup chain, so no need to worry about it here. */ + goto stop_stepping; + + case BPSTAT_WHAT_STOP_SILENT: + stop_print_frame = 0; + /* We are about to nuke the step_resume_breakpoint via the + cleanup chain, so no need to worry about it here. */ + goto stop_stepping; + + case BPSTAT_WHAT_KEEP_CHECKING: + break; + } + + if (what.step_resume) + { + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; + + /* If were waiting for a trap, hitting the step_resume_break + doesn't count as getting it. */ + if (trap_expected) + another_trap = 1; + } + } + + /* We come here if we hit a breakpoint but should not + stop for it. Possibly we also were stepping + and should stop for that. So fall through and + test for stepping. But, if not stepping, + do not stop. */ + +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + /* This is the old way of detecting the end of the stack dummy. + An architecture which defines CALL_DUMMY_BREAKPOINT_OFFSET gets + handled above. As soon as we can test it on all of them, all + architectures should define it. */ + + /* If this is the breakpoint at the end of a stack dummy, + just stop silently, unless the user was doing an si/ni, in which + case she'd better know what she's doing. */ + + if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + && !step_range_end) + { + stop_print_frame = 0; + stop_stack_dummy = 1; +#ifdef HP_OS_BUG + trap_expected_after_continue = 1; +#endif + break; + } +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + + if (step_resume_breakpoint) + /* Having a step-resume breakpoint overrides anything + else having to do with stepping commands until + that breakpoint is reached. */ + /* I suspect this could/should be keep_going, because if the + check_sigtramp2 check succeeds, then it will put in another + step_resume_breakpoint, and we aren't (yet) prepared to nest + them. */ + goto check_sigtramp2; + + if (step_range_end == 0) + /* Likewise if we aren't even stepping. */ + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + goto check_sigtramp2; + + /* If stepping through a line, keep going if still within it. */ + if (stop_pc >= step_range_start + && stop_pc < step_range_end + /* The step range might include the start of the + function, so if we are at the start of the + step range and either the stack or frame pointers + just changed, we've stepped outside */ + && !(stop_pc == step_range_start + && stop_frame_address + && (stop_sp INNER_THAN prev_sp + || stop_frame_address != step_frame_address))) + { + /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal. + So definately need to check for sigtramp here. */ + goto check_sigtramp2; + } + + /* We stepped out of the stepping range. See if that was due + to a subroutine call that we should proceed to the end of. */ + + /* Did we just take a signal? */ + if (IN_SIGTRAMP (stop_pc, stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name)) + { + /* This code is needed at least in the following case: + The user types "next" and then a signal arrives (before + the "next" is done). */ + /* We've just taken a signal; go until we are back to + the point where we took it and one more. */ + { + struct symtab_and_line sr_sal; + + sr_sal.pc = prev_pc; + sr_sal.symtab = NULL; + sr_sal.line = 0; + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, get_current_frame (), + bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + } + + /* If this is stepi or nexti, make sure that the stepping range + gets us past that instruction. */ + if (step_range_end == 1) + /* FIXME: Does this run afoul of the code below which, if + we step into the middle of a line, resets the stepping + range? */ + step_range_end = (step_range_start = prev_pc) + 1; + + remove_breakpoints_on_following_step = 1; + goto keep_going; + } + + if (stop_func_start) + { + /* Do this after the IN_SIGTRAMP check; it might give + an error. */ + prologue_pc = stop_func_start; + SKIP_PROLOGUE (prologue_pc); + } + + if ((/* Might be a non-recursive call. If the symbols are missing + enough that stop_func_start == prev_func_start even though + they are really two functions, we will treat some calls as + jumps. */ + stop_func_start != prev_func_start + + /* Might be a recursive call if either we have a prologue + or the call instruction itself saves the PC on the stack. */ + || prologue_pc != stop_func_start + || stop_sp != prev_sp) + && (/* PC is completely out of bounds of any known objfiles. Treat + like a subroutine call. */ + !stop_func_start + + /* If we do a call, we will be at the start of a function. */ + || stop_pc == stop_func_start + +#if 0 + /* Not conservative enough for 4.11. FIXME: enable this + after 4.11. */ + /* Except on the Alpha with -O (and perhaps other machines + with similar calling conventions), in which we might + call the address after the load of gp. Since prologues + don't contain calls, we can't return to within one, and + we don't jump back into them, so this check is OK. */ + || stop_pc < prologue_pc +#endif + + /* If we end up in certain places, it means we did a subroutine + call. I'm not completely sure this is necessary now that we + have the above checks with stop_func_start (and now that + find_pc_partial_function is pickier). */ + || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name) + + /* If none of the above apply, it is a jump within a function, + or a return from a subroutine. The other case is longjmp, + which can no longer happen here as long as the + handling_longjmp stuff is working. */ + )) + { + /* It's a subroutine call. */ + + if (step_over_calls == 0) + { + /* I presume that step_over_calls is only 0 when we're + supposed to be stepping at the assembly language level + ("stepi"). Just stop. */ + stop_step = 1; + break; + } + + if (step_over_calls > 0) + /* We're doing a "next". */ + goto step_over_function; + + /* If we are in a function call trampoline (a stub between + the calling routine and the real function), locate the real + function. That's what tells us (a) whether we want to step + into it at all, and (b) what prologue we want to run to + the end of, if we do step into it. */ + tmp = SKIP_TRAMPOLINE_CODE (stop_pc); + if (tmp != 0) + stop_func_start = tmp; + + /* If we have line number information for the function we + are thinking of stepping into, step into it. + + If there are several symtabs at that PC (e.g. with include + files), just want to know whether *any* of them have line + numbers. find_pc_line handles this. */ + { + struct symtab_and_line tmp_sal; + + tmp_sal = find_pc_line (stop_func_start, 0); + if (tmp_sal.line != 0) + goto step_into_function; + } + +step_over_function: + /* A subroutine call has happened. */ + { + /* Set a special breakpoint after the return */ + struct symtab_and_line sr_sal; + sr_sal.pc = + ADDR_BITS_REMOVE + (SAVED_PC_AFTER_CALL (get_current_frame ())); + sr_sal.symtab = NULL; + sr_sal.line = 0; + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, get_current_frame (), + bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + } + goto keep_going; + +step_into_function: + /* Subroutine call with source code we should not step over. + Do step to the first line of code in it. */ + SKIP_PROLOGUE (stop_func_start); + sal = find_pc_line (stop_func_start, 0); + /* Use the step_resume_break to step until + the end of the prologue, even if that involves jumps + (as it seems to on the vax under 4.2). */ + /* If the prologue ends in the middle of a source line, + continue to the end of that source line. + Otherwise, just go to end of prologue. */ +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* no, don't either. It skips any code that's + legitimately on the first line. */ +#else + if (sal.end && sal.pc != stop_func_start) + stop_func_start = sal.end; +#endif + + if (stop_func_start == stop_pc) + { + /* We are already there: stop now. */ + stop_step = 1; + break; + } + else + /* Put the step-breakpoint there and go until there. */ + { + struct symtab_and_line sr_sal; + + sr_sal.pc = stop_func_start; + sr_sal.symtab = NULL; + sr_sal.line = 0; + /* Do not specify what the fp should be when we stop + since on some machines the prologue + is where the new fp value is established. */ + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + + /* And make sure stepping stops right away then. */ + step_range_end = step_range_start; + } + goto keep_going; + } + + /* We've wandered out of the step range (but haven't done a + subroutine call or return). (Is that true? I think we get + here if we did a return and maybe a longjmp). */ + + sal = find_pc_line(stop_pc, 0); + + if (step_range_end == 1) + { + /* It is stepi or nexti. We always want to stop stepping after + one instruction. */ + stop_step = 1; + break; + } + + if (sal.line == 0) + { + /* We have no line number information. That means to stop + stepping (does this always happen right after one instruction, + when we do "s" in a function with no line numbers, + or can this happen as a result of a return or longjmp?). */ + stop_step = 1; + break; + } + + if (stop_pc == sal.pc && current_line != sal.line) + { + /* We are at the start of a different line. So stop. Note that + we don't stop if we step into the middle of a different line. + That is said to make things like for (;;) statements work + better. */ + stop_step = 1; + break; + } + + /* We aren't done stepping. + + Optimize by setting the stepping range to the line. + (We might not be in the original line, but if we entered a + new line in mid-statement, we continue stepping. This makes + things like for(;;) statements work better.) */ + step_range_start = sal.pc; + step_range_end = sal.end; + goto keep_going; + + check_sigtramp2: + if (trap_expected + && IN_SIGTRAMP (stop_pc, stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name)) + { + /* What has happened here is that we have just stepped the inferior + with a signal (because it is a signal which shouldn't make + us stop), thus stepping into sigtramp. + + So we need to set a step_resume_break_address breakpoint + and continue until we hit it, and then step. FIXME: This should + be more enduring than a step_resume breakpoint; we should know + that we will later need to keep going rather than re-hitting + the breakpoint here (see testsuite/gdb.t06/signals.exp where + it says "exceedingly difficult"). */ + struct symtab_and_line sr_sal; + + sr_sal.pc = prev_pc; + sr_sal.symtab = NULL; + sr_sal.line = 0; + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, get_current_frame (), + bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + + remove_breakpoints_on_following_step = 1; + another_trap = 1; + } + + keep_going: + /* Come to this label when you need to resume the inferior. + It's really much cleaner to do a goto than a maze of if-else + conditions. */ + + /* Save the pc before execution, to compare with pc after stop. */ + prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */ + prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER + BREAK is defined, the + original pc would not have + been at the start of a + function. */ + + prev_func_name = stop_func_name; + prev_sp = stop_sp; + + /* If we did not do break;, it means we should keep + running the inferior and not return to debugger. */ + + if (trap_expected && stop_signal != SIGTRAP) + { + /* We took a signal (which we are supposed to pass through to + the inferior, else we'd have done a break above) and we + haven't yet gotten our trap. Simply continue. */ + resume (CURRENTLY_STEPPING (), stop_signal); + } + else + { + /* Either the trap was not expected, but we are continuing + anyway (the user asked that this signal be passed to the + child) + -- or -- + The signal was SIGTRAP, e.g. it was our signal, but we + decided we should resume from it. + + We're going to run this baby now! + + Insert breakpoints now, unless we are trying + to one-proceed past a breakpoint. */ + /* If we've just finished a special step resume and we don't + want to hit a breakpoint, pull em out. */ + if (step_resume_breakpoint == NULL && + remove_breakpoints_on_following_step) + { + remove_breakpoints_on_following_step = 0; + remove_breakpoints (); + breakpoints_inserted = 0; + } + else if (!breakpoints_inserted && + (step_resume_breakpoint != NULL || !another_trap)) + { + breakpoints_failed = insert_breakpoints (); + if (breakpoints_failed) + break; + breakpoints_inserted = 1; + } + + trap_expected = another_trap; + + if (stop_signal == SIGTRAP) + stop_signal = 0; + +#ifdef SHIFT_INST_REGS + /* I'm not sure when this following segment applies. I do know, now, + that we shouldn't rewrite the regs when we were stopped by a + random signal from the inferior process. */ + /* FIXME: Shouldn't this be based on the valid bit of the SXIP? + (this is only used on the 88k). */ + + if (!bpstat_explains_signal (stop_bpstat) + && (stop_signal != SIGCLD) + && !stopped_by_random_signal) + SHIFT_INST_REGS(); +#endif /* SHIFT_INST_REGS */ + + resume (CURRENTLY_STEPPING (), stop_signal); + } + } + + stop_stepping: + if (target_has_execution) + { + /* Assuming the inferior still exists, set these up for next + time, just like we did above if we didn't break out of the + loop. */ + prev_pc = read_pc (); + prev_func_start = stop_func_start; + prev_func_name = stop_func_name; + prev_sp = stop_sp; + } + do_cleanups (old_cleanups); +} + +/* Here to return control to GDB when the inferior stops for real. + Print appropriate messages, remove breakpoints, give terminal our modes. + + STOP_PRINT_FRAME nonzero means print the executing frame + (pc, function, args, file, line number and line text). + BREAKPOINTS_FAILED nonzero means stop was due to error + attempting to insert breakpoints. */ + +void +normal_stop () +{ + /* Make sure that the current_frame's pc is correct. This + is a correction for setting up the frame info before doing + DECR_PC_AFTER_BREAK */ + if (target_has_execution && get_current_frame()) + (get_current_frame ())->pc = read_pc (); + + if (breakpoints_failed) + { + target_terminal_ours_for_output (); + print_sys_errmsg ("ptrace", breakpoints_failed); + printf_filtered ("Stopped; cannot insert breakpoints.\n\ +The same program may be running in another process.\n"); + } + + if (target_has_execution && breakpoints_inserted) + if (remove_breakpoints ()) + { + target_terminal_ours_for_output (); + printf_filtered ("Cannot remove breakpoints because program is no longer writable.\n\ +It might be running in another process.\n\ +Further execution is probably impossible.\n"); + } + + breakpoints_inserted = 0; + + /* Delete the breakpoint we stopped at, if it wants to be deleted. + Delete any breakpoint that is to be deleted at the next stop. */ + + breakpoint_auto_delete (stop_bpstat); + + /* If an auto-display called a function and that got a signal, + delete that auto-display to avoid an infinite recursion. */ + + if (stopped_by_random_signal) + disable_current_display (); + + if (step_multi && stop_step) + return; + + target_terminal_ours (); + + /* Look up the hook_stop and run it if it exists. */ + + if (stop_command->hook) + { + catch_errors (hook_stop_stub, (char *)stop_command->hook, + "Error while running hook_stop:\n", RETURN_MASK_ALL); + } + + if (!target_has_stack) + return; + + /* Select innermost stack frame except on return from a stack dummy routine, + or if the program has exited. Print it without a level number if + we have changed functions or hit a breakpoint. Print source line + if we have one. */ + if (!stop_stack_dummy) + { + select_frame (get_current_frame (), 0); + + if (stop_print_frame) + { + int source_only; + + source_only = bpstat_print (stop_bpstat); + source_only = source_only || + ( stop_step + && step_frame_address == stop_frame_address + && step_start_function == find_pc_function (stop_pc)); + + print_stack_frame (selected_frame, -1, source_only? -1: 1); + + /* Display the auto-display expressions. */ + do_displays (); + } + } + + /* Save the function value return registers, if we care. + We might be about to restore their previous contents. */ + if (proceed_to_finish) + read_register_bytes (0, stop_registers, REGISTER_BYTES); + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. + POP_FRAME ends with a setting of the current frame, so we + can use that next. */ + POP_FRAME; + select_frame (get_current_frame (), 0); + } +} + +static int +hook_stop_stub (cmd) + char *cmd; +{ + execute_user_command ((struct cmd_list_element *)cmd, 0); + return (0); +} + +int signal_stop_state (signo) + int signo; +{ + return ((signo >= 0 && signo < NSIG) ? signal_stop[signo] : 0); +} + +int signal_print_state (signo) + int signo; +{ + return ((signo >= 0 && signo < NSIG) ? signal_print[signo] : 0); +} + +int signal_pass_state (signo) + int signo; +{ + return ((signo >= 0 && signo < NSIG) ? signal_program[signo] : 0); +} + +static void +sig_print_header () +{ + printf_filtered ("Signal\t\tStop\tPrint\tPass to program\tDescription\n"); +} + +static void +sig_print_info (number) + int number; +{ + char *name; + + if ((name = strsigno (number)) == NULL) + printf_filtered ("%d\t\t", number); + else + printf_filtered ("%s (%d)\t", name, number); + printf_filtered ("%s\t", signal_stop[number] ? "Yes" : "No"); + printf_filtered ("%s\t", signal_print[number] ? "Yes" : "No"); + printf_filtered ("%s\t\t", signal_program[number] ? "Yes" : "No"); + printf_filtered ("%s\n", safe_strsignal (number)); +} + +/* Specify how various signals in the inferior should be handled. */ + +static void +handle_command (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + int digits, wordlen; + int sigfirst, signum, siglast; + int allsigs; + int nsigs; + unsigned char *sigs; + struct cleanup *old_chain; + + if (args == NULL) + { + error_no_arg ("signal to handle"); + } + + /* Allocate and zero an array of flags for which signals to handle. */ + + nsigs = signo_max () + 1; + sigs = (unsigned char *) alloca (nsigs); + memset (sigs, 0, nsigs); + + /* Break the command line up into args. */ + + argv = buildargv (args); + if (argv == NULL) + { + nomem (0); + } + old_chain = make_cleanup (freeargv, (char *) argv); + + /* Walk through the args, looking for signal numbers, signal names, and + actions. Signal numbers and signal names may be interspersed with + actions, with the actions being performed for all signals cumulatively + specified. Signal ranges can be specified as -. */ + + while (*argv != NULL) + { + wordlen = strlen (*argv); + for (digits = 0; isdigit ((*argv)[digits]); digits++) {;} + allsigs = 0; + sigfirst = siglast = -1; + + if (wordlen >= 1 && !strncmp (*argv, "all", wordlen)) + { + /* Apply action to all signals except those used by the + debugger. Silently skip those. */ + allsigs = 1; + sigfirst = 0; + siglast = nsigs - 1; + } + else if (wordlen >= 1 && !strncmp (*argv, "stop", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_stop); + SET_SIGS (nsigs, sigs, signal_print); + } + else if (wordlen >= 1 && !strncmp (*argv, "ignore", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_program); + } + else if (wordlen >= 2 && !strncmp (*argv, "print", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_print); + } + else if (wordlen >= 2 && !strncmp (*argv, "pass", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_program); + } + else if (wordlen >= 3 && !strncmp (*argv, "nostop", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_stop); + } + else if (wordlen >= 3 && !strncmp (*argv, "noignore", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_program); + } + else if (wordlen >= 4 && !strncmp (*argv, "noprint", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_print); + UNSET_SIGS (nsigs, sigs, signal_stop); + } + else if (wordlen >= 4 && !strncmp (*argv, "nopass", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_program); + } + else if (digits > 0) + { + sigfirst = siglast = atoi (*argv); + if ((*argv)[digits] == '-') + { + siglast = atoi ((*argv) + digits + 1); + } + if (sigfirst > siglast) + { + /* Bet he didn't figure we'd think of this case... */ + signum = sigfirst; + sigfirst = siglast; + siglast = signum; + } + if (sigfirst < 0 || sigfirst >= nsigs) + { + error ("Signal %d not in range 0-%d", sigfirst, nsigs - 1); + } + if (siglast < 0 || siglast >= nsigs) + { + error ("Signal %d not in range 0-%d", siglast, nsigs - 1); + } + } + else if ((signum = strtosigno (*argv)) != 0) + { + sigfirst = siglast = signum; + } + else + { + /* Not a number and not a recognized flag word => complain. */ + error ("Unrecognized or ambiguous flag word: \"%s\".", *argv); + } + + /* If any signal numbers or symbol names were found, set flags for + which signals to apply actions to. */ + + for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++) + { + switch (signum) + { + case SIGTRAP: + case SIGINT: + if (!allsigs && !sigs[signum]) + { + if (query ("%s is used by the debugger.\nAre you sure you want to change it? ", strsigno (signum))) + { + sigs[signum] = 1; + } + else + { + printf ("Not confirmed, unchanged.\n"); + fflush (stdout); + } + } + break; + default: + sigs[signum] = 1; + break; + } + } + + argv++; + } + + target_notice_signals(inferior_pid); + + if (from_tty) + { + /* Show the results. */ + sig_print_header (); + for (signum = 0; signum < nsigs; signum++) + { + if (sigs[signum]) + { + sig_print_info (signum); + } + } + } + + do_cleanups (old_chain); +} + +/* Print current contents of the tables set by the handle command. */ + +static void +signals_info (signum_exp, from_tty) + char *signum_exp; + int from_tty; +{ + register int i; + sig_print_header (); + + if (signum_exp) + { + /* First see if this is a symbol name. */ + i = strtosigno (signum_exp); + if (i == 0) + { + /* Nope, maybe it's an address which evaluates to a signal + number. */ + i = parse_and_eval_address (signum_exp); + if (i >= NSIG || i < 0) + error ("Signal number out of bounds."); + } + sig_print_info (i); + return; + } + + printf_filtered ("\n"); + for (i = 0; i < NSIG; i++) + { + QUIT; + + sig_print_info (i); + } + + printf_filtered ("\nUse the \"handle\" command to change these tables.\n"); +} + +/* Save all of the information associated with the inferior<==>gdb + connection. INF_STATUS is a pointer to a "struct inferior_status" + (defined in inferior.h). */ + +void +save_inferior_status (inf_status, restore_stack_info) + struct inferior_status *inf_status; + int restore_stack_info; +{ + inf_status->stop_signal = stop_signal; + inf_status->stop_pc = stop_pc; + inf_status->stop_frame_address = stop_frame_address; + inf_status->stop_step = stop_step; + inf_status->stop_stack_dummy = stop_stack_dummy; + inf_status->stopped_by_random_signal = stopped_by_random_signal; + inf_status->trap_expected = trap_expected; + inf_status->step_range_start = step_range_start; + inf_status->step_range_end = step_range_end; + inf_status->step_frame_address = step_frame_address; + inf_status->step_over_calls = step_over_calls; + inf_status->stop_after_trap = stop_after_trap; + inf_status->stop_soon_quietly = stop_soon_quietly; + /* Save original bpstat chain here; replace it with copy of chain. + If caller's caller is walking the chain, they'll be happier if we + hand them back the original chain when restore_i_s is called. */ + inf_status->stop_bpstat = stop_bpstat; + stop_bpstat = bpstat_copy (stop_bpstat); + inf_status->breakpoint_proceeded = breakpoint_proceeded; + inf_status->restore_stack_info = restore_stack_info; + inf_status->proceed_to_finish = proceed_to_finish; + + memcpy (inf_status->stop_registers, stop_registers, REGISTER_BYTES); + + read_register_bytes (0, inf_status->registers, REGISTER_BYTES); + + record_selected_frame (&(inf_status->selected_frame_address), + &(inf_status->selected_level)); + return; +} + +struct restore_selected_frame_args { + FRAME_ADDR frame_address; + int level; +}; + +static int restore_selected_frame PARAMS ((char *)); + +/* Restore the selected frame. args is really a struct + restore_selected_frame_args * (declared as char * for catch_errors) + telling us what frame to restore. Returns 1 for success, or 0 for + failure. An error message will have been printed on error. */ +static int +restore_selected_frame (args) + char *args; +{ + struct restore_selected_frame_args *fr = + (struct restore_selected_frame_args *) args; + FRAME fid; + int level = fr->level; + + fid = find_relative_frame (get_current_frame (), &level); + + /* If inf_status->selected_frame_address is NULL, there was no + previously selected frame. */ + if (fid == 0 || + FRAME_FP (fid) != fr->frame_address || + level != 0) + { + warning ("Unable to restore previously selected frame.\n"); + return 0; + } + select_frame (fid, fr->level); + return(1); +} + +void +restore_inferior_status (inf_status) + struct inferior_status *inf_status; +{ + stop_signal = inf_status->stop_signal; + stop_pc = inf_status->stop_pc; + stop_frame_address = inf_status->stop_frame_address; + stop_step = inf_status->stop_step; + stop_stack_dummy = inf_status->stop_stack_dummy; + stopped_by_random_signal = inf_status->stopped_by_random_signal; + trap_expected = inf_status->trap_expected; + step_range_start = inf_status->step_range_start; + step_range_end = inf_status->step_range_end; + step_frame_address = inf_status->step_frame_address; + step_over_calls = inf_status->step_over_calls; + stop_after_trap = inf_status->stop_after_trap; + stop_soon_quietly = inf_status->stop_soon_quietly; + bpstat_clear (&stop_bpstat); + stop_bpstat = inf_status->stop_bpstat; + breakpoint_proceeded = inf_status->breakpoint_proceeded; + proceed_to_finish = inf_status->proceed_to_finish; + + memcpy (stop_registers, inf_status->stop_registers, REGISTER_BYTES); + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + if (target_has_execution) + write_register_bytes (0, inf_status->registers, REGISTER_BYTES); + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + + /* FIXME: If we are being called after stopping in a function which + is called from gdb, we should not be trying to restore the + selected frame; it just prints a spurious error message (The + message is useful, however, in detecting bugs in gdb (like if gdb + clobbers the stack)). In fact, should we be restoring the + inferior status at all in that case? . */ + + if (target_has_stack && inf_status->restore_stack_info) + { + struct restore_selected_frame_args fr; + fr.level = inf_status->selected_level; + fr.frame_address = inf_status->selected_frame_address; + /* The point of catch_errors is that if the stack is clobbered, + walking the stack might encounter a garbage pointer and error() + trying to dereference it. */ + if (catch_errors (restore_selected_frame, &fr, + "Unable to restore previously selected frame:\n", + RETURN_MASK_ERROR) == 0) + /* Error in restoring the selected frame. Select the innermost + frame. */ + select_frame (get_current_frame (), 0); + } +} + + +void +_initialize_infrun () +{ + register int i; + register int numsigs; + + add_info ("signals", signals_info, + "What debugger does when program gets various signals.\n\ +Specify a signal number as argument to print info on that signal only."); + add_info_alias ("handle", "signals", 0); + + add_com ("handle", class_run, handle_command, + "Specify how to handle a signal.\n\ +Args are signal numbers and actions to apply to those signals.\n\ +Signal numbers may be numeric (ex. 11) or symbolic (ex. SIGSEGV).\n\ +Numeric ranges may be specified with the form LOW-HIGH (ex. 14-21).\n\ +The special arg \"all\" is recognized to mean all signals except those\n\ +used by the debugger, typically SIGTRAP and SIGINT.\n\ +Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\ +\"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\ +Stop means reenter debugger if this signal happens (implies print).\n\ +Print means print a message if this signal happens.\n\ +Pass means let program see this signal; otherwise program doesn't know.\n\ +Ignore is a synonym for nopass and noignore is a synonym for pass.\n\ +Pass and Stop may be combined."); + + stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command, + "There is no `stop' command, but you can set a hook on `stop'.\n\ +This allows you to set a list of commands to be run each time execution\n\ +of the program stops.", &cmdlist); + + numsigs = signo_max () + 1; + signal_stop = (unsigned char *) + xmalloc (sizeof (signal_stop[0]) * numsigs); + signal_print = (unsigned char *) + xmalloc (sizeof (signal_print[0]) * numsigs); + signal_program = (unsigned char *) + xmalloc (sizeof (signal_program[0]) * numsigs); + for (i = 0; i < numsigs; i++) + { + signal_stop[i] = 1; + signal_print[i] = 1; + signal_program[i] = 1; + } + + /* Signals caused by debugger's own actions + should not be given to the program afterwards. */ + signal_program[SIGTRAP] = 0; + signal_program[SIGINT] = 0; + + /* Signals that are not errors should not normally enter the debugger. */ +#ifdef SIGALRM + signal_stop[SIGALRM] = 0; + signal_print[SIGALRM] = 0; +#endif /* SIGALRM */ +#ifdef SIGVTALRM + signal_stop[SIGVTALRM] = 0; + signal_print[SIGVTALRM] = 0; +#endif /* SIGVTALRM */ +#ifdef SIGPROF + signal_stop[SIGPROF] = 0; + signal_print[SIGPROF] = 0; +#endif /* SIGPROF */ +#ifdef SIGCHLD + signal_stop[SIGCHLD] = 0; + signal_print[SIGCHLD] = 0; +#endif /* SIGCHLD */ +#ifdef SIGCLD + signal_stop[SIGCLD] = 0; + signal_print[SIGCLD] = 0; +#endif /* SIGCLD */ +#ifdef SIGIO + signal_stop[SIGIO] = 0; + signal_print[SIGIO] = 0; +#endif /* SIGIO */ +#ifdef SIGURG + signal_stop[SIGURG] = 0; + signal_print[SIGURG] = 0; +#endif /* SIGURG */ +} diff --git a/gnu/usr.bin/gdb/gdb/inftarg.c b/gnu/usr.bin/gdb/gdb/inftarg.c new file mode 100644 index 00000000000..f937be4ea6e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/inftarg.c @@ -0,0 +1,310 @@ +/* Target-vector operations for controlling Unix child processes, for GDB. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +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. */ + +#include "defs.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "gdbcore.h" + +#include + +static void +child_prepare_to_store PARAMS ((void)); + +#ifndef CHILD_WAIT +static int +child_wait PARAMS ((int, int *)); +#endif /* CHILD_WAIT */ + +static void +child_open PARAMS ((char *, int)); + +static void +child_files_info PARAMS ((struct target_ops *)); + +static void +child_detach PARAMS ((char *, int)); + +static void +child_attach PARAMS ((char *, int)); + +static void +ptrace_me PARAMS ((void)); + +static void +ptrace_him PARAMS ((int)); + +static void +child_create_inferior PARAMS ((char *, char *, char **)); + +static void +child_mourn_inferior PARAMS ((void)); + +static int +child_can_run PARAMS ((void)); + +extern char **environ; + +/* Forward declaration */ +extern struct target_ops child_ops; + +#ifndef CHILD_WAIT + +/* Wait for child to do something. Return pid of child, or -1 in case + of error; store status through argument pointer STATUS. */ + +static int +child_wait (pid, status) + int pid; + int *status; +{ + int save_errno; + + do { + if (attach_flag) + set_sigint_trap(); /* Causes SIGINT to be passed on to the + attached process. */ + pid = wait (status); + save_errno = errno; + + if (attach_flag) + clear_sigint_trap(); + + if (pid == -1) + { + if (save_errno == EINTR) + continue; + fprintf (stderr, "Child process unexpectedly missing: %s.\n", + safe_strerror (save_errno)); + *status = 42; /* Claim it exited with signal 42 */ + return -1; + } + } while (pid != inferior_pid); /* Some other child died or stopped */ + return pid; +} +#endif /* CHILD_WAIT */ + +/* Attach to process PID, then initialize for debugging it. */ + +static void +child_attach (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + + if (!args) + error_no_arg ("process-id to attach"); + +#ifndef ATTACH_DETACH + error ("Can't attach to a process on this machine."); +#else + pid = atoi (args); + + if (pid == getpid()) /* Trying to masturbate? */ + error ("I refuse to debug myself!"); + + if (from_tty) + { + exec_file = (char *) get_exec_file (0); + + if (exec_file) + printf ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid)); + else + printf ("Attaching to %s\n", target_pid_to_str (pid)); + + fflush (stdout); + } + + attach (pid); + inferior_pid = pid; + push_target (&child_ops); +#endif /* ATTACH_DETACH */ +} + + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +child_detach (args, from_tty) + char *args; + int from_tty; +{ + int siggnal = 0; + +#ifdef ATTACH_DETACH + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == 0) + exec_file = ""; + printf ("Detaching from program: %s %s\n", exec_file, + target_pid_to_str (inferior_pid)); + fflush (stdout); + } + if (args) + siggnal = atoi (args); + + detach (siggnal); + inferior_pid = 0; + unpush_target (&child_ops); /* Pop out of handling an inferior */ +#else + error ("This version of Unix does not support detaching a process."); +#endif +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +child_prepare_to_store () +{ +#ifdef CHILD_PREPARE_TO_STORE + CHILD_PREPARE_TO_STORE (); +#endif +} + +/* Print status information about what we're accessing. */ + +static void +child_files_info (ignore) + struct target_ops *ignore; +{ + printf ("\tUsing the running image of %s %s.\n", + attach_flag? "attached": "child", target_pid_to_str (inferior_pid)); +} + +/* ARGSUSED */ +static void +child_open (arg, from_tty) + char *arg; + int from_tty; +{ + error ("Use the \"run\" command to start a Unix child process."); +} + +/* Stub function which causes the inferior that runs it, to be ptrace-able + by its parent process. */ + +static void +ptrace_me () +{ + /* "Trace me, Dr. Memory!" */ + call_ptrace (0, 0, (PTRACE_ARG3_TYPE) 0, 0); +} + +/* Stub function which causes the GDB that runs it, to start ptrace-ing + the child process. */ + +static void +ptrace_him (pid) + int pid; +{ + push_target (&child_ops); +} + +/* Start an inferior Unix child process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). */ + +static void +child_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him); + /* We are at the first instruction we care about. */ + /* Pedal to the metal... */ + proceed ((CORE_ADDR) -1, 0, 0); +} + +static void +child_mourn_inferior () +{ + unpush_target (&child_ops); + generic_mourn_inferior (); +} + +static int +child_can_run () +{ + return(1); +} + +struct target_ops child_ops = { + "child", /* to_shortname */ + "Unix child process", /* to_longname */ + "Unix child process (started by the \"run\" command).", /* to_doc */ + child_open, /* to_open */ + 0, /* to_close */ + child_attach, /* to_attach */ + child_detach, /* to_detach */ + child_resume, /* to_resume */ + child_wait, /* to_wait */ + fetch_inferior_registers, /* to_fetch_registers */ + store_inferior_registers, /* to_store_registers */ + child_prepare_to_store, /* to_prepare_to_store */ + child_xfer_memory, /* to_xfer_memory */ + child_files_info, /* to_files_info */ + memory_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + terminal_init_inferior, /* to_terminal_init */ + terminal_inferior, /* to_terminal_inferior */ + terminal_ours_for_output, /* to_terminal_ours_for_output */ + terminal_ours, /* to_terminal_ours */ + child_terminal_info, /* to_terminal_info */ + kill_inferior, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + child_create_inferior, /* to_create_inferior */ + child_mourn_inferior, /* to_mourn_inferior */ + child_can_run, /* to_can_run */ + 0, /* to_notice_signals */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_inftarg () +{ + add_target (&child_ops); +} diff --git a/gnu/usr.bin/gdb/gdb/init.c b/gnu/usr.bin/gdb/gdb/init.c new file mode 100644 index 00000000000..26afe1d761e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/init.c @@ -0,0 +1,47 @@ +/* Do not modify this file. It is created automatically by "munch". */ +void initialize_all_files () { + {extern void _initialize_blockframe (); _initialize_blockframe ();} + {extern void _initialize_breakpoint (); _initialize_breakpoint ();} + {extern void _initialize_buildsym (); _initialize_buildsym ();} + {extern void _initialize_c_language (); _initialize_c_language ();} + {extern void _initialize_chill_language (); _initialize_chill_language ();} + {extern void _initialize_coffread (); _initialize_coffread ();} + {extern void _initialize_command (); _initialize_command ();} + {extern void _initialize_complaints (); _initialize_complaints ();} + {extern void _initialize_copying (); _initialize_copying ();} + {extern void _initialize_core (); _initialize_core ();} + {extern void _initialize_corelow (); _initialize_corelow ();} + {extern void _initialize_cp_valprint (); _initialize_cp_valprint ();} + {extern void _initialize_dbxread (); _initialize_dbxread ();} + {extern void _initialize_demangler (); _initialize_demangler ();} + {extern void _initialize_elfread (); _initialize_elfread ();} + {extern void _initialize_exec (); _initialize_exec ();} + {extern void _initialize_gdbtypes (); _initialize_gdbtypes ();} + {extern void _initialize_infcmd (); _initialize_infcmd ();} + {extern void _initialize_inflow (); _initialize_inflow ();} + {extern void _initialize_infrun (); _initialize_infrun ();} + {extern void _initialize_inftarg (); _initialize_inftarg ();} + {extern void _initialize_language (); _initialize_language ();} + {extern void _initialize_m2_language (); _initialize_m2_language ();} + {extern void _initialize_maint_cmds (); _initialize_maint_cmds ();} + {extern void _initialize_mipsread (); _initialize_mipsread ();} + {extern void _initialize_nlmread (); _initialize_nlmread ();} + {extern void _initialize_parse (); _initialize_parse ();} + {extern void _initialize_printcmd (); _initialize_printcmd ();} + {extern void _initialize_remote (); _initialize_remote ();} + {extern void _initialize_ser_hardwire (); _initialize_ser_hardwire ();} + {extern void _initialize_solib (); _initialize_solib ();} + {extern void _initialize_source (); _initialize_source ();} + {extern void _initialize_sr_support (); _initialize_sr_support ();} + {extern void _initialize_stabsread (); _initialize_stabsread ();} + {extern void _initialize_stack (); _initialize_stack ();} + {extern void _initialize_symfile (); _initialize_symfile ();} + {extern void _initialize_symmisc (); _initialize_symmisc ();} + {extern void _initialize_symtab (); _initialize_symtab ();} + {extern void _initialize_targets (); _initialize_targets ();} + {extern void _initialize_thread (); _initialize_thread ();} + {extern void _initialize_typeprint (); _initialize_typeprint ();} + {extern void _initialize_utils (); _initialize_utils ();} + {extern void _initialize_valprint (); _initialize_valprint ();} + {extern void _initialize_values (); _initialize_values ();} +} diff --git a/gnu/usr.bin/gdb/gdb/language.c b/gnu/usr.bin/gdb/gdb/language.c new file mode 100644 index 00000000000..be519532caf --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/language.c @@ -0,0 +1,1332 @@ +/* Multiple source language support for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + Contributed by the Department of Computer Science at the State University + of New York at Buffalo. + +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. */ + +/* This file contains functions that return things that are specific + to languages. Each function should examine current_language if necessary, + and return the appropriate result. */ + +/* FIXME: Most of these would be better organized as macros which + return data out of a "language-specific" struct pointer that is set + whenever the working language changes. That would be a lot faster. */ + +#include "defs.h" +#include +#include + +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "gdbcmd.h" +#include "frame.h" +#include "expression.h" +#include "language.h" +#include "target.h" +#include "parser-defs.h" + +static void +show_language_command PARAMS ((char *, int)); + +static void +set_language_command PARAMS ((char *, int)); + +static void +show_type_command PARAMS ((char *, int)); + +static void +set_type_command PARAMS ((char *, int)); + +static void +show_range_command PARAMS ((char *, int)); + +static void +set_range_command PARAMS ((char *, int)); + +static void +set_range_str PARAMS ((void)); + +static void +set_type_str PARAMS ((void)); + +static void +set_lang_str PARAMS ((void)); + +static void +unk_lang_error PARAMS ((char *)); + +static int +unk_lang_parser PARAMS ((void)); + +static void +show_check PARAMS ((char *, int)); + +static void +set_check PARAMS ((char *, int)); + +static void +set_type_range PARAMS ((void)); + +/* Forward declaration */ +extern const struct language_defn unknown_language_defn; +extern char *warning_pre_print; + +/* The current (default at startup) state of type and range checking. + (If the modes are set to "auto", though, these are changed based + on the default language at startup, and then again based on the + language of the first source file. */ + +enum range_mode range_mode = range_mode_auto; +enum range_check range_check = range_check_off; +enum type_mode type_mode = type_mode_auto; +enum type_check type_check = type_check_off; + +/* The current language and language_mode (see language.h) */ + +const struct language_defn *current_language = &unknown_language_defn; +enum language_mode language_mode = language_mode_auto; + +/* The language that the user expects to be typing in (the language + of main(), or the last language we notified them about, or C). */ + +const struct language_defn *expected_language; + +/* The list of supported languages. The list itself is malloc'd. */ + +static const struct language_defn **languages; +static unsigned languages_size; +static unsigned languages_allocsize; +#define DEFAULT_ALLOCSIZE 4 + +/* The "set language/type/range" commands all put stuff in these + buffers. This is to make them work as set/show commands. The + user's string is copied here, then the set_* commands look at + them and update them to something that looks nice when it is + printed out. */ + +static char *language; +static char *type; +static char *range; + +/* Warning issued when current_language and the language of the current + frame do not match. */ +char lang_frame_mismatch_warn[] = + "Warning: the current language does not match this frame."; + + +/* This page contains the functions corresponding to GDB commands + and their helpers. */ + +/* Show command. Display a warning if the language set + does not match the frame. */ +static void +show_language_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + enum language flang; /* The language of the current frame */ + + flang = get_frame_language(); + if (flang != language_unknown && + language_mode == language_mode_manual && + current_language->la_language != flang) + printf_filtered("%s\n",lang_frame_mismatch_warn); +} + +/* Set command. Change the current working language. */ +static void +set_language_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + int i; + enum language flang; + char *err_lang; + + /* FIXME -- do this from the list, with HELP. */ + if (!language || !language[0]) { + printf("The currently understood settings are:\n\n"); + printf ("local or auto Automatic setting based on source file\n"); + printf ("c Use the C language\n"); + printf ("c++ Use the C++ language\n"); + printf ("chill Use the Chill language\n"); + printf ("modula-2 Use the Modula-2 language\n"); + /* Restore the silly string. */ + set_language(current_language->la_language); + return; + } + + /* Search the list of languages for a match. */ + for (i = 0; i < languages_size; i++) { + if (STREQ (languages[i]->la_name, language)) { + /* Found it! Go into manual mode, and use this language. */ + if (languages[i]->la_language == language_auto) { + /* Enter auto mode. Set to the current frame's language, if known. */ + language_mode = language_mode_auto; + flang = get_frame_language(); + if (flang!=language_unknown) + set_language(flang); + expected_language = current_language; + return; + } else { + /* Enter manual mode. Set the specified language. */ + language_mode = language_mode_manual; + current_language = languages[i]; + set_type_range (); + set_lang_str(); + expected_language = current_language; + return; + } + } + } + + /* Reset the language (esp. the global string "language") to the + correct values. */ + err_lang=savestring(language,strlen(language)); + make_cleanup (free, err_lang); /* Free it after error */ + set_language(current_language->la_language); + error ("Unknown language `%s'.",err_lang); +} + +/* Show command. Display a warning if the type setting does + not match the current language. */ +static void +show_type_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + if (type_check != current_language->la_type_check) + printf( +"Warning: the current type check setting does not match the language.\n"); +} + +/* Set command. Change the setting for type checking. */ +static void +set_type_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + if (STREQ(type,"on")) + { + type_check = type_check_on; + type_mode = type_mode_manual; + } + else if (STREQ(type,"warn")) + { + type_check = type_check_warn; + type_mode = type_mode_manual; + } + else if (STREQ(type,"off")) + { + type_check = type_check_off; + type_mode = type_mode_manual; + } + else if (STREQ(type,"auto")) + { + type_mode = type_mode_auto; + set_type_range(); + /* Avoid hitting the set_type_str call below. We + did it in set_type_range. */ + return; + } + set_type_str(); + show_type_command((char *)NULL, from_tty); +} + +/* Show command. Display a warning if the range setting does + not match the current language. */ +static void +show_range_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + + if (range_check != current_language->la_range_check) + printf( +"Warning: the current range check setting does not match the language.\n"); +} + +/* Set command. Change the setting for range checking. */ +static void +set_range_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + if (STREQ(range,"on")) + { + range_check = range_check_on; + range_mode = range_mode_manual; + } + else if (STREQ(range,"warn")) + { + range_check = range_check_warn; + range_mode = range_mode_manual; + } + else if (STREQ(range,"off")) + { + range_check = range_check_off; + range_mode = range_mode_manual; + } + else if (STREQ(range,"auto")) + { + range_mode = range_mode_auto; + set_type_range(); + /* Avoid hitting the set_range_str call below. We + did it in set_type_range. */ + return; + } + set_range_str(); + show_range_command((char *)0, from_tty); +} + +/* Set the status of range and type checking based on + the current modes and the current language. + If SHOW is non-zero, then print out the current language, + type and range checking status. */ +static void +set_type_range() +{ + + if (range_mode == range_mode_auto) + range_check = current_language->la_range_check; + + if (type_mode == type_mode_auto) + type_check = current_language->la_type_check; + + set_type_str(); + set_range_str(); +} + +/* Set current language to (enum language) LANG. */ + +void +set_language(lang) + enum language lang; +{ + int i; + + for (i = 0; i < languages_size; i++) { + if (languages[i]->la_language == lang) { + current_language = languages[i]; + set_type_range (); + set_lang_str(); + break; + } + } +} + +/* This page contains functions that update the global vars + language, type and range. */ +static void +set_lang_str() +{ + char *prefix = ""; + + free (language); + if (language_mode == language_mode_auto) + prefix = "auto; currently "; + + language = concat(prefix, current_language->la_name, NULL); +} + +static void +set_type_str() +{ + char *tmp, *prefix = ""; + + free (type); + if (type_mode==type_mode_auto) + prefix = "auto; currently "; + + switch(type_check) + { + case type_check_on: + tmp = "on"; + break; + case type_check_off: + tmp = "off"; + break; + case type_check_warn: + tmp = "warn"; + break; + default: + error ("Unrecognized type check setting."); + } + + type = concat(prefix,tmp,NULL); +} + +static void +set_range_str() +{ + char *tmp, *pref = ""; + + free (range); + if (range_mode==range_mode_auto) + pref = "auto; currently "; + + switch(range_check) + { + case range_check_on: + tmp = "on"; + break; + case range_check_off: + tmp = "off"; + break; + case range_check_warn: + tmp = "warn"; + break; + default: + error ("Unrecognized range check setting."); + } + + range = concat(pref,tmp,NULL); +} + + +/* Print out the current language settings: language, range and + type checking. If QUIETLY, print only what has changed. */ + +void +language_info (quietly) + int quietly; +{ + if (quietly && expected_language == current_language) + return; + + expected_language = current_language; + printf("Current language: %s\n",language); + show_language_command((char *)0, 1); + + if (!quietly) + { + printf("Type checking: %s\n",type); + show_type_command((char *)0, 1); + printf("Range checking: %s\n",range); + show_range_command((char *)0, 1); + } +} + +/* Return the result of a binary operation. */ + +#if 0 /* Currently unused */ + +struct type * +binop_result_type(v1,v2) + value v1,v2; +{ + int l1,l2,size,uns; + + l1 = TYPE_LENGTH(VALUE_TYPE(v1)); + l2 = TYPE_LENGTH(VALUE_TYPE(v2)); + + switch(current_language->la_language) + { + case language_c: + case language_cplus: + if (TYPE_CODE(VALUE_TYPE(v1))==TYPE_CODE_FLT) + return TYPE_CODE(VALUE_TYPE(v2)) == TYPE_CODE_FLT && l2 > l1 ? + VALUE_TYPE(v2) : VALUE_TYPE(v1); + else if (TYPE_CODE(VALUE_TYPE(v2))==TYPE_CODE_FLT) + return TYPE_CODE(VALUE_TYPE(v1)) == TYPE_CODE_FLT && l1 > l2 ? + VALUE_TYPE(v1) : VALUE_TYPE(v2); + else if (TYPE_UNSIGNED(VALUE_TYPE(v1)) && l1 > l2) + return VALUE_TYPE(v1); + else if (TYPE_UNSIGNED(VALUE_TYPE(v2)) && l2 > l1) + return VALUE_TYPE(v2); + else /* Both are signed. Result is the longer type */ + return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2); + break; + case language_m2: + /* If we are doing type-checking, l1 should equal l2, so this is + not needed. */ + return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2); + break; + case language_chill: + error ("Missing Chill support in function binop_result_check.");/*FIXME*/ + } + abort(); + return (struct type *)0; /* For lint */ +} + +#endif /* 0 */ + + +/* This page contains functions that return format strings for + printf for printing out numbers in different formats */ + +/* Returns the appropriate printf format for hexadecimal + numbers. */ +char * +local_hex_format_custom(pre) + char *pre; +{ + static char form[50]; + + strcpy (form, local_hex_format_prefix ()); + strcat (form, "%"); + strcat (form, pre); + strcat (form, local_hex_format_specifier ()); + strcat (form, local_hex_format_suffix ()); + return form; +} + +/* Converts a number to hexadecimal and stores it in a static + string. Returns a pointer to this string. */ +char * +local_hex_string (num) + unsigned long num; +{ + static char res[50]; + + sprintf (res, local_hex_format(), num); + return res; +} + +/* Converts a number to custom hexadecimal and stores it in a static + string. Returns a pointer to this string. */ +char * +local_hex_string_custom(num,pre) + unsigned long num; + char *pre; +{ + static char res[50]; + + sprintf (res, local_hex_format_custom(pre), num); + return res; +} + +/* Returns the appropriate printf format for octal + numbers. */ +char * +local_octal_format_custom(pre) + char *pre; +{ + static char form[50]; + + strcpy (form, local_octal_format_prefix ()); + strcat (form, "%"); + strcat (form, pre); + strcat (form, local_octal_format_specifier ()); + strcat (form, local_octal_format_suffix ()); + return form; +} + +/* Returns the appropriate printf format for decimal numbers. */ +char * +local_decimal_format_custom(pre) + char *pre; +{ + static char form[50]; + + strcpy (form, local_decimal_format_prefix ()); + strcat (form, "%"); + strcat (form, pre); + strcat (form, local_decimal_format_specifier ()); + strcat (form, local_decimal_format_suffix ()); + return form; +} + +/* This page contains functions that are used in type/range checking. + They all return zero if the type/range check fails. + + It is hoped that these will make extending GDB to parse different + languages a little easier. These are primarily used in eval.c when + evaluating expressions and making sure that their types are correct. + Instead of having a mess of conjucted/disjuncted expressions in an "if", + the ideas of type can be wrapped up in the following functions. + + Note that some of them are not currently dependent upon which language + is currently being parsed. For example, floats are the same in + C and Modula-2 (ie. the only floating point type has TYPE_CODE of + TYPE_CODE_FLT), while booleans are different. */ + +/* Returns non-zero if its argument is a simple type. This is the same for + both Modula-2 and for C. In the C case, TYPE_CODE_CHAR will never occur, + and thus will never cause the failure of the test. */ +int +simple_type(type) + struct type *type; +{ + switch (TYPE_CODE (type)) { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLT: + case TYPE_CODE_RANGE: + case TYPE_CODE_BOOL: + return 1; + + default: + return 0; + } +} + +/* Returns non-zero if its argument is of an ordered type. + An ordered type is one in which the elements can be tested for the + properties of "greater than", "less than", etc, or for which the + operations "increment" or "decrement" make sense. */ +int +ordered_type (type) + struct type *type; +{ + switch (TYPE_CODE (type)) { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLT: + case TYPE_CODE_RANGE: + return 1; + + default: + return 0; + } +} + +/* Returns non-zero if the two types are the same */ +int +same_type (arg1, arg2) + struct type *arg1, *arg2; +{ + if (structured_type(arg1) ? !structured_type(arg2) : structured_type(arg2)) + /* One is structured and one isn't */ + return 0; + else if (structured_type(arg1) && structured_type(arg2)) + return arg1 == arg2; + else if (numeric_type(arg1) && numeric_type(arg2)) + return (TYPE_CODE(arg2) == TYPE_CODE(arg1)) && + (TYPE_UNSIGNED(arg1) == TYPE_UNSIGNED(arg2)) + ? 1 : 0; + else + return arg1==arg2; +} + +/* Returns non-zero if the type is integral */ +int +integral_type (type) + struct type *type; +{ + switch(current_language->la_language) + { + case language_c: + case language_cplus: + return (TYPE_CODE(type) != TYPE_CODE_INT) && + (TYPE_CODE(type) != TYPE_CODE_ENUM) ? 0 : 1; + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1; + case language_chill: + error ("Missing Chill support in function integral_type."); /*FIXME*/ + default: + error ("Language not supported."); + } +} + +/* Returns non-zero if the value is numeric */ +int +numeric_type (type) + struct type *type; +{ + switch (TYPE_CODE (type)) { + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + return 1; + + default: + return 0; + } +} + +/* Returns non-zero if the value is a character type */ +int +character_type (type) + struct type *type; +{ + switch(current_language->la_language) + { + case language_chill: + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_CHAR ? 0 : 1; + + case language_c: + case language_cplus: + return (TYPE_CODE(type) == TYPE_CODE_INT) && + TYPE_LENGTH(type) == sizeof(char) + ? 1 : 0; + default: + return (0); + } +} + +/* Returns non-zero if the value is a string type */ +int +string_type (type) + struct type *type; +{ + switch(current_language->la_language) + { + case language_chill: + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_STRING ? 0 : 1; + + case language_c: + case language_cplus: + /* C does not have distinct string type. */ + return (0); + default: + return (0); + } +} + +/* Returns non-zero if the value is a boolean type */ +int +boolean_type (type) + struct type *type; +{ + switch(current_language->la_language) + { + case language_chill: + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_BOOL ? 0 : 1; + + case language_c: + case language_cplus: + return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1; + default: + return (0); + } +} + +/* Returns non-zero if the value is a floating-point type */ +int +float_type (type) + struct type *type; +{ + return TYPE_CODE(type) == TYPE_CODE_FLT; +} + +/* Returns non-zero if the value is a pointer type */ +int +pointer_type(type) + struct type *type; +{ + return TYPE_CODE(type) == TYPE_CODE_PTR || + TYPE_CODE(type) == TYPE_CODE_REF; +} + +/* Returns non-zero if the value is a structured type */ +int +structured_type(type) + struct type *type; +{ + switch(current_language->la_language) + { + case language_c: + case language_cplus: + return (TYPE_CODE(type) == TYPE_CODE_STRUCT) || + (TYPE_CODE(type) == TYPE_CODE_UNION) || + (TYPE_CODE(type) == TYPE_CODE_ARRAY); + case language_m2: + return (TYPE_CODE(type) == TYPE_CODE_STRUCT) || + (TYPE_CODE(type) == TYPE_CODE_SET) || + (TYPE_CODE(type) == TYPE_CODE_ARRAY); + case language_chill: + error ("Missing Chill support in function structured_type."); /*FIXME*/ + default: + return (0); + } +} + +/* This page contains functions that return info about + (struct value) values used in GDB. */ + +/* Returns non-zero if the value VAL represents a true value. */ +int +value_true(val) + value val; +{ + int len, i; + struct type *type; + LONGEST v; + + switch (current_language->la_language) { + + case language_c: + case language_cplus: + return !value_logical_not (val); + + case language_m2: + type = VALUE_TYPE(val); + if (TYPE_CODE (type) != TYPE_CODE_BOOL) + return 0; /* Not a BOOLEAN at all */ + /* Search the fields for one that matches the current value. */ + len = TYPE_NFIELDS (type); + v = value_as_long (val); + for (i = 0; i < len; i++) + { + QUIT; + if (v == TYPE_FIELD_BITPOS (type, i)) + break; + } + if (i >= len) + return 0; /* Not a valid BOOLEAN value */ + if (STREQ ("TRUE", TYPE_FIELD_NAME(VALUE_TYPE(val), i))) + return 1; /* BOOLEAN with value TRUE */ + else + return 0; /* BOOLEAN with value FALSE */ + break; + + case language_chill: + error ("Missing Chill support in function value_type."); /*FIXME*/ + + default: + error ("Language not supported."); + } +} + +/* Returns non-zero if the operator OP is defined on + the values ARG1 and ARG2. */ + +#if 0 /* Currently unused */ + +void +binop_type_check(arg1,arg2,op) + value arg1,arg2; + int op; +{ + struct type *t1, *t2; + + /* If we're not checking types, always return success. */ + if (!STRICT_TYPE) + return; + + t1=VALUE_TYPE(arg1); + if (arg2!=(value)NULL) + t2=VALUE_TYPE(arg2); + else + t2=NULL; + + switch(op) + { + case BINOP_ADD: + case BINOP_SUB: + if ((numeric_type(t1) && pointer_type(t2)) || + (pointer_type(t1) && numeric_type(t2))) + { + warning ("combining pointer and integer.\n"); + break; + } + case BINOP_MUL: + case BINOP_LSH: + case BINOP_RSH: + if (!numeric_type(t1) || !numeric_type(t2)) + type_op_error ("Arguments to %s must be numbers.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_LOGICAL_AND: + case BINOP_LOGICAL_OR: + if (!boolean_type(t1) || !boolean_type(t2)) + type_op_error ("Arguments to %s must be of boolean type.",op); + break; + + case BINOP_EQUAL: + if ((pointer_type(t1) && !(pointer_type(t2) || integral_type(t2))) || + (pointer_type(t2) && !(pointer_type(t1) || integral_type(t1)))) + type_op_error ("A pointer can only be compared to an integer or pointer.",op); + else if ((pointer_type(t1) && integral_type(t2)) || + (integral_type(t1) && pointer_type(t2))) + { + warning ("combining integer and pointer.\n"); + break; + } + else if (!simple_type(t1) || !simple_type(t2)) + type_op_error ("Arguments to %s must be of simple type.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_REM: + case BINOP_MOD: + if (!integral_type(t1) || !integral_type(t2)) + type_op_error ("Arguments to %s must be of integral type.",op); + break; + + case BINOP_LESS: + case BINOP_GTR: + case BINOP_LEQ: + case BINOP_GEQ: + if (!ordered_type(t1) || !ordered_type(t2)) + type_op_error ("Arguments to %s must be of ordered type.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_ASSIGN: + if (pointer_type(t1) && !integral_type(t2)) + type_op_error ("A pointer can only be assigned an integer.",op); + else if (pointer_type(t1) && integral_type(t2)) + { + warning ("combining integer and pointer."); + break; + } + else if (!simple_type(t1) || !simple_type(t2)) + type_op_error ("Arguments to %s must be of simple type.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_CONCAT: + /* FIXME: Needs to handle bitstrings as well. */ + if (!(string_type(t1) || character_type(t1) || integral_type(t1)) + || !(string_type(t2) || character_type(t2) || integral_type(t2))) + type_op_error ("Arguments to %s must be strings or characters.", op); + break; + + /* Unary checks -- arg2 is null */ + + case UNOP_LOGICAL_NOT: + if (!boolean_type(t1)) + type_op_error ("Argument to %s must be of boolean type.",op); + break; + + case UNOP_PLUS: + case UNOP_NEG: + if (!numeric_type(t1)) + type_op_error ("Argument to %s must be of numeric type.",op); + break; + + case UNOP_IND: + if (integral_type(t1)) + { + warning ("combining pointer and integer.\n"); + break; + } + else if (!pointer_type(t1)) + type_op_error ("Argument to %s must be a pointer.",op); + break; + + case UNOP_PREINCREMENT: + case UNOP_POSTINCREMENT: + case UNOP_PREDECREMENT: + case UNOP_POSTDECREMENT: + if (!ordered_type(t1)) + type_op_error ("Argument to %s must be of an ordered type.",op); + break; + + default: + /* Ok. The following operators have different meanings in + different languages. */ + switch(current_language->la_language) + { +#ifdef _LANG_c + case language_c: + case language_cplus: + switch(op) + { + case BINOP_DIV: + if (!numeric_type(t1) || !numeric_type(t2)) + type_op_error ("Arguments to %s must be numbers.",op); + break; + } + break; +#endif + +#ifdef _LANG_m2 + case language_m2: + switch(op) + { + case BINOP_DIV: + if (!float_type(t1) || !float_type(t2)) + type_op_error ("Arguments to %s must be floating point numbers.",op); + break; + case BINOP_INTDIV: + if (!integral_type(t1) || !integral_type(t2)) + type_op_error ("Arguments to %s must be of integral type.",op); + break; + } +#endif + +#ifdef _LANG_chill + case language_chill: + error ("Missing Chill support in function binop_type_check.");/*FIXME*/ +#endif + + } + } +} + +#endif /* 0 */ + + +/* This page contains functions for the printing out of + error messages that occur during type- and range- + checking. */ + +/* Prints the format string FMT with the operator as a string + corresponding to the opcode OP. If FATAL is non-zero, then + this is an error and error () is called. Otherwise, it is + a warning and printf() is called. */ +void +op_error (fmt,op,fatal) + char *fmt; + enum exp_opcode op; + int fatal; +{ + if (fatal) + error (fmt,op_string(op)); + else + { + warning (fmt,op_string(op)); + } +} + +/* These are called when a language fails a type- or range-check. + The first argument should be a printf()-style format string, and + the rest of the arguments should be its arguments. If + [type|range]_check is [type|range]_check_on, then return_to_top_level() + is called in the style of error (). Otherwise, the message is prefixed + by the value of warning_pre_print and we do not return to the top level. */ + +void +type_error (va_alist) + va_dcl +{ + va_list args; + char *string; + + if (type_check==type_check_warn) + fprintf(stderr,warning_pre_print); + else + target_terminal_ours(); + + va_start (args); + string = va_arg (args, char *); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); + if (type_check==type_check_on) + return_to_top_level (RETURN_ERROR); +} + +void +range_error (va_alist) + va_dcl +{ + va_list args; + char *string; + + if (range_check==range_check_warn) + fprintf(stderr,warning_pre_print); + else + target_terminal_ours(); + + va_start (args); + string = va_arg (args, char *); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); + if (range_check==range_check_on) + return_to_top_level (RETURN_ERROR); +} + + +/* This page contains miscellaneous functions */ + +/* Return the language struct for a given language enum. */ + +const struct language_defn * +language_def(lang) + enum language lang; +{ + int i; + + for (i = 0; i < languages_size; i++) { + if (languages[i]->la_language == lang) { + return languages[i]; + } + } + return NULL; +} + +/* Return the language as a string */ +char * +language_str(lang) + enum language lang; +{ + int i; + + for (i = 0; i < languages_size; i++) { + if (languages[i]->la_language == lang) { + return languages[i]->la_name; + } + } + return "Unknown"; +} + +static void +set_check (ignore, from_tty) + char *ignore; + int from_tty; +{ + printf( +"\"set check\" must be followed by the name of a check subcommand.\n"); + help_list(setchecklist, "set check ", -1, stdout); +} + +static void +show_check (ignore, from_tty) + char *ignore; + int from_tty; +{ + cmd_show_list(showchecklist, from_tty, ""); +} + +/* Add a language to the set of known languages. */ + +void +add_language (lang) + const struct language_defn *lang; +{ + if (lang->la_magic != LANG_MAGIC) + { + fprintf(stderr, "Magic number of %s language struct wrong\n", + lang->la_name); + abort(); + } + + if (!languages) + { + languages_allocsize = DEFAULT_ALLOCSIZE; + languages = (const struct language_defn **) xmalloc + (languages_allocsize * sizeof (*languages)); + } + if (languages_size >= languages_allocsize) + { + languages_allocsize *= 2; + languages = (const struct language_defn **) xrealloc ((char *) languages, + languages_allocsize * sizeof (*languages)); + } + languages[languages_size++] = lang; +} + +/* Define the language that is no language. */ + +static int +unk_lang_parser () +{ + return 1; +} + +static void +unk_lang_error (msg) + char *msg; +{ + error ("Attempted to parse an expression with unknown language"); +} + +static void +unk_lang_printchar (c, stream) + register int c; + FILE *stream; +{ + error ("internal error - unimplemented function unk_lang_printchar called."); +} + +static void +unk_lang_printstr (stream, string, length, force_ellipses) + FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + error ("internal error - unimplemented function unk_lang_printstr called."); +} + +static struct type * +unk_lang_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + error ("internal error - unimplemented function unk_lang_create_fundamental_type called."); +} + +void +unk_lang_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + FILE *stream; + int show; + int level; +{ + error ("internal error - unimplemented function unk_lang_print_type called."); +} + +int +unk_lang_val_print (type, valaddr, address, stream, format, deref_ref, + recurse, pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + error ("internal error - unimplemented function unk_lang_val_print called."); +} + +static struct type ** const (unknown_builtin_types[]) = { 0 }; +static const struct op_print unk_op_print_tab[] = { + {NULL, OP_NULL, PREC_NULL, 0} +}; + +const struct language_defn unknown_language_defn = { + "unknown", + language_unknown, + &unknown_builtin_types[0], + range_check_off, + type_check_off, + unk_lang_parser, + unk_lang_error, + unk_lang_printchar, /* Print character constant */ + unk_lang_printstr, + unk_lang_create_fundamental_type, + unk_lang_print_type, /* Print a type using appropriate syntax */ + unk_lang_val_print, /* Print a value using appropriate syntax */ + &builtin_type_error, /* longest signed integral type */ + &builtin_type_error, /* longest unsigned integral type */ + &builtin_type_error, /* longest floating point type */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + unk_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +/* These two structs define fake entries for the "local" and "auto" options. */ +const struct language_defn auto_language_defn = { + "auto", + language_auto, + &unknown_builtin_types[0], + range_check_off, + type_check_off, + unk_lang_parser, + unk_lang_error, + unk_lang_printchar, /* Print character constant */ + unk_lang_printstr, + unk_lang_create_fundamental_type, + unk_lang_print_type, /* Print a type using appropriate syntax */ + unk_lang_val_print, /* Print a value using appropriate syntax */ + &builtin_type_error, /* longest signed integral type */ + &builtin_type_error, /* longest unsigned integral type */ + &builtin_type_error, /* longest floating point type */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + unk_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +const struct language_defn local_language_defn = { + "local", + language_auto, + &unknown_builtin_types[0], + range_check_off, + type_check_off, + unk_lang_parser, + unk_lang_error, + unk_lang_printchar, /* Print character constant */ + unk_lang_printstr, + unk_lang_create_fundamental_type, + unk_lang_print_type, /* Print a type using appropriate syntax */ + unk_lang_val_print, /* Print a value using appropriate syntax */ + &builtin_type_error, /* longest signed integral type */ + &builtin_type_error, /* longest unsigned integral type */ + &builtin_type_error, /* longest floating point type */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + unk_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +/* Initialize the language routines */ + +void +_initialize_language() +{ + struct cmd_list_element *set, *show; + + /* GDB commands for language specific stuff */ + + set = add_set_cmd ("language", class_support, var_string_noescape, + (char *)&language, + "Set the current source language.", + &setlist); + show = add_show_from_set (set, &showlist); + set->function.cfunc = set_language_command; + show->function.cfunc = show_language_command; + + add_prefix_cmd ("check", no_class, set_check, + "Set the status of the type/range checker", + &setchecklist, "set check ", 0, &setlist); + add_alias_cmd ("c", "check", no_class, 1, &setlist); + add_alias_cmd ("ch", "check", no_class, 1, &setlist); + + add_prefix_cmd ("check", no_class, show_check, + "Show the status of the type/range checker", + &showchecklist, "show check ", 0, &showlist); + add_alias_cmd ("c", "check", no_class, 1, &showlist); + add_alias_cmd ("ch", "check", no_class, 1, &showlist); + + set = add_set_cmd ("type", class_support, var_string_noescape, + (char *)&type, + "Set type checking. (on/warn/off/auto)", + &setchecklist); + show = add_show_from_set (set, &showchecklist); + set->function.cfunc = set_type_command; + show->function.cfunc = show_type_command; + + set = add_set_cmd ("range", class_support, var_string_noescape, + (char *)&range, + "Set range checking. (on/warn/off/auto)", + &setchecklist); + show = add_show_from_set (set, &showchecklist); + set->function.cfunc = set_range_command; + show->function.cfunc = show_range_command; + + add_language (&unknown_language_defn); + add_language (&local_language_defn); + add_language (&auto_language_defn); + + language = savestring ("auto",strlen("auto")); + range = savestring ("auto",strlen("auto")); + type = savestring ("auto",strlen("auto")); + + /* Have the above take effect */ + + set_language_command (language, 0); + set_type_command (NULL, 0); + set_range_command (NULL, 0); +} diff --git a/gnu/usr.bin/gdb/gdb/language.h b/gnu/usr.bin/gdb/gdb/language.h new file mode 100644 index 00000000000..9df5345c930 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/language.h @@ -0,0 +1,413 @@ +/* Source-language-related definitions for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + Contributed by the Department of Computer Science at the State University + of New York at Buffalo. + +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. */ + +#if !defined (LANGUAGE_H) +#define LANGUAGE_H 1 + +#ifdef __STDC__ /* Forward decls for prototypes */ +struct value; +struct objfile; +/* enum exp_opcode; ANSI's `wisdom' didn't include forward enum decls. */ +#endif + +/* This used to be included to configure GDB for one or more specific + languages. Now it is shortcutted to configure for all of them. FIXME. */ +/* #include "lang_def.h" */ +#define _LANG_c +#define _LANG_m2 +#define _LANG_chill + +/* range_mode == + range_mode_auto: range_check set automatically to default of language. + range_mode_manual: range_check set manually by user. */ + +extern enum range_mode {range_mode_auto, range_mode_manual} range_mode; + +/* range_check == + range_check_on: Ranges are checked in GDB expressions, producing errors. + range_check_warn: Ranges are checked, producing warnings. + range_check_off: Ranges are not checked in GDB expressions. */ + +extern enum range_check + {range_check_off, range_check_warn, range_check_on} range_check; + +/* type_mode == + type_mode_auto: type_check set automatically to default of language + type_mode_manual: type_check set manually by user. */ + +extern enum type_mode {type_mode_auto, type_mode_manual} type_mode; + +/* type_check == + type_check_on: Types are checked in GDB expressions, producing errors. + type_check_warn: Types are checked, producing warnings. + type_check_off: Types are not checked in GDB expressions. */ + +extern enum type_check + {type_check_off, type_check_warn, type_check_on} type_check; + +/* Information for doing language dependent formatting of printed values. */ + +struct language_format_info +{ + /* The format that can be passed directly to standard C printf functions + to generate a completely formatted value in the format appropriate for + the language. */ + + char *la_format; + + /* The prefix to be used when directly printing a value, or constructing + a standard C printf format. This generally is everything up to the + conversion specification (the part introduced by the '%' character + and terminated by the conversion specifier character). */ + + char *la_format_prefix; + + /* The conversion specifier. This is generally everything after the + field width and precision, typically only a single character such + as 'o' for octal format or 'x' for hexadecimal format. */ + + char *la_format_specifier; + + /* The suffix to be used when directly printing a value, or constructing + a standard C printf format. This generally is everything after the + conversion specification (the part introduced by the '%' character + and terminated by the conversion specifier character). */ + + char *la_format_suffix; /* Suffix for custom format string */ +}; + +/* Structure tying together assorted information about a language. */ + +struct language_defn +{ + /* Name of the language */ + + char *la_name; + + /* its symtab language-enum (defs.h) */ + + enum language la_language; + + /* Its builtin types */ + + struct type ** const *la_builtin_type_vector; + + /* Default range checking */ + + enum range_check la_range_check; + + /* Default type checking */ + + enum type_check la_type_check; + + /* Parser function. */ + + int (*la_parser) PARAMS((void)); + + /* Parser error function */ + + void (*la_error) PARAMS ((char *)); + + void (*la_printchar) PARAMS ((int, FILE *)); + + void (*la_printstr) PARAMS ((FILE *, char *, unsigned int, int)); + + struct type *(*la_fund_type) PARAMS ((struct objfile *, int)); + + /* Print a type using syntax appropriate for this language. */ + + void (*la_print_type) PARAMS ((struct type *, char *, FILE *, int, int)); + + /* Print a value using syntax appropriate for this language. */ + + int (*la_val_print) PARAMS ((struct type *, char *, CORE_ADDR, FILE *, + int, int, int, enum val_prettyprint)); + + /* Longest signed integral type */ + + struct type **la_longest_int; + + /* Longest unsigned integral type */ + + struct type **la_longest_unsigned_int; + + /* Longest floating point type */ + + struct type **la_longest_float; + + /* Base 2 (binary) formats. */ + + struct language_format_info la_binary_format; + + /* Base 8 (octal) formats. */ + + struct language_format_info la_octal_format; + + /* Base 10 (decimal) formats */ + + struct language_format_info la_decimal_format; + + /* Base 16 (hexadecimal) formats */ + + struct language_format_info la_hex_format; + + + /* Table for printing expressions */ + + const struct op_print *la_op_print_tab; + + /* Add fields above this point, so the magic number is always last. */ + /* Magic number for compat checking */ + + long la_magic; + +}; + +#define LANG_MAGIC 910823L + +/* Pointer to the language_defn for our current language. This pointer + always points to *some* valid struct; it can be used without checking + it for validity. + + The current language affects expression parsing and evaluation + (FIXME: it might be cleaner to make the evaluation-related stuff + separate exp_opcodes for each different set of semantics. We + should at least think this through more clearly with respect to + what happens if the language is changed between parsing and + evaluation) and printing of things like types and arrays. It does + *not* affect symbol-reading-- each source file in a symbol-file has + its own language and we should keep track of that regardless of the + language when symbols are read. If we want some manual setting for + the language of symbol files (e.g. detecting when ".c" files are + C++), it should be a seprate setting from the current_language. */ + +extern const struct language_defn *current_language; + +/* Pointer to the language_defn expected by the user, e.g. the language + of main(), or the language we last mentioned in a message, or C. */ + +extern const struct language_defn *expected_language; + +/* language_mode == + language_mode_auto: current_language automatically set upon selection + of scope (e.g. stack frame) + language_mode_manual: current_language set only by user. */ + +extern enum language_mode + {language_mode_auto, language_mode_manual} language_mode; + +/* These macros define the behaviour of the expression + evaluator. */ + +/* Should we strictly type check expressions? */ +#define STRICT_TYPE (type_check != type_check_off) + +/* Should we range check values against the domain of their type? */ +#define RANGE_CHECK (range_check != range_check_off) + +/* "cast" really means conversion */ +/* FIXME -- should be a setting in language_defn */ +#define CAST_IS_CONVERSION (current_language->la_language == language_c || \ + current_language->la_language == language_cplus) + +extern void +language_info PARAMS ((int)); + +extern void +set_language PARAMS ((enum language)); + + +/* This page contains functions that return things that are + specific to languages. Each of these functions is based on + the current setting of working_lang, which the user sets + with the "set language" command. */ + +/* Returns some built-in types */ +#define longest_int() (*current_language->la_longest_int) +#define longest_unsigned_int() (*current_language->la_longest_unsigned_int) +#define longest_float() (*current_language->la_longest_float) + +#define create_fundamental_type(objfile,typeid) \ + (current_language->la_fund_type(objfile, typeid)) + +#define LA_PRINT_TYPE(type,varstring,stream,show,level) \ + (current_language->la_print_type(type,varstring,stream,show,level)) + +#define LA_VAL_PRINT(type,valaddr,addr,stream,fmt,deref,recurse,pretty) \ + (current_language->la_val_print(type,valaddr,addr,stream,fmt,deref, \ + recurse,pretty)) + +/* Return a format string for printf that will print a number in one of + the local (language-specific) formats. Result is static and is + overwritten by the next call. Takes printf options like "08" or "l" + (to produce e.g. %08x or %lx). */ + +#define local_binary_format() \ + (current_language->la_binary_format.la_format) +#define local_binary_format_prefix() \ + (current_language->la_binary_format.la_format_prefix) +#define local_binary_format_specifier() \ + (current_language->la_binary_format.la_format_specifier) +#define local_binary_format_suffix() \ + (current_language->la_binary_format.la_format_suffix) + +#define local_octal_format() \ + (current_language->la_octal_format.la_format) +#define local_octal_format_prefix() \ + (current_language->la_octal_format.la_format_prefix) +#define local_octal_format_specifier() \ + (current_language->la_octal_format.la_format_specifier) +#define local_octal_format_suffix() \ + (current_language->la_octal_format.la_format_suffix) + +#define local_decimal_format() \ + (current_language->la_decimal_format.la_format) +#define local_decimal_format_prefix() \ + (current_language->la_decimal_format.la_format_prefix) +#define local_decimal_format_specifier() \ + (current_language->la_decimal_format.la_format_specifier) +#define local_decimal_format_suffix() \ + (current_language->la_decimal_format.la_format_suffix) + +#define local_hex_format() \ + (current_language->la_hex_format.la_format) +#define local_hex_format_prefix() \ + (current_language->la_hex_format.la_format_prefix) +#define local_hex_format_specifier() \ + (current_language->la_hex_format.la_format_specifier) +#define local_hex_format_suffix() \ + (current_language->la_hex_format.la_format_suffix) + +#define LA_PRINT_CHAR(ch, stream) \ + (current_language->la_printchar(ch, stream)) +#define LA_PRINT_STRING(stream, string, length, force_ellipses) \ + (current_language->la_printstr(stream, string, length, force_ellipses)) + +/* Test a character to decide whether it can be printed in literal form + or needs to be printed in another representation. For example, + in C the literal form of the character with octal value 141 is 'a' + and the "other representation" is '\141'. The "other representation" + is program language dependent. */ + +#define PRINT_LITERAL_FORM(c) \ + ((c)>=0x20 && ((c)<0x7F || (c)>=0xA0) && (!sevenbit_strings || (c)<0x80)) + +/* Return a format string for printf that will print a number in one of + the local (language-specific) formats. Result is static and is + overwritten by the next call. Takes printf options like "08" or "l" + (to produce e.g. %08x or %lx). */ + +extern char * +local_decimal_format_custom PARAMS ((char *)); /* language.c */ + +extern char * +local_octal_format_custom PARAMS ((char *)); /* language.c */ + +extern char * +local_hex_format_custom PARAMS ((char *)); /* language.c */ + +/* Return a string that contains a number formatted in one of the local + (language-specific) formats. Result is static and is overwritten by + the next call. Takes printf options like "08" or "l". */ + +extern char * +local_hex_string PARAMS ((unsigned long)); /* language.c */ + +extern char * +local_hex_string_custom PARAMS ((unsigned long, char *)); /* language.c */ + +/* Type predicates */ + +extern int +simple_type PARAMS ((struct type *)); + +extern int +ordered_type PARAMS ((struct type *)); + +extern int +same_type PARAMS ((struct type *, struct type *)); + +extern int +integral_type PARAMS ((struct type *)); + +extern int +numeric_type PARAMS ((struct type *)); + +extern int +character_type PARAMS ((struct type *)); + +extern int +boolean_type PARAMS ((struct type *)); + +extern int +float_type PARAMS ((struct type *)); + +extern int +pointer_type PARAMS ((struct type *)); + +extern int +structured_type PARAMS ((struct type *)); + +/* Checks Binary and Unary operations for semantic type correctness */ +/* FIXME: Does not appear to be used */ +#define unop_type_check(v,o) binop_type_check((v),NULL,(o)) + +extern void +binop_type_check PARAMS ((struct value *, struct value *, int)); + +/* Error messages */ + +extern void +op_error PARAMS ((char *fmt, enum exp_opcode, int)); + +#define type_op_error(f,o) \ + op_error((f),(o),type_check==type_check_on ? 1 : 0) +#define range_op_error(f,o) \ + op_error((f),(o),range_check==range_check_on ? 1 : 0) + +extern void +type_error (); + +void +range_error (); + +/* Data: Does this value represent "truth" to the current language? */ + +extern int +value_true PARAMS ((struct value *)); + +/* Misc: The string representing a particular enum language. */ + +extern const struct language_defn * +language_def PARAMS ((enum language)); + +extern char * +language_str PARAMS ((enum language)); + +/* Add a language to the set known by GDB (at initialization time). */ + +extern void +add_language PARAMS ((const struct language_defn *)); + +extern enum language +get_frame_language PARAMS ((void)); /* In stack.c */ + +#endif /* defined (LANGUAGE_H) */ diff --git a/gnu/usr.bin/gdb/gdb/m2-exp.tab.c b/gnu/usr.bin/gdb/gdb/m2-exp.tab.c new file mode 100644 index 00000000000..53b13858b68 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/m2-exp.tab.c @@ -0,0 +1,1991 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define yyparse m2_parse +#define yylex m2_lex +#define yyerror m2_error +#define yychar m2_char +#define yyval m2_val +#define yylval m2_lval +#define yydebug m2_debug +#define yynerrs m2_nerrs +#define yyerrflag m2_errflag +#define yyss m2_ss +#define yyssp m2_ssp +#define yyvs m2_vs +#define yyvsp m2_vsp +#define yylhs m2_lhs +#define yylen m2_len +#define yydefred m2_defred +#define yydgoto m2_dgoto +#define yysindex m2_sindex +#define yyrindex m2_rindex +#define yygindex m2_gindex +#define yytable m2_table +#define yycheck m2_check +#define yyname m2_name +#define yyrule m2_rule +#define YYPREFIX "m2_" +#line 40 "./m2-exp.y" + +#include "defs.h" +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "m2-lang.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth m2_maxdepth +#define yyparse m2_parse +#define yylex m2_lex +#define yyerror m2_error +#define yylval m2_lval +#define yychar m2_char +#define yydebug m2_debug +#define yypact m2_pact +#define yyr1 m2_r1 +#define yyr2 m2_r2 +#define yydef m2_def +#define yychk m2_chk +#define yypgo m2_pgo +#define yyact m2_act +#define yyexca m2_exca +#define yyerrflag m2_errflag +#define yynerrs m2_nerrs +#define yyps m2_ps +#define yypv m2_pv +#define yys m2_s +#define yy_yys m2_yys +#define yystate m2_state +#define yytmp m2_tmp +#define yyv m2_v +#define yy_yyv m2_yyv +#define yyval m2_val +#define yylloc m2_lloc +#define yyreds m2_reds /* With YYDEBUG defined */ +#define yytoks m2_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#if 0 +static char * +make_qualname PARAMS ((char *, char *)); +#endif + +static int +parse_number PARAMS ((int)); + +/* The sign of the number being parsed. */ +static int number_sign = 1; + +/* The block that the module specified by the qualifer on an identifer is + contained in, */ +#if 0 +static struct block *modblock=0; +#endif + +#line 121 "./m2-exp.y" +typedef union + { + LONGEST lval; + unsigned LONGEST ulval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } YYSTYPE; +#line 129 "y.tab.c" +#define INT 257 +#define HEX 258 +#define ERROR 259 +#define UINT 260 +#define M2_TRUE 261 +#define M2_FALSE 262 +#define CHAR 263 +#define FLOAT 264 +#define STRING 265 +#define NAME 266 +#define BLOCKNAME 267 +#define IDENT 268 +#define VARNAME 269 +#define TYPENAME 270 +#define SIZE 271 +#define CAP 272 +#define ORD 273 +#define HIGH 274 +#define ABS 275 +#define MIN_FUNC 276 +#define MAX_FUNC 277 +#define FLOAT_FUNC 278 +#define VAL 279 +#define CHR 280 +#define ODD 281 +#define TRUNC 282 +#define INC 283 +#define DEC 284 +#define INCL 285 +#define EXCL 286 +#define COLONCOLON 287 +#define LAST 288 +#define REGNAME 289 +#define INTERNAL_VAR 290 +#define ABOVE_COMMA 291 +#define ASSIGN 292 +#define LEQ 293 +#define GEQ 294 +#define NOTEQUAL 295 +#define IN 296 +#define OROR 297 +#define LOGICAL_AND 298 +#define DIV 299 +#define MOD 300 +#define UNARY 301 +#define DOT 302 +#define NOT 303 +#define QID 304 +#define YYERRCODE 256 +short m2_lhs[] = { -1, + 0, 0, 2, 1, 8, 1, 1, 1, 9, 9, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 12, 1, 13, 1, 10, 10, 10, + 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6, 7, 7, 4, 4, 4, 4, + 5, +}; +short m2_len[] = { 2, + 1, 1, 1, 2, 0, 3, 2, 2, 1, 1, + 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, + 4, 2, 4, 6, 4, 6, 3, 1, 3, 6, + 6, 3, 4, 0, 5, 0, 5, 0, 1, 3, + 1, 3, 4, 4, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 1, 1, 3, 1, 1, 3, 1, + 1, +}; +short m2_defred[] = { 0, + 65, 66, 63, 64, 67, 68, 73, 80, 75, 81, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 70, 71, 78, 0, + 5, 0, 9, 10, 0, 0, 0, 2, 28, 69, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 0, 34, 36, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 0, 0, 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, + 79, 76, 72, 11, 12, 14, 13, 15, 16, 17, + 0, 19, 20, 21, 0, 23, 0, 25, 0, 0, + 0, 0, 0, 0, 0, 44, 33, 0, 0, 0, + 0, 0, 0, 35, 37, 18, 24, 26, 30, 31, + 0, +}; +short m2_dgoto[] = { 36, + 66, 38, 39, 40, 47, 42, 43, 64, 44, 68, + 164, 137, 138, +}; +short m2_sindex[] = { 1597, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1779, -27, -21, -15, -10, -6, -3, -2, 18, 20, + 24, 31, 38, 39, 59, 77, 0, 0, 0, 1597, + 0, 1597, 0, 0, 1597, 0, 1670, 0, 0, 0, + -26, -256, 0, 1597, 1597, -24, -26, 1597, 1597, 1597, + 1597, -218, -218, 1597, -218, 1597, 1597, 1597, 1597, 1597, + 1597, 1597, -24, 1597, 939, 1670, -37, -17, 1597, 1597, + 1597, 1597, 1597, 1597, 1597, 1597, -118, 1597, 1597, 1597, + 1597, 1597, 1597, 1597, 1597, 1597, 0, -186, 0, 0, + 1597, 1597, -259, -24, -30, 967, 1002, 1044, 1079, 78, + 83, 1160, 74, 1268, 1323, 1351, 866, 894, 1183, 1404, + -24, 0, 1597, 1597, 0, 1727, -25, -25, -25, -25, + -25, -25, -25, 1597, 0, 8, 80, 192, 117, 49, + 49, -24, -24, -24, -24, 0, 1597, 1597, 1449, -11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1597, 0, 0, 0, 1597, 0, 1597, 0, 1597, 1597, + -24, 1670, 1670, -44, -20, 0, 0, 1484, 1512, 1547, + 1617, 1628, 1597, 0, 0, 0, 0, 0, 0, 0, + 1670, +}; +short m2_rindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -9, 0, 121, 0, 0, 0, + 135, 0, 1, 0, 0, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 0, 0, -35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -9, 0, 68, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 106, 0, 0, 0, 0, 98, 568, 575, 598, 653, + 677, 779, 838, -9, 0, 0, 561, 539, 502, 465, + 489, 134, 145, 220, 411, 0, 0, -12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 435, -18, -42, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -16, +}; +short m2_gindex[] = { 0, + 2066, 0, 61, 0, 341, 0, 0, 0, 0, -88, + 0, 0, 0, +}; +#define YYTABLESIZE 2239 +short m2_table[] = { 173, + 77, 41, 91, 140, 124, 39, 141, 142, 39, 91, + 143, 22, 48, 91, 90, 90, 83, 81, 49, 82, + 175, 84, 40, 114, 50, 40, 114, 42, 38, 51, + 93, 38, 114, 52, 38, 77, 53, 54, 80, 7, + 77, 77, 77, 77, 77, 77, 22, 77, 174, 165, + 41, 10, 22, 22, 22, 22, 22, 55, 22, 56, + 77, 77, 77, 57, 77, 89, 89, 8, 87, 87, + 58, 22, 22, 22, 7, 22, 42, 59, 60, 136, + 7, 7, 7, 7, 7, 92, 7, 113, 90, 39, + 83, 77, 92, 77, 77, 84, 92, 62, 61, 7, + 7, 7, 8, 7, 22, 6, 40, 115, 8, 8, + 8, 8, 8, 167, 8, 38, 62, 151, 148, 90, + 1, 83, 81, 149, 82, 77, 84, 8, 8, 8, + 92, 8, 7, 47, 3, 0, 22, 125, 62, 89, + 6, 62, 87, 80, 48, 0, 6, 6, 6, 6, + 6, 10, 6, 0, 0, 0, 90, 0, 83, 81, + 8, 82, 0, 84, 7, 6, 6, 6, 47, 6, + 89, 0, 0, 87, 47, 47, 47, 47, 47, 48, + 47, 0, 0, 0, 0, 48, 48, 48, 48, 48, + 62, 48, 8, 47, 47, 47, 0, 47, 6, 0, + 0, 0, 0, 0, 48, 48, 48, 89, 48, 0, + 87, 0, 0, 0, 0, 0, 0, 0, 0, 49, + 0, 0, 62, 0, 0, 0, 47, 0, 0, 0, + 6, 90, 0, 83, 81, 0, 82, 48, 84, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 49, 80, 0, 0, 47, 0, + 49, 49, 49, 49, 49, 0, 49, 0, 0, 48, + 0, 78, 79, 85, 86, 0, 88, 88, 0, 49, + 49, 49, 89, 49, 0, 87, 0, 74, 0, 0, + 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 0, 77, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 49, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 41, 0, 0, 0, 49, 0, 0, 85, 86, 0, + 88, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 67, 0, 79, 85, 86, + 0, 88, 0, 0, 0, 95, 0, 0, 0, 0, + 0, 0, 100, 101, 0, 103, 0, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, + 50, 0, 0, 0, 0, 85, 86, 126, 88, 0, + 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 43, 0, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 50, 0, 0, 0, 0, + 0, 50, 50, 50, 50, 50, 0, 50, 0, 0, + 0, 0, 0, 0, 51, 0, 0, 0, 0, 43, + 50, 50, 50, 0, 50, 43, 43, 43, 43, 43, + 0, 43, 0, 0, 0, 0, 0, 0, 52, 0, + 85, 86, 0, 88, 43, 43, 43, 0, 43, 51, + 0, 46, 0, 50, 0, 51, 0, 51, 51, 51, + 0, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 0, 0, 0, 52, 51, 51, 51, 43, 51, 52, + 0, 52, 52, 52, 0, 50, 46, 0, 60, 0, + 0, 0, 46, 0, 0, 46, 0, 0, 52, 52, + 52, 0, 52, 0, 0, 0, 0, 51, 0, 43, + 61, 46, 46, 46, 0, 46, 0, 58, 0, 0, + 0, 0, 0, 60, 59, 0, 0, 0, 0, 60, + 0, 52, 60, 0, 0, 0, 0, 0, 0, 51, + 0, 0, 0, 0, 46, 61, 0, 56, 60, 60, + 60, 61, 58, 0, 61, 0, 0, 0, 58, 59, + 0, 58, 0, 52, 0, 59, 0, 0, 59, 0, + 61, 61, 61, 0, 0, 0, 46, 58, 58, 58, + 0, 60, 56, 0, 59, 59, 59, 0, 56, 0, + 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 57, 61, 0, 0, 0, 56, 56, 56, + 58, 0, 0, 60, 0, 0, 0, 59, 0, 0, + 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, + 0, 0, 0, 0, 0, 61, 0, 57, 0, 0, + 56, 0, 58, 57, 0, 0, 57, 0, 0, 59, + 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 53, 57, 57, 57, 0, 0, 53, 0, 0, + 53, 0, 56, 0, 0, 0, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 0, 53, 53, 53, 0, + 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 51, 51, 51, 51, + 51, 51, 51, 0, 0, 0, 0, 0, 0, 53, + 0, 0, 0, 0, 0, 0, 0, 57, 54, 0, + 52, 52, 52, 52, 52, 52, 52, 0, 0, 0, + 0, 0, 0, 46, 46, 46, 46, 46, 46, 46, + 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 54, 0, 0, 0, 0, 0, 54, + 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, + 60, 60, 60, 60, 60, 60, 60, 55, 54, 54, + 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 61, 61, 61, 61, 61, 61, 0, 58, + 58, 58, 58, 58, 0, 0, 59, 59, 59, 59, + 59, 54, 55, 0, 0, 0, 0, 0, 55, 0, + 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, + 56, 56, 56, 56, 0, 0, 0, 55, 55, 55, + 76, 0, 0, 54, 0, 90, 156, 83, 81, 155, + 82, 0, 84, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70, 74, 71, 76, 80, + 55, 0, 0, 90, 158, 83, 81, 157, 82, 0, + 84, 0, 0, 0, 57, 57, 57, 57, 57, 0, + 0, 0, 0, 70, 74, 71, 89, 80, 0, 87, + 0, 0, 55, 0, 0, 0, 0, 0, 53, 53, + 53, 53, 53, 76, 0, 0, 0, 0, 90, 112, + 83, 81, 0, 82, 89, 84, 0, 87, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 70, 74, + 71, 76, 80, 0, 0, 0, 90, 144, 83, 81, + 0, 82, 0, 84, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 70, 74, 71, 89, + 80, 0, 87, 0, 0, 0, 76, 0, 0, 0, + 0, 90, 145, 83, 81, 0, 82, 0, 84, 0, + 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, + 87, 70, 74, 71, 0, 80, 0, 0, 0, 0, + 54, 54, 54, 54, 54, 0, 0, 0, 76, 0, + 0, 0, 0, 90, 146, 83, 81, 0, 82, 0, + 84, 0, 89, 0, 0, 87, 0, 0, 0, 0, + 0, 0, 0, 70, 74, 71, 0, 80, 0, 0, + 0, 0, 0, 76, 0, 0, 0, 0, 90, 147, + 83, 81, 0, 82, 0, 84, 0, 0, 0, 55, + 55, 55, 55, 55, 89, 0, 0, 87, 70, 74, + 71, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69, 72, 73, + 75, 77, 78, 79, 85, 86, 0, 88, 0, 89, + 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 69, 72, 73, 75, 77, + 78, 79, 85, 86, 76, 88, 0, 0, 0, 90, + 150, 83, 81, 0, 82, 0, 84, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 76, 0, 70, + 74, 71, 90, 80, 83, 81, 159, 82, 0, 84, + 69, 72, 73, 75, 77, 78, 79, 85, 86, 0, + 88, 0, 70, 74, 71, 0, 80, 0, 0, 0, + 89, 0, 0, 87, 0, 0, 0, 0, 69, 72, + 73, 75, 77, 78, 79, 85, 86, 0, 88, 0, + 0, 0, 0, 89, 0, 0, 87, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 72, 73, 75, 77, 78, 79, + 85, 86, 76, 88, 0, 0, 0, 90, 152, 83, + 81, 0, 82, 0, 84, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 70, 74, 71, + 0, 80, 0, 0, 0, 69, 72, 73, 75, 77, + 78, 79, 85, 86, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 76, 89, 0, + 0, 87, 90, 153, 83, 81, 0, 82, 0, 84, + 69, 72, 73, 75, 77, 78, 79, 85, 86, 0, + 88, 0, 70, 74, 71, 76, 80, 0, 0, 0, + 90, 154, 83, 81, 0, 82, 0, 84, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 70, 74, 71, 89, 80, 0, 87, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 0, + 0, 89, 0, 90, 87, 83, 81, 160, 82, 0, + 84, 69, 72, 73, 75, 77, 78, 79, 85, 86, + 0, 88, 0, 70, 74, 71, 0, 80, 0, 0, + 0, 0, 0, 0, 69, 72, 73, 75, 77, 78, + 79, 85, 86, 76, 88, 0, 0, 0, 90, 166, + 83, 81, 0, 82, 89, 84, 0, 87, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 70, 74, + 71, 0, 80, 0, 0, 0, 0, 0, 76, 0, + 0, 0, 0, 90, 176, 83, 81, 0, 82, 0, + 84, 0, 0, 0, 0, 0, 0, 0, 0, 89, + 0, 0, 87, 70, 74, 71, 76, 80, 0, 0, + 0, 90, 177, 83, 81, 0, 82, 0, 84, 69, + 72, 73, 75, 77, 78, 79, 85, 86, 0, 88, + 0, 70, 74, 71, 89, 80, 0, 87, 0, 0, + 0, 76, 0, 0, 0, 0, 90, 178, 83, 81, + 0, 82, 0, 84, 0, 0, 0, 0, 0, 0, + 0, 0, 89, 0, 0, 87, 70, 74, 71, 0, + 80, 0, 0, 0, 69, 72, 73, 75, 77, 78, + 79, 85, 86, 0, 88, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32, 89, 0, 30, + 87, 31, 69, 72, 73, 75, 77, 78, 79, 85, + 86, 76, 88, 0, 0, 0, 90, 179, 83, 81, + 0, 82, 76, 84, 0, 0, 0, 90, 180, 83, + 81, 0, 82, 0, 84, 0, 70, 74, 71, 0, + 80, 0, 0, 0, 0, 0, 0, 70, 74, 71, + 0, 80, 0, 0, 0, 69, 72, 73, 75, 77, + 78, 79, 85, 86, 76, 88, 0, 89, 0, 90, + 87, 83, 81, 0, 82, 0, 84, 0, 89, 35, + 0, 87, 34, 0, 0, 0, 0, 0, 0, 70, + 74, 71, 0, 80, 0, 0, 0, 0, 0, 0, + 69, 72, 73, 75, 77, 78, 79, 85, 86, 0, + 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 89, 76, 0, 87, 0, 0, 90, 0, 83, 81, + 0, 82, 0, 84, 0, 69, 72, 73, 75, 77, + 78, 79, 85, 86, 0, 88, 70, 74, 71, 0, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 72, 73, 75, 77, 78, 79, + 85, 86, 0, 88, 0, 0, 0, 89, 45, 0, + 87, 30, 0, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 69, 72, + 73, 75, 77, 78, 79, 85, 86, 0, 88, 0, + 0, 0, 0, 1, 0, 0, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 0, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 0, 27, 28, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, + 0, 35, 0, 0, 34, 0, 0, 0, 69, 72, + 73, 75, 77, 78, 79, 85, 86, 0, 88, 69, + 72, 73, 75, 77, 78, 79, 85, 86, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 69, 72, 73, 75, 77, 78, 79, 85, 86, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, + 73, 75, 77, 78, 79, 85, 86, 0, 88, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 0, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 37, 27, 28, 29, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, + 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 63, 0, 65, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, + 65, 0, 0, 96, 97, 98, 99, 0, 0, 102, + 0, 104, 105, 106, 107, 108, 109, 110, 0, 111, + 0, 0, 0, 0, 116, 117, 118, 119, 120, 121, + 122, 123, 0, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 0, 0, 0, 0, 139, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 161, 162, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, + 169, 0, 170, 0, 171, 172, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 181, +}; +short m2_check[] = { 44, + 0, 44, 40, 92, 123, 41, 266, 267, 44, 40, + 41, 0, 40, 40, 40, 40, 42, 43, 40, 45, + 41, 47, 41, 44, 40, 44, 44, 44, 41, 40, + 287, 44, 44, 40, 44, 35, 40, 40, 64, 0, + 40, 41, 42, 43, 44, 45, 35, 47, 93, 138, + 93, 270, 41, 42, 43, 44, 45, 40, 47, 40, + 60, 61, 62, 40, 64, 91, 91, 0, 94, 94, + 40, 60, 61, 62, 35, 64, 93, 40, 40, 266, + 41, 42, 43, 44, 45, 123, 47, 125, 40, 125, + 42, 91, 123, 93, 94, 47, 123, 0, 40, 60, + 61, 62, 35, 64, 93, 0, 125, 125, 41, 42, + 43, 44, 45, 125, 47, 125, 40, 44, 41, 40, + 0, 42, 43, 41, 45, 125, 47, 60, 61, 62, + 123, 64, 93, 0, 0, -1, 125, 77, 41, 91, + 35, 44, 94, 64, 0, -1, 41, 42, 43, 44, + 45, 270, 47, -1, -1, -1, 40, -1, 42, 43, + 93, 45, -1, 47, 125, 60, 61, 62, 35, 64, + 91, -1, -1, 94, 41, 42, 43, 44, 45, 35, + 47, -1, -1, -1, -1, 41, 42, 43, 44, 45, + 93, 47, 125, 60, 61, 62, -1, 64, 93, -1, + -1, -1, -1, -1, 60, 61, 62, 91, 64, -1, + 94, -1, -1, -1, -1, -1, -1, -1, -1, 0, + -1, -1, 125, -1, -1, -1, 93, -1, -1, -1, + 125, 40, -1, 42, 43, -1, 45, 93, 47, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 35, 64, -1, -1, 125, -1, + 41, 42, 43, 44, 45, -1, 47, -1, -1, 125, + -1, 297, 298, 299, 300, -1, 302, 302, -1, 60, + 61, 62, 91, 64, -1, 94, -1, 287, -1, -1, + -1, -1, 292, 293, 294, 295, 296, 297, 298, 299, + 300, -1, 302, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 93, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 0, -1, -1, -1, 125, -1, -1, 299, 300, -1, + 302, -1, -1, -1, -1, -1, -1, -1, -1, 292, + 293, 294, 295, 296, 297, 298, 299, 300, -1, -1, + -1, -1, -1, -1, -1, 35, -1, 298, 299, 300, + -1, 302, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, 52, 53, -1, 55, -1, 292, 293, 294, + 295, 296, 297, 298, 299, 300, -1, -1, -1, -1, + 0, -1, -1, -1, -1, 299, 300, 77, 302, -1, + -1, -1, -1, -1, -1, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 0, -1, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 35, -1, -1, -1, -1, + -1, 41, 42, 43, 44, 45, -1, 47, -1, -1, + -1, -1, -1, -1, 0, -1, -1, -1, -1, 35, + 60, 61, 62, -1, 64, 41, 42, 43, 44, 45, + -1, 47, -1, -1, -1, -1, -1, -1, 0, -1, + 299, 300, -1, 302, 60, 61, 62, -1, 64, 35, + -1, 0, -1, 93, -1, 41, -1, 43, 44, 45, + -1, 292, 293, 294, 295, 296, 297, 298, 299, 300, + -1, -1, -1, 35, 60, 61, 62, 93, 64, 41, + -1, 43, 44, 45, -1, 125, 35, -1, 0, -1, + -1, -1, 41, -1, -1, 44, -1, -1, 60, 61, + 62, -1, 64, -1, -1, -1, -1, 93, -1, 125, + 0, 60, 61, 62, -1, 64, -1, 0, -1, -1, + -1, -1, -1, 35, 0, -1, -1, -1, -1, 41, + -1, 93, 44, -1, -1, -1, -1, -1, -1, 125, + -1, -1, -1, -1, 93, 35, -1, 0, 60, 61, + 62, 41, 35, -1, 44, -1, -1, -1, 41, 35, + -1, 44, -1, 125, -1, 41, -1, -1, 44, -1, + 60, 61, 62, -1, -1, -1, 125, 60, 61, 62, + -1, 93, 35, -1, 60, 61, 62, -1, 41, -1, + -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0, 93, -1, -1, -1, 60, 61, 62, + 93, -1, -1, 125, -1, -1, -1, 93, -1, -1, + -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, 125, -1, 35, -1, -1, + 93, -1, 125, 41, -1, -1, 44, -1, -1, 125, + -1, -1, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 35, 60, 61, 62, -1, -1, 41, -1, -1, + 44, -1, 125, -1, -1, -1, 292, 293, 294, 295, + 296, 297, 298, 299, 300, -1, 60, 61, 62, -1, + -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 292, 293, 294, 295, + 296, 297, 298, -1, -1, -1, -1, -1, -1, 93, + -1, -1, -1, -1, -1, -1, -1, 125, 0, -1, + 292, 293, 294, 295, 296, 297, 298, -1, -1, -1, + -1, -1, -1, 292, 293, 294, 295, 296, 297, 298, + -1, 125, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 35, -1, -1, -1, -1, -1, 41, + -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, + 292, 293, 294, 295, 296, 297, 298, 0, 60, 61, + 62, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 292, 293, 294, 295, 296, 297, -1, 292, + 293, 294, 295, 296, -1, -1, 292, 293, 294, 295, + 296, 93, 35, -1, -1, -1, -1, -1, 41, -1, + -1, 44, -1, -1, -1, -1, -1, -1, -1, 292, + 293, 294, 295, 296, -1, -1, -1, 60, 61, 62, + 35, -1, -1, 125, -1, 40, 41, 42, 43, 44, + 45, -1, 47, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 60, 61, 62, 35, 64, + 93, -1, -1, 40, 41, 42, 43, 44, 45, -1, + 47, -1, -1, -1, 292, 293, 294, 295, 296, -1, + -1, -1, -1, 60, 61, 62, 91, 64, -1, 94, + -1, -1, 125, -1, -1, -1, -1, -1, 292, 293, + 294, 295, 296, 35, -1, -1, -1, -1, 40, 41, + 42, 43, -1, 45, 91, 47, -1, 94, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 60, 61, + 62, 35, 64, -1, -1, -1, 40, 41, 42, 43, + -1, 45, -1, 47, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 60, 61, 62, 91, + 64, -1, 94, -1, -1, -1, 35, -1, -1, -1, + -1, 40, 41, 42, 43, -1, 45, -1, 47, -1, + -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, + 94, 60, 61, 62, -1, 64, -1, -1, -1, -1, + 292, 293, 294, 295, 296, -1, -1, -1, 35, -1, + -1, -1, -1, 40, 41, 42, 43, -1, 45, -1, + 47, -1, 91, -1, -1, 94, -1, -1, -1, -1, + -1, -1, -1, 60, 61, 62, -1, 64, -1, -1, + -1, -1, -1, 35, -1, -1, -1, -1, 40, 41, + 42, 43, -1, 45, -1, 47, -1, -1, -1, 292, + 293, 294, 295, 296, 91, -1, -1, 94, 60, 61, + 62, -1, 64, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 292, 293, 294, + 295, 296, 297, 298, 299, 300, -1, 302, -1, 91, + -1, -1, 94, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 35, 302, -1, -1, -1, 40, + 41, 42, 43, -1, 45, -1, 47, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 35, -1, 60, + 61, 62, 40, 64, 42, 43, 44, 45, -1, 47, + 292, 293, 294, 295, 296, 297, 298, 299, 300, -1, + 302, -1, 60, 61, 62, -1, 64, -1, -1, -1, + 91, -1, -1, 94, -1, -1, -1, -1, 292, 293, + 294, 295, 296, 297, 298, 299, 300, -1, 302, -1, + -1, -1, -1, 91, -1, -1, 94, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 35, 302, -1, -1, -1, 40, 41, 42, + 43, -1, 45, -1, 47, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 60, 61, 62, + -1, 64, -1, -1, -1, 292, 293, 294, 295, 296, + 297, 298, 299, 300, -1, 302, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 35, 91, -1, + -1, 94, 40, 41, 42, 43, -1, 45, -1, 47, + 292, 293, 294, 295, 296, 297, 298, 299, 300, -1, + 302, -1, 60, 61, 62, 35, 64, -1, -1, -1, + 40, 41, 42, 43, -1, 45, -1, 47, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 60, 61, 62, 91, 64, -1, 94, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, + -1, 91, -1, 40, 94, 42, 43, 44, 45, -1, + 47, 292, 293, 294, 295, 296, 297, 298, 299, 300, + -1, 302, -1, 60, 61, 62, -1, 64, -1, -1, + -1, -1, -1, -1, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 35, 302, -1, -1, -1, 40, 41, + 42, 43, -1, 45, 91, 47, -1, 94, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 60, 61, + 62, -1, 64, -1, -1, -1, -1, -1, 35, -1, + -1, -1, -1, 40, 41, 42, 43, -1, 45, -1, + 47, -1, -1, -1, -1, -1, -1, -1, -1, 91, + -1, -1, 94, 60, 61, 62, 35, 64, -1, -1, + -1, 40, 41, 42, 43, -1, 45, -1, 47, 292, + 293, 294, 295, 296, 297, 298, 299, 300, -1, 302, + -1, 60, 61, 62, 91, 64, -1, 94, -1, -1, + -1, 35, -1, -1, -1, -1, 40, 41, 42, 43, + -1, 45, -1, 47, -1, -1, -1, -1, -1, -1, + -1, -1, 91, -1, -1, 94, 60, 61, 62, -1, + 64, -1, -1, -1, 292, 293, 294, 295, 296, 297, + 298, 299, 300, -1, 302, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 40, 91, -1, 43, + 94, 45, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 35, 302, -1, -1, -1, 40, 41, 42, 43, + -1, 45, 35, 47, -1, -1, -1, 40, 41, 42, + 43, -1, 45, -1, 47, -1, 60, 61, 62, -1, + 64, -1, -1, -1, -1, -1, -1, 60, 61, 62, + -1, 64, -1, -1, -1, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 35, 302, -1, 91, -1, 40, + 94, 42, 43, -1, 45, -1, 47, -1, 91, 123, + -1, 94, 126, -1, -1, -1, -1, -1, -1, 60, + 61, 62, -1, 64, -1, -1, -1, -1, -1, -1, + 292, 293, 294, 295, 296, 297, 298, 299, 300, -1, + 302, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 91, 35, -1, 94, -1, -1, 40, -1, 42, 43, + -1, 45, -1, 47, -1, 292, 293, 294, 295, 296, + 297, 298, 299, 300, -1, 302, 60, 61, 62, -1, + 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, 293, 294, 295, 296, 297, 298, + 299, 300, -1, 302, -1, -1, -1, 91, 40, -1, + 94, 43, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 292, 293, + 294, 295, 296, 297, 298, 299, 300, -1, 302, -1, + -1, -1, -1, 257, -1, -1, 260, 261, 262, 263, + 264, 265, 266, 267, -1, -1, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, -1, 288, 289, 290, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 303, + -1, 123, -1, -1, 126, -1, -1, -1, 292, 293, + 294, 295, 296, 297, 298, 299, 300, -1, 302, 292, + 293, 294, 295, 296, 297, 298, 299, 300, -1, 302, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 292, 293, 294, 295, 296, 297, 298, 299, 300, + -1, 302, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 293, + 294, 295, 296, 297, 298, 299, 300, -1, 302, -1, + -1, -1, -1, -1, -1, 257, -1, -1, 260, 261, + 262, 263, 264, 265, 266, 267, -1, -1, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 0, 288, 289, 290, -1, + -1, -1, -1, -1, -1, -1, 11, -1, -1, -1, + -1, 303, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 30, -1, 32, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, + 45, -1, -1, 48, 49, 50, 51, -1, -1, 54, + -1, 56, 57, 58, 59, 60, 61, 62, -1, 64, + -1, -1, -1, -1, 69, 70, 71, 72, 73, 74, + 75, 76, -1, 78, 79, 80, 81, 82, 83, 84, + 85, 86, -1, -1, -1, -1, 91, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 113, 114, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 151, -1, -1, -1, + 155, -1, 157, -1, 159, 160, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 173, +}; +#define YYFINAL 36 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 304 +#if YYDEBUG +char *m2_name[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,"'#'",0,0,"'&'",0,"'('","')'","'*'","'+'","','","'-'",0,"'/'",0,0,0,0,0,0,0,0, +0,0,0,0,"'<'","'='","'>'",0,"'@'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,"'['",0,"']'","'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,"'{'",0,"'}'","'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"INT","HEX","ERROR","UINT","M2_TRUE", +"M2_FALSE","CHAR","FLOAT","STRING","NAME","BLOCKNAME","IDENT","VARNAME", +"TYPENAME","SIZE","CAP","ORD","HIGH","ABS","MIN_FUNC","MAX_FUNC","FLOAT_FUNC", +"VAL","CHR","ODD","TRUNC","INC","DEC","INCL","EXCL","COLONCOLON","LAST", +"REGNAME","INTERNAL_VAR","ABOVE_COMMA","ASSIGN","LEQ","GEQ","NOTEQUAL","IN", +"OROR","LOGICAL_AND","DIV","MOD","UNARY","DOT","NOT","QID", +}; +char *m2_rule[] = { +"$accept : start", +"start : exp", +"start : type_exp", +"type_exp : type", +"exp : exp '^'", +"$$1 :", +"exp : '-' $$1 exp", +"exp : '+' exp", +"exp : not_exp exp", +"not_exp : NOT", +"not_exp : '~'", +"exp : CAP '(' exp ')'", +"exp : ORD '(' exp ')'", +"exp : ABS '(' exp ')'", +"exp : HIGH '(' exp ')'", +"exp : MIN_FUNC '(' type ')'", +"exp : MAX_FUNC '(' type ')'", +"exp : FLOAT_FUNC '(' exp ')'", +"exp : VAL '(' type ',' exp ')'", +"exp : CHR '(' exp ')'", +"exp : ODD '(' exp ')'", +"exp : TRUNC '(' exp ')'", +"exp : SIZE exp", +"exp : INC '(' exp ')'", +"exp : INC '(' exp ',' exp ')'", +"exp : DEC '(' exp ')'", +"exp : DEC '(' exp ',' exp ')'", +"exp : exp DOT NAME", +"exp : set", +"exp : exp IN set", +"exp : INCL '(' exp ',' exp ')'", +"exp : EXCL '(' exp ',' exp ')'", +"set : '{' arglist '}'", +"set : type '{' arglist '}'", +"$$2 :", +"exp : exp '[' $$2 non_empty_arglist ']'", +"$$3 :", +"exp : exp '(' $$3 arglist ')'", +"arglist :", +"arglist : exp", +"arglist : arglist ',' exp", +"non_empty_arglist : exp", +"non_empty_arglist : non_empty_arglist ',' exp", +"exp : '{' type '}' exp", +"exp : type '(' exp ')'", +"exp : '(' exp ')'", +"exp : exp '@' exp", +"exp : exp '*' exp", +"exp : exp '/' exp", +"exp : exp DIV exp", +"exp : exp MOD exp", +"exp : exp '+' exp", +"exp : exp '-' exp", +"exp : exp '=' exp", +"exp : exp NOTEQUAL exp", +"exp : exp '#' exp", +"exp : exp LEQ exp", +"exp : exp GEQ exp", +"exp : exp '<' exp", +"exp : exp '>' exp", +"exp : exp LOGICAL_AND exp", +"exp : exp OROR exp", +"exp : exp ASSIGN exp", +"exp : M2_TRUE", +"exp : M2_FALSE", +"exp : INT", +"exp : UINT", +"exp : CHAR", +"exp : FLOAT", +"exp : variable", +"exp : LAST", +"exp : REGNAME", +"exp : SIZE '(' type ')'", +"exp : STRING", +"block : fblock", +"fblock : BLOCKNAME", +"fblock : block COLONCOLON BLOCKNAME", +"variable : fblock", +"variable : INTERNAL_VAR", +"variable : block COLONCOLON NAME", +"variable : NAME", +"type : TYPENAME", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 658 "./m2-exp.y" + +#if 0 /* FIXME! */ +int +overflow(a,b) + long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a; +} + +int +uoverflow(a,b) + unsigned long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a; +} +#endif /* FIXME */ + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register LONGEST n = 0; + register LONGEST prevn = 0; + register int c,i,ischar=0; + register int base = input_radix; + register int len = olen; + int unsigned_p = number_sign == 1 ? 1 : 0; + + if(p[len-1] == 'H') + { + base = 16; + len--; + } + else if(p[len-1] == 'C' || p[len-1] == 'B') + { + base = 8; + ischar = p[len-1] == 'C'; + len--; + } + + /* Scan the number */ + for (c = 0; c < len; c++) + { + if (p[c] == '.' && base == 10) + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + if (p[c] == '.' && base != 10) + error("Floating point numbers must be base 10."); + if (base == 10 && (p[c] < '0' || p[c] > '9')) + error("Invalid digit \'%c\' in number.",p[c]); + } + + while (len-- > 0) + { + c = *p++; + n *= base; + if( base == 8 && (c == '8' || c == '9')) + error("Invalid digit \'%c\' in octal number.",c); + if (c >= '0' && c <= '9') + i = c - '0'; + else + { + if (base == 16 && c >= 'A' && c <= 'F') + i = c - 'A' + 10; + else + return ERROR; + } + n+=i; + if(i >= base) + return ERROR; + if(!unsigned_p && number_sign == 1 && (prevn >= n)) + unsigned_p=1; /* Try something unsigned */ + /* Don't do the range check if n==i and i==0, since that special + case will give an overflow error. */ + if(RANGE_CHECK && n!=i && i) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n) || + ((!unsigned_p && number_sign==-1) && -prevn <= -n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + lexptr = p; + if(*p == 'B' || *p == 'C' || *p == 'H') + lexptr++; /* Advance past B,C or H */ + + if (ischar) + { + yylval.ulval = n; + return CHAR; + } + else if ( unsigned_p && number_sign == 1) + { + yylval.ulval = n; + return UINT; + } + else if((unsigned_p && (n<0))) { + range_error("Overflow on numeric constant -- number too large."); + /* But, this can return if range_check == range_warn. */ + } + yylval.lval = n; + return INT; +} + + +/* Some tokens */ + +static struct +{ + char name[2]; + int token; +} tokentab2[] = +{ + { {'<', '>'}, NOTEQUAL }, + { {':', '='}, ASSIGN }, + { {'<', '='}, LEQ }, + { {'>', '='}, GEQ }, + { {':', ':'}, COLONCOLON }, + +}; + +/* Some specific keywords */ + +struct keyword { + char keyw[10]; + int token; +}; + +static struct keyword keytab[] = +{ + {"OR" , OROR }, + {"IN", IN },/* Note space after IN */ + {"AND", LOGICAL_AND}, + {"ABS", ABS }, + {"CHR", CHR }, + {"DEC", DEC }, + {"NOT", NOT }, + {"DIV", DIV }, + {"INC", INC }, + {"MAX", MAX_FUNC }, + {"MIN", MIN_FUNC }, + {"MOD", MOD }, + {"ODD", ODD }, + {"CAP", CAP }, + {"ORD", ORD }, + {"VAL", VAL }, + {"EXCL", EXCL }, + {"HIGH", HIGH }, + {"INCL", INCL }, + {"SIZE", SIZE }, + {"FLOAT", FLOAT_FUNC }, + {"TRUNC", TRUNC }, +}; + + +/* Read one token, getting characters through lexptr. */ + +/* This is where we will check to make sure that the language and the operators used are + compatible */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + register char quote; + + retry: + + tokstart = lexptr; + + + /* See if it is a special token of length 2 */ + for( i = 0 ; i < sizeof tokentab2 / sizeof tokentab2[0] ; i++) + if(STREQN(tokentab2[i].name, tokstart, 2)) + { + lexptr += 2; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] >= '0' && lexptr[1] <= '9') + break; /* Falls into number code. */ + else + { + lexptr++; + return DOT; + } + +/* These are character tokens that appear as-is in the YACC grammar */ + case '+': + case '-': + case '*': + case '/': + case '^': + case '<': + case '>': + case '[': + case ']': + case '=': + case '{': + case '}': + case '#': + case '@': + case '~': + case '&': + lexptr++; + return c; + + case '\'' : + case '"': + quote = c; + for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + if(c != quote) + error("Unterminated string or character constant."); + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + + if(namelen == 2) /* Single character */ + { + yylval.ulval = tokstart[1]; + return CHAR; + } + else + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9')) + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + register char *p = tokstart; + int toktype; + + for (++p ;; ++p) + { + if (!got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + else if ((*p < '0' || *p > '9') && + (*p < 'A' || *p > 'F') && + (*p != 'H')) /* Modula-2 hexadecimal number */ + break; + } + toktype = parse_number (p - tokstart); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + memcpy (err_copy, tokstart, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && STREQN (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < num_std_regs; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && STREQN (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + + + /* Lookup special keywords */ + for(i = 0 ; i < sizeof(keytab) / sizeof(keytab[0]) ; i++) + if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen)) + return keytab[i].token; + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1); + return INTERNAL_VAR; + } + + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + + + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + + if (lookup_partial_symtab (tmp)) + return BLOCKNAME; + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, 0, NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + + if(sym) + { + switch(sym->class) + { + case LOC_STATIC: + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_CONST: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + return NAME; + + case LOC_TYPEDEF: + return TYPENAME; + + case LOC_BLOCK: + return BLOCKNAME; + + case LOC_UNDEF: + error("internal: Undefined class in m2lex()"); + + case LOC_LABEL: + error("internal: Unforseen case in m2lex()"); + } + } + else + { + /* Built-in BOOLEAN type. This is sort of a hack. */ + if(STREQN(tokstart,"TRUE",4)) + { + yylval.ulval = 1; + return M2_TRUE; + } + else if(STREQN(tokstart,"FALSE",5)) + { + yylval.ulval = 0; + return M2_FALSE; + } + } + + /* Must be another type of name... */ + return NAME; + } +} + +#if 0 /* Unused */ +static char * +make_qualname(mod,ident) + char *mod, *ident; +{ + char *new = xmalloc(strlen(mod)+strlen(ident)+2); + + strcpy(new,mod); + strcat(new,"."); + strcat(new,ident); + return new; +} +#endif /* 0 */ + +void +yyerror(msg) + char *msg; /* unused */ +{ + printf("Parsing: %s\n",lexptr); + if (yychar < 256) + error("Invalid syntax in expression near character '%c'.",yychar); + else + error("Invalid syntax in expression"); +} + +#line 1366 "y.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 3: +#line 197 "./m2-exp.y" +{ write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(yyvsp[0].tval); + write_exp_elt_opcode(OP_TYPE); + } +break; +case 4: +#line 206 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_IND); } +break; +case 5: +#line 209 "./m2-exp.y" +{ number_sign = -1; } +break; +case 6: +#line 211 "./m2-exp.y" +{ number_sign = 1; + write_exp_elt_opcode (UNOP_NEG); } +break; +case 7: +#line 216 "./m2-exp.y" +{ write_exp_elt_opcode(UNOP_PLUS); } +break; +case 8: +#line 220 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); } +break; +case 11: +#line 228 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_CAP); } +break; +case 12: +#line 232 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_ORD); } +break; +case 13: +#line 236 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_ABS); } +break; +case 14: +#line 240 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_HIGH); } +break; +case 15: +#line 244 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_MIN); + write_exp_elt_type (yyvsp[-1].tval); + write_exp_elt_opcode (UNOP_MIN); } +break; +case 16: +#line 250 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_MAX); + write_exp_elt_type (yyvsp[-1].tval); + write_exp_elt_opcode (UNOP_MIN); } +break; +case 17: +#line 256 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_FLOAT); } +break; +case 18: +#line 260 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_VAL); + write_exp_elt_type (yyvsp[-3].tval); + write_exp_elt_opcode (BINOP_VAL); } +break; +case 19: +#line 266 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_CHR); } +break; +case 20: +#line 270 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_ODD); } +break; +case 21: +#line 274 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_TRUNC); } +break; +case 22: +#line 278 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); } +break; +case 23: +#line 283 "./m2-exp.y" +{ write_exp_elt_opcode(UNOP_PREINCREMENT); } +break; +case 24: +#line 287 "./m2-exp.y" +{ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_ADD); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } +break; +case 25: +#line 293 "./m2-exp.y" +{ write_exp_elt_opcode(UNOP_PREDECREMENT);} +break; +case 26: +#line 297 "./m2-exp.y" +{ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_SUB); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } +break; +case 27: +#line 303 "./m2-exp.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); } +break; +case 29: +#line 312 "./m2-exp.y" +{ error("Sets are not implemented.");} +break; +case 30: +#line 316 "./m2-exp.y" +{ error("Sets are not implemented.");} +break; +case 31: +#line 320 "./m2-exp.y" +{ error("Sets are not implemented.");} +break; +case 32: +#line 323 "./m2-exp.y" +{ error("Sets are not implemented.");} +break; +case 33: +#line 325 "./m2-exp.y" +{ error("Sets are not implemented.");} +break; +case 34: +#line 334 "./m2-exp.y" +{ start_arglist(); } +break; +case 35: +#line 336 "./m2-exp.y" +{ write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); } +break; +case 36: +#line 344 "./m2-exp.y" +{ start_arglist (); } +break; +case 37: +#line 346 "./m2-exp.y" +{ write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } +break; +case 39: +#line 355 "./m2-exp.y" +{ arglist_len = 1; } +break; +case 40: +#line 359 "./m2-exp.y" +{ arglist_len++; } +break; +case 41: +#line 364 "./m2-exp.y" +{ arglist_len = 1; } +break; +case 42: +#line 369 "./m2-exp.y" +{ arglist_len++; } +break; +case 43: +#line 374 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); } +break; +case 44: +#line 380 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-3].tval); + write_exp_elt_opcode (UNOP_CAST); } +break; +case 45: +#line 386 "./m2-exp.y" +{ } +break; +case 46: +#line 394 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_REPEAT); } +break; +case 47: +#line 398 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_MUL); } +break; +case 48: +#line 402 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_DIV); } +break; +case 49: +#line 406 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_INTDIV); } +break; +case 50: +#line 410 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_REM); } +break; +case 51: +#line 414 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_ADD); } +break; +case 52: +#line 418 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_SUB); } +break; +case 53: +#line 422 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_EQUAL); } +break; +case 54: +#line 426 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); } +break; +case 55: +#line 428 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); } +break; +case 56: +#line 432 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LEQ); } +break; +case 57: +#line 436 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_GEQ); } +break; +case 58: +#line 440 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LESS); } +break; +case 59: +#line 444 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_GTR); } +break; +case 60: +#line 448 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_AND); } +break; +case 61: +#line 452 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_OR); } +break; +case 62: +#line 456 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); } +break; +case 63: +#line 463 "./m2-exp.y" +{ write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_BOOL); } +break; +case 64: +#line 469 "./m2-exp.y" +{ write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_BOOL); } +break; +case 65: +#line 475 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_int); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LONG); } +break; +case 66: +#line 482 "./m2-exp.y" +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_card); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_LONG); + } +break; +case 67: +#line 491 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_char); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_LONG); } +break; +case 68: +#line 499 "./m2-exp.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_m2_real); + write_exp_elt_dblcst (yyvsp[0].dval); + write_exp_elt_opcode (OP_DOUBLE); } +break; +case 70: +#line 510 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LAST); } +break; +case 71: +#line 516 "./m2-exp.y" +{ write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_REGISTER); } +break; +case 72: +#line 522 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval)); + write_exp_elt_opcode (OP_LONG); } +break; +case 73: +#line 529 "./m2-exp.y" +{ write_exp_elt_opcode (OP_M2_STRING); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_M2_STRING); } +break; +case 74: +#line 536 "./m2-exp.y" +{ yyval.bval = SYMBOL_BLOCK_VALUE(yyvsp[0].sym); } +break; +case 75: +#line 540 "./m2-exp.y" +{ struct symbol *sym + = lookup_symbol (copy_name (yyvsp[0].sval), expression_context_block, + VAR_NAMESPACE, 0, NULL); + yyval.sym = sym;} +break; +case 76: +#line 549 "./m2-exp.y" +{ struct symbol *tem + = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + yyval.sym = tem; + } +break; +case 77: +#line 561 "./m2-exp.y" +{ write_exp_elt_opcode(OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (yyvsp[0].sym); + write_exp_elt_opcode (OP_VAR_VALUE); } +break; +case 78: +#line 569 "./m2-exp.y" +{ write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (yyvsp[0].ivar); + write_exp_elt_opcode (OP_INTERNALVAR); } +break; +case 79: +#line 576 "./m2-exp.y" +{ struct symbol *sym; + sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, 0, NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + + write_exp_elt_opcode (OP_VAR_VALUE); + /* block_found is set by lookup_symbol. */ + write_exp_elt_block (block_found); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } +break; +case 80: +#line 592 "./m2-exp.y" +{ struct symbol *sym; + int is_a_field_of_this; + + sym = lookup_symbol (copy_name (yyvsp[0].sval), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this, + NULL); + if (sym) + { + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not + another more inner frame which happens to + be in the same block. */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name (yyvsp[0].sval); + + msymbol = lookup_minimal_symbol (arg, + (struct objfile *) NULL); + if (msymbol != NULL) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (msymbol -> type == mst_data || + msymbol -> type == mst_bss) + write_exp_elt_type (builtin_type_int); + else if (msymbol -> type == mst_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name (yyvsp[0].sval)); + } + } +break; +case 81: +#line 652 "./m2-exp.y" +{ yyval.tval = lookup_typename (copy_name (yyvsp[0].sval), + expression_context_block, 0); } +break; +#line 1936 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/gnu/usr.bin/gdb/gdb/m2-exp.y b/gnu/usr.bin/gdb/gdb/m2-exp.y new file mode 100644 index 00000000000..cc4001fa984 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/m2-exp.y @@ -0,0 +1,1169 @@ +/* YACC grammar for Modula-2 expressions, for GDB. + Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + Generated from expread.y (now c-exp.y) and contributed by the Department + of Computer Science at the State University of New York at Buffalo, 1991. + +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. */ + +/* Parse a Modula-2 expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. + + Note that malloc's and realloc's in this file are transformed to + xmalloc and xrealloc respectively by the same sed command in the + makefile that remaps any other malloc/realloc inserted by the parser + generator. Doing this with #defines and trying to control the interaction + with include files ( and for example) just became + too messy, particularly when such includes can be inserted at random + times by the parser generator. */ + +%{ + +#include "defs.h" +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "m2-lang.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth m2_maxdepth +#define yyparse m2_parse +#define yylex m2_lex +#define yyerror m2_error +#define yylval m2_lval +#define yychar m2_char +#define yydebug m2_debug +#define yypact m2_pact +#define yyr1 m2_r1 +#define yyr2 m2_r2 +#define yydef m2_def +#define yychk m2_chk +#define yypgo m2_pgo +#define yyact m2_act +#define yyexca m2_exca +#define yyerrflag m2_errflag +#define yynerrs m2_nerrs +#define yyps m2_ps +#define yypv m2_pv +#define yys m2_s +#define yy_yys m2_yys +#define yystate m2_state +#define yytmp m2_tmp +#define yyv m2_v +#define yy_yyv m2_yyv +#define yyval m2_val +#define yylloc m2_lloc +#define yyreds m2_reds /* With YYDEBUG defined */ +#define yytoks m2_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#if 0 +static char * +make_qualname PARAMS ((char *, char *)); +#endif + +static int +parse_number PARAMS ((int)); + +/* The sign of the number being parsed. */ +static int number_sign = 1; + +/* The block that the module specified by the qualifer on an identifer is + contained in, */ +#if 0 +static struct block *modblock=0; +#endif + +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + LONGEST lval; + unsigned LONGEST ulval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%type exp type_exp start set +%type variable +%type type +%type block +%type fblock + +%token INT HEX ERROR +%token UINT M2_TRUE M2_FALSE CHAR +%token FLOAT + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token STRING +%token NAME BLOCKNAME IDENT VARNAME +%token TYPENAME + +%token SIZE CAP ORD HIGH ABS MIN_FUNC MAX_FUNC FLOAT_FUNC VAL CHR ODD TRUNC +%token INC DEC INCL EXCL + +/* The GDB scope operator */ +%token COLONCOLON + +%token LAST REGNAME + +%token INTERNAL_VAR + +/* M2 tokens */ +%left ',' +%left ABOVE_COMMA +%nonassoc ASSIGN +%left '<' '>' LEQ GEQ '=' NOTEQUAL '#' IN +%left OROR +%left LOGICAL_AND '&' +%left '@' +%left '+' '-' +%left '*' '/' DIV MOD +%right UNARY +%right '^' DOT '[' '(' +%right NOT '~' +%left COLONCOLON QID +/* This is not an actual token ; it is used for precedence. +%right QID +*/ + + +%% + +start : exp + | type_exp + ; + +type_exp: type + { write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type($1); + write_exp_elt_opcode(OP_TYPE); + } + ; + +/* Expressions */ + +exp : exp '^' %prec UNARY + { write_exp_elt_opcode (UNOP_IND); } + +exp : '-' + { number_sign = -1; } + exp %prec UNARY + { number_sign = 1; + write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '+' exp %prec UNARY + { write_exp_elt_opcode(UNOP_PLUS); } + ; + +exp : not_exp exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + ; + +not_exp : NOT + | '~' + ; + +exp : CAP '(' exp ')' + { write_exp_elt_opcode (UNOP_CAP); } + ; + +exp : ORD '(' exp ')' + { write_exp_elt_opcode (UNOP_ORD); } + ; + +exp : ABS '(' exp ')' + { write_exp_elt_opcode (UNOP_ABS); } + ; + +exp : HIGH '(' exp ')' + { write_exp_elt_opcode (UNOP_HIGH); } + ; + +exp : MIN_FUNC '(' type ')' + { write_exp_elt_opcode (UNOP_MIN); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_MIN); } + ; + +exp : MAX_FUNC '(' type ')' + { write_exp_elt_opcode (UNOP_MAX); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_MIN); } + ; + +exp : FLOAT_FUNC '(' exp ')' + { write_exp_elt_opcode (UNOP_FLOAT); } + ; + +exp : VAL '(' type ',' exp ')' + { write_exp_elt_opcode (BINOP_VAL); + write_exp_elt_type ($3); + write_exp_elt_opcode (BINOP_VAL); } + ; + +exp : CHR '(' exp ')' + { write_exp_elt_opcode (UNOP_CHR); } + ; + +exp : ODD '(' exp ')' + { write_exp_elt_opcode (UNOP_ODD); } + ; + +exp : TRUNC '(' exp ')' + { write_exp_elt_opcode (UNOP_TRUNC); } + ; + +exp : SIZE exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + + +exp : INC '(' exp ')' + { write_exp_elt_opcode(UNOP_PREINCREMENT); } + ; + +exp : INC '(' exp ',' exp ')' + { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_ADD); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } + ; + +exp : DEC '(' exp ')' + { write_exp_elt_opcode(UNOP_PREDECREMENT);} + ; + +exp : DEC '(' exp ',' exp ')' + { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_SUB); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } + ; + +exp : exp DOT NAME + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : set + ; + +exp : exp IN set + { error("Sets are not implemented.");} + ; + +exp : INCL '(' exp ',' exp ')' + { error("Sets are not implemented.");} + ; + +exp : EXCL '(' exp ',' exp ')' + { error("Sets are not implemented.");} + +set : '{' arglist '}' + { error("Sets are not implemented.");} + | type '{' arglist '}' + { error("Sets are not implemented.");} + ; + + +/* Modula-2 array subscript notation [a,b,c...] */ +exp : exp '[' + /* This function just saves the number of arguments + that follow in the list. It is *not* specific to + function types */ + { start_arglist(); } + non_empty_arglist ']' %prec DOT + { write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec DOT + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +non_empty_arglist + : exp + { arglist_len = 1; } + ; + +non_empty_arglist + : non_empty_arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +/* GDB construct */ +exp : '{' type '}' exp %prec UNARY + { write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_MEMVAL); } + ; + +exp : type '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($1); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : '(' exp ')' + { } + ; + +/* Binary operators in order of decreasing precedence. Note that some + of these operators are overloaded! (ie. sets) */ + +/* GDB construct */ +exp : exp '@' exp + { write_exp_elt_opcode (BINOP_REPEAT); } + ; + +exp : exp '*' exp + { write_exp_elt_opcode (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt_opcode (BINOP_DIV); } + ; + +exp : exp DIV exp + { write_exp_elt_opcode (BINOP_INTDIV); } + ; + +exp : exp MOD exp + { write_exp_elt_opcode (BINOP_REM); } + ; + +exp : exp '+' exp + { write_exp_elt_opcode (BINOP_ADD); } + ; + +exp : exp '-' exp + { write_exp_elt_opcode (BINOP_SUB); } + ; + +exp : exp '=' exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + | exp '#' exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt_opcode (BINOP_LEQ); } + ; + +exp : exp GEQ exp + { write_exp_elt_opcode (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt_opcode (BINOP_GTR); } + ; + +exp : exp LOGICAL_AND exp + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + ; + +exp : exp OROR exp + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + ; + +exp : exp ASSIGN exp + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + + +/* Constants */ + +exp : M2_TRUE + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); } + ; + +exp : M2_FALSE + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); } + ; + +exp : INT + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_int); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : UINT + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_card); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : CHAR + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_char); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_m2_real); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +/* The GDB internal variable $$, et al. */ +exp : LAST + { write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LAST); } + ; + +exp : REGNAME + { write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_REGISTER); } + ; + +exp : SIZE '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : STRING + { write_exp_elt_opcode (OP_M2_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_M2_STRING); } + ; + +/* This will be used for extensions later. Like adding modules. */ +block : fblock + { $$ = SYMBOL_BLOCK_VALUE($1); } + ; + +fblock : BLOCKNAME + { struct symbol *sym + = lookup_symbol (copy_name ($1), expression_context_block, + VAR_NAMESPACE, 0, NULL); + $$ = sym;} + ; + + +/* GDB scope operator */ +fblock : block COLONCOLON BLOCKNAME + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = tem; + } + ; + +/* Useful for assigning to PROCEDURE variables */ +variable: fblock + { write_exp_elt_opcode(OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym ($1); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +/* GDB internal ($foo) variable */ +variable: INTERNAL_VAR + { write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); } + ; + +/* GDB scope operator */ +variable: block COLONCOLON NAME + { struct symbol *sym; + sym = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name ($3)); + + write_exp_elt_opcode (OP_VAR_VALUE); + /* block_found is set by lookup_symbol. */ + write_exp_elt_block (block_found); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +/* Base case for variables. */ +variable: NAME + { struct symbol *sym; + int is_a_field_of_this; + + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this, + NULL); + if (sym) + { + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not + another more inner frame which happens to + be in the same block. */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name ($1); + + msymbol = lookup_minimal_symbol (arg, + (struct objfile *) NULL); + if (msymbol != NULL) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (msymbol -> type == mst_data || + msymbol -> type == mst_bss) + write_exp_elt_type (builtin_type_int); + else if (msymbol -> type == mst_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1)); + } + } + ; + +type + : TYPENAME + { $$ = lookup_typename (copy_name ($1), + expression_context_block, 0); } + + ; + +%% + +#if 0 /* FIXME! */ +int +overflow(a,b) + long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a; +} + +int +uoverflow(a,b) + unsigned long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a; +} +#endif /* FIXME */ + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register LONGEST n = 0; + register LONGEST prevn = 0; + register int c,i,ischar=0; + register int base = input_radix; + register int len = olen; + int unsigned_p = number_sign == 1 ? 1 : 0; + + if(p[len-1] == 'H') + { + base = 16; + len--; + } + else if(p[len-1] == 'C' || p[len-1] == 'B') + { + base = 8; + ischar = p[len-1] == 'C'; + len--; + } + + /* Scan the number */ + for (c = 0; c < len; c++) + { + if (p[c] == '.' && base == 10) + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + if (p[c] == '.' && base != 10) + error("Floating point numbers must be base 10."); + if (base == 10 && (p[c] < '0' || p[c] > '9')) + error("Invalid digit \'%c\' in number.",p[c]); + } + + while (len-- > 0) + { + c = *p++; + n *= base; + if( base == 8 && (c == '8' || c == '9')) + error("Invalid digit \'%c\' in octal number.",c); + if (c >= '0' && c <= '9') + i = c - '0'; + else + { + if (base == 16 && c >= 'A' && c <= 'F') + i = c - 'A' + 10; + else + return ERROR; + } + n+=i; + if(i >= base) + return ERROR; + if(!unsigned_p && number_sign == 1 && (prevn >= n)) + unsigned_p=1; /* Try something unsigned */ + /* Don't do the range check if n==i and i==0, since that special + case will give an overflow error. */ + if(RANGE_CHECK && n!=i && i) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n) || + ((!unsigned_p && number_sign==-1) && -prevn <= -n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + lexptr = p; + if(*p == 'B' || *p == 'C' || *p == 'H') + lexptr++; /* Advance past B,C or H */ + + if (ischar) + { + yylval.ulval = n; + return CHAR; + } + else if ( unsigned_p && number_sign == 1) + { + yylval.ulval = n; + return UINT; + } + else if((unsigned_p && (n<0))) { + range_error("Overflow on numeric constant -- number too large."); + /* But, this can return if range_check == range_warn. */ + } + yylval.lval = n; + return INT; +} + + +/* Some tokens */ + +static struct +{ + char name[2]; + int token; +} tokentab2[] = +{ + { {'<', '>'}, NOTEQUAL }, + { {':', '='}, ASSIGN }, + { {'<', '='}, LEQ }, + { {'>', '='}, GEQ }, + { {':', ':'}, COLONCOLON }, + +}; + +/* Some specific keywords */ + +struct keyword { + char keyw[10]; + int token; +}; + +static struct keyword keytab[] = +{ + {"OR" , OROR }, + {"IN", IN },/* Note space after IN */ + {"AND", LOGICAL_AND}, + {"ABS", ABS }, + {"CHR", CHR }, + {"DEC", DEC }, + {"NOT", NOT }, + {"DIV", DIV }, + {"INC", INC }, + {"MAX", MAX_FUNC }, + {"MIN", MIN_FUNC }, + {"MOD", MOD }, + {"ODD", ODD }, + {"CAP", CAP }, + {"ORD", ORD }, + {"VAL", VAL }, + {"EXCL", EXCL }, + {"HIGH", HIGH }, + {"INCL", INCL }, + {"SIZE", SIZE }, + {"FLOAT", FLOAT_FUNC }, + {"TRUNC", TRUNC }, +}; + + +/* Read one token, getting characters through lexptr. */ + +/* This is where we will check to make sure that the language and the operators used are + compatible */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + register char quote; + + retry: + + tokstart = lexptr; + + + /* See if it is a special token of length 2 */ + for( i = 0 ; i < sizeof tokentab2 / sizeof tokentab2[0] ; i++) + if(STREQN(tokentab2[i].name, tokstart, 2)) + { + lexptr += 2; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] >= '0' && lexptr[1] <= '9') + break; /* Falls into number code. */ + else + { + lexptr++; + return DOT; + } + +/* These are character tokens that appear as-is in the YACC grammar */ + case '+': + case '-': + case '*': + case '/': + case '^': + case '<': + case '>': + case '[': + case ']': + case '=': + case '{': + case '}': + case '#': + case '@': + case '~': + case '&': + lexptr++; + return c; + + case '\'' : + case '"': + quote = c; + for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + if(c != quote) + error("Unterminated string or character constant."); + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + + if(namelen == 2) /* Single character */ + { + yylval.ulval = tokstart[1]; + return CHAR; + } + else + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9')) + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + register char *p = tokstart; + int toktype; + + for (++p ;; ++p) + { + if (!got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + else if ((*p < '0' || *p > '9') && + (*p < 'A' || *p > 'F') && + (*p != 'H')) /* Modula-2 hexadecimal number */ + break; + } + toktype = parse_number (p - tokstart); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + memcpy (err_copy, tokstart, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && STREQN (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < num_std_regs; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && STREQN (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + + + /* Lookup special keywords */ + for(i = 0 ; i < sizeof(keytab) / sizeof(keytab[0]) ; i++) + if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen)) + return keytab[i].token; + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1); + return INTERNAL_VAR; + } + + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + + + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + + if (lookup_partial_symtab (tmp)) + return BLOCKNAME; + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, 0, NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + + if(sym) + { + switch(sym->class) + { + case LOC_STATIC: + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_CONST: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + return NAME; + + case LOC_TYPEDEF: + return TYPENAME; + + case LOC_BLOCK: + return BLOCKNAME; + + case LOC_UNDEF: + error("internal: Undefined class in m2lex()"); + + case LOC_LABEL: + error("internal: Unforseen case in m2lex()"); + } + } + else + { + /* Built-in BOOLEAN type. This is sort of a hack. */ + if(STREQN(tokstart,"TRUE",4)) + { + yylval.ulval = 1; + return M2_TRUE; + } + else if(STREQN(tokstart,"FALSE",5)) + { + yylval.ulval = 0; + return M2_FALSE; + } + } + + /* Must be another type of name... */ + return NAME; + } +} + +#if 0 /* Unused */ +static char * +make_qualname(mod,ident) + char *mod, *ident; +{ + char *new = malloc(strlen(mod)+strlen(ident)+2); + + strcpy(new,mod); + strcat(new,"."); + strcat(new,ident); + return new; +} +#endif /* 0 */ + +void +yyerror(msg) + char *msg; /* unused */ +{ + printf("Parsing: %s\n",lexptr); + if (yychar < 256) + error("Invalid syntax in expression near character '%c'.",yychar); + else + error("Invalid syntax in expression"); +} + diff --git a/gnu/usr.bin/gdb/gdb/m2-lang.c b/gnu/usr.bin/gdb/gdb/m2-lang.c new file mode 100644 index 00000000000..0b678fd9c3c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/m2-lang.c @@ -0,0 +1,457 @@ +/* Modula 2 language support routines for GDB, the GNU debugger. + Copyright 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "m2-lang.h" + +/* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing + characters and strings is language specific. + FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true Modula version. + */ + +static void +emit_char (c, stream, quoter) + register int c; + FILE *stream; + int quoter; +{ + + c &= 0xFF; /* Avoid sign bit follies */ + + if (PRINT_LITERAL_FORM (c)) + { + if (c == '\\' || c == quoter) + { + fputs_filtered ("\\", stream); + } + fprintf_filtered (stream, "%c", c); + } + else + { + switch (c) + { + case '\n': + fputs_filtered ("\\n", stream); + break; + case '\b': + fputs_filtered ("\\b", stream); + break; + case '\t': + fputs_filtered ("\\t", stream); + break; + case '\f': + fputs_filtered ("\\f", stream); + break; + case '\r': + fputs_filtered ("\\r", stream); + break; + case '\033': + fputs_filtered ("\\e", stream); + break; + case '\007': + fputs_filtered ("\\a", stream); + break; + default: + fprintf_filtered (stream, "\\%.3o", (unsigned int) c); + break; + } + } +} + +/* FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true Modula version. */ + +static void +m2_printchar (c, stream) + int c; + FILE *stream; +{ + fputs_filtered ("'", stream); + emit_char (c, stream, '\''); + fputs_filtered ("'", stream); +} + +/* Print the character string STRING, printing at most LENGTH characters. + Printing stops early if the number hits print_max; repeat counts + are printed as appropriate. Print ellipses at the end if we + had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. + FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true Modula version. */ + +static void +m2_printstr (stream, string, length, force_ellipses) + FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; + extern int inspect_it; + extern int repeat_count_threshold; + extern int print_max; + + if (length == 0) + { + fputs_filtered ("\"\"", stdout); + return; + } + + for (i = 0; i < length && things_printed < print_max; ++i) + { + /* Position of the character we are examining + to see whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + QUIT; + + if (need_comma) + { + fputs_filtered (", ", stream); + need_comma = 0; + } + + rep1 = i + 1; + reps = 1; + while (rep1 < length && string[rep1] == string[i]) + { + ++rep1; + ++reps; + } + + if (reps > repeat_count_threshold) + { + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\", ", stream); + else + fputs_filtered ("\", ", stream); + in_quotes = 0; + } + m2_printchar (string[i], stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_comma = 1; + } + else + { + if (!in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + in_quotes = 1; + } + emit_char (string[i], stream, '"'); + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + } + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +/* FIXME: This is a copy of c_create_fundamental_type(), before + all the non-C types were stripped from it. Needs to be fixed + by an experienced Modula programmer. */ + +static struct type * +m2_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "", objfile); + warning ("internal error: no Modula fundamental type %d", typeid); + break; + case FT_VOID: + type = init_type (TYPE_CODE_VOID, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "void", objfile); + break; + case FT_BOOLEAN: + type = init_type (TYPE_CODE_BOOL, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "boolean", objfile); + break; + case FT_STRING: + type = init_type (TYPE_CODE_STRING, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "string", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "char", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "signed char", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned char", objfile); + break; + case FT_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); + break; + case FT_SIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "short", objfile); /* FIXME-fnf */ + break; + case FT_UNSIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned short", objfile); + break; + case FT_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", objfile); + break; + case FT_SIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "int", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", objfile); + break; + case FT_FIXED_DECIMAL: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "fixed decimal", objfile); + break; + case FT_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); + break; + case FT_SIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "long", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", objfile); + break; + case FT_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long long", objfile); + break; + case FT_SIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_SIGNED, "signed long long", objfile); + break; + case FT_UNSIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "float", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "double", objfile); + break; + case FT_FLOAT_DECIMAL: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "floating decimal", objfile); + break; + case FT_EXT_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long double", objfile); + break; + case FT_COMPLEX: + type = init_type (TYPE_CODE_FLT, + TARGET_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "complex", objfile); + break; + case FT_DBL_PREC_COMPLEX: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "double complex", objfile); + break; + case FT_EXT_PREC_COMPLEX: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "long double complex", objfile); + break; + } + return (type); +} + + +/* Table of operators and their precedences for printing expressions. */ + +static const struct op_print m2_op_print_tab[] = { + {"+", BINOP_ADD, PREC_ADD, 0}, + {"+", UNOP_PLUS, PREC_PREFIX, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"DIV", BINOP_INTDIV, PREC_MUL, 0}, + {"MOD", BINOP_REM, PREC_MUL, 0}, + {":=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"=", BINOP_EQUAL, PREC_EQUAL, 0}, + {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {"^", UNOP_IND, PREC_PREFIX, 0}, + {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {NULL, 0, 0, 0} +}; + +/* The built-in types of Modula-2. */ + +struct type *builtin_type_m2_char; +struct type *builtin_type_m2_int; +struct type *builtin_type_m2_card; +struct type *builtin_type_m2_real; +struct type *builtin_type_m2_bool; + +struct type ** const (m2_builtin_types[]) = +{ + &builtin_type_m2_char, + &builtin_type_m2_int, + &builtin_type_m2_card, + &builtin_type_m2_real, + &builtin_type_m2_bool, + 0 +}; + +const struct language_defn m2_language_defn = { + "modula-2", + language_m2, + m2_builtin_types, + range_check_on, + type_check_on, + m2_parse, /* parser */ + m2_error, /* parser error function */ + m2_printchar, /* Print character constant */ + m2_printstr, /* function to print string constant */ + m2_create_fundamental_type, /* Create fundamental type in this language */ + m2_print_type, /* Print a type using appropriate syntax */ + m2_val_print, /* Print a value using appropriate syntax */ + &builtin_type_m2_int, /* longest signed integral type */ + &builtin_type_m2_card, /* longest unsigned integral type */ + &builtin_type_m2_real, /* longest floating point type */ + {"", "", "", ""}, /* Binary format info */ + {"%loB", "", "o", "B"}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0%lXH", "0", "X", "H"}, /* Hex format info */ + m2_op_print_tab, /* expression operators for printing */ + LANG_MAGIC +}; + +/* Initialization for Modula-2 */ + +void +_initialize_m2_language () +{ + /* Modula-2 "pervasive" types. NOTE: these can be redefined!!! */ + builtin_type_m2_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "INTEGER", (struct objfile *) NULL); + builtin_type_m2_card = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "CARDINAL", (struct objfile *) NULL); + builtin_type_m2_real = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "REAL", (struct objfile *) NULL); + builtin_type_m2_char = + init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "CHAR", (struct objfile *) NULL); + builtin_type_m2_bool = + init_type (TYPE_CODE_BOOL, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "BOOLEAN", (struct objfile *) NULL); + + TYPE_NFIELDS(builtin_type_m2_bool) = 2; + TYPE_FIELDS(builtin_type_m2_bool) = + (struct field *) xmalloc (sizeof (struct field) * 2); + TYPE_FIELD_BITPOS(builtin_type_m2_bool,0) = 0; + TYPE_FIELD_NAME(builtin_type_m2_bool,0) = (char *)xmalloc(6); + strcpy(TYPE_FIELD_NAME(builtin_type_m2_bool,0),"FALSE"); + TYPE_FIELD_BITPOS(builtin_type_m2_bool,1) = 1; + TYPE_FIELD_NAME(builtin_type_m2_bool,1) = (char *)xmalloc(5); + strcpy(TYPE_FIELD_NAME(builtin_type_m2_bool,1),"TRUE"); + + add_language (&m2_language_defn); +} diff --git a/gnu/usr.bin/gdb/gdb/m2-lang.h b/gnu/usr.bin/gdb/gdb/m2-lang.h new file mode 100644 index 00000000000..4bc57f5c294 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/m2-lang.h @@ -0,0 +1,31 @@ +/* Modula 2 language support definitions for GDB, the GNU debugger. + Copyright 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. */ + +extern int +m2_parse PARAMS ((void)); /* Defined in m2-exp.y */ + +extern void +m2_error PARAMS ((char *)); /* Defined in m2-exp.y */ + +extern void /* Defined in m2-typeprint.c */ +m2_print_type PARAMS ((struct type *, char *, FILE *, int, int)); + +extern int +m2_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, + int, enum val_prettyprint)); diff --git a/gnu/usr.bin/gdb/gdb/m2-typeprint.c b/gnu/usr.bin/gdb/gdb/m2-typeprint.c new file mode 100644 index 00000000000..ef66a80a8b9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/m2-typeprint.c @@ -0,0 +1,49 @@ +/* Support for printing Modula 2 types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "m2-lang.h" + +#include +#include + +void +m2_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + FILE *stream; + int show; + int level; +{ + extern void c_print_type PARAMS ((struct type *, char *, FILE *, int, int)); + + c_print_type (type, varstring, stream, show, level); /* FIXME */ +} diff --git a/gnu/usr.bin/gdb/gdb/m2-valprint.c b/gnu/usr.bin/gdb/gdb/m2-valprint.c new file mode 100644 index 00000000000..fc17ea50c9a --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/m2-valprint.c @@ -0,0 +1,45 @@ +/* Support for printing Modula 2 values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "valprint.h" + +/* FIXME: For now, just explicitly declare c_val_print and use it instead */ + +int +m2_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + extern int + c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, + int, enum val_prettyprint)); + return (c_val_print (type, valaddr, address, stream, format, deref_ref, + recurse, pretty)); +} diff --git a/gnu/usr.bin/gdb/gdb/main.c b/gnu/usr.bin/gdb/gdb/main.c new file mode 100644 index 00000000000..deaf6240ef9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/main.c @@ -0,0 +1,2799 @@ +/* Top level `main' program for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1990, 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. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "call-cmds.h" +#include "symtab.h" +#include "inferior.h" +#include "signals.h" +#include "target.h" +#include "breakpoint.h" +#include "gdbtypes.h" +#include "expression.h" +#include "language.h" +#include "terminal.h" /* For job_control. */ + +#include "getopt.h" + +/* readline include files */ +#include "readline.h" +#include "history.h" + +/* readline defines this. */ +#undef savestring + +#ifdef USG +#include +#include +#endif + +#include +#ifndef NO_SYS_FILE +#include +#endif +#include +#include +#include +#include + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include + +int original_stack_limit; +#endif + +/* Prototypes for local functions */ + +static char * +symbol_completion_function PARAMS ((char *, int)); + +static void +command_loop PARAMS ((void)); + +static void +command_loop_marker PARAMS ((int)); + +static void +print_gdb_version PARAMS ((FILE *)); + +static void +quit_command PARAMS ((char *, int)); + +static void +init_main PARAMS ((void)); + +static void +init_history PARAMS ((void)); + +static void +init_cmd_lists PARAMS ((void)); + +static void +float_handler PARAMS ((int)); + +static void +source_command PARAMS ((char *, int)); + +static void cd_command PARAMS ((char *, int)); + +static void +print_gnu_advertisement PARAMS ((void)); + +static void +init_signals PARAMS ((void)); + +static void +read_command_file PARAMS ((FILE *)); + +static void +set_verbose PARAMS ((char *, int, struct cmd_list_element *)); + +static void +show_history PARAMS ((char *, int)); + +static void +set_history PARAMS ((char *, int)); + +static void +set_history_size_command PARAMS ((char *, int, struct cmd_list_element *)); + +static void +show_commands PARAMS ((char *, int)); + +static void +echo_command PARAMS ((char *, int)); + +static void +pwd_command PARAMS ((char *, int)); + +static void +show_version PARAMS ((char *, int)); + +static void +document_command PARAMS ((char *, int)); + +static void +define_command PARAMS ((char *, int)); + +static void +validate_comname PARAMS ((char *)); + +static void +help_command PARAMS ((char *, int)); + +static void +show_command PARAMS ((char *, int)); + +static void +info_command PARAMS ((char *, int)); + +static void +do_nothing PARAMS ((int)); + +static int +quit_cover PARAMS ((char *)); + +static void +disconnect PARAMS ((int)); + +static void +source_cleanup PARAMS ((FILE *)); + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) +#endif + +/* Initialization file name for gdb. This is overridden in some configs. */ + +#ifndef GDBINIT_FILENAME +#define GDBINIT_FILENAME ".gdbinit" +#endif +static char gdbinit[] = GDBINIT_FILENAME; +static int inhibit_gdbinit = 0; + +#define ALL_CLEANUPS ((struct cleanup *)0) + +/* Version number of GDB, as a string. */ + +extern char *version; + +/* Canonical host name as a string. */ + +extern char *host_canonical; + +/* Canonical target name as a string. */ + +extern char *target_canonical; + +/* Message to be printed before the error message, when an error occurs. */ + +extern char *error_pre_print; + +/* Message to be printed before the warning message, when a warning occurs. */ + +extern char *warning_pre_print; + +extern char lang_frame_mismatch_warn[]; /* language.c */ + +/* Flag for whether we want all the "from_tty" gubbish printed. */ + +int caution = 1; /* Default is yes, sigh. */ + +/* + * Define all cmd_list_element's + */ + +/* Chain containing all defined commands. */ + +struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +struct cmd_list_element *infolist; + +/* Chain containing all defined enable subcommands. */ + +struct cmd_list_element *enablelist; + +/* Chain containing all defined disable subcommands. */ + +struct cmd_list_element *disablelist; + +/* Chain containing all defined delete subcommands. */ + +struct cmd_list_element *deletelist; + +/* Chain containing all defined "enable breakpoint" subcommands. */ + +struct cmd_list_element *enablebreaklist; + +/* Chain containing all defined set subcommands */ + +struct cmd_list_element *setlist; + +/* Chain containing all defined unset subcommands */ + +struct cmd_list_element *unsetlist; + +/* Chain containing all defined show subcommands. */ + +struct cmd_list_element *showlist; + +/* Chain containing all defined \"set history\". */ + +struct cmd_list_element *sethistlist; + +/* Chain containing all defined \"show history\". */ + +struct cmd_list_element *showhistlist; + +/* Chain containing all defined \"unset history\". */ + +struct cmd_list_element *unsethistlist; + +/* Chain containing all defined maintenance subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenancelist; +#endif + +/* Chain containing all defined "maintenance info" subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenanceinfolist; +#endif + +/* Chain containing all defined "maintenance print" subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenanceprintlist; +#endif + +struct cmd_list_element *setprintlist; + +struct cmd_list_element *showprintlist; + +struct cmd_list_element *setchecklist; + +struct cmd_list_element *showchecklist; + +/* stdio stream that command input is being read from. Set to stdin normally. + Set by source_command to the file we are sourcing. Set to NULL if we are + executing a user-defined command. */ + +FILE *instream; + +/* Current working directory. */ + +char *current_directory; + +/* The directory name is actually stored here (usually). */ +static char dirbuf[1024]; + +/* Function to call before reading a command, if nonzero. + The function receives two args: an input stream, + and a prompt string. */ + +void (*window_hook) PARAMS ((FILE *, char *)); + +extern int mapped_symbol_files; +extern int readnow_symbol_files; + +int epoch_interface; +int xgdb_verbose; + +/* gdb prints this when reading a command interactively */ +static char *prompt; + +/* Buffer used for reading command lines, and the size + allocated for it so far. */ + +char *line; +int linesize = 100; + +/* Baud rate specified for talking to serial target systems. Default + is left as -1, so targets can choose their own defaults. */ + +int baud_rate = -1; + +/* Non-zero tells remote* modules to output debugging info. */ + +int remote_debug = 0; + +/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */ + +#ifndef STOP_SIGNAL +#ifdef SIGTSTP +#define STOP_SIGNAL SIGTSTP +static void stop_sig PARAMS ((int)); +#endif +#endif + +/* Some System V have job control but not sigsetmask(). */ +#if !defined (HAVE_SIGSETMASK) +#define HAVE_SIGSETMASK !defined (USG) +#endif + +#if 0 == (HAVE_SIGSETMASK) +#define sigsetmask(n) +#endif + +/* Where to go for return_to_top_level (RETURN_ERROR). */ +static jmp_buf error_return; +/* Where to go for return_to_top_level (RETURN_QUIT). */ +static jmp_buf quit_return; + +/* Temporary variable for SET_TOP_LEVEL. */ +static int top_level_val; + +/* Do a setjmp on error_return and quit_return. catch_errors is + generally a cleaner way to do this, but main() would look pretty + ugly if it had to use catch_errors each time. */ + +#define SET_TOP_LEVEL() \ + (((top_level_val = setjmp (error_return)) \ + ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \ + , top_level_val) + +/* Return for reason REASON. This generally gets back to the command + loop, but can be caught via catch_errors. */ + +NORETURN void +return_to_top_level (reason) + enum return_reason reason; +{ + quit_flag = 0; + immediate_quit = 0; + + /* Perhaps it would be cleaner to do this via the cleanup chain (not sure + I can think of a reason why that is vital, though). */ + bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */ + + disable_current_display (); + do_cleanups (ALL_CLEANUPS); + (NORETURN void) longjmp + (reason == RETURN_ERROR ? error_return : quit_return, 1); +} + +/* Call FUNC with arg ARGS, catching any errors. If there is no + error, return the value returned by FUNC. If there is an error, + print ERRSTRING, print the specific error message, then return + zero. + + Must not be called with immediate_quit in effect (bad things might + happen, say we got a signal in the middle of a memcpy to quit_return). + This is an OK restriction; with very few exceptions immediate_quit can + be replaced by judicious use of QUIT. + + MASK specifies what to catch; it is normally set to + RETURN_MASK_ALL, if for no other reason than that the code which + calls catch_errors might not be set up to deal with a quit which + isn't caught. But if the code can deal with it, it generally + should be RETURN_MASK_ERROR, unless for some reason it is more + useful to abort only the portion of the operation inside the + catch_errors. Note that quit should return to the command line + fairly quickly, even if some further processing is being done. */ + +int +catch_errors (func, args, errstring, mask) + int (*func) PARAMS ((char *)); + PTR args; + char *errstring; + return_mask mask; +{ + jmp_buf saved_error; + jmp_buf saved_quit; + jmp_buf tmp_jmp; + int val; + struct cleanup *saved_cleanup_chain; + char *saved_error_pre_print; + + saved_cleanup_chain = save_cleanups (); + saved_error_pre_print = error_pre_print; + + if (mask & RETURN_MASK_ERROR) + memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (saved_quit, quit_return, sizeof (jmp_buf)); + error_pre_print = errstring; + + if (setjmp (tmp_jmp) == 0) + { + if (mask & RETURN_MASK_ERROR) + memcpy (error_return, tmp_jmp, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (quit_return, tmp_jmp, sizeof (jmp_buf)); + val = (*func) (args); + } + else + val = 0; + + restore_cleanups (saved_cleanup_chain); + + error_pre_print = saved_error_pre_print; + if (mask & RETURN_MASK_ERROR) + memcpy (error_return, saved_error, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (quit_return, saved_quit, sizeof (jmp_buf)); + return val; +} + +/* Handler for SIGHUP. */ + +static void +disconnect (signo) +int signo; +{ + catch_errors (quit_cover, NULL, + "Could not kill the program being debugged", RETURN_MASK_ALL); + signal (SIGHUP, SIG_DFL); + kill (getpid (), SIGHUP); +} + +/* Just a little helper function for disconnect(). */ + +static int +quit_cover (s) +char *s; +{ + caution = 0; /* Throw caution to the wind -- we're exiting. + This prevents asking the user dumb questions. */ + quit_command((char *)0, 0); + return 0; +} + +/* Clean up on error during a "source" command (or execution of a + user-defined command). */ + +static void +source_cleanup (stream) + FILE *stream; +{ + /* Restore the previous input stream. */ + instream = stream; +} + +/* Read commands from STREAM. */ +static void +read_command_file (stream) + FILE *stream; +{ + struct cleanup *cleanups; + + cleanups = make_cleanup (source_cleanup, instream); + instream = stream; + command_loop (); + do_cleanups (cleanups); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + int count; + static int quiet = 0; + static int batch = 0; + + /* Pointers to various arguments from command line. */ + char *symarg = NULL; + char *execarg = NULL; + char *corearg = NULL; + char *cdarg = NULL; + char *ttyarg = NULL; + + /* These are static so that we can take their address in an initializer. */ + static int print_help; + static int print_version; + + /* Pointers to all arguments of --command option. */ + char **cmdarg; + /* Allocated size of cmdarg. */ + int cmdsize; + /* Number of elements of cmdarg used. */ + int ncmd; + + /* Indices of all arguments of --directory option. */ + char **dirarg; + /* Allocated size. */ + int dirsize; + /* Number of elements used. */ + int ndir; + + struct stat homebuf, cwdbuf; + char *homedir, *homeinit; + + register int i; + + /* This needs to happen before the first use of malloc. */ + init_malloc ((PTR) NULL); + +#if defined (ALIGN_STACK_ON_STARTUP) + i = (int) &count & 0x3; + if (i != 0) + alloca (4 - i); +#endif + + /* If error() is called from initialization code, just exit */ + if (SET_TOP_LEVEL ()) { + exit(1); + } + + cmdsize = 1; + cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg)); + ncmd = 0; + dirsize = 1; + dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg)); + ndir = 0; + + quit_flag = 0; + line = (char *) xmalloc (linesize); + line[0] = '\0'; /* Terminate saved (now empty) cmd line */ + instream = stdin; + + getcwd (dirbuf, sizeof (dirbuf)); + current_directory = dirbuf; + +#ifdef SET_STACK_LIMIT_HUGE + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca (particularly stringtab + * in dbxread.c) does not fail. */ + getrlimit (RLIMIT_STACK, &rlim); + original_stack_limit = rlim.rlim_cur; + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* SET_STACK_LIMIT_HUGE */ + + /* Parse arguments and options. */ + { + int c; + /* When var field is 0, use flag field to record the equivalent + short option (or arbitrary numbers starting at 10 for those + with no equivalent). */ + static struct option long_options[] = + { + {"readnow", no_argument, &readnow_symbol_files, 1}, + {"r", no_argument, &readnow_symbol_files, 1}, + {"mapped", no_argument, &mapped_symbol_files, 1}, + {"m", no_argument, &mapped_symbol_files, 1}, + {"quiet", no_argument, &quiet, 1}, + {"q", no_argument, &quiet, 1}, + {"silent", no_argument, &quiet, 1}, + {"nx", no_argument, &inhibit_gdbinit, 1}, + {"n", no_argument, &inhibit_gdbinit, 1}, + {"batch", no_argument, &batch, 1}, + {"epoch", no_argument, &epoch_interface, 1}, + {"fullname", no_argument, &frame_file_full_name, 1}, + {"f", no_argument, &frame_file_full_name, 1}, + {"help", no_argument, &print_help, 1}, + {"se", required_argument, 0, 10}, + {"symbols", required_argument, 0, 's'}, + {"s", required_argument, 0, 's'}, + {"exec", required_argument, 0, 'e'}, + {"e", required_argument, 0, 'e'}, + {"core", required_argument, 0, 'c'}, + {"c", required_argument, 0, 'c'}, + {"command", required_argument, 0, 'x'}, + {"version", no_argument, &print_version, 1}, + {"x", required_argument, 0, 'x'}, + {"directory", required_argument, 0, 'd'}, + {"cd", required_argument, 0, 11}, + {"tty", required_argument, 0, 't'}, + {"baud", required_argument, 0, 'b'}, + {"b", required_argument, 0, 'b'}, +/* Allow machine descriptions to add more options... */ +#ifdef ADDITIONAL_OPTIONS + ADDITIONAL_OPTIONS +#endif + {0, no_argument, 0, 0}, + }; + + while (1) + { + int option_index; + + c = getopt_long_only (argc, argv, "", + long_options, &option_index); + if (c == EOF) + break; + + /* Long option that takes an argument. */ + if (c == 0 && long_options[option_index].flag == 0) + c = long_options[option_index].val; + + switch (c) + { + case 0: + /* Long option that just sets a flag. */ + break; + case 10: + symarg = optarg; + execarg = optarg; + break; + case 11: + cdarg = optarg; + break; + case 's': + symarg = optarg; + break; + case 'e': + execarg = optarg; + break; + case 'c': + corearg = optarg; + break; + case 'x': + cmdarg[ncmd++] = optarg; + if (ncmd >= cmdsize) + { + cmdsize *= 2; + cmdarg = (char **) xrealloc ((char *)cmdarg, + cmdsize * sizeof (*cmdarg)); + } + break; + case 'd': + dirarg[ndir++] = optarg; + if (ndir >= dirsize) + { + dirsize *= 2; + dirarg = (char **) xrealloc ((char *)dirarg, + dirsize * sizeof (*dirarg)); + } + break; + case 't': + ttyarg = optarg; + break; + case 'q': + quiet = 1; + break; + case 'b': + { + int i; + char *p; + + i = strtol (optarg, &p, 0); + if (i == 0 && p == optarg) + warning ("Could not set baud rate to `%s'.\n", optarg); + else + baud_rate = i; + } + break; + +#ifdef ADDITIONAL_OPTION_CASES + ADDITIONAL_OPTION_CASES +#endif + case '?': + fprintf (stderr, + "Use `%s --help' for a complete list of options.\n", + argv[0]); + exit (1); + } + } + + /* OK, that's all the options. The other arguments are filenames. */ + count = 0; + for (; optind < argc; optind++) + switch (++count) + { + case 1: + symarg = argv[optind]; + execarg = argv[optind]; + break; + case 2: + corearg = argv[optind]; + break; + case 3: + fprintf (stderr, + "Excess command line arguments ignored. (%s%s)\n", + argv[optind], (optind == argc - 1) ? "" : " ..."); + break; + } + if (batch) + quiet = 1; + } + + /* Run the init function of each source file */ + + init_cmd_lists (); /* This needs to be done first */ + initialize_all_files (); + init_main (); /* But that omits this file! Do it now */ + init_signals (); + + /* Do these (and anything which might call wrap_here or *_filtered) + after initialize_all_files. */ + if (print_version) + { + print_gdb_version (stdout); + wrap_here (""); + printf_filtered ("\n"); + exit (0); + } + + if (print_help) + { + /* --version is intentionally not documented here, because we + are printing the version here, and the help is long enough + already. */ + + print_gdb_version (stdout); + /* Make sure the output gets printed. */ + wrap_here (""); + printf_filtered ("\n"); + + /* But don't use *_filtered here. We don't want to prompt for continue + no matter how small the screen or how much we're going to print. */ + fputs ("\ +This is the GNU debugger. Usage:\n\ + gdb [options] [executable-file [core-file or process-id]]\n\ +Options:\n\ + --help Print this message.\n\ + --quiet Do not print version number on startup.\n\ + --fullname Output information used by emacs-GDB interface.\n\ + --epoch Output information used by epoch emacs-GDB interface.\n\ + --batch Exit after processing options.\n\ + --nx Do not read .gdbinit file.\n\ + --tty=TTY Use TTY for input/output by the program being debugged.\n\ + --cd=DIR Change current directory to DIR.\n\ + --directory=DIR Search for source files in DIR.\n\ + --command=FILE Execute GDB commands from FILE.\n\ + --symbols=SYMFILE Read symbols from SYMFILE.\n\ + --exec=EXECFILE Use EXECFILE as the executable.\n\ + --se=FILE Use FILE as symbol file and executable file.\n\ + --core=COREFILE Analyze the core dump COREFILE.\n\ + -b BAUDRATE Set serial port baud rate used for remote debugging.\n\ + --mapped Use mapped symbol files if supported on this system.\n\ + --readnow Fully read symbol files on first access.\n\ +", stdout); +#ifdef ADDITIONAL_OPTION_HELP + fputs (ADDITIONAL_OPTION_HELP, stdout); +#endif + fputs ("\n\ +For more information, type \"help\" from within GDB, or consult the\n\ +GDB manual (available as on-line info or a printed manual).\n", stdout); + exit (0); + } + + if (!quiet) + { + /* Print all the junk at the top, with trailing "..." if we are about + to read a symbol file (possibly slowly). */ + print_gnu_advertisement (); + print_gdb_version (stdout); + if (symarg) + printf_filtered (".."); + wrap_here(""); + fflush (stdout); /* Force to screen during slow operations */ + } + + error_pre_print = "\n\n"; + /* We may get more than one warning, don't double space all of them... */ + warning_pre_print = "\nwarning: "; + + /* We need a default language for parsing expressions, so simple things like + "set width 0" won't fail if no language is explicitly set in a config file + or implicitly set by reading an executable during startup. */ + set_language (language_c); + expected_language = current_language; /* don't warn about the change. */ + + /* Read and execute $HOME/.gdbinit file, if it exists. This is done + *before* all the command line arguments are processed; it sets + global parameters, which are independent of what file you are + debugging or what directory you are in. */ + homedir = getenv ("HOME"); + if (homedir) + { + homeinit = (char *) alloca (strlen (getenv ("HOME")) + + strlen (gdbinit) + 10); + strcpy (homeinit, getenv ("HOME")); + strcat (homeinit, "/"); + strcat (homeinit, gdbinit); + if (!inhibit_gdbinit && access (homeinit, R_OK) == 0) + { + if (!SET_TOP_LEVEL ()) + source_command (homeinit, 0); + } + do_cleanups (ALL_CLEANUPS); + + /* Do stats; no need to do them elsewhere since we'll only + need them if homedir is set. Make sure that they are + zero in case one of them fails (this guarantees that they + won't match if either exists). */ + + memset (&homebuf, 0, sizeof (struct stat)); + memset (&cwdbuf, 0, sizeof (struct stat)); + + stat (homeinit, &homebuf); + stat (gdbinit, &cwdbuf); /* We'll only need this if + homedir was set. */ + } + + /* Now perform all the actions indicated by the arguments. */ + if (cdarg != NULL) + { + if (!SET_TOP_LEVEL ()) + { + cd_command (cdarg, 0); + init_source_path (); + } + } + do_cleanups (ALL_CLEANUPS); + + for (i = 0; i < ndir; i++) + if (!SET_TOP_LEVEL ()) + directory_command (dirarg[i], 0); + free ((PTR)dirarg); + do_cleanups (ALL_CLEANUPS); + + if (execarg != NULL + && symarg != NULL + && STREQ (execarg, symarg)) + { + /* The exec file and the symbol-file are the same. If we can't open + it, better only print one error message. */ + if (!SET_TOP_LEVEL ()) + { + exec_file_command (execarg, !batch); + symbol_file_command (symarg, 0); + } + } + else + { + if (execarg != NULL) + if (!SET_TOP_LEVEL ()) + exec_file_command (execarg, !batch); + if (symarg != NULL) + if (!SET_TOP_LEVEL ()) + symbol_file_command (symarg, 0); + } + do_cleanups (ALL_CLEANUPS); + + /* After the symbol file has been read, print a newline to get us + beyond the copyright line... But errors should still set off + the error message with a (single) blank line. */ + if (!quiet) + printf_filtered ("\n"); + error_pre_print = "\n"; + warning_pre_print = "\nwarning: "; + + if (corearg != NULL) + if (!SET_TOP_LEVEL ()) + core_file_command (corearg, !batch); + else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ()) + attach_command (corearg, !batch); + do_cleanups (ALL_CLEANUPS); + + if (ttyarg != NULL) + if (!SET_TOP_LEVEL ()) + tty_command (ttyarg, !batch); + do_cleanups (ALL_CLEANUPS); + +#ifdef ADDITIONAL_OPTION_HANDLER + ADDITIONAL_OPTION_HANDLER; +#endif + + /* Error messages should no longer be distinguished with extra output. */ + error_pre_print = 0; + warning_pre_print = "warning: "; + + /* Read the .gdbinit file in the current directory, *if* it isn't + the same as the $HOME/.gdbinit file (it should exist, also). */ + + if (!homedir + || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat))) + if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0) + { + if (!SET_TOP_LEVEL ()) + source_command (gdbinit, 0); + } + do_cleanups (ALL_CLEANUPS); + + for (i = 0; i < ncmd; i++) + { + if (!SET_TOP_LEVEL ()) + { + if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0') + read_command_file (stdin); + else + source_command (cmdarg[i], !batch); + do_cleanups (ALL_CLEANUPS); + } + } + free ((PTR)cmdarg); + + /* Read in the old history after all the command files have been read. */ + init_history(); + + if (batch) + { + /* We have hit the end of the batch file. */ + exit (0); + } + + /* Do any host- or target-specific hacks. This is used for i960 targets + to force the user to set a nindy target and spec its parameters. */ + +#ifdef BEFORE_MAIN_LOOP_HOOK + BEFORE_MAIN_LOOP_HOOK; +#endif + + /* The command loop. */ + + while (1) + { + if (!SET_TOP_LEVEL ()) + { + do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */ + command_loop (); + quit_command ((char *)0, instream == stdin); + } + } + /* No exit -- exit is through quit_command. */ +} + +void +execute_user_command (c, args) + struct cmd_list_element *c; + char *args; +{ + register struct command_line *cmdlines; + struct cleanup *old_chain; + + if (args) + error ("User-defined commands cannot take arguments."); + + cmdlines = c->user_commands; + if (cmdlines == 0) + /* Null command */ + return; + + /* Set the instream to 0, indicating execution of a + user-defined function. */ + old_chain = make_cleanup (source_cleanup, instream); + instream = (FILE *) 0; + while (cmdlines) + { + execute_command (cmdlines->line, 0); + cmdlines = cmdlines->next; + } + do_cleanups (old_chain); +} + +/* Execute the line P as a command. + Pass FROM_TTY as second argument to the defining function. */ + +void +execute_command (p, from_tty) + char *p; + int from_tty; +{ + register struct cmd_list_element *c; + register enum language flang; + static int warned = 0; + + free_all_values (); + + /* This can happen when command_line_input hits end of file. */ + if (p == NULL) + return; + + while (*p == ' ' || *p == '\t') p++; + if (*p) + { + char *arg; + + c = lookup_cmd (&p, cmdlist, "", 0, 1); + /* Pass null arg rather than an empty one. */ + arg = *p ? p : 0; + + /* If this command has been hooked, run the hook first. */ + if (c->hook) + execute_user_command (c->hook, (char *)0); + + if (c->class == class_user) + execute_user_command (c, arg); + else if (c->type == set_cmd || c->type == show_cmd) + do_setshow_command (arg, from_tty & caution, c); + else if (c->function.cfunc == NO_FUNCTION) + error ("That is not a command, just a help topic."); + else + (*c->function.cfunc) (arg, from_tty & caution); + } + + /* Tell the user if the language has changed (except first time). */ + if (current_language != expected_language) + { + if (language_mode == language_mode_auto) { + language_info (1); /* Print what changed. */ + } + warned = 0; + } + + /* Warn the user if the working language does not match the + language of the current frame. Only warn the user if we are + actually running the program, i.e. there is a stack. */ + /* FIXME: This should be cacheing the frame and only running when + the frame changes. */ + if (target_has_stack) + { + flang = get_frame_language (); + if (!warned + && flang != language_unknown + && flang != current_language->la_language) + { + printf_filtered ("%s\n", lang_frame_mismatch_warn); + warned = 1; + } + } +} + +/* ARGSUSED */ +static void +command_loop_marker (foo) + int foo; +{ +} + +/* Read commands from `instream' and execute them + until end of file or error reading instream. */ +static void +command_loop () +{ + struct cleanup *old_chain; + char *command; + int stdin_is_tty = ISATTY (stdin); + + while (!feof (instream)) + { + if (window_hook && instream == stdin) + (*window_hook) (instream, prompt); + + quit_flag = 0; + if (instream == stdin && stdin_is_tty) + reinitialize_more_filter (); + old_chain = make_cleanup (command_loop_marker, 0); + command = command_line_input (instream == stdin ? prompt : (char *) NULL, + instream == stdin); + if (command == 0) + return; + execute_command (command, instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + bpstat_do_actions (&stop_bpstat); + do_cleanups (old_chain); + } +} + +/* Commands call this if they do not want to be repeated by null lines. */ + +void +dont_repeat () +{ + /* If we aren't reading from standard input, we are saving the last + thing read from stdin in line and don't want to delete it. Null lines + won't repeat here in any case. */ + if (instream == stdin) + *line = 0; +} + +/* Read a line from the stream "instream" without command line editing. + + It prints PRROMPT once at the start. + Action is compatible with "readline", e.g. space for the result is + malloc'd and should be freed by the caller. + + A NULL return means end of file. */ +char * +gdb_readline (prrompt) + char *prrompt; +{ + int c; + char *result; + int input_index = 0; + int result_size = 80; + + if (prrompt) + { + /* Don't use a _filtered function here. It causes the assumed + character position to be off, since the newline we read from + the user is not accounted for. */ + fputs (prrompt, stdout); + fflush (stdout); + } + + result = (char *) xmalloc (result_size); + + while (1) + { + /* Read from stdin if we are executing a user defined command. + This is the right thing for prompt_for_continue, at least. */ + c = fgetc (instream ? instream : stdin); + + if (c == EOF) + { + if (input_index > 0) + /* The last line does not end with a newline. Return it, and + if we are called again fgetc will still return EOF and + we'll return NULL then. */ + break; + free (result); + return NULL; + } + + if (c == '\n') + break; + + result[input_index++] = c; + while (input_index >= result_size) + { + result_size *= 2; + result = (char *) xrealloc (result, result_size); + } + } + + result[input_index++] = '\0'; + return result; +} + +/* Variables which control command line editing and history + substitution. These variables are given default values at the end + of this file. */ +static int command_editing_p; +static int history_expansion_p; +static int write_history_p; +static int history_size; +static char *history_filename; + +/* readline uses the word breaks for two things: + (1) In figuring out where to point the TEXT parameter to the + rl_completion_entry_function. Since we don't use TEXT for much, + it doesn't matter a lot what the word breaks are for this purpose, but + it does affect how much stuff M-? lists. + (2) If one of the matches contains a word break character, readline + will quote it. That's why we switch between + gdb_completer_word_break_characters and + gdb_completer_command_word_break_characters. I'm not sure when + we need this behavior (perhaps for funky characters in C++ symbols?). */ + +/* Variables which are necessary for fancy command line editing. */ +char *gdb_completer_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-"; + +/* When completing on command names, we remove '-' from the list of + word break characters, since we use it in command names. If the + readline library sees one in any of the current completion strings, + it thinks that the string needs to be quoted and automatically supplies + a leading quote. */ +char *gdb_completer_command_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,"; + +/* Characters that can be used to quote completion strings. Note that we + can't include '"' because the gdb C parser treats such quoted sequences + as strings. */ +char *gdb_completer_quote_characters = + "'"; + +/* Functions that are used as part of the fancy command line editing. */ + +/* This can be used for functions which don't want to complete on symbols + but don't want to complete on anything else either. */ +/* ARGSUSED */ +char ** +noop_completer (text, prefix) + char *text; + char *prefix; +{ + return NULL; +} + +/* Complete on filenames. */ +char ** +filename_completer (text, word) + char *text; + char *word; +{ + /* From readline. */ + extern char *filename_completion_function (); + int subsequent_name; + char **return_val; + int return_val_used; + int return_val_alloced; + + return_val_used = 0; + /* Small for testing. */ + return_val_alloced = 1; + return_val = (char **) xmalloc (return_val_alloced * sizeof (char *)); + + subsequent_name = 0; + while (1) + { + char *p; + p = filename_completion_function (text, subsequent_name); + if (return_val_used >= return_val_alloced) + { + return_val_alloced *= 2; + return_val = + (char **) xrealloc (return_val, + return_val_alloced * sizeof (char *)); + } + if (p == NULL) + { + return_val[return_val_used++] = p; + break; + } + /* Like emacs, don't complete on old versions. Especially useful + in the "source" command. */ + if (p[strlen (p) - 1] == '~') + continue; + + { + char *q; + if (word == text) + /* Return exactly p. */ + return_val[return_val_used++] = p; + else if (word > text) + { + /* Return some portion of p. */ + q = xmalloc (strlen (p) + 5); + strcpy (q, p + (word - text)); + return_val[return_val_used++] = q; + free (p); + } + else + { + /* Return some of TEXT plus p. */ + q = xmalloc (strlen (p) + (text - word) + 5); + strncpy (q, word, text - word); + q[text - word] = '\0'; + strcat (q, p); + return_val[return_val_used++] = q; + free (p); + } + } + subsequent_name = 1; + } +#if 0 + /* There is no way to do this just long enough to affect quote inserting + without also affecting the next completion. This should be fixed in + readline. FIXME. */ + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = ""; +#endif + return return_val; +} + +/* Here are some useful test cases for completion. FIXME: These should + be put in the test suite. They should be tested with both M-? and TAB. + + "show output-" "radix" + "show output" "-radix" + "p" ambiguous (commands starting with p--path, print, printf, etc.) + "p " ambiguous (all symbols) + "info t foo" no completions + "info t " no completions + "info t" ambiguous ("info target", "info terminal", etc.) + "info ajksdlfk" no completions + "info ajksdlfk " no completions + "info" " " + "info " ambiguous (all info commands) + "p \"a" no completions (string constant) + "p 'a" ambiguous (all symbols starting with a) + "p b-a" ambiguous (all symbols starting with a) + "p b-" ambiguous (all symbols) + "file Make" "file" (word break hard to screw up here) + "file ../gdb.stabs/wi" "erd" (needs to not break word at slash) + */ + +/* Generate completions one by one for the completer. Each time we are + called return another potential completion to the caller. The function + is misnamed; it just completes on commands or passes the buck to the + command's completer function; the stuff specific to symbol completion + is in make_symbol_completion_list. + + TEXT is readline's idea of the "word" we are looking at; we don't really + like readline's ideas about word breaking so we ignore it. + + MATCHES is the number of matches that have currently been collected from + calling this completion function. When zero, then we need to initialize, + otherwise the initialization has already taken place and we can just + return the next potential completion string. + + Returns NULL if there are no more completions, else a pointer to a string + which is a possible completion. + + RL_LINE_BUFFER is available to be looked at; it contains the entire text + of the line. RL_POINT is the offset in that line of the cursor. You + should pretend that the line ends at RL_POINT. */ + +static char * +symbol_completion_function (text, matches) + char *text; + int matches; +{ + static char **list = (char **)NULL; /* Cache of completions */ + static int index; /* Next cached completion */ + char *output = NULL; + char *tmp_command, *p; + /* Pointer within tmp_command which corresponds to text. */ + char *word; + struct cmd_list_element *c, *result_list; + extern char *rl_line_buffer; + extern int rl_point; + + if (matches == 0) + { + /* The caller is beginning to accumulate a new set of completions, so + we need to find all of them now, and cache them for returning one at + a time on future calls. */ + + if (list) + { + /* Free the storage used by LIST, but not by the strings inside. + This is because rl_complete_internal () frees the strings. */ + free ((PTR)list); + } + list = 0; + index = 0; + + /* Choose the default set of word break characters to break completions. + If we later find out that we are doing completions on command strings + (as opposed to strings supplied by the individual command completer + functions, which can be any string) then we will switch to the + special word break set for command strings, which leaves out the + '-' character used in some commands. */ + + rl_completer_word_break_characters = + gdb_completer_word_break_characters; + + /* Decide whether to complete on a list of gdb commands or on symbols. */ + tmp_command = (char *) alloca (rl_point + 1); + p = tmp_command; + + strncpy (tmp_command, rl_line_buffer, rl_point); + tmp_command[rl_point] = '\0'; + /* Since text always contains some number of characters leading up + to rl_point, we can find the equivalent position in tmp_command + by subtracting that many characters from the end of tmp_command. */ + word = tmp_command + rl_point - strlen (text); + + if (rl_point == 0) + { + /* An empty line we want to consider ambiguous; that is, it + could be any command. */ + c = (struct cmd_list_element *) -1; + result_list = 0; + } + else + { + c = lookup_cmd_1 (&p, cmdlist, &result_list, 1); + } + + /* Move p up to the next interesting thing. */ + while (*p == ' ' || *p == '\t') + { + p++; + } + + if (!c) + { + /* It is an unrecognized command. So there are no + possible completions. */ + list = NULL; + } + else if (c == (struct cmd_list_element *) -1) + { + char *q; + + /* lookup_cmd_1 advances p up to the first ambiguous thing, but + doesn't advance over that thing itself. Do so now. */ + q = p; + while (*q && (isalnum (*q) || *q == '-' || *q == '_')) + ++q; + if (q != tmp_command + rl_point) + { + /* There is something beyond the ambiguous + command, so there are no possible completions. For + example, "info t " or "info t foo" does not complete + to anything, because "info t" can be "info target" or + "info terminal". */ + list = NULL; + } + else + { + /* We're trying to complete on the command which was ambiguous. + This we can deal with. */ + if (result_list) + { + list = complete_on_cmdlist (*result_list->prefixlist, p, + word); + } + else + { + list = complete_on_cmdlist (cmdlist, p, word); + } + /* Insure that readline does the right thing with respect to + inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + } + else + { + /* We've recognized a full command. */ + + if (p == tmp_command + rl_point) + { + /* There is no non-whitespace in the line beyond the command. */ + + if (p[-1] == ' ' || p[-1] == '\t') + { + /* The command is followed by whitespace; we need to complete + on whatever comes after command. */ + if (c->prefixlist) + { + /* It is a prefix command; what comes after it is + a subcommand (e.g. "info "). */ + list = complete_on_cmdlist (*c->prefixlist, p, word); + + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + else + { + /* It is a normal command; what comes after it is + completed by the command's completer function. */ + list = (*c->completer) (p, word); + } + } + else + { + /* The command is not followed by whitespace; we need to + complete on the command itself. e.g. "p" which is a + command itself but also can complete to "print", "ptype" + etc. */ + char *q; + + /* Find the command we are completing on. */ + q = p; + while (q > tmp_command) + { + if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_') + --q; + else + break; + } + + list = complete_on_cmdlist (result_list, q, word); + + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + } + else + { + /* There is non-whitespace beyond the command. */ + + if (c->prefixlist && !c->allow_unknown) + { + /* It is an unrecognized subcommand of a prefix command, + e.g. "info adsfkdj". */ + list = NULL; + } + else + { + /* It is a normal command. */ + list = (*c->completer) (p, word); + } + } + } + } + + /* If we found a list of potential completions during initialization then + dole them out one at a time. The vector of completions is NULL + terminated, so after returning the last one, return NULL (and continue + to do so) each time we are called after that, until a new list is + available. */ + + if (list) + { + output = list[index]; + if (output) + { + index++; + } + } + +#if 0 + /* Can't do this because readline hasn't yet checked the word breaks + for figuring out whether to insert a quote. */ + if (output == NULL) + /* Make sure the word break characters are set back to normal for the + next time that readline tries to complete something. */ + rl_completer_word_break_characters = + gdb_completer_word_break_characters; +#endif + + return (output); +} + +/* Skip over a possibly quoted word (as defined by the quote characters + and word break characters the completer uses). Returns pointer to the + location after the "word". */ + +char * +skip_quoted (str) + char *str; +{ + char quote_char = '\0'; + char *scan; + + for (scan = str; *scan != '\0'; scan++) + { + if (quote_char != '\0') + { + /* Ignore everything until the matching close quote char */ + if (*scan == quote_char) + { + /* Found matching close quote. */ + scan++; + break; + } + } + else if (strchr (gdb_completer_quote_characters, *scan)) + { + /* Found start of a quoted string. */ + quote_char = *scan; + } + else if (strchr (gdb_completer_word_break_characters, *scan)) + { + break; + } + } + return (scan); +} + + +#ifdef STOP_SIGNAL +static void +stop_sig (signo) +int signo; +{ +#if STOP_SIGNAL == SIGTSTP + signal (SIGTSTP, SIG_DFL); + sigsetmask (0); + kill (getpid (), SIGTSTP); + signal (SIGTSTP, stop_sig); +#else + signal (STOP_SIGNAL, stop_sig); +#endif + printf ("%s", prompt); + fflush (stdout); + + /* Forget about any previous command -- null line now will do nothing. */ + dont_repeat (); +} +#endif /* STOP_SIGNAL */ + +/* Initialize signal handlers. */ +static void +do_nothing (signo) +int signo; +{ +} + +static void +init_signals () +{ + signal (SIGINT, request_quit); + + /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get + passed to the inferior, which we don't want. It would be + possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but + on BSD4.3 systems using vfork, that can affect the + GDB process as well as the inferior (the signal handling tables + might be in memory, shared between the two). Since we establish + a handler for SIGQUIT, when we call exec it will set the signal + to SIG_DFL for us. */ + signal (SIGQUIT, do_nothing); + if (signal (SIGHUP, do_nothing) != SIG_IGN) + signal (SIGHUP, disconnect); + signal (SIGFPE, float_handler); + +#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) + signal (SIGWINCH, SIGWINCH_HANDLER); +#endif +} + +/* Read one line from the command input stream `instream' + into the local static buffer `linebuffer' (whose current length + is `linelength'). + The buffer is made bigger as necessary. + Returns the address of the start of the line. + + NULL is returned for end of file. + + *If* the instream == stdin & stdin is a terminal, the line read + is copied into the file line saver (global var char *line, + length linesize) so that it can be duplicated. + + This routine either uses fancy command line editing or + simple input as the user has requested. */ + +char * +command_line_input (prrompt, repeat) + char *prrompt; + int repeat; +{ + static char *linebuffer = 0; + static unsigned linelength = 0; + register char *p; + char *p1; + char *rl; + char *local_prompt = prrompt; + register int c; + char *nline; + char got_eof = 0; + + if (linebuffer == 0) + { + linelength = 80; + linebuffer = (char *) xmalloc (linelength); + } + + p = linebuffer; + + /* Control-C quits instantly if typed while in this loop + since it should not wait until the user types a newline. */ + immediate_quit++; +#ifdef STOP_SIGNAL + if (job_control) + signal (STOP_SIGNAL, stop_sig); +#endif + + while (1) + { + /* Reports are that some Sys V's don't flush stdout/err on reads + from stdin, when stdin/out are sockets rather than ttys. So we + have to do it ourselves, to make emacs-gdb and xxgdb work. + On other machines, doing this once per input should be a cheap nop. */ + fflush (stdout); + fflush (stderr); + + /* Don't use fancy stuff if not talking to stdin. */ + if (command_editing_p && instream == stdin + && ISATTY (instream)) + rl = readline (local_prompt); + else + rl = gdb_readline (local_prompt); + + if (!rl || rl == (char *) EOF) + { + got_eof = 1; + break; + } + if (strlen(rl) + 1 + (p - linebuffer) > linelength) + { + linelength = strlen(rl) + 1 + (p - linebuffer); + nline = (char *) xrealloc (linebuffer, linelength); + p += nline - linebuffer; + linebuffer = nline; + } + p1 = rl; + /* Copy line. Don't copy null at end. (Leaves line alone + if this was just a newline) */ + while (*p1) + *p++ = *p1++; + + free (rl); /* Allocated in readline. */ + + if (p == linebuffer || *(p - 1) != '\\') + break; + + p--; /* Put on top of '\'. */ + local_prompt = (char *) 0; + } + +#ifdef STOP_SIGNAL + if (job_control) + signal (STOP_SIGNAL, SIG_DFL); +#endif + immediate_quit--; + + if (got_eof) + return NULL; + + /* Do history expansion if that is wished. */ + if (history_expansion_p && instream == stdin + && ISATTY (instream)) + { + char *history_value; + int expanded; + + *p = '\0'; /* Insert null now. */ + expanded = history_expand (linebuffer, &history_value); + if (expanded) + { + /* Print the changes. */ + printf ("%s\n", history_value); + + /* If there was an error, call this function again. */ + if (expanded < 0) + { + free (history_value); + return command_line_input (prrompt, repeat); + } + if (strlen (history_value) > linelength) + { + linelength = strlen (history_value) + 1; + linebuffer = (char *) xrealloc (linebuffer, linelength); + } + strcpy (linebuffer, history_value); + p = linebuffer + strlen(linebuffer); + free (history_value); + } + } + + /* If we just got an empty line, and that is supposed + to repeat the previous command, return the value in the + global buffer. */ + if (repeat) + { + if (p == linebuffer) + return line; + p1 = linebuffer; + while (*p1 == ' ' || *p1 == '\t') + p1++; + if (!*p1) + return line; + } + + *p = 0; + + /* Add line to history if appropriate. */ + if (instream == stdin + && ISATTY (stdin) && *linebuffer) + add_history (linebuffer); + + /* Note: lines consisting soley of comments are added to the command + history. This is useful when you type a command, and then + realize you don't want to execute it quite yet. You can comment + out the command and then later fetch it from the value history + and remove the '#'. The kill ring is probably better, but some + people are in the habit of commenting things out. */ + p1 = linebuffer; + while ((c = *p1++) != '\0') + { + if (c == '"') + while ((c = *p1++) != '"') + { + /* Make sure an escaped '"' doesn't make us think the string + is ended. */ + if (c == '\\') + parse_escape (&p1); + if (c == '\0') + break; + } + else if (c == '\'') + while ((c = *p1++) != '\'') + { + /* Make sure an escaped '\'' doesn't make us think the string + is ended. */ + if (c == '\\') + parse_escape (&p1); + if (c == '\0') + break; + } + else if (c == '#') + { + /* Found a comment. */ + p1[-1] = '\0'; + break; + } + } + + /* Save into global buffer if appropriate. */ + if (repeat) + { + if (linelength > linesize) + { + line = xrealloc (line, linelength); + linesize = linelength; + } + strcpy (line, linebuffer); + return line; + } + + return linebuffer; +} + +/* Read lines from the input stream + and accumulate them in a chain of struct command_line's + which is then returned. */ + +struct command_line * +read_command_lines () +{ + struct command_line *first = 0; + register struct command_line *next, *tail = 0; + register char *p, *p1; + struct cleanup *old_chain = 0; + + while (1) + { + dont_repeat (); + p = command_line_input ((char *) NULL, instream == stdin); + if (p == NULL) + /* Treat end of file like "end". */ + break; + + /* Remove leading and trailing blanks. */ + while (*p == ' ' || *p == '\t') p++; + p1 = p + strlen (p); + while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--; + + /* Is this "end"? */ + if (p1 - p == 3 && !strncmp (p, "end", 3)) + break; + + /* No => add this line to the chain of command lines. */ + next = (struct command_line *) xmalloc (sizeof (struct command_line)); + next->line = savestring (p, p1 - p); + next->next = 0; + if (tail) + { + tail->next = next; + } + else + { + /* We just read the first line. + From now on, arrange to throw away the lines we have + if we quit or get an error while inside this function. */ + first = next; + old_chain = make_cleanup (free_command_lines, &first); + } + tail = next; + } + + dont_repeat (); + + /* Now we are about to return the chain to our caller, + so freeing it becomes his responsibility. */ + if (first) + discard_cleanups (old_chain); + return first; +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines (lptr) + struct command_line **lptr; +{ + register struct command_line *l = *lptr; + register struct command_line *next; + + while (l) + { + next = l->next; + free (l->line); + free ((PTR)l); + l = next; + } +} + +/* Add an element to the list of info subcommands. */ + +void +add_info (name, fun, doc) + char *name; + void (*fun) PARAMS ((char *, int)); + char *doc; +{ + add_cmd (name, no_class, fun, doc, &infolist); +} + +/* Add an alias to the list of info subcommands. */ + +void +add_info_alias (name, oldname, abbrev_flag) + char *name; + char *oldname; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); +} + +/* The "info" command is defined as a prefix, with allow_unknown = 0. + Therefore, its own definition is called only for "info" with no args. */ + +/* ARGSUSED */ +static void +info_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf ("\"info\" must be followed by the name of an info command.\n"); + help_list (infolist, "info ", -1, stdout); +} + +/* The "show" command with no arguments shows all the settings. */ + +/* ARGSUSED */ +static void +show_command (arg, from_tty) + char *arg; + int from_tty; +{ + cmd_show_list (showlist, from_tty, ""); +} + +/* Add an element to the list of commands. */ + +void +add_com (name, class, fun, doc) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; +{ + add_cmd (name, class, fun, doc, &cmdlist); +} + +/* Add an alias or abbreviation command to the list of commands. */ + +void +add_com_alias (name, oldname, class, abbrev_flag) + char *name; + char *oldname; + enum command_class class; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist); +} + +void +error_no_arg (why) + char *why; +{ + error ("Argument required (%s).", why); +} + +/* ARGSUSED */ +static void +help_command (command, from_tty) + char *command; + int from_tty; /* Ignored */ +{ + help_cmd (command, stdout); +} + +static void +validate_comname (comname) + char *comname; +{ + register char *p; + + if (comname == 0) + error_no_arg ("name of command to define"); + + p = comname; + while (*p) + { + if (!isalnum(*p) && *p != '-') + error ("Junk in argument list: \"%s\"", p); + p++; + } +} + +/* This is just a placeholder in the command data structures. */ +static void +user_defined_command (ignore, from_tty) + char *ignore; + int from_tty; +{ +} + +static void +define_command (comname, from_tty) + char *comname; + int from_tty; +{ + register struct command_line *cmds; + register struct cmd_list_element *c, *newc, *hookc = 0; + char *tem = comname; +#define HOOK_STRING "hook-" +#define HOOK_LEN 5 + + validate_comname (comname); + + /* Look it up, and verify that we got an exact match. */ + c = lookup_cmd (&tem, cmdlist, "", -1, 1); + if (c && !STREQ (comname, c->name)) + c = 0; + + if (c) + { + if (c->class == class_user || c->class == class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, c->name)) + error ("Command \"%s\" not redefined.", c->name); + } + + /* If this new command is a hook, then mark the command which it + is hooking. Note that we allow hooking `help' commands, so that + we can hook the `stop' pseudo-command. */ + + if (!strncmp (comname, HOOK_STRING, HOOK_LEN)) + { + /* Look up cmd it hooks, and verify that we got an exact match. */ + tem = comname+HOOK_LEN; + hookc = lookup_cmd (&tem, cmdlist, "", -1, 0); + if (hookc && !STREQ (comname+HOOK_LEN, hookc->name)) + hookc = 0; + if (!hookc) + { + warning ("Your new `%s' command does not hook any existing command.", + comname); + if (!query ("Proceed? ", (char *)0)) + error ("Not confirmed."); + } + } + + comname = savestring (comname, strlen (comname)); + + /* If the rest of the commands will be case insensitive, this one + should behave in the same manner. */ + for (tem = comname; *tem; tem++) + if (isupper(*tem)) *tem = tolower(*tem); + + if (from_tty) + { + printf ("Type commands for definition of \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + fflush (stdout); + } + + cmds = read_command_lines (); + + if (c && c->class == class_user) + free_command_lines (&c->user_commands); + + newc = add_cmd (comname, class_user, user_defined_command, + (c && c->class == class_user) + ? c->doc : savestring ("User-defined.", 13), &cmdlist); + newc->user_commands = cmds; + + /* If this new command is a hook, then mark both commands as being + tied. */ + if (hookc) + { + hookc->hook = newc; /* Target gets hooked. */ + newc->hookee = hookc; /* We are marked as hooking target cmd. */ + } +} + +static void +document_command (comname, from_tty) + char *comname; + int from_tty; +{ + struct command_line *doclines; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", 0, 1); + + if (c->class != class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf ("Type documentation for \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + doclines = read_command_lines (); + + if (c->doc) free (c->doc); + + { + register struct command_line *cl1; + register int len = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + len += strlen (cl1->line) + 1; + + c->doc = (char *) xmalloc (len + 1); + *c->doc = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + { + strcat (c->doc, cl1->line); + if (cl1->next) + strcat (c->doc, "\n"); + } + } + + free_command_lines (&doclines); +} + +static void +print_gnu_advertisement() +{ + printf ("\ +GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"show copying\" to see the conditions.\n\ +There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\ +"); +} + +static void +print_gdb_version (stream) + FILE *stream; +{ + fprintf_filtered (stream, "\ +GDB %s (%s", version, host_canonical); + + if (strcmp(host_canonical, target_canonical)) + fprintf_filtered (stream, " --target %s", target_canonical); + + fprintf_filtered (stream, "), "); + wrap_here(""); + fprintf_filtered (stream, "Copyright 1993 Free Software Foundation, Inc."); +} + +/* ARGSUSED */ +static void +show_version (args, from_tty) + char *args; + int from_tty; +{ + immediate_quit++; + print_gnu_advertisement (); + print_gdb_version (stdout); + printf_filtered ("\n"); + immediate_quit--; +} + +/* xgdb calls this to reprint the usual GDB prompt. */ + +void +print_prompt () +{ + printf ("%s", prompt); + fflush (stdout); +} + +static void +quit_command (args, from_tty) + char *args; + int from_tty; +{ + if (inferior_pid != 0 && target_has_execution) + { + if (attach_flag) + { + if (query ("The program is running. Quit anyway (and detach it)? ")) + target_detach (args, from_tty); + else + error ("Not confirmed."); + } + else + { + if (query ("The program is running. Quit anyway (and kill it)? ")) + target_kill (); + else + error ("Not confirmed."); + } + } + /* Save the history information if it is appropriate to do so. */ + if (write_history_p && history_filename) + write_history (history_filename); + exit (0); +} + +/* Returns whether GDB is running on a terminal and whether the user + desires that questions be asked of them on that terminal. */ + +int +input_from_terminal_p () +{ + return gdb_has_a_terminal () && (instream == stdin) & caution; +} + +/* ARGSUSED */ +static void +pwd_command (args, from_tty) + char *args; + int from_tty; +{ + if (args) error ("The \"pwd\" command does not take an argument: %s", args); + getcwd (dirbuf, sizeof (dirbuf)); + + if (!STREQ (dirbuf, current_directory)) + printf ("Working directory %s\n (canonically %s).\n", + current_directory, dirbuf); + else + printf ("Working directory %s.\n", current_directory); +} + +static void +cd_command (dir, from_tty) + char *dir; + int from_tty; +{ + int len; + /* Found something other than leading repetitions of "/..". */ + int found_real_path; + char *p; + + /* If the new directory is absolute, repeat is a no-op; if relative, + repeat might be useful but is more likely to be a mistake. */ + dont_repeat (); + + if (dir == 0) + error_no_arg ("new working directory"); + + dir = tilde_expand (dir); + make_cleanup (free, dir); + + if (chdir (dir) < 0) + perror_with_name (dir); + + len = strlen (dir); + dir = savestring (dir, len - (len > 1 && dir[len-1] == '/')); + if (dir[0] == '/') + current_directory = dir; + else + { + if (current_directory[0] == '/' && current_directory[1] == '\0') + current_directory = concat (current_directory, dir, NULL); + else + current_directory = concat (current_directory, "/", dir, NULL); + free (dir); + } + + /* Now simplify any occurrences of `.' and `..' in the pathname. */ + + found_real_path = 0; + for (p = current_directory; *p;) + { + if (p[0] == '/' && p[1] == '.' && (p[2] == 0 || p[2] == '/')) + strcpy (p, p + 2); + else if (p[0] == '/' && p[1] == '.' && p[2] == '.' + && (p[3] == 0 || p[3] == '/')) + { + if (found_real_path) + { + /* Search backwards for the directory just before the "/.." + and obliterate it and the "/..". */ + char *q = p; + while (q != current_directory && q[-1] != '/') + --q; + + if (q == current_directory) + /* current_directory is + a relative pathname ("can't happen"--leave it alone). */ + ++p; + else + { + strcpy (q - 1, p + 3); + p = q - 1; + } + } + else + /* We are dealing with leading repetitions of "/..", for example + "/../..", which is the Mach super-root. */ + p += 3; + } + else + { + found_real_path = 1; + ++p; + } + } + + forget_cached_source_info (); + + if (from_tty) + pwd_command ((char *) 0, 1); +} + +/* ARGSUSED */ +static void +source_command (args, from_tty) + char *args; + int from_tty; +{ + FILE *stream; + struct cleanup *cleanups; + char *file = args; + + if (file == NULL) + { + error ("source command requires pathname of file to source."); + } + + file = tilde_expand (file); + make_cleanup (free, file); + + stream = fopen (file, FOPEN_RT); + if (stream == 0) + perror_with_name (file); + + cleanups = make_cleanup (fclose, stream); + + read_command_file (stream); + + do_cleanups (cleanups); +} + +/* ARGSUSED */ +static void +echo_command (text, from_tty) + char *text; + int from_tty; +{ + char *p = text; + register int c; + + if (text) + while ((c = *p++) != '\0') + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + return; + + c = parse_escape (&p); + if (c >= 0) + printf_filtered ("%c", c); + } + else + printf_filtered ("%c", c); + } + + /* Force this output to appear now. */ + wrap_here (""); + fflush (stdout); +} + + +/* Functions to manipulate command line editing control variables. */ + +/* Number of commands to print in each call to show_commands. */ +#define Hist_print 10 +static void +show_commands (args, from_tty) + char *args; + int from_tty; +{ + /* Index for history commands. Relative to history_base. */ + int offset; + + /* Number of the history entry which we are planning to display next. + Relative to history_base. */ + static int num = 0; + + /* The first command in the history which doesn't exist (i.e. one more + than the number of the last command). Relative to history_base. */ + int hist_len; + + extern struct _hist_entry *history_get PARAMS ((int)); + extern int history_base; + + /* Print out some of the commands from the command history. */ + /* First determine the length of the history list. */ + hist_len = history_size; + for (offset = 0; offset < history_size; offset++) + { + if (!history_get (history_base + offset)) + { + hist_len = offset; + break; + } + } + + if (args) + { + if (args[0] == '+' && args[1] == '\0') + /* "info editing +" should print from the stored position. */ + ; + else + /* "info editing " should print around command number . */ + num = (parse_and_eval_address (args) - history_base) - Hist_print / 2; + } + /* "show commands" means print the last Hist_print commands. */ + else + { + num = hist_len - Hist_print; + } + + if (num < 0) + num = 0; + + /* If there are at least Hist_print commands, we want to display the last + Hist_print rather than, say, the last 6. */ + if (hist_len - num < Hist_print) + { + num = hist_len - Hist_print; + if (num < 0) + num = 0; + } + + for (offset = num; offset < num + Hist_print && offset < hist_len; offset++) + { + printf_filtered ("%5d %s\n", history_base + offset, + (history_get (history_base + offset))->line); + } + + /* The next command we want to display is the next one that we haven't + displayed yet. */ + num += Hist_print; + + /* If the user repeats this command with return, it should do what + "show commands +" does. This is unnecessary if arg is null, + because "show commands +" is not useful after "show commands". */ + if (from_tty && args) + { + args[0] = '+'; + args[1] = '\0'; + } +} + +/* Called by do_setshow_command. */ +/* ARGSUSED */ +static void +set_history_size_command (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + if (history_size == INT_MAX) + unstifle_history (); + else if (history_size >= 0) + stifle_history (history_size); + else + { + history_size = INT_MAX; + error ("History size must be non-negative"); + } +} + +/* ARGSUSED */ +static void +set_history (args, from_tty) + char *args; + int from_tty; +{ + printf ("\"set history\" must be followed by the name of a history subcommand.\n"); + help_list (sethistlist, "set history ", -1, stdout); +} + +/* ARGSUSED */ +static void +show_history (args, from_tty) + char *args; + int from_tty; +{ + cmd_show_list (showhistlist, from_tty, ""); +} + +int info_verbose = 0; /* Default verbose msgs off */ + +/* Called by do_setshow_command. An elaborate joke. */ +/* ARGSUSED */ +static void +set_verbose (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + char *cmdname = "verbose"; + struct cmd_list_element *showcmd; + + showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1); + + if (info_verbose) + { + c->doc = "Set verbose printing of informational messages."; + showcmd->doc = "Show verbose printing of informational messages."; + } + else + { + c->doc = "Set verbosity."; + showcmd->doc = "Show verbosity."; + } +} + +static void +float_handler (signo) +int signo; +{ + /* This message is based on ANSI C, section 4.7. Note that integer + divide by zero causes this, so "float" is a misnomer. */ + signal (SIGFPE, float_handler); + error ("Erroneous arithmetic operation."); +} + +/* Return whether we are running a batch file or from terminal. */ +int +batch_mode () +{ + return !(instream == stdin && ISATTY (stdin)); +} + + +static void +init_cmd_lists () +{ + cmdlist = NULL; + infolist = NULL; + enablelist = NULL; + disablelist = NULL; + deletelist = NULL; + enablebreaklist = NULL; + setlist = NULL; + unsetlist = NULL; + showlist = NULL; + sethistlist = NULL; + showhistlist = NULL; + unsethistlist = NULL; +#if MAINTENANCE_CMDS + maintenancelist = NULL; + maintenanceinfolist = NULL; + maintenanceprintlist = NULL; +#endif + setprintlist = NULL; + showprintlist = NULL; + setchecklist = NULL; + showchecklist = NULL; +} + +/* Init the history buffer. Note that we are called after the init file(s) + * have been read so that the user can change the history file via his + * .gdbinit file (for instance). The GDBHISTFILE environment variable + * overrides all of this. + */ + +static void +init_history() +{ + char *tmpenv; + + tmpenv = getenv ("HISTSIZE"); + if (tmpenv) + history_size = atoi (tmpenv); + else if (!history_size) + history_size = 256; + + stifle_history (history_size); + + tmpenv = getenv ("GDBHISTFILE"); + if (tmpenv) + history_filename = savestring (tmpenv, strlen(tmpenv)); + else if (!history_filename) { + /* We include the current directory so that if the user changes + directories the file written will be the same as the one + that was read. */ + history_filename = concat (current_directory, "/.gdb_history", NULL); + } + read_history (history_filename); +} + +static void +init_main () +{ + struct cmd_list_element *c; + +#ifdef DEFAULT_PROMPT + prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); +#else + prompt = savestring ("(gdb) ", 6); +#endif + + /* Set the important stuff up for command editing. */ + command_editing_p = 1; + history_expansion_p = 0; + write_history_p = 0; + + /* Setup important stuff for command line editing. */ + rl_completion_entry_function = (int (*)()) symbol_completion_function; + rl_completer_word_break_characters = gdb_completer_word_break_characters; + rl_completer_quote_characters = gdb_completer_quote_characters; + rl_readline_name = "gdb"; + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + + add_cmd ("internals", class_maintenance, NO_FUNCTION, + "Maintenance commands.\n\ +Some gdb commands are provided just for use by gdb maintainers.\n\ +These commands are subject to frequent change, and may not be as\n\ +well documented as user commands.", + &cmdlist); + add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist); + add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist); + add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\ +The commands in this class are those defined by the user.\n\ +Use the \"define\" command to define a command.", &cmdlist); + add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\ +The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ +counting from zero for the innermost (currently executing) frame.\n\n\ +At any time gdb identifies one frame as the \"selected\" frame.\n\ +Variable lookups are done with respect to the selected frame.\n\ +When the program being debugged stops, gdb selects the innermost frame.\n\ +The commands below can be used to select other frames by number or address.", + &cmdlist); + add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist); + + add_com ("pwd", class_files, pwd_command, + "Print working directory. This is used for your program as well."); + c = add_cmd ("cd", class_files, cd_command, + "Set working directory to DIR for debugger and program being debugged.\n\ +The change does not take effect for the program being debugged\n\ +until the next time it is started.", &cmdlist); + c->completer = filename_completer; + + add_show_from_set + (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt, + "Set gdb's prompt", + &setlist), + &showlist); + + add_com ("echo", class_support, echo_command, + "Print a constant string. Give string as argument.\n\ +C escape sequences may be used in the argument.\n\ +No newline is added at the end of the argument;\n\ +use \"\\n\" if you want a newline to be printed.\n\ +Since leading and trailing whitespace are ignored in command arguments,\n\ +if you want to print some you must use \"\\\" before leading whitespace\n\ +to be printed or after trailing whitespace."); + add_com ("document", class_support, document_command, + "Document a user-defined command.\n\ +Give command name as argument. Give documentation on following lines.\n\ +End with a line of just \"end\"."); + add_com ("define", class_support, define_command, + "Define a new command name. Command name is argument.\n\ +Definition appears on following lines, one command per line.\n\ +End with a line of just \"end\".\n\ +Use the \"document\" command to give documentation for the new command.\n\ +Commands defined in this way do not take arguments."); + +#ifdef __STDC__ + c = add_cmd ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\ +when gdb is started.", &cmdlist); +#else + /* Punt file name, we can't help it easily. */ + c = add_cmd ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \".gdbinit\" is read automatically in this way\n\ +when gdb is started.", &cmdlist); +#endif + c->completer = filename_completer; + + add_com ("quit", class_support, quit_command, "Exit gdb."); + add_com ("help", class_support, help_command, "Print list of commands."); + add_com_alias ("q", "quit", class_support, 1); + add_com_alias ("h", "help", class_support, 1); + + + c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose, + "Set ", + &setlist), + add_show_from_set (c, &showlist); + c->function.sfunc = set_verbose; + set_verbose (NULL, 0, c); + + add_show_from_set + (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p, + "Set editing of command lines as they are typed.\n\ +Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\ +Without an argument, command line editing is enabled. To edit, use\n\ +EMACS-like or VI-like commands like control-P or ESC.", &setlist), + &showlist); + + add_prefix_cmd ("history", class_support, set_history, + "Generic command for setting command history parameters.", + &sethistlist, "set history ", 0, &setlist); + add_prefix_cmd ("history", class_support, show_history, + "Generic command for showing command history parameters.", + &showhistlist, "show history ", 0, &showlist); + + add_show_from_set + (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p, + "Set history expansion on command input.\n\ +Without an argument, history expansion is enabled.", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("save", no_class, var_boolean, (char *)&write_history_p, + "Set saving of the history record on exit.\n\ +Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\ +Without an argument, saving is enabled.", &sethistlist), + &showhistlist); + + c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size, + "Set the size of the command history, \n\ +ie. the number of previous commands to keep a record of.", &sethistlist); + add_show_from_set (c, &showhistlist); + c->function.sfunc = set_history_size_command; + + add_show_from_set + (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename, + "Set the filename in which to record the command history\n\ + (the list of previous commands of which a record is kept).", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("confirm", class_support, var_boolean, + (char *)&caution, + "Set whether to confirm potentially dangerous operations.", + &setlist), + &showlist); + + add_prefix_cmd ("info", class_info, info_command, + "Generic command for showing things about the program being debugged.", + &infolist, "info ", 0, &cmdlist); + add_com_alias ("i", "info", class_info, 1); + + add_prefix_cmd ("show", class_info, show_command, + "Generic command for showing things about the debugger.", + &showlist, "show ", 0, &cmdlist); + /* Another way to get at the same thing. */ + add_info ("set", show_command, "Show all GDB settings."); + + add_cmd ("commands", no_class, show_commands, + "Show the the history of commands you typed.\n\ +You can supply a command number to start with, or a `+' to start after\n\ +the previous command number shown.", + &showlist); + + add_cmd ("version", no_class, show_version, + "Show what version of GDB this is.", &showlist); + + add_show_from_set ( + add_set_cmd ("remotedebug", no_class, var_boolean, (char *)&remote_debug, + "Set debugging of remote protocol.\n\ +When enabled, each packet sent or received with the remote target\n\ +is displayed.", &setlist), + &showlist); +} diff --git a/gnu/usr.bin/gdb/gdb/maint.c b/gnu/usr.bin/gdb/gdb/maint.c new file mode 100644 index 00000000000..b5334512ab4 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/maint.c @@ -0,0 +1,305 @@ +/* Support for GDB maintenance commands. + Copyright (C) 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. + +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. */ + + +#include "defs.h" + +#if MAINTENANCE_CMDS /* Entire file goes away if not including maint cmds */ + +#include +#include "command.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "demangle.h" +#include "gdbcore.h" + +static void +maintenance_command PARAMS ((char *, int)); + +static void +maintenance_dump_me PARAMS ((char *, int)); + +static void +maintenance_demangle PARAMS ((char *, int)); + +/* + +LOCAL FUNCTION + + maintenance_command -- access the maintenance subcommands + +SYNOPSIS + + void maintenance_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +maintenance_command (args, from_tty) + char *args; + int from_tty; +{ + printf ("\"maintenance\" must be followed by the name of a maintenance command.\n"); + help_list (maintenancelist, "maintenance ", -1, stdout); +} + + +/* ARGSUSED */ +static void +maintenance_dump_me (args, from_tty) + char *args; + int from_tty; +{ + if (query ("Should GDB dump core? ")) + { + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + } +} + +/* Someday we should allow demangling for things other than just + explicit strings. For example, we might want to be able to + specify the address of a string in either GDB's process space + or the debuggee's process space, and have gdb fetch and demangle + that string. If we have a char* pointer "ptr" that points to + a string, we might want to be able to given just the name and + have GDB demangle and print what it points to, etc. (FIXME) */ + +static void +maintenance_demangle (args, from_tty) + char *args; + int from_tty; +{ + char *demangled; + + if (args == NULL || *args == '\0') + { + printf ("\"maintenance demangle\" takes an argument to demangle.\n"); + } + else + { + demangled = cplus_demangle (args, DMGL_ANSI | DMGL_PARAMS); + if (demangled != NULL) + { + printf ("%s\n", demangled); + free (demangled); + } + else + { + printf ("Can't demangle \"%s\"\n", args); + } + } +} + +/* The "maintenance info" command is defined as a prefix, with allow_unknown 0. + Therefore, its own definition is called only for "maintenance info" with + no args. */ + +/* ARGSUSED */ +static void +maintenance_info_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf ("\"maintenance info\" must be followed by the name of an info command.\n"); + help_list (maintenanceinfolist, "maintenance info ", -1, stdout); +} + +static void +print_section_table (abfd, asect, ignore) + bfd *abfd; + asection *asect; + PTR ignore; +{ + flagword flags; + + flags = bfd_get_section_flags (abfd, asect); + + printf_filtered (" %s", + local_hex_string_custom + ((unsigned long) bfd_section_vma (abfd, asect), "08l")); + printf_filtered ("->%s", + local_hex_string_custom + ((unsigned long) (bfd_section_vma (abfd, asect) + + bfd_section_size (abfd, asect)), + "08l")); + printf_filtered (" at %s", + local_hex_string_custom + ((unsigned long) asect->filepos, "08l")); + printf_filtered (": %s", bfd_section_name (abfd, asect)); + + if (flags & SEC_ALLOC) + printf_filtered (" ALLOC"); + if (flags & SEC_LOAD) + printf_filtered (" LOAD"); + if (flags & SEC_RELOC) + printf_filtered (" RELOC"); + if (flags & SEC_READONLY) + printf_filtered (" READONLY"); + if (flags & SEC_CODE) + printf_filtered (" CODE"); + if (flags & SEC_DATA) + printf_filtered (" DATA"); + if (flags & SEC_ROM) + printf_filtered (" ROM"); + if (flags & SEC_CONSTRUCTOR) + printf_filtered (" CONSTRUCTOR"); + if (flags & SEC_HAS_CONTENTS) + printf_filtered (" HAS_CONTENTS"); + if (flags & SEC_NEVER_LOAD) + printf_filtered (" NEVER_LOAD"); + if (flags & SEC_SHARED_LIBRARY) + printf_filtered (" SHARED_LIBRARY"); + if (flags & SEC_IS_COMMON) + printf_filtered (" IS_COMMON"); + + printf_filtered ("\n"); +} + +/* ARGSUSED */ +static void +maintenance_info_sections (arg, from_tty) + char *arg; + int from_tty; +{ + if (exec_bfd) + { + printf_filtered ("Exec file:\n"); + printf_filtered (" `%s', ", bfd_get_filename(exec_bfd)); + wrap_here (" "); + printf_filtered ("file type %s.\n", bfd_get_target(exec_bfd)); + bfd_map_over_sections(exec_bfd, print_section_table, 0); + } + + if (core_bfd) + { + printf_filtered ("Core file:\n"); + printf_filtered (" `%s', ", bfd_get_filename(core_bfd)); + wrap_here (" "); + printf_filtered ("file type %s.\n", bfd_get_target(core_bfd)); + bfd_map_over_sections(core_bfd, print_section_table, 0); + } +} + +/* The "maintenance print" command is defined as a prefix, with allow_unknown + 0. Therefore, its own definition is called only for "maintenance print" + with no args. */ + +/* ARGSUSED */ +static void +maintenance_print_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf ("\"maintenance print\" must be followed by the name of a print command.\n"); + help_list (maintenanceprintlist, "maintenance print ", -1, stdout); +} + +/* + +GLOBAL FUNCTION + + _initialize_maint_cmds -- initialize the process file system stuff + +SYNOPSIS + + void _initialize_maint_cmds (void) + +DESCRIPTION + + Do required initializations during gdb startup for using the + /proc file system interface. + +*/ + + +void +_initialize_maint_cmds () +{ + add_prefix_cmd ("maintenance", class_maintenance, maintenance_command, + "Commands for use by GDB maintainers.\n\ +Includes commands to dump specific internal GDB structures in\n\ +a human readable form, to cause GDB to deliberately dump core,\n\ +to test internal functions such as the C++ demangler, etc.", + &maintenancelist, "maintenance ", 0, + &cmdlist); + + add_com_alias ("mt", "maintenance", class_maintenance, 1); + + add_prefix_cmd ("info", class_maintenance, maintenance_info_command, + "Commands for showing internal info about the program being debugged.", + &maintenanceinfolist, "maintenance info ", 0, + &maintenancelist); + + add_cmd ("sections", class_maintenance, maintenance_info_sections, + "List the BFD sections of the exec and core files.", + &maintenanceinfolist); + + add_prefix_cmd ("print", class_maintenance, maintenance_print_command, + "Maintenance command for printing GDB internal state.", + &maintenanceprintlist, "maintenance print ", 0, + &maintenancelist); + + add_cmd ("dump-me", class_maintenance, maintenance_dump_me, + "Get fatal error; make debugger dump its core.\n\ +GDB sets it's handling of SIGQUIT back to SIG_DFL and then sends\n\ +itself a SIGQUIT signal.", + &maintenancelist); + + add_cmd ("demangle", class_maintenance, maintenance_demangle, + "Demangle a C++ mangled name.\n\ +Call internal GDB demangler routine to demangle a C++ link name\n\ +and prints the result.", + &maintenancelist); + + add_cmd ("type", class_maintenance, maintenance_print_type, + "Print a type chain for a given symbol.\n\ +For each node in a type chain, print the raw data for each member of\n\ +the type structure, and the interpretation of the data.", + &maintenanceprintlist); + + add_cmd ("symbols", class_maintenance, maintenance_print_symbols, + "Print dump of current symbol definitions.\n\ +Entries in the full symbol table are dumped to file OUTFILE.\n\ +If a SOURCE file is specified, dump only that file's symbols.", + &maintenanceprintlist); + + add_cmd ("msymbols", class_maintenance, maintenance_print_msymbols, + "Print dump of current minimal symbol definitions.\n\ +Entries in the minimal symbol table are dumped to file OUTFILE.\n\ +If a SOURCE file is specified, dump only that file's minimal symbols.", + &maintenanceprintlist); + + add_cmd ("psymbols", class_maintenance, maintenance_print_psymbols, + "Print dump of current partial symbol definitions.\n\ +Entries in the partial symbol table are dumped to file OUTFILE.\n\ +If a SOURCE file is specified, dump only that file's partial symbols.", + &maintenanceprintlist); + + add_cmd ("objfiles", class_maintenance, maintenance_print_objfiles, + "Print dump of current object file definitions.", + &maintenanceprintlist); + +} + +#endif /* MAINTENANCE_CMDS */ diff --git a/gnu/usr.bin/gdb/gdb/mem-break.c b/gnu/usr.bin/gdb/gdb/mem-break.c new file mode 100644 index 00000000000..74dfaa14750 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/mem-break.c @@ -0,0 +1,104 @@ +/* Simulate breakpoints by patching locations in the target system, for GDB. + Copyright 1990, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +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. */ + +#include "defs.h" + +#ifdef BREAKPOINT +/* This file is only useful if BREAKPOINT is set. If not, we punt. */ + +#include "symtab.h" +#include "breakpoint.h" +#include "inferior.h" +#include "target.h" + +/* This is the sequence of bytes we insert for a breakpoint. On some + machines, breakpoints are handled by the target environment and we + don't have to worry about them here. */ + +static unsigned char break_insn[] = BREAKPOINT; + +/* This is only to check that BREAKPOINT fits in BREAKPOINT_MAX bytes. */ + +static unsigned char check_break_insn_size[BREAKPOINT_MAX] = BREAKPOINT; + +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes (this + is accomplished via BREAKPOINT_MAX). */ + +int +memory_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, sizeof break_insn); + + if (val == 0) + val = target_write_memory (addr, (char *)break_insn, sizeof break_insn); + + return val; +} + + +int +memory_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + return target_write_memory (addr, contents_cache, sizeof break_insn); +} + + +/* FIXME: This is a hack and should depend on the debugging target. + See comment in breakpoint.c where this is used. */ + +int memory_breakpoint_size = sizeof (break_insn); + + +#else /* BREAKPOINT */ + +char nogo[] = "Breakpoints not implemented for this target."; + +int +memory_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + error (nogo); + return 0; /* lint */ +} + +int +memory_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + error (nogo); + return 0; /* lint */ +} + +int memory_breakpoint_size = -1; + +#endif /* BREAKPOINT */ diff --git a/gnu/usr.bin/gdb/gdb/minsyms.c b/gnu/usr.bin/gdb/gdb/minsyms.c new file mode 100644 index 00000000000..dbb4e797d97 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/minsyms.c @@ -0,0 +1,597 @@ +/* GDB routines for manipulating the minimal symbol tables. + Copyright 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +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. */ + + +/* This file contains support routines for creating, manipulating, and + destroying minimal symbol tables. + + Minimal symbol tables are used to hold some very basic information about + all defined global symbols (text, data, bss, abs, etc). The only two + required pieces of information are the symbol's name and the address + associated with that symbol. + + In many cases, even if a file was compiled with no special options for + debugging at all, as long as was not stripped it will contain sufficient + information to build useful minimal symbol tables using this structure. + + Even when a file contains enough debugging information to build a full + symbol table, these minimal symbols are still useful for quickly mapping + between names and addresses, and vice versa. They are also sometimes used + to figure out what full symbol table entries need to be read in. */ + + +#include "defs.h" +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "demangle.h" + +/* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE. + At the end, copy them all into one newly allocated location on an objfile's + symbol obstack. */ + +#define BUNCH_SIZE 127 + +struct msym_bunch +{ + struct msym_bunch *next; + struct minimal_symbol contents[BUNCH_SIZE]; +}; + +/* Bunch currently being filled up. + The next field points to chain of filled bunches. */ + +static struct msym_bunch *msym_bunch; + +/* Number of slots filled in current bunch. */ + +static int msym_bunch_index; + +/* Total number of minimal symbols recorded so far for the objfile. */ + +static int msym_count; + +/* Prototypes for local functions. */ + +static int +compare_minimal_symbols PARAMS ((const void *, const void *)); + +static int +compact_minimal_symbols PARAMS ((struct minimal_symbol *, int)); + +/* Look through all the current minimal symbol tables and find the first + minimal symbol that matches NAME. If OBJF is non-NULL, it specifies a + particular objfile and the search is limited to that objfile. Returns + a pointer to the minimal symbol that matches, or NULL if no match is found. + + Note: One instance where there may be duplicate minimal symbols with + the same name is when the symbol tables for a shared library and the + symbol tables for an executable contain global symbols with the same + names (the dynamic linker deals with the duplication). */ + +struct minimal_symbol * +lookup_minimal_symbol (name, objf) + register const char *name; + struct objfile *objf; +{ + struct objfile *objfile; + struct minimal_symbol *msymbol; + struct minimal_symbol *found_symbol = NULL; + struct minimal_symbol *found_file_symbol = NULL; +#ifdef IBM6000_TARGET + struct minimal_symbol *trampoline_symbol = NULL; +#endif + + for (objfile = object_files; + objfile != NULL && found_symbol == NULL; + objfile = objfile -> next) + { + if (objf == NULL || objf == objfile) + { + for (msymbol = objfile -> msymbols; + msymbol != NULL && SYMBOL_NAME (msymbol) != NULL && + found_symbol == NULL; + msymbol++) + { + if (SYMBOL_MATCHES_NAME (msymbol, name)) + { + switch (MSYMBOL_TYPE (msymbol)) + { + case mst_file_text: + case mst_file_data: + case mst_file_bss: + /* It is file-local. If we find more than one, just + return the latest one (the user can't expect + useful behavior in that case). */ + found_file_symbol = msymbol; + break; + + case mst_unknown: +#ifdef IBM6000_TARGET + /* I *think* all platforms using shared + libraries (and trampoline code) will suffer + this problem. Consider a case where there are + 5 shared libraries, each referencing `foo' + with a trampoline entry. When someone wants + to put a breakpoint on `foo' and the only + info we have is minimal symbol vector, we + want to use the real `foo', rather than one + of those trampoline entries. MGO */ + + /* If a trampoline symbol is found, we prefer to + keep looking for the *real* symbol. If the + actual symbol not found, then we'll use the + trampoline entry. Sorry for the machine + dependent code here, but I hope this will + benefit other platforms as well. For + trampoline entries, we used mst_unknown + earlier. Perhaps we should define a + `mst_trampoline' type?? */ + + if (trampoline_symbol == NULL) + trampoline_symbol = msymbol; + break; +#else + /* FALLTHROUGH */ +#endif + default: + found_symbol = msymbol; + break; + } + } + } + } + } + /* External symbols are best. */ + if (found_symbol) + return found_symbol; + + /* File-local symbols are next best. */ + if (found_file_symbol) + return found_file_symbol; + + /* Symbols for IBM shared library trampolines are next best. */ +#ifdef IBM6000_TARGET + if (trampoline_symbol) + return trampoline_symbol; +#endif + + return NULL; +} + + +/* Search through the minimal symbol table for each objfile and find the + symbol whose address is the largest address that is still less than or + equal to PC. Returns a pointer to the minimal symbol if such a symbol + is found, or NULL if PC is not in a suitable range. Note that we need + to look through ALL the minimal symbol tables before deciding on the + symbol that comes closest to the specified PC. This is because objfiles + can overlap, for example objfile A has .text at 0x100 and .data at 0x40000 + and objfile B has .text at 0x234 and .data at 0x40048. */ + +struct minimal_symbol * +lookup_minimal_symbol_by_pc (pc) + register CORE_ADDR pc; +{ + register int lo; + register int hi; + register int new; + register struct objfile *objfile; + register struct minimal_symbol *msymbol; + register struct minimal_symbol *best_symbol = NULL; + + for (objfile = object_files; + objfile != NULL; + objfile = objfile -> next) + { + /* If this objfile has a minimal symbol table, go search it using + a binary search. Note that a minimal symbol table always consists + of at least two symbols, a "real" symbol and the terminating + "null symbol". If there are no real symbols, then there is no + minimal symbol table at all. */ + + if ((msymbol = objfile -> msymbols) != NULL) + { + lo = 0; + hi = objfile -> minimal_symbol_count - 1; + + /* This code assumes that the minimal symbols are sorted by + ascending address values. If the pc value is greater than or + equal to the first symbol's address, then some symbol in this + minimal symbol table is a suitable candidate for being the + "best" symbol. This includes the last real symbol, for cases + where the pc value is larger than any address in this vector. + + By iterating until the address associated with the current + hi index (the endpoint of the test interval) is less than + or equal to the desired pc value, we accomplish two things: + (1) the case where the pc value is larger than any minimal + symbol address is trivially solved, (2) the address associated + with the hi index is always the one we want when the interation + terminates. In essence, we are iterating the test interval + down until the pc value is pushed out of it from the high end. + + Warning: this code is trickier than it would appear at first. */ + + /* Should also requires that pc is <= end of objfile. FIXME! */ + if (pc >= SYMBOL_VALUE_ADDRESS (&msymbol[lo])) + { + while (SYMBOL_VALUE_ADDRESS (&msymbol[hi]) > pc) + { + /* pc is still strictly less than highest address */ + /* Note "new" will always be >= lo */ + new = (lo + hi) / 2; + if ((SYMBOL_VALUE_ADDRESS (&msymbol[new]) >= pc) || + (lo == new)) + { + hi = new; + } + else + { + lo = new; + } + } + /* The minimal symbol indexed by hi now is the best one in this + objfile's minimal symbol table. See if it is the best one + overall. */ + + /* Skip any absolute symbols. This is apparently what adb + and dbx do, and is needed for the CM-5. There are two + known possible problems: (1) on ELF, apparently end, edata, + etc. are absolute. Not sure ignoring them here is a big + deal, but if we want to use them, the fix would go in + elfread.c. (2) I think shared library entry points on the + NeXT are absolute. If we want special handling for this + it probably should be triggered by a special + mst_abs_or_lib or some such. */ + while (hi >= 0 + && msymbol[hi].type == mst_abs) + --hi; + + if (hi >= 0 + && ((best_symbol == NULL) || + (SYMBOL_VALUE_ADDRESS (best_symbol) < + SYMBOL_VALUE_ADDRESS (&msymbol[hi])))) + { + best_symbol = &msymbol[hi]; + } + } + } + } + return (best_symbol); +} + +/* Prepare to start collecting minimal symbols. Note that presetting + msym_bunch_index to BUNCH_SIZE causes the first call to save a minimal + symbol to allocate the memory for the first bunch. */ + +void +init_minimal_symbol_collection () +{ + msym_count = 0; + msym_bunch = NULL; + msym_bunch_index = BUNCH_SIZE; +} + +void +prim_record_minimal_symbol (name, address, ms_type) + const char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; +{ + register struct msym_bunch *new; + register struct minimal_symbol *msymbol; + + if (msym_bunch_index == BUNCH_SIZE) + { + new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch)); + msym_bunch_index = 0; + new -> next = msym_bunch; + msym_bunch = new; + } + msymbol = &msym_bunch -> contents[msym_bunch_index]; + SYMBOL_NAME (msymbol) = (char *) name; + SYMBOL_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown); + SYMBOL_VALUE_ADDRESS (msymbol) = address; + SYMBOL_SECTION (msymbol) = -1; + MSYMBOL_TYPE (msymbol) = ms_type; + /* FIXME: This info, if it remains, needs its own field. */ + MSYMBOL_INFO (msymbol) = NULL; /* FIXME! */ + msym_bunch_index++; + msym_count++; +} + +/* FIXME: Why don't we just combine this function with the one above + and pass it a NULL info pointer value if info is not needed? */ + +void +prim_record_minimal_symbol_and_info (name, address, ms_type, info, section) + const char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + char *info; + int section; +{ + register struct msym_bunch *new; + register struct minimal_symbol *msymbol; + + if (msym_bunch_index == BUNCH_SIZE) + { + new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch)); + msym_bunch_index = 0; + new -> next = msym_bunch; + msym_bunch = new; + } + msymbol = &msym_bunch -> contents[msym_bunch_index]; + SYMBOL_NAME (msymbol) = (char *) name; + SYMBOL_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown); + SYMBOL_VALUE_ADDRESS (msymbol) = address; + SYMBOL_SECTION (msymbol) = section; + MSYMBOL_TYPE (msymbol) = ms_type; + /* FIXME: This info, if it remains, needs its own field. */ + MSYMBOL_INFO (msymbol) = info; /* FIXME! */ + msym_bunch_index++; + msym_count++; +} + +/* Compare two minimal symbols by address and return a signed result based + on unsigned comparisons, so that we sort into unsigned numeric order. */ + +static int +compare_minimal_symbols (fn1p, fn2p) + const PTR fn1p; + const PTR fn2p; +{ + register const struct minimal_symbol *fn1; + register const struct minimal_symbol *fn2; + + fn1 = (const struct minimal_symbol *) fn1p; + fn2 = (const struct minimal_symbol *) fn2p; + + if (SYMBOL_VALUE_ADDRESS (fn1) < SYMBOL_VALUE_ADDRESS (fn2)) + { + return (-1); + } + else if (SYMBOL_VALUE_ADDRESS (fn1) > SYMBOL_VALUE_ADDRESS (fn2)) + { + return (1); + } + else + { + return (0); + } +} + +/* Discard the currently collected minimal symbols, if any. If we wish + to save them for later use, we must have already copied them somewhere + else before calling this function. + + FIXME: We could allocate the minimal symbol bunches on their own + obstack and then simply blow the obstack away when we are done with + it. Is it worth the extra trouble though? */ + +/* ARGSUSED */ +void +discard_minimal_symbols (foo) + int foo; +{ + register struct msym_bunch *next; + + while (msym_bunch != NULL) + { + next = msym_bunch -> next; + free ((PTR)msym_bunch); + msym_bunch = next; + } +} + +/* Compact duplicate entries out of a minimal symbol table by walking + through the table and compacting out entries with duplicate addresses + and matching names. Return the number of entries remaining. + + On entry, the table resides between msymbol[0] and msymbol[mcount]. + On exit, it resides between msymbol[0] and msymbol[result_count]. + + When files contain multiple sources of symbol information, it is + possible for the minimal symbol table to contain many duplicate entries. + As an example, SVR4 systems use ELF formatted object files, which + usually contain at least two different types of symbol tables (a + standard ELF one and a smaller dynamic linking table), as well as + DWARF debugging information for files compiled with -g. + + Without compacting, the minimal symbol table for gdb itself contains + over a 1000 duplicates, about a third of the total table size. Aside + from the potential trap of not noticing that two successive entries + identify the same location, this duplication impacts the time required + to linearly scan the table, which is done in a number of places. So we + just do one linear scan here and toss out the duplicates. + + Note that we are not concerned here about recovering the space that + is potentially freed up, because the strings themselves are allocated + on the symbol_obstack, and will get automatically freed when the symbol + table is freed. The caller can free up the unused minimal symbols at + the end of the compacted region if their allocation strategy allows it. + + Also note we only go up to the next to last entry within the loop + and then copy the last entry explicitly after the loop terminates. + + Since the different sources of information for each symbol may + have different levels of "completeness", we may have duplicates + that have one entry with type "mst_unknown" and the other with a + known type. So if the one we are leaving alone has type mst_unknown, + overwrite its type with the type from the one we are compacting out. */ + +static int +compact_minimal_symbols (msymbol, mcount) + struct minimal_symbol *msymbol; + int mcount; +{ + struct minimal_symbol *copyfrom; + struct minimal_symbol *copyto; + + if (mcount > 0) + { + copyfrom = copyto = msymbol; + while (copyfrom < msymbol + mcount - 1) + { + if (SYMBOL_VALUE_ADDRESS (copyfrom) == + SYMBOL_VALUE_ADDRESS ((copyfrom + 1)) && + (STREQ (SYMBOL_NAME (copyfrom), SYMBOL_NAME ((copyfrom + 1))))) + { + if (MSYMBOL_TYPE((copyfrom + 1)) == mst_unknown) + { + MSYMBOL_TYPE ((copyfrom + 1)) = MSYMBOL_TYPE (copyfrom); + } + copyfrom++; + } + else + { + *copyto++ = *copyfrom++; + } + } + *copyto++ = *copyfrom++; + mcount = copyto - msymbol; + } + return (mcount); +} + +/* Add the minimal symbols in the existing bunches to the objfile's official + minimal symbol table. In most cases there is no minimal symbol table yet + for this objfile, and the existing bunches are used to create one. Once + in a while (for shared libraries for example), we add symbols (e.g. common + symbols) to an existing objfile. + + Because of the way minimal symbols are collected, we generally have no way + of knowing what source language applies to any particular minimal symbol. + Specifically, we have no way of knowing if the minimal symbol comes from a + C++ compilation unit or not. So for the sake of supporting cached + demangled C++ names, we have no choice but to try and demangle each new one + that comes in. If the demangling succeeds, then we assume it is a C++ + symbol and set the symbol's language and demangled name fields + appropriately. Note that in order to avoid unnecessary demanglings, and + allocating obstack space that subsequently can't be freed for the demangled + names, we mark all newly added symbols with language_auto. After + compaction of the minimal symbols, we go back and scan the entire minimal + symbol table looking for these new symbols. For each new symbol we attempt + to demangle it, and if successful, record it as a language_cplus symbol + and cache the demangled form on the symbol obstack. Symbols which don't + demangle are marked as language_unknown symbols, which inhibits future + attempts to demangle them if we later add more minimal symbols. */ + +void +install_minimal_symbols (objfile) + struct objfile *objfile; +{ + register int bindex; + register int mcount; + register struct msym_bunch *bunch; + register struct minimal_symbol *msymbols; + int alloc_count; + register char leading_char; + + if (msym_count > 0) + { + /* Allocate enough space in the obstack, into which we will gather the + bunches of new and existing minimal symbols, sort them, and then + compact out the duplicate entries. Once we have a final table, + we will give back the excess space. */ + + alloc_count = msym_count + objfile->minimal_symbol_count + 1; + obstack_blank (&objfile->symbol_obstack, + alloc_count * sizeof (struct minimal_symbol)); + msymbols = (struct minimal_symbol *) + obstack_base (&objfile->symbol_obstack); + + /* Copy in the existing minimal symbols, if there are any. */ + + if (objfile->minimal_symbol_count) + memcpy ((char *)msymbols, (char *)objfile->msymbols, + objfile->minimal_symbol_count * sizeof (struct minimal_symbol)); + + /* Walk through the list of minimal symbol bunches, adding each symbol + to the new contiguous array of symbols. Note that we start with the + current, possibly partially filled bunch (thus we use the current + msym_bunch_index for the first bunch we copy over), and thereafter + each bunch is full. */ + + mcount = objfile->minimal_symbol_count; + leading_char = bfd_get_symbol_leading_char (objfile->obfd); + + for (bunch = msym_bunch; bunch != NULL; bunch = bunch -> next) + { + for (bindex = 0; bindex < msym_bunch_index; bindex++, mcount++) + { + msymbols[mcount] = bunch -> contents[bindex]; + SYMBOL_LANGUAGE (&msymbols[mcount]) = language_auto; + if (SYMBOL_NAME (&msymbols[mcount])[0] == leading_char) + { + SYMBOL_NAME(&msymbols[mcount])++; + } + } + msym_bunch_index = BUNCH_SIZE; + } + + /* Sort the minimal symbols by address. */ + + qsort (msymbols, mcount, sizeof (struct minimal_symbol), + compare_minimal_symbols); + + /* Compact out any duplicates, and free up whatever space we are + no longer using. */ + + mcount = compact_minimal_symbols (msymbols, mcount); + + obstack_blank (&objfile->symbol_obstack, + (mcount + 1 - alloc_count) * sizeof (struct minimal_symbol)); + msymbols = (struct minimal_symbol *) + obstack_finish (&objfile->symbol_obstack); + + /* We also terminate the minimal symbol table with a "null symbol", + which is *not* included in the size of the table. This makes it + easier to find the end of the table when we are handed a pointer + to some symbol in the middle of it. Zero out the fields in the + "null symbol" allocated at the end of the array. Note that the + symbol count does *not* include this null symbol, which is why it + is indexed by mcount and not mcount-1. */ + + SYMBOL_NAME (&msymbols[mcount]) = NULL; + SYMBOL_VALUE_ADDRESS (&msymbols[mcount]) = 0; + MSYMBOL_INFO (&msymbols[mcount]) = NULL; + MSYMBOL_TYPE (&msymbols[mcount]) = mst_unknown; + SYMBOL_INIT_LANGUAGE_SPECIFIC (&msymbols[mcount], language_unknown); + + /* Attach the minimal symbol table to the specified objfile. + The strings themselves are also located in the symbol_obstack + of this objfile. */ + + objfile -> minimal_symbol_count = mcount; + objfile -> msymbols = msymbols; + + /* Now walk through all the minimal symbols, selecting the newly added + ones and attempting to cache their C++ demangled names. */ + + for ( ; mcount-- > 0 ; msymbols++) + { + SYMBOL_INIT_DEMANGLED_NAME (msymbols, &objfile->symbol_obstack); + } + } +} + diff --git a/gnu/usr.bin/gdb/gdb/mipsread.c b/gnu/usr.bin/gdb/gdb/mipsread.c new file mode 100644 index 00000000000..199092bb5c3 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/mipsread.c @@ -0,0 +1,3653 @@ +/* Read a symbol table in MIPS' format (Third-Eye). + Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 Free Software + Foundation, Inc. + Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU. Major work + by Per Bothner, John Gilmore and Ian Lance Taylor at Cygnus Support. + +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. */ + +/* This module provides three functions: mipscoff_symfile_init, + which initializes to read a symbol file; mipscoff_new_init, which + discards existing cached information when all symbols are being + discarded; and mipscoff_symfile_read, which reads a symbol table + from a file. + + mipscoff_symfile_read only does the minimum work necessary for letting the + user "name" things symbolically; it does not read the entire symtab. + Instead, it reads the external and static symbols and puts them in partial + symbol tables. When more extensive information is requested of a + file, the corresponding partial symbol table is mutated into a full + fledged symbol table by going back and reading the symbols + for real. mipscoff_psymtab_to_symtab() is called indirectly through + a pointer in the psymtab to do this. + + ECOFF symbol tables are mostly written in the byte order of the + target machine. However, one section of the table (the auxiliary + symbol information) is written in the host byte order. There is a + bit in the other symbol info which describes which host byte order + was used. ECOFF thereby takes the trophy from Intel `b.out' for + the most brain-dead adaptation of a file format to byte order. + + This module can read all four of the known byte-order combinations, + on any type of host. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "symfile.h" +#include "objfiles.h" +#include "obstack.h" +#include "buildsym.h" +#include "stabsread.h" +#include "complaints.h" + +/* These are needed if the tm.h file does not contain the necessary + mips specific definitions. */ + +#ifndef MIPS_EFI_SYMBOL_NAME +#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__" +#include "coff/sym.h" +#include "coff/symconst.h" +typedef struct mips_extra_func_info { + long numargs; + PDR pdr; +} *mips_extra_func_info_t; +#ifndef RA_REGNUM +#define RA_REGNUM 0 +#endif +#endif + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#include "gdb-stabs.h" + +#include "bfd.h" + +#include "coff/internal.h" +#include "coff/ecoff.h" /* COFF-like aspects of ecoff files */ + +/* FIXME: coff/internal.h and aout/aout64.h both define N_ABS. We + want the definition from aout/aout64.h. */ +#undef N_ABS + +#include "libaout.h" /* Private BFD a.out information. */ +#include "aout/aout64.h" +#include "aout/stab_gnu.h" /* STABS information */ + +/* FIXME: libcoff.h and libaout.h both define a couple of macros. We + don't use them. */ +#undef exec_hdr +#undef obj_sym_filepos + +#include "libcoff.h" /* Private BFD COFF information. */ +#include "libecoff.h" /* Private BFD ECOFF information. */ + +#include "expression.h" +#include "language.h" /* Needed inside partial-stab.h */ + +/* Provide a default mapping from a ecoff register number to a gdb REGNUM. */ +#ifndef ECOFF_REG_TO_REGNUM +#define ECOFF_REG_TO_REGNUM(num) (num) +#endif + +/* Information is passed among various mipsread routines for accessing + symbol files. A pointer to this structure is kept in the sym_private + field of the objfile struct. */ + +struct ecoff_symfile_info { + struct mips_pending **pending_list; +}; +#define ECOFF_SYMFILE_INFO(o) ((struct ecoff_symfile_info *)((o)->sym_private)) +#define ECOFF_PENDING_LIST(o) (ECOFF_SYMFILE_INFO(o)->pending_list) + + +/* Each partial symbol table entry contains a pointer to private data + for the read_symtab() function to use when expanding a partial + symbol table entry to a full symbol table entry. + + For mipsread this structure contains the index of the FDR that this + psymtab represents and a pointer to the BFD that the psymtab was + created from. */ + +#define PST_PRIVATE(p) ((struct symloc *)(p)->read_symtab_private) +#define FDR_IDX(p) (PST_PRIVATE(p)->fdr_idx) +#define CUR_BFD(p) (PST_PRIVATE(p)->cur_bfd) + +struct symloc +{ + int fdr_idx; + bfd *cur_bfd; + EXTR *extern_tab; /* Pointer to external symbols for this file. */ + int extern_count; /* Size of extern_tab. */ + enum language pst_language; +}; + +/* Things we import explicitly from other modules */ + +extern int info_verbose; + +/* Various complaints about symbol reading that don't abort the process */ + +struct complaint bad_file_number_complaint = +{"bad file number %d", 0, 0}; + +struct complaint index_complaint = +{"bad aux index at symbol %s", 0, 0}; + +struct complaint aux_index_complaint = +{"bad proc end in aux found from symbol %s", 0, 0}; + +struct complaint block_index_complaint = +{"bad aux index at block symbol %s", 0, 0}; + +struct complaint unknown_ext_complaint = +{"unknown external symbol %s", 0, 0}; + +struct complaint unknown_sym_complaint = +{"unknown local symbol %s", 0, 0}; + +struct complaint unknown_st_complaint = +{"with type %d", 0, 0}; + +struct complaint block_overflow_complaint = +{"block containing %s overfilled", 0, 0}; + +struct complaint basic_type_complaint = +{"cannot map MIPS basic type 0x%x for %s", 0, 0}; + +struct complaint unknown_type_qual_complaint = +{"unknown type qualifier 0x%x", 0, 0}; + +struct complaint array_index_type_complaint = +{"illegal array index type for %s, assuming int", 0, 0}; + +struct complaint bad_tag_guess_complaint = +{"guessed tag type of %s incorrectly", 0, 0}; + +struct complaint block_member_complaint = +{"declaration block contains unhandled symbol type %d", 0, 0}; + +struct complaint stEnd_complaint = +{"stEnd with storage class %d not handled", 0, 0}; + +struct complaint unknown_mips_symtype_complaint = +{"unknown symbol type 0x%x", 0, 0}; + +struct complaint stab_unknown_complaint = +{"unknown stabs symbol %s", 0, 0}; + +struct complaint pdr_for_nonsymbol_complaint = +{"PDR for %s, but no symbol", 0, 0}; + +struct complaint pdr_static_symbol_complaint = +{"can't handle PDR for static proc at 0x%lx", 0, 0}; + +struct complaint bad_setjmp_pdr_complaint = +{"fixing bad setjmp PDR from libc", 0, 0}; + +struct complaint bad_fbitfield_complaint = +{"can't handle TIR fBitfield for %s", 0, 0}; + +struct complaint bad_continued_complaint = +{"illegal TIR continued for %s", 0, 0}; + +struct complaint bad_rfd_entry_complaint = +{"bad rfd entry for %s: file %d, index %d", 0, 0}; + +struct complaint unexpected_type_code_complaint = +{"unexpected type code for %s", 0, 0}; + +struct complaint unable_to_cross_ref_complaint = +{"unable to cross ref btTypedef for %s", 0, 0}; + +struct complaint illegal_forward_tq0_complaint = +{"illegal tq0 in forward typedef for %s", 0, 0}; + +struct complaint illegal_forward_bt_complaint = +{"illegal bt %d in forward typedef for %s", 0, 0}; + +struct complaint bad_linetable_guess_complaint = +{"guessed size of linetable for %s incorrectly", 0, 0}; + +/* Macros and extra defs */ + +/* Puns: hard to find whether -g was used and how */ + +#define MIN_GLEVEL GLEVEL_0 +#define compare_glevel(a,b) \ + (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \ + ((b) == GLEVEL_3) ? -1 : (int)((b) - (a))) + +/* Things that really are local to this module */ + +/* Remember what we deduced to be the source language of this psymtab. */ + +static enum language psymtab_language = language_unknown; + +/* Current BFD. */ + +static bfd *cur_bfd; + +/* Pointer to current file decriptor record, and its index */ + +static FDR *cur_fdr; +static int cur_fd; + +/* Index of current symbol */ + +static int cur_sdx; + +/* Note how much "debuggable" this image is. We would like + to see at least one FDR with full symbols */ + +static max_gdbinfo; +static max_glevel; + +/* When examining .o files, report on undefined symbols */ + +static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs; + +/* Pseudo symbol to use when putting stabs into the symbol table. */ + +static char stabs_symbol[] = STABS_SYMBOL; + +/* Extra builtin types */ + +struct type *builtin_type_complex; +struct type *builtin_type_double_complex; +struct type *builtin_type_fixed_dec; +struct type *builtin_type_float_dec; +struct type *builtin_type_string; + +/* Forward declarations */ + +static void +read_mips_symtab PARAMS ((struct objfile *, struct section_offsets *)); + +static void +read_the_mips_symtab PARAMS ((bfd *)); + +static int +upgrade_type PARAMS ((int, struct type **, int, union aux_ext *, int, char *)); + +static void +parse_partial_symbols PARAMS ((struct objfile *, + struct section_offsets *)); + +static int +cross_ref PARAMS ((int, union aux_ext *, struct type **, enum type_code, + char **, int, char *)); + +static void +fixup_sigtramp PARAMS ((void)); + +static struct symbol * +new_symbol PARAMS ((char *)); + +static struct type * +new_type PARAMS ((char *)); + +static struct block * +new_block PARAMS ((int)); + +static struct symtab * +new_symtab PARAMS ((char *, int, int, struct objfile *)); + +static struct linetable * +new_linetable PARAMS ((int)); + +static struct blockvector * +new_bvect PARAMS ((int)); + +static int +parse_symbol PARAMS ((SYMR *, union aux_ext *, char *, int)); + +static struct type * +parse_type PARAMS ((int, union aux_ext *, unsigned int, int *, int, char *)); + +static struct symbol * +mylookup_symbol PARAMS ((char *, struct block *, enum namespace, + enum address_class)); + +static struct block * +shrink_block PARAMS ((struct block *, struct symtab *)); + +static PTR +xzalloc PARAMS ((unsigned int)); + +static void +sort_blocks PARAMS ((struct symtab *)); + +static int +compare_blocks PARAMS ((const void *, const void *)); + +static struct partial_symtab * +new_psymtab PARAMS ((char *, struct objfile *)); + +static void +psymtab_to_symtab_1 PARAMS ((struct partial_symtab *, char *)); + +static void +add_block PARAMS ((struct block *, struct symtab *)); + +static void +add_symbol PARAMS ((struct symbol *, struct block *)); + +static int +add_line PARAMS ((struct linetable *, int, CORE_ADDR, int)); + +static struct linetable * +shrink_linetable PARAMS ((struct linetable *)); + +static char * +mips_next_symbol_text PARAMS ((void)); + +/* Things we export to other modules */ + +/* Address bounds for the signal trampoline in inferior, if any */ +/* FIXME: Nothing really seems to use this. Why is it here? */ + +CORE_ADDR sigtramp_address, sigtramp_end; + +static void +mipscoff_new_init (ignore) + struct objfile *ignore; +{ + sigtramp_address = 0; + stabsread_new_init (); + buildsym_new_init (); +} + +static void +mipscoff_symfile_init (objfile) + struct objfile *objfile; +{ + if (objfile->sym_private != NULL) + { + mfree (objfile->md, objfile->sym_private); + } + objfile->sym_private = (PTR) + xmmalloc (objfile->md, sizeof (struct ecoff_symfile_info)); +} + +static void +mipscoff_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + struct cleanup * back_to; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + read_mips_symtab (objfile, section_offsets); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + +/* Perform any local cleanups required when we are done with a particular + objfile. I.E, we are in the process of discarding all symbol information + for an objfile, freeing up all memory held for it, and unlinking the + objfile struct from the global list of known objfiles. */ + +static void +mipscoff_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile->sym_private != NULL) + { + mfree (objfile->md, objfile->sym_private); + } + + cur_bfd = 0; +} + +/* Allocate zeroed memory */ + +static PTR +xzalloc (size) + unsigned int size; +{ + PTR p = xmalloc (size); + + memset (p, 0, size); + return p; +} + +/* Exported procedure: Builds a symtab from the PST partial one. + Restores the environment in effect when PST was created, delegates + most of the work to an ancillary procedure, and sorts + and reorders the symtab list at the end */ + +static void +mipscoff_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + + if (!pst) + return; + + if (info_verbose) + { + printf_filtered ("Reading in symbols for %s...", pst->filename); + fflush (stdout); + } + + next_symbol_text_func = mips_next_symbol_text; + + psymtab_to_symtab_1 (pst, pst->filename); + + /* Match with global symbols. This only needs to be done once, + after all of the symtabs and dependencies have been read in. */ + scan_file_globals (pst->objfile); + + if (info_verbose) + printf_filtered ("done.\n"); +} + +/* Exported procedure: Is PC in the signal trampoline code */ + +int +in_sigtramp (pc, ignore) + CORE_ADDR pc; + char *ignore; /* function name */ +{ + if (sigtramp_address == 0) + fixup_sigtramp (); + return (pc >= sigtramp_address && pc < sigtramp_end); +} + +/* File-level interface functions */ + +/* Read the symtab information from file ABFD into memory. */ + +static void +read_the_mips_symtab (abfd) + bfd *abfd; +{ + if (ecoff_slurp_symbolic_info (abfd) == false) + error ("Error reading symbol table: %s", bfd_errmsg (bfd_error)); +} + +/* Find a file descriptor given its index RF relative to a file CF */ + +static FDR * +get_rfd (cf, rf) + int cf, rf; +{ + FDR *fdrs; + register FDR *f; + RFDT rfd; + + fdrs = ecoff_data (cur_bfd)->fdr; + f = fdrs + cf; + /* Object files do not have the RFD table, all refs are absolute */ + if (f->rfdBase == 0) + return fdrs + rf; + (*ecoff_backend (cur_bfd)->swap_rfd_in) + (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_rfd + + (f->rfdBase + rf) * ecoff_backend (cur_bfd)->external_rfd_size), + &rfd); + return fdrs + rfd; +} + +/* Return a safer print NAME for a file descriptor */ + +static char * +fdr_name (f) + FDR *f; +{ + if (f->rss == -1) + return ""; + if (f->rss == 0) + return ""; + return ecoff_data (cur_bfd)->ss + f->issBase + f->rss; +} + + +/* Read in and parse the symtab of the file OBJFILE. Symbols from + different sections are relocated via the SECTION_OFFSETS. */ + +static void +read_mips_symtab (objfile, section_offsets) + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + cur_bfd = objfile->obfd; + + read_the_mips_symtab (objfile->obfd); + + parse_partial_symbols (objfile, section_offsets); + +#if 0 + /* Check to make sure file was compiled with -g. If not, warn the + user of this limitation. */ + if (compare_glevel (max_glevel, GLEVEL_2) < 0) + { + if (max_gdbinfo == 0) + printf ("\n%s not compiled with -g, debugging support is limited.\n", + objfile->name); + printf ("You should compile with -g2 or -g3 for best debugging support.\n"); + fflush (stdout); + } +#endif +} + +/* Local utilities */ + +/* Map of FDR indexes to partial symtabs */ + +struct pst_map +{ + struct partial_symtab *pst; /* the psymtab proper */ + long n_globals; /* exported globals (external symbols) */ + long globals_offset; /* cumulative */ +}; + + +/* Utility stack, used to nest procedures and blocks properly. + It is a doubly linked list, to avoid too many alloc/free. + Since we might need it quite a few times it is NOT deallocated + after use. */ + +static struct parse_stack +{ + struct parse_stack *next, *prev; + struct symtab *cur_st; /* Current symtab. */ + struct block *cur_block; /* Block in it. */ + int blocktype; /* What are we parsing. */ + int maxsyms; /* Max symbols in this block. */ + struct type *cur_type; /* Type we parse fields for. */ + int cur_field; /* Field number in cur_type. */ + CORE_ADDR procadr; /* Start addres of this procedure */ + int numargs; /* Its argument count */ +} + + *top_stack; /* Top stack ptr */ + + +/* Enter a new lexical context */ + +static void +push_parse_stack () +{ + struct parse_stack *new; + + /* Reuse frames if possible */ + if (top_stack && top_stack->prev) + new = top_stack->prev; + else + new = (struct parse_stack *) xzalloc (sizeof (struct parse_stack)); + /* Initialize new frame with previous content */ + if (top_stack) + { + register struct parse_stack *prev = new->prev; + + *new = *top_stack; + top_stack->prev = new; + new->prev = prev; + new->next = top_stack; + } + top_stack = new; +} + +/* Exit a lexical context */ + +static void +pop_parse_stack () +{ + if (!top_stack) + return; + if (top_stack->next) + top_stack = top_stack->next; +} + + +/* Cross-references might be to things we haven't looked at + yet, e.g. type references. To avoid too many type + duplications we keep a quick fixup table, an array + of lists of references indexed by file descriptor */ + +struct mips_pending +{ + struct mips_pending *next; /* link */ + char *s; /* the unswapped symbol */ + struct type *t; /* its partial type descriptor */ +}; + + +/* Check whether we already saw symbol SH in file FH */ + +static struct mips_pending * +is_pending_symbol (fh, sh) + FDR *fh; + char *sh; +{ + int f_idx = fh - ecoff_data (cur_bfd)->fdr; + register struct mips_pending *p; + struct mips_pending **pending_list = ECOFF_PENDING_LIST (current_objfile); + + /* Linear search is ok, list is typically no more than 10 deep */ + for (p = pending_list[f_idx]; p; p = p->next) + if (p->s == sh) + break; + return p; +} + +/* Add a new symbol SH of type T */ + +static void +add_pending (fh, sh, t) + FDR *fh; + char *sh; + struct type *t; +{ + int f_idx = fh - ecoff_data (cur_bfd)->fdr; + struct mips_pending *p = is_pending_symbol (fh, sh); + + /* Make sure we do not make duplicates */ + if (!p) + { + struct mips_pending **pending_list = ECOFF_PENDING_LIST (current_objfile); + + p = ((struct mips_pending *) + obstack_alloc (¤t_objfile->psymbol_obstack, + sizeof (struct mips_pending))); + p->s = sh; + p->t = t; + p->next = pending_list[f_idx]; + pending_list[f_idx] = p; + } +} + + +/* Parsing Routines proper. */ + +/* Parse a single symbol. Mostly just make up a GDB symbol for it. + For blocks, procedures and types we open a new lexical context. + This is basically just a big switch on the symbol's type. Argument + AX is the base pointer of aux symbols for this file (fh->iauxBase). + EXT_SH points to the unswapped symbol, which is needed for struct, + union, etc., types; it is NULL for an EXTR. BIGEND says whether + aux symbols are big-endian or little-endian. Return count of + SYMR's handled (normally one). */ + +static int +parse_symbol (sh, ax, ext_sh, bigend) + SYMR *sh; + union aux_ext *ax; + char *ext_sh; + int bigend; +{ + const bfd_size_type external_sym_size + = ecoff_backend (cur_bfd)->external_sym_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) = + ecoff_backend (cur_bfd)->swap_sym_in; + char *name; + struct symbol *s; + struct block *b; + struct mips_pending *pend; + struct type *t; + struct field *f; + int count = 1; + enum address_class class; + TIR tir; + long svalue = sh->value; + int bitsize; + + if (ext_sh == (char *) NULL) + name = ecoff_data (cur_bfd)->ssext + sh->iss; + else + name = ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh->iss; + + switch (sh->st) + { + case stNil: + break; + + case stGlobal: /* external symbol, goes into global block */ + class = LOC_STATIC; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st), + GLOBAL_BLOCK); + s = new_symbol (name); + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + goto data; + + case stStatic: /* static data, goes into current block. */ + class = LOC_STATIC; + b = top_stack->cur_block; + s = new_symbol (name); + if (sh->sc == scCommon) + { + /* It is a FORTRAN common block. At least for SGI Fortran the + address is not in the symbol; we need to fix it later in + scan_file_globals. */ + int bucket = hashname (SYMBOL_NAME (s)); + SYMBOL_VALUE_CHAIN (s) = global_sym_chain[bucket]; + global_sym_chain[bucket] = s; + } + else + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + goto data; + + case stLocal: /* local variable, goes into current block */ + if (sh->sc == scRegister) + { + class = LOC_REGISTER; + svalue = ECOFF_REG_TO_REGNUM (svalue); + } + else + class = LOC_LOCAL; + b = top_stack->cur_block; + s = new_symbol (name); + SYMBOL_VALUE (s) = svalue; + + data: /* Common code for symbols describing data */ + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = class; + add_symbol (s, b); + + /* Type could be missing in a number of cases */ + if (sh->sc == scUndefined || sh->sc == scNil || + sh->index == 0xfffff) + SYMBOL_TYPE (s) = builtin_type_int; /* undefined? */ + else + SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name); + /* Value of a data symbol is its memory address */ + break; + + case stParam: /* arg to procedure, goes into current block */ + max_gdbinfo++; + top_stack->numargs++; + + /* Special GNU C++ name. */ + if (name[0] == CPLUS_MARKER && name[1] == 't' && name[2] == 0) + name = "this"; /* FIXME, not alloc'd in obstack */ + s = new_symbol (name); + + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + switch (sh->sc) + { + case scRegister: + /* Pass by value in register. */ + SYMBOL_CLASS(s) = LOC_REGPARM; + svalue = ECOFF_REG_TO_REGNUM (svalue); + break; + case scVar: + /* Pass by reference on stack. */ + SYMBOL_CLASS(s) = LOC_REF_ARG; + break; + case scVarRegister: + /* Pass by reference in register. */ + SYMBOL_CLASS(s) = LOC_REGPARM_ADDR; + svalue = ECOFF_REG_TO_REGNUM (svalue); + break; + default: + /* Pass by value on stack. */ + SYMBOL_CLASS(s) = LOC_ARG; + break; + } + SYMBOL_VALUE (s) = svalue; + SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name); + add_symbol (s, top_stack->cur_block); +#if 0 + /* FIXME: This has not been tested. See dbxread.c */ + /* Add the type of this parameter to the function/procedure + type of this block. */ + add_param_to_type (&top_stack->cur_block->function->type, s); +#endif + break; + + case stLabel: /* label, goes into current block */ + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; /* so that it can be used */ + SYMBOL_CLASS (s) = LOC_LABEL; /* but not misused */ + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + SYMBOL_TYPE (s) = builtin_type_int; + add_symbol (s, top_stack->cur_block); + break; + + case stProc: /* Procedure, usually goes into global block */ + case stStaticProc: /* Static procedure, goes into current block */ + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + /* Type of the return value */ + if (sh->sc == scUndefined || sh->sc == scNil) + t = builtin_type_int; + else + t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name); + b = top_stack->cur_block; + if (sh->st == stProc) + { + struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st); + /* The next test should normally be true, + but provides a hook for nested functions + (which we don't want to make global). */ + if (b == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + } + add_symbol (s, b); + + /* Make a type for the procedure itself */ +#if 0 + /* FIXME: This has not been tested yet! See dbxread.c */ + /* Generate a template for the type of this function. The + types of the arguments will be added as we read the symbol + table. */ + memcpy (lookup_function_type (t), SYMBOL_TYPE (s), sizeof (struct type)); +#else + SYMBOL_TYPE (s) = lookup_function_type (t); +#endif + + /* Create and enter a new lexical context */ + b = new_block (top_stack->maxsyms); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_FUNCTION (b) = s; + BLOCK_START (b) = BLOCK_END (b) = sh->value; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + add_block (b, top_stack->cur_st); + + /* Not if we only have partial info */ + if (sh->sc == scUndefined || sh->sc == scNil) + break; + + push_parse_stack (); + top_stack->cur_block = b; + top_stack->blocktype = sh->st; + top_stack->cur_type = SYMBOL_TYPE (s); + top_stack->cur_field = -1; + top_stack->procadr = sh->value; + top_stack->numargs = 0; + break; + + /* Beginning of code for structure, union, and enum definitions. + They all share a common set of local variables, defined here. */ + { + enum type_code type_code; + char *ext_tsym; + int nfields; + long max_value; + struct field *f; + + case stStruct: /* Start a block defining a struct type */ + type_code = TYPE_CODE_STRUCT; + goto structured_common; + + case stUnion: /* Start a block defining a union type */ + type_code = TYPE_CODE_UNION; + goto structured_common; + + case stEnum: /* Start a block defining an enum type */ + type_code = TYPE_CODE_ENUM; + goto structured_common; + + case stBlock: /* Either a lexical block, or some type */ + if (sh->sc != scInfo && sh->sc != scCommon) + goto case_stBlock_code; /* Lexical block */ + + type_code = TYPE_CODE_UNDEF; /* We have a type. */ + + /* Common code for handling struct, union, enum, and/or as-yet- + unknown-type blocks of info about structured data. `type_code' + has been set to the proper TYPE_CODE, if we know it. */ + structured_common: + push_parse_stack (); + top_stack->blocktype = stBlock; + + /* First count the number of fields and the highest value. */ + nfields = 0; + max_value = 0; + for (ext_tsym = ext_sh + external_sym_size; + ; + ext_tsym += external_sym_size) + { + SYMR tsym; + + (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); + + switch (tsym.st) + { + case stEnd: + goto end_of_fields; + + case stMember: + if (nfields == 0 && type_code == TYPE_CODE_UNDEF) + /* If the type of the member is Nil (or Void), + without qualifiers, assume the tag is an + enumeration. */ + if (tsym.index == indexNil) + type_code = TYPE_CODE_ENUM; + else + { + ecoff_swap_tir_in (bigend, + &ax[tsym.index].a_ti, + &tir); + if ((tir.bt == btNil || tir.bt == btVoid) + && tir.tq0 == tqNil) + type_code = TYPE_CODE_ENUM; + } + nfields++; + if (tsym.value > max_value) + max_value = tsym.value; + break; + + case stBlock: + case stUnion: + case stEnum: + case stStruct: + { +#if 0 + /* This is a no-op; is it trying to tell us something + we should be checking? */ + if (tsym.sc == scVariant); /*UNIMPLEMENTED*/ +#endif + if (tsym.index != 0) + { + /* This is something like a struct within a + struct. Skip over the fields of the inner + struct. The -1 is because the for loop will + increment ext_tsym. */ + ext_tsym = ((char *) ecoff_data (cur_bfd)->external_sym + + ((cur_fdr->isymBase + tsym.index - 1) + * external_sym_size)); + } + } + break; + + case stTypedef: + /* mips cc puts out a typedef for struct x if it is not yet + defined when it encounters + struct y { struct x *xp; }; + Just ignore it. */ + break; + + default: + complain (&block_member_complaint, tsym.st); + } + } + end_of_fields:; + + /* In an stBlock, there is no way to distinguish structs, + unions, and enums at this point. This is a bug in the + original design (that has been fixed with the recent + addition of the stStruct, stUnion, and stEnum symbol + types.) The way you can tell is if/when you see a variable + or field of that type. In that case the variable's type + (in the AUX table) says if the type is struct, union, or + enum, and points back to the stBlock here. So you can + patch the tag kind up later - but only if there actually is + a variable or field of that type. + + So until we know for sure, we will guess at this point. + The heuristic is: + If the first member has index==indexNil or a void type, + assume we have an enumeration. + Otherwise, if there is more than one member, and all + the members have offset 0, assume we have a union. + Otherwise, assume we have a struct. + + The heuristic could guess wrong in the case of of an + enumeration with no members or a union with one (or zero) + members, or when all except the last field of a struct have + width zero. These are uncommon and/or illegal situations, + and in any case guessing wrong probably doesn't matter + much. + + But if we later do find out we were wrong, we fixup the tag + kind. Members of an enumeration must be handled + differently from struct/union fields, and that is harder to + patch up, but luckily we shouldn't need to. (If there are + any enumeration members, we can tell for sure it's an enum + here.) */ + + if (type_code == TYPE_CODE_UNDEF) + if (nfields > 1 && max_value == 0) + type_code = TYPE_CODE_UNION; + else + type_code = TYPE_CODE_STRUCT; + + /* Create a new type or use the pending type. */ + pend = is_pending_symbol (cur_fdr, ext_sh); + if (pend == (struct mips_pending *) NULL) + { + t = new_type (NULL); + add_pending (cur_fdr, ext_sh, t); + } + else + t = pend->t; + + /* Alpha cc unnamed structs do not get a tag name. */ + if (sh->iss == 0) + TYPE_TAG_NAME (t) = NULL; + else + TYPE_TAG_NAME (t) = obconcat (¤t_objfile->symbol_obstack, + "", "", name); + + TYPE_CODE (t) = type_code; + TYPE_LENGTH (t) = sh->value; + TYPE_NFIELDS (t) = nfields; + TYPE_FIELDS (t) = f = ((struct field *) + TYPE_ALLOC (t, + nfields * sizeof (struct field))); + + if (type_code == TYPE_CODE_ENUM) + { + /* This is a non-empty enum. */ + for (ext_tsym = ext_sh + external_sym_size; + ; + ext_tsym += external_sym_size) + { + SYMR tsym; + struct symbol *enum_sym; + + (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); + + if (tsym.st != stMember) + break; + + f->bitpos = tsym.value; + f->type = t; + f->name = (ecoff_data (cur_bfd)->ss + + cur_fdr->issBase + + tsym.iss); + f->bitsize = 0; + + enum_sym = ((struct symbol *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct symbol))); + memset ((PTR) enum_sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (enum_sym) = f->name; + SYMBOL_CLASS (enum_sym) = LOC_CONST; + SYMBOL_TYPE (enum_sym) = t; + SYMBOL_NAMESPACE (enum_sym) = VAR_NAMESPACE; + SYMBOL_VALUE (enum_sym) = tsym.value; + add_symbol (enum_sym, top_stack->cur_block); + + /* Skip the stMembers that we've handled. */ + count++; + f++; + } + } + /* make this the current type */ + top_stack->cur_type = t; + top_stack->cur_field = 0; + + /* Do not create a symbol for alpha cc unnamed structs. */ + if (sh->iss == 0) + break; + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = STRUCT_NAMESPACE; + SYMBOL_CLASS (s) = LOC_TYPEDEF; + SYMBOL_VALUE (s) = 0; + SYMBOL_TYPE (s) = t; + + /* gcc puts out an empty struct for an opaque struct definitions. */ + if (TYPE_NFIELDS (t) == 0) + { + TYPE_FLAGS (t) |= TYPE_FLAG_STUB; + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + } + add_symbol (s, top_stack->cur_block); + break; + + /* End of local variables shared by struct, union, enum, and + block (as yet unknown struct/union/enum) processing. */ + } + + case_stBlock_code: + /* beginnning of (code) block. Value of symbol + is the displacement from procedure start */ + push_parse_stack (); + top_stack->blocktype = stBlock; + b = new_block (top_stack->maxsyms); + BLOCK_START (b) = sh->value + top_stack->procadr; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + top_stack->cur_block = b; + add_block (b, top_stack->cur_st); + break; + + case stEnd: /* end (of anything) */ + if (sh->sc == scInfo || sh->sc == scCommon) + { + /* Finished with type */ + top_stack->cur_type = 0; + } + else if (sh->sc == scText && + (top_stack->blocktype == stProc || + top_stack->blocktype == stStaticProc)) + { + /* Finished with procedure */ + struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st); + struct mips_extra_func_info *e; + struct block *b; + int i; + + BLOCK_END (top_stack->cur_block) += sh->value; /* size */ + + /* Make up special symbol to contain procedure specific info */ + s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = builtin_type_void; + e = ((struct mips_extra_func_info *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct mips_extra_func_info))); + SYMBOL_VALUE (s) = (long) e; + e->numargs = top_stack->numargs; + add_symbol (s, top_stack->cur_block); + + /* Reallocate symbols, saving memory */ + b = shrink_block (top_stack->cur_block, top_stack->cur_st); + + /* f77 emits proc-level with address bounds==[0,0], + So look for such child blocks, and patch them. */ + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) + { + struct block *b_bad = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SUPERBLOCK (b_bad) == b + && BLOCK_START (b_bad) == top_stack->procadr + && BLOCK_END (b_bad) == top_stack->procadr) + { + BLOCK_START (b_bad) = BLOCK_START (b); + BLOCK_END (b_bad) = BLOCK_END (b); + } + } + } + else if (sh->sc == scText && top_stack->blocktype == stBlock) + { + /* End of (code) block. The value of the symbol is the + displacement from the procedure`s start address of the + end of this block. */ + BLOCK_END (top_stack->cur_block) = sh->value + top_stack->procadr; + shrink_block (top_stack->cur_block, top_stack->cur_st); + } + else if (sh->sc == scText && top_stack->blocktype == stFile) + { + /* End of file. Pop parse stack and ignore. Higher + level code deals with this. */ + ; + } + else + complain (&stEnd_complaint, sh->sc); + + pop_parse_stack (); /* restore previous lexical context */ + break; + + case stMember: /* member of struct or union */ + f = &TYPE_FIELDS (top_stack->cur_type)[top_stack->cur_field++]; + f->name = name; + f->bitpos = sh->value; + bitsize = 0; + f->type = parse_type (cur_fd, ax, sh->index, &bitsize, bigend, name); + f->bitsize = bitsize; + break; + + case stTypedef: /* type definition */ + /* Typedefs for forward declarations and opaque structs from alpha cc + are handled by cross_ref, skip them. */ + if (sh->iss == 0) + break; + + /* Parse the type or use the pending type. */ + pend = is_pending_symbol (cur_fdr, ext_sh); + if (pend == (struct mips_pending *) NULL) + { + t = parse_type (cur_fd, ax, sh->index, (int *)NULL, bigend, name); + add_pending (cur_fdr, ext_sh, t); + } + else + t = pend->t; + + /* mips cc puts out a typedef with the name of the struct for forward + declarations. These should not go into the symbol table and + TYPE_NAME should not be set for them. + They can't be distinguished from an intentional typedef to + the same name however: + x.h: + struct x { int ix; int jx; }; + struct xx; + x.c: + typedef struct x x; + struct xx {int ixx; int jxx; }; + generates a cross referencing stTypedef for x and xx. + The user visible effect of this is that the type of a pointer + to struct foo sometimes is given as `foo *' instead of `struct foo *'. + The problem is fixed with alpha cc. */ + + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_TYPEDEF; + SYMBOL_BLOCK_VALUE (s) = top_stack->cur_block; + SYMBOL_TYPE (s) = t; + add_symbol (s, top_stack->cur_block); + + /* Incomplete definitions of structs should not get a name. */ + if (TYPE_NAME (SYMBOL_TYPE (s)) == NULL + && (TYPE_NFIELDS (SYMBOL_TYPE (s)) != 0 + || (TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_STRUCT + && TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_UNION))) + { + if (TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_PTR + || TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; CC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type + refering to the stTypedef symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + } + else + TYPE_NAME (SYMBOL_TYPE (s)) = SYMBOL_NAME (s); + } + break; + + case stFile: /* file name */ + push_parse_stack (); + top_stack->blocktype = sh->st; + break; + + /* I`ve never seen these for C */ + case stRegReloc: + break; /* register relocation */ + case stForward: + break; /* forwarding address */ + case stConstant: + break; /* constant */ + default: + complain (&unknown_mips_symtype_complaint, sh->st); + break; + } + + return count; +} + +/* Parse the type information provided in the raw AX entries for + the symbol SH. Return the bitfield size in BS, in case. + We must byte-swap the AX entries before we use them; BIGEND says whether + they are big-endian or little-endian (from fh->fBigendian). */ + +static struct type * +parse_type (fd, ax, aux_index, bs, bigend, sym_name) + int fd; + union aux_ext *ax; + unsigned int aux_index; + int *bs; + int bigend; + char *sym_name; +{ + /* Null entries in this map are treated specially */ + static struct type **map_bt[] = + { + &builtin_type_void, /* btNil */ + 0, /* btAdr */ + &builtin_type_char, /* btChar */ + &builtin_type_unsigned_char,/* btUChar */ + &builtin_type_short, /* btShort */ + &builtin_type_unsigned_short, /* btUShort */ + &builtin_type_int, /* btInt */ + &builtin_type_unsigned_int, /* btUInt */ + &builtin_type_long, /* btLong */ + &builtin_type_unsigned_long,/* btULong */ + &builtin_type_float, /* btFloat */ + &builtin_type_double, /* btDouble */ + 0, /* btStruct */ + 0, /* btUnion */ + 0, /* btEnum */ + 0, /* btTypedef */ + 0, /* btRange */ + 0, /* btSet */ + &builtin_type_complex, /* btComplex */ + &builtin_type_double_complex, /* btDComplex */ + 0, /* btIndirect */ + &builtin_type_fixed_dec, /* btFixedDec */ + &builtin_type_float_dec, /* btFloatDec */ + &builtin_type_string, /* btString */ + 0, /* btBit */ + 0, /* btPicture */ + &builtin_type_void, /* btVoid */ + 0, /* DEC C++: Pointer to member */ + 0, /* DEC C++: Virtual function table */ + 0, /* DEC C++: Class (Record) */ + &builtin_type_long, /* btLong64 */ + &builtin_type_unsigned_long, /* btULong64 */ + &builtin_type_long_long, /* btLongLong64 */ + &builtin_type_unsigned_long_long, /* btULongLong64 */ + &builtin_type_unsigned_long, /* btAdr64 */ + &builtin_type_long, /* btInt64 */ + &builtin_type_unsigned_long, /* btUInt64 */ + }; + + TIR t[1]; + struct type *tp = 0; + enum type_code type_code = TYPE_CODE_UNDEF; + + /* Handle corrupt aux indices. */ + if (aux_index >= (ecoff_data (cur_bfd)->fdr + fd)->caux) + { + complain (&index_complaint, sym_name); + return builtin_type_int; + } + ax += aux_index; + + /* Use aux as a type information record, map its basic type. */ + ecoff_swap_tir_in (bigend, &ax->a_ti, t); + if (t->bt >= (sizeof (map_bt) / sizeof (*map_bt))) + { + complain (&basic_type_complaint, t->bt, sym_name); + return builtin_type_int; + } + if (map_bt[t->bt]) + { + tp = *map_bt[t->bt]; + } + else + { + tp = NULL; + /* Cannot use builtin types -- build our own */ + switch (t->bt) + { + case btAdr: + tp = lookup_pointer_type (builtin_type_void); + break; + case btStruct: + type_code = TYPE_CODE_STRUCT; + break; + case btUnion: + type_code = TYPE_CODE_UNION; + break; + case btEnum: + type_code = TYPE_CODE_ENUM; + break; + case btRange: + type_code = TYPE_CODE_RANGE; + break; + case btSet: + type_code = TYPE_CODE_SET; + break; + case btTypedef: + /* alpha cc uses this for typedefs. The true type will be + obtained by crossreferencing below. */ + type_code = TYPE_CODE_ERROR; + break; + default: + complain (&basic_type_complaint, t->bt, sym_name); + return builtin_type_int; + } + } + + /* Move on to next aux */ + ax++; + + if (t->fBitfield) + { + /* Inhibit core dumps with some cfront generated objects that + corrupt the TIR. */ + if (bs == (int *)NULL) + { + complain (&bad_fbitfield_complaint, sym_name); + return builtin_type_int; + } + *bs = AUX_GET_WIDTH (bigend, ax); + ax++; + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We'll make the same effort at sharing. */ + if (t->bt == btStruct || + t->bt == btUnion || + t->bt == btEnum || + + /* btSet (I think) implies that the name is a tag name, not a typedef + name. This apparently is a MIPS extension for C sets. */ + t->bt == btSet) + { + char *name; + + /* Try to cross reference this type, build new type on failure. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + + /* Make sure that TYPE_CODE(tp) has an expected type code. + Any type may be returned from cross_ref if file indirect entries + are corrupted. */ + if (TYPE_CODE (tp) != TYPE_CODE_STRUCT + && TYPE_CODE (tp) != TYPE_CODE_UNION + && TYPE_CODE (tp) != TYPE_CODE_ENUM) + { + complain (&unexpected_type_code_complaint, sym_name); + } + else + { + + /* Usually, TYPE_CODE(tp) is already type_code. The main + exception is if we guessed wrong re struct/union/enum. + But for struct vs. union a wrong guess is harmless, so + don't complain(). */ + if ((TYPE_CODE (tp) == TYPE_CODE_ENUM + && type_code != TYPE_CODE_ENUM) + || (TYPE_CODE (tp) != TYPE_CODE_ENUM + && type_code == TYPE_CODE_ENUM)) + { + complain (&bad_tag_guess_complaint, sym_name); + } + + if (TYPE_CODE (tp) != type_code) + { + TYPE_CODE (tp) = type_code; + } + + /* Do not set the tag name if it is a compiler generated tag name + (.Fxx or .xxfake or empty) for unnamed struct/union/enums. */ + if (name[0] == '.' || name[0] == '\0') + TYPE_TAG_NAME (tp) = NULL; + else if (TYPE_TAG_NAME (tp) == NULL + || !STREQ (TYPE_TAG_NAME (tp), name)) + TYPE_TAG_NAME (tp) = obsavestring (name, strlen (name), + ¤t_objfile->type_obstack); + } + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We'll make the same effort at sharing. + FIXME: btIndirect cannot happen here as it is handled by the + switch t->bt above. And we are not doing any guessing on range types. */ + if (t->bt == btIndirect || + t->bt == btRange) + { + char *name; + + /* Try to cross reference this type, build new type on failure. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + + /* Make sure that TYPE_CODE(tp) has an expected type code. + Any type may be returned from cross_ref if file indirect entries + are corrupted. */ + if (TYPE_CODE (tp) != TYPE_CODE_RANGE) + { + complain (&unexpected_type_code_complaint, sym_name); + } + else + { + /* Usually, TYPE_CODE(tp) is already type_code. The main + exception is if we guessed wrong re struct/union/enum. */ + if (TYPE_CODE (tp) != type_code) + { + complain (&bad_tag_guess_complaint, sym_name); + TYPE_CODE (tp) = type_code; + } + if (TYPE_NAME (tp) == NULL || !STREQ (TYPE_NAME (tp), name)) + TYPE_NAME (tp) = obsavestring (name, strlen (name), + ¤t_objfile->type_obstack); + } + } + if (t->bt == btTypedef) + { + char *name; + + /* Try to cross reference this type, it should succeed. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + { + complain (&unable_to_cross_ref_complaint, sym_name); + tp = builtin_type_int; + } + } + + /* Deal with range types */ + if (t->bt == btRange) + { + TYPE_NFIELDS (tp) = 2; + TYPE_FIELDS (tp) = ((struct field *) + TYPE_ALLOC (tp, 2 * sizeof (struct field))); + TYPE_FIELD_NAME (tp, 0) = obsavestring ("Low", strlen ("Low"), + ¤t_objfile->type_obstack); + TYPE_FIELD_BITPOS (tp, 0) = AUX_GET_DNLOW (bigend, ax); + ax++; + TYPE_FIELD_NAME (tp, 1) = obsavestring ("High", strlen ("High"), + ¤t_objfile->type_obstack); + TYPE_FIELD_BITPOS (tp, 1) = AUX_GET_DNHIGH (bigend, ax); + ax++; + } + + /* Parse all the type qualifiers now. If there are more + than 6 the game will continue in the next aux */ + + while (1) + { +#define PARSE_TQ(tq) \ + if (t->tq != tqNil) \ + ax += upgrade_type(fd, &tp, t->tq, ax, bigend, sym_name); \ + else \ + break; + + PARSE_TQ (tq0); + PARSE_TQ (tq1); + PARSE_TQ (tq2); + PARSE_TQ (tq3); + PARSE_TQ (tq4); + PARSE_TQ (tq5); +#undef PARSE_TQ + + /* mips cc 2.x and gcc never put out continued aux entries. */ + if (!t->continued) + break; + + ecoff_swap_tir_in (bigend, &ax->a_ti, t); + ax++; + } + + /* Complain for illegal continuations due to corrupt aux entries. */ + if (t->continued) + complain (&bad_continued_complaint, sym_name); + + return tp; +} + +/* Make up a complex type from a basic one. Type is passed by + reference in TPP and side-effected as necessary. The type + qualifier TQ says how to handle the aux symbols at AX for + the symbol SX we are currently analyzing. BIGEND says whether + aux symbols are big-endian or little-endian. + Returns the number of aux symbols we parsed. */ + +static int +upgrade_type (fd, tpp, tq, ax, bigend, sym_name) + int fd; + struct type **tpp; + int tq; + union aux_ext *ax; + int bigend; + char *sym_name; +{ + int off; + struct type *t; + + /* Used in array processing */ + int rf, id; + FDR *fh; + struct type *range; + struct type *indx; + int lower, upper; + RNDXR rndx; + + switch (tq) + { + case tqPtr: + t = lookup_pointer_type (*tpp); + *tpp = t; + return 0; + + case tqProc: + t = lookup_function_type (*tpp); + *tpp = t; + return 0; + + case tqArray: + off = 0; + + /* Determine and record the domain type (type of index) */ + ecoff_swap_rndx_in (bigend, &ax->a_rndx, &rndx); + id = rndx.index; + rf = rndx.rfd; + if (rf == 0xfff) + { + ax++; + rf = AUX_GET_ISYM (bigend, ax); + off++; + } + fh = get_rfd (fd, rf); + + indx = parse_type (fd, + ecoff_data (cur_bfd)->external_aux + fh->iauxBase, + id, (int *) NULL, bigend, sym_name); + + /* The bounds type should be an integer type, but might be anything + else due to corrupt aux entries. */ + if (TYPE_CODE (indx) != TYPE_CODE_INT) + { + complain (&array_index_type_complaint, sym_name); + indx = builtin_type_int; + } + + /* Get the bounds, and create the array type. */ + ax++; + lower = AUX_GET_DNLOW (bigend, ax); + ax++; + upper = AUX_GET_DNHIGH (bigend, ax); + ax++; + rf = AUX_GET_WIDTH (bigend, ax); /* bit size of array element */ + + range = create_range_type ((struct type *) NULL, indx, + lower, upper); + + t = create_array_type ((struct type *) NULL, *tpp, range); + + /* We used to fill in the supplied array element bitsize + here if the TYPE_LENGTH of the target type was zero. + This happens for a `pointer to an array of anonymous structs', + but in this case the array element bitsize is also zero, + so nothing is gained. + And we used to check the TYPE_LENGTH of the target type against + the supplied array element bitsize. + gcc causes a mismatch for `pointer to array of object', + since the sdb directives it uses do not have a way of + specifying the bitsize, but it does no harm (the + TYPE_LENGTH should be correct) and we should be able to + ignore the erroneous bitsize from the auxiliary entry safely. + dbx seems to ignore it too. */ + + *tpp = t; + return 4 + off; + + case tqVol: + /* Volatile -- currently ignored */ + return 0; + + case tqConst: + /* Const -- currently ignored */ + return 0; + + default: + complain (&unknown_type_qual_complaint, tq); + return 0; + } +} + + +/* Parse a procedure descriptor record PR. Note that the procedure is + parsed _after_ the local symbols, now we just insert the extra + information we need into a MIPS_EFI_SYMBOL_NAME symbol that has + already been placed in the procedure's main block. Note also that + images that have been partially stripped (ld -x) have been deprived + of local symbols, and we have to cope with them here. FIRST_OFF is + the offset of the first procedure for this FDR; we adjust the + address by this amount, but I don't know why. SEARCH_SYMTAB is the symtab + to look for the function which contains the MIPS_EFI_SYMBOL_NAME symbol + in question, or NULL to use top_stack->cur_block. */ + +static void parse_procedure PARAMS ((PDR *, struct symtab *, unsigned long)); + +static void +parse_procedure (pr, search_symtab, first_off) + PDR *pr; + struct symtab *search_symtab; + unsigned long first_off; +{ + struct symbol *s, *i; + struct block *b; + struct mips_extra_func_info *e; + char *sh_name; + + /* Simple rule to find files linked "-x" */ + if (cur_fdr->rss == -1) + { + if (pr->isym == -1) + { + /* Static procedure at address pr->adr. Sigh. */ + complain (&pdr_static_symbol_complaint, (unsigned long) pr->adr); + return; + } + else + { + /* external */ + EXTR she; + + (*ecoff_backend (cur_bfd)->swap_ext_in) + (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_ext + + pr->isym * ecoff_backend (cur_bfd)->external_ext_size), + &she); + sh_name = ecoff_data (cur_bfd)->ssext + she.asym.iss; + } + } + else + { + /* Full symbols */ + SYMR sh; + + (*ecoff_backend (cur_bfd)->swap_sym_in) + (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + ((cur_fdr->isymBase + pr->isym) + * ecoff_backend (cur_bfd)->external_sym_size)), + &sh); + sh_name = ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh.iss; + } + + if (search_symtab != NULL) + { +#if 0 + /* This loses both in the case mentioned (want a static, find a global), + but also if we are looking up a non-mangled name which happens to + match the name of a mangled function. */ + /* We have to save the cur_fdr across the call to lookup_symbol. + If the pdr is for a static function and if a global function with + the same name exists, lookup_symbol will eventually read in the symtab + for the global function and clobber cur_fdr. */ + FDR *save_cur_fdr = cur_fdr; + s = lookup_symbol (sh_name, NULL, VAR_NAMESPACE, 0, NULL); + cur_fdr = save_cur_fdr; +#else + s = mylookup_symbol + (sh_name, + BLOCKVECTOR_BLOCK (BLOCKVECTOR (search_symtab), STATIC_BLOCK), + VAR_NAMESPACE, + LOC_BLOCK); +#endif + } + else + s = mylookup_symbol (sh_name, top_stack->cur_block, + VAR_NAMESPACE, LOC_BLOCK); + + if (s != 0) + { + b = SYMBOL_BLOCK_VALUE (s); + } + else + { + complain (&pdr_for_nonsymbol_complaint, sh_name); +#if 1 + return; +#else +/* FIXME -- delete. We can't do symbol allocation now; it's all done. */ + s = new_symbol (sh_name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + /* Donno its type, hope int is ok */ + SYMBOL_TYPE (s) = lookup_function_type (builtin_type_int); + add_symbol (s, top_stack->cur_block); + /* Wont have symbols for this one */ + b = new_block (2); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_FUNCTION (b) = s; + BLOCK_START (b) = pr->adr; + /* BOUND used to be the end of procedure's text, but the + argument is no longer passed in. */ + BLOCK_END (b) = bound; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + add_block (b, top_stack->cur_st); +#endif + } + + i = mylookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, LOC_CONST); + + if (i) + { + e = (struct mips_extra_func_info *) SYMBOL_VALUE (i); + e->pdr = *pr; + e->pdr.isym = (long) s; + e->pdr.adr += cur_fdr->adr - first_off; + + /* Correct incorrect setjmp procedure descriptor from the library + to make backtrace through setjmp work. */ + if (e->pdr.pcreg == 0 && STREQ (sh_name, "setjmp")) + { + complain (&bad_setjmp_pdr_complaint, 0); + e->pdr.pcreg = RA_REGNUM; + e->pdr.regmask = 0x80000000; + e->pdr.regoffset = -4; + } + + /* Fake PC_REGNUM for alpha __sigtramp so that read_next_frame_reg + will use the saved user pc from the sigcontext. */ + if (STREQ (sh_name, "__sigtramp")) + e->pdr.pcreg = PC_REGNUM; + } +} + +/* Parse the external symbol ES. Just call parse_symbol() after + making sure we know where the aux are for it. For procedures, + parsing of the PDRs has already provided all the needed + information, we only parse them if SKIP_PROCEDURES is false, + and only if this causes no symbol duplication. + BIGEND says whether aux entries are big-endian or little-endian. + + This routine clobbers top_stack->cur_block and ->cur_st. */ + +static void +parse_external (es, skip_procedures, bigend) + EXTR *es; + int skip_procedures; + int bigend; +{ + union aux_ext *ax; + + if (es->ifd != ifdNil) + { + cur_fd = es->ifd; + cur_fdr = ecoff_data (cur_bfd)->fdr + cur_fd; + ax = ecoff_data (cur_bfd)->external_aux + cur_fdr->iauxBase; + } + else + { + cur_fdr = ecoff_data (cur_bfd)->fdr; + ax = 0; + } + + /* Reading .o files */ + if (es->asym.sc == scUndefined || es->asym.sc == scNil) + { + char *what; + switch (es->asym.st) + { + case stNil: + /* These are generated for static symbols in .o files, + ignore them. */ + return; + case stStaticProc: + case stProc: + what = "procedure"; + n_undef_procs++; + break; + case stGlobal: + what = "variable"; + n_undef_vars++; + break; + case stLabel: + what = "label"; + n_undef_labels++; + break; + default: + what = "symbol"; + break; + } + n_undef_symbols++; + /* FIXME: Turn this into a complaint? */ + if (info_verbose) + printf_filtered ("Warning: %s `%s' is undefined (in %s)\n", + what, + ecoff_data (cur_bfd)->ssext + es->asym.iss, + fdr_name (cur_fdr)); + return; + } + + switch (es->asym.st) + { + case stProc: + /* If we have full symbols we do not need more */ + if (skip_procedures) + return; + if (mylookup_symbol (ecoff_data (cur_bfd)->ssext + es->asym.iss, + top_stack->cur_block, + VAR_NAMESPACE, LOC_BLOCK)) + break; + /* fall through */ + case stGlobal: + case stLabel: + /* Note that the case of a symbol with indexNil must be handled + anyways by parse_symbol(). */ + parse_symbol (&es->asym, ax, (char *) NULL, bigend); + break; + default: + break; + } +} + +/* Parse the line number info for file descriptor FH into + GDB's linetable LT. MIPS' encoding requires a little bit + of magic to get things out. Note also that MIPS' line + numbers can go back and forth, apparently we can live + with that and do not need to reorder our linetables */ + +static void +parse_lines (fh, pr, lt, maxlines) + FDR *fh; + PDR *pr; + struct linetable *lt; + int maxlines; +{ + unsigned char *base; + int j, k; + int delta, count, lineno = 0; + unsigned long first_off = pr->adr; + + if (fh->cbLine == 0) + return; + + base = ecoff_data (cur_bfd)->line + fh->cbLineOffset; + + /* Scan by procedure descriptors */ + k = 0; + for (j = 0; j < fh->cpd; j++, pr++) + { + long l; + unsigned long adr; + unsigned char *halt; + + /* No code for this one */ + if (pr->iline == ilineNil || + pr->lnLow == -1 || pr->lnHigh == -1) + continue; + + /* Determine start and end address of compressed line bytes for + this procedure. */ + base = ecoff_data (cur_bfd)->line + fh->cbLineOffset; + if (j != (fh->cpd - 1)) + halt = base + pr[1].cbLineOffset; + else + halt = base + fh->cbLine; + base += pr->cbLineOffset; + + adr = fh->adr + pr->adr - first_off; + l = adr >> 2; /* in words */ + for (lineno = pr->lnLow; base < halt; ) + { + count = *base & 0x0f; + delta = *base++ >> 4; + if (delta >= 8) + delta -= 16; + if (delta == -8) + { + delta = (base[0] << 8) | base[1]; + if (delta >= 0x8000) + delta -= 0x10000; + base += 2; + } + lineno += delta; /* first delta is 0 */ + + /* Complain if the line table overflows. Could happen + with corrupt binaries. */ + if (lt->nitems >= maxlines) + { + complain (&bad_linetable_guess_complaint, fdr_name (fh)); + break; + } + k = add_line (lt, lineno, l, k); + l += count + 1; + } + } +} + +/* Master parsing procedure for first-pass reading of file symbols + into a partial_symtab. */ + +static void +parse_partial_symbols (objfile, section_offsets) + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (cur_bfd); + const bfd_size_type external_sym_size = backend->external_sym_size; + const bfd_size_type external_rfd_size = backend->external_rfd_size; + const bfd_size_type external_ext_size = backend->external_ext_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->swap_ext_in; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = backend->swap_sym_in; + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = backend->swap_rfd_in; + int f_idx, s_idx; + HDRR *hdr = &ecoff_data (cur_bfd)->symbolic_header; + /* Running pointers */ + FDR *fh; + char *ext_out; + char *ext_out_end; + EXTR *ext_block; + register EXTR *ext_in; + EXTR *ext_in_end; + SYMR sh; + struct partial_symtab *pst; + + int past_first_source_file = 0; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + EXTR *extern_tab; + struct pst_map *fdr_to_pst; + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + struct cleanup *old_chain; + char *name; + enum language prev_language; + + extern_tab = (EXTR *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (EXTR) * hdr->iextMax); + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + next_symbol_text_func = mips_next_symbol_text; + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + last_source_file = NULL; + + /* + * Big plan: + * + * Only parse the Local and External symbols, and the Relative FDR. + * Fixup enough of the loader symtab to be able to use it. + * Allocate space only for the file's portions we need to + * look at. (XXX) + */ + + max_gdbinfo = 0; + max_glevel = MIN_GLEVEL; + + /* Allocate the map FDR -> PST. + Minor hack: -O3 images might claim some global data belongs + to FDR -1. We`ll go along with that */ + fdr_to_pst = (struct pst_map *) xzalloc ((hdr->ifdMax + 1) * sizeof *fdr_to_pst); + old_chain = make_cleanup (free, fdr_to_pst); + fdr_to_pst++; + { + struct partial_symtab *pst = new_psymtab ("", objfile); + fdr_to_pst[-1].pst = pst; + FDR_IDX (pst) = -1; + } + + /* Allocate the global pending list. */ + ECOFF_PENDING_LIST (objfile) = + ((struct mips_pending **) + obstack_alloc (&objfile->psymbol_obstack, + hdr->ifdMax * sizeof (struct mips_pending *))); + memset ((PTR) ECOFF_PENDING_LIST (objfile), 0, + hdr->ifdMax * sizeof (struct mips_pending *)); + + /* Pass 0 over external syms: swap them in. */ + ext_block = (EXTR *) xmalloc (hdr->iextMax * sizeof (EXTR)); + make_cleanup (free, ext_block); + + ext_out = (char *) ecoff_data (cur_bfd)->external_ext; + ext_out_end = ext_out + hdr->iextMax * external_ext_size; + ext_in = ext_block; + for (; ext_out < ext_out_end; ext_out += external_ext_size, ext_in++) + (*swap_ext_in) (cur_bfd, ext_out, ext_in); + + /* Pass 1 over external syms: Presize and partition the list */ + ext_in = ext_block; + ext_in_end = ext_in + hdr->iextMax; + for (; ext_in < ext_in_end; ext_in++) + fdr_to_pst[ext_in->ifd].n_globals++; + + /* Pass 1.5 over files: partition out global symbol space */ + s_idx = 0; + for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) + { + fdr_to_pst[f_idx].globals_offset = s_idx; + s_idx += fdr_to_pst[f_idx].n_globals; + fdr_to_pst[f_idx].n_globals = 0; + } + + /* Pass 2 over external syms: fill in external symbols */ + ext_in = ext_block; + ext_in_end = ext_in + hdr->iextMax; + for (; ext_in < ext_in_end; ext_in++) + { + enum minimal_symbol_type ms_type = mst_text; + + extern_tab[fdr_to_pst[ext_in->ifd].globals_offset + + fdr_to_pst[ext_in->ifd].n_globals++] = *ext_in; + + if (ext_in->asym.sc == scUndefined || ext_in->asym.sc == scNil) + continue; + + name = ecoff_data (cur_bfd)->ssext + ext_in->asym.iss; + switch (ext_in->asym.st) + { + case stProc: + break; + case stStaticProc: + ms_type = mst_file_text; + break; + case stGlobal: + if (ext_in->asym.sc == scData + || ext_in->asym.sc == scSData + || ext_in->asym.sc == scRData) + ms_type = mst_data; + else + ms_type = mst_bss; + break; + case stLabel: + if (ext_in->asym.sc == scAbs) + ms_type = mst_abs; + else if (ext_in->asym.sc == scText) + ms_type = mst_text; + else if (ext_in->asym.sc == scData + || ext_in->asym.sc == scSData + || ext_in->asym.sc == scRData) + ms_type = mst_data; + else + ms_type = mst_bss; + break; + case stLocal: + /* The alpha has the section start addresses in stLocal symbols + whose name starts with a `.'. Skip those but complain for all + other stLocal symbols. */ + if (name[0] == '.') + continue; + /* Fall through. */ + default: + ms_type = mst_unknown; + complain (&unknown_ext_complaint, name); + } + prim_record_minimal_symbol (name, ext_in->asym.value, ms_type); + } + + /* Pass 3 over files, over local syms: fill in static symbols */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + { + struct partial_symtab *save_pst; + EXTR *ext_ptr; + + cur_fdr = fh = ecoff_data (cur_bfd)->fdr + f_idx; + + if (fh->csym == 0) + { + fdr_to_pst[f_idx].pst = NULL; + continue; + } + pst = start_psymtab_common (objfile, section_offsets, + fdr_name (fh), + fh->cpd ? fh->adr : 0, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + pst->read_symtab_private = ((char *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc))); + memset ((PTR) pst->read_symtab_private, 0, sizeof (struct symloc)); + + save_pst = pst; + FDR_IDX (pst) = f_idx; + CUR_BFD (pst) = cur_bfd; + + /* The way to turn this into a symtab is to call... */ + pst->read_symtab = mipscoff_psymtab_to_symtab; + + /* Set up language for the pst. + The language from the FDR is used if it is unambigious (e.g. cfront + with native cc and g++ will set the language to C). + Otherwise we have to deduce the language from the filename. + Native ecoff has every header file in a separate FDR, so + deduce_language_from_filename will return language_unknown for + a header file, which is not what we want. + But the FDRs for the header files are after the FDR for the source + file, so we can assign the language of the source file to the + following header files. Then we save the language in the private + pst data so that we can reuse it when building symtabs. */ + prev_language = psymtab_language; + + switch (fh->lang) + { + case langCplusplusV2: + psymtab_language = language_cplus; + break; + default: + psymtab_language = deduce_language_from_filename (fdr_name (fh)); + break; + } + if (psymtab_language == language_unknown) + psymtab_language = prev_language; + PST_PRIVATE (pst)->pst_language = psymtab_language; + + pst->texthigh = pst->textlow; + + /* For stabs-in-ecoff files, the second symbol must be @stab. + This symbol is emitted by mips-tfile to signal that the + current object file uses encapsulated stabs instead of mips + ecoff for local symbols. (It is the second symbol because + the first symbol is the stFile used to signal the start of a + file). */ + processing_gcc_compilation = 0; + if (fh->csym >= 2) + { + (*swap_sym_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + (fh->isymBase + 1) * external_sym_size), + &sh); + if (STREQ (ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss, + stabs_symbol)) + processing_gcc_compilation = 2; + } + + if (processing_gcc_compilation != 0) + { + for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) + { + int type_code; + char *namestring; + + (*swap_sym_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + (fh->isymBase + cur_sdx) * external_sym_size), + &sh); + type_code = ECOFF_UNMARK_STAB (sh.index); + if (!ECOFF_IS_STAB (&sh)) + { + if (sh.st == stProc || sh.st == stStaticProc) + { + long procaddr = sh.value; + long isym; + + + isym = AUX_GET_ISYM (fh->fBigendian, + (ecoff_data (cur_bfd)->external_aux + + fh->iauxBase + + sh.index)); + (*swap_sym_in) (cur_bfd, + (((char *) + ecoff_data (cur_bfd)->external_sym) + + ((fh->isymBase + isym - 1) + * external_sym_size)), + &sh); + if (sh.st == stEnd) + { + long high = procaddr + sh.value; + if (high > pst->texthigh) + pst->texthigh = high; + } + } + continue; + } +#define SET_NAMESTRING() \ + namestring = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss +#define CUR_SYMBOL_TYPE type_code +#define CUR_SYMBOL_VALUE sh.value +#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\ + pst = save_pst +#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) (void)0 +#define HANDLE_RBRAC(val) \ + if ((val) > save_pst->texthigh) save_pst->texthigh = (val); +#include "partial-stab.h" + } + } + else + { + for (cur_sdx = 0; cur_sdx < fh->csym;) + { + char *name; + enum address_class class; + + (*swap_sym_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + ((fh->isymBase + cur_sdx) + * external_sym_size)), + &sh); + + if (ECOFF_IS_STAB (&sh)) + { + cur_sdx++; + continue; + } + + /* Non absolute static symbols go into the minimal table. */ + if (sh.sc == scUndefined || sh.sc == scNil + || (sh.index == indexNil + && (sh.st != stStatic || sh.sc == scAbs))) + { + /* FIXME, premature? */ + cur_sdx++; + continue; + } + + name = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss; + + switch (sh.st) + { + long high; + long procaddr; + int new_sdx; + + case stStaticProc: /* Function */ + /* I believe this is used only for file-local functions. + The comment in symconst.h ("load time only static procs") + isn't particularly clear on this point. */ + prim_record_minimal_symbol (name, sh.value, mst_file_text); + /* FALLTHROUGH */ + + case stProc: /* Asm labels apparently */ + ADD_PSYMBOL_TO_LIST (name, strlen (name), + VAR_NAMESPACE, LOC_BLOCK, + objfile->static_psymbols, sh.value, + psymtab_language, objfile); + /* Skip over procedure to next one. */ + if (sh.index >= hdr->iauxMax) + { + /* Should not happen, but does when cross-compiling + with the MIPS compiler. FIXME -- pull later. */ + complain (&index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip at all */ + } + else + new_sdx = AUX_GET_ISYM (fh->fBigendian, + (ecoff_data (cur_bfd)->external_aux + + fh->iauxBase + + sh.index)); + procaddr = sh.value; + + if (new_sdx <= cur_sdx) + { + /* This should not happen either... FIXME. */ + complain (&aux_index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip backward */ + } + + cur_sdx = new_sdx; + (*swap_sym_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + ((fh->isymBase + cur_sdx - 1) + * external_sym_size)), + &sh); + if (sh.st != stEnd) + continue; + high = procaddr + sh.value; + if (high > pst->texthigh) + pst->texthigh = high; + continue; + + case stStatic: /* Variable */ + if (sh.sc == scData || sh.sc == scSData || sh.sc == scRData) + prim_record_minimal_symbol (name, sh.value, mst_file_data); + else + prim_record_minimal_symbol (name, sh.value, mst_file_bss); + class = LOC_STATIC; + break; + + case stTypedef:/* Typedef */ + class = LOC_TYPEDEF; + break; + + case stConstant: /* Constant decl */ + class = LOC_CONST; + break; + + case stUnion: + case stStruct: + case stEnum: + case stBlock: /* { }, str, un, enum*/ + if (sh.sc == scInfo || sh.sc == scCommon) + { + ADD_PSYMBOL_TO_LIST (name, strlen (name), + STRUCT_NAMESPACE, LOC_TYPEDEF, + objfile->static_psymbols, + sh.value, + psymtab_language, objfile); + } + /* Skip over the block */ + new_sdx = sh.index; + if (new_sdx <= cur_sdx) + { + /* This happens with the Ultrix kernel. */ + complain (&block_index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip backward */ + } + cur_sdx = new_sdx; + continue; + + case stFile: /* File headers */ + case stLabel: /* Labels */ + case stEnd: /* Ends of files */ + goto skip; + + case stLocal: /* Local variables */ + /* Normally these are skipped because we skip over + all blocks we see. However, these can occur + as visible symbols in a .h file that contains code. */ + goto skip; + + default: + /* Both complaints are valid: one gives symbol name, + the other the offending symbol type. */ + complain (&unknown_sym_complaint, name); + complain (&unknown_st_complaint, sh.st); + cur_sdx++; + continue; + } + /* Use this gdb symbol */ + ADD_PSYMBOL_TO_LIST (name, strlen (name), + VAR_NAMESPACE, class, + objfile->static_psymbols, sh.value, + psymtab_language, objfile); + skip: + cur_sdx++; /* Go to next file symbol */ + } + + /* Now do enter the external symbols. */ + ext_ptr = &extern_tab[fdr_to_pst[f_idx].globals_offset]; + cur_sdx = fdr_to_pst[f_idx].n_globals; + PST_PRIVATE (save_pst)->extern_count = cur_sdx; + PST_PRIVATE (save_pst)->extern_tab = ext_ptr; + for (; --cur_sdx >= 0; ext_ptr++) + { + enum address_class class; + SYMR *psh; + char *name; + + if (ext_ptr->ifd != f_idx) + abort (); + psh = &ext_ptr->asym; + + /* Do not add undefined symbols to the partial symbol table. */ + if (psh->sc == scUndefined || psh->sc == scNil) + continue; + + switch (psh->st) + { + case stNil: + /* These are generated for static symbols in .o files, + ignore them. */ + continue; + case stProc: + case stStaticProc: + class = LOC_BLOCK; + break; + case stLabel: + class = LOC_LABEL; + break; + default: + complain (&unknown_ext_complaint, + ecoff_data (cur_bfd)->ssext + psh->iss); + /* Fall through, pretend it's global. */ + case stGlobal: + class = LOC_STATIC; + break; + } + name = ecoff_data (cur_bfd)->ssext + psh->iss; + ADD_PSYMBOL_ADDR_TO_LIST (name, strlen (name), + VAR_NAMESPACE, class, + objfile->global_psymbols, (CORE_ADDR) psh->value, + psymtab_language, objfile); + } + } + + /* Link pst to FDR. end_psymtab returns NULL if the psymtab was + empty and put on the free list. */ + fdr_to_pst[f_idx].pst = end_psymtab (save_pst, + psymtab_include_list, includes_used, + -1, save_pst->texthigh, + dependency_list, dependencies_used); + if (objfile->ei.entry_point >= save_pst->textlow && + objfile->ei.entry_point < save_pst->texthigh) + { + objfile->ei.entry_file_lowpc = save_pst->textlow; + objfile->ei.entry_file_highpc = save_pst->texthigh; + } + } + + /* Now scan the FDRs for dependencies */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + { + fh = f_idx + ecoff_data (cur_bfd)->fdr; + pst = fdr_to_pst[f_idx].pst; + + if (pst == (struct partial_symtab *)NULL) + continue; + + /* This should catch stabs-in-ecoff. */ + if (fh->crfd <= 1) + continue; + + /* Skip the first file indirect entry as it is a self dependency + for source files or a reverse .h -> .c dependency for header files. */ + pst->number_of_dependencies = 0; + pst->dependencies = + ((struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + ((fh->crfd - 1) + * sizeof (struct partial_symtab *)))); + for (s_idx = 1; s_idx < fh->crfd; s_idx++) + { + RFDT rh; + + (*swap_rfd_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_rfd + + (fh->rfdBase + s_idx) * external_rfd_size), + &rh); + if (rh < 0 || rh >= hdr->ifdMax) + { + complain (&bad_file_number_complaint, rh); + continue; + } + + /* Skip self dependencies of header files. */ + if (rh == f_idx) + continue; + + /* Do not add to dependeny list if psymtab was empty. */ + if (fdr_to_pst[rh].pst == (struct partial_symtab *)NULL) + continue; + pst->dependencies[pst->number_of_dependencies++] = fdr_to_pst[rh].pst; + } + } + do_cleanups (old_chain); +} + + +static char * +mips_next_symbol_text () +{ + SYMR sh; + + cur_sdx++; + (*ecoff_backend (cur_bfd)->swap_sym_in) + (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + ((cur_fdr->isymBase + cur_sdx) + * ecoff_backend (cur_bfd)->external_sym_size)), + &sh); + return ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh.iss; +} + +/* Ancillary function to psymtab_to_symtab(). Does all the work + for turning the partial symtab PST into a symtab, recurring + first on all dependent psymtabs. The argument FILENAME is + only passed so we can see in debug stack traces what file + is being read. + + This function has a split personality, based on whether the + symbol table contains ordinary ecoff symbols, or stabs-in-ecoff. + The flow of control and even the memory allocation differs. FIXME. */ + +static void +psymtab_to_symtab_1 (pst, filename) + struct partial_symtab *pst; + char *filename; +{ + const bfd_size_type external_sym_size + = ecoff_backend (cur_bfd)->external_sym_size; + const bfd_size_type external_pdr_size + = ecoff_backend (cur_bfd)->external_pdr_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = ecoff_backend (cur_bfd)->swap_sym_in; + void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)) + = ecoff_backend (cur_bfd)->swap_pdr_in; + int i; + struct symtab *st; + FDR *fh; + struct linetable *lines; + + if (pst->readin) + return; + pst->readin = 1; + + /* Read in all partial symbtabs on which this one is dependent. + NOTE that we do have circular dependencies, sigh. We solved + that by setting pst->readin before this point. */ + + for (i = 0; i < pst->number_of_dependencies; i++) + if (!pst->dependencies[i]->readin) + { + /* Inform about additional files to be read in. */ + if (info_verbose) + { + fputs_filtered (" ", stdout); + wrap_here (""); + fputs_filtered ("and ", stdout); + wrap_here (""); + printf_filtered ("%s...", + pst->dependencies[i]->filename); + wrap_here (""); /* Flush output */ + fflush (stdout); + } + /* We only pass the filename for debug purposes */ + psymtab_to_symtab_1 (pst->dependencies[i], + pst->dependencies[i]->filename); + } + + /* Do nothing if this is a dummy psymtab. */ + + if (pst->n_global_syms == 0 && pst->n_static_syms == 0 + && pst->textlow == 0 && pst->texthigh == 0) + return; + + /* Now read the symbols for this symtab */ + + cur_bfd = CUR_BFD (pst); + current_objfile = pst->objfile; + cur_fd = FDR_IDX (pst); + fh = (cur_fd == -1) ? (FDR *) NULL : ecoff_data (cur_bfd)->fdr + cur_fd; + cur_fdr = fh; + + /* See comment in parse_partial_symbols about the @stabs sentinel. */ + processing_gcc_compilation = 0; + if (fh != (FDR *) NULL && fh->csym >= 2) + { + SYMR sh; + + (*swap_sym_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + (fh->isymBase + 1) * external_sym_size), + &sh); + if (STREQ (ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss, + stabs_symbol)) + { + /* We indicate that this is a GCC compilation so that certain + features will be enabled in stabsread/dbxread. */ + processing_gcc_compilation = 2; + } + } + + if (processing_gcc_compilation != 0) + { + char *pdr_ptr; + char *pdr_end; + int first_pdr; + unsigned long first_off = 0; + + /* This symbol table contains stabs-in-ecoff entries. */ + + /* Parse local symbols first */ + + if (fh->csym <= 2) /* FIXME, this blows psymtab->symtab ptr */ + { + current_objfile = NULL; + return; + } + for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) + { + SYMR sh; + char *name; + CORE_ADDR valu; + + (*swap_sym_in) (cur_bfd, + ((char *) ecoff_data (cur_bfd)->external_sym + + (fh->isymBase + cur_sdx) * external_sym_size), + &sh); + name = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss; + valu = sh.value; + if (ECOFF_IS_STAB (&sh)) + { + int type_code = ECOFF_UNMARK_STAB (sh.index); + process_one_symbol (type_code, 0, valu, name, + pst->section_offsets, pst->objfile); + if (type_code == N_FUN) + { + /* Make up special symbol to contain + procedure specific info */ + struct mips_extra_func_info *e = + ((struct mips_extra_func_info *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct mips_extra_func_info))); + struct symbol *s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = builtin_type_void; + SYMBOL_VALUE (s) = (long) e; + add_symbol_to_list (s, &local_symbols); + } + } + else if (sh.st == stLabel && sh.index != indexNil) + { + /* Handle encoded stab line number. */ + record_line (current_subfile, sh.index, valu); + } + else if (sh.st == stProc || sh.st == stStaticProc || sh.st == stEnd) + /* These are generated by gcc-2.x, do not complain */ + ; + else + complain (&stab_unknown_complaint, name); + } + st = end_symtab (pst->texthigh, 0, 0, pst->objfile, SECT_OFF_TEXT); + end_stabs (); + + /* Sort the symbol table now, we are done adding symbols to it. + We must do this before parse_procedure calls lookup_symbol. */ + sort_symtab_syms (st); + + /* This may not be necessary for stabs symtabs. FIXME. */ + sort_blocks (st); + + /* Fill in procedure info next. */ + first_pdr = 1; + pdr_ptr = ((char *) ecoff_data (cur_bfd)->external_pdr + + fh->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fh->cpd * external_pdr_size; + for (; pdr_ptr < pdr_end; pdr_ptr += external_pdr_size) + { + PDR pr; + + (*swap_pdr_in) (cur_bfd, pdr_ptr, &pr); + if (first_pdr) + { + first_off = pr.adr; + first_pdr = 0; + } + parse_procedure (&pr, st, first_off); + } + } + else + { + /* This symbol table contains ordinary ecoff entries. */ + + /* FIXME: doesn't use pst->section_offsets. */ + + int f_max; + int maxlines; + EXTR *ext_ptr; + + /* How many symbols will we need */ + /* FIXME, this does not count enum values. */ + f_max = pst->n_global_syms + pst->n_static_syms; + if (fh == 0) + { + maxlines = 0; + st = new_symtab ("unknown", f_max, 0, pst->objfile); + } + else + { + f_max += fh->csym + fh->cpd; + maxlines = 2 * fh->cline; + st = new_symtab (pst->filename, 2 * f_max, maxlines, pst->objfile); + + /* The proper language was already determined when building + the psymtab, use it. */ + st->language = PST_PRIVATE (pst)->pst_language; + } + + psymtab_language = st->language; + + lines = LINETABLE (st); + + /* Get a new lexical context */ + + push_parse_stack (); + top_stack->cur_st = st; + top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (st), + STATIC_BLOCK); + BLOCK_START (top_stack->cur_block) = fh ? fh->adr : 0; + BLOCK_END (top_stack->cur_block) = 0; + top_stack->blocktype = stFile; + top_stack->maxsyms = 2 * f_max; + top_stack->cur_type = 0; + top_stack->procadr = 0; + top_stack->numargs = 0; + + if (fh) + { + char *sym_ptr; + char *sym_end; + + /* Parse local symbols first */ + sym_ptr = ((char *) ecoff_data (cur_bfd)->external_sym + + fh->isymBase * external_sym_size); + sym_end = sym_ptr + fh->csym * external_sym_size; + while (sym_ptr < sym_end) + { + SYMR sh; + int c; + + (*swap_sym_in) (cur_bfd, sym_ptr, &sh); + c = parse_symbol (&sh, + (ecoff_data (cur_bfd)->external_aux + + fh->iauxBase), + sym_ptr, fh->fBigendian); + sym_ptr += c * external_sym_size; + } + + /* Linenumbers. At the end, check if we can save memory. + parse_lines has to look ahead an arbitrary number of PDR + structures, so we swap them all first. */ + if (fh->cpd > 0) + { + PDR *pr_block; + struct cleanup *old_chain; + char *pdr_ptr; + char *pdr_end; + PDR *pdr_in; + PDR *pdr_in_end; + + pr_block = (PDR *) xmalloc (fh->cpd * sizeof (PDR)); + + old_chain = make_cleanup (free, pr_block); + + pdr_ptr = ((char *) ecoff_data (cur_bfd)->external_pdr + + fh->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fh->cpd * external_pdr_size; + pdr_in = pr_block; + for (; + pdr_ptr < pdr_end; + pdr_ptr += external_pdr_size, pdr_in++) + (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in); + + parse_lines (fh, pr_block, lines, maxlines); + if (lines->nitems < fh->cline) + lines = shrink_linetable (lines); + + /* Fill in procedure info next. */ + pdr_in = pr_block; + pdr_in_end = pdr_in + fh->cpd; + for (; pdr_in < pdr_in_end; pdr_in++) + parse_procedure (pdr_in, 0, pr_block->adr); + + do_cleanups (old_chain); + } + } + + LINETABLE (st) = lines; + + /* .. and our share of externals. + XXX use the global list to speed up things here. how? + FIXME, Maybe quit once we have found the right number of ext's? */ + top_stack->cur_st = st; + top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st), + GLOBAL_BLOCK); + top_stack->blocktype = stFile; + top_stack->maxsyms = (ecoff_data (cur_bfd)->symbolic_header.isymMax + + ecoff_data (cur_bfd)->symbolic_header.ipdMax + + ecoff_data (cur_bfd)->symbolic_header.iextMax); + + ext_ptr = PST_PRIVATE (pst)->extern_tab; + for (i = PST_PRIVATE (pst)->extern_count; --i >= 0; ext_ptr++) + parse_external (ext_ptr, 1, fh->fBigendian); + + /* If there are undefined symbols, tell the user. + The alpha has an undefined symbol for every symbol that is + from a shared library, so tell the user only if verbose is on. */ + if (info_verbose && n_undef_symbols) + { + printf_filtered ("File %s contains %d unresolved references:", + st->filename, n_undef_symbols); + printf_filtered ("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n", + n_undef_vars, n_undef_procs, n_undef_labels); + n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0; + + } + pop_parse_stack (); + + /* Sort the symbol table now, we are done adding symbols to it.*/ + sort_symtab_syms (st); + + sort_blocks (st); + } + + /* Now link the psymtab and the symtab. */ + pst->symtab = st; + + current_objfile = NULL; +} + +/* Ancillary parsing procedures. */ + +/* Lookup the type at relative index RN. Return it in TPP + if found and in any event come up with its name PNAME. + BIGEND says whether aux symbols are big-endian or not (from fh->fBigendian). + Return value says how many aux symbols we ate. */ + +static int +cross_ref (fd, ax, tpp, type_code, pname, bigend, sym_name) + int fd; + union aux_ext *ax; + struct type **tpp; + enum type_code type_code; /* Use to alloc new type if none is found. */ + char **pname; + int bigend; + char *sym_name; +{ + RNDXR rn[1]; + unsigned int rf; + int result = 1; + FDR *fh; + char *esh; + SYMR sh; + int xref_fd; + struct mips_pending *pend; + + *tpp = (struct type *)NULL; + + ecoff_swap_rndx_in (bigend, &ax->a_rndx, rn); + + /* Escape index means 'the next one' */ + if (rn->rfd == 0xfff) + { + result++; + rf = AUX_GET_ISYM (bigend, ax + 1); + } + else + { + rf = rn->rfd; + } + + /* mips cc uses a rf of -1 for opaque struct definitions. + Set TYPE_FLAG_STUB for these types so that check_stub_type will + resolve them if the struct gets defined in another compilation unit. */ + if (rf == -1) + { + *pname = ""; + *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + TYPE_FLAGS (*tpp) |= TYPE_FLAG_STUB; + return result; + } + + /* mips cc uses an escaped rn->index of 0 for struct return types + of procedures that were compiled without -g. These will always remain + undefined. */ + if (rn->rfd == 0xfff && rn->index == 0) + { + *pname = ""; + return result; + } + + /* Find the relative file descriptor and the symbol in it. */ + fh = get_rfd (fd, rf); + xref_fd = fh - ecoff_data (cur_bfd)->fdr; + + if (rn->index >= fh->csym) + { + /* File indirect entry is corrupt. */ + *pname = ""; + complain (&bad_rfd_entry_complaint, + sym_name, xref_fd, rn->index); + return result; + } + + /* If we have processed this symbol then we left a forwarding + pointer to the type in the pending list. If not, we`ll put + it in a list of pending types, to be processed later when + the file will be. In any event, we collect the name for the + type here. */ + + esh = ((char *) ecoff_data (cur_bfd)->external_sym + + ((fh->isymBase + rn->index) + * ecoff_backend (cur_bfd)->external_sym_size)); + (*ecoff_backend (cur_bfd)->swap_sym_in) (cur_bfd, esh, &sh); + + /* Make sure that this type of cross reference can be handled. */ + if (sh.sc != scInfo + || (sh.st != stBlock && sh.st != stTypedef + && sh.st != stStruct && sh.st != stUnion + && sh.st != stEnum)) + { + /* File indirect entry is corrupt. */ + *pname = ""; + complain (&bad_rfd_entry_complaint, + sym_name, xref_fd, rn->index); + return result; + } + + *pname = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss; + + pend = is_pending_symbol (fh, esh); + if (pend) + *tpp = pend->t; + else + { + /* We have not yet seen this type. */ + + if (sh.iss == 0 && sh.st == stTypedef) + { + TIR tir; + + /* alpha cc puts out a stTypedef with a sh.iss of zero for + two cases: + a) forward declarations of structs/unions/enums which are not + defined in this compilation unit. + For these the type will be void. This is a bad design decision + as cross referencing across compilation units is impossible + due to the missing name. + b) forward declarations of structs/unions/enums which are defined + later in this file or in another file in the same compilation + unit. Simply cross reference those again to get the + true type. + The forward references are not entered in the pending list and + in the symbol table. */ + + ecoff_swap_tir_in (bigend, + &(ecoff_data (cur_bfd)->external_aux + + fh->iauxBase + sh.index)->a_ti, + &tir); + if (tir.tq0 != tqNil) + complain (&illegal_forward_tq0_complaint, sym_name); + switch (tir.bt) + { + case btVoid: + *tpp = init_type (type_code, 0, 0, (char *) NULL, + current_objfile); + *pname = ""; + break; + + case btStruct: + case btUnion: + case btEnum: + cross_ref (xref_fd, + (ecoff_data (cur_bfd)->external_aux + + fh->iauxBase + sh.index + 1), + tpp, type_code, pname, + fh->fBigendian, sym_name); + break; + + default: + complain (&illegal_forward_bt_complaint, tir.bt, sym_name); + *tpp = init_type (type_code, 0, 0, (char *) NULL, + current_objfile); + break; + } + return result; + } + else if (sh.st == stTypedef) + { + /* Parse the type for a normal typedef. This might recursively call + cross_ref till we get a non typedef'ed type. + FIXME: This is not correct behaviour, but gdb currently + cannot handle typedefs without type copying. But type copying is + impossible as we might have mutual forward references between + two files and the copied type would not get filled in when + we later parse its definition. */ + *tpp = parse_type (xref_fd, + ecoff_data (cur_bfd)->external_aux + fh->iauxBase, + sh.index, + (int *)NULL, + fh->fBigendian, + (ecoff_data (cur_bfd)->ss + + fh->issBase + sh.iss)); + } + else + { + /* Cross reference to a struct/union/enum which is defined + in another file in the same compilation unit but that file + has not been parsed yet. + Initialize the type only, it will be filled in when + it's definition is parsed. */ + *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + } + add_pending (fh, esh, *tpp); + } + + /* We used one auxent normally, two if we got a "next one" rf. */ + return result; +} + + +/* Quick&dirty lookup procedure, to avoid the MI ones that require + keeping the symtab sorted */ + +static struct symbol * +mylookup_symbol (name, block, namespace, class) + char *name; + register struct block *block; + enum namespace namespace; + enum address_class class; +{ + register int bot, top, inc; + register struct symbol *sym; + + bot = 0; + top = BLOCK_NSYMS (block); + inc = name[0]; + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + if (SYMBOL_NAME (sym)[0] == inc + && SYMBOL_NAMESPACE (sym) == namespace + && SYMBOL_CLASS (sym) == class + && strcmp (SYMBOL_NAME (sym), name) == 0) + return sym; + bot++; + } + block = BLOCK_SUPERBLOCK (block); + if (block) + return mylookup_symbol (name, block, namespace, class); + return 0; +} + + +/* Add a new symbol S to a block B. + Infrequently, we will need to reallocate the block to make it bigger. + We only detect this case when adding to top_stack->cur_block, since + that's the only time we know how big the block is. FIXME. */ + +static void +add_symbol (s, b) + struct symbol *s; + struct block *b; +{ + int nsyms = BLOCK_NSYMS (b)++; + struct block *origb; + struct parse_stack *stackp; + + if (b == top_stack->cur_block && + nsyms >= top_stack->maxsyms) + { + complain (&block_overflow_complaint, SYMBOL_NAME (s)); + /* In this case shrink_block is actually grow_block, since + BLOCK_NSYMS(b) is larger than its current size. */ + origb = b; + b = shrink_block (top_stack->cur_block, top_stack->cur_st); + + /* Now run through the stack replacing pointers to the + original block. shrink_block has already done this + for the blockvector and BLOCK_FUNCTION. */ + for (stackp = top_stack; stackp; stackp = stackp->next) + { + if (stackp->cur_block == origb) + { + stackp->cur_block = b; + stackp->maxsyms = BLOCK_NSYMS (b); + } + } + } + BLOCK_SYM (b, nsyms) = s; +} + +/* Add a new block B to a symtab S */ + +static void +add_block (b, s) + struct block *b; + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR (s); + + bv = (struct blockvector *) xrealloc ((PTR) bv, + (sizeof (struct blockvector) + + BLOCKVECTOR_NBLOCKS (bv) + * sizeof (bv->block))); + if (bv != BLOCKVECTOR (s)) + BLOCKVECTOR (s) = bv; + + BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)++) = b; +} + +/* Add a new linenumber entry (LINENO,ADR) to a linevector LT. + MIPS' linenumber encoding might need more than one byte + to describe it, LAST is used to detect these continuation lines. + + Combining lines with the same line number seems like a bad idea. + E.g: There could be a line number entry with the same line number after the + prologue and GDB should not ignore it (this is a better way to find + a prologue than mips_skip_prologue). + But due to the compressed line table format there are line number entries + for the same line which are needed to bridge the gap to the next + line number entry. These entries have a bogus address info with them + and we are unable to tell them from intended duplicate line number + entries. + This is another reason why -ggdb debugging format is preferable. */ + +static int +add_line (lt, lineno, adr, last) + struct linetable *lt; + int lineno; + CORE_ADDR adr; + int last; +{ + if (last == 0) + last = -2; /* make sure we record first line */ + + if (last == lineno) /* skip continuation lines */ + return lineno; + + lt->item[lt->nitems].line = lineno; + lt->item[lt->nitems++].pc = adr << 2; + return lineno; +} + +/* Sorting and reordering procedures */ + +/* Blocks with a smaller low bound should come first */ + +static int +compare_blocks (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + register int addr_diff; + struct block **b1 = (struct block **) arg1; + struct block **b2 = (struct block **) arg2; + + addr_diff = (BLOCK_START ((*b1))) - (BLOCK_START ((*b2))); + if (addr_diff == 0) + return (BLOCK_END ((*b2))) - (BLOCK_END ((*b1))); + return addr_diff; +} + +/* Sort the blocks of a symtab S. + Reorder the blocks in the blockvector by code-address, + as required by some MI search routines */ + +static void +sort_blocks (s) + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR (s); + + if (BLOCKVECTOR_NBLOCKS (bv) <= 2) + { + /* Cosmetic */ + if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) == 0) + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = 0; + if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) == 0) + BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = 0; + return; + } + /* + * This is very unfortunate: normally all functions are compiled in + * the order they are found, but if the file is compiled -O3 things + * are very different. It would be nice to find a reliable test + * to detect -O3 images in advance. + */ + if (BLOCKVECTOR_NBLOCKS (bv) > 3) + qsort (&BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK), + BLOCKVECTOR_NBLOCKS (bv) - FIRST_LOCAL_BLOCK, + sizeof (struct block *), + compare_blocks); + + { + register CORE_ADDR high = 0; + register int i, j = BLOCKVECTOR_NBLOCKS (bv); + + for (i = FIRST_LOCAL_BLOCK; i < j; i++) + if (high < BLOCK_END (BLOCKVECTOR_BLOCK (bv, i))) + high = BLOCK_END (BLOCKVECTOR_BLOCK (bv, i)); + BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = high; + } + + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = + BLOCK_START (BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK)); + + BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = + BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); +} + + +/* Constructor/restructor/destructor procedures */ + +/* Allocate a new symtab for NAME. Needs an estimate of how many symbols + MAXSYMS and linenumbers MAXLINES we'll put in it */ + +static struct symtab * +new_symtab (name, maxsyms, maxlines, objfile) + char *name; + int maxsyms; + int maxlines; + struct objfile *objfile; +{ + struct symtab *s = allocate_symtab (name, objfile); + + LINETABLE (s) = new_linetable (maxlines); + + /* All symtabs must have at least two blocks */ + BLOCKVECTOR (s) = new_bvect (2); + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK) = new_block (maxsyms); + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) = new_block (maxsyms); + BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)) = + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + + s->free_code = free_linetable; + + return (s); +} + +/* Allocate a new partial_symtab NAME */ + +static struct partial_symtab * +new_psymtab (name, objfile) + char *name; + struct objfile *objfile; +{ + struct partial_symtab *psymtab; + + psymtab = allocate_psymtab (name, objfile); + + /* Keep a backpointer to the file's symbols */ + + psymtab->read_symtab_private = ((char *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc))); + memset ((PTR) psymtab->read_symtab_private, 0, sizeof (struct symloc)); + CUR_BFD (psymtab) = cur_bfd; + + /* The way to turn this into a symtab is to call... */ + psymtab->read_symtab = mipscoff_psymtab_to_symtab; + return (psymtab); +} + + +/* Allocate a linetable array of the given SIZE. Since the struct + already includes one item, we subtract one when calculating the + proper size to allocate. */ + +static struct linetable * +new_linetable (size) + int size; +{ + struct linetable *l; + + size = (size - 1) * sizeof (l->item) + sizeof (struct linetable); + l = (struct linetable *) xmalloc (size); + l->nitems = 0; + return l; +} + +/* Oops, too big. Shrink it. This was important with the 2.4 linetables, + I am not so sure about the 3.4 ones. + + Since the struct linetable already includes one item, we subtract one when + calculating the proper size to allocate. */ + +static struct linetable * +shrink_linetable (lt) + struct linetable *lt; +{ + + return (struct linetable *) xrealloc ((PTR) lt, + (sizeof (struct linetable) + + ((lt->nitems - 1) + * sizeof (lt->item)))); +} + +/* Allocate and zero a new blockvector of NBLOCKS blocks. */ + +static struct blockvector * +new_bvect (nblocks) + int nblocks; +{ + struct blockvector *bv; + int size; + + size = sizeof (struct blockvector) + nblocks * sizeof (struct block *); + bv = (struct blockvector *) xzalloc (size); + + BLOCKVECTOR_NBLOCKS (bv) = nblocks; + + return bv; +} + +/* Allocate and zero a new block of MAXSYMS symbols */ + +static struct block * +new_block (maxsyms) + int maxsyms; +{ + int size = sizeof (struct block) + (maxsyms - 1) * sizeof (struct symbol *); + + return (struct block *) xzalloc (size); +} + +/* Ooops, too big. Shrink block B in symtab S to its minimal size. + Shrink_block can also be used by add_symbol to grow a block. */ + +static struct block * +shrink_block (b, s) + struct block *b; + struct symtab *s; +{ + struct block *new; + struct blockvector *bv = BLOCKVECTOR (s); + int i; + + /* Just reallocate it and fix references to the old one */ + + new = (struct block *) xrealloc ((PTR) b, + (sizeof (struct block) + + ((BLOCK_NSYMS (b) - 1) + * sizeof (struct symbol *)))); + + /* Should chase pointers to old one. Fortunately, that`s just + the block`s function and inferior blocks */ + if (BLOCK_FUNCTION (new) && SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) == b) + SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) = new; + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) + if (BLOCKVECTOR_BLOCK (bv, i) == b) + BLOCKVECTOR_BLOCK (bv, i) = new; + else if (BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) == b) + BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) = new; + return new; +} + +/* Create a new symbol with printname NAME */ + +static struct symbol * +new_symbol (name) + char *name; +{ + struct symbol *s = ((struct symbol *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct symbol))); + + memset ((PTR) s, 0, sizeof (*s)); + SYMBOL_NAME (s) = name; + SYMBOL_LANGUAGE (s) = psymtab_language; + SYMBOL_INIT_DEMANGLED_NAME (s, ¤t_objfile->symbol_obstack); + return s; +} + +/* Create a new type with printname NAME */ + +static struct type * +new_type (name) + char *name; +{ + struct type *t; + + t = alloc_type (current_objfile); + TYPE_NAME (t) = name; + TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default; + return t; +} + + +/* Things used for calling functions in the inferior. + These functions are exported to our companion + mips-tdep.c file and are here because they play + with the symbol-table explicitly. */ + +/* Sigtramp: make sure we have all the necessary information + about the signal trampoline code. Since the official code + from MIPS does not do so, we make up that information ourselves. + If they fix the library (unlikely) this code will neutralize itself. */ + +static void +fixup_sigtramp () +{ + struct symbol *s; + struct symtab *st; + struct block *b, *b0 = NULL; + + sigtramp_address = -1; + + /* We have to handle the following cases here: + a) The Mips library has a sigtramp label within sigvec. + b) Irix has a _sigtramp which we want to use, but it also has sigvec. */ + s = lookup_symbol ("sigvec", 0, VAR_NAMESPACE, 0, NULL); + if (s != 0) + { + b0 = SYMBOL_BLOCK_VALUE (s); + s = lookup_symbol ("sigtramp", b0, VAR_NAMESPACE, 0, NULL); + } + if (s == 0) + { + /* No sigvec or no sigtramp inside sigvec, try _sigtramp. */ + s = lookup_symbol ("_sigtramp", 0, VAR_NAMESPACE, 0, NULL); + } + + /* But maybe this program uses its own version of sigvec */ + if (s == 0) + return; + + /* Did we or MIPSco fix the library ? */ + if (SYMBOL_CLASS (s) == LOC_BLOCK) + { + sigtramp_address = BLOCK_START (SYMBOL_BLOCK_VALUE (s)); + sigtramp_end = BLOCK_END (SYMBOL_BLOCK_VALUE (s)); + return; + } + + sigtramp_address = SYMBOL_VALUE (s); + sigtramp_end = sigtramp_address + 0x88; /* black magic */ + + /* But what symtab does it live in ? */ + st = find_pc_symtab (SYMBOL_VALUE (s)); + + /* + * Ok, there goes the fix: turn it into a procedure, with all the + * needed info. Note we make it a nested procedure of sigvec, + * which is the way the (assembly) code is actually written. + */ + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + SYMBOL_TYPE (s) = init_type (TYPE_CODE_FUNC, 4, 0, (char *) NULL, + st->objfile); + TYPE_TARGET_TYPE (SYMBOL_TYPE (s)) = builtin_type_void; + + /* Need a block to allocate MIPS_EFI_SYMBOL_NAME in */ + b = new_block (1); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_START (b) = sigtramp_address; + BLOCK_END (b) = sigtramp_end; + BLOCK_FUNCTION (b) = s; + BLOCK_SUPERBLOCK (b) = BLOCK_SUPERBLOCK (b0); + add_block (b, st); + sort_blocks (st); + + /* Make a MIPS_EFI_SYMBOL_NAME entry for it */ + { + struct mips_extra_func_info *e = + ((struct mips_extra_func_info *) + xzalloc (sizeof (struct mips_extra_func_info))); + + e->numargs = 0; /* the kernel thinks otherwise */ + /* align_longword(sigcontext + SIGFRAME) */ + e->pdr.frameoffset = 0x150; + e->pdr.framereg = SP_REGNUM; + /* read_next_frame_reg provides the true pc at the time of signal */ + e->pdr.pcreg = PC_REGNUM; + e->pdr.regmask = -2; + e->pdr.regoffset = -(41 * sizeof (int)); + e->pdr.fregmask = -1; + e->pdr.fregoffset = -(7 * sizeof (int)); + e->pdr.isym = (long) s; + e->pdr.adr = sigtramp_address; + + current_objfile = st->objfile; /* Keep new_symbol happy */ + s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_VALUE (s) = (long) e; + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = builtin_type_void; + current_objfile = NULL; + } + + BLOCK_SYM (b, BLOCK_NSYMS (b)++) = s; +} + + +/* Fake up identical offsets for all sections. */ + +struct section_offsets * +mipscoff_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + section_offsets = ((struct section_offsets *) + obstack_alloc (&objfile->psymbol_obstack, + (sizeof (struct section_offsets) + + (sizeof (section_offsets->offsets) + * (SECT_OFF_MAX - 1))))); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* Initialization */ + +static struct sym_fns ecoff_sym_fns = +{ + "ecoff", /* sym_name: name or name prefix of BFD target type */ + 5, /* sym_namelen: number of significant sym_name chars */ + mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */ + mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */ + mipscoff_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */ + NULL /* next: pointer to next struct sym_fns */ +}; + + +void +_initialize_mipsread () +{ + add_symtab_fns (&ecoff_sym_fns); + + /* Missing basic types */ + + builtin_type_string = + init_type (TYPE_CODE_STRING, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "string", + (struct objfile *) NULL); + builtin_type_complex = + init_type (TYPE_CODE_FLT, + TARGET_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "complex", + (struct objfile *) NULL); + builtin_type_double_complex = + init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "double complex", + (struct objfile *) NULL); + builtin_type_fixed_dec = + init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "fixed decimal", + (struct objfile *) NULL); + builtin_type_float_dec = + init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "floating decimal", + (struct objfile *) NULL); +} diff --git a/gnu/usr.bin/gdb/gdb/nlmread.c b/gnu/usr.bin/gdb/gdb/nlmread.c new file mode 100644 index 00000000000..fde3af24932 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/nlmread.c @@ -0,0 +1,300 @@ +/* Read NLM (NetWare Loadable Module) format executable files for GDB. + Copyright 1993 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com). + +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. */ + +#include "defs.h" +#include "bfd.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb-stabs.h" + +static void +nlm_new_init PARAMS ((struct objfile *)); + +static void +nlm_symfile_init PARAMS ((struct objfile *)); + +static void +nlm_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +nlm_symfile_finish PARAMS ((struct objfile *)); + +static void +nlm_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *)); + +static struct section_offsets * +nlm_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type, + struct objfile *)); + + +/* Initialize anything that needs initializing when a completely new symbol + file is specified (not just adding some symbols from another file, e.g. a + shared library). + + We reinitialize buildsym, since gdb will be able to read stabs from an NLM + file at some point in the near future. */ + +static void +nlm_new_init (ignore) + struct objfile *ignore; +{ + stabsread_new_init (); + buildsym_new_init (); +} + + +/* NLM specific initialization routine for reading symbols. + + It is passed a pointer to a struct sym_fns which contains, among other + things, the BFD for the file whose symbols are being read, and a slot for + a pointer to "private data" which we can fill with goodies. + + For now at least, we have nothing in particular to do, so this function is + just a stub. */ + +static void +nlm_symfile_init (ignore) + struct objfile *ignore; +{ +} + +static void +record_minimal_symbol (name, address, ms_type, objfile) + char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + struct objfile *objfile; +{ + name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); + prim_record_minimal_symbol (name, address, ms_type); +} + + +/* + +LOCAL FUNCTION + + nlm_symtab_read -- read the symbol table of an NLM file + +SYNOPSIS + + void nlm_symtab_read (bfd *abfd, CORE_ADDR addr, + struct objfile *objfile) + +DESCRIPTION + + Given an open bfd, a base address to relocate symbols to, and a + flag that specifies whether or not this bfd is for an executable + or not (may be shared library for example), add all the global + function and data symbols to the minimal symbol table. +*/ + +static void +nlm_symtab_read (abfd, addr, objfile) + bfd *abfd; + CORE_ADDR addr; + struct objfile *objfile; +{ + unsigned int storage_needed; + asymbol *sym; + asymbol **symbol_table; + unsigned int number_of_symbols; + unsigned int i; + struct cleanup *back_to; + CORE_ADDR symaddr; + enum minimal_symbol_type ms_type; + + storage_needed = get_symtab_upper_bound (abfd); + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + + for (i = 0; i < number_of_symbols; i++) + { + sym = symbol_table[i]; + if (sym -> flags & BSF_GLOBAL) + { + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate all non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + { + symaddr += addr; + } + + /* For non-absolute symbols, use the type of the section + they are relative to, to intuit text/data. Bfd provides + no way of figuring this out for absolute symbols. */ + if (sym -> section -> flags & SEC_CODE) + { + ms_type = mst_text; + } + else if (sym -> section -> flags & SEC_DATA) + { + ms_type = mst_data; + } + else + { + ms_type = mst_unknown; + } + record_minimal_symbol ((char *) sym -> name, symaddr, ms_type, + objfile); + } + } + do_cleanups (back_to); + } +} + + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to nlm_symfile_init, which + currently does nothing. + + SECTION_OFFSETS is a set of offsets to apply to relocate the symbols + in each section. We simplify it down to a single offset for all + symbols. FIXME. + + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + + This function only does the minimum work necessary for letting the + user "name" things symbolically; it does not read the entire symtab. + Instead, it reads the external and static symbols and puts them in partial + symbol tables. When more extensive information is requested of a + file, the corresponding partial symbol table is mutated into a full + fledged symbol table by going back and reading the symbols + for real. + + Note that NLM files have two sets of information that is potentially + useful for building gdb's minimal symbol table. The first is a list + of the publically exported symbols, and is currently used to build + bfd's canonical symbol table. The second is an optional native debugging + format which contains additional symbols (and possibly duplicates of + the publically exported symbols). The optional native debugging format + is not currently used. */ + +static void +nlm_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + bfd *abfd = objfile -> obfd; + struct cleanup *back_to; + CORE_ADDR offset; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + /* FIXME, should take a section_offsets param, not just an offset. */ + + offset = ANOFFSET (section_offsets, 0); + + /* Process the NLM export records, which become the bfd's canonical symbol + table. */ + + nlm_symtab_read (abfd, offset, objfile); + + /* FIXME: We could locate and read the optional native debugging format + here and add the symbols to the minimal symbol table. */ + + if (!have_partial_symbols ()) + { + wrap_here (""); + printf_filtered ("(no debugging symbols found)..."); + wrap_here (""); + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + + +/* Perform any local cleanups required when we are done with a particular + objfile. I.E, we are in the process of discarding all symbol information + for an objfile, freeing up all memory held for it, and unlinking the + objfile struct from the global list of known objfiles. */ + +static void +nlm_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_private != NULL) + { + mfree (objfile -> md, objfile -> sym_private); + } +} + +/* NLM specific parsing routine for section offsets. + FIXME: This may or may not be necessary. All the symbol readers seem + to have similar code. See if it can be generalized and moved elsewhere. */ + +static +struct section_offsets * +nlm_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + { + ANOFFSET (section_offsets, i) = addr; + } + + return (section_offsets); +} + + +/* Register that we are able to handle NLM file format. */ + +static struct sym_fns nlm_sym_fns = +{ + "nlm", /* sym_name: name or name prefix of BFD target type */ + 3, /* sym_namelen: number of significant sym_name chars */ + nlm_new_init, /* sym_new_init: init anything gbl to entire symtab */ + nlm_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + nlm_symfile_read, /* sym_read: read a symbol file into symtab */ + nlm_symfile_finish, /* sym_finish: finished with file, cleanup */ + nlm_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_nlmread () +{ + add_symtab_fns (&nlm_sym_fns); +} diff --git a/gnu/usr.bin/gdb/gdb/nm.h b/gnu/usr.bin/gdb/gdb/nm.h new file mode 100644 index 00000000000..a7af00f33d8 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/nm.h @@ -0,0 +1,44 @@ +/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 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. */ + +#ifndef NM_FREEBSD_H +#define NM_FREEBSD_H + +/* Be shared lib aware */ +#include "solib.h" + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#include +#define KERNEL_U_ADDR USRSTACK + +/* #undef FLOAT_INFO /* No float info yet */ +#define FLOAT_INFO extern i386_float_info (); \ + i386_float_info () + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +#define PTRACE_ARG3_TYPE char* + +#endif /* NM_FREEBSD_H */ diff --git a/gnu/usr.bin/gdb/gdb/objfiles.c b/gnu/usr.bin/gdb/gdb/objfiles.c new file mode 100644 index 00000000000..b111f005c05 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/objfiles.c @@ -0,0 +1,773 @@ +/* GDB routines for manipulating objfiles. + Copyright 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +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. */ + +/* This file contains support routines for creating, manipulating, and + destroying objfile structures. */ + +#include "defs.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "target.h" + +#include +#include +#include +#include + +/* Prototypes for local functions */ + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + +static int +open_existing_mapped_file PARAMS ((char *, long, int)); + +static int +open_mapped_file PARAMS ((char *filename, long mtime, int mapped)); + +static CORE_ADDR +map_to_address PARAMS ((void)); + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + +/* Message to be printed before the error message, when an error occurs. */ + +extern char *error_pre_print; + +/* Externally visible variables that are owned by this module. + See declarations in objfile.h for more info. */ + +struct objfile *object_files; /* Linked list of all objfiles */ +struct objfile *current_objfile; /* For symbol file being read in */ +struct objfile *symfile_objfile; /* Main symbol table loaded from */ + +int mapped_symbol_files; /* Try to use mapped symbol files */ + +/* Locate all mappable sections of a BFD file. + objfile_p_char is a char * to get it through + bfd_map_over_sections; we cast it back to its proper type. */ + +static void +add_to_objfile_sections (abfd, asect, objfile_p_char) + bfd *abfd; + sec_ptr asect; + PTR objfile_p_char; +{ + struct objfile *objfile = (struct objfile *) objfile_p_char; + struct obj_section section; + flagword aflag; + + aflag = bfd_get_section_flags (abfd, asect); + /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */ + if (!(aflag & SEC_LOAD)) + return; + if (0 == bfd_section_size (abfd, asect)) + return; + section.offset = 0; + section.objfile = objfile; + section.sec_ptr = asect; + section.addr = bfd_section_vma (abfd, asect); + section.endaddr = section.addr + bfd_section_size (abfd, asect); + obstack_grow (&objfile->psymbol_obstack, §ion, sizeof(section)); + objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1); +} + +/* Builds a section table for OBJFILE. + Returns 0 if OK, 1 on error. */ + +static int +build_objfile_section_table (objfile) + struct objfile *objfile; +{ + if (objfile->sections) + abort(); + + objfile->sections_end = 0; + bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *)objfile); + objfile->sections = (struct obj_section *) + obstack_finish (&objfile->psymbol_obstack); + objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end; + return(0); +} + +/* Given a pointer to an initialized bfd (ABFD) and a flag that indicates + whether or not an objfile is to be mapped (MAPPED), allocate a new objfile + struct, fill it in as best we can, link it into the list of all known + objfiles, and return a pointer to the new objfile struct. */ + +struct objfile * +allocate_objfile (abfd, mapped) + bfd *abfd; + int mapped; +{ + struct objfile *objfile = NULL; + int fd; + PTR md; + CORE_ADDR mapto; + + mapped |= mapped_symbol_files; + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + + /* If we can support mapped symbol files, try to open/reopen the mapped file + that corresponds to the file from which we wish to read symbols. If the + objfile is to be mapped, we must malloc the structure itself using the + mmap version, and arrange that all memory allocation for the objfile uses + the mmap routines. If we are reusing an existing mapped file, from which + we get our objfile pointer, we have to make sure that we update the + pointers to the alloc/free functions in the obstack, in case these + functions have moved within the current gdb. */ + + fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd), + mapped); + if (fd >= 0) + { + if (((mapto = map_to_address ()) == 0) || + ((md = mmalloc_attach (fd, (PTR) mapto)) == NULL)) + { + close (fd); + } + else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL) + { + /* Update memory corruption handler function addresses. */ + init_malloc (md); + objfile -> md = md; + objfile -> mmfd = fd; + /* Update pointers to functions to *our* copies */ + obstack_chunkfun (&objfile -> psymbol_obstack, xmmalloc); + obstack_freefun (&objfile -> psymbol_obstack, mfree); + obstack_chunkfun (&objfile -> symbol_obstack, xmmalloc); + obstack_freefun (&objfile -> symbol_obstack, mfree); + obstack_chunkfun (&objfile -> type_obstack, xmmalloc); + obstack_freefun (&objfile -> type_obstack, mfree); + /* If already in objfile list, unlink it. */ + unlink_objfile (objfile); + /* Forget things specific to a particular gdb, may have changed. */ + objfile -> sf = NULL; + } + else + { + /* Set up to detect internal memory corruption. MUST be done before + the first malloc. See comments in init_malloc() and mmcheck(). */ + init_malloc (md); + objfile = (struct objfile *) xmmalloc (md, sizeof (struct objfile)); + memset (objfile, 0, sizeof (struct objfile)); + objfile -> md = md; + objfile -> mmfd = fd; + objfile -> flags |= OBJF_MAPPED; + mmalloc_setkey (objfile -> md, 0, objfile); + obstack_specify_allocation_with_arg (&objfile -> psymbol_obstack, + 0, 0, xmmalloc, mfree, + objfile -> md); + obstack_specify_allocation_with_arg (&objfile -> symbol_obstack, + 0, 0, xmmalloc, mfree, + objfile -> md); + obstack_specify_allocation_with_arg (&objfile -> type_obstack, + 0, 0, xmmalloc, mfree, + objfile -> md); + } + } + + if (mapped && (objfile == NULL)) + { + warning ("symbol table for '%s' will not be mapped", + bfd_get_filename (abfd)); + } + +#else /* defined(NO_MMALLOC) || !defined(HAVE_MMAP) */ + + if (mapped) + { + warning ("this version of gdb does not support mapped symbol tables."); + + /* Turn off the global flag so we don't try to do mapped symbol tables + any more, which shuts up gdb unless the user specifically gives the + "mapped" keyword again. */ + + mapped_symbol_files = 0; + } + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + + /* If we don't support mapped symbol files, didn't ask for the file to be + mapped, or failed to open the mapped file for some reason, then revert + back to an unmapped objfile. */ + + if (objfile == NULL) + { + objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); + memset (objfile, 0, sizeof (struct objfile)); + objfile -> md = NULL; + obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc, + free); + obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc, + free); + obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc, + free); + } + + /* Update the per-objfile information that comes from the bfd, ensuring + that any data that is reference is saved in the per-objfile data + region. */ + + objfile -> obfd = abfd; + if (objfile -> name != NULL) + { + mfree (objfile -> md, objfile -> name); + } + objfile -> name = mstrsave (objfile -> md, bfd_get_filename (abfd)); + objfile -> mtime = bfd_get_mtime (abfd); + + /* Build section table. */ + + if (build_objfile_section_table (objfile)) + { + error ("Can't find the file sections in `%s': %s", + objfile -> name, bfd_errmsg (bfd_error)); + } + + /* Push this file onto the head of the linked list of other such files. */ + + objfile -> next = object_files; + object_files = objfile; + + return (objfile); +} + +/* Unlink OBJFILE from the list of known objfiles, if it is found in the + list. + + It is not a bug, or error, to call this function if OBJFILE is not known + to be in the current list. This is done in the case of mapped objfiles, + for example, just to ensure that the mapped objfile doesn't appear twice + in the list. Since the list is threaded, linking in a mapped objfile + twice would create a circular list. + + If OBJFILE turns out to be in the list, we zap it's NEXT pointer after + unlinking it, just to ensure that we have completely severed any linkages + between the OBJFILE and the list. */ + +void +unlink_objfile (objfile) + struct objfile *objfile; +{ + struct objfile** objpp; + + for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp) -> next)) + { + if (*objpp == objfile) + { + *objpp = (*objpp) -> next; + objfile -> next = NULL; + break; + } + } +} + + +/* Destroy an objfile and all the symtabs and psymtabs under it. Note + that as much as possible is allocated on the symbol_obstack and + psymbol_obstack, so that the memory can be efficiently freed. + + Things which we do NOT free because they are not in malloc'd memory + or not in memory specific to the objfile include: + + objfile -> sf + + FIXME: If the objfile is using reusable symbol information (via mmalloc), + then we need to take into account the fact that more than one process + may be using the symbol information at the same time (when mmalloc is + extended to support cooperative locking). When more than one process + is using the mapped symbol info, we need to be more careful about when + we free objects in the reusable area. */ + +void +free_objfile (objfile) + struct objfile *objfile; +{ + int mmfd; + + /* First do any symbol file specific actions required when we are + finished with a particular symbol file. Note that if the objfile + is using reusable symbol information (via mmalloc) then each of + these routines is responsible for doing the correct thing, either + freeing things which are valid only during this particular gdb + execution, or leaving them to be reused during the next one. */ + + if (objfile -> sf != NULL) + { + (*objfile -> sf -> sym_finish) (objfile); + } + + /* We always close the bfd. */ + + if (objfile -> obfd != NULL) + { + char *name = bfd_get_filename (objfile->obfd); + bfd_close (objfile -> obfd); + free (name); + } + + /* Remove it from the chain of all objfiles. */ + + unlink_objfile (objfile); + + /* Before the symbol table code was redone to make it easier to + selectively load and remove information particular to a specific + linkage unit, gdb used to do these things whenever the monolithic + symbol table was blown away. How much still needs to be done + is unknown, but we play it safe for now and keep each action until + it is shown to be no longer needed. */ + +#if defined (CLEAR_SOLIB) + CLEAR_SOLIB (); + /* CLEAR_SOLIB closes the bfd's for any shared libraries. But + the to_sections for a core file might refer to those bfd's. So + detach any core file. */ + { + struct target_ops *t = find_core_target (); + if (t != NULL) + (t->to_detach) (NULL, 0); + } +#endif + clear_pc_function_cache (); + + /* The last thing we do is free the objfile struct itself for the + non-reusable case, or detach from the mapped file for the reusable + case. Note that the mmalloc_detach or the mfree is the last thing + we can do with this objfile. */ + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + + if (objfile -> flags & OBJF_MAPPED) + { + /* Remember the fd so we can close it. We can't close it before + doing the detach, and after the detach the objfile is gone. */ + mmfd = objfile -> mmfd; + mmalloc_detach (objfile -> md); + objfile = NULL; + close (mmfd); + } + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + + /* If we still have an objfile, then either we don't support reusable + objfiles or this one was not reusable. So free it normally. */ + + if (objfile != NULL) + { + if (objfile -> name != NULL) + { + mfree (objfile -> md, objfile -> name); + } + if (objfile->global_psymbols.list) + mfree (objfile->md, objfile->global_psymbols.list); + if (objfile->static_psymbols.list) + mfree (objfile->md, objfile->static_psymbols.list); + /* Free the obstacks for non-reusable objfiles */ + obstack_free (&objfile -> psymbol_obstack, 0); + obstack_free (&objfile -> symbol_obstack, 0); + obstack_free (&objfile -> type_obstack, 0); + mfree (objfile -> md, objfile); + objfile = NULL; + } +} + + +/* Free all the object files at once and clean up their users. */ + +void +free_all_objfiles () +{ + struct objfile *objfile, *temp; + + ALL_OBJFILES_SAFE (objfile, temp) + { + free_objfile (objfile); + } + clear_symtab_users (); +} + +/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS + entries in new_offsets. */ +void +objfile_relocate (objfile, new_offsets) + struct objfile *objfile; + struct section_offsets *new_offsets; +{ + struct section_offsets *delta = (struct section_offsets *) alloca + (sizeof (struct section_offsets) + + objfile->num_sections * sizeof (delta->offsets)); + + { + int i; + int something_changed = 0; + for (i = 0; i < objfile->num_sections; ++i) + { + ANOFFSET (delta, i) = + ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i); + if (ANOFFSET (delta, i) != 0) + something_changed = 1; + } + if (!something_changed) + return; + } + + /* OK, get all the symtabs. */ + { + struct symtab *s; + + for (s = objfile->symtabs; s; s = s->next) + { + struct linetable *l; + struct blockvector *bv; + int i; + + /* First the line table. */ + l = LINETABLE (s); + if (l) + { + for (i = 0; i < l->nitems; ++i) + l->item[i].pc += ANOFFSET (delta, s->block_line_section); + } + + /* Don't relocate a shared blockvector more than once. */ + if (!s->primary) + continue; + + bv = BLOCKVECTOR (s); + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i) + { + struct block *b; + int j; + + b = BLOCKVECTOR_BLOCK (bv, i); + BLOCK_START (b) += ANOFFSET (delta, s->block_line_section); + BLOCK_END (b) += ANOFFSET (delta, s->block_line_section); + + for (j = 0; j < BLOCK_NSYMS (b); ++j) + { + struct symbol *sym = BLOCK_SYM (b, j); + /* The RS6000 code from which this was taken skipped + any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE. + But I'm leaving out that test, on the theory that + they can't possibly pass the tests below. */ + if ((SYMBOL_CLASS (sym) == LOC_LABEL + || SYMBOL_CLASS (sym) == LOC_STATIC) + && SYMBOL_SECTION (sym) >= 0) + { + SYMBOL_VALUE_ADDRESS (sym) += + ANOFFSET (delta, SYMBOL_SECTION (sym)); + } + } + } + } + } + + { + struct partial_symtab *p; + + ALL_OBJFILE_PSYMTABS (objfile, p) + { + /* FIXME: specific to symbol readers which use gdb-stabs.h. + We can only get away with it since objfile_relocate is only + used on XCOFF, which lacks psymtabs, and for gdb-stabs.h + targets. */ + p->textlow += ANOFFSET (delta, SECT_OFF_TEXT); + p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT); + } + } + + { + struct partial_symbol *psym; + + for (psym = objfile->global_psymbols.list; + psym < objfile->global_psymbols.next; + psym++) + if (SYMBOL_SECTION (psym) >= 0) + SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym)); + for (psym = objfile->static_psymbols.list; + psym < objfile->static_psymbols.next; + psym++) + if (SYMBOL_SECTION (psym) >= 0) + SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym)); + } + + { + struct minimal_symbol *msym; + ALL_OBJFILE_MSYMBOLS (objfile, msym) + if (SYMBOL_SECTION (msym) >= 0) + SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym)); + } + + { + int i; + for (i = 0; i < objfile->num_sections; ++i) + ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i); + } +} + +/* Many places in gdb want to test just to see if we have any partial + symbols available. This function returns zero if none are currently + available, nonzero otherwise. */ + +int +have_partial_symbols () +{ + struct objfile *ofp; + + ALL_OBJFILES (ofp) + { + if (ofp -> psymtabs != NULL) + { + return 1; + } + } + return 0; +} + +/* Many places in gdb want to test just to see if we have any full + symbols available. This function returns zero if none are currently + available, nonzero otherwise. */ + +int +have_full_symbols () +{ + struct objfile *ofp; + + ALL_OBJFILES (ofp) + { + if (ofp -> symtabs != NULL) + { + return 1; + } + } + return 0; +} + +/* Many places in gdb want to test just to see if we have any minimal + symbols available. This function returns zero if none are currently + available, nonzero otherwise. */ + +int +have_minimal_symbols () +{ + struct objfile *ofp; + + ALL_OBJFILES (ofp) + { + if (ofp -> msymbols != NULL) + { + return 1; + } + } + return 0; +} + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + +/* Given the name of a mapped symbol file in SYMSFILENAME, and the timestamp + of the corresponding symbol file in MTIME, try to open an existing file + with the name SYMSFILENAME and verify it is more recent than the base + file by checking it's timestamp against MTIME. + + If SYMSFILENAME does not exist (or can't be stat'd), simply returns -1. + + If SYMSFILENAME does exist, but is out of date, we check to see if the + user has specified creation of a mapped file. If so, we don't issue + any warning message because we will be creating a new mapped file anyway, + overwriting the old one. If not, then we issue a warning message so that + the user will know why we aren't using this existing mapped symbol file. + In either case, we return -1. + + If SYMSFILENAME does exist and is not out of date, but can't be opened for + some reason, then prints an appropriate system error message and returns -1. + + Otherwise, returns the open file descriptor. */ + +static int +open_existing_mapped_file (symsfilename, mtime, mapped) + char *symsfilename; + long mtime; + int mapped; +{ + int fd = -1; + struct stat sbuf; + + if (stat (symsfilename, &sbuf) == 0) + { + if (sbuf.st_mtime < mtime) + { + if (!mapped) + { + warning ("mapped symbol file `%s' is out of date, ignored it", + symsfilename); + } + } + else if ((fd = open (symsfilename, O_RDWR)) < 0) + { + if (error_pre_print) + { + printf (error_pre_print); + } + print_sys_errmsg (symsfilename, errno); + } + } + return (fd); +} + +/* Look for a mapped symbol file that corresponds to FILENAME and is more + recent than MTIME. If MAPPED is nonzero, the user has asked that gdb + use a mapped symbol file for this file, so create a new one if one does + not currently exist. + + If found, then return an open file descriptor for the file, otherwise + return -1. + + This routine is responsible for implementing the policy that generates + the name of the mapped symbol file from the name of a file containing + symbols that gdb would like to read. Currently this policy is to append + ".syms" to the name of the file. + + This routine is also responsible for implementing the policy that + determines where the mapped symbol file is found (the search path). + This policy is that when reading an existing mapped file, a file of + the correct name in the current directory takes precedence over a + file of the correct name in the same directory as the symbol file. + When creating a new mapped file, it is always created in the current + directory. This helps to minimize the chances of a user unknowingly + creating big mapped files in places like /bin and /usr/local/bin, and + allows a local copy to override a manually installed global copy (in + /bin for example). */ + +static int +open_mapped_file (filename, mtime, mapped) + char *filename; + long mtime; + int mapped; +{ + int fd; + char *symsfilename; + + /* First try to open an existing file in the current directory, and + then try the directory where the symbol file is located. */ + + symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL); + if ((fd = open_existing_mapped_file (symsfilename, mtime, mapped)) < 0) + { + free (symsfilename); + symsfilename = concat (filename, ".syms", (char *) NULL); + fd = open_existing_mapped_file (symsfilename, mtime, mapped); + } + + /* If we don't have an open file by now, then either the file does not + already exist, or the base file has changed since it was created. In + either case, if the user has specified use of a mapped file, then + create a new mapped file, truncating any existing one. If we can't + create one, print a system error message saying why we can't. + + By default the file is rw for everyone, with the user's umask taking + care of turning off the permissions the user wants off. */ + + if ((fd < 0) && mapped) + { + free (symsfilename); + symsfilename = concat ("./", basename (filename), ".syms", + (char *) NULL); + if ((fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) + { + if (error_pre_print) + { + printf (error_pre_print); + } + print_sys_errmsg (symsfilename, errno); + } + } + + free (symsfilename); + return (fd); +} + +/* Return the base address at which we would like the next objfile's + mapped data to start. + + For now, we use the kludge that the configuration specifies a base + address to which it is safe to map the first mmalloc heap, and an + increment to add to this address for each successive heap. There are + a lot of issues to deal with here to make this work reasonably, including: + + Avoid memory collisions with existing mapped address spaces + + Reclaim address spaces when their mmalloc heaps are unmapped + + When mmalloc heaps are shared between processes they have to be + mapped at the same addresses in each + + Once created, a mmalloc heap that is to be mapped back in must be + mapped at the original address. I.E. each objfile will expect to + be remapped at it's original address. This becomes a problem if + the desired address is already in use. + + etc, etc, etc. + + */ + + +static CORE_ADDR +map_to_address () +{ + +#if defined(MMAP_BASE_ADDRESS) && defined (MMAP_INCREMENT) + + static CORE_ADDR next = MMAP_BASE_ADDRESS; + CORE_ADDR mapto = next; + + next += MMAP_INCREMENT; + return (mapto); + +#else + + return (0); + +#endif + +} + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + +/* Returns a section whose range includes PC or NULL if none found. */ + +struct obj_section * +find_pc_section(pc) + CORE_ADDR pc; +{ + struct obj_section *s; + struct objfile *objfile; + + ALL_OBJFILES (objfile) + for (s = objfile->sections; s < objfile->sections_end; ++s) + if (s->addr <= pc + && pc < s->endaddr) + return(s); + + return(NULL); +} diff --git a/gnu/usr.bin/gdb/gdb/objfiles.h b/gnu/usr.bin/gdb/gdb/objfiles.h new file mode 100644 index 00000000000..50226ff47e7 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/objfiles.h @@ -0,0 +1,437 @@ +/* Definitions for symbol file management in GDB. + Copyright (C) 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. */ + +#if !defined (OBJFILES_H) +#define OBJFILES_H + +/* This structure maintains information on a per-objfile basis about the + "entry point" of the objfile, and the scope within which the entry point + exists. It is possible that gdb will see more than one objfile that is + executable, each with it's own entry point. + + For example, for dynamically linked executables in SVR4, the dynamic linker + code is contained within the shared C library, which is actually executable + and is run by the kernel first when an exec is done of a user executable + that is dynamically linked. The dynamic linker within the shared C library + then maps in the various program segments in the user executable and jumps + to the user executable's recorded entry point, as if the call had been made + directly by the kernel. + + The traditional gdb method of using this info is to use the recorded entry + point to set the variables entry_file_lowpc and entry_file_highpc from + the debugging information, where these values are the starting address + (inclusive) and ending address (exclusive) of the instruction space in the + executable which correspond to the "startup file", I.E. crt0.o in most + cases. This file is assumed to be a startup file and frames with pc's + inside it are treated as nonexistent. Setting these variables is necessary + so that backtraces do not fly off the bottom of the stack (or top, depending + upon your stack orientation). + + Gdb also supports an alternate method to avoid running off the top/bottom + of the stack. + + There are two frames that are "special", the frame for the function + containing the process entry point, since it has no predecessor frame, + and the frame for the function containing the user code entry point + (the main() function), since all the predecessor frames are for the + process startup code. Since we have no guarantee that the linked + in startup modules have any debugging information that gdb can use, + we need to avoid following frame pointers back into frames that might + have been built in the startup code, as we might get hopelessly + confused. However, we almost always have debugging information + available for main(). + + These variables are used to save the range of PC values which are valid + within the main() function and within the function containing the process + entry point. If we always consider the frame for main() as the outermost + frame when debugging user code, and the frame for the process entry + point function as the outermost frame when debugging startup code, then + all we have to do is have FRAME_CHAIN_VALID return false whenever a + frame's current PC is within the range specified by these variables. + In essence, we set "ceilings" in the frame chain beyond which we will + not proceed when following the frame chain back up the stack. + + A nice side effect is that we can still debug startup code without + running off the end of the frame chain, assuming that we have usable + debugging information in the startup modules, and if we choose to not + use the block at main, or can't find it for some reason, everything + still works as before. And if we have no startup code debugging + information but we do have usable information for main(), backtraces + from user code don't go wandering off into the startup code. + + To use this method, define your FRAME_CHAIN_VALID macro like: + + #define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 \ + && !(inside_main_func ((thisframe)->pc)) \ + && !(inside_entry_func ((thisframe)->pc))) + + and add initializations of the four scope controlling variables inside + the object file / debugging information processing modules. */ + +struct entry_info +{ + + /* The value we should use for this objects entry point. + The illegal/unknown value needs to be something other than 0, ~0 + for instance, which is much less likely than 0. */ + + CORE_ADDR entry_point; + + /* Start (inclusive) and end (exclusive) of function containing the + entry point. */ + + CORE_ADDR entry_func_lowpc; + CORE_ADDR entry_func_highpc; + + /* Start (inclusive) and end (exclusive) of object file containing the + entry point. */ + + CORE_ADDR entry_file_lowpc; + CORE_ADDR entry_file_highpc; + + /* Start (inclusive) and end (exclusive) of the user code main() function. */ + + CORE_ADDR main_func_lowpc; + CORE_ADDR main_func_highpc; + +}; + + +/* Sections in an objfile. + + It is strange that we have both this notion of "sections" + and the one used by section_offsets. Section as used + here, (currently at least) means a BFD section, and the sections + are set up from the BFD sections in allocate_objfile. + + The sections in section_offsets have their meaning determined by + the symbol format, and they are set up by the sym_offsets function + for that symbol file format. + + I'm not sure this could or should be changed, however. */ + +struct obj_section { + CORE_ADDR addr; /* lowest address in section */ + CORE_ADDR endaddr; /* 1+highest address in section */ + + /* This field is being used for nefarious purposes by syms_from_objfile. + It is said to be redundant with section_offsets; it's not really being + used that way, however, it's some sort of hack I don't understand + and am not going to try to eliminate (yet, anyway). FIXME. + + It was documented as "offset between (end)addr and actual memory + addresses", but that's not true; addr & endaddr are actual memory + addresses. */ + CORE_ADDR offset; + + sec_ptr sec_ptr; /* BFD section pointer */ + + /* Objfile this section is part of. Not currently used, but I'm sure + that someone will want the bfd that the sec_ptr goes with or something + like that before long. */ + struct objfile *objfile; +}; + +/* Master structure for keeping track of each input file from which + gdb reads symbols. One of these is allocated for each such file we + access, e.g. the exec_file, symbol_file, and any shared library object + files. */ + +struct objfile +{ + + /* All struct objfile's are chained together by their next pointers. + The global variable "object_files" points to the first link in this + chain. + + FIXME: There is a problem here if the objfile is reusable, and if + multiple users are to be supported. The problem is that the objfile + list is linked through a member of the objfile struct itself, which + is only valid for one gdb process. The list implementation needs to + be changed to something like: + + struct list {struct list *next; struct objfile *objfile}; + + where the list structure is completely maintained separately within + each gdb process. */ + + struct objfile *next; + + /* The object file's name. Malloc'd; free it if you free this struct. */ + + char *name; + + /* Some flag bits for this objfile. */ + + unsigned short flags; + + /* Each objfile points to a linked list of symtabs derived from this file, + one symtab structure for each compilation unit (source file). Each link + in the symtab list contains a backpointer to this objfile. */ + + struct symtab *symtabs; + + /* Each objfile points to a linked list of partial symtabs derived from + this file, one partial symtab structure for each compilation unit + (source file). */ + + struct partial_symtab *psymtabs; + + /* List of freed partial symtabs, available for re-use */ + + struct partial_symtab *free_psymtabs; + + /* The object file's BFD. Can be null, in which case bfd_open (name) and + put the result here. */ + + bfd *obfd; + + /* The modification timestamp of the object file, as of the last time + we read its symbols. */ + + long mtime; + + /* Obstacks to hold objects that should be freed when we load a new symbol + table from this object file. */ + + struct obstack psymbol_obstack; /* Partial symbols */ + struct obstack symbol_obstack; /* Full symbols */ + struct obstack type_obstack; /* Types */ + + /* Vectors of all partial symbols read in from file. The actual data + is stored in the psymbol_obstack. */ + + struct psymbol_allocation_list global_psymbols; + struct psymbol_allocation_list static_psymbols; + + /* Each file contains a pointer to an array of minimal symbols for all + global symbols that are defined within the file. The array is terminated + by a "null symbol", one that has a NULL pointer for the name and a zero + value for the address. This makes it easy to walk through the array + when passed a pointer to somewhere in the middle of it. There is also + a count of the number of symbols, which does include the terminating + null symbol. The array itself, as well as all the data that it points + to, should be allocated on the symbol_obstack for this file. */ + + struct minimal_symbol *msymbols; + int minimal_symbol_count; + + /* For object file formats which don't specify fundamental types, gdb + can create such types. For now, it maintains a vector of pointers + to these internally created fundamental types on a per objfile basis, + however it really should ultimately keep them on a per-compilation-unit + basis, to account for linkage-units that consist of a number of + compilation units that may have different fundamental types, such as + linking C modules with ADA modules, or linking C modules that are + compiled with 32-bit ints with C modules that are compiled with 64-bit + ints (not inherently evil with a smarter linker). */ + + struct type **fundamental_types; + + /* The mmalloc() malloc-descriptor for this objfile if we are using + the memory mapped malloc() package to manage storage for this objfile's + data. NULL if we are not. */ + + PTR md; + + /* The file descriptor that was used to obtain the mmalloc descriptor + for this objfile. If we call mmalloc_detach with the malloc descriptor + we should then close this file descriptor. */ + + int mmfd; + + /* Structure which keeps track of functions that manipulate objfile's + of the same type as this objfile. I.E. the function to read partial + symbols for example. Note that this structure is in statically + allocated memory, and is shared by all objfiles that use the + object module reader of this type. */ + + struct sym_fns *sf; + + /* The per-objfile information about the entry point, the scope (file/func) + containing the entry point, and the scope of the user's main() func. */ + + struct entry_info ei; + + /* Information about stabs. Will be filled in with a dbx_symfile_info + struct by those readers that need it. */ + + PTR sym_stab_info; + + /* Hook for information for use by the symbol reader (currently used + for information shared by sym_init and sym_read). It is + typically a pointer to malloc'd memory. The symbol reader's finish + function is responsible for freeing the memory thusly allocated. */ + + PTR sym_private; + + /* Hook for target-architecture-specific information. This must + point to memory allocated on one of the obstacks in this objfile, + so that it gets freed automatically when reading a new object + file. */ + + PTR obj_private; + + /* Set of relocation offsets to apply to each section. + Currently on the psymbol_obstack (which makes no sense, but I'm + not sure it's harming anything). + + These offsets indicate that all symbols (including partial and + minimal symbols) which have been read have been relocated by this + much. Symbols which are yet to be read need to be relocated by + it. */ + + struct section_offsets *section_offsets; + int num_sections; + + /* set of section begin and end addresses used to map pc addresses + into sections. Currently on the psymbol_obstack (which makes no + sense, but I'm not sure it's harming anything). */ + + struct obj_section + *sections, + *sections_end; +}; + +/* Defines for the objfile flag word. */ + +/* Gdb can arrange to allocate storage for all objects related to a + particular objfile in a designated section of it's address space, + managed at a low level by mmap() and using a special version of + malloc that handles malloc/free/realloc on top of the mmap() interface. + This allows the "internal gdb state" for a particular objfile to be + dumped to a gdb state file and subsequently reloaded at a later time. */ + +#define OBJF_MAPPED (1 << 0) /* Objfile data is mmap'd */ + +/* When using mapped/remapped predigested gdb symbol information, we need + a flag that indicates that we have previously done an initial symbol + table read from this particular objfile. We can't just look for the + absence of any of the three symbol tables (msymbols, psymtab, symtab) + because if the file has no symbols for example, none of these will + exist. */ + +#define OBJF_SYMS (1 << 1) /* Have tried to read symbols */ + +/* The object file that the main symbol table was loaded from (e.g. the + argument to the "symbol-file" or "file" command). */ + +extern struct objfile *symfile_objfile; + +/* When we need to allocate a new type, we need to know which type_obstack + to allocate the type on, since there is one for each objfile. The places + where types are allocated are deeply buried in function call hierarchies + which know nothing about objfiles, so rather than trying to pass a + particular objfile down to them, we just do an end run around them and + set current_objfile to be whatever objfile we expect to be using at the + time types are being allocated. For instance, when we start reading + symbols for a particular objfile, we set current_objfile to point to that + objfile, and when we are done, we set it back to NULL, to ensure that we + never put a type someplace other than where we are expecting to put it. + FIXME: Maybe we should review the entire type handling system and + see if there is a better way to avoid this problem. */ + +extern struct objfile *current_objfile; + +/* All known objfiles are kept in a linked list. This points to the + root of this list. */ + +extern struct objfile *object_files; + +/* Declarations for functions defined in objfiles.c */ + +extern struct objfile * +allocate_objfile PARAMS ((bfd *, int)); + +extern void +unlink_objfile PARAMS ((struct objfile *)); + +extern void +free_objfile PARAMS ((struct objfile *)); + +extern void +free_all_objfiles PARAMS ((void)); + +extern void +objfile_relocate PARAMS ((struct objfile *, struct section_offsets *)); + +extern int +have_partial_symbols PARAMS ((void)); + +extern int +have_full_symbols PARAMS ((void)); + +/* Functions for dealing with the minimal symbol table, really a misc + address<->symbol mapping for things we don't have debug symbols for. */ + +extern int +have_minimal_symbols PARAMS ((void)); + +extern struct obj_section * +find_pc_section PARAMS((CORE_ADDR pc)); + +/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete + the objfile during the traversal. */ + +#define ALL_OBJFILES(obj) \ + for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next) + +#define ALL_OBJFILES_SAFE(obj,nxt) \ + for ((obj) = object_files; \ + (obj) != NULL? ((nxt)=(obj)->next,1) :0; \ + (obj) = (nxt)) + + +/* Traverse all symtabs in one objfile. */ + +#define ALL_OBJFILE_SYMTABS(objfile, s) \ + for ((s) = (objfile) -> symtabs; (s) != NULL; (s) = (s) -> next) + +/* Traverse all psymtabs in one objfile. */ + +#define ALL_OBJFILE_PSYMTABS(objfile, p) \ + for ((p) = (objfile) -> psymtabs; (p) != NULL; (p) = (p) -> next) + +/* Traverse all minimal symbols in one objfile. */ + +#define ALL_OBJFILE_MSYMBOLS(objfile, m) \ + for ((m) = (objfile) -> msymbols; SYMBOL_NAME(m) != NULL; (m)++) + + +/* Traverse all symtabs in all objfiles. */ + +#define ALL_SYMTABS(objfile, s) \ + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_SYMTABS (objfile, s) + +/* Traverse all psymtabs in all objfiles. */ + +#define ALL_PSYMTABS(objfile, p) \ + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_PSYMTABS (objfile, p) + +/* Traverse all minimal symbols in all objfiles. */ + +#define ALL_MSYMBOLS(objfile, m) \ + ALL_OBJFILES (objfile) \ + if ((objfile)->msymbols) \ + ALL_OBJFILE_MSYMBOLS (objfile, m) + +#endif /* !defined (OBJFILES_H) */ diff --git a/gnu/usr.bin/gdb/gdb/obstack.h b/gnu/usr.bin/gdb/gdb/obstack.h new file mode 100644 index 00000000000..689f14855fe --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/obstack.h @@ -0,0 +1,490 @@ +/* obstack.h - object stack macros + Copyright (C) 1988, 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Library General Public License as published by the +Free Software Foundation; either version 2, 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 Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +--Gosper's immortal quote from HAKMEM item 154, out of context--you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' an obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef __OBSTACKS__ +#define __OBSTACKS__ + +/* We use subtraction of (char *)0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +#define __PTR_TO_INT(P) ((P) - (char *)0) +#endif + +#ifndef __INT_TO_PTR +#define __INT_TO_PTR(P) ((P) + (char *)0) +#endif + +/* We need the type of the resulting object. In ANSI C it is ptrdiff_t + but in traditional C it is usually long. If we are in ANSI C and + don't already have ptrdiff_t get it. */ + +#if defined (__STDC__) && ! defined (offsetof) +#if defined (__GNUC__) && defined (IN_GCC) +/* On Next machine, the system's stddef.h screws up if included + after we have defined just ptrdiff_t, so include all of gstddef.h. + Otherwise, define just ptrdiff_t, which is all we need. */ +#ifndef __NeXT__ +#define __need_ptrdiff_t +#endif + +/* While building GCC, the stddef.h that goes with GCC has this name. */ +#include "gstddef.h" +#else +#include +#endif +#endif + +#ifdef __STDC__ +#define PTR_INT_TYPE ptrdiff_t +#else +#define PTR_INT_TYPE long +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + PTR_INT_TYPE temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ + struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */ + void (*freefun) (); /* User's function to free a chunk. */ + char *extra_arg; /* first arg for chunk alloc/dealloc funcs */ + unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */ + unsigned maybe_empty_object:1;/* There is a possibility that the current + chunk contains a zero-length object. This + prevents freeing the chunk if we allocate + a bigger chunk to replace it. */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +#ifdef __STDC__ +extern void _obstack_newchunk (struct obstack *, int); +extern void _obstack_free (struct obstack *, void *); +extern void _obstack_begin (struct obstack *, int, int, + void *(*) (), void (*) ()); +extern void _obstack_begin_1 (struct obstack *, int, int, + void *(*) (), void (*) (), void *); +#else +extern void _obstack_newchunk (); +extern void _obstack_free (); +extern void _obstack_begin (); +extern void _obstack_begin_1 (); +#endif + +#ifdef __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun)) + +#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg)) + +#define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun)) + +#define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)()) (newfreefun)) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#if defined (__GNUC__) && defined (__STDC__) +#if __GNUC__ < 2 +#define __extension__ +#endif + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +#define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +#define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ +#define obstack_grow(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, __len), 0) : 0); \ + bcopy (where, __o->next_free, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len + 1 > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, __len + 1), 0) : 0), \ + bcopy (where, __o->next_free, __len), \ + __o->next_free += __len, \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +#define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + 1 > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, 1), 0) : 0), \ + *(__o->next_free)++ = (datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers or ints, + and that the data added so far to the current object + shares that much alignment. */ + +#define obstack_ptr_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + sizeof (void *) > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, sizeof (void *)), 0) : 0), \ + *((void **)__o->next_free)++ = ((void *)datum); \ + (void) 0; }) + +#define obstack_int_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + sizeof (int) > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, sizeof (int)), 0) : 0), \ + *((int *)__o->next_free)++ = ((int)datum); \ + (void) 0; }) + +#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr) +#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + +#define obstack_blank(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->chunk_limit - __o->next_free < __len) \ + ? (_obstack_newchunk (__o, __len), 0) : 0); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_alloc(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +#define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +#define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *value = (void *) __o1->object_base; \ + if (__o1->next_free == value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\ + & ~ (__o1->alignment_mask)); \ + ((__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + ? (__o1->next_free = __o1->chunk_limit) : 0); \ + __o1->object_base = __o1->next_free; \ + value; }) + +#define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +#define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +#define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +#define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp) + +#define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0) + +#define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + *((h)->next_free)++ = (datum)) + +#define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + *((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum)) + +#define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + *((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum)) + +#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr) +#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + +#define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + (h)->next_free += (h)->temp) + +#define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +#define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_finish(h) \ +( ((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *)(h)->chunk \ + > (h)->chunk_limit - (char *)(h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +#ifdef __STDC__ +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) +#else +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0))) +#endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#endif /* not __OBSTACKS__ */ diff --git a/gnu/usr.bin/gdb/gdb/parse.c b/gnu/usr.bin/gdb/gdb/parse.c new file mode 100644 index 00000000000..08f2b7e6748 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/parse.c @@ -0,0 +1,827 @@ +/* Parse expressions for GDB. + Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + Modified from expread.y by the Department of Computer Science at the + State University of New York at Buffalo, 1991. + +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. */ + +/* Parse an expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "frame.h" +#include "expression.h" +#include "value.h" +#include "command.h" +#include "language.h" +#include "parser-defs.h" + +static void +free_funcalls PARAMS ((void)); + +static void +prefixify_expression PARAMS ((struct expression *)); + +static int +length_of_subexp PARAMS ((struct expression *, int)); + +static void +prefixify_subexp PARAMS ((struct expression *, struct expression *, int, int)); + +/* Data structure for saving values of arglist_len for function calls whose + arguments contain other function calls. */ + +struct funcall + { + struct funcall *next; + int arglist_len; + }; + +static struct funcall *funcall_chain; + +/* Assign machine-independent names to certain registers + (unless overridden by the REGISTER_NAMES table) */ + +#ifdef NO_STD_REGS +unsigned num_std_regs = 0; +struct std_regs std_regs[1]; +#else +struct std_regs std_regs[] = { + +#ifdef PC_REGNUM + { "pc", PC_REGNUM }, +#endif +#ifdef FP_REGNUM + { "fp", FP_REGNUM }, +#endif +#ifdef SP_REGNUM + { "sp", SP_REGNUM }, +#endif +#ifdef PS_REGNUM + { "ps", PS_REGNUM }, +#endif + +}; + +unsigned num_std_regs = (sizeof std_regs / sizeof std_regs[0]); + +#endif + + +/* Begin counting arguments for a function call, + saving the data about any containing call. */ + +void +start_arglist () +{ + register struct funcall *new; + + new = (struct funcall *) xmalloc (sizeof (struct funcall)); + new->next = funcall_chain; + new->arglist_len = arglist_len; + arglist_len = 0; + funcall_chain = new; +} + +/* Return the number of arguments in a function call just terminated, + and restore the data for the containing function call. */ + +int +end_arglist () +{ + register int val = arglist_len; + register struct funcall *call = funcall_chain; + funcall_chain = call->next; + arglist_len = call->arglist_len; + free ((PTR)call); + return val; +} + +/* Free everything in the funcall chain. + Used when there is an error inside parsing. */ + +static void +free_funcalls () +{ + register struct funcall *call, *next; + + for (call = funcall_chain; call; call = next) + { + next = call->next; + free ((PTR)call); + } +} + +/* This page contains the functions for adding data to the struct expression + being constructed. */ + +/* Add one element to the end of the expression. */ + +/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into + a register through here */ + +void +write_exp_elt (expelt) + union exp_element expelt; +{ + if (expout_ptr >= expout_size) + { + expout_size *= 2; + expout = (struct expression *) + xrealloc ((char *) expout, sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size)); + } + expout->elts[expout_ptr++] = expelt; +} + +void +write_exp_elt_opcode (expelt) + enum exp_opcode expelt; +{ + union exp_element tmp; + + tmp.opcode = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_sym (expelt) + struct symbol *expelt; +{ + union exp_element tmp; + + tmp.symbol = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_block (b) + struct block *b; +{ + union exp_element tmp; + tmp.block = b; + write_exp_elt (tmp); +} + +void +write_exp_elt_longcst (expelt) + LONGEST expelt; +{ + union exp_element tmp; + + tmp.longconst = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_dblcst (expelt) + double expelt; +{ + union exp_element tmp; + + tmp.doubleconst = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_type (expelt) + struct type *expelt; +{ + union exp_element tmp; + + tmp.type = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_intern (expelt) + struct internalvar *expelt; +{ + union exp_element tmp; + + tmp.internalvar = expelt; + + write_exp_elt (tmp); +} + +/* Add a string constant to the end of the expression. + + String constants are stored by first writing an expression element + that contains the length of the string, then stuffing the string + constant itself into however many expression elements are needed + to hold it, and then writing another expression element that contains + the length of the string. I.E. an expression element at each end of + the string records the string length, so you can skip over the + expression elements containing the actual string bytes from either + end of the string. Note that this also allows gdb to handle + strings with embedded null bytes, as is required for some languages. + + Don't be fooled by the fact that the string is null byte terminated, + this is strictly for the convenience of debugging gdb itself. Gdb + Gdb does not depend up the string being null terminated, since the + actual length is recorded in expression elements at each end of the + string. The null byte is taken into consideration when computing how + many expression elements are required to hold the string constant, of + course. */ + + +void +write_exp_string (str) + struct stoken str; +{ + register int len = str.length; + register int lenelt; + register char *strdata; + + /* Compute the number of expression elements required to hold the string + (including a null byte terminator), along with one expression element + at each end to record the actual string length (not including the + null byte terminator). */ + + lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1); + + /* Ensure that we have enough available expression elements to store + everything. */ + + if ((expout_ptr + lenelt) >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + lenelt + 10); + expout = (struct expression *) + xrealloc ((char *) expout, (sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size))); + } + + /* Write the leading length expression element (which advances the current + expression element index), then write the string constant followed by a + terminating null byte, and then write the trailing length expression + element. */ + + write_exp_elt_longcst ((LONGEST) len); + strdata = (char *) &expout->elts[expout_ptr]; + memcpy (strdata, str.ptr, len); + *(strdata + len) = '\0'; + expout_ptr += lenelt - 2; + write_exp_elt_longcst ((LONGEST) len); +} + +/* Add a bitstring constant to the end of the expression. + + Bitstring constants are stored by first writing an expression element + that contains the length of the bitstring (in bits), then stuffing the + bitstring constant itself into however many expression elements are + needed to hold it, and then writing another expression element that + contains the length of the bitstring. I.E. an expression element at + each end of the bitstring records the bitstring length, so you can skip + over the expression elements containing the actual bitstring bytes from + either end of the bitstring. */ + +void +write_exp_bitstring (str) + struct stoken str; +{ + register int bits = str.length; /* length in bits */ + register int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; + register int lenelt; + register char *strdata; + + /* Compute the number of expression elements required to hold the bitstring, + along with one expression element at each end to record the actual + bitstring length in bits. */ + + lenelt = 2 + BYTES_TO_EXP_ELEM (len); + + /* Ensure that we have enough available expression elements to store + everything. */ + + if ((expout_ptr + lenelt) >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + lenelt + 10); + expout = (struct expression *) + xrealloc ((char *) expout, (sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size))); + } + + /* Write the leading length expression element (which advances the current + expression element index), then write the bitstring constant, and then + write the trailing length expression element. */ + + write_exp_elt_longcst ((LONGEST) bits); + strdata = (char *) &expout->elts[expout_ptr]; + memcpy (strdata, str.ptr, len); + expout_ptr += lenelt - 2; + write_exp_elt_longcst ((LONGEST) bits); +} + +/* Return a null-terminated temporary copy of the name + of a string token. */ + +char * +copy_name (token) + struct stoken token; +{ + memcpy (namecopy, token.ptr, token.length); + namecopy[token.length] = 0; + return namecopy; +} + +/* Reverse an expression from suffix form (in which it is constructed) + to prefix form (in which we can conveniently print or execute it). */ + +static void +prefixify_expression (expr) + register struct expression *expr; +{ + register int len = + sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts); + register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; + + temp = (struct expression *) alloca (len); + + /* Copy the original expression into temp. */ + memcpy (temp, expr, len); + + prefixify_subexp (temp, expr, inpos, outpos); +} + +/* Return the number of exp_elements in the subexpression of EXPR + whose last exp_element is at index ENDPOS - 1 in EXPR. */ + +static int +length_of_subexp (expr, endpos) + register struct expression *expr; + register int endpos; +{ + register int oplen = 1; + register int args = 0; + register int i; + + if (endpos < 1) + error ("?error in length_of_subexp"); + + i = (int) expr->elts[endpos - 1].opcode; + + switch (i) + { + /* C++ */ + case OP_SCOPE: + oplen = longest_to_int (expr->elts[endpos - 2].longconst); + oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_LONG: + case OP_DOUBLE: + case OP_VAR_VALUE: + oplen = 4; + break; + + case OP_TYPE: + case OP_BOOL: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); + break; + + case UNOP_MAX: + case UNOP_MIN: + oplen = 3; + break; + + case BINOP_VAL: + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case UNOP_ABS: + case UNOP_CAP: + case UNOP_CHR: + case UNOP_FLOAT: + case UNOP_HIGH: + case UNOP_ODD: + case UNOP_ORD: + case UNOP_TRUNC: + oplen = 1; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + /* fall through */ + case OP_M2_STRING: + case OP_STRING: + oplen = longest_to_int (expr->elts[endpos - 2].longconst); + oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_BITSTRING: + oplen = longest_to_int (expr->elts[endpos - 2].longconst); + oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; + oplen = 4 + BYTES_TO_EXP_ELEM (oplen); + break; + + case OP_ARRAY: + oplen = 4; + args = longest_to_int (expr->elts[endpos - 2].longconst); + args -= longest_to_int (expr->elts[endpos - 3].longconst); + args += 1; + break; + + case TERNOP_COND: + args = 3; + break; + + /* Modula-2 */ + case MULTI_SUBSCRIPT: + oplen=3; + args = 1 + longest_to_int (expr->elts[endpos- 2].longconst); + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + (i < (int) BINOP_END); + } + + while (args > 0) + { + oplen += length_of_subexp (expr, endpos - oplen); + args--; + } + + return oplen; +} + +/* Copy the subexpression ending just before index INEND in INEXPR + into OUTEXPR, starting at index OUTBEG. + In the process, convert it from suffix to prefix form. */ + +static void +prefixify_subexp (inexpr, outexpr, inend, outbeg) + register struct expression *inexpr; + struct expression *outexpr; + register int inend; + int outbeg; +{ + register int oplen = 1; + register int args = 0; + register int i; + int *arglens; + enum exp_opcode opcode; + + /* Compute how long the last operation is (in OPLEN), + and also how many preceding subexpressions serve as + arguments for it (in ARGS). */ + + opcode = inexpr->elts[inend - 1].opcode; + switch (opcode) + { + /* C++ */ + case OP_SCOPE: + oplen = longest_to_int (inexpr->elts[inend - 2].longconst); + oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_LONG: + case OP_DOUBLE: + case OP_VAR_VALUE: + oplen = 4; + break; + + case OP_TYPE: + case OP_BOOL: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst); + break; + + case UNOP_MIN: + case UNOP_MAX: + oplen = 3; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case UNOP_ABS: + case UNOP_CAP: + case UNOP_CHR: + case UNOP_FLOAT: + case UNOP_HIGH: + case UNOP_ODD: + case UNOP_ORD: + case UNOP_TRUNC: + oplen=1; + args=1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + /* fall through */ + case OP_M2_STRING: + case OP_STRING: + oplen = longest_to_int (inexpr->elts[inend - 2].longconst); + oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_BITSTRING: + oplen = longest_to_int (inexpr->elts[inend - 2].longconst); + oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; + oplen = 4 + BYTES_TO_EXP_ELEM (oplen); + break; + + case OP_ARRAY: + oplen = 4; + args = longest_to_int (inexpr->elts[inend - 2].longconst); + args -= longest_to_int (inexpr->elts[inend - 3].longconst); + args += 1; + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* Modula-2 */ + case MULTI_SUBSCRIPT: + oplen=3; + args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst); + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + ((int) opcode < (int) BINOP_END); + } + + /* Copy the final operator itself, from the end of the input + to the beginning of the output. */ + inend -= oplen; + memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend], + EXP_ELEM_TO_BYTES (oplen)); + outbeg += oplen; + + /* Find the lengths of the arg subexpressions. */ + arglens = (int *) alloca (args * sizeof (int)); + for (i = args - 1; i >= 0; i--) + { + oplen = length_of_subexp (inexpr, inend); + arglens[i] = oplen; + inend -= oplen; + } + + /* Now copy each subexpression, preserving the order of + the subexpressions, but prefixifying each one. + In this loop, inend starts at the beginning of + the expression this level is working on + and marches forward over the arguments. + outbeg does similarly in the output. */ + for (i = 0; i < args; i++) + { + oplen = arglens[i]; + inend += oplen; + prefixify_subexp (inexpr, outexpr, inend, outbeg); + outbeg += oplen; + } +} + +/* This page contains the two entry points to this file. */ + +/* Read an expression from the string *STRINGPTR points to, + parse it, and return a pointer to a struct expression that we malloc. + Use block BLOCK as the lexical context for variable names; + if BLOCK is zero, use the block of the selected stack frame. + Meanwhile, advance *STRINGPTR to point after the expression, + at the first nonwhite character that is not part of the expression + (possibly a null character). + + If COMMA is nonzero, stop if a comma is reached. */ + +struct expression * +parse_exp_1 (stringptr, block, comma) + char **stringptr; + struct block *block; + int comma; +{ + struct cleanup *old_chain; + + lexptr = *stringptr; + + paren_depth = 0; + type_stack_depth = 0; + + comma_terminates = comma; + + if (lexptr == 0 || *lexptr == 0) + error_no_arg ("expression to compute"); + + old_chain = make_cleanup (free_funcalls, 0); + funcall_chain = 0; + + expression_context_block = block ? block : get_selected_block (); + + namecopy = (char *) alloca (strlen (lexptr) + 1); + expout_size = 10; + expout_ptr = 0; + expout = (struct expression *) + xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size)); + expout->language_defn = current_language; + make_cleanup (free_current_contents, &expout); + + if (current_language->la_parser ()) + current_language->la_error (NULL); + + discard_cleanups (old_chain); + + /* Record the actual number of expression elements, and then + reallocate the expression memory so that we free up any + excess elements. */ + + expout->nelts = expout_ptr; + expout = (struct expression *) + xrealloc ((char *) expout, + sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_ptr));; + + /* Convert expression from postfix form as generated by yacc + parser, to a prefix form. */ + + DUMP_EXPRESSION (expout, stdout, "before conversion to prefix form"); + prefixify_expression (expout); + DUMP_EXPRESSION (expout, stdout, "after conversion to prefix form"); + + *stringptr = lexptr; + return expout; +} + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ + +struct expression * +parse_expression (string) + char *string; +{ + register struct expression *exp; + exp = parse_exp_1 (&string, 0, 0); + if (*string) + error ("Junk after end of expression."); + return exp; +} + +/* Stuff for maintaining a stack of types. Currently just used by C, but + probably useful for any language which declares its types "backwards". */ + +void +push_type (tp) + enum type_pieces tp; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (union type_stack_elt *) + xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack)); + } + type_stack[type_stack_depth++].piece = tp; +} + +void +push_type_int (n) + int n; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (union type_stack_elt *) + xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack)); + } + type_stack[type_stack_depth++].int_val = n; +} + +enum type_pieces +pop_type () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth].piece; + return tp_end; +} + +int +pop_type_int () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth].int_val; + /* "Can't happen". */ + return 0; +} + +/* Pop the type stack and return the type which corresponds to FOLLOW_TYPE + as modified by all the stuff on the stack. */ +struct type * +follow_types (follow_type) + struct type *follow_type; +{ + int done = 0; + int array_size; + struct type *range_type; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = pop_type_int (); + if (array_size != -1) + { + range_type = + create_range_type ((struct type *) NULL, + builtin_type_int, 0, + array_size - 1); + follow_type = + create_array_type ((struct type *) NULL, + follow_type, range_type); + } + else + follow_type = lookup_pointer_type (follow_type); + break; + case tp_function: + follow_type = lookup_function_type (follow_type); + break; + } + return follow_type; +} + +void +_initialize_parse () +{ + type_stack_size = 80; + type_stack_depth = 0; + type_stack = (union type_stack_elt *) + xmalloc (type_stack_size * sizeof (*type_stack)); +} diff --git a/gnu/usr.bin/gdb/gdb/parser-defs.h b/gnu/usr.bin/gdb/gdb/parser-defs.h new file mode 100644 index 00000000000..5c8710e4e6e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/parser-defs.h @@ -0,0 +1,188 @@ +/* Parser definitions for GDB. + Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + Modified from expread.y by the Department of Computer Science at the + State University of New York at Buffalo. + +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. */ + +#if !defined (PARSER_DEFS_H) +#define PARSER_DEFS_H 1 + +struct std_regs { + char *name; + int regnum; +}; + +extern struct std_regs std_regs[]; +extern unsigned num_std_regs; + +struct expression *expout; +int expout_size; +int expout_ptr; + +/* If this is nonzero, this block is used as the lexical context + for symbol names. */ + +struct block *expression_context_block; + +/* The innermost context required by the stack and register variables + we've encountered so far. */ +struct block *innermost_block; + +/* The block in which the most recently discovered symbol was found. */ +struct block *block_found; + +/* Number of arguments seen so far in innermost function call. */ +int arglist_len; + +/* A string token, either a char-string or bit-string. Char-strings are + used, for example, for the names of symbols. */ + +struct stoken + { + /* Pointer to first byte of char-string or first bit of bit-string */ + char *ptr; + /* Length of string in bytes for char-string or bits for bit-string */ + int length; + }; + +struct ttype + { + struct stoken stoken; + struct type *type; + }; + +struct symtoken + { + struct stoken stoken; + struct symbol *sym; + int is_a_field_of_this; + }; + +/* For parsing of complicated types. + An array should be preceded in the list by the size of the array. */ +enum type_pieces + {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function}; +/* The stack can contain either an enum type_pieces or an int. */ +union type_stack_elt { + enum type_pieces piece; + int int_val; +}; +union type_stack_elt *type_stack; +int type_stack_depth, type_stack_size; + +extern void +write_exp_elt PARAMS ((union exp_element)); + +extern void +write_exp_elt_opcode PARAMS ((enum exp_opcode)); + +extern void +write_exp_elt_sym PARAMS ((struct symbol *)); + +extern void +write_exp_elt_longcst PARAMS ((LONGEST)); + +extern void +write_exp_elt_dblcst PARAMS ((double)); + +extern void +write_exp_elt_type PARAMS ((struct type *)); + +extern void +write_exp_elt_intern PARAMS ((struct internalvar *)); + +extern void +write_exp_string PARAMS ((struct stoken)); + +extern void +write_exp_bitstring PARAMS ((struct stoken)); + +extern void +start_arglist PARAMS ((void)); + +extern int +end_arglist PARAMS ((void)); + +extern char * +copy_name PARAMS ((struct stoken)); + +extern void +push_type PARAMS ((enum type_pieces)); + +extern void +push_type_int PARAMS ((int)); + +extern enum type_pieces +pop_type PARAMS ((void)); + +extern int +pop_type_int PARAMS ((void)); + +extern struct type *follow_types PARAMS ((struct type *)); + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +char *lexptr; + +/* Tokens that refer to names do so with explicit pointer and length, + so they can share the storage that lexptr is parsing. + + When it is necessary to pass a name to a function that expects + a null-terminated string, the substring is copied out + into a block of storage that namecopy points to. + + namecopy is allocated once, guaranteed big enough, for each parsing. */ + +char *namecopy; + +/* Current depth in parentheses within the expression. */ + +int paren_depth; + +/* Nonzero means stop parsing on first comma (if not within parentheses). */ + +int comma_terminates; + +/* These codes indicate operator precedences for expression printing, + least tightly binding first. */ +/* Adding 1 to a precedence value is done for binary operators, + on the operand which is more tightly bound, so that operators + of equal precedence within that operand will get parentheses. */ +/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator; + they are used as the "surrounding precedence" to force + various kinds of things to be parenthesized. */ +enum precedence +{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_LOGICAL_OR, + PREC_LOGICAL_AND, PREC_BITWISE_IOR, PREC_BITWISE_AND, PREC_BITWISE_XOR, + PREC_EQUAL, PREC_ORDER, PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT, + PREC_HYPER, PREC_PREFIX, PREC_SUFFIX }; + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +struct op_print +{ + char *string; + enum exp_opcode opcode; + /* Precedence of operator. These values are used only by comparisons. */ + enum precedence precedence; + int right_assoc; +}; + +#endif /* PARSER_DEFS_H */ diff --git a/gnu/usr.bin/gdb/gdb/partial-stab.h b/gnu/usr.bin/gdb/gdb/partial-stab.h new file mode 100644 index 00000000000..3be0be61887 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/partial-stab.h @@ -0,0 +1,618 @@ +/* Shared code to pre-read a stab (dbx-style), when building a psymtab. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993 + 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. */ + +/* The following need to be defined: + SET_NAMESTRING() --Set namestring to name of symbol. + CUR_SYMBOL_TYPE --Type code of current symbol. + CUR_SYMBOL_VALUE --Value field of current symbol. May be adjusted here. + */ + +/* End of macro definitions, now let's handle them symbols! */ + + switch (CUR_SYMBOL_TYPE) + { + char *p; + /* + * Standard, external, non-debugger, symbols + */ + + case N_TEXT | N_EXT: + case N_NBTEXT | N_EXT: + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto record_it; + + case N_DATA | N_EXT: + case N_NBDATA | N_EXT: + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + goto record_it; + + case N_BSS: + case N_BSS | N_EXT: + case N_NBBSS | N_EXT: + case N_SETV | N_EXT: /* FIXME, is this in BSS? */ + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_BSS); + goto record_it; + + case N_ABS | N_EXT: + record_it: +#ifdef DBXREAD_ONLY + SET_NAMESTRING(); + + bss_ext_symbol: + record_minimal_symbol (namestring, CUR_SYMBOL_VALUE, + CUR_SYMBOL_TYPE, objfile); /* Always */ +#endif /* DBXREAD_ONLY */ + continue; + + /* Standard, local, non-debugger, symbols */ + + case N_NBTEXT: + + /* We need to be able to deal with both N_FN or N_TEXT, + because we have no way of knowing whether the sys-supplied ld + or GNU ld was used to make the executable. Sequents throw + in another wrinkle -- they renumbered N_FN. */ + + case N_FN: + case N_FN_SEQ: + case N_TEXT: +#ifdef DBXREAD_ONLY + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT); + SET_NAMESTRING(); + if ((namestring[0] == '-' && namestring[1] == 'l') + || (namestring [(nsl = strlen (namestring)) - 1] == 'o' + && namestring [nsl - 2] == '.') +#ifdef GDB_TARGET_IS_HPPA + /* some cooperation from gcc to get around ld stupidity */ + || (namestring[0] == 'e' && STREQ (namestring, "end_file.")) +#endif + ) + { +#ifndef GDB_TARGET_IS_HPPA + if (objfile -> ei.entry_point < CUR_SYMBOL_VALUE && + objfile -> ei.entry_point >= last_o_file_start) + { + objfile -> ei.entry_file_lowpc = last_o_file_start; + objfile -> ei.entry_file_highpc = CUR_SYMBOL_VALUE; + } +#endif + if (past_first_source_file && pst + /* The gould NP1 uses low values for .o and -l symbols + which are not the address. */ + && CUR_SYMBOL_VALUE >= pst->textlow) + { + END_PSYMTAB (pst, psymtab_include_list, includes_used, + symnum * symbol_size, CUR_SYMBOL_VALUE, + dependency_list, dependencies_used); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + else + past_first_source_file = 1; + last_o_file_start = CUR_SYMBOL_VALUE; + } + else + goto record_it; +#endif /* DBXREAD_ONLY */ + continue; + + case N_DATA: + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + goto record_it; + + case N_UNDF | N_EXT: +#ifdef DBXREAD_ONLY + if (CUR_SYMBOL_VALUE != 0) { + /* This is a "Fortran COMMON" symbol. See if the target + environment knows where it has been relocated to. */ + + CORE_ADDR reladdr; + + SET_NAMESTRING(); + if (target_lookup_symbol (namestring, &reladdr)) { + continue; /* Error in lookup; ignore symbol for now. */ + } + CUR_SYMBOL_TYPE ^= (N_BSS^N_UNDF); /* Define it as a bss-symbol */ + CUR_SYMBOL_VALUE = reladdr; + goto bss_ext_symbol; + } +#endif /* DBXREAD_ONLY */ + continue; /* Just undefined, not COMMON */ + + case N_UNDF: +#ifdef DBXREAD_ONLY + if (processing_acc_compilation && bufp->n_strx == 1) { + /* Deal with relative offsets in the string table + used in ELF+STAB under Solaris. If we want to use the + n_strx field, which contains the name of the file, + we must adjust file_string_table_offset *before* calling + SET_NAMESTRING(). */ + past_first_source_file = 1; + file_string_table_offset = next_file_string_table_offset; + next_file_string_table_offset = + file_string_table_offset + bufp->n_value; + if (next_file_string_table_offset < file_string_table_offset) + error ("string table offset backs up at %d", symnum); + /* FIXME -- replace error() with complaint. */ + continue; + } +#endif /* DBXREAD_ONLY */ + continue; + + /* Lots of symbol types we can just ignore. */ + + case N_ABS: + case N_NBDATA: + case N_NBBSS: + continue; + + /* Keep going . . .*/ + + /* + * Special symbol types for GNU + */ + case N_INDR: + case N_INDR | N_EXT: + case N_SETA: + case N_SETA | N_EXT: + case N_SETT: + case N_SETT | N_EXT: + case N_SETD: + case N_SETD | N_EXT: + case N_SETB: + case N_SETB | N_EXT: + case N_SETV: + continue; + + /* + * Debugger symbols + */ + + case N_SO: { + unsigned long valu; + static int prev_so_symnum = -10; + static int first_so_symnum; + char *p; + + valu = CUR_SYMBOL_VALUE + ANOFFSET (section_offsets, SECT_OFF_TEXT); + + past_first_source_file = 1; + + if (prev_so_symnum != symnum - 1) + { /* Here if prev stab wasn't N_SO */ + first_so_symnum = symnum; + + if (pst) + { + END_PSYMTAB (pst, psymtab_include_list, includes_used, + symnum * symbol_size, valu, + dependency_list, dependencies_used); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + } + + prev_so_symnum = symnum; + + /* End the current partial symtab and start a new one */ + + SET_NAMESTRING(); + + /* Some compilers (including gcc) emit a pair of initial N_SOs. + The first one is a directory name; the second the file name. + If pst exists, is empty, and has a filename ending in '/', + we assume the previous N_SO was a directory name. */ + + p = strrchr (namestring, '/'); + if (p && *(p+1) == '\000') + continue; /* Simply ignore directory name SOs */ + + /* Some other compilers (C++ ones in particular) emit useless + SOs for non-existant .c files. We ignore all subsequent SOs that + immediately follow the first. */ + + if (!pst) + pst = START_PSYMTAB (objfile, section_offsets, + namestring, valu, + first_so_symnum * symbol_size, + objfile -> global_psymbols.next, + objfile -> static_psymbols.next); + continue; + } + + case N_BINCL: +#ifdef DBXREAD_ONLY + /* Add this bincl to the bincl_list for future EXCLs. No + need to save the string; it'll be around until + read_dbx_symtab function returns */ + + SET_NAMESTRING(); + + add_bincl_to_list (pst, namestring, CUR_SYMBOL_VALUE); + + /* Mark down an include file in the current psymtab */ + + goto record_include_file; + +#else /* DBXREAD_ONLY */ + continue; +#endif + + case N_SOL: + /* Mark down an include file in the current psymtab */ + + SET_NAMESTRING(); + + /* In C++, one may expect the same filename to come round many + times, when code is coming alternately from the main file + and from inline functions in other files. So I check to see + if this is a file we've seen before -- either the main + source file, or a previously included file. + + This seems to be a lot of time to be spending on N_SOL, but + things like "break c-exp.y:435" need to work (I + suppose the psymtab_include_list could be hashed or put + in a binary tree, if profiling shows this is a major hog). */ + if (pst && STREQ (namestring, pst->filename)) + continue; + { + register int i; + for (i = 0; i < includes_used; i++) + if (STREQ (namestring, psymtab_include_list[i])) + { + i = -1; + break; + } + if (i == -1) + continue; + } + +#ifdef DBXREAD_ONLY + record_include_file: +#endif + + psymtab_include_list[includes_used++] = namestring; + if (includes_used >= includes_allocated) + { + char **orig = psymtab_include_list; + + psymtab_include_list = (char **) + alloca ((includes_allocated *= 2) * + sizeof (char *)); + memcpy ((PTR)psymtab_include_list, (PTR)orig, + includes_used * sizeof (char *)); + } + continue; + + case N_LSYM: /* Typedef or automatic variable. */ + case N_STSYM: /* Data seg var -- static */ + case N_LCSYM: /* BSS " */ + case N_ROSYM: /* Read-only data seg var -- static. */ + case N_NBSTS: /* Gould nobase. */ + case N_NBLCS: /* symbols. */ + case N_FUN: + case N_GSYM: /* Global (extern) variable; can be + data or bss (sigh FIXME). */ + + /* Following may probably be ignored; I'll leave them here + for now (until I do Pascal and Modula 2 extensions). */ + + case N_PC: /* I may or may not need this; I + suspect not. */ + case N_M2C: /* I suspect that I can ignore this here. */ + case N_SCOPE: /* Same. */ + + SET_NAMESTRING(); + + p = (char *) strchr (namestring, ':'); + if (!p) + continue; /* Not a debugging symbol. */ + + + + /* Main processing section for debugging symbols which + the initial read through the symbol tables needs to worry + about. If we reach this point, the symbol which we are + considering is definitely one we are interested in. + p must also contain the (valid) index into the namestring + which indicates the debugging type symbol. */ + + switch (p[1]) + { + case 'S': + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + objfile->static_psymbols, + CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + case 'G': + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + /* The addresses in these entries are reported to be + wrong. See the code that reads 'G's for symtabs. */ + ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + objfile->global_psymbols, + CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + + case 'T': + if (p != namestring) /* a name is there, not just :T... */ + { + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + STRUCT_NAMESPACE, LOC_TYPEDEF, + objfile->static_psymbols, + CUR_SYMBOL_VALUE, + psymtab_language, objfile); + if (p[2] == 't') + { + /* Also a typedef with the same name. */ + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + objfile->static_psymbols, + CUR_SYMBOL_VALUE, psymtab_language, + objfile); + p += 1; + } + } + goto check_enum; + case 't': + if (p != namestring) /* a name is there, not just :T... */ + { + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + objfile->static_psymbols, + CUR_SYMBOL_VALUE, + psymtab_language, objfile); + } + check_enum: + /* If this is an enumerated type, we need to + add all the enum constants to the partial symbol + table. This does not cover enums without names, e.g. + "enum {a, b} c;" in C, but fortunately those are + rare. There is no way for GDB to find those from the + enum type without spending too much time on it. Thus + to solve this problem, the compiler needs to put out the + enum in a nameless type. GCC2 does this. */ + + /* We are looking for something of the form + ":" ("t" | "T") [ "="] "e" + { ":" ","} ";". */ + + /* Skip over the colon and the 't' or 'T'. */ + p += 2; + /* This type may be given a number. Also, numbers can come + in pairs like (0,26). Skip over it. */ + while ((*p >= '0' && *p <= '9') + || *p == '(' || *p == ',' || *p == ')' + || *p == '=') + p++; + + if (*p++ == 'e') + { + /* We have found an enumerated type. */ + /* According to comments in read_enum_type + a comma could end it instead of a semicolon. + I don't know where that happens. + Accept either. */ + while (*p && *p != ';' && *p != ',') + { + char *q; + + /* Check for and handle cretinous dbx symbol name + continuation! */ + if (*p == '\\') + p = next_symbol_text (); + + /* Point to the character after the name + of the enum constant. */ + for (q = p; *q && *q != ':'; q++) + ; + /* Note that the value doesn't matter for + enum constants in psymtabs, just in symtabs. */ + ADD_PSYMBOL_TO_LIST (p, q - p, + VAR_NAMESPACE, LOC_CONST, + objfile->static_psymbols, 0, + psymtab_language, objfile); + /* Point past the name. */ + p = q; + /* Skip over the value. */ + while (*p && *p != ',') + p++; + /* Advance past the comma. */ + if (*p) + p++; + } + } + continue; + case 'c': + /* Constant, e.g. from "const" in Pascal. */ + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_CONST, + objfile->static_psymbols, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + + case 'f': +#ifdef DBXREAD_ONLY + /* Kludges for ELF/STABS with Sun ACC */ + last_function_name = namestring; + if (pst && pst->textlow == 0) + pst->textlow = CUR_SYMBOL_VALUE; +#if 0 + if (startup_file_end == 0) + startup_file_end = CUR_SYMBOL_VALUE; +#endif + /* End kludge. */ +#endif /* DBXREAD_ONLY */ + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + objfile->static_psymbols, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + + /* Global functions were ignored here, but now they + are put into the global psymtab like one would expect. + They're also in the minimal symbol table. */ + case 'F': +#ifdef DBXREAD_ONLY + /* Kludges for ELF/STABS with Sun ACC */ + last_function_name = namestring; + if (pst && pst->textlow == 0) + pst->textlow = CUR_SYMBOL_VALUE; +#if 0 + if (startup_file_end == 0) + startup_file_end = CUR_SYMBOL_VALUE; +#endif + /* End kludge. */ +#endif /* DBXREAD_ONLY */ + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + objfile->global_psymbols, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + + /* Two things show up here (hopefully); static symbols of + local scope (static used inside braces) or extensions + of structure symbols. We can ignore both. */ + case 'V': + case '(': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + continue; + + default: + /* Unexpected symbol. Ignore it; perhaps it is an extension + that we don't know about. + + Someone says sun cc puts out symbols like + /foo/baz/maclib::/usr/local/bin/maclib, + which would get here with a symbol type of ':'. */ + complain (&unknown_symchar_complaint, p[1]); + continue; + } + + case N_EXCL: +#ifdef DBXREAD_ONLY + + SET_NAMESTRING(); + + /* Find the corresponding bincl and mark that psymtab on the + psymtab dependency list */ + { + struct partial_symtab *needed_pst = + find_corresponding_bincl_psymtab (namestring, CUR_SYMBOL_VALUE); + + /* If this include file was defined earlier in this file, + leave it alone. */ + if (needed_pst == pst) continue; + + if (needed_pst) + { + int i; + int found = 0; + + for (i = 0; i < dependencies_used; i++) + if (dependency_list[i] == needed_pst) + { + found = 1; + break; + } + + /* If it's already in the list, skip the rest. */ + if (found) continue; + + dependency_list[dependencies_used++] = needed_pst; + if (dependencies_used >= dependencies_allocated) + { + struct partial_symtab **orig = dependency_list; + dependency_list = + (struct partial_symtab **) + alloca ((dependencies_allocated *= 2) + * sizeof (struct partial_symtab *)); + memcpy ((PTR)dependency_list, (PTR)orig, + (dependencies_used + * sizeof (struct partial_symtab *))); +#ifdef DEBUG_INFO + fprintf (stderr, "Had to reallocate dependency list.\n"); + fprintf (stderr, "New dependencies allocated: %d\n", + dependencies_allocated); +#endif + } + } + else + error ("Invalid symbol data: \"repeated\" header file not previously seen, at symtab pos %d.", + symnum); + } +#endif /* DBXREAD_ONLY */ + continue; + + case N_RBRAC: +#ifdef HANDLE_RBRAC + HANDLE_RBRAC(CUR_SYMBOL_VALUE); + continue; +#endif + case N_EINCL: + case N_DSLINE: + case N_BSLINE: + case N_SSYM: /* Claim: Structure or union element. + Hopefully, I can ignore this. */ + case N_ENTRY: /* Alternate entry point; can ignore. */ + case N_MAIN: /* Can definitely ignore this. */ + case N_CATCH: /* These are GNU C++ extensions */ + case N_EHDECL: /* that can safely be ignored here. */ + case N_LENG: + case N_BCOMM: + case N_ECOMM: + case N_ECOML: + case N_FNAME: + case N_SLINE: + case N_RSYM: + case N_PSYM: + case N_LBRAC: + case N_NSYMS: /* Ultrix 4.0: symbol count */ + case N_DEFD: /* GNU Modula-2 */ + + case N_OBJ: /* useless types from Solaris */ + case N_OPT: + case N_ENDM: + /* These symbols aren't interesting; don't worry about them */ + + continue; + + default: + /* If we haven't found it yet, ignore it. It's probably some + new type we don't know about yet. */ + complain (&unknown_symtype_complaint, + local_hex_string ((unsigned long) CUR_SYMBOL_TYPE)); + continue; + } diff --git a/gnu/usr.bin/gdb/gdb/printcmd.c b/gnu/usr.bin/gdb/gdb/printcmd.c new file mode 100644 index 00000000000..3530ac2f32f --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/printcmd.c @@ -0,0 +1,2078 @@ +/* Print values for GNU debugger GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991 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. */ + +#include "defs.h" +#include +#include +#include "frame.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "language.h" +#include "expression.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "target.h" +#include "breakpoint.h" +#include "demangle.h" + +extern int asm_demangle; /* Whether to demangle syms in asm printouts */ +extern int addressprint; /* Whether to print hex addresses in HLL " */ + +struct format_data +{ + int count; + char format; + char size; +}; + +/* Last specified output format. */ + +static char last_format = 'x'; + +/* Last specified examination size. 'b', 'h', 'w' or `q'. */ + +static char last_size = 'w'; + +/* Default address to examine next. */ + +static CORE_ADDR next_address; + +/* Last address examined. */ + +static CORE_ADDR last_examine_address; + +/* Contents of last address examined. + This is not valid past the end of the `x' command! */ + +static value last_examine_value; + +/* Largest offset between a symbolic value and an address, that will be + printed as `0x1234 '. */ + +static unsigned int max_symbolic_offset = UINT_MAX; + +/* Append the source filename and linenumber of the symbol when + printing a symbolic value as `' if set. */ +static int print_symbol_filename = 0; + +/* Number of auto-display expression currently being displayed. + So that we can disable it if we get an error or a signal within it. + -1 when not doing one. */ + +int current_display_number; + +/* Flag to low-level print routines that this value is being printed + in an epoch window. We'd like to pass this as a parameter, but + every routine would need to take it. Perhaps we can encapsulate + this in the I/O stream once we have GNU stdio. */ + +int inspect_it = 0; + +struct display +{ + /* Chain link to next auto-display item. */ + struct display *next; + /* Expression to be evaluated and displayed. */ + struct expression *exp; + /* Item number of this auto-display item. */ + int number; + /* Display format specified. */ + struct format_data format; + /* Innermost block required by this expression when evaluated */ + struct block *block; + /* Status of this display (enabled or disabled) */ + enum enable status; +}; + +/* Chain of expressions whose values should be displayed + automatically each time the program stops. */ + +static struct display *display_chain; + +static int display_number; + +/* Prototypes for local functions */ + +static void +delete_display PARAMS ((int)); + +static void +enable_display PARAMS ((char *, int)); + +static void +disable_display_command PARAMS ((char *, int)); + +static void +disassemble_command PARAMS ((char *, int)); + +static void +printf_command PARAMS ((char *, int)); + +static void +print_frame_nameless_args PARAMS ((struct frame_info *, long, int, int, + FILE *)); + +static void +display_info PARAMS ((char *, int)); + +static void +do_one_display PARAMS ((struct display *)); + +static void +undisplay_command PARAMS ((char *, int)); + +static void +free_display PARAMS ((struct display *)); + +static void +display_command PARAMS ((char *, int)); + +static void +x_command PARAMS ((char *, int)); + +static void +address_info PARAMS ((char *, int)); + +static void +set_command PARAMS ((char *, int)); + +static void +output_command PARAMS ((char *, int)); + +static void +call_command PARAMS ((char *, int)); + +static void +inspect_command PARAMS ((char *, int)); + +static void +print_command PARAMS ((char *, int)); + +static void +print_command_1 PARAMS ((char *, int, int)); + +static void +validate_format PARAMS ((struct format_data, char *)); + +static void +do_examine PARAMS ((struct format_data, CORE_ADDR)); + +static void +print_formatted PARAMS ((value, int, int)); + +static struct format_data +decode_format PARAMS ((char **, int, int)); + + +/* Decode a format specification. *STRING_PTR should point to it. + OFORMAT and OSIZE are used as defaults for the format and size + if none are given in the format specification. + If OSIZE is zero, then the size field of the returned value + should be set only if a size is explicitly specified by the + user. + The structure returned describes all the data + found in the specification. In addition, *STRING_PTR is advanced + past the specification and past all whitespace following it. */ + +static struct format_data +decode_format (string_ptr, oformat, osize) + char **string_ptr; + int oformat; + int osize; +{ + struct format_data val; + register char *p = *string_ptr; + + val.format = '?'; + val.size = '?'; + val.count = 1; + + if (*p >= '0' && *p <= '9') + val.count = atoi (p); + while (*p >= '0' && *p <= '9') p++; + + /* Now process size or format letters that follow. */ + + while (1) + { + if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') + val.size = *p++; + else if (*p >= 'a' && *p <= 'z') + val.format = *p++; + else + break; + } + +#ifndef CC_HAS_LONG_LONG + /* Make sure 'g' size is not used on integer types. + Well, actually, we can handle hex. */ + if (val.size == 'g' && val.format != 'f' && val.format != 'x') + val.size = 'w'; +#endif + + while (*p == ' ' || *p == '\t') p++; + *string_ptr = p; + + /* Set defaults for format and size if not specified. */ + if (val.format == '?') + { + if (val.size == '?') + { + /* Neither has been specified. */ + val.format = oformat; + val.size = osize; + } + else + /* If a size is specified, any format makes a reasonable + default except 'i'. */ + val.format = oformat == 'i' ? 'x' : oformat; + } + else if (val.size == '?') + switch (val.format) + { + case 'a': + case 's': + /* Addresses must be words. */ + val.size = osize ? 'w' : osize; + break; + case 'f': + /* Floating point has to be word or giantword. */ + if (osize == 'w' || osize == 'g') + val.size = osize; + else + /* Default it to giantword if the last used size is not + appropriate. */ + val.size = osize ? 'g' : osize; + break; + case 'c': + /* Characters default to one byte. */ + val.size = osize ? 'b' : osize; + break; + default: + /* The default is the size most recently specified. */ + val.size = osize; + } + + return val; +} + +/* Print value VAL on stdout according to FORMAT, a letter or 0. + Do not end with a newline. + 0 means print VAL according to its own type. + SIZE is the letter for the size of datum being printed. + This is used to pad hex numbers so they line up. */ + +static void +print_formatted (val, format, size) + register value val; + register int format; + int size; +{ + int len = TYPE_LENGTH (VALUE_TYPE (val)); + + if (VALUE_LVAL (val) == lval_memory) + next_address = VALUE_ADDRESS (val) + len; + + switch (format) + { + case 's': + next_address = VALUE_ADDRESS (val) + + value_print (value_addr (val), stdout, format, Val_pretty_default); + break; + + case 'i': + /* The old comment says + "Force output out, print_insn not using _filtered". + I'm not completely sure what that means, I suspect most print_insn + now do use _filtered, so I guess it's obsolete. */ + /* We often wrap here if there are long symbolic names. */ + wrap_here (" "); + next_address = VALUE_ADDRESS (val) + + print_insn (VALUE_ADDRESS (val), stdout); + break; + + default: + if (format == 0 + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRING + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION + || VALUE_REPEATED (val)) + value_print (val, stdout, format, Val_pretty_default); + else + print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val), + format, size, stdout); + } +} + +/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR, + according to letters FORMAT and SIZE on STREAM. + FORMAT may not be zero. Formats s and i are not supported at this level. + + This is how the elements of an array or structure are printed + with a format. */ + +void +print_scalar_formatted (valaddr, type, format, size, stream) + char *valaddr; + struct type *type; + int format; + int size; + FILE *stream; +{ + LONGEST val_long; + int len = TYPE_LENGTH (type); + + if (len > sizeof (LONGEST) + && (format == 't' + || format == 'c' + || format == 'o' + || format == 'u' + || format == 'd' + || format == 'x')) + { + /* We can't print it normally, but we can print it in hex. + Printing it in the wrong radix is more useful than saying + "use /x, you dummy". */ + /* FIXME: we could also do octal or binary if that was the + desired format. */ + /* FIXME: we should be using the size field to give us a minimum + field width to print. */ + val_print_type_code_int (type, valaddr, stream); + return; + } + + val_long = unpack_long (type, valaddr); + + /* If we are printing it as unsigned, truncate it in case it is actually + a negative signed value (e.g. "print/u (short)-1" should print 65535 + (if shorts are 16 bits) instead of 4294967295). */ + if (format != 'd') + { + if (len < sizeof (LONGEST)) + val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1; + } + + switch (format) + { + case 'x': + if (!size) + { + /* no size specified, like in print. Print varying # of digits. */ + print_longest (stream, 'x', 1, val_long); + } + else + switch (size) + { + case 'b': + case 'h': + case 'w': + case 'g': + print_longest (stream, size, 1, val_long); + break; + default: + error ("Undefined output size \"%c\".", size); + } + break; + + case 'd': + print_longest (stream, 'd', 1, val_long); + break; + + case 'u': + print_longest (stream, 'u', 0, val_long); + break; + + case 'o': + if (val_long) + print_longest (stream, 'o', 1, val_long); + else + fprintf_filtered (stream, "0"); + break; + + case 'a': + print_address (unpack_pointer (type, valaddr), stream); + break; + + case 'c': + value_print (value_from_longest (builtin_type_char, val_long), stream, 0, + Val_pretty_default); + break; + + case 'f': + if (len == sizeof (float)) + type = builtin_type_float; + else if (len == sizeof (double)) + type = builtin_type_double; + print_floating (valaddr, type, stream); + break; + + case 0: + abort (); + + case 't': + /* Binary; 't' stands for "two". */ + { + char bits[8*(sizeof val_long) + 1]; + char *cp = bits; + int width; + + if (!size) + width = 8*(sizeof val_long); + else + switch (size) + { + case 'b': + width = 8; + break; + case 'h': + width = 16; + break; + case 'w': + width = 32; + break; + case 'g': + width = 64; + break; + default: + error ("Undefined output size \"%c\".", size); + } + + bits[width] = '\0'; + while (width-- > 0) + { + bits[width] = (val_long & 1) ? '1' : '0'; + val_long >>= 1; + } + if (!size) + { + while (*cp && *cp == '0') + cp++; + if (*cp == '\0') + cp--; + } + fprintf_filtered (stream, local_binary_format_prefix()); + fprintf_filtered (stream, cp); + fprintf_filtered (stream, local_binary_format_suffix()); + } + break; + + default: + error ("Undefined output format \"%c\".", format); + } +} + +/* Specify default address for `x' command. + `info lines' uses this. */ + +void +set_next_address (addr) + CORE_ADDR addr; +{ + next_address = addr; + + /* Make address available to the user as $_. */ + set_internalvar (lookup_internalvar ("_"), + value_from_longest (lookup_pointer_type (builtin_type_void), + (LONGEST) addr)); +} + +/* Optionally print address ADDR symbolically as on STREAM, + after LEADIN. Print nothing if no symbolic name is found nearby. + DO_DEMANGLE controls whether to print a symbol in its native "raw" form, + or to interpret it as a possible C++ name and convert it back to source + form. However note that DO_DEMANGLE can be overridden by the specific + settings of the demangle and asm_demangle variables. */ + +void +print_address_symbolic (addr, stream, do_demangle, leadin) + CORE_ADDR addr; + FILE *stream; + int do_demangle; + char *leadin; +{ + CORE_ADDR name_location; + register struct symbol *symbol; + char *name; + + /* First try to find the address in the symbol tables to find + static functions. If that doesn't succeed we try the minimal symbol + vector for symbols in non-text space. + FIXME: Should find a way to get at the static non-text symbols too. */ + + symbol = find_pc_function (addr); + if (symbol) + { + name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)); + if (do_demangle) + name = SYMBOL_SOURCE_NAME (symbol); + else + name = SYMBOL_LINKAGE_NAME (symbol); + } + else + { + register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (addr); + + /* If nothing comes out, don't print anything symbolic. */ + if (msymbol == NULL) + return; + name_location = SYMBOL_VALUE_ADDRESS (msymbol); + if (do_demangle) + name = SYMBOL_SOURCE_NAME (msymbol); + else + name = SYMBOL_LINKAGE_NAME (msymbol); + } + + /* If the nearest symbol is too far away, don't print anything symbolic. */ + + /* For when CORE_ADDR is larger than unsigned int, we do math in + CORE_ADDR. But when we detect unsigned wraparound in the + CORE_ADDR math, we ignore this test and print the offset, + because addr+max_symbolic_offset has wrapped through the end + of the address space back to the beginning, giving bogus comparison. */ + if (addr > name_location + max_symbolic_offset + && name_location + max_symbolic_offset > name_location) + return; + + fputs_filtered (leadin, stream); + fputs_filtered ("<", stream); + fputs_filtered (name, stream); + if (addr != name_location) + fprintf_filtered (stream, "+%u", (unsigned int)(addr - name_location)); + + /* Append source filename and line number if desired. */ + if (symbol && print_symbol_filename) + { + struct symtab_and_line sal; + + sal = find_pc_line (addr, 0); + if (sal.symtab) + fprintf_filtered (stream, " at %s:%d", sal.symtab->filename, sal.line); + } + fputs_filtered (">", stream); +} + +/* Print address ADDR symbolically on STREAM. + First print it as a number. Then perhaps print + after the number. */ + +void +print_address (addr, stream) + CORE_ADDR addr; + FILE *stream; +{ +#if 0 && defined (ADDR_BITS_REMOVE) + /* This is wrong for pointer to char, in which we do want to print + the low bits. */ + fprintf_filtered (stream, local_hex_format(), + (unsigned long) ADDR_BITS_REMOVE(addr)); +#else + fprintf_filtered (stream, local_hex_format(), (unsigned long) addr); +#endif + print_address_symbolic (addr, stream, asm_demangle, " "); +} + +/* Print address ADDR symbolically on STREAM. Parameter DEMANGLE + controls whether to print the symbolic name "raw" or demangled. + Global setting "addressprint" controls whether to print hex address + or not. */ + +void +print_address_demangle (addr, stream, do_demangle) + CORE_ADDR addr; + FILE *stream; + int do_demangle; +{ + if (addr == 0) { + fprintf_filtered (stream, "0"); + } else if (addressprint) { + fprintf_filtered (stream, local_hex_format(), (unsigned long) addr); + print_address_symbolic (addr, stream, do_demangle, " "); + } else { + print_address_symbolic (addr, stream, do_demangle, ""); + } +} + + +/* These are the types that $__ will get after an examine command of one + of these sizes. */ + +static struct type *examine_b_type; +static struct type *examine_h_type; +static struct type *examine_w_type; +static struct type *examine_g_type; + +/* Examine data at address ADDR in format FMT. + Fetch it from memory and print on stdout. */ + +static void +do_examine (fmt, addr) + struct format_data fmt; + CORE_ADDR addr; +{ + register char format = 0; + register char size; + register int count = 1; + struct type *val_type = NULL; + register int i; + register int maxelts; + + format = fmt.format; + size = fmt.size; + count = fmt.count; + next_address = addr; + + /* String or instruction format implies fetch single bytes + regardless of the specified size. */ + if (format == 's' || format == 'i') + size = 'b'; + + if (size == 'b') + val_type = examine_b_type; + else if (size == 'h') + val_type = examine_h_type; + else if (size == 'w') + val_type = examine_w_type; + else if (size == 'g') + val_type = examine_g_type; + + maxelts = 8; + if (size == 'w') + maxelts = 4; + if (size == 'g') + maxelts = 2; + if (format == 's' || format == 'i') + maxelts = 1; + + /* Print as many objects as specified in COUNT, at most maxelts per line, + with the address of the next one at the start of each line. */ + + while (count > 0) + { + print_address (next_address, stdout); + printf_filtered (":"); + for (i = maxelts; + i > 0 && count > 0; + i--, count--) + { + printf_filtered ("\t"); + /* Note that print_formatted sets next_address for the next + object. */ + last_examine_address = next_address; + last_examine_value = value_at (val_type, next_address); + print_formatted (last_examine_value, format, size); + } + printf_filtered ("\n"); + fflush (stdout); + } +} + +static void +validate_format (fmt, cmdname) + struct format_data fmt; + char *cmdname; +{ + if (fmt.size != 0) + error ("Size letters are meaningless in \"%s\" command.", cmdname); + if (fmt.count != 1) + error ("Item count other than 1 is meaningless in \"%s\" command.", + cmdname); + if (fmt.format == 'i' || fmt.format == 's') + error ("Format letter \"%c\" is meaningless in \"%s\" command.", + fmt.format, cmdname); +} + +/* Evaluate string EXP as an expression in the current language and + print the resulting value. EXP may contain a format specifier as the + first argument ("/x myvar" for example, to print myvar in hex). + */ + +static void +print_command_1 (exp, inspect, voidprint) + char *exp; + int inspect; + int voidprint; +{ + struct expression *expr; + register struct cleanup *old_chain = 0; + register char format = 0; + register value val; + struct format_data fmt; + int cleanup = 0; + + /* Pass inspect flag to the rest of the print routines in a global (sigh). */ + inspect_it = inspect; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, 0); + validate_format (fmt, "print"); + last_format = format = fmt.format; + } + else + { + fmt.count = 1; + fmt.format = 0; + fmt.size = 0; + } + + if (exp && *exp) + { + extern int objectprint; + struct type *type; + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + cleanup = 1; + val = evaluate_expression (expr); + + /* C++: figure out what type we actually want to print it as. */ + type = VALUE_TYPE (val); + + if (objectprint + && ( TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF) + && ( TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT + || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_UNION)) + { + value v; + + v = value_from_vtable_info (val, TYPE_TARGET_TYPE (type)); + if (v != 0) + { + val = v; + type = VALUE_TYPE (val); + } + } + } + else + val = access_value_history (0); + + if (voidprint || (val && VALUE_TYPE (val) && + TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_VOID)) + { + int histindex = record_latest_value (val); + + if (inspect) + printf ("\031(gdb-makebuffer \"%s\" %d '(\"", exp, histindex); + else + if (histindex >= 0) printf_filtered ("$%d = ", histindex); + + print_formatted (val, format, fmt.size); + printf_filtered ("\n"); + if (inspect) + printf("\") )\030"); + } + + if (cleanup) + do_cleanups (old_chain); + inspect_it = 0; /* Reset print routines to normal */ +} + +/* ARGSUSED */ +static void +print_command (exp, from_tty) + char *exp; + int from_tty; +{ + print_command_1 (exp, 0, 1); +} + +/* Same as print, except in epoch, it gets its own window */ +/* ARGSUSED */ +static void +inspect_command (exp, from_tty) + char *exp; + int from_tty; +{ + extern int epoch_interface; + + print_command_1 (exp, epoch_interface, 1); +} + +/* Same as print, except it doesn't print void results. */ +/* ARGSUSED */ +static void +call_command (exp, from_tty) + char *exp; + int from_tty; +{ + print_command_1 (exp, 0, 0); +} + +/* ARGSUSED */ +static void +output_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr; + register struct cleanup *old_chain; + register char format = 0; + register value val; + struct format_data fmt; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, 0, 0); + validate_format (fmt, "output"); + format = fmt.format; + } + + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + + print_formatted (val, format, fmt.size); + + do_cleanups (old_chain); +} + +/* ARGSUSED */ +static void +set_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr = parse_expression (exp); + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + evaluate_expression (expr); + do_cleanups (old_chain); +} + +/* ARGSUSED */ +static void +address_info (exp, from_tty) + char *exp; + int from_tty; +{ + register struct symbol *sym; + register struct minimal_symbol *msymbol; + register long val; + register long basereg; + int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero + if exp is a field of `this'. */ + + if (exp == 0) + error ("Argument required."); + + sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE, + &is_a_field_of_this, (struct symtab **)NULL); + if (sym == NULL) + { + if (is_a_field_of_this) + { + printf ("Symbol \"%s\" is a field of the local class variable `this'\n", exp); + return; + } + + msymbol = lookup_minimal_symbol (exp, (struct objfile *) NULL); + + if (msymbol != NULL) + printf ("Symbol \"%s\" is at %s in a file compiled without debugging.\n", + exp, + local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (msymbol))); + else + error ("No symbol \"%s\" in current context.", exp); + return; + } + + printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym)); + val = SYMBOL_VALUE (sym); + basereg = SYMBOL_BASEREG (sym); + + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_CONST_BYTES: + printf ("constant"); + break; + + case LOC_LABEL: + printf ("a label at address %s", + local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym))); + break; + + case LOC_REGISTER: + printf ("a variable in register %s", reg_names[val]); + break; + + case LOC_STATIC: + printf ("static storage at address %s", + local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym))); + break; + + case LOC_REGPARM: + printf ("an argument in register %s", reg_names[val]); + break; + + case LOC_REGPARM_ADDR: + printf ("address of an argument in register %s", reg_names[val]); + break; + + case LOC_ARG: + printf ("an argument at offset %ld", val); + break; + + case LOC_LOCAL_ARG: + printf ("an argument at frame offset %ld", val); + break; + + case LOC_LOCAL: + printf ("a local variable at frame offset %ld", val); + break; + + case LOC_REF_ARG: + printf ("a reference argument at offset %ld", val); + break; + + case LOC_BASEREG: + printf ("a variable at offset %ld from register %s", + val, reg_names[basereg]); + break; + + case LOC_BASEREG_ARG: + printf ("an argument at offset %ld from register %s", + val, reg_names[basereg]); + break; + + case LOC_TYPEDEF: + printf ("a typedef"); + break; + + case LOC_BLOCK: + printf ("a function at address %s", + local_hex_string((unsigned long) BLOCK_START (SYMBOL_BLOCK_VALUE (sym)))); + break; + + case LOC_OPTIMIZED_OUT: + printf_filtered ("optimized out"); + break; + + default: + printf ("of unknown (botched) type"); + break; + } + printf (".\n"); +} + +static void +x_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr; + struct format_data fmt; + struct cleanup *old_chain; + struct value *val; + + fmt.format = last_format; + fmt.size = last_size; + fmt.count = 1; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, last_size); + } + + /* If we have an expression, evaluate it and use it as the address. */ + + if (exp != 0 && *exp != 0) + { + expr = parse_expression (exp); + /* Cause expression not to be there any more + if this command is repeated with Newline. + But don't clobber a user-defined command's definition. */ + if (from_tty) + *exp = 0; + old_chain = make_cleanup (free_current_contents, &expr); + val = evaluate_expression (expr); + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF) + val = value_ind (val); + /* In rvalue contexts, such as this, functions are coerced into + pointers to functions. This makes "x/i main" work. */ + if (/* last_format == 'i' + && */ TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC + && VALUE_LVAL (val) == lval_memory) + next_address = VALUE_ADDRESS (val); + else + next_address = value_as_pointer (val); + do_cleanups (old_chain); + } + + do_examine (fmt, next_address); + + /* If the examine succeeds, we remember its size and format for next time. */ + last_size = fmt.size; + last_format = fmt.format; + + /* Set a couple of internal variables if appropriate. */ + if (last_examine_value) + { + /* Make last address examined available to the user as $_. Use + the correct pointer type. */ + set_internalvar (lookup_internalvar ("_"), + value_from_longest ( + lookup_pointer_type (VALUE_TYPE (last_examine_value)), + (LONGEST) last_examine_address)); + + /* Make contents of last address examined available to the user as $__.*/ + set_internalvar (lookup_internalvar ("__"), last_examine_value); + } +} + + +/* Add an expression to the auto-display chain. + Specify the expression. */ + +static void +display_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct format_data fmt; + register struct expression *expr; + register struct display *new; + + if (exp == 0) + { + do_displays (); + return; + } + + if (*exp == '/') + { + exp++; + fmt = decode_format (&exp, 0, 0); + if (fmt.size && fmt.format == 0) + fmt.format = 'x'; + if (fmt.format == 'i' || fmt.format == 's') + fmt.size = 'b'; + } + else + { + fmt.format = 0; + fmt.size = 0; + fmt.count = 0; + } + + innermost_block = 0; + expr = parse_expression (exp); + + new = (struct display *) xmalloc (sizeof (struct display)); + + new->exp = expr; + new->block = innermost_block; + new->next = display_chain; + new->number = ++display_number; + new->format = fmt; + new->status = enabled; + display_chain = new; + + if (from_tty && target_has_execution) + do_one_display (new); + + dont_repeat (); +} + +static void +free_display (d) + struct display *d; +{ + free ((PTR)d->exp); + free ((PTR)d); +} + +/* Clear out the display_chain. + Done when new symtabs are loaded, since this invalidates + the types stored in many expressions. */ + +void +clear_displays () +{ + register struct display *d; + + while ((d = display_chain) != NULL) + { + free ((PTR)d->exp); + display_chain = d->next; + free ((PTR)d); + } +} + +/* Delete the auto-display number NUM. */ + +static void +delete_display (num) + int num; +{ + register struct display *d1, *d; + + if (!display_chain) + error ("No display number %d.", num); + + if (display_chain->number == num) + { + d1 = display_chain; + display_chain = d1->next; + free_display (d1); + } + else + for (d = display_chain; ; d = d->next) + { + if (d->next == 0) + error ("No display number %d.", num); + if (d->next->number == num) + { + d1 = d->next; + d->next = d1->next; + free_display (d1); + break; + } + } +} + +/* Delete some values from the auto-display chain. + Specify the element numbers. */ + +static void +undisplay_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + register char *p1; + register int num; + + if (args == 0) + { + if (query ("Delete all auto-display expressions? ")) + clear_displays (); + dont_repeat (); + return; + } + + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + num = atoi (p); + + delete_display (num); + + p = p1; + while (*p == ' ' || *p == '\t') p++; + } + dont_repeat (); +} + +/* Display a single auto-display. + Do nothing if the display cannot be printed in the current context, + or if the display is disabled. */ + +static void +do_one_display (d) + struct display *d; +{ + int within_current_scope; + + if (d->status == disabled) + return; + + if (d->block) + within_current_scope = contained_in (get_selected_block (), d->block); + else + within_current_scope = 1; + if (!within_current_scope) + return; + + current_display_number = d->number; + + printf_filtered ("%d: ", d->number); + if (d->format.size) + { + CORE_ADDR addr; + + printf_filtered ("x/"); + if (d->format.count != 1) + printf_filtered ("%d", d->format.count); + printf_filtered ("%c", d->format.format); + if (d->format.format != 'i' && d->format.format != 's') + printf_filtered ("%c", d->format.size); + printf_filtered (" "); + print_expression (d->exp, stdout); + if (d->format.count != 1) + printf_filtered ("\n"); + else + printf_filtered (" "); + + addr = value_as_pointer (evaluate_expression (d->exp)); + if (d->format.format == 'i') + addr = ADDR_BITS_REMOVE (addr); + + do_examine (d->format, addr); + } + else + { + if (d->format.format) + printf_filtered ("/%c ", d->format.format); + print_expression (d->exp, stdout); + printf_filtered (" = "); + print_formatted (evaluate_expression (d->exp), + d->format.format, d->format.size); + printf_filtered ("\n"); + } + + fflush (stdout); + current_display_number = -1; +} + +/* Display all of the values on the auto-display chain which can be + evaluated in the current scope. */ + +void +do_displays () +{ + register struct display *d; + + for (d = display_chain; d; d = d->next) + do_one_display (d); +} + +/* Delete the auto-display which we were in the process of displaying. + This is done when there is an error or a signal. */ + +void +disable_display (num) + int num; +{ + register struct display *d; + + for (d = display_chain; d; d = d->next) + if (d->number == num) + { + d->status = disabled; + return; + } + printf ("No display number %d.\n", num); +} + +void +disable_current_display () +{ + if (current_display_number >= 0) + { + disable_display (current_display_number); + fprintf (stderr, "Disabling display %d to avoid infinite recursion.\n", + current_display_number); + } + current_display_number = -1; +} + +static void +display_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct display *d; + + if (!display_chain) + printf ("There are no auto-display expressions now.\n"); + else + printf_filtered ("Auto-display expressions now in effect:\n\ +Num Enb Expression\n"); + + for (d = display_chain; d; d = d->next) + { + printf_filtered ("%d: %c ", d->number, "ny"[(int)d->status]); + if (d->format.size) + printf_filtered ("/%d%c%c ", d->format.count, d->format.size, + d->format.format); + else if (d->format.format) + printf_filtered ("/%c ", d->format.format); + print_expression (d->exp, stdout); + if (d->block && !contained_in (get_selected_block (), d->block)) + printf_filtered (" (cannot be evaluated in the current context)"); + printf_filtered ("\n"); + fflush (stdout); + } +} + +static void +enable_display (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + register char *p1; + register int num; + register struct display *d; + + if (p == 0) + { + for (d = display_chain; d; d = d->next) + d->status = enabled; + } + else + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') + p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + num = atoi (p); + + for (d = display_chain; d; d = d->next) + if (d->number == num) + { + d->status = enabled; + goto win; + } + printf ("No display number %d.\n", num); + win: + p = p1; + while (*p == ' ' || *p == '\t') + p++; + } +} + +/* ARGSUSED */ +static void +disable_display_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + register char *p1; + register struct display *d; + + if (p == 0) + { + for (d = display_chain; d; d = d->next) + d->status = disabled; + } + else + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') + p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + disable_display (atoi (p)); + + p = p1; + while (*p == ' ' || *p == '\t') + p++; + } +} + + +/* Print the value in stack frame FRAME of a variable + specified by a struct symbol. */ + +void +print_variable_value (var, frame, stream) + struct symbol *var; + FRAME frame; + FILE *stream; +{ + value val = read_var_value (var, frame); + value_print (val, stream, 0, Val_pretty_default); +} + +/* Print the arguments of a stack frame, given the function FUNC + running in that frame (as a symbol), the info on the frame, + and the number of args according to the stack frame (or -1 if unknown). */ + +/* References here and elsewhere to "number of args according to the + stack frame" appear in all cases to refer to "number of ints of args + according to the stack frame". At least for VAX, i386, isi. */ + +void +print_frame_args (func, fi, num, stream) + struct symbol *func; + struct frame_info *fi; + int num; + FILE *stream; +{ + struct block *b = NULL; + int nsyms = 0; + int first = 1; + register int i; + register struct symbol *sym; + register value val; + /* Offset of next stack argument beyond the one we have seen that is + at the highest offset. + -1 if we haven't come to a stack argument yet. */ + long highest_offset = -1; + int arg_size; + /* Number of ints of arguments that we have printed so far. */ + int args_printed = 0; + + if (func) + { + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + } + + for (i = 0; i < nsyms; i++) + { + QUIT; + sym = BLOCK_SYM (b, i); + + /* Keep track of the highest stack argument offset seen, and + skip over any kinds of symbols we don't care about. */ + + switch (SYMBOL_CLASS (sym)) { + case LOC_ARG: + case LOC_REF_ARG: + { + long current_offset = SYMBOL_VALUE (sym); + + arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym)); + + /* Compute address of next argument by adding the size of + this argument and rounding to an int boundary. */ + current_offset + = ((current_offset + arg_size + sizeof (int) - 1) + & ~(sizeof (int) - 1)); + + /* If this is the highest offset seen yet, set highest_offset. */ + if (highest_offset == -1 + || (current_offset > highest_offset)) + highest_offset = current_offset; + + /* Add the number of ints we're about to print to args_printed. */ + args_printed += (arg_size + sizeof (int) - 1) / sizeof (int); + } + + /* We care about types of symbols, but don't need to keep track of + stack offsets in them. */ + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL_ARG: + case LOC_BASEREG_ARG: + break; + + /* Other types of symbols we just skip over. */ + default: + continue; + } + + /* We have to look up the symbol because arguments can have + two entries (one a parameter, one a local) and the one we + want is the local, which lookup_symbol will find for us. + This includes gcc1 (not gcc2) on the sparc when passing a + small structure and gcc2 when the argument type is float + and it is passed as a double and converted to float by + the prologue (in the latter case the type of the LOC_ARG + symbol is double and the type of the LOC_LOCAL symbol is + float). There are also LOC_ARG/LOC_REGISTER pairs which + are not combined in symbol-reading. */ + /* But if the parameter name is null, don't try it. + Null parameter names occur on the RS/6000, for traceback tables. + FIXME, should we even print them? */ + + if (*SYMBOL_NAME (sym)) + sym = lookup_symbol + (SYMBOL_NAME (sym), + b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL); + + /* Print the current arg. */ + if (! first) + fprintf_filtered (stream, ", "); + wrap_here (" "); + fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym), + SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI); + fputs_filtered ("=", stream); + + /* Avoid value_print because it will deref ref parameters. We just + want to print their addresses. Print ??? for args whose address + we do not know. We pass 2 as "recurse" to val_print because our + standard indentation here is 4 spaces, and val_print indents + 2 for each recurse. */ + val = read_var_value (sym, FRAME_INFO_ID (fi)); + if (val) + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val), + stream, 0, 0, 2, Val_no_prettyprint); + else + fputs_filtered ("???", stream); + first = 0; + } + + /* Don't print nameless args in situations where we don't know + enough about the stack to find them. */ + if (num != -1) + { + long start; + + if (highest_offset == -1) + start = FRAME_ARGS_SKIP; + else + start = highest_offset; + + print_frame_nameless_args (fi, start, num - args_printed, + first, stream); + } +} + +/* Print nameless args on STREAM. + FI is the frameinfo for this frame, START is the offset + of the first nameless arg, and NUM is the number of nameless args to + print. FIRST is nonzero if this is the first argument (not just + the first nameless arg). */ +static void +print_frame_nameless_args (fi, start, num, first, stream) + struct frame_info *fi; + long start; + int num; + int first; + FILE *stream; +{ + int i; + CORE_ADDR argsaddr; + long arg_value; + + for (i = 0; i < num; i++) + { + QUIT; +#ifdef NAMELESS_ARG_VALUE + NAMELESS_ARG_VALUE (fi, start, &arg_value); +#else + argsaddr = FRAME_ARGS_ADDRESS (fi); + if (!argsaddr) + return; + + arg_value = read_memory_integer (argsaddr + start, sizeof (int)); +#endif + + if (!first) + fprintf_filtered (stream, ", "); + +#ifdef PRINT_NAMELESS_INTEGER + PRINT_NAMELESS_INTEGER (stream, arg_value); +#else +#ifdef PRINT_TYPELESS_INTEGER + PRINT_TYPELESS_INTEGER (stream, builtin_type_int, (LONGEST) arg_value); +#else + fprintf_filtered (stream, "%d", arg_value); +#endif /* PRINT_TYPELESS_INTEGER */ +#endif /* PRINT_NAMELESS_INTEGER */ + first = 0; + start += sizeof (int); + } +} + +/* ARGSUSED */ +static void +printf_command (arg, from_tty) + char *arg; + int from_tty; +{ + register char *f; + register char *s = arg; + char *string; + value *val_args; + char *substrings; + char *current_substring; + int nargs = 0; + int allocated_args = 20; + va_list args_to_vprintf; + struct cleanup *old_cleanups; + + val_args = (value *) xmalloc (allocated_args * sizeof (value)); + old_cleanups = make_cleanup (free_current_contents, &val_args); + + if (s == 0) + error_no_arg ("format-control string and values to print"); + + /* Skip white space before format string */ + while (*s == ' ' || *s == '\t') s++; + + /* A format string should follow, enveloped in double quotes */ + if (*s++ != '"') + error ("Bad format string, missing '\"'."); + + /* Parse the format-control string and copy it into the string STRING, + processing some kinds of escape sequence. */ + + f = string = (char *) alloca (strlen (s) + 1); + + while (*s != '"') + { + int c = *s++; + switch (c) + { + case '\0': + error ("Bad format string, non-terminated '\"'."); + + case '\\': + switch (c = *s++) + { + case '\\': + *f++ = '\\'; + break; + case 'n': + *f++ = '\n'; + break; + case 't': + *f++ = '\t'; + break; + case 'r': + *f++ = '\r'; + break; + case '"': + *f++ = '"'; + break; + default: + /* ??? TODO: handle other escape sequences */ + error ("Unrecognized \\ escape character in format string."); + } + break; + + default: + *f++ = c; + } + } + + /* Skip over " and following space and comma. */ + s++; + *f++ = '\0'; + while (*s == ' ' || *s == '\t') s++; + + if (*s != ',' && *s != 0) + error ("Invalid argument syntax"); + + if (*s == ',') s++; + while (*s == ' ' || *s == '\t') s++; + + /* Need extra space for the '\0's. Doubling the size is sufficient. */ + substrings = alloca (strlen (string) * 2); + current_substring = substrings; + + { + /* Now scan the string for %-specs and see what kinds of args they want. + argclass[I] classifies the %-specs so we can give vprintf something + of the right size. */ + + enum argclass {no_arg, int_arg, string_arg, double_arg, long_long_arg}; + enum argclass *argclass; + enum argclass this_argclass; + char *last_arg; + int nargs_wanted; + int lcount; + int i; + + argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass); + nargs_wanted = 0; + f = string; + last_arg = string; + while (*f) + if (*f++ == '%') + { + lcount = 0; + while (strchr ("0123456789.hlL-+ #", *f)) + { + if (*f == 'l' || *f == 'L') + lcount++; + f++; + } + switch (*f) + { + case 's': + this_argclass = string_arg; + break; + + case 'e': + case 'f': + case 'g': + this_argclass = double_arg; + break; + + case '*': + error ("`*' not supported for precision or width in printf"); + + case 'n': + error ("Format specifier `n' not supported in printf"); + + case '%': + this_argclass = no_arg; + break; + + default: + if (lcount > 1) + this_argclass = long_long_arg; + else + this_argclass = int_arg; + break; + } + f++; + if (this_argclass != no_arg) + { + strncpy (current_substring, last_arg, f - last_arg); + current_substring += f - last_arg; + *current_substring++ = '\0'; + last_arg = f; + argclass[nargs_wanted++] = this_argclass; + } + } + + /* Now, parse all arguments and evaluate them. + Store the VALUEs in VAL_ARGS. */ + + while (*s != '\0') + { + char *s1; + if (nargs == allocated_args) + val_args = (value *) xrealloc ((char *) val_args, + (allocated_args *= 2) + * sizeof (value)); + s1 = s; + val_args[nargs] = parse_to_comma_and_eval (&s1); + + /* If format string wants a float, unchecked-convert the value to + floating point of the same size */ + + if (argclass[nargs] == double_arg) + { + if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (float)) + VALUE_TYPE (val_args[nargs]) = builtin_type_float; + if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (double)) + VALUE_TYPE (val_args[nargs]) = builtin_type_double; + } + nargs++; + s = s1; + if (*s == ',') + s++; + } + + if (nargs != nargs_wanted) + error ("Wrong number of arguments for specified format-string"); + + /* FIXME: We should be using vprintf_filtered, but as long as it + has an arbitrary limit that is unacceptable. Correct fix is + for vprintf_filtered to scan down the format string so it knows + how big a buffer it needs (perhaps by putting a vasprintf (see + GNU C library) in libiberty). + + But for now, just force out any pending output, so at least the output + appears in the correct order. */ + wrap_here ((char *)NULL); + + /* Now actually print them. */ + current_substring = substrings; + for (i = 0; i < nargs; i++) + { + switch (argclass[i]) + { + case string_arg: + { + char *str; + CORE_ADDR tem; + int j; + tem = value_as_pointer (val_args[i]); + + /* This is a %s argument. Find the length of the string. */ + for (j = 0; ; j++) + { + char c; + QUIT; + read_memory (tem + j, &c, 1); + if (c == 0) + break; + } + + /* Copy the string contents into a string inside GDB. */ + str = (char *) alloca (j + 1); + read_memory (tem, str, j); + str[j] = 0; + + /* Don't use printf_filtered because of arbitrary limit. */ + printf (current_substring, str); + } + break; + case double_arg: + { + double val = value_as_double (val_args[i]); + /* Don't use printf_filtered because of arbitrary limit. */ + printf (current_substring, val); + break; + } + case long_long_arg: +#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) + { + long long val = value_as_long (val_args[i]); + /* Don't use printf_filtered because of arbitrary limit. */ + printf (current_substring, val); + break; + } +#else + error ("long long not supported in printf"); +#endif + case int_arg: + { + /* FIXME: there should be separate int_arg and long_arg. */ + long val = value_as_long (val_args[i]); + /* Don't use printf_filtered because of arbitrary limit. */ + printf (current_substring, val); + break; + } + default: + error ("internal error in printf_command"); + } + /* Skip to the next substring. */ + current_substring += strlen (current_substring) + 1; + } + /* Print the portion of the format string after the last argument. */ + /* It would be OK to use printf_filtered here. */ + printf (last_arg); + } + do_cleanups (old_cleanups); +} + +/* Dump a specified section of assembly code. With no command line + arguments, this command will dump the assembly code for the + function surrounding the pc value in the selected frame. With one + argument, it will dump the assembly code surrounding that pc value. + Two arguments are interpeted as bounds within which to dump + assembly. */ + +/* ARGSUSED */ +static void +disassemble_command (arg, from_tty) + char *arg; + int from_tty; +{ + CORE_ADDR low, high; + char *name; + CORE_ADDR pc; + char *space_index; + + name = NULL; + if (!arg) + { + if (!selected_frame) + error ("No frame selected.\n"); + + pc = get_frame_pc (selected_frame); + if (find_pc_partial_function (pc, &name, &low, &high) == 0) + error ("No function contains program counter for selected frame.\n"); + } + else if (!(space_index = (char *) strchr (arg, ' '))) + { + /* One argument. */ + pc = parse_and_eval_address (arg); + if (find_pc_partial_function (pc, &name, &low, &high) == 0) + error ("No function contains specified address.\n"); + } + else + { + /* Two arguments. */ + *space_index = '\0'; + low = parse_and_eval_address (arg); + high = parse_and_eval_address (space_index + 1); + } + + printf_filtered ("Dump of assembler code "); + if (name != NULL) + { + printf_filtered ("for function %s:\n", name); + } + else + { + printf_filtered ("from %s ", local_hex_string((unsigned long) low)); + printf_filtered ("to %s:\n", local_hex_string((unsigned long) high)); + } + + /* Dump the specified range. */ + for (pc = low; pc < high; ) + { + QUIT; + print_address (pc, stdout); + printf_filtered (":\t"); + pc += print_insn (pc, stdout); + printf_filtered ("\n"); + } + printf_filtered ("End of assembler dump.\n"); + fflush (stdout); +} + + +void +_initialize_printcmd () +{ + current_display_number = -1; + + add_info ("address", address_info, + "Describe where variable VAR is stored."); + + add_com ("x", class_vars, x_command, + "Examine memory: x/FMT ADDRESS.\n\ +ADDRESS is an expression for the memory address to examine.\n\ +FMT is a repeat count followed by a format letter and a size letter.\n\ +Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\ + t(binary), f(float), a(address), i(instruction), c(char) and s(string).\n\ +Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\ +The specified number of objects of the specified size are printed\n\ +according to the format.\n\n\ +Defaults for format and size letters are those previously used.\n\ +Default count is 1. Default address is following last thing printed\n\ +with this command or \"print\"."); + + add_com ("disassemble", class_vars, disassemble_command, + "Disassemble a specified section of memory.\n\ +Default is the function surrounding the pc of the selected frame.\n\ +With a single argument, the function surrounding that address is dumped.\n\ +Two arguments are taken as a range of memory to dump."); + +#if 0 + add_com ("whereis", class_vars, whereis_command, + "Print line number and file of definition of variable."); +#endif + + add_info ("display", display_info, + "Expressions to display when program stops, with code numbers."); + + add_cmd ("undisplay", class_vars, undisplay_command, + "Cancel some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +\"delete display\" has the same effect as this command.\n\ +Do \"info display\" to see current list of code numbers.", + &cmdlist); + + add_com ("display", class_vars, display_command, + "Print value of expression EXP each time the program stops.\n\ +/FMT may be used before EXP as in the \"print\" command.\n\ +/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\ +as in the \"x\" command, and then EXP is used to get the address to examine\n\ +and examining is done as in the \"x\" command.\n\n\ +With no argument, display all currently requested auto-display expressions.\n\ +Use \"undisplay\" to cancel display requests previously made."); + + add_cmd ("display", class_vars, enable_display, + "Enable some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to resume displaying.\n\ +No argument means enable all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &enablelist); + + add_cmd ("display", class_vars, disable_display_command, + "Disable some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means disable all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &disablelist); + + add_cmd ("display", class_vars, undisplay_command, + "Cancel some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &deletelist); + + add_com ("printf", class_vars, printf_command, + "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\ +This is useful for formatted output in user-defined commands."); + add_com ("output", class_vars, output_command, + "Like \"print\" but don't put in value history and don't print newline.\n\ +This is useful in user-defined commands."); + + add_prefix_cmd ("set", class_vars, set_command, +"Evaluate expression EXP and assign result to variable VAR, using assignment\n\ +syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\ +example). VAR may be a debugger \"convenience\" variable (names starting\n\ +with $), a register (a few standard names starting with $), or an actual\n\ +variable in the program being debugged. EXP is any valid expression.\n\ +Use \"set variable\" for variables with names identical to set subcommands.\n\ +\nWith a subcommand, this command modifies parts of the gdb environment.\n\ +You can see these environment settings with the \"show\" command.", + &setlist, "set ", 1, &cmdlist); + + /* "call" is the same as "set", but handy for dbx users to call fns. */ + add_com ("call", class_vars, call_command, + "Call a function in the program.\n\ +The argument is the function name and arguments, in the notation of the\n\ +current working language. The result is printed and saved in the value\n\ +history, if it is not void."); + + add_cmd ("variable", class_vars, set_command, +"Evaluate expression EXP and assign result to variable VAR, using assignment\n\ +syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\ +example). VAR may be a debugger \"convenience\" variable (names starting\n\ +with $), a register (a few standard names starting with $), or an actual\n\ +variable in the program being debugged. EXP is any valid expression.\n\ +This may usually be abbreviated to simply \"set\".", + &setlist); + + add_com ("print", class_vars, print_command, + concat ("Print value of expression EXP.\n\ +Variables accessible are those of the lexical environment of the selected\n\ +stack frame, plus all those whose scope is global or an entire file.\n\ +\n\ +$NUM gets previous value number NUM. $ and $$ are the last two values.\n\ +$$NUM refers to NUM'th value back from the last one.\n\ +Names starting with $ refer to registers (with the values they would have\n\ +if the program were to return to the stack frame now selected, restoring\n\ +all registers saved by frames farther in) or else to debugger\n\ +\"convenience\" variables (any such name not a known register).\n\ +Use assignment expressions to give values to convenience variables.\n", + "\n\ +{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\ +@ is a binary operator for treating consecutive data objects\n\ +anywhere in memory as an array. FOO@NUM gives an array whose first\n\ +element is FOO, whose second element is stored in the space following\n\ +where FOO is stored, etc. FOO must be an expression whose value\n\ +resides in memory.\n", + "\n\ +EXP may be preceded with /FMT, where FMT is a format letter\n\ +but no count or size letter (see \"x\" command).", NULL)); + add_com_alias ("p", "print", class_vars, 1); + + add_com ("inspect", class_vars, inspect_command, +"Same as \"print\" command, except that if you are running in the epoch\n\ +environment, the value is printed in its own window."); + + add_show_from_set ( + add_set_cmd ("max-symbolic-offset", no_class, var_uinteger, + (char *)&max_symbolic_offset, + "Set the largest offset that will be printed in form.", + &setprintlist), + &showprintlist); + add_show_from_set ( + add_set_cmd ("symbol-filename", no_class, var_boolean, + (char *)&print_symbol_filename, + "Set printing of source filename and line number with .", + &setprintlist), + &showprintlist); + + examine_b_type = init_type (TYPE_CODE_INT, 1, 0, NULL, NULL); + examine_h_type = init_type (TYPE_CODE_INT, 2, 0, NULL, NULL); + examine_w_type = init_type (TYPE_CODE_INT, 4, 0, NULL, NULL); + examine_g_type = init_type (TYPE_CODE_INT, 8, 0, NULL, NULL); +} diff --git a/gnu/usr.bin/gdb/gdb/putenv.c b/gnu/usr.bin/gdb/gdb/putenv.c new file mode 100644 index 00000000000..e2ea3572d91 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/putenv.c @@ -0,0 +1,111 @@ +/****************************************************************/ +/* */ +/* putenv(3) */ +/* */ +/* Change or add an environment entry */ +/* */ +/****************************************************************/ +/* origination 1987-Oct-7 T. Holm */ +/****************************************************************/ + +/* +Path: hoptoad!pacbell!ames!ll-xn!mit-eddie!uw-beaver!ssc-vax!uvicctr!tholm +From: tholm@uvicctr.UUCP (Terrence W. Holm) +Newsgroups: comp.os.minix +Subject: putenv(3) +Message-ID: <395@uvicctr.UUCP> +Date: 5 May 88 06:40:52 GMT +Organization: University of Victoria, Victoria B.C. Canada + +EFTH Minix report #2 - May 1988 - putenv(3) + +This is an implementation of putenv(3) that we +wrote for Minix. Please consider this a public +domain program. +*/ + +#include + +#define PSIZE sizeof(char *) + +extern char **environ; + +char *strchr(); +char *malloc(); + +/****************************************************************/ +/* */ +/* int */ +/* putenv( entry ) */ +/* */ +/* The "entry" should follow the form */ +/* "NAME=VALUE". This routine will search the */ +/* user environment for "NAME" and replace its */ +/* value with "VALUE". */ +/* */ +/* Note that "entry" is not copied, it is used */ +/* as the environment entry. This means that it */ +/* must not be unallocated or otherwise modifed */ +/* by the caller, unless it is replaced by a */ +/* subsequent putenv(). */ +/* */ +/* If the name is not found in the environment, */ +/* then a new vector of pointers is allocated, */ +/* "entry" is put at the end and the global */ +/* variable "environ" is updated. */ +/* */ +/* This function normally returns NULL, but -1 */ +/* is returned if it can not allocate enough */ +/* space using malloc(3), or "entry" does not */ +/* contain a '='. */ +/* */ +/****************************************************************/ + + +int +putenv( entry ) + char *entry; +{ + unsigned length; + unsigned size; + char *temp; + char **p; + char **new_environ; + + /* Find the length of the "NAME=" */ + + temp = strchr(entry,'='); + if ( temp == 0 ) + return( -1 ); + + length = (unsigned) (temp - entry + 1); + + + /* Scan through the environment looking for "NAME=" */ + + for ( p=environ; *p != 0 ; p++ ) + if ( strncmp( entry, *p, length ) == 0 ) + { + *p = entry; + return( 0 ); + } + + + /* The name was not found, build a bigger environment */ + + size = p - environ; + + new_environ = (char **) malloc( (size+2)*PSIZE ); + + if ( new_environ == (char **) NULL ) + return( -1 ); + + memcpy ((char *) new_environ, (char *) environ, size*PSIZE ); + + new_environ[size] = entry; + new_environ[size+1] = NULL; + + environ = new_environ; + + return(0); +} diff --git a/gnu/usr.bin/gdb/gdb/regex.c b/gnu/usr.bin/gdb/gdb/regex.c new file mode 100644 index 00000000000..75bf4e9fc23 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/regex.c @@ -0,0 +1,1725 @@ +/* Extended regular expression matching and search library. + Copyright (C) 1985, 1989 Free Software Foundation, Inc. + +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. */ + +/* To test, compile with -Dtest. + This Dtestable feature turns this into a self-contained program + which reads a pattern, describes how it compiles, + then reads a string and searches for it. */ + +#ifdef emacs + +/* The `emacs' switch turns on certain special matching commands + that make sense only in emacs. */ + +#include "config.h" +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +#else /* not emacs */ + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef sparc +#include +#endif +#endif + +/* + * Define the syntax stuff, so we can do the \<...\> things. + */ + +#ifndef Sword /* must be non-zero in some of the tests below... */ +#define Sword 1 +#endif + +#define SYNTAX(c) re_syntax_table[c] + +#ifdef SYNTAX_TABLE + +char *re_syntax_table; + +#else + +static char re_syntax_table[256]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + memset (re_syntax_table, '\0', sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + done = 1; +} + +#endif /* SYNTAX_TABLE */ +#endif /* not emacs */ + +#include "regex.h" + +/* Number of failure points to allocate space for initially, + when matching. If this number is exceeded, more space is allocated, + so it is not a hard limit. */ + +#ifndef NFAILURES +#define NFAILURES 80 +#endif /* NFAILURES */ + +/* width of a byte in bits */ + +#define BYTEWIDTH 8 + +#ifndef SIGN_EXTEND_CHAR +#define SIGN_EXTEND_CHAR(x) (x) +#endif + +static int obscure_syntax = 0; + +/* Specify the precise syntax of regexp for compilation. + This provides for compatibility for various utilities + which historically have different, incompatible syntaxes. + + The argument SYNTAX is a bit-mask containing the two bits + RE_NO_BK_PARENS and RE_NO_BK_VBAR. */ + +int +re_set_syntax (syntax) + int syntax; +{ + int ret; + + ret = obscure_syntax; + obscure_syntax = syntax; + return ret; +} + +/* re_compile_pattern takes a regular-expression string + and converts it into a buffer full of byte commands for matching. + + PATTERN is the address of the pattern string + SIZE is the length of it. + BUFP is a struct re_pattern_buffer * which points to the info + on where to store the byte commands. + This structure contains a char * which points to the + actual space, which should have been obtained with malloc. + re_compile_pattern may use realloc to grow the buffer space. + + The number of bytes of commands can be found out by looking in + the struct re_pattern_buffer that bufp pointed to, + after re_compile_pattern returns. +*/ + +#define PATPUSH(ch) (*b++ = (char) (ch)) + +#define PATFETCH(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; \ + if (translate) c = translate[c]; } + +#define PATFETCH_RAW(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; } + +#define PATUNFETCH p-- + +#define EXTEND_BUFFER \ + { char *old_buffer = bufp->buffer; \ + if (bufp->allocated == (1<<16)) goto too_big; \ + bufp->allocated *= 2; \ + if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \ + if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \ + goto memory_exhausted; \ + c = bufp->buffer - old_buffer; \ + b += c; \ + if (fixup_jump) \ + fixup_jump += c; \ + if (laststart) \ + laststart += c; \ + begalt += c; \ + if (pending_exact) \ + pending_exact += c; \ + } + +static void store_jump (), insert_jump (); + +char * +re_compile_pattern (pattern, size, bufp) + char *pattern; + int size; + struct re_pattern_buffer *bufp; +{ + register char *b = bufp->buffer; + register char *p = pattern; + char *pend = pattern + size; + register unsigned c, c1; + char *p1; + unsigned char *translate = (unsigned char *) bufp->translate; + + /* address of the count-byte of the most recently inserted "exactn" command. + This makes it possible to tell whether a new exact-match character + can be added to that command or requires a new "exactn" command. */ + + char *pending_exact = 0; + + /* address of the place where a forward-jump should go + to the end of the containing expression. + Each alternative of an "or", except the last, ends with a forward-jump + of this sort. */ + + char *fixup_jump = 0; + + /* address of start of the most recently finished expression. + This tells postfix * where to find the start of its operand. */ + + char *laststart = 0; + + /* In processing a repeat, 1 means zero matches is allowed */ + + char zero_times_ok; + + /* In processing a repeat, 1 means many matches is allowed */ + + char many_times_ok; + + /* address of beginning of regexp, or inside of last \( */ + + char *begalt = b; + + /* Stack of information saved by \( and restored by \). + Four stack elements are pushed by each \(: + First, the value of b. + Second, the value of fixup_jump. + Third, the value of regnum. + Fourth, the value of begalt. */ + + int stackb[40]; + int *stackp = stackb; + int *stacke = stackb + 40; + int *stackt; + + /* Counts \('s as they are encountered. Remembered for the matching \), + where it becomes the "register number" to put in the stop_memory command */ + + int regnum = 1; + + bufp->fastmap_accurate = 0; + +#ifndef emacs +#ifndef SYNTAX_TABLE + /* + * Initialize the syntax table. + */ + init_syntax_once(); +#endif +#endif + + if (bufp->allocated == 0) + { + bufp->allocated = 28; + if (bufp->buffer) + /* EXTEND_BUFFER loses when bufp->allocated is 0 */ + bufp->buffer = (char *) realloc (bufp->buffer, 28); + else + /* Caller did not allocate a buffer. Do it for him */ + bufp->buffer = (char *) malloc (28); + if (!bufp->buffer) goto memory_exhausted; + begalt = b = bufp->buffer; + } + + while (p != pend) + { + if (b - bufp->buffer > bufp->allocated - 10) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + PATFETCH (c); + + switch (c) + { + case '$': + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend) + goto normal_char; + /* Make operand of last vbar end before this `$'. */ + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = 0; + PATPUSH (endline); + break; + } + + /* $ means succeed if at end of line, but only in special contexts. + If randomly in the middle of a pattern, it is a normal character. */ + if (p == pend || *p == '\n' + || (obscure_syntax & RE_CONTEXT_INDEP_OPS) + || (obscure_syntax & RE_NO_BK_PARENS + ? *p == ')' + : *p == '\\' && p[1] == ')') + || (obscure_syntax & RE_NO_BK_VBAR + ? *p == '|' + : *p == '\\' && p[1] == '|')) + { + PATPUSH (endline); + break; + } + goto normal_char; + + case '^': + /* ^ means succeed if at beg of line, but only if no preceding pattern. */ + + if (laststart && p[-2] != '\n' + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (p != pattern + 1 + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + PATPUSH (begline); + begalt = b; + } + else + PATPUSH (begline); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern, char not special. */ + if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + /* If there is a sequence of repetition chars, + collapse it down to equivalent to just one. */ + zero_times_ok = 0; + many_times_ok = 0; + while (1) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + if (p == pend) + break; + PATFETCH (c); + if (c == '*') + ; + else if (!(obscure_syntax & RE_BK_PLUS_QM) + && (c == '+' || c == '?')) + ; + else if ((obscure_syntax & RE_BK_PLUS_QM) + && c == '\\') + { + int c1; + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + c = c1; + } + else + { + PATUNFETCH; + break; + } + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether 0 matches is allowed, + and whether 2 or more matches is allowed. */ + if (many_times_ok) + { + /* If more than one repetition is allowed, + put in a backward jump at the end. */ + store_jump (b, maybe_finalize_jump, laststart - 3); + b += 3; + } + insert_jump (on_failure_jump, laststart, b + 3, b); + pending_exact = 0; + b += 3; + if (!zero_times_ok) + { + /* At least one repetition required: insert before the loop + a skip over the initial on-failure-jump instruction */ + insert_jump (dummy_failure_jump, laststart, laststart + 6, b); + b += 3; + } + break; + + case '.': + laststart = b; + PATPUSH (anychar); + break; + + case '[': + while (b - bufp->buffer + > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + laststart = b; + if (*p == '^') + PATPUSH (charset_not), p++; + else + PATPUSH (charset); + p1 = p; + + PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map */ + memset (b, '\0', (1 << BYTEWIDTH) / BYTEWIDTH); + /* Read in characters and ranges, setting map bits */ + while (1) + { + PATFETCH (c); + if (c == ']' && p != p1 + 1) break; + if (*p == '-' && p[1] != ']') + { + PATFETCH (c1); + PATFETCH (c1); + while (c <= c1) + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++; + } + else + { + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH); + } + } + /* Discard any bitmap bytes that are all 0 at the end of the map. + Decrement the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + break; + + case '(': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_open; + + case ')': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_close; + + case '\n': + if (! (obscure_syntax & RE_NEWLINE_OR)) + goto normal_char; + else + goto handle_bar; + + case '|': + if (! (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_char; + else + goto handle_bar; + + case '\\': + if (p == pend) goto invalid_pattern; + PATFETCH_RAW (c); + switch (c) + { + case '(': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_open: + if (stackp == stacke) goto nesting_too_deep; + if (regnum < RE_NREGS) + { + PATPUSH (start_memory); + PATPUSH (regnum); + } + *stackp++ = b - bufp->buffer; + *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = regnum++; + *stackp++ = begalt - bufp->buffer; + fixup_jump = 0; + laststart = 0; + begalt = b; + break; + + case ')': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_close: + if (stackp == stackb) goto unmatched_close; + begalt = *--stackp + bufp->buffer; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + if (stackp[-1] < RE_NREGS) + { + PATPUSH (stop_memory); + PATPUSH (stackp[-1]); + } + stackp -= 2; + fixup_jump = 0; + if (*stackp) + fixup_jump = *stackp + bufp->buffer - 1; + laststart = *--stackp + bufp->buffer; + break; + + case '|': + if (obscure_syntax & RE_NO_BK_VBAR) + goto normal_backsl; + handle_bar: + insert_jump (on_failure_jump, begalt, b + 6, b); + pending_exact = 0; + b += 3; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = b; + b += 3; + laststart = 0; + begalt = b; + break; + +#ifdef emacs + case '=': + PATPUSH (at_dot); + break; + + case 's': + laststart = b; + PATPUSH (syntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATPUSH (notsyntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; +#endif /* emacs */ + + case 'w': + laststart = b; + PATPUSH (wordchar); + break; + + case 'W': + laststart = b; + PATPUSH (notwordchar); + break; + + case '<': + PATPUSH (wordbeg); + break; + + case '>': + PATPUSH (wordend); + break; + + case 'b': + PATPUSH (wordbound); + break; + + case 'B': + PATPUSH (notwordbound); + break; + + case '`': + PATPUSH (begbuf); + break; + + case '\'': + PATPUSH (endbuf); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c1 = c - '0'; + if (c1 >= regnum) + goto normal_char; + for (stackt = stackp - 2; stackt > stackb; stackt -= 4) + if (*stackt == c1) + goto normal_char; + laststart = b; + PATPUSH (duplicate); + PATPUSH (c1); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto handle_plus; + + default: + normal_backsl: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + if (translate) c = translate[c]; + goto normal_char; + } + break; + + default: + normal_char: + if (!pending_exact || pending_exact + *pending_exact + 1 != b + || *pending_exact == 0177 || *p == '*' || *p == '^' + || ((obscure_syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?'))) + { + laststart = b; + PATPUSH (exactn); + pending_exact = b; + PATPUSH (0); + } + PATPUSH (c); + (*pending_exact)++; + } + } + + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + if (stackp != stackb) goto unmatched_open; + + bufp->used = b - bufp->buffer; + return 0; + + invalid_pattern: + return "Invalid regular expression"; + + unmatched_open: + return "Unmatched \\("; + + unmatched_close: + return "Unmatched \\)"; + + end_of_pattern: + return "Premature end of regular expression"; + + nesting_too_deep: + return "Nesting too deep"; + + too_big: + return "Regular expression too big"; + + memory_exhausted: + return "Memory exhausted"; +} + +/* Store where `from' points a jump operation to jump to where `to' points. + `opcode' is the opcode to store. */ + +static void +store_jump (from, opcode, to) + char *from, *to; + char opcode; +{ + from[0] = opcode; + from[1] = (to - (from + 3)) & 0377; + from[2] = (to - (from + 3)) >> 8; +} + +/* Open up space at char FROM, and insert there a jump to TO. + CURRENT_END gives te end of the storage no in use, + so we know how much data to copy up. + OP is the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_jump (op, from, to, current_end) + char op; + char *from, *to, *current_end; +{ + register char *pto = current_end + 3; + register char *pfrom = current_end; + while (pfrom != from) + *--pto = *--pfrom; + store_jump (from, op, to); +} + +/* Given a pattern, compute a fastmap from it. + The fastmap records which of the (1 << BYTEWIDTH) possible characters + can start a string that matches the pattern. + This fastmap is used by re_search to skip quickly over totally implausible text. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data area + as bufp->fastmap. + The other components of bufp describe the pattern to be used. */ + +void +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *pattern = (unsigned char *) bufp->buffer; + int size = bufp->used; + register char *fastmap = bufp->fastmap; + register unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + register int j; + unsigned char *translate = (unsigned char *) bufp->translate; + + unsigned char *stackb[NFAILURES]; + unsigned char **stackp = stackb; + + memset (fastmap, '\0', (1 << BYTEWIDTH)); + bufp->fastmap_accurate = 1; + bufp->can_be_null = 0; + + while (p) + { + if (p == pend) + { + bufp->can_be_null = 1; + break; + } +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + case exactn: + if (translate) + fastmap[translate[p[1]]] = 1; + else + fastmap[p[1]] = 1; + break; + + case begline: + case before_dot: + case at_dot: + case after_dot: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + case endline: + if (translate) + fastmap[translate['\n']] = 1; + else + fastmap['\n'] = 1; + if (bufp->can_be_null != 1) + bufp->can_be_null = 2; + break; + + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + bufp->can_be_null = 1; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (j > 0) + continue; + /* Jump backward reached implies we just went through + the body of a loop and matched nothing. + Opcode jumped to should be an on_failure_jump. + Just treat it like an ordinary jump. + For a * loop, it has pushed its failure point already; + if so, discard that as redundant. */ + if ((enum regexpcode) *p != on_failure_jump) + continue; + p++; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (stackp != stackb && *stackp == p) + stackp--; + continue; + + case on_failure_jump: + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *++stackp = p + j; + continue; + + case start_memory: + case stop_memory: + p++; + continue; + + case duplicate: + bufp->can_be_null = 1; + fastmap['\n'] = 1; + case anychar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (j != '\n') + fastmap[j] = 1; + if (bufp->can_be_null) + return; + /* Don't return; check the alternative paths + so we can set can_be_null if appropriate. */ + break; + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; +#endif /* emacs */ + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + + case charset_not: + /* Chars beyond end of map must be allowed */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + } + + /* Get here means we have successfully found the possible starting characters + of one path of the pattern. We need not follow this path any farther. + Instead, look at the next alternative remembered in the stack. */ + if (stackp != stackb) + p = *stackp--; + else + break; + } +} + +/* Like re_search_2, below, but only one string is specified. */ + +int +re_search (pbufp, string, size, startpos, range, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size); +} + +/* Like re_match_2 but tries first a match starting at index STARTPOS, + then at STARTPOS + 1, and so on. + RANGE is the number of places to try before giving up. + If RANGE is negative, the starting positions tried are + STARTPOS, STARTPOS - 1, etc. + It is up to the caller to make sure that range is not so large + as to take the starting position outside of the input strings. + +The value returned is the position at which the match was found, + or -1 if no match was found, + or -2 if error (such as failure stack overflow). */ + +int +re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1, *string2; + int size1, size2; + int startpos; + register int range; + struct re_registers *regs; + int mstop; +{ + register char *fastmap = pbufp->fastmap; + register unsigned char *translate = (unsigned char *) pbufp->translate; + int total = size1 + size2; + int val; + + /* Update the fastmap now if not correct already */ + if (fastmap && !pbufp->fastmap_accurate) + re_compile_fastmap (pbufp); + + /* Don't waste time in a long search for a pattern + that says it is anchored. */ + if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf + && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + while (1) + { + /* If a fastmap is supplied, skip quickly over characters + that cannot possibly be the start of a match. + Note, however, that if the pattern can possibly match + the null string, we must test it at each starting point + so that we take the first null string we get. */ + + if (fastmap && startpos < total && pbufp->can_be_null != 1) + { + if (range > 0) + { + register int lim = 0; + register unsigned char *p; + int irange = range; + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + p = ((unsigned char *) + &(startpos >= size1 ? string2 - size1 : string1)[startpos]); + + if (translate) + { + while (range > lim && !fastmap[translate[*p++]]) + range--; + } + else + { + while (range > lim && !fastmap[*p++]) + range--; + } + startpos += irange - range; + } + else + { + register unsigned char c; + if (startpos >= size1) + c = string2[startpos - size1]; + else + c = string1[startpos]; + c &= 0xff; + if (translate ? !fastmap[translate[c]] : !fastmap[c]) + goto advance; + } + } + + if (range >= 0 && startpos == total + && fastmap && pbufp->can_be_null == 0) + return -1; + + val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop); + if (0 <= val) + { + if (val == -2) + return -2; + return startpos; + } + +#ifdef C_ALLOCA + alloca (0); +#endif /* C_ALLOCA */ + + advance: + if (!range) break; + if (range > 0) range--, startpos++; else range++, startpos--; + } + return -1; +} + +#ifndef emacs /* emacs never uses this */ +int +re_match (pbufp, string, size, pos, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, pos; + struct re_registers *regs; +{ + return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size); +} +#endif /* emacs */ + +/* Maximum size of failure stack. Beyond this, overflow is an error. */ + +int re_max_failures = 2000; + +static int memcmp_translate(); +/* Match the pattern described by PBUFP + against data which is the virtual concatenation of STRING1 and STRING2. + SIZE1 and SIZE2 are the sizes of the two data strings. + Start the match at position POS. + Do not consider matching past the position MSTOP. + + If pbufp->fastmap is nonzero, then it had better be up to date. + + The reason that the data to match are specified as two components + which are to be regarded as concatenated + is so this function can be used directly on the contents of an Emacs buffer. + + -1 is returned if there is no match. -2 is returned if there is + an error (such as match stack overflow). Otherwise the value is the length + of the substring which was matched. */ + +int +re_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop) + struct re_pattern_buffer *pbufp; + unsigned char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int mstop; +{ + register unsigned char *p = (unsigned char *) pbufp->buffer; + register unsigned char *pend = p + pbufp->used; + /* End of first string */ + unsigned char *end1; + /* End of second string */ + unsigned char *end2; + /* Pointer just past last char to consider matching */ + unsigned char *end_match_1, *end_match_2; + register unsigned char *d, *dend; + register int mcnt; + unsigned char *translate = (unsigned char *) pbufp->translate; + + /* Failure point stack. Each place that can handle a failure further down the line + pushes a failure point on this stack. It consists of two char *'s. + The first one pushed is where to resume scanning the pattern; + the second pushed is where to resume scanning the strings. + If the latter is zero, the failure point is a "dummy". + If a failure happens and the innermost failure point is dormant, + it discards that failure point and tries the next one. */ + + unsigned char *initial_stack[2 * NFAILURES]; + unsigned char **stackb = initial_stack; + unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES]; + + /* Information on the "contents" of registers. + These are pointers into the input strings; they record + just what was matched (on this attempt) by some part of the pattern. + The start_memory command stores the start of a register's contents + and the stop_memory command stores the end. + + At that point, regstart[regnum] points to the first character in the register, + regend[regnum] points to the first character beyond the end of the register, + regstart_seg1[regnum] is true iff regstart[regnum] points into string1, + and regend_seg1[regnum] is true iff regend[regnum] points into string1. */ + + unsigned char *regstart[RE_NREGS]; + unsigned char *regend[RE_NREGS]; + unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS]; + + /* Set up pointers to ends of strings. + Don't allow the second string to be empty unless both are empty. */ + if (!size2) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings */ + if (mstop <= size1) + { + end_match_1 = string1 + mstop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + mstop - size1; + } + + /* Initialize \) text positions to -1 + to mark ones that no \( or \) has been seen for. */ + + for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++) + regend[mcnt] = (unsigned char *) -1; + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. + `d' is advanced into the following input string whenever necessary, + but this happens before fetching; + therefore, at the beginning of the loop, + `d' can be pointing at the end of a string, + but it cannot equal string2. */ + + if (pos <= size1) + d = string1 + pos, dend = end_match_1; + else + d = string2 + pos - size1, dend = end_match_2; + +/* Write PREFETCH; just before fetching a character with *d. */ +#define PREFETCH \ + while (d == dend) \ + { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \ + d = string2; /* end of string1 => advance to string2. */ \ + dend = end_match_2; } + + /* This loop loops over pattern commands. + It exits by returning from the function if match is complete, + or it drops through if match fails at this starting point in the input data. */ + + while (1) + { + if (p == pend) + /* End of pattern means we have succeeded! */ + { + /* If caller wants register contents data back, convert it to indices */ + if (regs) + { + regs->start[0] = pos; + if (dend == end_match_1) + regs->end[0] = d - string1; + else + regs->end[0] = d - string2 + size1; + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + if (regend[mcnt] == (unsigned char *) -1) + { + regs->start[mcnt] = -1; + regs->end[mcnt] = -1; + continue; + } + if (regstart_seg1[mcnt]) + regs->start[mcnt] = regstart[mcnt] - string1; + else + regs->start[mcnt] = regstart[mcnt] - string2 + size1; + if (regend_seg1[mcnt]) + regs->end[mcnt] = regend[mcnt] - string1; + else + regs->end[mcnt] = regend[mcnt] - string2 + size1; + } + } + if (dend == end_match_1) + return (d - string1 - pos); + else + return d - string2 + size1 - pos; + } + + /* Otherwise match next pattern command */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + + /* \( is represented by a start_memory, \) by a stop_memory. + Both of those commands contain a "register number" argument. + The text matched within the \( and \) is recorded under that number. + Then, \ turns into a `duplicate' command which + is followed by the numeric value of as the register number. */ + + case start_memory: + regstart[*p] = d; + regstart_seg1[*p++] = (dend == end_match_1); + break; + + case stop_memory: + regend[*p] = d; + regend_seg1[*p++] = (dend == end_match_1); + break; + + case duplicate: + { + int regno = *p++; /* Get which register to match against */ + register unsigned char *d2, *dend2; + + d2 = regstart[regno]; + dend2 = ((regstart_seg1[regno] == regend_seg1[regno]) + ? regend[regno] : end_match_1); + while (1) + { + /* Advance to next segment in register contents, if necessary */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */ + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* Advance to next segment in data being matched, if necessary */ + PREFETCH; + + /* mcnt gets # consecutive chars to compare */ + mcnt = dend - d; + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + /* Compare that many; failure if mismatch, else skip them. */ + if (translate ? memcmp_translate (d, d2, mcnt, translate) : memcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + case anychar: + /* fetch a data character */ + PREFETCH; + /* Match anything but a newline. */ + if ((translate ? translate[*d++] : *d++) == '\n') + goto fail; + break; + + case charset: + case charset_not: + { + /* Nonzero for charset_not */ + int not = 0; + register int c; + if (*(p - 1) == (unsigned char) charset_not) + not = 1; + + /* fetch a data character */ + PREFETCH; + + if (translate) + c = translate [*d]; + else + c = *d; + + if (c < *p * BYTEWIDTH + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + d++; + break; + } + + case begline: + if (d == string1 || d[-1] == '\n') + break; + goto fail; + + case endline: + if (d == end2 + || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n')) + break; + goto fail; + + /* "or" constructs ("|") are handled by starting each alternative + with an on_failure_jump that points to the start of the next alternative. + Each alternative except the last ends with a jump to the joining point. + (Actually, each jump except for the last one really jumps + to the following jump, because tensioning the jumps is a hassle.) */ + + /* The start of a stupid repeat has an on_failure_jump that points + past the end of the repeat text. + This makes a failure point so that, on failure to match a repetition, + matching restarts past as many repetitions have been found + with no way to fail and look for another one. */ + + /* A smart repeat is similar but loops back to the on_failure_jump + so that each repetition makes another failure point. */ + + case on_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx; + if (stacke - stackb > re_max_failures * 2) + return -2; + stackx = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *stackp++ = mcnt + p; + *stackp++ = d; + break; + + /* The end of a smart repeat has an maybe_finalize_jump back. + Change it either to a finalize_jump or an ordinary jump. */ + + case maybe_finalize_jump: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + { + register unsigned char *p2 = p; + /* Compare what follows with the begining of the repeat. + If we can establish that there is nothing that they would + both match, we can change to finalize_jump */ + while (p2 != pend + && (*p2 == (unsigned char) stop_memory + || *p2 == (unsigned char) start_memory)) + p2++; + if (p2 == pend) + p[-3] = (unsigned char) finalize_jump; + else if (*p2 == (unsigned char) exactn + || *p2 == (unsigned char) endline) + { + register int c = *p2 == (unsigned char) endline ? '\n' : p2[2]; + register unsigned char *p1 = p + mcnt; + /* p1[0] ... p1[2] are an on_failure_jump. + Examine what follows that */ + if (p1[3] == (unsigned char) exactn && p1[5] != c) + p[-3] = (unsigned char) finalize_jump; + else if (p1[3] == (unsigned char) charset + || p1[3] == (unsigned char) charset_not) + { + int not = p1[3] == (unsigned char) charset_not; + if (c < p1[4] * BYTEWIDTH + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + /* not is 1 if c would match */ + /* That means it is not safe to finalize */ + if (!not) + p[-3] = (unsigned char) finalize_jump; + } + } + } + p -= 2; + if (p[-1] != (unsigned char) finalize_jump) + { + p[-1] = (unsigned char) jump; + goto nofinalize; + } + + /* The end of a stupid repeat has a finalize-jump + back to the start, where another failure point will be made + which will point after all the repetitions found so far. */ + + case finalize_jump: + stackp -= 2; + + case jump: + nofinalize: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += mcnt + 1; /* The 1 compensates for missing ++ above */ + break; + + case dummy_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx + = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + *stackp++ = 0; + *stackp++ = 0; + goto nofinalize; + + case wordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + break; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + break; + goto fail; + + case notwordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + goto fail; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + goto fail; + break; + + case wordbeg: + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */ + goto fail; + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + break; + goto fail; + + case wordend: + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + goto fail; + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */ + break; + goto fail; + +#ifdef emacs + case before_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + <= point) + goto fail; + break; + + case at_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + == point) + goto fail; + break; + + case after_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + >= point) + goto fail; + break; + + case wordchar: + mcnt = (int) Sword; + goto matchsyntax; + + case syntaxspec: + mcnt = *p++; + matchsyntax: + PREFETCH; + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; + break; + + case notwordchar: + mcnt = (int) Sword; + goto matchnotsyntax; + + case notsyntaxspec: + mcnt = *p++; + matchnotsyntax: + PREFETCH; + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; + break; +#else + case wordchar: + PREFETCH; + if (SYNTAX (*d++) == 0) goto fail; + break; + + case notwordchar: + PREFETCH; + if (SYNTAX (*d++) != 0) goto fail; + break; +#endif /* not emacs */ + + case begbuf: + if (d == string1) /* Note, d cannot equal string2 */ + break; /* unless string1 == string2. */ + goto fail; + + case endbuf: + if (d == end2 || (d == end1 && size2 == 0)) + break; + goto fail; + + case exactn: + /* Match the next few pattern characters exactly. + mcnt is how many characters to match. */ + mcnt = *p++; + if (translate) + { + do + { + PREFETCH; + if (translate[*d++] != *p++) goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH; + if (*d++ != *p++) goto fail; + } + while (--mcnt); + } + break; + } + continue; /* Successfully matched one pattern command; keep matching */ + + /* Jump here if any matching operation fails. */ + fail: + if (stackp != stackb) + /* A restart point is known. Restart there and pop it. */ + { + if (!stackp[-2]) + { /* If innermost failure point is dormant, flush it and keep looking */ + stackp -= 2; + goto fail; + } + d = *--stackp; + p = *--stackp; + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else break; /* Matching at this starting point really fails! */ + } + return -1; /* Failure to match */ +} + +static int +memcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + unsigned char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate [*p1++] != translate [*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points compatible with bsd4.2 regex library */ + +#ifndef emacs + +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + char *s; +{ + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + if (!(re_comp_buf.buffer = (char *) malloc (200))) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH))) + return "Memory exhausted"; + } + return re_compile_pattern (s, strlen (s), &re_comp_buf); +} + +int +re_exec (s) + char *s; +{ + int len = strlen (s); + return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0); +} + +#endif /* emacs */ + +#ifdef test + +#include + +/* Indexed by a character, gives the upper case equivalent of the character */ + +static char upcase[0400] = + { 000, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, + 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 + }; + +main (argc, argv) + int argc; + char **argv; +{ + char pat[80]; + struct re_pattern_buffer buf; + int i; + char c; + char fastmap[(1 << BYTEWIDTH)]; + + /* Allow a command argument to specify the style of syntax. */ + if (argc > 1) + obscure_syntax = atoi (argv[1]); + + buf.allocated = 40; + buf.buffer = (char *) malloc (buf.allocated); + buf.fastmap = fastmap; + buf.translate = upcase; + + while (1) + { + gets (pat); + + if (*pat) + { + re_compile_pattern (pat, strlen(pat), &buf); + + for (i = 0; i < buf.used; i++) + printchar (buf.buffer[i]); + + putchar ('\n'); + + printf ("%d allocated, %d used.\n", buf.allocated, buf.used); + + re_compile_fastmap (&buf); + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (fastmap[i]) printchar (i); + putchar ('\n'); + } + + gets (pat); /* Now read the string to match against */ + + i = re_match (&buf, pat, strlen (pat), 0, 0); + printf ("Match value %d.\n", i); + } +} + +#ifdef NOTDEF +print_buf (bufp) + struct re_pattern_buffer *bufp; +{ + int i; + + printf ("buf is :\n----------------\n"); + for (i = 0; i < bufp->used; i++) + printchar (bufp->buffer[i]); + + printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used); + + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->fastmap[i]) + printchar (i); + printf ("\nAllowed by translate: "); + if (bufp->translate) + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->translate[i]) + printchar (i); + printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't"); + printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not"); +} +#endif + +printchar (c) + char c; +{ + if (c < 041 || c >= 0177) + { + putchar ('\\'); + putchar (((c >> 6) & 3) + '0'); + putchar (((c >> 3) & 7) + '0'); + putchar ((c & 7) + '0'); + } + else + putchar (c); +} + +error (string) + char *string; +{ + puts (string); + exit (1); +} + +#endif /* test */ diff --git a/gnu/usr.bin/gdb/gdb/regex.h b/gnu/usr.bin/gdb/gdb/regex.h new file mode 100644 index 00000000000..6348c3eb6e4 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/regex.h @@ -0,0 +1,179 @@ +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985, 1989 Free Software Foundation, Inc. + +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. */ + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +/* These bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* 1 means plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + 0 means backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1 + +/* 1 means plain | serves as the "or"-operator, and \| is a literal. + 0 means \| serves as the "or"-operator, and | is a literal. */ +#define RE_NO_BK_VBAR 2 + +/* 0 means plain + or ? serves as an operator, and \+, \? are literals. + 1 means \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM 4 + +/* 1 means | binds tighter than ^ or $. + 0 means the contrary. */ +#define RE_TIGHT_VBAR 8 + +/* 1 means treat \n as an _OR operator + 0 means treat it as a normal character */ +#define RE_NEWLINE_OR 16 + +/* 0 means that a special characters (such as *, ^, and $) always have + their special meaning regardless of the surrounding context. + 1 means that special characters may act as normal characters in some + contexts. Specifically, this applies to: + ^ - only special at the beginning, or after ( or | + $ - only special at the end, or before ) or | + *, +, ? - only special when not after the beginning, (, or | */ +#define RE_CONTEXT_INDEP_OPS 32 + +/* Now define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + int allocated; /* Size of space that buffer points to */ + int used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip quickly over totally implausible characters */ + char *translate; /* Translate table to apply to all characters before comparing. + Or zero for no translation. + The translation is applied to a pattern when it is compiled + and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + +/* Structure to store "register" contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + start[i] and end[i] record the string matched by \( ... \) grouping i, + for i from 1 to RE_NREGS - 1. + start[0] and end[0] record the entire string matched. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + +/* These are the command codes that appear in compiled regular expressions, one per byte. + Some command codes are followed by argument bytes. + A command code can specify any interpretation whatever for its arguments. + Zero-bytes may appear in the compiled regular expression. */ + +enum regexpcode + { + unused, + exactn, /* followed by one byte giving n, and then by n literal bytes */ + begline, /* fails unless at beginning of line */ + endline, /* fails unless at end of line */ + jump, /* followed by two bytes giving relative address to jump to */ + on_failure_jump, /* followed by two bytes giving relative address of place + to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* jump, and push a dummy failure point. + This failure point will be thrown away + if an attempt is made to use it for a failure. + A + construct makes this before the first repeat. */ + anychar, /* matches any one character */ + charset, /* matches any one char belonging to specified set. + First following byte is # bitmap bytes. + Then come bytes for a bit-map saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set */ + charset_not, /* similar but match any character that is NOT one of those specified */ + start_memory, /* starts remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + stop_memory, /* stops remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + duplicate, /* match a duplicate of something remembered. + Followed by one byte containing the index of the memory register. */ + before_dot, /* Succeeds if before dot */ + at_dot, /* Succeeds if at dot */ + after_dot, /* Succeeds if after dot */ + begbuf, /* Succeeds if at beginning of buffer */ + endbuf, /* Succeeds if at end of buffer */ + wordchar, /* Matches any word-constituent character */ + notwordchar, /* Matches any char that is not a word-constituent */ + wordbeg, /* Succeeds if at word beginning */ + wordend, /* Succeeds if at word end */ + wordbound, /* Succeeds if at a word boundary */ + notwordbound, /* Succeeds if not at a word boundary */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, Sword or such like */ + notsyntaxspec /* Matches any character whose syntax differs from the specified. */ + }; + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); + +/* 4.2 bsd compatibility (yuck) */ +extern char *re_comp (); +extern int re_exec (); + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif diff --git a/gnu/usr.bin/gdb/gdb/remote-utils.c b/gnu/usr.bin/gdb/gdb/remote-utils.c new file mode 100644 index 00000000000..f4f25e4c490 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/remote-utils.c @@ -0,0 +1,645 @@ +/* Generic support for remote debugging interfaces. + + Copyright 1993 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. */ + +/* This file actually contains two distinct logical "packages". They + are packaged together in this one file because they are typically + used together. + + The first package is an addition to the serial package. The + addition provides reading and writing with debugging output and + timeouts based on user settable variables. These routines are + intended to support serial port based remote backends. These + functions are prefixed with sr_. + + The second package is a collection of more or less generic + functions for use by remote backends. They support user settable + variables for debugging, retries, and the like. + + Todo: + + * a pass through mode a la kermit or telnet. + * autobaud. + * ask remote to change his baud rate. + * put generic load here. + + */ + +#include + +#include "defs.h" +#include "gdbcmd.h" +#include "target.h" +#include "serial.h" +#include "gdbcore.h" /* for exec_bfd */ +#include "inferior.h" /* for generic_mourn_inferior */ +#include "remote-utils.h" + +struct _sr_settings sr_settings = { + 4, /* timeout: + remote-hms.c had 2 + remote-bug.c had "with a timeout of 2, we time out waiting for + the prompt after an s-record dump." + + remote.c had (2): This was 5 seconds, which is a long time to + sit and wait. Unless this is going though some terminal server + or multiplexer or other form of hairy serial connection, I + would think 2 seconds would be plenty. +*/ + + 10, /* retries */ + NULL, /* device */ + NULL, /* descriptor */ +}; + +struct gr_settings *gr_settings = NULL; + +static void +usage(proto, junk) + char *proto; + char *junk; +{ + if (junk != NULL) + fprintf(stderr, "Unrecognized arguments: `%s'.\n", junk); + + /* FIXME-now: service@host? */ + + error("Usage: target %s >>\n\ +or target %s \n", proto, proto); + + return; +} + +#define CHECKDONE(p, q) \ +{ \ + if (q == p) \ + { \ + if (*p == '\0') \ + return; \ + else \ + usage(proto, p); \ + } \ +} + +void +sr_scan_args(proto, args) + char *proto; + char *args; +{ + int n; + char *p, *q; + + extern int strtol(); + + /* if no args, then nothing to do. */ + if (args == NULL || *args == '\0') + return; + + /* scan off white space. */ + for (p = args; isspace(*p); ++p) ;; + + /* find end of device name. */ + for (q = p; *q != '\0' && !isspace(*q); ++q) ;; + + /* check for missing or empty device name. */ + CHECKDONE(p, q); + sr_set_device(savestring(p, q - p)); + + /* look for baud rate. */ + n = strtol(q, &p, 10); + + /* check for missing or empty baud rate. */ + CHECKDONE(p, q); + sr_set_baud_rate(n); + + /* look for debug value. */ + n = strtol(p, &q, 10); + + /* check for missing or empty debug value. */ + CHECKDONE(p, q); + sr_set_debug(n); + + /* scan off remaining white space. */ + for (p = q; isspace(*p); ++p) ;; + + /* if not end of string, then there's unrecognized junk. */ + if (*p != '\0') + usage(proto, p); + + return; +} + +void +gr_generic_checkin() +{ + sr_write_cr(""); + gr_expect_prompt(); +} + +void +gr_open(args, from_tty, gr) + char *args; + int from_tty; + struct gr_settings *gr; +{ + target_preopen(from_tty); + sr_scan_args(gr->ops->to_shortname, args); + unpush_target(gr->ops); + + gr_settings = gr; + + gr_set_dcache(dcache_init(gr->readfunc, gr->writefunc)); + + if (sr_get_desc() != NULL) + gr_close (0); + + sr_set_desc(SERIAL_OPEN (sr_get_device())); + if (!sr_get_desc()) + perror_with_name((char *) sr_get_device()); + + if (SERIAL_SETBAUDRATE(sr_get_desc(), sr_get_baud_rate()) != 0) + { + SERIAL_CLOSE(sr_get_desc()); + perror_with_name(sr_get_device()); + } + + SERIAL_RAW (sr_get_desc()); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (sr_get_desc ()); + + /* default retries */ + if (sr_get_retries() == 0) + sr_set_retries(1); + + /* default clear breakpoint function */ + if (gr_settings->clear_all_breakpoints == NULL) + gr_settings->clear_all_breakpoints = remove_breakpoints; + + if (from_tty) + printf_filtered ("Remote debugging using `%s' at baud rate of %d\n", + sr_get_device(), sr_get_baud_rate()); + + push_target(gr->ops); + gr_checkin(); + gr_clear_all_breakpoints (); + return; +} + +/* Read a character from the remote system masking it down to 7 bits + and doing all the fancy timeout stuff. */ + +int +sr_readchar () +{ + int buf; + + buf = SERIAL_READCHAR (sr_get_desc(), sr_get_timeout()); + + if (buf == SERIAL_TIMEOUT) + error ("Timeout reading from remote system."); + + if (sr_get_debug() > 0) + printf ("%c", buf); + + return buf & 0x7f; +} + +int +sr_pollchar() +{ + int buf; + + buf = SERIAL_READCHAR (sr_get_desc(), 0); + if (buf == SERIAL_TIMEOUT) + buf = 0; + if (sr_get_debug() > 0) + if (buf) + printf ("%c", buf); + else + printf (""); + + return buf & 0x7f; +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +void +sr_expect (string) + char *string; +{ + char *p = string; + + immediate_quit = 1; + while (1) + { + if (sr_readchar () == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + p = string; + } +} + +void +sr_write (a, l) + char *a; + int l; +{ + int i; + + if (SERIAL_WRITE (sr_get_desc(), a, l) != 0) + perror_with_name ("sr_write: Error writing to remote"); + + if (sr_get_debug() > 0) + for (i = 0; i < l; i++) + printf ("%c", a[i]); + + return; +} + +void +sr_write_cr (s) + char *s; +{ + sr_write (s, strlen (s)); + sr_write ("\r", 1); + return; +} + +int +sr_timed_read (buf, n) + char *buf; + int n; +{ + int i; + char c; + + i = 0; + while (i < n) + { + c = sr_readchar (); + + if (c == 0) + return i; + buf[i] = c; + i++; + + } + return i; +} + +/* Get a hex digit from the remote system & return its value. If + ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ + +int +sr_get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + + while (1) + { + ch = sr_readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch != ' ' || !ignore_space) + { + gr_expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from the remote and put it in *BYT. Accept any number + leading spaces. */ +void +sr_get_hex_byte (byt) + char *byt; +{ + int val; + + val = sr_get_hex_digit (1) << 4; + val |= sr_get_hex_digit (0); + *byt = val; +} + +/* Read a 32-bit hex word from the remote, preceded by a space */ +long +sr_get_hex_word () +{ + long val; + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + sr_get_hex_digit (j == 0); + return val; +} + +/* Put a command string, in args, out to the remote. The remote is assumed to + be in raw mode, all writing/reading done through desc. + Ouput from the remote is placed on the users terminal until the + prompt from the remote is seen. + FIXME: Can't handle commands that take input. */ + +void +sr_com (args, fromtty) + char *args; + int fromtty; +{ + sr_check_open (); + + if (!args) + return; + + /* Clear all input so only command relative output is displayed */ + + sr_write_cr (args); + sr_write ("\030", 1); + gr_expect_prompt (); +} + +void +gr_close(quitting) + int quitting; +{ + gr_clear_all_breakpoints(); + + if (sr_is_open()) + { + SERIAL_CLOSE (sr_get_desc()); + sr_set_desc(NULL); + } + + return; +} + +/* gr_detach() + takes a program previously attached to and detaches it. + We better not have left any breakpoints + in the program or it'll die when it hits one. + Close the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ + +void +gr_detach(args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + if (sr_is_open()) + gr_clear_all_breakpoints (); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); + + return; +} + +void +gr_files_info (ops) + struct target_ops *ops; +{ + char *file = "nothing"; + + if (exec_bfd) + file = bfd_get_filename (exec_bfd); + + if (exec_bfd) + { +#ifdef __GO32__ + printf_filtered ("\tAttached to DOS asynctsr\n"); +#else + printf_filtered ("\tAttached to %s at %d baud\n", + sr_get_device(), sr_get_baud_rate()); +#endif + } + + printf_filtered ("\tand running program %s\n", file); + printf_filtered ("\tusing the %s protocol.\n", ops->to_shortname); +} + +void +gr_mourn () +{ + gr_clear_all_breakpoints (); + unpush_target (gr_get_ops()); + generic_mourn_inferior (); +} + +void +gr_kill () +{ + return; +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +void +gr_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error ("Can't pass arguments to remote process."); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + sr_check_open (); + + gr_kill (); + gr_clear_all_breakpoints (); + + init_wait_for_inferior (); + gr_checkin(); + + insert_breakpoints (); /* Needed to get correct instruction in cache */ + proceed (entry_pt, -1, 0); +} + +/* Given a null terminated list of strings LIST, read the input until we find one of + them. Return the index of the string found or -1 on error. '?' means match + any single character. Note that with the algorithm we use, the initial + character of the string cannot recur in the string, or we will not find some + cases of the string in the input. If PASSTHROUGH is non-zero, then + pass non-matching data on. */ + +int +gr_multi_scan (list, passthrough) + char *list[]; + int passthrough; +{ + char *swallowed = NULL; /* holding area */ + char *swallowed_p = swallowed; /* Current position in swallowed. */ + int ch; + int ch_handled; + int i; + int string_count; + int max_length; + char **plist; + + /* Look through the strings. Count them. Find the largest one so we can + allocate a holding area. */ + + for (max_length = string_count = i = 0; + list[i] != NULL; + ++i, ++string_count) + { + int length = strlen(list[i]); + + if (length > max_length) + max_length = length; + } + + /* if we have no strings, then something is wrong. */ + if (string_count == 0) + return(-1); + + /* otherwise, we will need a holding area big enough to hold almost two + copies of our largest string. */ + swallowed_p = swallowed = alloca(max_length << 1); + + /* and a list of pointers to current scan points. */ + plist = (char **) alloca (string_count * sizeof(*plist)); + + /* and initialize */ + for (i = 0; i < string_count; ++i) + plist[i] = list[i]; + + for (ch = sr_readchar(); /* loop forever */ ; ch = sr_readchar()) + { + QUIT; /* Let user quit and leave process running */ + ch_handled = 0; + + for (i = 0; i < string_count; ++i) + { + if (ch == *plist[i] || *plist[i] == '?') + { + ++plist[i]; + if (*plist[i] == '\0') + return(i); + + if (!ch_handled) + *swallowed_p++ = ch; + + ch_handled = 1; + } + else + plist[i] = list[i]; + } + + if (!ch_handled) + { + char *p; + + /* Print out any characters which have been swallowed. */ + if (passthrough) + { + for (p = swallowed; p < swallowed_p; ++p) + putc (*p, stdout); + + putc (ch, stdout); + } + + swallowed_p = swallowed; + } + } +#if 0 + /* Never reached. */ + return(-1); +#endif +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +gr_prepare_to_store () +{ + /* Do nothing, since we assume we can store individual regs */ +} + +/* Read a word from remote address ADDR and return it. + * This goes through the data cache. + */ +int +gr_fetch_word (addr) + CORE_ADDR addr; +{ + return dcache_fetch (gr_get_dcache(), addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +void +gr_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (gr_get_dcache(), addr, word); +} + +void +_initialize_sr_support () +{ +/* FIXME-now: if target is open when baud changes... */ + add_show_from_set (add_set_cmd ("remotebaud", no_class, + var_zinteger, (char *)&baud_rate, + "Set baud rate for remote serial I/O.\n\ +This value is used to set the speed of the serial port when debugging\n\ +using remote targets.", &setlist), + &showlist); + +/* FIXME-now: if target is open... */ + add_show_from_set (add_set_cmd ("remotedevice", no_class, + var_filename, (char *)&sr_settings.device, + "Set device for remote serial I/O.\n\ +This device is used as the serial port when debugging using remote\n\ +targets.", &setlist), + &showlist); + + add_com ("remote ", class_obscure, sr_com, + "Send a command to the remote monitor."); + +} diff --git a/gnu/usr.bin/gdb/gdb/remote-utils.h b/gnu/usr.bin/gdb/gdb/remote-utils.h new file mode 100644 index 00000000000..59f4d3b3706 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/remote-utils.h @@ -0,0 +1,149 @@ +/* Generic support for remote debugging interfaces. + + Copyright 1993 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. */ + +#ifndef REMOTE_UTILS_H +#define REMOTE_UTILS_H + +#include "serial.h" +#include "target.h" +#include "dcache.h" + +/* Stuff that should be shared (and handled consistently) among the various + remote targets. */ + +struct _sr_settings { + unsigned int timeout; + + int retries; + + char *device; + serial_t desc; + +}; + +extern struct _sr_settings sr_settings; +extern int remote_debug; +extern int baud_rate; + +/* get and set debug value. */ +#define sr_get_debug() (remote_debug) +#define sr_set_debug(newval) (remote_debug = (newval)) + +/* get and set baud rate. */ +#define sr_get_baud_rate() (baud_rate) +#define sr_set_baud_rate(newval) (baud_rate = (newval)) + +/* get and set timeout. */ +#define sr_get_timeout() (sr_settings.timeout) +#define sr_set_timeout(newval) (sr_settings.timeout = (newval)) + +/* get and set device. */ +#define sr_get_device() (sr_settings.device) +#define sr_set_device(newval) \ +{ \ + if (sr_settings.device) free(sr_settings.device); \ + sr_settings.device = (newval); \ +} + +/* get and set descriptor value. */ +#define sr_get_desc() (sr_settings.desc) +#define sr_set_desc(newval) (sr_settings.desc = (newval)) + +/* get and set retries. */ +#define sr_get_retries() (sr_settings.retries) +#define sr_set_retries(newval) (sr_settings.retries = (newval)) + +#define sr_is_open() (sr_settings.desc != NULL) + +#define sr_check_open() { if (!sr_is_open()) \ + error ("Remote device not open"); } + +struct gr_settings { + /* This is our data cache. */ + DCACHE *dcache; + char *prompt; + struct target_ops *ops; + int (*clear_all_breakpoints)PARAMS((void)); + memxferfunc readfunc; + memxferfunc writefunc; + void (*checkin)PARAMS((void)); +}; + +extern struct gr_settings *gr_settings; + +/* get and set dcache. */ +#define gr_get_dcache() (gr_settings->dcache) +#define gr_set_dcache(newval) (gr_settings->dcache = (newval)) + +/* get and set prompt. */ +#define gr_get_prompt() (gr_settings->prompt) +#define gr_set_prompt(newval) (gr_settings->prompt = (newval)) + +/* get and set ops. */ +#define gr_get_ops() (gr_settings->ops) +#define gr_set_ops(newval) (gr_settings->ops = (newval)) + +#define gr_clear_all_breakpoints() ((gr_settings->clear_all_breakpoints)()) +#define gr_checkin() ((gr_settings->checkin)()) + +/* Keep discarding input until we see the prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an gr_expect_prompt(). Exception: resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a bug_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ + +#define gr_expect_prompt() sr_expect(gr_get_prompt()) + +int gr_fetch_word PARAMS((CORE_ADDR addr)); +int gr_multi_scan PARAMS((char *list[], int passthrough)); +int sr_get_hex_digit PARAMS((int ignore_space)); +int sr_pollchar PARAMS((void)); +int sr_readchar PARAMS((void)); +int sr_timed_read PARAMS((char *buf, int n)); +long sr_get_hex_word PARAMS((void)); +void gr_close PARAMS((int quitting)); +void gr_create_inferior PARAMS((char *execfile, char *args, char **env)); +void gr_detach PARAMS((char *args, int from_tty)); +void gr_files_info PARAMS((struct target_ops *ops)); +void gr_generic_checkin PARAMS((void)); +void gr_kill PARAMS((void)); +void gr_mourn PARAMS((void)); +void gr_prepare_to_store PARAMS((void)); +void gr_store_word PARAMS((CORE_ADDR addr, int word)); +void sr_expect PARAMS((char *string)); +void sr_get_hex_byte PARAMS((char *byt)); +void sr_scan_args PARAMS((char *proto, char *args)); +void sr_write PARAMS((char *a, int l)); +void sr_write_cr PARAMS((char *s)); + +void gr_open PARAMS((char *args, int from_tty, + struct gr_settings *gr_settings)); + + +#endif /* REMOTE_UTILS_H */ diff --git a/gnu/usr.bin/gdb/gdb/remote.c b/gnu/usr.bin/gdb/gdb/remote.c new file mode 100644 index 00000000000..266d5f389de --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/remote.c @@ -0,0 +1,1272 @@ +/* Remote target communications for serial-line targets in custom GDB protocol + Copyright 1988, 1991, 1992, 1993 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. */ + +/* Remote communication protocol. + + A debug packet whose contents are + is encapsulated for transmission in the form: + + $ # CSUM1 CSUM2 + + must be ASCII alphanumeric and cannot include characters + '$' or '#' + + CSUM1 and CSUM2 are ascii hex representation of an 8-bit + checksum of , the most significant nibble is sent first. + the hex digits 0-9,a-f are used. + + Receiver responds with: + + + - if CSUM is correct and ready for next packet + - - if CSUM is incorrect + + is as follows: + All values are encoded in ascii hex digits. + + Request Packet + + read registers g + reply XX....X Each byte of register data + is described by two hex digits. + Registers are in the internal order + for GDB, and the bytes in a register + are in the same order the machine uses. + or ENN for an error. + + write regs GXX..XX Each byte of register data + is described by two hex digits. + reply OK for success + ENN for an error + + read mem mAA..AA,LLLL AA..AA is address, LLLL is length. + reply XX..XX XX..XX is mem contents + Can be fewer bytes than requested + if able to read only part of the data. + or ENN NN is errno + + write mem MAA..AA,LLLL:XX..XX + AA..AA is address, + LLLL is number of bytes, + XX..XX is data + reply OK for success + ENN for an error (this includes the case + where only part of the data was + written). + + cont cAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + step sAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + last signal ? Reply the current reason for stopping. + This is the same reply as is generated + for step or cont : SAA where AA is the + signal number. + + There is no immediate reply to step or cont. + The reply comes when the machine stops. + It is SAA AA is the "signal number" + + or... TAAn...:r...;n:r...;n...:r...; + AA = signal number + n... = register number + r... = register contents + or... WAA The process extited, and AA is + the exit status. This is only + applicable for certains sorts of + targets. + or... NAATT;DD;BB Relocate the object file. + AA = signal number + TT = text address + DD = data address + BB = bss address + This is used by the NLM stub, + which is why it only has three + addresses rather than one per + section: the NLM stub always + sees only three sections, even + though gdb may see more. + + kill request k + + toggle debug d toggle debug flag (see 386 & 68k stubs) + reset r reset -- see sparc stub. + reserved On other requests, the stub should + ignore the request and send an empty + response ($#). This way + we can extend the protocol and GDB + can tell whether the stub it is + talking to uses the old or the new. +*/ + +#include "defs.h" +#include +#include +#include "frame.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "target.h" +#include "wait.h" +#include "terminal.h" +#include "gdbcmd.h" +#include "objfiles.h" +#include "gdb-stabs.h" + +#include "dcache.h" + +#if !defined(DONT_USE_REMOTE) +#ifdef USG +#include +#endif + +#include +#include "serial.h" + +/* Prototypes for local functions */ + +static int +remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len)); + +static int +remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len)); + +static void +remote_files_info PARAMS ((struct target_ops *ignore)); + +static int +remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len, + int should_write, struct target_ops *target)); + +static void +remote_prepare_to_store PARAMS ((void)); + +static void +remote_fetch_registers PARAMS ((int regno)); + +static void +remote_resume PARAMS ((int pid, int step, int siggnal)); + +static int +remote_start_remote PARAMS ((char *dummy)); + +static void +remote_open PARAMS ((char *name, int from_tty)); + +static void +remote_close PARAMS ((int quitting)); + +static void +remote_store_registers PARAMS ((int regno)); + +static void +getpkt PARAMS ((char *buf, int forever)); + +static void +putpkt PARAMS ((char *buf)); + +static void +remote_send PARAMS ((char *buf)); + +static int +readchar PARAMS ((void)); + +static int +remote_wait PARAMS ((int pid, WAITTYPE *status)); + +static int +tohex PARAMS ((int nib)); + +static int +fromhex PARAMS ((int a)); + +static void +remote_detach PARAMS ((char *args, int from_tty)); + +static void +remote_interrupt PARAMS ((int signo)); + +static void +remote_interrupt_twice PARAMS ((int signo)); + +static void +interrupt_query PARAMS ((void)); + +extern struct target_ops remote_ops; /* Forward decl */ + +extern int baud_rate; + +extern int remote_debug; + +/* This was 5 seconds, which is a long time to sit and wait. + Unless this is going though some terminal server or multiplexer or + other form of hairy serial connection, I would think 2 seconds would + be plenty. */ +static int timeout = 2; + +#if 0 +int icache; +#endif + +/* Descriptor for I/O to remote machine. Initialize it to NULL so that + remote_open knows that we don't have a file open when the program + starts. */ +serial_t remote_desc = NULL; + +#define PBUFSIZ 1024 + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet (the headers account for the 32). */ +#define MAXBUFBYTES ((PBUFSIZ-32)/2) + +/* Round up PBUFSIZ to hold all the registers, at least. */ +#if REGISTER_BYTES > MAXBUFBYTES +#undef PBUFSIZ +#define PBUFSIZ (REGISTER_BYTES * 2 + 32) +#endif + +/* Clean up connection to a remote debugger. */ + +/* ARGSUSED */ +static void +remote_close (quitting) + int quitting; +{ + if (remote_desc) + SERIAL_CLOSE (remote_desc); + remote_desc = NULL; +} + +/* Stub for catch_errors. */ + +static int +remote_start_remote (dummy) + char *dummy; +{ + immediate_quit = 1; /* Allow user to interrupt it */ + + /* Ack any packet which the remote side has already sent. */ + /* I'm not sure this \r is needed; we don't use it any other time we + send an ack. */ + SERIAL_WRITE (remote_desc, "+\r", 2); + putpkt ("?"); /* initiate a query from remote machine */ + immediate_quit = 0; + + start_remote (); /* Initialize gdb process mechanisms */ + return 1; +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static DCACHE *remote_dcache; + +static void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + if (name == 0) + error ( +"To open a remote debug connection, you need to specify what serial\n\ +device is attached to the remote system (e.g. /dev/ttya)."); + + target_preopen (from_tty); + + unpush_target (&remote_ops); + + remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes); + + remote_desc = SERIAL_OPEN (name); + if (!remote_desc) + perror_with_name (name); + + if (SERIAL_SETBAUDRATE (remote_desc, baud_rate)) + { + SERIAL_CLOSE (remote_desc); + perror_with_name (name); + } + + SERIAL_RAW (remote_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (remote_desc); + + if (from_tty) + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } + push_target (&remote_ops); /* Switch to using remote target now */ + + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (remote_start_remote, (char *)0, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) + pop_target(); +} + +/* remote_detach() + takes a program previously attached to and detaches it. + We better not have left any breakpoints + in the program or it'll die when it hits one. + Close the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ + +static void +remote_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit"); + return -1; +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* Tell the remote machine to resume. */ + +static void +remote_resume (pid, step, siggnal) + int pid, step, siggnal; +{ + char buf[PBUFSIZ]; + + if (siggnal) + { + char *name; + target_terminal_ours_for_output (); + printf_filtered ("Can't send signals to a remote system. "); + name = strsigno (siggnal); + if (name) + printf_filtered (name); + else + printf_filtered ("Signal %d", siggnal); + printf_filtered (" not sent.\n"); + target_terminal_inferior (); + } + + dcache_flush (remote_dcache); + + strcpy (buf, step ? "s": "c"); + + putpkt (buf); +} + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +remote_interrupt (signo) + int signo; +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, remote_interrupt_twice); + + if (remote_debug) + printf ("remote_interrupt called\n"); + + SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */ +} + +static void (*ofunc)(); + +/* The user typed ^C twice. */ +static void +remote_interrupt_twice (signo) + int signo; +{ + signal (signo, ofunc); + + interrupt_query (); + + signal (signo, remote_interrupt); +} + +/* Ask the user what to do when an interrupt is received. */ + +static void +interrupt_query () +{ + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + return_to_top_level (RETURN_QUIT); + } + + target_terminal_inferior (); +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. + Returns "pid" (though it's not clear what, if anything, that + means in the case of this target). */ + +static int +remote_wait (pid, status) + int pid; + WAITTYPE *status; +{ + unsigned char buf[PBUFSIZ]; + + WSETEXIT ((*status), 0); + + while (1) + { + unsigned char *p; + + ofunc = (void (*)()) signal (SIGINT, remote_interrupt); + getpkt ((char *) buf, 1); + signal (SIGINT, ofunc); + + if (buf[0] == 'E') + warning ("Remote failure reply: %s", buf); + else if (buf[0] == 'T') + { + int i; + long regno; + char regs[MAX_REGISTER_RAW_SIZE]; + + /* Expedited reply, containing Signal, {regno, reg} repeat */ + /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where + ss = signal number + n... = register number + r... = register contents + */ + + p = &buf[3]; /* after Txx */ + + while (*p) + { + unsigned char *p1; + + regno = strtol (p, &p1, 16); /* Read the register number */ + + if (p1 == p) + warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n", + p1, buf); + + p = p1; + + if (*p++ != ':') + warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n", + p, buf); + + if (regno >= NUM_REGS) + warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n", + regno, p, buf); + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i++) + { + if (p[0] == 0 || p[1] == 0) + warning ("Remote reply is too short: %s", buf); + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + + if (*p++ != ';') + warning ("Remote register badly formatted: %s", buf); + + supply_register (regno, regs); + } + break; + } + else if (buf[0] == 'N') + { + unsigned char *p1; + bfd_vma text_addr, data_addr, bss_addr; + + /* Relocate object file. Format is NAATT;DD;BB where AA is + the signal number, TT is the new text address, DD is the + new data address, and BB is the new bss address. This is + used by the NLM stub; gdb may see more sections. */ + p = &buf[3]; + text_addr = strtoul (p, &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + data_addr = strtoul (p, &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + bss_addr = strtoul (p, &p1, 16); + if (p1 == p) + warning ("Malformed relocation packet: Packet '%s'", buf); + + if (symfile_objfile != NULL + && (ANOFFSET (symfile_objfile->section_offsets, + SECT_OFF_TEXT) != text_addr + || ANOFFSET (symfile_objfile->section_offsets, + SECT_OFF_DATA) != data_addr + || ANOFFSET (symfile_objfile->section_offsets, + SECT_OFF_BSS) != bss_addr)) + { + struct section_offsets *offs; + + /* FIXME: This code assumes gdb-stabs.h is being used; + it's broken for xcoff, dwarf, sdb-coff, etc. But + there is no simple canonical representation for this + stuff. (Just what does "text" as seen by the stub + mean, anyway?). */ + + /* FIXME: Why don't the various symfile_offsets routines + in the sym_fns vectors set this? + (no good reason -kingdon). */ + if (symfile_objfile->num_sections == 0) + symfile_objfile->num_sections = SECT_OFF_MAX; + + offs = ((struct section_offsets *) + alloca (sizeof (struct section_offsets) + + (symfile_objfile->num_sections + * sizeof (offs->offsets)))); + memcpy (offs, symfile_objfile->section_offsets, + (sizeof (struct section_offsets) + + (symfile_objfile->num_sections + * sizeof (offs->offsets)))); + ANOFFSET (offs, SECT_OFF_TEXT) = text_addr; + ANOFFSET (offs, SECT_OFF_DATA) = data_addr; + ANOFFSET (offs, SECT_OFF_BSS) = bss_addr; + + objfile_relocate (symfile_objfile, offs); + { + struct obj_section *s; + bfd *abfd; + + abfd = symfile_objfile->obfd; + + for (s = symfile_objfile->sections; + s < symfile_objfile->sections_end; ++s) + { + flagword flags; + + flags = bfd_get_section_flags (abfd, s->sec_ptr); + + if (flags & SEC_CODE) + { + s->addr += text_addr; + s->endaddr += text_addr; + } + else if (flags & (SEC_DATA | SEC_LOAD)) + { + s->addr += data_addr; + s->endaddr += data_addr; + } + else if (flags & SEC_ALLOC) + { + s->addr += bss_addr; + s->endaddr += bss_addr; + } + } + } + } + break; + } + else if (buf[0] == 'W') + { + /* The remote process exited. */ + WSETEXIT (*status, (fromhex (buf[1]) << 4) + fromhex (buf[2])); + return 0; + } + else if (buf[0] == 'S') + break; + else + warning ("Invalid remote reply: %s", buf); + } + + WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2])))); + + return 0; +} + +/* Number of bytes of registers this stub implements. */ +static int register_bytes_found; + +/* Read the remote registers into the block REGS. */ +/* Currently we just read all the registers, so we don't use regno. */ +/* ARGSUSED */ +static void +remote_fetch_registers (regno) + int regno; +{ + char buf[PBUFSIZ]; + int i; + char *p; + char regs[REGISTER_BYTES]; + + sprintf (buf, "g"); + remote_send (buf); + + /* Unimplemented registers read as all bits zero. */ + memset (regs, 0, REGISTER_BYTES); + + /* We can get out of synch in various cases. If the first character + in the buffer is not a hex character, assume that has happened + and try to fetch another packet to read. */ + while ((buf[0] < '0' || buf[0] > '9') + && (buf[0] < 'a' || buf[0] > 'f')) + { + if (remote_debug) + printf ("Bad register packet; fetching a new packet\n"); + getpkt (buf, 0); + } + + /* Reply describes registers byte by byte, each byte encoded as two + hex characters. Suck them all up, then supply them to the + register cacheing/storage mechanism. */ + + p = buf; + for (i = 0; i < REGISTER_BYTES; i++) + { + if (p[0] == 0) + break; + if (p[1] == 0) + { + warning ("Remote reply is of odd length: %s", buf); + /* Don't change register_bytes_found in this case, and don't + print a second warning. */ + goto supply_them; + } + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + + if (i != register_bytes_found) + { + register_bytes_found = i; +#ifdef REGISTER_BYTES_OK + if (!REGISTER_BYTES_OK (i)) + warning ("Remote reply is too short: %s", buf); +#endif + } + + supply_them: + for (i = 0; i < NUM_REGS; i++) + supply_register (i, ®s[REGISTER_BYTE(i)]); +} + +/* Prepare to store registers. Since we send them all, we have to + read out the ones we don't want to change first. */ + +static void +remote_prepare_to_store () +{ + /* Make sure the entire registers array is valid. */ + read_register_bytes (0, (char *)NULL, REGISTER_BYTES); +} + +/* Store the remote registers from the contents of the block REGISTERS. + FIXME, eventually just store one register if that's all that is needed. */ + +/* ARGSUSED */ +static void +remote_store_registers (regno) + int regno; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + buf[0] = 'G'; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf + 1; + /* remote_prepare_to_store insures that register_bytes_found gets set. */ + for (i = 0; i < register_bytes_found; i++) + { + *p++ = tohex ((registers[i] >> 4) & 0xf); + *p++ = tohex (registers[i] & 0xf); + } + *p = '\0'; + + remote_send (buf); +} + +#if 0 + +/* Use of the data cache is disabled because it loses for looking at + and changing hardware I/O ports and the like. Accepting `volatile' + would perhaps be one way to fix it, but a better way which would + win for more cases would be to use the executable file for the text + segment, like the `icache' code below but done cleanly (in some + target-independent place, perhaps in target_xfer_memory, perhaps + based on assigning each target a speed or perhaps by some simpler + mechanism). */ + +/* Read a word from remote address ADDR and return it. + This goes through the data cache. */ + +static int +remote_fetch_word (addr) + CORE_ADDR addr; +{ +#if 0 + if (icache) + { + extern CORE_ADDR text_start, text_end; + + if (addr >= text_start && addr < text_end) + { + int buffer; + xfer_core_file (addr, &buffer, sizeof (int)); + return buffer; + } + } +#endif + return dcache_fetch (remote_dcache, addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +static void +remote_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (remote_dcache, addr, word); +} +#endif /* 0 */ + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +remote_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + if (len > PBUFSIZ / 2 - 20) + abort (); + + sprintf (buf, "M%x,%x:", memaddr, len); + + /* We send target system values byte by byte, in increasing byte addresses, + each byte encoded as two hex characters. */ + + p = buf + strlen (buf); + for (i = 0; i < len; i++) + { + *p++ = tohex ((myaddr[i] >> 4) & 0xf); + *p++ = tohex (myaddr[i] & 0xf); + } + *p = '\0'; + + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + return len; +} + +/* Read memory data directly from the remote machine. + This does not use the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +remote_read_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + if (len > PBUFSIZ / 2 - 1) + abort (); + + sprintf (buf, "m%x,%x", memaddr, len); + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + + /* Reply describes memory byte by byte, + each byte encoded as two hex characters. */ + + p = buf; + for (i = 0; i < len; i++) + { + if (p[0] == 0 || p[1] == 0) + /* Reply is short. This means that we were able to read only part + of what we wanted to. */ + break; + myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + return i; +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, transferring + to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is + nonzero. Returns length of data written or read; 0 for error. */ + +/* ARGSUSED */ +static int +remote_xfer_memory(memaddr, myaddr, len, should_write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int should_write; + struct target_ops *target; /* ignored */ +{ + int xfersize; + int bytes_xferred; + int total_xferred = 0; + + while (len > 0) + { + if (len > MAXBUFBYTES) + xfersize = MAXBUFBYTES; + else + xfersize = len; + + if (should_write) + bytes_xferred = remote_write_bytes (memaddr, myaddr, xfersize); + else + bytes_xferred = remote_read_bytes (memaddr, myaddr, xfersize); + + /* If we get an error, we are done xferring. */ + if (bytes_xferred == 0) + break; + + memaddr += bytes_xferred; + myaddr += bytes_xferred; + len -= bytes_xferred; + total_xferred += bytes_xferred; + } + return total_xferred; +} + +static void +remote_files_info (ignore) + struct target_ops *ignore; +{ + puts_filtered ("Debugging a target over a serial line.\n"); +} + +/* Stuff for dealing with the packets which are part of this protocol. + See comment at top of file for details. */ + +/* Read a single character from the remote end, masking it down to 7 bits. */ + +static int +readchar () +{ + int ch; + + ch = SERIAL_READCHAR (remote_desc, timeout); + + if (ch < 0) + return ch; + + return ch & 0x7f; +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +static void +remote_send (buf) + char *buf; +{ + + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + error ("Remote failure reply: %s", buf); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +static void +putpkt (buf) + char *buf; +{ + int i; + unsigned char csum = 0; + char buf2[PBUFSIZ]; + int cnt = strlen (buf); + int ch; + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + if (cnt > sizeof(buf2) - 5) /* Prosanity check */ + abort(); + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + while (1) + { + if (remote_debug) + { + *p = '\0'; + printf ("Sending packet: %s...", buf2); fflush(stdout); + } + if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) + perror_with_name ("putpkt: write failed"); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (1) + { + ch = readchar (); + + switch (ch) + { + case '+': + if (remote_debug) + printf("Ack\n"); + return; + case SERIAL_TIMEOUT: + break; /* Retransmit buffer */ + case SERIAL_ERROR: + perror_with_name ("putpkt: couldn't read ACK"); + case SERIAL_EOF: + error ("putpkt: EOF while trying to read ACK"); + default: + if (remote_debug) + printf ("%02X %c ", ch&0xFF, ch); + continue; + } + break; /* Here to retransmit */ + } + + if (quit_flag) + { + quit_flag = 0; + interrupt_query (); + } + } +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. BUF is expected to be of size PBUFSIZ. + If FOREVER, wait forever rather than timing out; this is used + while the target is executing user code. */ + +static void +getpkt (buf, forever) + char *buf; + int forever; +{ + char *bp; + unsigned char csum; + int c = 0; + unsigned char c1, c2; + int retries = 0; +#define MAX_RETRIES 10 + + while (1) + { + if (quit_flag) + { + quit_flag = 0; + interrupt_query (); + } + + /* This can loop forever if the remote side sends us characters + continuously, but if it pauses, we'll get a zero from readchar + because of timeout. Then we'll count that as a retry. */ + + c = readchar(); + if (c > 0 && c != '$') + continue; + + if (c == SERIAL_TIMEOUT) + { + if (forever) + continue; + if (++retries >= MAX_RETRIES) + if (remote_debug) puts_filtered ("Timed out.\n"); + goto out; + } + + if (c == SERIAL_EOF) + error ("Remote connection closed"); + if (c == SERIAL_ERROR) + perror_with_name ("Remote communication error"); + + /* Force csum to be zero here because of possible error retry. */ + csum = 0; + bp = buf; + + while (1) + { + c = readchar (); + if (c == SERIAL_TIMEOUT) + { + if (remote_debug) + puts_filtered ("Timeout in mid-packet, retrying\n"); + goto whole; /* Start a new packet, count retries */ + } + if (c == '$') + { + if (remote_debug) + puts_filtered ("Saw new packet start in middle of old one\n"); + goto whole; /* Start a new packet, count retries */ + } + if (c == '#') + break; + if (bp >= buf+PBUFSIZ-1) + { + *bp = '\0'; + puts_filtered ("Remote packet too long: "); + puts_filtered (buf); + puts_filtered ("\n"); + goto whole; + } + *bp++ = c; + csum += c; + } + *bp = 0; + + c1 = fromhex (readchar ()); + c2 = fromhex (readchar ()); + if ((csum & 0xff) == (c1 << 4) + c2) + break; + printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=", + (c1 << 4) + c2, csum & 0xff); + puts_filtered (buf); + puts_filtered ("\n"); + + /* Try the whole thing again. */ +whole: + if (++retries < MAX_RETRIES) + { + SERIAL_WRITE (remote_desc, "-", 1); + } + else + { + printf ("Ignoring packet error, continuing...\n"); + break; + } + } + +out: + + SERIAL_WRITE (remote_desc, "+", 1); + + if (remote_debug) + fprintf (stderr,"Packet received: %s\n", buf); +} + +static void +remote_kill () +{ + putpkt ("k"); + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. For the existing stubs, kill is a noop. */ + target_mourn_inferior (); +} + +static void +remote_mourn () +{ + unpush_target (&remote_ops); + generic_mourn_inferior (); +} + +#ifdef REMOTE_BREAKPOINT + +/* On some machines, e.g. 68k, we may use a different breakpoint instruction + than other targets. */ +static unsigned char break_insn[] = REMOTE_BREAKPOINT; + +/* Check that it fits in BREAKPOINT_MAX bytes. */ +static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT; + +#else /* No REMOTE_BREAKPOINT. */ + +/* Same old breakpoint instruction. This code does nothing different + than mem-break.c. */ +static unsigned char break_insn[] = BREAKPOINT; + +#endif /* No REMOTE_BREAKPOINT. */ + +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes (this + is accomplished via BREAKPOINT_MAX). */ + +static int +remote_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, sizeof break_insn); + + if (val == 0) + val = target_write_memory (addr, (char *)break_insn, sizeof break_insn); + + return val; +} + +static int +remote_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + return target_write_memory (addr, contents_cache, sizeof break_insn); +} + +/* Define the target subroutine names */ + +struct target_ops remote_ops = { + "remote", /* to_shortname */ + "Remote serial target in gdb-specific protocol", /* to_longname */ + "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */ + remote_open, /* to_open */ + remote_close, /* to_close */ + NULL, /* to_attach */ + remote_detach, /* to_detach */ + remote_resume, /* to_resume */ + remote_wait, /* to_wait */ + remote_fetch_registers, /* to_fetch_registers */ + remote_store_registers, /* to_store_registers */ + remote_prepare_to_store, /* to_prepare_to_store */ + remote_xfer_memory, /* to_xfer_memory */ + remote_files_info, /* to_files_info */ + + remote_insert_breakpoint, /* to_insert_breakpoint */ + remote_remove_breakpoint, /* 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 */ + remote_kill, /* to_kill */ + generic_load, /* to_load */ + NULL, /* to_lookup_symbol */ + NULL, /* to_create_inferior */ + remote_mourn, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote () +{ + add_target (&remote_ops); +} +#endif diff --git a/gnu/usr.bin/gdb/gdb/ser-unix.c b/gnu/usr.bin/gdb/gdb/ser-unix.c new file mode 100644 index 00000000000..b306e8ace5b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ser-unix.c @@ -0,0 +1,633 @@ +/* Serial interface for local (hardwired) serial ports on Un*x like systems + Copyright 1992, 1993 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. */ + +#include "defs.h" +#include "serial.h" +#include +#include + +#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY) +#define HAVE_SGTTY +#endif + +#ifdef HAVE_TERMIOS +#include +#include + +struct hardwire_ttystate +{ + struct termios termios; +}; +#endif /* termios */ + +#ifdef HAVE_TERMIO +#include + +/* It is believed that all systems which have added job control to SVR3 + (e.g. sco) have also added termios. Even if not, trying to figure out + all the variations (TIOCGPGRP vs. TCGETPGRP, etc.) would be pretty + bewildering. So we don't attempt it. */ + +struct hardwire_ttystate +{ + struct termio termio; +}; +#endif /* termio */ + +#ifdef HAVE_SGTTY +/* Needed for the code which uses select(). We would include + too if it existed on all systems. */ +#include + +#include + +struct hardwire_ttystate +{ + struct sgttyb sgttyb; + struct tchars tc; + struct ltchars ltc; + /* Line discipline flags. */ + int lmode; +}; +#endif /* sgtty */ + +static int hardwire_open PARAMS ((serial_t scb, const char *name)); +static void hardwire_raw PARAMS ((serial_t scb)); +static int wait_for PARAMS ((serial_t scb, int timeout)); +static int hardwire_readchar PARAMS ((serial_t scb, int timeout)); +static int rate_to_code PARAMS ((int rate)); +static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate)); +static int hardwire_write PARAMS ((serial_t scb, const char *str, int len)); +/* FIXME: static void hardwire_restore PARAMS ((serial_t scb)); */ +static void hardwire_close PARAMS ((serial_t scb)); +static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); +static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); +static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb)); +static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); + +/* Open up a real live device for serial I/O */ + +static int +hardwire_open(scb, name) + serial_t scb; + const char *name; +{ + scb->fd = open (name, O_RDWR); + if (scb->fd < 0) + return -1; + + return 0; +} + +static int +get_tty_state(scb, state) + serial_t scb; + struct hardwire_ttystate *state; +{ +#ifdef HAVE_TERMIOS + extern int errno; + + if (tcgetattr(scb->fd, &state->termios) < 0) + return -1; + + return 0; +#endif + +#ifdef HAVE_TERMIO + if (ioctl (scb->fd, TCGETA, &state->termio) < 0) + return -1; + return 0; +#endif + +#ifdef HAVE_SGTTY + if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0) + return -1; + if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0) + return -1; + if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0) + return -1; + if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0) + return -1; + + return 0; +#endif +} + +static int +set_tty_state(scb, state) + serial_t scb; + struct hardwire_ttystate *state; +{ +#ifdef HAVE_TERMIOS + if (tcsetattr(scb->fd, TCSANOW, &state->termios) < 0) + return -1; + + return 0; +#endif + +#ifdef HAVE_TERMIO + if (ioctl (scb->fd, TCSETA, &state->termio) < 0) + return -1; + return 0; +#endif + +#ifdef HAVE_SGTTY + if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0) + return -1; + + return 0; +#endif +} + +static serial_ttystate +hardwire_get_tty_state(scb) + serial_t scb; +{ + struct hardwire_ttystate *state; + + state = (struct hardwire_ttystate *)xmalloc(sizeof *state); + + if (get_tty_state(scb, state)) + return NULL; + + return (serial_ttystate)state; +} + +static int +hardwire_set_tty_state(scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + struct hardwire_ttystate *state; + + state = (struct hardwire_ttystate *)ttystate; + + return set_tty_state(scb, state); +} + +static int +hardwire_noflush_set_tty_state (scb, new_ttystate, old_ttystate) + serial_t scb; + serial_ttystate new_ttystate; + serial_ttystate old_ttystate; +{ + struct hardwire_ttystate new_state; + struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate; + + new_state = *(struct hardwire_ttystate *)new_ttystate; + +#ifdef HAVE_TERMIOS + /* I'm not sure whether this is necessary; the manpage makes no mention + of discarding input when switching to/from ICANON. */ + if (state->termios.c_lflag & ICANON) + new_state.termios.c_lflag |= ICANON; + else + new_state.termios.c_lflag &= ~ICANON; +#endif + +#ifdef HAVE_TERMIO + /* I'm not sure whether this is necessary; the manpage makes no mention + of discarding input when switching to/from ICANON. */ + if (state->termio.c_lflag & ICANON) + new_state.termio.c_lflag |= ICANON; + else + new_state.termio.c_lflag &= ~ICANON; +#endif + +#ifdef HAVE_SGTTY + if (state->sgttyb.sg_flags & RAW) + new_state.sgttyb.sg_flags |= RAW; + else + new_state.sgttyb.sg_flags &= ~RAW; + + /* I'm not sure whether this is necessary; the manpage just mentions + RAW not CBREAK. */ + if (state->sgttyb.sg_flags & CBREAK) + new_state.sgttyb.sg_flags |= CBREAK; + else + new_state.sgttyb.sg_flags &= ~CBREAK; +#endif + + return set_tty_state (scb, &new_state); +} + +static void +hardwire_print_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate; + int i; + +#ifdef HAVE_TERMIOS + printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n", + state->termios.c_iflag, state->termios.c_oflag); + printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x\n", + state->termios.c_cflag, state->termios.c_lflag); +#if 0 + /* This not in POSIX, and is not really documented by those systems + which have it (at least not Sun). */ + printf_filtered ("c_line = 0x%x.\n", state->termios.c_line); +#endif + printf_filtered ("c_cc: "); + for (i = 0; i < NCCS; i += 1) + printf_filtered ("0x%x ", state->termios.c_cc[i]); + printf_filtered ("\n"); +#endif + +#ifdef HAVE_TERMIO + printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n", + state->termio.c_iflag, state->termio.c_oflag); + printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", + state->termio.c_cflag, state->termio.c_lflag, + state->termio.c_line); + printf_filtered ("c_cc: "); + for (i = 0; i < NCC; i += 1) + printf_filtered ("0x%x ", state->termio.c_cc[i]); + printf_filtered ("\n"); +#endif + +#ifdef HAVE_SGTTY + printf_filtered ("sgttyb.sg_flags = 0x%x.\n", state->sgttyb.sg_flags); + + printf_filtered ("tchars: "); + for (i = 0; i < (int)sizeof (struct tchars); i++) + printf_filtered ("0x%x ", ((unsigned char *)&state->tc)[i]); + printf_filtered ("\n"); + + printf_filtered ("ltchars: "); + for (i = 0; i < (int)sizeof (struct ltchars); i++) + printf_filtered ("0x%x ", ((unsigned char *)&state->ltc)[i]); + printf_filtered ("\n"); + + printf_filtered ("lmode: 0x%x\n", state->lmode); +#endif +} + +static int +hardwire_flush_output (scb) + serial_t scb; +{ +#ifdef HAVE_TERMIOS + return tcflush (scb->fd, TCOFLUSH); +#endif + +#ifdef HAVE_TERMIO + return ioctl (scb->fd, TCFLSH, 1); +#endif + +#ifdef HAVE_SGTTY + /* This flushes both input and output, but we can't do better. */ + return ioctl (scb->fd, TIOCFLUSH, 0); +#endif +} + +static int +hardwire_flush_input (scb) + serial_t scb; +{ +#ifdef HAVE_TERMIOS + return tcflush (scb->fd, TCIFLUSH); +#endif + +#ifdef HAVE_TERMIO + return ioctl (scb->fd, TCFLSH, 0); +#endif + +#ifdef HAVE_SGTTY + /* This flushes both input and output, but we can't do better. */ + return ioctl (scb->fd, TIOCFLUSH, 0); +#endif +} + +static int +hardwire_send_break (scb) + serial_t scb; +{ +#ifdef HAVE_TERMIOS + return tcsendbreak (scb->fd, 0); +#endif + +#ifdef HAVE_TERMIO + return ioctl (scb->fd, TCSBRK, 0); +#endif + +#ifdef HAVE_SGTTY + { + int status; + struct timeval timeout; + + status = ioctl (scb->fd, TIOCSBRK, 0); + + /* Can't use usleep; it doesn't exist in BSD 4.2. */ + /* Note that if this select() is interrupted by a signal it will not wait + the full length of time. I think that is OK. */ + timeout.tv_sec = 0; + timeout.tv_usec = 250000; + select (0, 0, 0, 0, &timeout); + status = ioctl (scb->fd, TIOCCBRK, 0); + return status; + } +#endif +} + +static void +hardwire_raw(scb) + serial_t scb; +{ + struct hardwire_ttystate state; + + if (get_tty_state(scb, &state)) + fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); + +#ifdef HAVE_TERMIOS + state.termios.c_iflag = 0; + state.termios.c_oflag = 0; + state.termios.c_lflag = 0; + state.termios.c_cflag &= ~(CSIZE|PARENB); + state.termios.c_cflag |= CS8; + state.termios.c_cc[VMIN] = 0; + state.termios.c_cc[VTIME] = 0; +#endif + +#ifdef HAVE_TERMIO + state.termio.c_iflag = 0; + state.termio.c_oflag = 0; + state.termio.c_lflag = 0; + state.termio.c_cflag &= ~(CSIZE|PARENB); + state.termio.c_cflag |= CS8; + state.termio.c_cc[VMIN] = 0; + state.termio.c_cc[VTIME] = 0; +#endif + +#ifdef HAVE_SGTTY + state.sgttyb.sg_flags |= RAW | ANYP; + state.sgttyb.sg_flags &= ~(CBREAK | ECHO); +#endif + + scb->current_timeout = 0; + + if (set_tty_state (scb, &state)) + fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); +} + +/* Wait for input on scb, with timeout seconds. Returns 0 on success, + otherwise SERIAL_TIMEOUT or SERIAL_ERROR. + + For termio{s}, we actually just setup VTIME if necessary, and let the + timeout occur in the read() in hardwire_read(). + */ + +static int +wait_for(scb, timeout) + serial_t scb; + int timeout; +{ +#ifdef HAVE_SGTTY + struct timeval tv; + fd_set readfds; + + FD_ZERO (&readfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_SET(scb->fd, &readfds); + + while (1) + { + int numfds; + + if (timeout >= 0) + numfds = select(scb->fd+1, &readfds, 0, 0, &tv); + else + numfds = select(scb->fd+1, &readfds, 0, 0, 0); + + if (numfds <= 0) + if (numfds == 0) + return SERIAL_TIMEOUT; + else if (errno == EINTR) + continue; + else + return SERIAL_ERROR; /* Got an error from select or poll */ + + return 0; + } + +#endif /* HAVE_SGTTY */ + +#if defined HAVE_TERMIO || defined HAVE_TERMIOS + if (timeout == scb->current_timeout) + return 0; + + { + struct hardwire_ttystate state; + + if (get_tty_state(scb, &state)) + fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); + +#ifdef HAVE_TERMIOS + state.termios.c_cc[VTIME] = timeout * 10; +#endif + +#ifdef HAVE_TERMIO + state.termio.c_cc[VTIME] = timeout * 10; +#endif + + scb->current_timeout = timeout; + + if (set_tty_state (scb, &state)) + fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); + + return 0; + } +#endif /* HAVE_TERMIO || HAVE_TERMIOS */ +} + +/* Read a character with user-specified timeout. TIMEOUT is number of seconds + to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns + char if successful. Returns SERIAL_TIMEOUT if timeout expired, EOF if line + dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */ + +static int +hardwire_readchar(scb, timeout) + serial_t scb; + int timeout; +{ + int status; + + if (scb->bufcnt-- > 0) + return *scb->bufp++; + + status = wait_for(scb, timeout); + + if (status < 0) + return status; + + scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ); + + if (scb->bufcnt <= 0) + if (scb->bufcnt == 0) + return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to + distinguish between EOF & timeouts + someday] */ + else + return SERIAL_ERROR; /* Got an error from read */ + + scb->bufcnt--; + scb->bufp = scb->buf; + return *scb->bufp++; +} + +#ifndef B19200 +#define B19200 EXTA +#endif + +#ifndef B38400 +#define B38400 EXTB +#endif + +/* Translate baud rates from integers to damn B_codes. Unix should + have outgrown this crap years ago, but even POSIX wouldn't buck it. */ + +static struct +{ + int rate; + int code; +} +baudtab[] = +{ + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {-1, -1}, +}; + +static int +rate_to_code(rate) + int rate; +{ + int i; + + for (i = 0; baudtab[i].rate != -1; i++) + if (rate == baudtab[i].rate) + return baudtab[i].code; + + return -1; +} + +static int +hardwire_setbaudrate(scb, rate) + serial_t scb; + int rate; +{ + struct hardwire_ttystate state; + + if (get_tty_state(scb, &state)) + return -1; + +#ifdef HAVE_TERMIOS + cfsetospeed (&state.termios, rate_to_code (rate)); + cfsetispeed (&state.termios, rate_to_code (rate)); +#endif + +#ifdef HAVE_TERMIO +#ifndef CIBAUD +#define CIBAUD CBAUD +#endif + + state.termio.c_cflag &= ~(CBAUD | CIBAUD); + state.termio.c_cflag |= rate_to_code (rate); +#endif + +#ifdef HAVE_SGTTY + state.sgttyb.sg_ispeed = rate_to_code (rate); + state.sgttyb.sg_ospeed = rate_to_code (rate); +#endif + + return set_tty_state (scb, &state); +} + +static int +hardwire_write(scb, str, len) + serial_t scb; + const char *str; + int len; +{ + int cc; + + while (len > 0) + { + cc = write(scb->fd, str, len); + + if (cc < 0) + return 1; + len -= cc; + str += cc; + } + return 0; +} + +static void +hardwire_close(scb) + serial_t scb; +{ + if (scb->fd < 0) + return; + + close(scb->fd); + scb->fd = -1; +} + +static struct serial_ops hardwire_ops = +{ + "hardwire", + 0, + hardwire_open, + hardwire_close, + hardwire_readchar, + hardwire_write, + hardwire_flush_output, + hardwire_flush_input, + hardwire_send_break, + hardwire_raw, + hardwire_get_tty_state, + hardwire_set_tty_state, + hardwire_print_tty_state, + hardwire_noflush_set_tty_state, + hardwire_setbaudrate, +}; + +void +_initialize_ser_hardwire () +{ + serial_add_interface (&hardwire_ops); +} diff --git a/gnu/usr.bin/gdb/gdb/serial.c b/gnu/usr.bin/gdb/gdb/serial.c new file mode 100644 index 00000000000..6913fd6e239 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/serial.c @@ -0,0 +1,261 @@ +/* Generic serial interface routines + Copyright 1992, 1993 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. */ + +#include "defs.h" +#include "serial.h" + +/* Linked list of serial I/O handlers */ + +static struct serial_ops *serial_ops_list = NULL; + +/* This is the last serial stream opened. Used by connect command. */ + +static serial_t last_serial_opened = NULL; + +static struct serial_ops * +serial_interface_lookup (name) + char *name; +{ + struct serial_ops *ops; + + for (ops = serial_ops_list; ops; ops = ops->next) + if (strcmp (name, ops->name) == 0) + return ops; + + return NULL; +} + +void +serial_add_interface(optable) + struct serial_ops *optable; +{ + optable->next = serial_ops_list; + serial_ops_list = optable; +} + +/* Open up a device or a network socket, depending upon the syntax of NAME. */ + +serial_t +serial_open(name) + const char *name; +{ + serial_t scb; + struct serial_ops *ops; + + if (strchr (name, ':')) + ops = serial_interface_lookup ("tcp"); + else + ops = serial_interface_lookup ("hardwire"); + + if (!ops) + return NULL; + + scb = (serial_t)xmalloc (sizeof (struct _serial_t)); + + scb->ops = ops; + + scb->bufcnt = 0; + scb->bufp = scb->buf; + + if (scb->ops->open(scb, name)) + { + free (scb); + return NULL; + } + + last_serial_opened = scb; + + return scb; +} + +serial_t +serial_fdopen(fd) + const int fd; +{ + serial_t scb; + struct serial_ops *ops; + + ops = serial_interface_lookup ("hardwire"); + + if (!ops) + return NULL; + + scb = (serial_t)xmalloc (sizeof (struct _serial_t)); + + scb->ops = ops; + + scb->bufcnt = 0; + scb->bufp = scb->buf; + + scb->fd = fd; + + last_serial_opened = scb; + + return scb; +} + +void +serial_close(scb) + serial_t scb; +{ + last_serial_opened = NULL; + +/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you + should fix your code instead. */ + + if (!scb) + return; + + scb->ops->close(scb); + free(scb); +} + +#if 0 +/* +The connect command is #if 0 because I hadn't thought of an elegant +way to wait for I/O on two serial_t's simultaneously. Two solutions +came to mind: + + 1) Fork, and have have one fork handle the to user direction, + and have the other hand the to target direction. This + obviously won't cut it for MSDOS. + + 2) Use something like select. This assumes that stdin and + the target side can both be waited on via the same + mechanism. This may not be true for DOS, if GDB is + talking to the target via a TCP socket. +-grossman, 8 Jun 93 +*/ + +/* Connect the user directly to the remote system. This command acts just like + the 'cu' or 'tip' command. Use ~. or ~^D to break out. */ + +static serial_t tty_desc; /* Controlling terminal */ + +static void +cleanup_tty(ttystate) + serial_ttystate ttystate; +{ + printf ("\r\n[Exiting connect mode]\r\n"); + SERIAL_SET_TTY_STATE (tty_desc, ttystate); + free (ttystate); + SERIAL_CLOSE (tty_desc); +} + +static void +connect_command (args, fromtty) + char *args; + int fromtty; +{ + int c; + char cur_esc = 0; + serial_ttystate ttystate; + serial_t port_desc; /* TTY port */ + + dont_repeat(); + + if (args) + fprintf(stderr, "This command takes no args. They have been ignored.\n"); + + printf("[Entering connect mode. Use ~. or ~^D to escape]\n"); + + tty_desc = SERIAL_FDOPEN (0); + port_desc = last_serial_opened; + + ttystate = SERIAL_GET_TTY_STATE (tty_desc); + + SERIAL_RAW (tty_desc); + SERIAL_RAW (port_desc); + + make_cleanup (cleanup_tty, ttystate); + + while (1) + { + int mask; + + mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1); + + if (mask & 2) + { /* tty input */ + char cx; + + while (1) + { + c = SERIAL_READCHAR(tty_desc, 0); + + if (c == SERIAL_TIMEOUT) + break; + + if (c < 0) + perror_with_name("connect"); + + cx = c; + SERIAL_WRITE(port_desc, &cx, 1); + + switch (cur_esc) + { + case 0: + if (c == '\r') + cur_esc = c; + break; + case '\r': + if (c == '~') + cur_esc = c; + else + cur_esc = 0; + break; + case '~': + if (c == '.' || c == '\004') + return; + else + cur_esc = 0; + } + } + } + + if (mask & 1) + { /* Port input */ + char cx; + + while (1) + { + c = SERIAL_READCHAR(port_desc, 0); + + if (c == SERIAL_TIMEOUT) + break; + + if (c < 0) + perror_with_name("connect"); + + cx = c; + + SERIAL_WRITE(tty_desc, &cx, 1); + } + } + } +} + +void +_initialize_serial () +{ + add_com ("connect", class_obscure, connect_command, + "Connect the terminal directly up to the command monitor.\n\ +Use ~. or ~^D to break out."); +} +#endif /* 0 */ diff --git a/gnu/usr.bin/gdb/gdb/serial.h b/gnu/usr.bin/gdb/gdb/serial.h new file mode 100644 index 00000000000..7e7e5306686 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/serial.h @@ -0,0 +1,153 @@ +/* Remote serial support interface definitions for GDB, the GNU Debugger. + Copyright 1992, 1993 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. */ + +#ifndef SERIAL_H +#define SERIAL_H + +/* Terminal state pointer. This is specific to each type of interface. */ + +typedef PTR serial_ttystate; + +struct _serial_t +{ + int fd; /* File descriptor */ + struct serial_ops *ops; /* Function vector */ + serial_ttystate ttystate; /* Not used (yet) */ + int bufcnt; /* Amount of data in receive buffer */ + unsigned char *bufp; /* Current byte */ + unsigned char buf[BUFSIZ]; /* Da buffer itself */ + int current_timeout; /* (termio{s} only), last value of VTIME */ +}; + +typedef struct _serial_t *serial_t; + +struct serial_ops { + char *name; + struct serial_ops *next; + int (*open) PARAMS ((serial_t, const char *name)); + void (*close) PARAMS ((serial_t)); + int (*readchar) PARAMS ((serial_t, int timeout)); + int (*write) PARAMS ((serial_t, const char *str, int len)); + int (*flush_output) PARAMS ((serial_t)); + int (*flush_input) PARAMS ((serial_t)); + int (*send_break) PARAMS ((serial_t)); + void (*go_raw) PARAMS ((serial_t)); + serial_ttystate (*get_tty_state) PARAMS ((serial_t)); + int (*set_tty_state) PARAMS ((serial_t, serial_ttystate)); + void (*print_tty_state) PARAMS ((serial_t, serial_ttystate)); + int (*noflush_set_tty_state) + PARAMS ((serial_t, serial_ttystate, serial_ttystate)); + int (*setbaudrate) PARAMS ((serial_t, int rate)); +}; + +/* Add a new serial interface to the interface list */ + +void serial_add_interface PARAMS ((struct serial_ops *optable)); + +serial_t serial_open PARAMS ((const char *name)); + +serial_t serial_fdopen PARAMS ((int fd)); + +/* For most routines, if a failure is indicated, then errno should be + examined. */ + +/* Try to open NAME. Returns a new serial_t on success, NULL on failure. + */ + +#define SERIAL_OPEN(NAME) serial_open(NAME) + +/* Open a new serial stream using a file handle. */ + +#define SERIAL_FDOPEN(FD) serial_fdopen(FD) + +/* Flush pending output. Might also flush input (if this system can't flush + only output). */ + +#define SERIAL_FLUSH_OUTPUT(SERIAL_T) \ + ((SERIAL_T)->ops->flush_output((SERIAL_T))) + +/* Flush pending input. Might also flush output (if this system can't flush + only input). */ + +#define SERIAL_FLUSH_INPUT(SERIAL_T)\ + ((*(SERIAL_T)->ops->flush_input) ((SERIAL_T))) + +/* Send a break between 0.25 and 0.5 seconds long. */ + +#define SERIAL_SEND_BREAK(SERIAL_T) \ + ((*(SERIAL_T)->ops->send_break) (SERIAL_T)) + +/* Turn the port into raw mode. */ + +#define SERIAL_RAW(SERIAL_T) (SERIAL_T)->ops->go_raw((SERIAL_T)) + +/* Return a pointer to a newly malloc'd ttystate containing the state + of the tty. */ +#define SERIAL_GET_TTY_STATE(SERIAL_T) (SERIAL_T)->ops->get_tty_state((SERIAL_T)) + +/* Set the state of the tty to TTYSTATE. The change is immediate. + When changing to or from raw mode, input might be discarded. */ +#define SERIAL_SET_TTY_STATE(SERIAL_T, TTYSTATE) (SERIAL_T)->ops->set_tty_state((SERIAL_T), (TTYSTATE)) + +/* printf_filtered a user-comprehensible description of ttystate. */ +#define SERIAL_PRINT_TTY_STATE(SERIAL_T, TTYSTATE) \ + ((*((SERIAL_T)->ops->print_tty_state)) ((SERIAL_T), (TTYSTATE))) + +/* Set the tty state to NEW_TTYSTATE, where OLD_TTYSTATE is the + current state (generally obtained from a recent call to + SERIAL_GET_TTY_STATE), but be careful not to discard any input. + This means that we never switch in or out of raw mode, even + if NEW_TTYSTATE specifies a switch. */ +#define SERIAL_NOFLUSH_SET_TTY_STATE(SERIAL_T, NEW_TTYSTATE, OLD_TTYSTATE) \ + ((*((SERIAL_T)->ops->noflush_set_tty_state)) \ + ((SERIAL_T), (NEW_TTYSTATE), (OLD_TTYSTATE))) + +/* Read one char from the serial device with TIMEOUT seconds to wait + or -1 to wait forever. Use timeout of 0 to effect a poll. Returns + char if ok, else one of the following codes. Note that all error + codes are guaranteed to be < 0. */ + +#define SERIAL_ERROR -1 /* General error, see errno for details */ +#define SERIAL_TIMEOUT -2 +#define SERIAL_EOF -3 + +#define SERIAL_READCHAR(SERIAL_T, TIMEOUT) ((SERIAL_T)->ops->readchar((SERIAL_T), TIMEOUT)) + +/* Set the baudrate to the decimal value supplied. Returns 0 for success, + -1 for failure. */ + +#define SERIAL_SETBAUDRATE(SERIAL_T, RATE) ((SERIAL_T)->ops->setbaudrate((SERIAL_T), RATE)) + +/* Write LEN chars from STRING to the port SERIAL_T. Returns 0 for + success, non-zero for failure. */ + +#define SERIAL_WRITE(SERIAL_T, STRING, LEN) ((SERIAL_T)->ops->write((SERIAL_T), STRING, LEN)) + +/* Push out all buffers, close the device and destroy SERIAL_T. */ + +void serial_close PARAMS ((serial_t)); + +#define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T) + +/* Destroy SERIAL_T without doing the rest of the stuff that SERIAL_CLOSE + does. */ + +#define SERIAL_UN_FDOPEN(SERIAL_T) (free (SERIAL_T)) + +#endif /* SERIAL_H */ diff --git a/gnu/usr.bin/gdb/gdb/signals.h b/gnu/usr.bin/gdb/gdb/signals.h new file mode 100644 index 00000000000..08fa606ef09 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/signals.h @@ -0,0 +1,27 @@ +/* Signal handler definitions for GDB, the GNU Debugger. + Copyright (C) 1986, 1989 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. */ + + +/* This file is almost the same as including except that it + eliminates certain signal names when job control is not supported, + (or, on some systems, when job control is there but doesn't work + the way GDB expects it to work). */ +/* This has been superceded by the job_control variable in serial.h. */ + +#include diff --git a/gnu/usr.bin/gdb/gdb/solib.h b/gnu/usr.bin/gdb/gdb/solib.h new file mode 100644 index 00000000000..ddabf7460bc --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/solib.h @@ -0,0 +1,56 @@ +/* Shared library declarations for GDB, the GNU Debugger. + Copyright (C) 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. */ + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct target_ops; +#endif + +/* Called when we free all symtabs, to free the shared library information + as well. */ + +#define CLEAR_SOLIB clear_solib + +extern void +clear_solib PARAMS ((void)); + +/* Called to add symbols from a shared library to gdb's symbol table. */ + +#define SOLIB_ADD(filename, from_tty, targ) \ + solib_add (filename, from_tty, targ) + +extern void +solib_add PARAMS ((char *, int, struct target_ops *)); + +/* Function to be called when the inferior starts up, to discover the names + of shared libraries that are dynamically linked, the base addresses to + which they are linked, and sufficient information to read in their symbols + at a later time. */ + +#define SOLIB_CREATE_INFERIOR_HOOK(PID) solib_create_inferior_hook() + +extern void +solib_create_inferior_hook PARAMS((void)); /* solib.c */ + +/* If we can't set a breakpoint, and it's in a shared library, just + disable it. */ + +#define DISABLE_UNSETTABLE_BREAK(addr) solib_address(addr) + +extern int +solib_address PARAMS ((CORE_ADDR)); /* solib.c */ diff --git a/gnu/usr.bin/gdb/gdb/source.c b/gnu/usr.bin/gdb/gdb/source.c new file mode 100644 index 00000000000..88781d7cbc9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/source.c @@ -0,0 +1,1398 @@ +/* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include "symtab.h" +#include "expression.h" +#include "language.h" +#include "command.h" +#include "gdbcmd.h" +#include "frame.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include "gdbcore.h" +#include "regex.h" +#include "symfile.h" +#include "objfiles.h" + +/* Prototypes for local functions. */ + +static int +open_source_file PARAMS ((struct symtab *)); + +static int +get_filename_and_charpos PARAMS ((struct symtab *, char **)); + +static void +reverse_search_command PARAMS ((char *, int)); + +static void +forward_search_command PARAMS ((char *, int)); + +static void +line_info PARAMS ((char *, int)); + +static void +list_command PARAMS ((char *, int)); + +static void +ambiguous_line_spec PARAMS ((struct symtabs_and_lines *)); + +static void +source_info PARAMS ((char *, int)); + +static void +show_directories PARAMS ((char *, int)); + +static void +find_source_lines PARAMS ((struct symtab *, int)); + +/* If we use this declaration, it breaks because of fucking ANSI "const" stuff + on some systems. We just have to not declare it at all, have it default + to int, and possibly botch on a few systems. Thanks, ANSIholes... */ +/* extern char *strstr(); */ + +/* Path of directories to search for source files. + Same format as the PATH environment variable's value. */ + +char *source_path; + +/* Symtab of default file for listing lines of. */ + +struct symtab *current_source_symtab; + +/* Default next line to list. */ + +int current_source_line; + +/* Default number of lines to print with commands like "list". + This is based on guessing how many long (i.e. more than chars_per_line + characters) lines there will be. To be completely correct, "list" + and friends should be rewritten to count characters and see where + things are wrapping, but that would be a fair amount of work. */ + +int lines_to_list = 10; + +/* Line number of last line printed. Default for various commands. + current_source_line is usually, but not always, the same as this. */ + +static int last_line_listed; + +/* First line number listed by last listing command. */ + +static int first_line_listed; + + +/* Set the source file default for the "list" command to be S. + + If S is NULL, and we don't have a default, find one. This + should only be called when the user actually tries to use the + default, since we produce an error if we can't find a reasonable + default. Also, since this can cause symbols to be read, doing it + before we need to would make things slower than necessary. */ + +void +select_source_symtab (s) + register struct symtab *s; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct partial_symtab *ps; + struct partial_symtab *cs_pst = 0; + struct objfile *ofp; + + if (s) + { + current_source_symtab = s; + current_source_line = 1; + return; + } + + if (current_source_symtab) + return; + + /* Make the default place to list be the function `main' + if one exists. */ + if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0, NULL)) + { + sals = decode_line_spec ("main", 1); + sal = sals.sals[0]; + free (sals.sals); + current_source_symtab = sal.symtab; + current_source_line = max (sal.line - (lines_to_list - 1), 1); + if (current_source_symtab) + return; + } + + /* All right; find the last file in the symtab list (ignoring .h's). */ + + current_source_line = 1; + + for (ofp = object_files; ofp != NULL; ofp = ofp -> next) + { + for (s = ofp -> symtabs; s; s = s->next) + { + char *name = s -> filename; + int len = strlen (name); + if (! (len > 2 && (STREQ (&name[len - 2], ".h")))) + { + current_source_symtab = s; + } + } + } + if (current_source_symtab) + return; + + /* Howabout the partial symbol tables? */ + + for (ofp = object_files; ofp != NULL; ofp = ofp -> next) + { + for (ps = ofp -> psymtabs; ps != NULL; ps = ps -> next) + { + char *name = ps -> filename; + int len = strlen (name); + if (! (len > 2 && (STREQ (&name[len - 2], ".h")))) + { + cs_pst = ps; + } + } + } + if (cs_pst) + { + if (cs_pst -> readin) + { + fatal ("Internal: select_source_symtab: readin pst found and no symtabs."); + } + else + { + current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst); + } + } + + error ("Can't find a default source file"); +} + +static void +show_directories (ignore, from_tty) + char *ignore; + int from_tty; +{ + puts_filtered ("Source directories searched: "); + puts_filtered (source_path); + puts_filtered ("\n"); +} + +/* Forget what we learned about line positions in source files, + and which directories contain them; + must check again now since files may be found in + a different directory now. */ + +void +forget_cached_source_info () +{ + register struct symtab *s; + register struct objfile *objfile; + + for (objfile = object_files; objfile != NULL; objfile = objfile -> next) + { + for (s = objfile -> symtabs; s != NULL; s = s -> next) + { + if (s -> line_charpos != NULL) + { + mfree (objfile -> md, s -> line_charpos); + s -> line_charpos = NULL; + } + if (s -> fullname != NULL) + { + mfree (objfile -> md, s -> fullname); + s -> fullname = NULL; + } + } + } +} + +void +init_source_path () +{ + source_path = savestring ("$cdir:$cwd", /* strlen of it */ 10); + forget_cached_source_info (); +} + +/* Add zero or more directories to the front of the source path. */ + +void +directory_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + dont_repeat (); + /* FIXME, this goes to "delete dir"... */ + if (dirname == 0) + { + if (query ("Reinitialize source path to empty? ", "")) + { + free (source_path); + init_source_path (); + } + } + else + mod_path (dirname, &source_path); + if (from_tty) + show_directories ((char *)0, from_tty); + forget_cached_source_info (); +} + +/* Add zero or more directories to the front of an arbitrary path. */ + +void +mod_path (dirname, which_path) + char *dirname; + char **which_path; +{ + char *old = *which_path; + int prefix = 0; + + if (dirname == 0) + return; + + dirname = strsave (dirname); + make_cleanup (free, dirname); + + do + { + char *name = dirname; + register char *p; + struct stat st; + + { + char *colon = strchr (name, ':'); + char *space = strchr (name, ' '); + char *tab = strchr (name, '\t'); + if (colon == 0 && space == 0 && tab == 0) + p = dirname = name + strlen (name); + else + { + p = 0; + if (colon != 0 && (p == 0 || colon < p)) + p = colon; + if (space != 0 && (p == 0 || space < p)) + p = space; + if (tab != 0 && (p == 0 || tab < p)) + p = tab; + dirname = p + 1; + while (*dirname == ':' || *dirname == ' ' || *dirname == '\t') + ++dirname; + } + } + + if (p[-1] == '/') + /* Sigh. "foo/" => "foo" */ + --p; + *p = '\0'; + + while (p[-1] == '.') + { + if (p - name == 1) + { + /* "." => getwd (). */ + name = current_directory; + goto append; + } + else if (p[-2] == '/') + { + if (p - name == 2) + { + /* "/." => "/". */ + *--p = '\0'; + goto append; + } + else + { + /* "...foo/." => "...foo". */ + p -= 2; + *p = '\0'; + continue; + } + } + else + break; + } + + if (name[0] == '~') + name = tilde_expand (name); + else if (name[0] != '/' && name[0] != '$') + name = concat (current_directory, "/", name, NULL); + else + name = savestring (name, p - name); + make_cleanup (free, name); + + /* Unless it's a variable, check existence. */ + if (name[0] != '$') { + /* These are warnings, not errors, since we don't want a + non-existent directory in a .gdbinit file to stop processing + of the .gdbinit file. + + Whether they get added to the path is more debatable. Current + answer is yes, in case the user wants to go make the directory + or whatever. If the directory continues to not exist/not be + a directory/etc, then having them in the path should be + harmless. */ + if (stat (name, &st) < 0) + { + int save_errno = errno; + fprintf (stderr, "Warning: "); + print_sys_errmsg (name, save_errno); + } + else if ((st.st_mode & S_IFMT) != S_IFDIR) + warning ("%s is not a directory.", name); + } + + append: + { + register unsigned int len = strlen (name); + + p = *which_path; + while (1) + { + if (!strncmp (p, name, len) + && (p[len] == '\0' || p[len] == ':')) + { + /* Found it in the search path, remove old copy */ + if (p > *which_path) + p--; /* Back over leading colon */ + if (prefix > p - *which_path) + goto skip_dup; /* Same dir twice in one cmd */ + strcpy (p, &p[len+1]); /* Copy from next \0 or : */ + } + p = strchr (p, ':'); + if (p != 0) + ++p; + else + break; + } + if (p == 0) + { + /* If we have already tacked on a name(s) in this command, be sure they stay on the front as we tack on some more. */ + if (prefix) + { + char *temp, c; + + c = old[prefix]; + old[prefix] = '\0'; + temp = concat (old, ":", name, NULL); + old[prefix] = c; + *which_path = concat (temp, "", &old[prefix], NULL); + prefix = strlen (temp); + free (temp); + } + else + { + *which_path = concat (name, (old[0]? ":" : old), old, NULL); + prefix = strlen (name); + } + free (old); + old = *which_path; + } + } + skip_dup: ; + } while (*dirname != '\0'); +} + + +static void +source_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct symtab *s = current_source_symtab; + + if (!s) + { + printf_filtered("No current source file.\n"); + return; + } + printf_filtered ("Current source file is %s\n", s->filename); + if (s->dirname) + printf_filtered ("Compilation directory is %s\n", s->dirname); + if (s->fullname) + printf_filtered ("Located in %s\n", s->fullname); + if (s->nlines) + printf_filtered ("Contains %d line%s.\n", s->nlines, + s->nlines == 1 ? "" : "s"); + + printf_filtered("Source language is %s.\n", language_str (s->language)); +} + + + +/* Open a file named STRING, searching path PATH (dir names sep by colons) + using mode MODE and protection bits PROT in the calls to open. + + If TRY_CWD_FIRST, try to open ./STRING before searching PATH. + (ie pretend the first element of PATH is "."). This also indicates + that a slash in STRING disables searching of the path (this is + so that "exec-file ./foo" or "symbol-file ./foo" insures that you + get that particular version of foo or an error message). + + If FILENAMED_OPENED is non-null, set it to a newly allocated string naming + the actual file opened (this string will always start with a "/". We + have to take special pains to avoid doubling the "/" between the directory + and the file, sigh! Emacs gets confuzzed by this when we print the + source file name!!! + + If a file is found, return the descriptor. + Otherwise, return -1, with errno set for the last name we tried to open. */ + +/* >>>> This should only allow files of certain types, + >>>> eg executable, non-directory */ +int +openp (path, try_cwd_first, string, mode, prot, filename_opened) + char *path; + int try_cwd_first; + char *string; + int mode; + int prot; + char **filename_opened; +{ + register int fd; + register char *filename; + register char *p, *p1; + register int len; + int alloclen; + + if (!path) + path = "."; + + if (try_cwd_first || string[0] == '/') + { + filename = string; + fd = open (filename, mode, prot); + if (fd >= 0 || string[0] == '/' || strchr (string, '/')) + goto done; + } + + /* ./foo => foo */ + while (string[0] == '.' && string[1] == '/') + string += 2; + + alloclen = strlen (path) + strlen (string) + 2; + filename = (char *) alloca (alloclen); + fd = -1; + for (p = path; p; p = p1 ? p1 + 1 : 0) + { + p1 = (char *) strchr (p, ':'); + if (p1) + len = p1 - p; + else + len = strlen (p); + + if (len == 4 && p[0] == '$' && p[1] == 'c' + && p[2] == 'w' && p[3] == 'd') { + /* Name is $cwd -- insert current directory name instead. */ + int newlen; + + /* First, realloc the filename buffer if too short. */ + len = strlen (current_directory); + newlen = len + strlen (string) + 2; + if (newlen > alloclen) { + alloclen = newlen; + filename = (char *) alloca (alloclen); + } + strcpy (filename, current_directory); + } else { + /* Normal file name in path -- just use it. */ + strncpy (filename, p, len); + filename[len] = 0; + } + + /* Remove trailing slashes */ + while (len > 0 && filename[len-1] == '/') + filename[--len] = 0; + + strcat (filename+len, "/"); + strcat (filename, string); + + fd = open (filename, mode, prot); + if (fd >= 0) break; + } + + done: + if (filename_opened) + if (fd < 0) + *filename_opened = (char *) 0; + else if (filename[0] == '/') + *filename_opened = savestring (filename, strlen (filename)); + else + { + /* Beware the // my son, the Emacs barfs, the botch that catch... */ + + *filename_opened = concat (current_directory, + '/' == current_directory[strlen(current_directory)-1]? "": "/", + filename, NULL); + } + + return fd; +} + +/* Open a source file given a symtab S. Returns a file descriptor + or negative number for error. */ + +static int +open_source_file (s) + struct symtab *s; +{ + char *path = source_path; + char *p; + int result; + char *fullname; + + /* Quick way out if we already know its full name */ + if (s->fullname) + { + result = open (s->fullname, O_RDONLY); + if (result >= 0) + return result; + /* Didn't work -- free old one, try again. */ + mfree (s->objfile->md, s->fullname); + s->fullname = NULL; + } + + if (s->dirname != NULL) + { + /* Replace a path entry of $cdir with the compilation directory name */ +#define cdir_len 5 + /* We cast strstr's result in case an ANSIhole has made it const, + which produces a "required warning" when assigned to a nonconst. */ + p = (char *)strstr (source_path, "$cdir"); + if (p && (p == path || p[-1] == ':') + && (p[cdir_len] == ':' || p[cdir_len] == '\0')) { + int len; + + path = (char *) + alloca (strlen (source_path) + 1 + strlen (s->dirname) + 1); + len = p - source_path; + strncpy (path, source_path, len); /* Before $cdir */ + strcpy (path + len, s->dirname); /* new stuff */ + strcat (path + len, source_path + len + cdir_len); /* After $cdir */ + } + } + + result = openp (path, 0, s->filename, O_RDONLY, 0, &s->fullname); + if (result < 0) + { + /* Didn't work. Try using just the basename. */ + p = basename (s->filename); + if (p != s->filename) + result = openp(path, 0, p, O_RDONLY,0, &s->fullname); + } + if (result >= 0) + { + fullname = s -> fullname; + s -> fullname = mstrsave (s -> objfile -> md, s -> fullname); + free (fullname); + } + return result; +} + + +/* Create and initialize the table S->line_charpos that records + the positions of the lines in the source file, which is assumed + to be open on descriptor DESC. + All set S->nlines to the number of such lines. */ + +static void +find_source_lines (s, desc) + struct symtab *s; + int desc; +{ + struct stat st; + register char *data, *p, *end; + int nlines = 0; + int lines_allocated = 1000; + int *line_charpos; + long exec_mtime; + int size; +#ifdef LSEEK_NOT_LINEAR + char c; +#endif + + line_charpos = (int *) xmmalloc (s -> objfile -> md, + lines_allocated * sizeof (int)); + if (fstat (desc, &st) < 0) + perror_with_name (s->filename); + + if (exec_bfd) { + exec_mtime = bfd_get_mtime(exec_bfd); + if (exec_mtime && exec_mtime < st.st_mtime) + printf_filtered ("Source file is more recent than executable.\n"); + } + +#ifdef LSEEK_NOT_LINEAR + /* Have to read it byte by byte to find out where the chars live */ + + line_charpos[0] = tell(desc); + nlines = 1; + while (myread(desc, &c, 1)>0) + { + if (c == '\n') + { + if (nlines == lines_allocated) + { + lines_allocated *= 2; + line_charpos = + (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos, + sizeof (int) * lines_allocated); + } + line_charpos[nlines++] = tell(desc); + } + } + +#else + /* st_size might be a large type, but we only support source files whose + size fits in an int. FIXME. */ + size = (int) st.st_size; + +#ifdef BROKEN_LARGE_ALLOCA + data = (char *) xmalloc (size); + make_cleanup (free, data); +#else + data = (char *) alloca (size); +#endif + if (myread (desc, data, size) < 0) + perror_with_name (s->filename); + end = data + size; + p = data; + line_charpos[0] = 0; + nlines = 1; + while (p != end) + { + if (*p++ == '\n' + /* A newline at the end does not start a new line. */ + && p != end) + { + if (nlines == lines_allocated) + { + lines_allocated *= 2; + line_charpos = + (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos, + sizeof (int) * lines_allocated); + } + line_charpos[nlines++] = p - data; + } + } +#endif + s->nlines = nlines; + s->line_charpos = + (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos, + nlines * sizeof (int)); + +} + +/* Return the character position of a line LINE in symtab S. + Return 0 if anything is invalid. */ + +#if 0 /* Currently unused */ + +int +source_line_charpos (s, line) + struct symtab *s; + int line; +{ + if (!s) return 0; + if (!s->line_charpos || line <= 0) return 0; + if (line > s->nlines) + line = s->nlines; + return s->line_charpos[line - 1]; +} + +/* Return the line number of character position POS in symtab S. */ + +int +source_charpos_line (s, chr) + register struct symtab *s; + register int chr; +{ + register int line = 0; + register int *lnp; + + if (s == 0 || s->line_charpos == 0) return 0; + lnp = s->line_charpos; + /* Files are usually short, so sequential search is Ok */ + while (line < s->nlines && *lnp <= chr) + { + line++; + lnp++; + } + if (line >= s->nlines) + line = s->nlines; + return line; +} + +#endif /* 0 */ + + +/* Get full pathname and line number positions for a symtab. + Return nonzero if line numbers may have changed. + Set *FULLNAME to actual name of the file as found by `openp', + or to 0 if the file is not found. */ + +static int +get_filename_and_charpos (s, fullname) + struct symtab *s; + char **fullname; +{ + register int desc, linenums_changed = 0; + + desc = open_source_file (s); + if (desc < 0) + { + if (fullname) + *fullname = NULL; + return 0; + } + if (fullname) + *fullname = s->fullname; + if (s->line_charpos == 0) linenums_changed = 1; + if (linenums_changed) find_source_lines (s, desc); + close (desc); + return linenums_changed; +} + +/* Print text describing the full name of the source file S + and the line number LINE and its corresponding character position. + The text starts with two Ctrl-z so that the Emacs-GDB interface + can easily find it. + + MID_STATEMENT is nonzero if the PC is not at the beginning of that line. + + Return 1 if successful, 0 if could not find the file. */ + +int +identify_source_line (s, line, mid_statement, pc) + struct symtab *s; + int line; + int mid_statement; + CORE_ADDR pc; +{ + if (s->line_charpos == 0) + get_filename_and_charpos (s, (char **)NULL); + if (s->fullname == 0) + return 0; + if (line > s->nlines) + /* Don't index off the end of the line_charpos array. */ + return 0; + printf ("\032\032%s:%d:%d:%s:0x%lx\n", s->fullname, + line, s->line_charpos[line - 1], + mid_statement ? "middle" : "beg", + (unsigned long) pc); + current_source_line = line; + first_line_listed = line; + last_line_listed = line; + current_source_symtab = s; + return 1; +} + +/* Print source lines from the file of symtab S, + starting with line number LINE and stopping before line number STOPLINE. */ + +void +print_source_lines (s, line, stopline, noerror) + struct symtab *s; + int line, stopline; + int noerror; +{ + register int c; + register int desc; + register FILE *stream; + int nlines = stopline - line; + + /* Regardless of whether we can open the file, set current_source_symtab. */ + current_source_symtab = s; + current_source_line = line; + first_line_listed = line; + + desc = open_source_file (s); + if (desc < 0) + { + if (! noerror) { + char *name = alloca (strlen (s->filename) + 100); + sprintf (name, "%s:%d", s->filename, line); + print_sys_errmsg (name, errno); + } + return; + } + + if (s->line_charpos == 0) + find_source_lines (s, desc); + + if (line < 1 || line > s->nlines) + { + close (desc); + error ("Line number %d out of range; %s has %d lines.", + line, s->filename, s->nlines); + } + + if (lseek (desc, s->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (s->filename); + } + + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + + while (nlines-- > 0) + { + c = fgetc (stream); + if (c == EOF) break; + last_line_listed = current_source_line; + printf_filtered ("%d\t", current_source_line++); + do + { + if (c < 040 && c != '\t' && c != '\n' && c != '\r') + printf_filtered ("^%c", c + 0100); + else if (c == 0177) + printf_filtered ("^?"); + else + printf_filtered ("%c", c); + } while (c != '\n' && (c = fgetc (stream)) >= 0); + } + + fclose (stream); +} + + + +/* + C++ + Print a list of files and line numbers which a user may choose from + in order to list a function which was specified ambiguously + (as with `list classname::overloadedfuncname', for example). + The vector in SALS provides the filenames and line numbers. + */ +static void +ambiguous_line_spec (sals) + struct symtabs_and_lines *sals; +{ + int i; + + for (i = 0; i < sals->nelts; ++i) + printf_filtered("file: \"%s\", line number: %d\n", + sals->sals[i].symtab->filename, sals->sals[i].line); +} + + +static void +list_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals, sals_end; + struct symtab_and_line sal, sal_end; + struct symbol *sym; + char *arg1; + int no_end = 1; + int dummy_end = 0; + int dummy_beg = 0; + int linenum_beg = 0; + char *p; + + if (!have_full_symbols () && !have_partial_symbols()) + error ("No symbol table is loaded. Use the \"file\" command."); + + /* Pull in a current source symtab if necessary */ + if (current_source_symtab == 0 && + (arg == 0 || arg[0] == '+' || arg[0] == '-')) + select_source_symtab (0); + + /* "l" or "l +" lists next ten lines. */ + + if (arg == 0 || STREQ (arg, "+")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, current_source_line, + current_source_line + lines_to_list, 0); + return; + } + + /* "l -" lists previous ten lines, the ones before the ten just listed. */ + if (STREQ (arg, "-")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, + max (first_line_listed - lines_to_list, 1), + first_line_listed, 0); + return; + } + + /* Now if there is only one argument, decode it in SAL + and set NO_END. + If there are two arguments, decode them in SAL and SAL_END + and clear NO_END; however, if one of the arguments is blank, + set DUMMY_BEG or DUMMY_END to record that fact. */ + + arg1 = arg; + if (*arg1 == ',') + dummy_beg = 1; + else + { + sals = decode_line_1 (&arg1, 0, 0, 0, 0); + + if (! sals.nelts) return; /* C++ */ + if (sals.nelts > 1) + { + ambiguous_line_spec (&sals); + free (sals.sals); + return; + } + + sal = sals.sals[0]; + free (sals.sals); + } + + /* Record whether the BEG arg is all digits. */ + + for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++); + linenum_beg = (p == arg1); + + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == ',') + { + no_end = 0; + arg1++; + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == 0) + dummy_end = 1; + else + { + if (dummy_beg) + sals_end = decode_line_1 (&arg1, 0, 0, 0, 0); + else + sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0); + if (sals_end.nelts == 0) + return; + if (sals_end.nelts > 1) + { + ambiguous_line_spec (&sals_end); + free (sals_end.sals); + return; + } + sal_end = sals_end.sals[0]; + free (sals_end.sals); + } + } + + if (*arg1) + error ("Junk at end of line specification."); + + if (!no_end && !dummy_beg && !dummy_end + && sal.symtab != sal_end.symtab) + error ("Specified start and end are in different files."); + if (dummy_beg && dummy_end) + error ("Two empty args do not say what lines to list."); + + /* if line was specified by address, + first print exactly which line, and which file. + In this case, sal.symtab == 0 means address is outside + of all known source files, not that user failed to give a filename. */ + if (*arg == '*') + { + if (sal.symtab == 0) + error ("No source file for address %s.", + local_hex_string((unsigned long) sal.pc)); + sym = find_pc_function (sal.pc); + if (sym) + { + printf_filtered ("%s is in ", + local_hex_string((unsigned long) sal.pc)); + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout); + printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line); + } + else + printf_filtered ("%s is at %s:%d.\n", + local_hex_string((unsigned long) sal.pc), + sal.symtab->filename, sal.line); + } + + /* If line was not specified by just a line number, + and it does not imply a symtab, it must be an undebuggable symbol + which means no source code. */ + + if (! linenum_beg && sal.symtab == 0) + error ("No line number known for %s.", arg); + + /* If this command is repeated with RET, + turn it into the no-arg variant. */ + + if (from_tty) + *arg = 0; + + if (dummy_beg && sal_end.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + if (dummy_beg) + print_source_lines (sal_end.symtab, + max (sal_end.line - (lines_to_list - 1), 1), + sal_end.line + 1, 0); + else if (sal.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + else if (no_end) + print_source_lines (sal.symtab, + max (sal.line - (lines_to_list / 2), 1), + sal.line + (lines_to_list / 2), 0); + else + print_source_lines (sal.symtab, sal.line, + (dummy_end + ? sal.line + lines_to_list + : sal_end.line + 1), + 0); +} + +/* Print info on range of pc's in a specified line. */ + +static void +line_info (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + CORE_ADDR start_pc, end_pc; + int i; + + if (arg == 0) + { + sal.symtab = current_source_symtab; + sal.line = last_line_listed; + sals.nelts = 1; + sals.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + sals.sals[0] = sal; + } + else + { + sals = decode_line_spec_1 (arg, 0); + + dont_repeat (); + } + + /* C++ More than one line may have been specified, as when the user + specifies an overloaded function name. Print info on them all. */ + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; + + if (sal.symtab == 0) + { + printf_filtered ("No line number information available"); + if (sal.pc != 0) + { + /* This is useful for "info line *0x7f34". If we can't tell the + user about a source line, at least let them have the symbolic + address. */ + printf_filtered (" for address "); + wrap_here (" "); + print_address (sal.pc, stdout); + } + else + printf_filtered ("."); + printf_filtered ("\n"); + } + else if (sal.line > 0 + && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc)) + { + if (start_pc == end_pc) + { + printf_filtered ("Line %d of \"%s\"", + sal.line, sal.symtab->filename); + wrap_here (" "); + printf_filtered (" is at address "); + print_address (start_pc, stdout); + wrap_here (" "); + printf_filtered (" but contains no code.\n"); + } + else + { + printf_filtered ("Line %d of \"%s\"", + sal.line, sal.symtab->filename); + wrap_here (" "); + printf_filtered (" starts at address "); + print_address (start_pc, stdout); + wrap_here (" "); + printf_filtered (" and ends at "); + print_address (end_pc, stdout); + printf_filtered (".\n"); + } + + /* x/i should display this line's code. */ + set_next_address (start_pc); + + /* Repeating "info line" should do the following line. */ + last_line_listed = sal.line + 1; + + /* If this is the only line, show the source code. If it could + not find the file, don't do anything special. */ + if (frame_file_full_name && sals.nelts == 1) + identify_source_line (sal.symtab, sal.line, 0, start_pc); + } + else + /* Is there any case in which we get here, and have an address + which the user would want to see? If we have debugging symbols + and no line numbers? */ + printf_filtered ("Line number %d is out of range for \"%s\".\n", + sal.line, sal.symtab->filename); + } + free (sals.sals); +} + +/* Commands to search the source file for a regexp. */ + +/* ARGSUSED */ +static void +forward_search_command (regex, from_tty) + char *regex; + int from_tty; +{ + register int c; + register int desc; + register FILE *stream; + int line = last_line_listed + 1; + char *msg; + + msg = (char *) re_comp (regex); + if (msg) + error (msg); + + if (current_source_symtab == 0) + select_source_symtab (0); + + /* Search from last_line_listed+1 in current_source_symtab */ + + desc = open_source_file (current_source_symtab); + if (desc < 0) + perror_with_name (current_source_symtab->filename); + + if (current_source_symtab->line_charpos == 0) + find_source_lines (current_source_symtab, desc); + + if (line < 1 || line > current_source_symtab->nlines) + { + close (desc); + error ("Expression not found"); + } + + if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (current_source_symtab->filename); + } + + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + while (1) { +/* FIXME!!! We walk right off the end of buf if we get a long line!!! */ + char buf[4096]; /* Should be reasonable??? */ + register char *p = buf; + + c = getc (stream); + if (c == EOF) + break; + do { + *p++ = c; + } while (c != '\n' && (c = getc (stream)) >= 0); + + /* we now have a source line in buf, null terminate and match */ + *p = 0; + if (re_exec (buf) > 0) + { + /* Match! */ + fclose (stream); + print_source_lines (current_source_symtab, + line, line+1, 0); + current_source_line = max (line - lines_to_list / 2, 1); + return; + } + line++; + } + + printf_filtered ("Expression not found\n"); + fclose (stream); +} + +/* ARGSUSED */ +static void +reverse_search_command (regex, from_tty) + char *regex; + int from_tty; +{ + register int c; + register int desc; + register FILE *stream; + int line = last_line_listed - 1; + char *msg; + + msg = (char *) re_comp (regex); + if (msg) + error (msg); + + if (current_source_symtab == 0) + select_source_symtab (0); + + /* Search from last_line_listed-1 in current_source_symtab */ + + desc = open_source_file (current_source_symtab); + if (desc < 0) + perror_with_name (current_source_symtab->filename); + + if (current_source_symtab->line_charpos == 0) + find_source_lines (current_source_symtab, desc); + + if (line < 1 || line > current_source_symtab->nlines) + { + close (desc); + error ("Expression not found"); + } + + if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (current_source_symtab->filename); + } + + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + while (line > 1) + { +/* FIXME!!! We walk right off the end of buf if we get a long line!!! */ + char buf[4096]; /* Should be reasonable??? */ + register char *p = buf; + + c = getc (stream); + if (c == EOF) + break; + do { + *p++ = c; + } while (c != '\n' && (c = getc (stream)) >= 0); + + /* We now have a source line in buf; null terminate and match. */ + *p = 0; + if (re_exec (buf) > 0) + { + /* Match! */ + fclose (stream); + print_source_lines (current_source_symtab, + line, line+1, 0); + current_source_line = max (line - lines_to_list / 2, 1); + return; + } + line--; + if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0) + { + fclose (stream); + perror_with_name (current_source_symtab->filename); + } + } + + printf_filtered ("Expression not found\n"); + fclose (stream); + return; +} + +void +_initialize_source () +{ + struct cmd_list_element *c; + current_source_symtab = 0; + init_source_path (); + + /* The intention is to use POSIX Basic Regular Expressions. + Always use the GNU regex routine for consistency across all hosts. + Our current GNU regex.c does not have all the POSIX features, so this is + just an approximation. */ + re_set_syntax (RE_SYNTAX_GREP); + + c = add_cmd ("directory", class_files, directory_command, + "Add directory DIR to beginning of search path for source files.\n\ +Forget cached info on source file locations and line positions.\n\ +DIR can also be $cwd for the current working directory, or $cdir for the\n\ +directory in which the source file was compiled into object code.\n\ +With no argument, reset the search path to $cdir:$cwd, the default.", + &cmdlist); + c->completer = filename_completer; + + add_cmd ("directories", no_class, show_directories, + "Current search path for finding source files.\n\ +$cwd in the path means the current working directory.\n\ +$cdir in the path means the compilation directory of the source file.", + &showlist); + + add_info ("source", source_info, + "Information about the current source file."); + + add_info ("line", line_info, + "Core addresses of the code for a source line.\n\ +Line can be specified as\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ +Default is to describe the last source line that was listed.\n\n\ +This sets the default address for \"x\" to the line's first instruction\n\ +so that \"x/i\" suffices to start examining the machine code.\n\ +The address is also stored as the value of \"$_\"."); + + add_com ("forward-search", class_files, forward_search_command, + "Search for regular expression (see regex(3)) from last line listed."); + add_com_alias ("search", "forward-search", class_files, 0); + + add_com ("reverse-search", class_files, reverse_search_command, + "Search backward for regular expression (see regex(3)) from last line listed."); + + add_com ("list", class_files, list_command, + "List specified function or line.\n\ +With no argument, lists ten more lines after or around previous listing.\n\ +\"list -\" lists the ten lines before a previous ten-line listing.\n\ +One argument specifies a line, and ten lines are listed around that line.\n\ +Two arguments with comma between specify starting and ending lines to list.\n\ +Lines can be specified in these ways:\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ + *ADDRESS, to list around the line containing that address.\n\ +With two args if one is empty it stands for ten lines away from the other arg."); + add_com_alias ("l", "list", class_files, 1); + + add_show_from_set + (add_set_cmd ("listsize", class_support, var_uinteger, + (char *)&lines_to_list, + "Set number of source lines gdb will list by default.", + &setlist), + &showlist); +} diff --git a/gnu/usr.bin/gdb/gdb/stabsread.c b/gnu/usr.bin/gdb/gdb/stabsread.c new file mode 100644 index 00000000000..e81c314b6de --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/stabsread.c @@ -0,0 +1,3770 @@ +/* Support routines for decoding "stabs" debugging information format. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993 + 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. */ + +/* Support routines for reading and decoding debugging information in + the "stabs" format. This format is used with many systems that use + the a.out object file format, as well as some systems that use + COFF or ELF where the stabs data is placed in a special section. + Avoid placing any object file format specific code in this file. */ + +#include "defs.h" +#include "bfd.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "symfile.h" +#include "objfiles.h" +#include "aout/stab_gnu.h" /* We always use GNU stabs, not native */ +#include "buildsym.h" +#include "complaints.h" +#include "demangle.h" + +#include + +/* Ask stabsread.h to define the vars it normally declares `extern'. */ +#define EXTERN /**/ +#include "stabsread.h" /* Our own declarations */ +#undef EXTERN + +/* The routines that read and process a complete stabs for a C struct or + C++ class pass lists of data member fields and lists of member function + fields in an instance of a field_info structure, as defined below. + This is part of some reorganization of low level C++ support and is + expected to eventually go away... (FIXME) */ + +struct field_info +{ + struct nextfield + { + struct nextfield *next; + int visibility; + struct field field; + } *list; + struct next_fnfieldlist + { + struct next_fnfieldlist *next; + struct fn_fieldlist fn_fieldlist; + } *fnlist; +}; + +static struct type * +dbx_alloc_type PARAMS ((int [2], struct objfile *)); + +static long read_huge_number PARAMS ((char **, int, int *)); + +static struct type *error_type PARAMS ((char **)); + +static void +patch_block_stabs PARAMS ((struct pending *, struct pending_stabs *, + struct objfile *)); + +static void +fix_common_block PARAMS ((struct symbol *, int)); + +static int +read_type_number PARAMS ((char **, int *)); + +static struct type * +read_range_type PARAMS ((char **, int [2], struct objfile *)); + +static struct type * +read_sun_builtin_type PARAMS ((char **, int [2], struct objfile *)); + +static struct type * +read_sun_floating_type PARAMS ((char **, int [2], struct objfile *)); + +static struct type * +read_enum_type PARAMS ((char **, struct type *, struct objfile *)); + +static struct type * +rs6000_builtin_type PARAMS ((int)); + +static int +read_member_functions PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +read_struct_fields PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +read_baseclasses PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +read_tilde_fields PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +attach_fn_fields_to_type PARAMS ((struct field_info *, struct type *)); + +static int +attach_fields_to_type PARAMS ((struct field_info *, struct type *, + struct objfile *)); + +static struct type * +read_struct_type PARAMS ((char **, struct type *, struct objfile *)); + +static struct type * +read_array_type PARAMS ((char **, struct type *, struct objfile *)); + +static struct type ** +read_args PARAMS ((char **, int, struct objfile *)); + +static int +read_cpp_abbrev PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' }; +static const char vb_name[] = { '_','v','b',CPLUS_MARKER,'\0' }; + +/* Define this as 1 if a pcc declaration of a char or short argument + gives the correct address. Otherwise assume pcc gives the + address of the corresponding int, which is not the same on a + big-endian machine. */ + +#ifndef BELIEVE_PCC_PROMOTION +#define BELIEVE_PCC_PROMOTION 0 +#endif + +#if 0 +/* I think this can go away, all current uses have been removed. + GCC emits a few crazy types which can only be distinguished by the + name (complex, long long on some machines), but I'd say fix GCC. */ + +/* During some calls to read_type (and thus to read_range_type), this + contains the name of the type being defined. Range types are only + used in C as basic types. We use the name to distinguish the otherwise + identical basic types "int" and "long" and their unsigned versions. + FIXME, this should disappear with better type management. */ + +static char *long_kludge_name; +#endif + +#if 0 +struct complaint dbx_class_complaint = +{ + "encountered DBX-style class variable debugging information.\n\ +You seem to have compiled your program with \ +\"g++ -g0\" instead of \"g++ -g\".\n\ +Therefore GDB will not know about your class variables", 0, 0 +}; +#endif + +struct complaint invalid_cpp_abbrev_complaint = + {"invalid C++ abbreviation `%s'", 0, 0}; + +struct complaint invalid_cpp_type_complaint = + {"C++ abbreviated type name unknown at symtab pos %d", 0, 0}; + +struct complaint member_fn_complaint = + {"member function type missing, got '%c'", 0, 0}; + +struct complaint const_vol_complaint = + {"const/volatile indicator missing, got '%c'", 0, 0}; + +struct complaint error_type_complaint = + {"debug info mismatch between compiler and debugger", 0, 0}; + +struct complaint invalid_member_complaint = + {"invalid (minimal) member type data format at symtab pos %d.", 0, 0}; + +struct complaint range_type_base_complaint = + {"base type %d of range type is not defined", 0, 0}; + +struct complaint reg_value_complaint = + {"register number too large in symbol %s", 0, 0}; + +struct complaint vtbl_notfound_complaint = + {"virtual function table pointer not found when defining class `%s'", 0, 0}; + +struct complaint unrecognized_cplus_name_complaint = + {"Unknown C++ symbol name `%s'", 0, 0}; + +struct complaint rs6000_builtin_complaint = + {"Unknown builtin type %d", 0, 0}; + +struct complaint stabs_general_complaint = + {"%s", 0, 0}; + +/* Make a list of forward references which haven't been defined. */ + +static struct type **undef_types; +static int undef_types_allocated; +static int undef_types_length; + +/* Check for and handle cretinous stabs symbol name continuation! */ +#define STABS_CONTINUE(pp) \ + do { \ + if (**(pp) == '\\') *(pp) = next_symbol_text (); \ + } while (0) + + +/* Look up a dbx type-number pair. Return the address of the slot + where the type for that number-pair is stored. + The number-pair is in TYPENUMS. + + This can be used for finding the type associated with that pair + or for associating a new type with the pair. */ + +struct type ** +dbx_lookup_type (typenums) + int typenums[2]; +{ + register int filenum = typenums[0]; + register int index = typenums[1]; + unsigned old_len; + register int real_filenum; + register struct header_file *f; + int f_orig_length; + + if (filenum == -1) /* -1,-1 is for temporary types. */ + return 0; + + if (filenum < 0 || filenum >= n_this_object_header_files) + { + static struct complaint msg = {"\ +Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.", + 0, 0}; + complain (&msg, filenum, index, symnum); + goto error_return; + } + + if (filenum == 0) + { + if (index < 0) + { + /* Caller wants address of address of type. We think + that negative (rs6k builtin) types will never appear as + "lvalues", (nor should they), so we stuff the real type + pointer into a temp, and return its address. If referenced, + this will do the right thing. */ + static struct type *temp_type; + + temp_type = rs6000_builtin_type(index); + return &temp_type; + } + + /* Type is defined outside of header files. + Find it in this object file's type vector. */ + if (index >= type_vector_length) + { + old_len = type_vector_length; + if (old_len == 0) + { + type_vector_length = INITIAL_TYPE_VECTOR_LENGTH; + type_vector = (struct type **) + malloc (type_vector_length * sizeof (struct type *)); + } + while (index >= type_vector_length) + { + type_vector_length *= 2; + } + type_vector = (struct type **) + xrealloc ((char *) type_vector, + (type_vector_length * sizeof (struct type *))); + memset (&type_vector[old_len], 0, + (type_vector_length - old_len) * sizeof (struct type *)); + } + return (&type_vector[index]); + } + else + { + real_filenum = this_object_header_files[filenum]; + + if (real_filenum >= n_header_files) + { + struct type *temp_type; + struct type **temp_type_p; + + warning ("GDB internal error: bad real_filenum"); + + error_return: + temp_type = init_type (TYPE_CODE_ERROR, 0, 0, NULL, NULL); + temp_type_p = (struct type **) xmalloc (sizeof (struct type *)); + *temp_type_p = temp_type; + return temp_type_p; + } + + f = &header_files[real_filenum]; + + f_orig_length = f->length; + if (index >= f_orig_length) + { + while (index >= f->length) + { + f->length *= 2; + } + f->vector = (struct type **) + xrealloc ((char *) f->vector, f->length * sizeof (struct type *)); + memset (&f->vector[f_orig_length], 0, + (f->length - f_orig_length) * sizeof (struct type *)); + } + return (&f->vector[index]); + } +} + +/* Make sure there is a type allocated for type numbers TYPENUMS + and return the type object. + This can create an empty (zeroed) type object. + TYPENUMS may be (-1, -1) to return a new type object that is not + put into the type vector, and so may not be referred to by number. */ + +static struct type * +dbx_alloc_type (typenums, objfile) + int typenums[2]; + struct objfile *objfile; +{ + register struct type **type_addr; + + if (typenums[0] == -1) + { + return (alloc_type (objfile)); + } + + type_addr = dbx_lookup_type (typenums); + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (*type_addr == 0) + { + *type_addr = alloc_type (objfile); + } + + return (*type_addr); +} + +/* for all the stabs in a given stab vector, build appropriate types + and fix their symbols in given symbol vector. */ + +static void +patch_block_stabs (symbols, stabs, objfile) + struct pending *symbols; + struct pending_stabs *stabs; + struct objfile *objfile; +{ + int ii; + char *name; + char *pp; + struct symbol *sym; + + if (stabs) + { + + /* for all the stab entries, find their corresponding symbols and + patch their types! */ + + for (ii = 0; ii < stabs->count; ++ii) + { + name = stabs->stab[ii]; + pp = (char*) strchr (name, ':'); + sym = find_symbol_in_list (symbols, name, pp-name); + if (!sym) + { + /* On xcoff, if a global is defined and never referenced, + ld will remove it from the executable. There is then + a N_GSYM stab for it, but no regular (C_EXT) symbol. */ + sym = (struct symbol *) + obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; + SYMBOL_NAME (sym) = + obstack_copy0 (&objfile->symbol_obstack, name, pp - name); + pp += 2; + if (*(pp-1) == 'F' || *(pp-1) == 'f') + { + /* I don't think the linker does this with functions, + so as far as I know this is never executed. + But it doesn't hurt to check. */ + SYMBOL_TYPE (sym) = + lookup_function_type (read_type (&pp, objfile)); + } + else + { + SYMBOL_TYPE (sym) = read_type (&pp, objfile); + } + add_symbol_to_list (sym, &global_symbols); + } + else + { + pp += 2; + if (*(pp-1) == 'F' || *(pp-1) == 'f') + { + SYMBOL_TYPE (sym) = + lookup_function_type (read_type (&pp, objfile)); + } + else + { + SYMBOL_TYPE (sym) = read_type (&pp, objfile); + } + } + } + } +} + + +/* Read a number by which a type is referred to in dbx data, + or perhaps read a pair (FILENUM, TYPENUM) in parentheses. + Just a single number N is equivalent to (0,N). + Return the two numbers by storing them in the vector TYPENUMS. + TYPENUMS will then be used as an argument to dbx_lookup_type. + + Returns 0 for success, -1 for error. */ + +static int +read_type_number (pp, typenums) + register char **pp; + register int *typenums; +{ + int nbits; + if (**pp == '(') + { + (*pp)++; + typenums[0] = read_huge_number (pp, ',', &nbits); + if (nbits != 0) return -1; + typenums[1] = read_huge_number (pp, ')', &nbits); + if (nbits != 0) return -1; + } + else + { + typenums[0] = 0; + typenums[1] = read_huge_number (pp, 0, &nbits); + if (nbits != 0) return -1; + } + return 0; +} + + +/* To handle GNU C++ typename abbreviation, we need to be able to + fill in a type's name as soon as space for that type is allocated. + `type_synonym_name' is the name of the type being allocated. + It is cleared as soon as it is used (lest all allocated types + get this name). */ + +static char *type_synonym_name; + +/* ARGSUSED */ +struct symbol * +define_symbol (valu, string, desc, type, objfile) + CORE_ADDR valu; + char *string; + int desc; + int type; + struct objfile *objfile; +{ + register struct symbol *sym; + char *p = (char *) strchr (string, ':'); + int deftype; + int synonym = 0; + register int i; + + /* We would like to eliminate nameless symbols, but keep their types. + E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer + to type 2, but, should not create a symbol to address that type. Since + the symbol will be nameless, there is no way any user can refer to it. */ + + int nameless; + + /* Ignore syms with empty names. */ + if (string[0] == 0) + return 0; + + /* Ignore old-style symbols from cc -go */ + if (p == 0) + return 0; + + /* If a nameless stab entry, all we need is the type, not the symbol. + e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */ + nameless = (p == string || ((string[0] == ' ') && (string[1] == ':'))); + + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + + if (processing_gcc_compilation) + { + /* GCC 2.x puts the line number in desc. SunOS apparently puts in the + number of bytes occupied by a type or object, which we ignore. */ + SYMBOL_LINE(sym) = desc; + } + else + { + SYMBOL_LINE(sym) = 0; /* unknown */ + } + + if (string[0] == CPLUS_MARKER) + { + /* Special GNU C++ names. */ + switch (string[1]) + { + case 't': + SYMBOL_NAME (sym) = obsavestring ("this", strlen ("this"), + &objfile -> symbol_obstack); + break; + + case 'v': /* $vtbl_ptr_type */ + /* Was: SYMBOL_NAME (sym) = "vptr"; */ + goto normal; + + case 'e': + SYMBOL_NAME (sym) = obsavestring ("eh_throw", strlen ("eh_throw"), + &objfile -> symbol_obstack); + break; + + case '_': + /* This was an anonymous type that was never fixed up. */ + goto normal; + + default: + complain (&unrecognized_cplus_name_complaint, string); + goto normal; /* Do *something* with it */ + } + } + else + { + normal: + SYMBOL_LANGUAGE (sym) = current_subfile -> language; + SYMBOL_NAME (sym) = (char *) + obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1)); + /* Open-coded memcpy--saves function call time. */ + /* FIXME: Does it really? Try replacing with simple strcpy and + try it on an executable with a large symbol table. */ + /* FIXME: considering that gcc can open code memcpy anyway, I + doubt it. xoxorich. */ + { + register char *p1 = string; + register char *p2 = SYMBOL_NAME (sym); + while (p1 != p) + { + *p2++ = *p1++; + } + *p2++ = '\0'; + } + + /* If this symbol is from a C++ compilation, then attempt to cache the + demangled form for future reference. This is a typical time versus + space tradeoff, that was decided in favor of time because it sped up + C++ symbol lookups by a factor of about 20. */ + + SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack); + } + p++; + + /* Determine the type of name being defined. */ +#if 0 + /* Getting GDB to correctly skip the symbol on an undefined symbol + descriptor and not ever dump core is a very dodgy proposition if + we do things this way. I say the acorn RISC machine can just + fix their compiler. */ + /* The Acorn RISC machine's compiler can put out locals that don't + start with "234=" or "(3,4)=", so assume anything other than the + deftypes we know how to handle is a local. */ + if (!strchr ("cfFGpPrStTvVXCR", *p)) +#else + if (isdigit (*p) || *p == '(' || *p == '-') +#endif + deftype = 'l'; + else + deftype = *p++; + + switch (deftype) + { + case 'c': + /* c is a special case, not followed by a type-number. + SYMBOL:c=iVALUE for an integer constant symbol. + SYMBOL:c=rVALUE for a floating constant symbol. + SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + if (*p != '=') + { + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = error_type (&p); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + return sym; + } + ++p; + switch (*p++) + { + case 'r': + { + double d = atof (p); + char *dbl_valu; + + /* FIXME: lookup_fundamental_type is a hack. We should be + creating a type especially for the type of float constants. + Problem is, what type should it be? We currently have to + read this in host floating point format, but what type + represents a host format "double"? + + Also, what should the name of this type be? Should we + be using 'S' constants (see stabs.texinfo) instead? */ + + SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile, + FT_DBL_PREC_FLOAT); + dbl_valu = (char *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (double)); + memcpy (dbl_valu, &d, sizeof (double)); + /* Put it in target byte order, but it's still in host + floating point format. */ + SWAP_TARGET_AND_HOST (dbl_valu, sizeof (double)); + SYMBOL_VALUE_BYTES (sym) = dbl_valu; + SYMBOL_CLASS (sym) = LOC_CONST_BYTES; + } + break; + case 'i': + { + /* Defining integer constants this way is kind of silly, + since 'e' constants allows the compiler to give not + only the value, but the type as well. C has at least + int, long, unsigned int, and long long as constant + types; other languages probably should have at least + unsigned as well as signed constants. */ + + /* We just need one int constant type for all objfiles. + It doesn't depend on languages or anything (arguably its + name should be a language-specific name for a type of + that size, but I'm inclined to say that if the compiler + wants a nice name for the type, it can use 'e'). */ + static struct type *int_const_type; + + /* Yes, this is as long as a *host* int. That is because we + use atoi. */ + if (int_const_type == NULL) + int_const_type = + init_type (TYPE_CODE_INT, + sizeof (int) * HOST_CHAR_BIT / TARGET_CHAR_BIT, 0, + "integer constant", + (struct objfile *)NULL); + SYMBOL_TYPE (sym) = int_const_type; + SYMBOL_VALUE (sym) = atoi (p); + SYMBOL_CLASS (sym) = LOC_CONST; + } + break; + case 'e': + /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value + can be represented as integral. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + { + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + if (*p != ',') + { + SYMBOL_TYPE (sym) = error_type (&p); + break; + } + ++p; + + /* If the value is too big to fit in an int (perhaps because + it is unsigned), or something like that, we silently get + a bogus value. The type and everything else about it is + correct. Ideally, we should be using whatever we have + available for parsing unsigned and long long values, + however. */ + SYMBOL_VALUE (sym) = atoi (p); + } + break; + default: + { + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = error_type (&p); + } + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + return sym; + + case 'C': + /* The name of a caught exception. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_LABEL; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE_ADDRESS (sym) = valu; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'f': + /* A static function definition. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + /* fall into process_function_types. */ + + process_function_types: + /* Function result types are described as the result type in stabs. + We need to convert this to the function-returning-type-X type + in GDB. E.g. "int" is converted to "function returning int". */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_FUNC) + { +#if 0 + /* This code doesn't work -- it needs to realloc and can't. */ + /* Attempt to set up to record a function prototype... */ + struct type *new = alloc_type (objfile); + + /* Generate a template for the type of this function. The + types of the arguments will be added as we read the symbol + table. */ + *new = *lookup_function_type (SYMBOL_TYPE(sym)); + SYMBOL_TYPE(sym) = new; + TYPE_OBJFILE (new) = objfile; + in_function_type = new; +#else + SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym)); +#endif + } + /* fall into process_prototype_types */ + + process_prototype_types: + /* Sun acc puts declared types of arguments here. We don't care + about their actual types (FIXME -- we should remember the whole + function prototype), but the list may define some new types + that we have to remember, so we must scan it now. */ + while (*p == ';') { + p++; + read_type (&p, objfile); + } + break; + + case 'F': + /* A global function definition. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &global_symbols); + goto process_function_types; + + case 'G': + /* For a class G (global) symbol, it appears that the + value is not correct. It is necessary to search for the + corresponding linker definition to find the value. + These definitions appear at the end of the namelist. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + i = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i]; + global_sym_chain[i] = sym; + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &global_symbols); + break; + + /* This case is faked by a conditional above, + when there is no code letter in the dbx data. + Dbx data never actually contains 'l'. */ + case 'l': + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_LOCAL; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'p': + if (*p == 'F') + /* pF is a two-letter code that means a function parameter in Fortran. + The type-number specifies the type of the return value. + Translate it into a pointer-to-function type. */ + { + p++; + SYMBOL_TYPE (sym) + = lookup_pointer_type + (lookup_function_type (read_type (&p, objfile))); + } + else + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + /* Normally this is a parameter, a LOC_ARG. On the i960, it + can also be a LOC_LOCAL_ARG depending on symbol type. */ +#ifndef DBX_PARM_SYMBOL_CLASS +#define DBX_PARM_SYMBOL_CLASS(type) LOC_ARG +#endif + + SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type); + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; +#if 0 + /* This doesn't work yet. */ + add_param_to_type (&in_function_type, sym); +#endif + add_symbol_to_list (sym, &local_symbols); + +#if TARGET_BYTE_ORDER == LITTLE_ENDIAN + /* On little-endian machines, this crud is never necessary, and, + if the extra bytes contain garbage, is harmful. */ + break; +#else /* Big endian. */ + /* If it's gcc-compiled, if it says `short', believe it. */ + if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION) + break; + +#if !BELIEVE_PCC_PROMOTION + { + /* This is the signed type which arguments get promoted to. */ + static struct type *pcc_promotion_type; + /* This is the unsigned type which arguments get promoted to. */ + static struct type *pcc_unsigned_promotion_type; + + /* Call it "int" because this is mainly C lossage. */ + if (pcc_promotion_type == NULL) + pcc_promotion_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", NULL); + + if (pcc_unsigned_promotion_type == NULL) + pcc_unsigned_promotion_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", NULL); + +#if defined(BELIEVE_PCC_PROMOTION_TYPE) + /* This macro is defined on machines (e.g. sparc) where + we should believe the type of a PCC 'short' argument, + but shouldn't believe the address (the address is + the address of the corresponding int). Note that + this is only different from the BELIEVE_PCC_PROMOTION + case on big-endian machines. + + My guess is that this correction, as opposed to changing + the parameter to an 'int' (as done below, for PCC + on most machines), is the right thing to do + on all machines, but I don't want to risk breaking + something that already works. On most PCC machines, + the sparc problem doesn't come up because the calling + function has to zero the top bytes (not knowing whether + the called function wants an int or a short), so there + is no practical difference between an int and a short + (except perhaps what happens when the GDB user types + "print short_arg = 0x10000;"). + + Hacked for SunOS 4.1 by gnu@cygnus.com. In 4.1, the compiler + actually produces the correct address (we don't need to fix it + up). I made this code adapt so that it will offset the symbol + if it was pointing at an int-aligned location and not + otherwise. This way you can use the same gdb for 4.0.x and + 4.1 systems. + + If the parameter is shorter than an int, and is integral + (e.g. char, short, or unsigned equivalent), and is claimed to + be passed on an integer boundary, don't believe it! Offset the + parameter's address to the tail-end of that integer. */ + + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT + && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (pcc_promotion_type)) + { + SYMBOL_VALUE (sym) += TYPE_LENGTH (pcc_promotion_type) + - TYPE_LENGTH (SYMBOL_TYPE (sym)); + } + break; + +#else /* no BELIEVE_PCC_PROMOTION_TYPE. */ + + /* If PCC says a parameter is a short or a char, + it is really an int. */ + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT) + { + SYMBOL_TYPE (sym) = + TYPE_UNSIGNED (SYMBOL_TYPE (sym)) + ? pcc_unsigned_promotion_type + : pcc_promotion_type; + } + break; + +#endif /* no BELIEVE_PCC_PROMOTION_TYPE. */ + } +#endif /* !BELIEVE_PCC_PROMOTION. */ +#endif /* Big endian. */ + + case 'P': + /* acc seems to use P to delare the prototypes of functions that + are referenced by this file. gdb is not prepared to deal + with this extra information. FIXME, it ought to. */ + if (type == N_FUN) + { + read_type (&p, objfile); + goto process_prototype_types; + } + /*FALLTHROUGH*/ + + case 'R': + /* Parameter which is in a register. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REGPARM; + SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu); + if (SYMBOL_VALUE (sym) >= NUM_REGS) + { + complain (®_value_complaint, SYMBOL_SOURCE_NAME (sym)); + SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */ + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'r': + /* Register variable (either global or local). */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu); + if (SYMBOL_VALUE (sym) >= NUM_REGS) + { + complain (®_value_complaint, SYMBOL_SOURCE_NAME (sym)); + SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */ + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + if (within_function) + { + /* Sun cc uses a pair of symbols, one 'p' and one 'r' with the same + name to represent an argument passed in a register. + GCC uses 'P' for the same case. So if we find such a symbol pair + we combine it into one 'P' symbol. + Note that this code illegally combines + main(argc) int argc; { register int argc = 1; } + but this case is considered pathological and causes a warning + from a decent compiler. */ + if (local_symbols + && local_symbols->nsyms > 0) + { + struct symbol *prev_sym; + prev_sym = local_symbols->symbol[local_symbols->nsyms - 1]; + if (SYMBOL_CLASS (prev_sym) == LOC_ARG + && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym))) + { + SYMBOL_CLASS (prev_sym) = LOC_REGPARM; + SYMBOL_VALUE (prev_sym) = SYMBOL_VALUE (sym); + sym = prev_sym; + break; + } + } + add_symbol_to_list (sym, &local_symbols); + } + else + add_symbol_to_list (sym, &file_symbols); + break; + + case 'S': + /* Static symbol at top level of file */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + + case 't': +#if 0 + /* See comment where long_kludge_name is declared. */ + /* Here we save the name of the symbol for read_range_type, which + ends up reading in the basic types. In stabs, unfortunately there + is no distinction between "int" and "long" types except their + names. Until we work out a saner type policy (eliminating most + builtin types and using the names specified in the files), we + save away the name so that far away from here in read_range_type, + we can examine it to decide between "int" and "long". FIXME. */ + long_kludge_name = SYMBOL_NAME (sym); +#endif + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + /* For a nameless type, we don't want a create a symbol, thus we + did not use `sym'. Return without further processing. */ + if (nameless) return NULL; + + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + /* C++ vagaries: we may have a type which is derived from + a base type which did not have its name defined when the + derived class was output. We fill in the derived class's + base part member's name here in that case. */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) != NULL) + if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION) + && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym))) + { + int j; + for (j = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)) - 1; j >= 0; j--) + if (TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) == 0) + TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) = + type_name_no_tag (TYPE_BASECLASS (SYMBOL_TYPE (sym), j)); + } + + if (TYPE_NAME (SYMBOL_TYPE (sym)) == NULL) + { + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; PCC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type number + defined in the 't' symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + } + else + TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NAME (sym); + } + + add_symbol_to_list (sym, &file_symbols); + break; + + case 'T': + /* Struct, union, or enum tag. For GNU C++, this can be be followed + by 't' which means we are typedef'ing it as well. */ + synonym = *p == 't'; + + if (synonym) + { + p++; + type_synonym_name = obsavestring (SYMBOL_NAME (sym), + strlen (SYMBOL_NAME (sym)), + &objfile -> symbol_obstack); + } + + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + /* For a nameless type, we don't want a create a symbol, thus we + did not use `sym'. Return without further processing. */ + if (nameless) return NULL; + + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0) + TYPE_TAG_NAME (SYMBOL_TYPE (sym)) + = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym)); + add_symbol_to_list (sym, &file_symbols); + + if (synonym) + { + /* Clone the sym and then modify it. */ + register struct symbol *typedef_sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + *typedef_sym = *sym; + SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF; + SYMBOL_VALUE (typedef_sym) = valu; + SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym)); + add_symbol_to_list (typedef_sym, &file_symbols); + } + break; + + case 'V': + /* Static symbol of local scope */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'v': + /* Reference parameter */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REF_ARG; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'X': + /* This is used by Sun FORTRAN for "function result value". + Sun claims ("dbx and dbxtool interfaces", 2nd ed) + that Pascal uses it too, but when I tried it Pascal used + "x:3" (local symbol) instead. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_LOCAL; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + default: + SYMBOL_TYPE (sym) = error_type (&p); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_VALUE (sym) = 0; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + } + + /* When passing structures to a function, some systems sometimes pass + the address in a register, not the structure itself. + + If REG_STRUCT_HAS_ADDR yields non-zero we have to convert LOC_REGPARM + to LOC_REGPARM_ADDR for structures and unions. */ + +#if !defined (REG_STRUCT_HAS_ADDR) +#define REG_STRUCT_HAS_ADDR(gcc_p) 0 +#endif + + if (SYMBOL_CLASS (sym) == LOC_REGPARM + && REG_STRUCT_HAS_ADDR (processing_gcc_compilation) + && ( (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT) + || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION))) + SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR; + + return sym; +} + + +/* Skip rest of this symbol and return an error type. + + General notes on error recovery: error_type always skips to the + end of the symbol (modulo cretinous dbx symbol name continuation). + Thus code like this: + + if (*(*pp)++ != ';') + return error_type (pp); + + is wrong because if *pp starts out pointing at '\0' (typically as the + result of an earlier error), it will be incremented to point to the + start of the next symbol, which might produce strange results, at least + if you run off the end of the string table. Instead use + + if (**pp != ';') + return error_type (pp); + ++*pp; + + or + + if (**pp != ';') + foo = error_type (pp); + else + ++*pp; + + And in case it isn't obvious, the point of all this hair is so the compiler + can define new types and new syntaxes, and old versions of the + debugger will be able to read the new symbol tables. */ + +static struct type * +error_type (pp) + char **pp; +{ + complain (&error_type_complaint); + while (1) + { + /* Skip to end of symbol. */ + while (**pp != '\0') + { + (*pp)++; + } + + /* Check for and handle cretinous dbx symbol name continuation! */ + if ((*pp)[-1] == '\\') + { + *pp = next_symbol_text (); + } + else + { + break; + } + } + return (builtin_type_error); +} + + +/* Read type information or a type definition; return the type. Even + though this routine accepts either type information or a type + definition, the distinction is relevant--some parts of stabsread.c + assume that type information starts with a digit, '-', or '(' in + deciding whether to call read_type. */ + +struct type * +read_type (pp, objfile) + register char **pp; + struct objfile *objfile; +{ + register struct type *type = 0; + struct type *type1; + int typenums[2]; + int xtypenums[2]; + char type_descriptor; + + /* Size in bits of type if specified by a type attribute, or -1 if + there is no size attribute. */ + int type_size = -1; + + /* Read type number if present. The type number may be omitted. + for instance in a two-dimensional array declared with type + "ar1;1;10;ar1;1;10;4". */ + if ((**pp >= '0' && **pp <= '9') + || **pp == '(' + || **pp == '-') + { + if (read_type_number (pp, typenums) != 0) + return error_type (pp); + + /* Type is not being defined here. Either it already exists, + or this is a forward reference to it. dbx_alloc_type handles + both cases. */ + if (**pp != '=') + return dbx_alloc_type (typenums, objfile); + + /* Type is being defined here. */ + /* Skip the '='. */ + ++(*pp); + + while (**pp == '@') + { + char *p = *pp + 1; + /* It might be a type attribute or a member type. */ + if (isdigit (*p) || *p == '(' || *p == '-') + /* Member type. */ + break; + else + { + /* Type attributes. */ + char *attr = p; + + /* Skip to the semicolon. */ + while (*p != ';' && *p != '\0') + ++p; + *pp = p; + if (*p == '\0') + return error_type (pp); + else + /* Skip the semicolon. */ + ++*pp; + + switch (*attr) + { + case 's': + type_size = atoi (attr + 1); + if (type_size <= 0) + type_size = -1; + break; + default: + /* Ignore unrecognized type attributes, so future compilers + can invent new ones. */ + break; + } + } + } + /* Skip the type descriptor, we get it below with (*pp)[-1]. */ + ++(*pp); + } + else + { + /* 'typenums=' not present, type is anonymous. Read and return + the definition, but don't put it in the type vector. */ + typenums[0] = typenums[1] = -1; + (*pp)++; + } + + type_descriptor = (*pp)[-1]; + switch (type_descriptor) + { + case 'x': + { + enum type_code code; + + /* Used to index through file_symbols. */ + struct pending *ppt; + int i; + + /* Name including "struct", etc. */ + char *type_name; + + { + char *from, *to; + + /* Set the type code according to the following letter. */ + switch ((*pp)[0]) + { + case 's': + code = TYPE_CODE_STRUCT; + break; + case 'u': + code = TYPE_CODE_UNION; + break; + case 'e': + code = TYPE_CODE_ENUM; + break; + default: + return error_type (pp); + } + + to = type_name = (char *) + obstack_alloc (&objfile -> type_obstack, + (((char *) strchr (*pp, ':') - (*pp)) + 1)); + + /* Copy the name. */ + from = *pp + 1; + while ((*to++ = *from++) != ':') + ; + *--to = '\0'; + + /* Set the pointer ahead of the name which we just read. */ + *pp = from; + } + + /* Now check to see whether the type has already been declared. */ + /* This is necessary at least in the case where the + program says something like + struct foo bar[5]; + The compiler puts out a cross-reference; we better find + set the length of the structure correctly so we can + set the length of the array. */ + for (ppt = file_symbols; ppt; ppt = ppt->next) + for (i = 0; i < ppt->nsyms; i++) + { + struct symbol *sym = ppt->symbol[i]; + + if (SYMBOL_CLASS (sym) == LOC_TYPEDEF + && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE + && (TYPE_CODE (SYMBOL_TYPE (sym)) == code) + && STREQ (SYMBOL_NAME (sym), type_name)) + { + obstack_free (&objfile -> type_obstack, type_name); + type = SYMBOL_TYPE (sym); + return type; + } + } + + /* Didn't find the type to which this refers, so we must + be dealing with a forward reference. Allocate a type + structure for it, and keep track of it so we can + fill in the rest of the fields when we get the full + type. */ + type = dbx_alloc_type (typenums, objfile); + TYPE_CODE (type) = code; + TYPE_TAG_NAME (type) = type_name; + INIT_CPLUS_SPECIFIC(type); + TYPE_FLAGS (type) |= TYPE_FLAG_STUB; + + add_undefined_type (type); + return type; + } + + case '-': /* RS/6000 built-in type */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '(': + + (*pp)--; + if (read_type_number (pp, xtypenums) != 0) + return error_type (pp); + + if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1]) + /* It's being defined as itself. That means it is "void". */ + type = init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile); + else + { + struct type *xtype = *dbx_lookup_type (xtypenums); + + /* This can happen if we had '-' followed by a garbage character, + for example. */ + if (xtype == NULL) + return error_type (pp); + + /* The type is being defined to another type. So we copy the type. + This loses if we copy a C++ class and so we lose track of how + the names are mangled (but g++ doesn't output stabs like this + now anyway). */ + + type = alloc_type (objfile); + memcpy (type, xtype, sizeof (struct type)); + + /* The idea behind clearing the names is that the only purpose + for defining a type to another type is so that the name of + one can be different. So we probably don't need to worry much + about the case where the compiler doesn't give a name to the + new type. */ + TYPE_NAME (type) = NULL; + TYPE_TAG_NAME (type) = NULL; + } + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + /* In the following types, we must be sure to overwrite any existing + type that the typenums refer to, rather than allocating a new one + and making the typenums point to the new one. This is because there + may already be pointers to the existing type (if it had been + forward-referenced), and we must change it to a pointer, function, + reference, or whatever, *in-place*. */ + + case '*': + type1 = read_type (pp, objfile); + type = make_pointer_type (type1, dbx_lookup_type (typenums)); + break; + + case '&': /* Reference to another type */ + type1 = read_type (pp, objfile); + type = make_reference_type (type1, dbx_lookup_type (typenums)); + break; + + case 'f': /* Function returning another type */ + type1 = read_type (pp, objfile); + type = make_function_type (type1, dbx_lookup_type (typenums)); + break; + + case 'k': /* Const qualifier on some type (Sun) */ + type = read_type (pp, objfile); + /* FIXME! For now, we ignore const and volatile qualifiers. */ + break; + + case 'B': /* Volatile qual on some type (Sun) */ + type = read_type (pp, objfile); + /* FIXME! For now, we ignore const and volatile qualifiers. */ + break; + +/* FIXME -- we should be doing smash_to_XXX types here. */ + case '@': /* Member (class & variable) type */ + { + struct type *domain = read_type (pp, objfile); + struct type *memtype; + + if (**pp != ',') + /* Invalid member type data format. */ + return error_type (pp); + ++*pp; + + memtype = read_type (pp, objfile); + type = dbx_alloc_type (typenums, objfile); + smash_to_member_type (type, domain, memtype); + } + break; + + case '#': /* Method (class & fn) type */ + if ((*pp)[0] == '#') + { + /* We'll get the parameter types from the name. */ + struct type *return_type; + + (*pp)++; + return_type = read_type (pp, objfile); + if (*(*pp)++ != ';') + complain (&invalid_member_complaint, symnum); + type = allocate_stub_method (return_type); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + } + else + { + struct type *domain = read_type (pp, objfile); + struct type *return_type; + struct type **args; + + if (**pp != ',') + /* Invalid member type data format. */ + return error_type (pp); + else + ++(*pp); + + return_type = read_type (pp, objfile); + args = read_args (pp, ';', objfile); + type = dbx_alloc_type (typenums, objfile); + smash_to_method_type (type, domain, return_type, args); + } + break; + + case 'r': /* Range type */ + type = read_range_type (pp, typenums, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 'b': /* Sun ACC builtin int type */ + type = read_sun_builtin_type (pp, typenums, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 'R': /* Sun ACC builtin float type */ + type = read_sun_floating_type (pp, typenums, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 'e': /* Enumeration type */ + type = dbx_alloc_type (typenums, objfile); + type = read_enum_type (pp, type, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 's': /* Struct type */ + case 'u': /* Union type */ + type = dbx_alloc_type (typenums, objfile); + if (!TYPE_NAME (type)) + { + TYPE_NAME (type) = type_synonym_name; + } + type_synonym_name = NULL; + switch (type_descriptor) + { + case 's': + TYPE_CODE (type) = TYPE_CODE_STRUCT; + break; + case 'u': + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + } + type = read_struct_type (pp, type, objfile); + break; + + case 'a': /* Array type */ + if (**pp != 'r') + return error_type (pp); + ++*pp; + + type = dbx_alloc_type (typenums, objfile); + type = read_array_type (pp, type, objfile); + break; + + default: + --*pp; /* Go back to the symbol in error */ + /* Particularly important if it was \0! */ + return error_type (pp); + } + + if (type == 0) + { + warning ("GDB internal error, type is NULL in stabsread.c\n"); + return error_type (pp); + } + + /* Size specified in a type attribute overrides any other size. */ + if (type_size != -1) + TYPE_LENGTH (type) = type_size / TARGET_CHAR_BIT; + + return type; +} + +/* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1. + Return the proper type node for a given builtin type number. */ + +static struct type * +rs6000_builtin_type (typenum) + int typenum; +{ + /* We recognize types numbered from -NUMBER_RECOGNIZED to -1. */ +#define NUMBER_RECOGNIZED 30 + /* This includes an empty slot for type number -0. */ + static struct type *negative_types[NUMBER_RECOGNIZED + 1]; + struct type *rettype = NULL; + + if (typenum >= 0 || typenum < -NUMBER_RECOGNIZED) + { + complain (&rs6000_builtin_complaint, typenum); + return builtin_type_error; + } + if (negative_types[-typenum] != NULL) + return negative_types[-typenum]; + +#if TARGET_CHAR_BIT != 8 + #error This code wrong for TARGET_CHAR_BIT not 8 + /* These definitions all assume that TARGET_CHAR_BIT is 8. I think + that if that ever becomes not true, the correct fix will be to + make the size in the struct type to be in bits, not in units of + TARGET_CHAR_BIT. */ +#endif + + switch (-typenum) + { + case 1: + /* The size of this and all the other types are fixed, defined + by the debugging format. If there is a type called "int" which + is other than 32 bits, then it should use a new negative type + number (or avoid negative type numbers for that case). + See stabs.texinfo. */ + rettype = init_type (TYPE_CODE_INT, 4, 0, "int", NULL); + break; + case 2: + rettype = init_type (TYPE_CODE_INT, 1, 0, "char", NULL); + break; + case 3: + rettype = init_type (TYPE_CODE_INT, 2, 0, "short", NULL); + break; + case 4: + rettype = init_type (TYPE_CODE_INT, 4, 0, "long", NULL); + break; + case 5: + rettype = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, + "unsigned char", NULL); + break; + case 6: + rettype = init_type (TYPE_CODE_INT, 1, 0, "signed char", NULL); + break; + case 7: + rettype = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, + "unsigned short", NULL); + break; + case 8: + rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, + "unsigned int", NULL); + break; + case 9: + rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, + "unsigned", NULL); + case 10: + rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, + "unsigned long", NULL); + break; + case 11: + rettype = init_type (TYPE_CODE_VOID, 0, 0, "void", NULL); + break; + case 12: + /* IEEE single precision (32 bit). */ + rettype = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL); + break; + case 13: + /* IEEE double precision (64 bit). */ + rettype = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL); + break; + case 14: + /* This is an IEEE double on the RS/6000, and different machines with + different sizes for "long double" should use different negative + type numbers. See stabs.texinfo. */ + rettype = init_type (TYPE_CODE_FLT, 8, 0, "long double", NULL); + break; + case 15: + rettype = init_type (TYPE_CODE_INT, 4, 0, "integer", NULL); + break; + case 16: + rettype = init_type (TYPE_CODE_BOOL, 4, 0, "boolean", NULL); + break; + case 17: + rettype = init_type (TYPE_CODE_FLT, 4, 0, "short real", NULL); + break; + case 18: + rettype = init_type (TYPE_CODE_FLT, 8, 0, "real", NULL); + break; + case 19: + rettype = init_type (TYPE_CODE_ERROR, 0, 0, "stringptr", NULL); + break; + case 20: + rettype = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED, + "character", NULL); + break; + case 21: + rettype = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED, + "logical*1", NULL); + break; + case 22: + rettype = init_type (TYPE_CODE_BOOL, 2, TYPE_FLAG_UNSIGNED, + "logical*2", NULL); + break; + case 23: + rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED, + "logical*4", NULL); + break; + case 24: + rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED, + "logical", NULL); + break; + case 25: + /* Complex type consisting of two IEEE single precision values. */ + rettype = init_type (TYPE_CODE_ERROR, 8, 0, "complex", NULL); + break; + case 26: + /* Complex type consisting of two IEEE double precision values. */ + rettype = init_type (TYPE_CODE_ERROR, 16, 0, "double complex", NULL); + break; + case 27: + rettype = init_type (TYPE_CODE_INT, 1, 0, "integer*1", NULL); + break; + case 28: + rettype = init_type (TYPE_CODE_INT, 2, 0, "integer*2", NULL); + break; + case 29: + rettype = init_type (TYPE_CODE_INT, 4, 0, "integer*4", NULL); + break; + case 30: + rettype = init_type (TYPE_CODE_CHAR, 2, 0, "wchar", NULL); + break; + } + negative_types[-typenum] = rettype; + return rettype; +} + +/* This page contains subroutines of read_type. */ + +#define VISIBILITY_PRIVATE '0' /* Stabs character for private field */ +#define VISIBILITY_PROTECTED '1' /* Stabs character for protected fld */ +#define VISIBILITY_PUBLIC '2' /* Stabs character for public field */ + +/* Read member function stabs info for C++ classes. The form of each member + function data is: + + NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ; + + An example with two member functions is: + + afunc1::20=##15;:i;2A.;afunc2::20:i;2A.; + + For the case of overloaded operators, the format is op$::*.funcs, where + $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator + name (such as `+=') and `.' marks the end of the operator name. + + Returns 1 for success, 0 for failure. */ + +static int +read_member_functions (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + int nfn_fields = 0; + int length = 0; + /* Total number of member functions defined in this class. If the class + defines two `f' functions, and one `g' function, then this will have + the value 3. */ + int total_length = 0; + int i; + struct next_fnfield + { + struct next_fnfield *next; + struct fn_field fn_field; + } *sublist; + struct type *look_ahead_type; + struct next_fnfieldlist *new_fnlist; + struct next_fnfield *new_sublist; + char *main_fn_name; + register char *p; + + /* Process each list until we find something that is not a member function + or find the end of the functions. */ + + while (**pp != ';') + { + /* We should be positioned at the start of the function name. + Scan forward to find the first ':' and if it is not the + first of a "::" delimiter, then this is not a member function. */ + p = *pp; + while (*p != ':') + { + p++; + } + if (p[1] != ':') + { + break; + } + + sublist = NULL; + look_ahead_type = NULL; + length = 0; + + new_fnlist = (struct next_fnfieldlist *) + xmalloc (sizeof (struct next_fnfieldlist)); + make_cleanup (free, new_fnlist); + memset (new_fnlist, 0, sizeof (struct next_fnfieldlist)); + + if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER) + { + /* This is a completely wierd case. In order to stuff in the + names that might contain colons (the usual name delimiter), + Mike Tiemann defined a different name format which is + signalled if the identifier is "op$". In that case, the + format is "op$::XXXX." where XXXX is the name. This is + used for names like "+" or "=". YUUUUUUUK! FIXME! */ + /* This lets the user type "break operator+". + We could just put in "+" as the name, but that wouldn't + work for "*". */ + static char opname[32] = {'o', 'p', CPLUS_MARKER}; + char *o = opname + 3; + + /* Skip past '::'. */ + *pp = p + 2; + + STABS_CONTINUE (pp); + p = *pp; + while (*p != '.') + { + *o++ = *p++; + } + main_fn_name = savestring (opname, o - opname); + /* Skip past '.' */ + *pp = p + 1; + } + else + { + main_fn_name = savestring (*pp, p - *pp); + /* Skip past '::'. */ + *pp = p + 2; + } + new_fnlist -> fn_fieldlist.name = main_fn_name; + + do + { + new_sublist = + (struct next_fnfield *) xmalloc (sizeof (struct next_fnfield)); + make_cleanup (free, new_sublist); + memset (new_sublist, 0, sizeof (struct next_fnfield)); + + /* Check for and handle cretinous dbx symbol name continuation! */ + if (look_ahead_type == NULL) + { + /* Normal case. */ + STABS_CONTINUE (pp); + + new_sublist -> fn_field.type = read_type (pp, objfile); + if (**pp != ':') + { + /* Invalid symtab info for member function. */ + return 0; + } + } + else + { + /* g++ version 1 kludge */ + new_sublist -> fn_field.type = look_ahead_type; + look_ahead_type = NULL; + } + + (*pp)++; + p = *pp; + while (*p != ';') + { + p++; + } + + /* If this is just a stub, then we don't have the real name here. */ + + if (TYPE_FLAGS (new_sublist -> fn_field.type) & TYPE_FLAG_STUB) + { + if (!TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type)) + TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type) = type; + new_sublist -> fn_field.is_stub = 1; + } + new_sublist -> fn_field.physname = savestring (*pp, p - *pp); + *pp = p + 1; + + /* Set this member function's visibility fields. */ + switch (*(*pp)++) + { + case VISIBILITY_PRIVATE: + new_sublist -> fn_field.is_private = 1; + break; + case VISIBILITY_PROTECTED: + new_sublist -> fn_field.is_protected = 1; + break; + } + + STABS_CONTINUE (pp); + switch (**pp) + { + case 'A': /* Normal functions. */ + new_sublist -> fn_field.is_const = 0; + new_sublist -> fn_field.is_volatile = 0; + (*pp)++; + break; + case 'B': /* `const' member functions. */ + new_sublist -> fn_field.is_const = 1; + new_sublist -> fn_field.is_volatile = 0; + (*pp)++; + break; + case 'C': /* `volatile' member function. */ + new_sublist -> fn_field.is_const = 0; + new_sublist -> fn_field.is_volatile = 1; + (*pp)++; + break; + case 'D': /* `const volatile' member function. */ + new_sublist -> fn_field.is_const = 1; + new_sublist -> fn_field.is_volatile = 1; + (*pp)++; + break; + case '*': /* File compiled with g++ version 1 -- no info */ + case '?': + case '.': + break; + default: + complain (&const_vol_complaint, **pp); + break; + } + + switch (*(*pp)++) + { + case '*': + { + int nbits; + /* virtual member function, followed by index. + The sign bit is set to distinguish pointers-to-methods + from virtual function indicies. Since the array is + in words, the quantity must be shifted left by 1 + on 16 bit machine, and by 2 on 32 bit machine, forcing + the sign bit out, and usable as a valid index into + the array. Remove the sign bit here. */ + new_sublist -> fn_field.voffset = + (0x7fffffff & read_huge_number (pp, ';', &nbits)) + 2; + if (nbits != 0) + return 0; + + STABS_CONTINUE (pp); + if (**pp == ';' || **pp == '\0') + { + /* Must be g++ version 1. */ + new_sublist -> fn_field.fcontext = 0; + } + else + { + /* Figure out from whence this virtual function came. + It may belong to virtual function table of + one of its baseclasses. */ + look_ahead_type = read_type (pp, objfile); + if (**pp == ':') + { + /* g++ version 1 overloaded methods. */ + } + else + { + new_sublist -> fn_field.fcontext = look_ahead_type; + if (**pp != ';') + { + return 0; + } + else + { + ++*pp; + } + look_ahead_type = NULL; + } + } + break; + } + case '?': + /* static member function. */ + new_sublist -> fn_field.voffset = VOFFSET_STATIC; + if (strncmp (new_sublist -> fn_field.physname, + main_fn_name, strlen (main_fn_name))) + { + new_sublist -> fn_field.is_stub = 1; + } + break; + + default: + /* error */ + complain (&member_fn_complaint, (*pp)[-1]); + /* Fall through into normal member function. */ + + case '.': + /* normal member function. */ + new_sublist -> fn_field.voffset = 0; + new_sublist -> fn_field.fcontext = 0; + break; + } + + new_sublist -> next = sublist; + sublist = new_sublist; + length++; + STABS_CONTINUE (pp); + } + while (**pp != ';' && **pp != '\0'); + + (*pp)++; + + new_fnlist -> fn_fieldlist.fn_fields = (struct fn_field *) + obstack_alloc (&objfile -> type_obstack, + sizeof (struct fn_field) * length); + memset (new_fnlist -> fn_fieldlist.fn_fields, 0, + sizeof (struct fn_field) * length); + for (i = length; (i--, sublist); sublist = sublist -> next) + { + new_fnlist -> fn_fieldlist.fn_fields[i] = sublist -> fn_field; + } + + new_fnlist -> fn_fieldlist.length = length; + new_fnlist -> next = fip -> fnlist; + fip -> fnlist = new_fnlist; + nfn_fields++; + total_length += length; + STABS_CONTINUE (pp); + } + + if (nfn_fields) + { + ALLOCATE_CPLUS_STRUCT_TYPE (type); + TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *) + TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * nfn_fields); + memset (TYPE_FN_FIELDLISTS (type), 0, + sizeof (struct fn_fieldlist) * nfn_fields); + TYPE_NFN_FIELDS (type) = nfn_fields; + TYPE_NFN_FIELDS_TOTAL (type) = total_length; + } + + return 1; +} + +/* Special GNU C++ name. + + Returns 1 for success, 0 for failure. "failure" means that we can't + keep parsing and it's time for error_type(). */ + +static int +read_cpp_abbrev (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + register char *p; + char *name; + char cpp_abbrev; + struct type *context; + + p = *pp; + if (*++p == 'v') + { + name = NULL; + cpp_abbrev = *++p; + + *pp = p + 1; + + /* At this point, *pp points to something like "22:23=*22...", + where the type number before the ':' is the "context" and + everything after is a regular type definition. Lookup the + type, find it's name, and construct the field name. */ + + context = read_type (pp, objfile); + + switch (cpp_abbrev) + { + case 'f': /* $vf -- a virtual function table pointer */ + fip->list->field.name = + obconcat (&objfile->type_obstack, vptr_name, "", ""); + break; + + case 'b': /* $vb -- a virtual bsomethingorother */ + name = type_name_no_tag (context); + if (name == NULL) + { + complain (&invalid_cpp_type_complaint, symnum); + name = "FOO"; + } + fip->list->field.name = + obconcat (&objfile->type_obstack, vb_name, name, ""); + break; + + default: + complain (&invalid_cpp_abbrev_complaint, *pp); + fip->list->field.name = + obconcat (&objfile->type_obstack, + "INVALID_CPLUSPLUS_ABBREV", "", ""); + break; + } + + /* At this point, *pp points to the ':'. Skip it and read the + field type. */ + + p = ++(*pp); + if (p[-1] != ':') + { + complain (&invalid_cpp_abbrev_complaint, *pp); + return 0; + } + fip->list->field.type = read_type (pp, objfile); + if (**pp == ',') + (*pp)++; /* Skip the comma. */ + else + return 0; + + { + int nbits; + fip->list->field.bitpos = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return 0; + } + /* This field is unpacked. */ + fip->list->field.bitsize = 0; + fip->list->visibility = VISIBILITY_PRIVATE; + } + else + { + complain (&invalid_cpp_abbrev_complaint, *pp); + /* We have no idea what syntax an unrecognized abbrev would have, so + better return 0. If we returned 1, we would need to at least advance + *pp to avoid an infinite loop. */ + return 0; + } + return 1; +} + +static void +read_one_struct_field (fip, pp, p, type, objfile) + struct field_info *fip; + char **pp; + char *p; + struct type *type; + struct objfile *objfile; +{ + fip -> list -> field.name = + obsavestring (*pp, p - *pp, &objfile -> type_obstack); + *pp = p + 1; + + /* This means we have a visibility for a field coming. */ + if (**pp == '/') + { + (*pp)++; + fip -> list -> visibility = *(*pp)++; + switch (fip -> list -> visibility) + { + case VISIBILITY_PRIVATE: + case VISIBILITY_PROTECTED: + break; + + case VISIBILITY_PUBLIC: + /* Nothing to do */ + break; + + default: + /* Unknown visibility specifier. */ + complain (&stabs_general_complaint, + "unknown visibility specifier"); + return; + break; + } + } + else + { + /* normal dbx-style format, no explicit visibility */ + fip -> list -> visibility = VISIBILITY_PUBLIC; + } + + fip -> list -> field.type = read_type (pp, objfile); + if (**pp == ':') + { + p = ++(*pp); +#if 0 + /* Possible future hook for nested types. */ + if (**pp == '!') + { + fip -> list -> field.bitpos = (long)-2; /* nested type */ + p = ++(*pp); + } + else +#endif + { + /* Static class member. */ + fip -> list -> field.bitpos = (long) -1; + } + while (*p != ';') + { + p++; + } + fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp); + *pp = p + 1; + return; + } + else if (**pp != ',') + { + /* Bad structure-type format. */ + complain (&stabs_general_complaint, "bad structure-type format"); + return; + } + + (*pp)++; /* Skip the comma. */ + + { + int nbits; + fip -> list -> field.bitpos = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + { + complain (&stabs_general_complaint, "bad structure-type format"); + return; + } + fip -> list -> field.bitsize = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + { + complain (&stabs_general_complaint, "bad structure-type format"); + return; + } + } +#if 0 + /* FIXME-tiemann: Can't the compiler put out something which + lets us distinguish these? (or maybe just not put out anything + for the field). What is the story here? What does the compiler + really do? Also, patch gdb.texinfo for this case; I document + it as a possible problem there. Search for "DBX-style". */ + + /* This is wrong because this is identical to the symbols + produced for GCC 0-size arrays. For example: + typedef union { + int num; + char str[0]; + } foo; + The code which dumped core in such circumstances should be + fixed not to dump core. */ + + /* g++ -g0 can put out bitpos & bitsize zero for a static + field. This does not give us any way of getting its + class, so we can't know its name. But we can just + ignore the field so we don't dump core and other nasty + stuff. */ + if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0) + { + complain (&dbx_class_complaint); + /* Ignore this field. */ + fip -> list = fip -> list -> next; + } + else +#endif /* 0 */ + { + /* Detect an unpacked field and mark it as such. + dbx gives a bit size for all fields. + Note that forward refs cannot be packed, + and treat enums as if they had the width of ints. */ + + if (TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_INT + && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM) + { + fip -> list -> field.bitsize = 0; + } + if ((fip -> list -> field.bitsize + == TARGET_CHAR_BIT * TYPE_LENGTH (fip -> list -> field.type) + || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM + && (fip -> list -> field.bitsize + == TARGET_INT_BIT) + ) + ) + && + fip -> list -> field.bitpos % 8 == 0) + { + fip -> list -> field.bitsize = 0; + } + } +} + + +/* Read struct or class data fields. They have the form: + + NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ; + + At the end, we see a semicolon instead of a field. + + In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for + a static field. + + The optional VISIBILITY is one of: + + '/0' (VISIBILITY_PRIVATE) + '/1' (VISIBILITY_PROTECTED) + '/2' (VISIBILITY_PUBLIC) + + or nothing, for C style fields with public visibility. + + Returns 1 for success, 0 for failure. */ + +static int +read_struct_fields (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + register char *p; + struct nextfield *new; + + /* We better set p right now, in case there are no fields at all... */ + + p = *pp; + + /* Read each data member type until we find the terminating ';' at the end of + the data member list, or break for some other reason such as finding the + start of the member function list. */ + + while (**pp != ';') + { + STABS_CONTINUE (pp); + /* Get space to record the next field's data. */ + new = (struct nextfield *) xmalloc (sizeof (struct nextfield)); + make_cleanup (free, new); + memset (new, 0, sizeof (struct nextfield)); + new -> next = fip -> list; + fip -> list = new; + + /* Get the field name. */ + p = *pp; + /* If is starts with CPLUS_MARKER it is a special abbreviation, unless + the CPLUS_MARKER is followed by an underscore, in which case it is + just the name of an anonymous type, which we should handle like any + other type name. */ + if (*p == CPLUS_MARKER && p[1] != '_') + { + if (!read_cpp_abbrev (fip, pp, type, objfile)) + return 0; + continue; + } + + /* Look for the ':' that separates the field name from the field + values. Data members are delimited by a single ':', while member + functions are delimited by a pair of ':'s. When we hit the member + functions (if any), terminate scan loop and return. */ + + while (*p != ':' && *p != '\0') + { + p++; + } + if (*p == '\0') + return 0; + + /* Check to see if we have hit the member functions yet. */ + if (p[1] == ':') + { + break; + } + read_one_struct_field (fip, pp, p, type, objfile); + } + if (p[1] == ':') + { + /* chill the list of fields: the last entry (at the head) is a + partially constructed entry which we now scrub. */ + fip -> list = fip -> list -> next; + } + return 1; +} + +/* The stabs for C++ derived classes contain baseclass information which + is marked by a '!' character after the total size. This function is + called when we encounter the baseclass marker, and slurps up all the + baseclass information. + + Immediately following the '!' marker is the number of base classes that + the class is derived from, followed by information for each base class. + For each base class, there are two visibility specifiers, a bit offset + to the base class information within the derived class, a reference to + the type for the base class, and a terminating semicolon. + + A typical example, with two base classes, would be "!2,020,19;0264,21;". + ^^ ^ ^ ^ ^ ^ ^ + Baseclass information marker __________________|| | | | | | | + Number of baseclasses __________________________| | | | | | | + Visibility specifiers (2) ________________________| | | | | | + Offset in bits from start of class _________________| | | | | + Type number for base class ___________________________| | | | + Visibility specifiers (2) _______________________________| | | + Offset in bits from start of class ________________________| | + Type number of base class ____________________________________| + + Return 1 for success, 0 for (error-type-inducing) failure. */ + +static int +read_baseclasses (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + int i; + struct nextfield *new; + + if (**pp != '!') + { + return 1; + } + else + { + /* Skip the '!' baseclass information marker. */ + (*pp)++; + } + + ALLOCATE_CPLUS_STRUCT_TYPE (type); + { + int nbits; + TYPE_N_BASECLASSES (type) = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + return 0; + } + +#if 0 + /* Some stupid compilers have trouble with the following, so break + it up into simpler expressions. */ + TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) + TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type))); +#else + { + int num_bytes = B_BYTES (TYPE_N_BASECLASSES (type)); + char *pointer; + + pointer = (char *) TYPE_ALLOC (type, num_bytes); + TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer; + } +#endif /* 0 */ + + B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type)); + + for (i = 0; i < TYPE_N_BASECLASSES (type); i++) + { + new = (struct nextfield *) xmalloc (sizeof (struct nextfield)); + make_cleanup (free, new); + memset (new, 0, sizeof (struct nextfield)); + new -> next = fip -> list; + fip -> list = new; + new -> field.bitsize = 0; /* this should be an unpacked field! */ + + STABS_CONTINUE (pp); + switch (*(*pp)++) + { + case '0': + /* Nothing to do. */ + break; + case '1': + SET_TYPE_FIELD_VIRTUAL (type, i); + break; + default: + /* Bad visibility format. */ + return 0; + } + + new -> visibility = *(*pp)++; + switch (new -> visibility) + { + case VISIBILITY_PRIVATE: + case VISIBILITY_PROTECTED: + case VISIBILITY_PUBLIC: + break; + default: + /* Bad visibility format. */ + return 0; + } + + { + int nbits; + + /* The remaining value is the bit offset of the portion of the object + corresponding to this baseclass. Always zero in the absence of + multiple inheritance. */ + + new -> field.bitpos = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + return 0; + } + + /* The last piece of baseclass information is the type of the + base class. Read it, and remember it's type name as this + field's name. */ + + new -> field.type = read_type (pp, objfile); + new -> field.name = type_name_no_tag (new -> field.type); + + /* skip trailing ';' and bump count of number of fields seen */ + if (**pp == ';') + (*pp)++; + else + return 0; + } + return 1; +} + +/* The tail end of stabs for C++ classes that contain a virtual function + pointer contains a tilde, a %, and a type number. + The type number refers to the base class (possibly this class itself) which + contains the vtable pointer for the current class. + + This function is called when we have parsed all the method declarations, + so we can look for the vptr base class info. */ + +static int +read_tilde_fields (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + register char *p; + + STABS_CONTINUE (pp); + + /* If we are positioned at a ';', then skip it. */ + if (**pp == ';') + { + (*pp)++; + } + + if (**pp == '~') + { + (*pp)++; + + if (**pp == '=' || **pp == '+' || **pp == '-') + { + /* Obsolete flags that used to indicate the presence + of constructors and/or destructors. */ + (*pp)++; + } + + /* Read either a '%' or the final ';'. */ + if (*(*pp)++ == '%') + { + /* The next number is the type number of the base class + (possibly our own class) which supplies the vtable for + this class. Parse it out, and search that class to find + its vtable pointer, and install those into TYPE_VPTR_BASETYPE + and TYPE_VPTR_FIELDNO. */ + + struct type *t; + int i; + + t = read_type (pp, objfile); + p = (*pp)++; + while (*p != '\0' && *p != ';') + { + p++; + } + if (*p == '\0') + { + /* Premature end of symbol. */ + return 0; + } + + TYPE_VPTR_BASETYPE (type) = t; + if (type == t) /* Our own class provides vtbl ptr */ + { + for (i = TYPE_NFIELDS (t) - 1; + i >= TYPE_N_BASECLASSES (t); + --i) + { + if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name, + sizeof (vptr_name) - 1)) + { + TYPE_VPTR_FIELDNO (type) = i; + goto gotit; + } + } + /* Virtual function table field not found. */ + complain (&vtbl_notfound_complaint, TYPE_NAME (type)); + return 0; + } + else + { + TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t); + } + + gotit: + *pp = p + 1; + } + } + return 1; +} + +static int +attach_fn_fields_to_type (fip, type) + struct field_info *fip; + register struct type *type; +{ + register int n; + + for (n = 0; n < TYPE_N_BASECLASSES (type); n++) + { + if (TYPE_CODE (TYPE_BASECLASS (type, n)) == TYPE_CODE_UNDEF) + { + /* @@ Memory leak on objfile -> type_obstack? */ + return 0; + } + TYPE_NFN_FIELDS_TOTAL (type) += + TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, n)); + } + + for (n = TYPE_NFN_FIELDS (type); + fip -> fnlist != NULL; + fip -> fnlist = fip -> fnlist -> next) + { + --n; /* Circumvent Sun3 compiler bug */ + TYPE_FN_FIELDLISTS (type)[n] = fip -> fnlist -> fn_fieldlist; + } + return 1; +} + +/* Create the vector of fields, and record how big it is. + We need this info to record proper virtual function table information + for this class's virtual functions. */ + +static int +attach_fields_to_type (fip, type, objfile) + struct field_info *fip; + register struct type *type; + struct objfile *objfile; +{ + register int nfields = 0; + register int non_public_fields = 0; + register struct nextfield *scan; + + /* Count up the number of fields that we have, as well as taking note of + whether or not there are any non-public fields, which requires us to + allocate and build the private_field_bits and protected_field_bits + bitfields. */ + + for (scan = fip -> list; scan != NULL; scan = scan -> next) + { + nfields++; + if (scan -> visibility != VISIBILITY_PUBLIC) + { + non_public_fields++; + } + } + + /* Now we know how many fields there are, and whether or not there are any + non-public fields. Record the field count, allocate space for the + array of fields, and create blank visibility bitfields if necessary. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields); + + if (non_public_fields) + { + ALLOCATE_CPLUS_STRUCT_TYPE (type); + + TYPE_FIELD_PRIVATE_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields); + + TYPE_FIELD_PROTECTED_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields); + } + + /* Copy the saved-up fields into the field vector. Start from the head + of the list, adding to the tail of the field array, so that they end + up in the same order in the array in which they were added to the list. */ + + while (nfields-- > 0) + { + TYPE_FIELD (type, nfields) = fip -> list -> field; + switch (fip -> list -> visibility) + { + case VISIBILITY_PRIVATE: + SET_TYPE_FIELD_PRIVATE (type, nfields); + break; + + case VISIBILITY_PROTECTED: + SET_TYPE_FIELD_PROTECTED (type, nfields); + break; + + case VISIBILITY_PUBLIC: + break; + + default: + /* Should warn about this unknown visibility? */ + break; + } + fip -> list = fip -> list -> next; + } + return 1; +} + +/* Read the description of a structure (or union type) and return an object + describing the type. + + PP points to a character pointer that points to the next unconsumed token + in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;", + *PP will point to "4a:1,0,32;;". + + TYPE points to an incomplete type that needs to be filled in. + + OBJFILE points to the current objfile from which the stabs information is + being read. (Note that it is redundant in that TYPE also contains a pointer + to this same objfile, so it might be a good idea to eliminate it. FIXME). + */ + +static struct type * +read_struct_type (pp, type, objfile) + char **pp; + struct type *type; + struct objfile *objfile; +{ + struct cleanup *back_to; + struct field_info fi; + + fi.list = NULL; + fi.fnlist = NULL; + + back_to = make_cleanup (null_cleanup, 0); + + INIT_CPLUS_SPECIFIC (type); + TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB; + + /* First comes the total size in bytes. */ + + { + int nbits; + TYPE_LENGTH (type) = read_huge_number (pp, 0, &nbits); + if (nbits != 0) + return error_type (pp); + } + + /* Now read the baseclasses, if any, read the regular C struct or C++ + class member fields, attach the fields to the type, read the C++ + member functions, attach them to the type, and then read any tilde + field (baseclass specifier for the class holding the main vtable). */ + + if (!read_baseclasses (&fi, pp, type, objfile) + || !read_struct_fields (&fi, pp, type, objfile) + || !attach_fields_to_type (&fi, type, objfile) + || !read_member_functions (&fi, pp, type, objfile) + || !attach_fn_fields_to_type (&fi, type) + || !read_tilde_fields (&fi, pp, type, objfile)) + { + do_cleanups (back_to); + return (error_type (pp)); + } + + do_cleanups (back_to); + return (type); +} + +/* Read a definition of an array type, + and create and return a suitable type object. + Also creates a range type which represents the bounds of that + array. */ + +static struct type * +read_array_type (pp, type, objfile) + register char **pp; + register struct type *type; + struct objfile *objfile; +{ + struct type *index_type, *element_type, *range_type; + int lower, upper; + int adjustable = 0; + int nbits; + + /* Format of an array type: + "ar;lower;upper;". Put code in + to handle this. + + Fortran adjustable arrays use Adigits or Tdigits for lower or upper; + for these, produce a type like float[][]. */ + + index_type = read_type (pp, objfile); + if (**pp != ';') + /* Improper format of array type decl. */ + return error_type (pp); + ++*pp; + + if (!(**pp >= '0' && **pp <= '9')) + { + (*pp)++; + adjustable = 1; + } + lower = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp); + + if (!(**pp >= '0' && **pp <= '9')) + { + (*pp)++; + adjustable = 1; + } + upper = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp); + + element_type = read_type (pp, objfile); + + if (adjustable) + { + lower = 0; + upper = -1; + } + + range_type = + create_range_type ((struct type *) NULL, index_type, lower, upper); + type = create_array_type (type, element_type, range_type); + + /* If we have an array whose element type is not yet known, but whose + bounds *are* known, record it to be adjusted at the end of the file. */ + + if (TYPE_LENGTH (element_type) == 0 && !adjustable) + { + add_undefined_type (type); + } + + return type; +} + + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +static struct type * +read_enum_type (pp, type, objfile) + register char **pp; + register struct type *type; + struct objfile *objfile; +{ + register char *p; + char *name; + register long n; + register struct symbol *sym; + int nsyms = 0; + struct pending **symlist; + struct pending *osyms, *syms; + int o_nsyms; + +#if 0 + /* FIXME! The stabs produced by Sun CC merrily define things that ought + to be file-scope, between N_FN entries, using N_LSYM. What's a mother + to do? For now, force all enum values to file scope. */ + if (within_function) + symlist = &local_symbols; + else +#endif + symlist = &file_symbols; + osyms = *symlist; + o_nsyms = osyms ? osyms->nsyms : 0; + + /* Read the value-names and their values. + The input syntax is NAME:VALUE,NAME:VALUE, and so on. + A semicolon or comma instead of a NAME means the end. */ + while (**pp && **pp != ';' && **pp != ',') + { + int nbits; + STABS_CONTINUE (pp); + p = *pp; + while (*p != ':') p++; + name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack); + *pp = p + 1; + n = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + return error_type (pp); + + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = name; + SYMBOL_LANGUAGE (sym) = current_subfile -> language; + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = n; + add_symbol_to_list (sym, symlist); + nsyms++; + } + + if (**pp == ';') + (*pp)++; /* Skip the semicolon. */ + + /* Now fill in the fields of the type-structure. */ + + TYPE_LENGTH (type) = sizeof (int); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nsyms); + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + /* Note that we preserve the order of the enum constants, so + that in something like "enum {FOO, LAST_THING=FOO}" we print + FOO, not LAST_THING. */ + + for (syms = *symlist, n = 0; syms; syms = syms->next) + { + int j = 0; + if (syms == osyms) + j = o_nsyms; + for (; j < syms->nsyms; j++,n++) + { + struct symbol *xsym = syms->symbol[j]; + SYMBOL_TYPE (xsym) = type; + TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym); + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym); + TYPE_FIELD_BITSIZE (type, n) = 0; + } + if (syms == osyms) + break; + } + +#if 0 + /* This screws up perfectly good C programs with enums. FIXME. */ + /* Is this Modula-2's BOOLEAN type? Flag it as such if so. */ + if(TYPE_NFIELDS(type) == 2 && + ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") && + STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) || + (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") && + STREQ(TYPE_FIELD_NAME(type,0),"FALSE")))) + TYPE_CODE(type) = TYPE_CODE_BOOL; +#endif + + return type; +} + +/* Sun's ACC uses a somewhat saner method for specifying the builtin + typedefs in every file (for int, long, etc): + + type = b ; ; + signed = u or s. Possible c in addition to u or s (for char?). + offset = offset from high order bit to start bit of type. + width is # bytes in object of this type, nbits is # bits in type. + + The width/offset stuff appears to be for small objects stored in + larger ones (e.g. `shorts' in `int' registers). We ignore it for now, + FIXME. */ + +static struct type * +read_sun_builtin_type (pp, typenums, objfile) + char **pp; + int typenums[2]; + struct objfile *objfile; +{ + int type_bits; + int nbits; + int signed_type; + + switch (**pp) + { + case 's': + signed_type = 1; + break; + case 'u': + signed_type = 0; + break; + default: + return error_type (pp); + } + (*pp)++; + + /* For some odd reason, all forms of char put a c here. This is strange + because no other type has this honor. We can safely ignore this because + we actually determine 'char'acterness by the number of bits specified in + the descriptor. */ + + if (**pp == 'c') + (*pp)++; + + /* The first number appears to be the number of bytes occupied + by this type, except that unsigned short is 4 instead of 2. + Since this information is redundant with the third number, + we will ignore it. */ + read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp); + + /* The second number is always 0, so ignore it too. */ + read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp); + + /* The third number is the number of bits for this type. */ + type_bits = read_huge_number (pp, 0, &nbits); + if (nbits != 0) + return error_type (pp); + +#if 0 + /* FIXME. Here we should just be able to make a type of the right + number of bits and signedness. FIXME. */ + + if (type_bits == TARGET_LONG_LONG_BIT) + return (lookup_fundamental_type (objfile, + signed_type? FT_LONG_LONG: FT_UNSIGNED_LONG_LONG)); + + if (type_bits == TARGET_INT_BIT) + { + /* FIXME -- the only way to distinguish `int' from `long' + is to look at its name! */ + if (signed_type) + { + if (long_kludge_name && long_kludge_name[0] == 'l' /* long */) + return lookup_fundamental_type (objfile, FT_LONG); + else + return lookup_fundamental_type (objfile, FT_INTEGER); + } + else + { + if (long_kludge_name + && ((long_kludge_name[0] == 'u' /* unsigned */ && + long_kludge_name[9] == 'l' /* long */) + || (long_kludge_name[0] == 'l' /* long unsigned */))) + return lookup_fundamental_type (objfile, FT_UNSIGNED_LONG); + else + return lookup_fundamental_type (objfile, FT_UNSIGNED_INTEGER); + } + } + + if (type_bits == TARGET_SHORT_BIT) + return (lookup_fundamental_type (objfile, + signed_type? FT_SHORT: FT_UNSIGNED_SHORT)); + + if (type_bits == TARGET_CHAR_BIT) + return (lookup_fundamental_type (objfile, + signed_type? FT_CHAR: FT_UNSIGNED_CHAR)); + + if (type_bits == 0) + return lookup_fundamental_type (objfile, FT_VOID); + + return error_type (pp); +#else + return init_type (type_bits == 0 ? TYPE_CODE_VOID : TYPE_CODE_INT, + type_bits / TARGET_CHAR_BIT, + signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL, + objfile); +#endif +} + +static struct type * +read_sun_floating_type (pp, typenums, objfile) + char **pp; + int typenums[2]; + struct objfile *objfile; +{ + int nbits; + int details; + int nbytes; + + /* The first number has more details about the type, for example + FN_COMPLEX. */ + details = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp); + + /* The second number is the number of bytes occupied by this type */ + nbytes = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp); + + if (details == NF_COMPLEX || details == NF_COMPLEX16 + || details == NF_COMPLEX32) + /* This is a type we can't handle, but we do know the size. + We also will be able to give it a name. */ + return init_type (TYPE_CODE_ERROR, nbytes, 0, NULL, objfile); + + return init_type (TYPE_CODE_FLT, nbytes, 0, NULL, objfile); +} + +/* Read a number from the string pointed to by *PP. + The value of *PP is advanced over the number. + If END is nonzero, the character that ends the + number must match END, or an error happens; + and that character is skipped if it does match. + If END is zero, *PP is left pointing to that character. + + If the number fits in a long, set *BITS to 0 and return the value. + If not, set *BITS to be the number of bits in the number and return 0. + + If encounter garbage, set *BITS to -1 and return 0. */ + +static long +read_huge_number (pp, end, bits) + char **pp; + int end; + int *bits; +{ + char *p = *pp; + int sign = 1; + long n = 0; + int radix = 10; + char overflow = 0; + int nbits = 0; + int c; + long upper_limit; + + if (*p == '-') + { + sign = -1; + p++; + } + + /* Leading zero means octal. GCC uses this to output values larger + than an int (because that would be hard in decimal). */ + if (*p == '0') + { + radix = 8; + p++; + } + + upper_limit = LONG_MAX / radix; + while ((c = *p++) >= '0' && c < ('0' + radix)) + { + if (n <= upper_limit) + { + n *= radix; + n += c - '0'; /* FIXME this overflows anyway */ + } + else + overflow = 1; + + /* This depends on large values being output in octal, which is + what GCC does. */ + if (radix == 8) + { + if (nbits == 0) + { + if (c == '0') + /* Ignore leading zeroes. */ + ; + else if (c == '1') + nbits = 1; + else if (c == '2' || c == '3') + nbits = 2; + else + nbits = 3; + } + else + nbits += 3; + } + } + if (end) + { + if (c && c != end) + { + if (bits != NULL) + *bits = -1; + return 0; + } + } + else + --p; + + *pp = p; + if (overflow) + { + if (nbits == 0) + { + /* Large decimal constants are an error (because it is hard to + count how many bits are in them). */ + if (bits != NULL) + *bits = -1; + return 0; + } + + /* -0x7f is the same as 0x80. So deal with it by adding one to + the number of bits. */ + if (sign == -1) + ++nbits; + if (bits) + *bits = nbits; + } + else + { + if (bits) + *bits = 0; + return n * sign; + } + /* It's *BITS which has the interesting information. */ + return 0; +} + +static struct type * +read_range_type (pp, typenums, objfile) + char **pp; + int typenums[2]; + struct objfile *objfile; +{ + int rangenums[2]; + long n2, n3; + int n2bits, n3bits; + int self_subrange; + struct type *result_type; + struct type *index_type; + + /* First comes a type we are a subrange of. + In C it is usually 0, 1 or the type being defined. */ + /* FIXME: according to stabs.texinfo and AIX doc, this can be a type-id + not just a type number. */ + if (read_type_number (pp, rangenums) != 0) + return error_type (pp); + self_subrange = (rangenums[0] == typenums[0] && + rangenums[1] == typenums[1]); + + /* A semicolon should now follow; skip it. */ + if (**pp == ';') + (*pp)++; + + /* The remaining two operands are usually lower and upper bounds + of the range. But in some special cases they mean something else. */ + n2 = read_huge_number (pp, ';', &n2bits); + n3 = read_huge_number (pp, ';', &n3bits); + + if (n2bits == -1 || n3bits == -1) + return error_type (pp); + + /* If limits are huge, must be large integral type. */ + if (n2bits != 0 || n3bits != 0) + { + char got_signed = 0; + char got_unsigned = 0; + /* Number of bits in the type. */ + int nbits = 0; + + /* Range from 0 to is an unsigned large integral type. */ + if ((n2bits == 0 && n2 == 0) && n3bits != 0) + { + got_unsigned = 1; + nbits = n3bits; + } + /* Range from to -1 is a large signed + integral type. Take care of the case where doesn't + fit in a long but -1 does. */ + else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1) + || (n2bits != 0 && n3bits == 0 + && (n2bits == sizeof (long) * HOST_CHAR_BIT) + && n3 == LONG_MAX)) + { + got_signed = 1; + nbits = n2bits; + } + + if (got_signed || got_unsigned) + { + return init_type (TYPE_CODE_INT, nbits / TARGET_CHAR_BIT, + got_unsigned ? TYPE_FLAG_UNSIGNED : 0, NULL, + objfile); + } + else + return error_type (pp); + } + + /* A type defined as a subrange of itself, with bounds both 0, is void. */ + if (self_subrange && n2 == 0 && n3 == 0) + return init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile); + + /* If n3 is zero and n2 is not, we want a floating type, + and n2 is the width in bytes. + + Fortran programs appear to use this for complex types also, + and they give no way to distinguish between double and single-complex! + + GDB does not have complex types. + + Just return the complex as a float of that size. It won't work right + for the complex values, but at least it makes the file loadable. */ + + if (n3 == 0 && n2 > 0) + { + return init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile); + } + + /* If the upper bound is -1, it must really be an unsigned int. */ + + else if (n2 == 0 && n3 == -1) + { + /* It is unsigned int or unsigned long. */ + /* GCC 2.3.3 uses this for long long too, but that is just a GDB 3.5 + compatibility hack. */ + return init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, NULL, objfile); + } + + /* Special case: char is defined (Who knows why) as a subrange of + itself with range 0-127. */ + else if (self_subrange && n2 == 0 && n3 == 127) + return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile); + + /* We used to do this only for subrange of self or subrange of int. */ + else if (n2 == 0) + { + if (n3 < 0) + /* n3 actually gives the size. */ + return init_type (TYPE_CODE_INT, - n3, TYPE_FLAG_UNSIGNED, + NULL, objfile); + if (n3 == 0xff) + return init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, NULL, objfile); + if (n3 == 0xffff) + return init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, NULL, objfile); + + /* -1 is used for the upper bound of (4 byte) "unsigned int" and + "unsigned long", and we already checked for that, + so don't need to test for it here. */ + } + /* I think this is for Convex "long long". Since I don't know whether + Convex sets self_subrange, I also accept that particular size regardless + of self_subrange. */ + else if (n3 == 0 && n2 < 0 + && (self_subrange + || n2 == - TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT)) + return init_type (TYPE_CODE_INT, - n2, 0, NULL, objfile); + else if (n2 == -n3 -1) + { + if (n3 == 0x7f) + return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile); + if (n3 == 0x7fff) + return init_type (TYPE_CODE_INT, 2, 0, NULL, objfile); + if (n3 == 0x7fffffff) + return init_type (TYPE_CODE_INT, 4, 0, NULL, objfile); + } + + /* We have a real range type on our hands. Allocate space and + return a real pointer. */ + + /* At this point I don't have the faintest idea how to deal with + a self_subrange type; I'm going to assume that this is used + as an idiom, and that all of them are special cases. So . . . */ + if (self_subrange) + return error_type (pp); + + index_type = *dbx_lookup_type (rangenums); + if (index_type == NULL) + { + /* Does this actually ever happen? Is that why we are worrying + about dealing with it rather than just calling error_type? */ + + static struct type *range_type_index; + + complain (&range_type_base_complaint, rangenums[1]); + if (range_type_index == NULL) + range_type_index = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "range type index type", NULL); + index_type = range_type_index; + } + + result_type = create_range_type ((struct type *) NULL, index_type, n2, n3); + return (result_type); +} + +/* Read in an argument list. This is a list of types, separated by commas + and terminated with END. Return the list of types read in, or (struct type + **)-1 if there is an error. */ + +static struct type ** +read_args (pp, end, objfile) + char **pp; + int end; + struct objfile *objfile; +{ + /* FIXME! Remove this arbitrary limit! */ + struct type *types[1024], **rval; /* allow for fns of 1023 parameters */ + int n = 0; + + while (**pp != end) + { + if (**pp != ',') + /* Invalid argument list: no ','. */ + return (struct type **)-1; + (*pp)++; + STABS_CONTINUE (pp); + types[n++] = read_type (pp, objfile); + } + (*pp)++; /* get past `end' (the ':' character) */ + + if (n == 1) + { + rval = (struct type **) xmalloc (2 * sizeof (struct type *)); + } + else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID) + { + rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *)); + memset (rval + n, 0, sizeof (struct type *)); + } + else + { + rval = (struct type **) xmalloc (n * sizeof (struct type *)); + } + memcpy (rval, types, n * sizeof (struct type *)); + return rval; +} + +/* Common block handling. */ + +/* List of symbols declared since the last BCOMM. This list is a tail + of local_symbols. When ECOMM is seen, the symbols on the list + are noted so their proper addresses can be filled in later, + using the common block base address gotten from the assembler + stabs. */ + +static struct pending *common_block; +static int common_block_i; + +/* Name of the current common block. We get it from the BCOMM instead of the + ECOMM to match IBM documentation (even though IBM puts the name both places + like everyone else). */ +static char *common_block_name; + +/* Process a N_BCOMM symbol. The storage for NAME is not guaranteed + to remain after this function returns. */ + +void +common_block_start (name, objfile) + char *name; + struct objfile *objfile; +{ + if (common_block_name != NULL) + { + static struct complaint msg = { + "Invalid symbol data: common block within common block", + 0, 0}; + complain (&msg); + } + common_block = local_symbols; + common_block_i = local_symbols ? local_symbols->nsyms : 0; + common_block_name = obsavestring (name, strlen (name), + &objfile -> symbol_obstack); +} + +/* Process a N_ECOMM symbol. */ + +void +common_block_end (objfile) + struct objfile *objfile; +{ + /* Symbols declared since the BCOMM are to have the common block + start address added in when we know it. common_block and + common_block_i point to the first symbol after the BCOMM in + the local_symbols list; copy the list and hang it off the + symbol for the common block name for later fixup. */ + int i; + struct symbol *sym; + struct pending *new = 0; + struct pending *next; + int j; + + if (common_block_name == NULL) + { + static struct complaint msg = {"ECOMM symbol unmatched by BCOMM", 0, 0}; + complain (&msg); + return; + } + + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = common_block_name; + SYMBOL_CLASS (sym) = LOC_BLOCK; + + /* Now we copy all the symbols which have been defined since the BCOMM. */ + + /* Copy all the struct pendings before common_block. */ + for (next = local_symbols; + next != NULL && next != common_block; + next = next->next) + { + for (j = 0; j < next->nsyms; j++) + add_symbol_to_list (next->symbol[j], &new); + } + + /* Copy however much of COMMON_BLOCK we need. If COMMON_BLOCK is + NULL, it means copy all the local symbols (which we already did + above). */ + + if (common_block != NULL) + for (j = common_block_i; j < common_block->nsyms; j++) + add_symbol_to_list (common_block->symbol[j], &new); + + SYMBOL_NAMESPACE (sym) = (enum namespace)((long) new); + + /* Should we be putting local_symbols back to what it was? + Does it matter? */ + + i = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i]; + global_sym_chain[i] = sym; + common_block_name = NULL; +} + +/* Add a common block's start address to the offset of each symbol + declared to be in it (by being between a BCOMM/ECOMM pair that uses + the common block name). */ + +static void +fix_common_block (sym, valu) + struct symbol *sym; + int valu; +{ + struct pending *next = (struct pending *) SYMBOL_NAMESPACE (sym); + for ( ; next; next = next->next) + { + register int j; + for (j = next->nsyms - 1; j >= 0; j--) + SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu; + } +} + + + +/* What about types defined as forward references inside of a small lexical + scope? */ +/* Add a type to the list of undefined types to be checked through + once this file has been read in. */ + +void +add_undefined_type (type) + struct type *type; +{ + if (undef_types_length == undef_types_allocated) + { + undef_types_allocated *= 2; + undef_types = (struct type **) + xrealloc ((char *) undef_types, + undef_types_allocated * sizeof (struct type *)); + } + undef_types[undef_types_length++] = type; +} + +/* Go through each undefined type, see if it's still undefined, and fix it + up if possible. We have two kinds of undefined types: + + TYPE_CODE_ARRAY: Array whose target type wasn't defined yet. + Fix: update array length using the element bounds + and the target type's length. + TYPE_CODE_STRUCT, TYPE_CODE_UNION: Structure whose fields were not + yet defined at the time a pointer to it was made. + Fix: Do a full lookup on the struct/union tag. */ +void +cleanup_undefined_types () +{ + struct type **type; + + for (type = undef_types; type < undef_types + undef_types_length; type++) + { + switch (TYPE_CODE (*type)) + { + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + { + /* Check if it has been defined since. */ + if (TYPE_FLAGS (*type) & TYPE_FLAG_STUB) + { + struct pending *ppt; + int i; + /* Name of the type, without "struct" or "union" */ + char *typename = TYPE_TAG_NAME (*type); + + if (typename == NULL) + { + static struct complaint msg = {"need a type name", 0, 0}; + complain (&msg); + break; + } + for (ppt = file_symbols; ppt; ppt = ppt->next) + { + for (i = 0; i < ppt->nsyms; i++) + { + struct symbol *sym = ppt->symbol[i]; + + if (SYMBOL_CLASS (sym) == LOC_TYPEDEF + && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE + && (TYPE_CODE (SYMBOL_TYPE (sym)) == + TYPE_CODE (*type)) + && STREQ (SYMBOL_NAME (sym), typename)) + { + memcpy (*type, SYMBOL_TYPE (sym), + sizeof (struct type)); + } + } + } + } + } + break; + + case TYPE_CODE_ARRAY: + { + struct type *range_type; + int lower, upper; + + if (TYPE_LENGTH (*type) != 0) /* Better be unknown */ + goto badtype; + if (TYPE_NFIELDS (*type) != 1) + goto badtype; + range_type = TYPE_FIELD_TYPE (*type, 0); + if (TYPE_CODE (range_type) != TYPE_CODE_RANGE) + goto badtype; + + /* Now recompute the length of the array type, based on its + number of elements and the target type's length. */ + lower = TYPE_FIELD_BITPOS (range_type, 0); + upper = TYPE_FIELD_BITPOS (range_type, 1); + TYPE_LENGTH (*type) = (upper - lower + 1) + * TYPE_LENGTH (TYPE_TARGET_TYPE (*type)); + } + break; + + default: + badtype: + { + static struct complaint msg = {"\ +GDB internal error. cleanup_undefined_types with bad type %d.", 0, 0}; + complain (&msg, TYPE_CODE (*type)); + } + break; + } + } + undef_types_length = 0; +} + +/* Scan through all of the global symbols defined in the object file, + assigning values to the debugging symbols that need to be assigned + to. Get these symbols from the minimal symbol table. */ + +void +scan_file_globals (objfile) + struct objfile *objfile; +{ + int hash; + struct minimal_symbol *msymbol; + struct symbol *sym, *prev; + + if (objfile->msymbols == 0) /* Beware the null file. */ + return; + + for (msymbol = objfile -> msymbols; SYMBOL_NAME (msymbol) != NULL; msymbol++) + { + QUIT; + + prev = NULL; + + /* Get the hash index and check all the symbols + under that hash index. */ + + hash = hashname (SYMBOL_NAME (msymbol)); + + for (sym = global_sym_chain[hash]; sym;) + { + if (SYMBOL_NAME (msymbol)[0] == SYMBOL_NAME (sym)[0] && + STREQ(SYMBOL_NAME (msymbol) + 1, SYMBOL_NAME (sym) + 1)) + { + /* Splice this symbol out of the hash chain and + assign the value we have to it. */ + if (prev) + { + SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym); + } + else + { + global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym); + } + + /* Check to see whether we need to fix up a common block. */ + /* Note: this code might be executed several times for + the same symbol if there are multiple references. */ + + if (SYMBOL_CLASS (sym) == LOC_BLOCK) + { + fix_common_block (sym, SYMBOL_VALUE_ADDRESS (msymbol)); + } + else + { + SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msymbol); + } + + if (prev) + { + sym = SYMBOL_VALUE_CHAIN (prev); + } + else + { + sym = global_sym_chain[hash]; + } + } + else + { + prev = sym; + sym = SYMBOL_VALUE_CHAIN (sym); + } + } + } +} + +/* Initialize anything that needs initializing when starting to read + a fresh piece of a symbol file, e.g. reading in the stuff corresponding + to a psymtab. */ + +void +stabsread_init () +{ +} + +/* Initialize anything that needs initializing when a completely new + symbol file is specified (not just adding some symbols from another + file, e.g. a shared library). */ + +void +stabsread_new_init () +{ + /* Empty the hash table of global syms looking for values. */ + memset (global_sym_chain, 0, sizeof (global_sym_chain)); +} + +/* Initialize anything that needs initializing at the same time as + start_symtab() is called. */ + +void start_stabs () +{ + global_stabs = NULL; /* AIX COFF */ + /* Leave FILENUM of 0 free for builtin types and this file's types. */ + n_this_object_header_files = 1; + type_vector_length = 0; + type_vector = (struct type **) 0; + + /* FIXME: If common_block_name is not already NULL, we should complain(). */ + common_block_name = NULL; +} + +/* Call after end_symtab() */ + +void end_stabs () +{ + if (type_vector) + { + free ((char *) type_vector); + } + type_vector = 0; + type_vector_length = 0; + previous_stab_code = 0; +} + +void +finish_global_stabs (objfile) + struct objfile *objfile; +{ + if (global_stabs) + { + patch_block_stabs (global_symbols, global_stabs, objfile); + free ((PTR) global_stabs); + global_stabs = NULL; + } +} + +/* Initializer for this module */ + +void +_initialize_stabsread () +{ + undef_types_allocated = 20; + undef_types_length = 0; + undef_types = (struct type **) + xmalloc (undef_types_allocated * sizeof (struct type *)); +} diff --git a/gnu/usr.bin/gdb/gdb/stabsread.h b/gnu/usr.bin/gdb/gdb/stabsread.h new file mode 100644 index 00000000000..3b890d80584 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/stabsread.h @@ -0,0 +1,194 @@ +/* Include file for stabs debugging format support functions. + Copyright 1986-1991, 1992, 1993 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. */ + +/* Definitions, prototypes, etc for stabs debugging format support + functions. + + Variables declared in this file can be defined by #define-ing + the name EXTERN to null. It is used to declare variables that + are normally extern, but which get defined in a single module + using this technique. */ + +#ifndef EXTERN +#define EXTERN extern +#endif + +/* Convert stab register number (from `r' declaration) to a gdb REGNUM. */ + +#ifndef STAB_REG_TO_REGNUM +#define STAB_REG_TO_REGNUM(VALUE) (VALUE) +#endif + +/* Hash table of global symbols whose values are not known yet. + They are chained thru the SYMBOL_VALUE_CHAIN, since we don't + have the correct data for that slot yet. + + The use of the LOC_BLOCK code in this chain is nonstandard-- + it refers to a FORTRAN common block rather than the usual meaning. */ + +EXTERN struct symbol *global_sym_chain[HASHSIZE]; + +extern void common_block_start PARAMS ((char *, struct objfile *)); +extern void common_block_end PARAMS ((struct objfile *)); + +/* Kludge for xcoffread.c */ + +struct pending_stabs +{ + int count; + int length; + char *stab[1]; +}; + +EXTERN struct pending_stabs *global_stabs; + +/* The type code that process_one_symbol saw on its previous invocation. + Used to detect pairs of N_SO symbols. */ + +EXTERN int previous_stab_code; + +/* Support for Sun changes to dbx symbol format */ + +/* For each identified header file, we have a table of types defined + in that header file. + + header_files maps header file names to their type tables. + It is a vector of n_header_files elements. + Each element describes one header file. + It contains a vector of types. + + Sometimes it can happen that the same header file produces + different results when included in different places. + This can result from conditionals or from different + things done before including the file. + When this happens, there are multiple entries for the file in this table, + one entry for each distinct set of results. + The entries are distinguished by the INSTANCE field. + The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is + used to match header-file references to their corresponding data. */ + +struct header_file +{ + + /* Name of header file */ + + char *name; + + /* Numeric code distinguishing instances of one header file that produced + different results when included. It comes from the N_BINCL or N_EXCL. */ + + int instance; + + /* Pointer to vector of types */ + + struct type **vector; + + /* Allocated length (# elts) of that vector */ + + int length; + +}; + +EXTERN struct header_file *header_files; + +EXTERN int n_header_files; + +EXTERN int n_allocated_header_files; + +/* Within each object file, various header files are assigned numbers. + A type is defined or referred to with a pair of numbers + (FILENUM,TYPENUM) where FILENUM is the number of the header file + and TYPENUM is the number within that header file. + TYPENUM is the index within the vector of types for that header file. + + FILENUM == 1 is special; it refers to the main source of the object file, + and not to any header file. FILENUM != 1 is interpreted by looking it up + in the following table, which contains indices in header_files. */ + +EXTERN int *this_object_header_files; + +EXTERN int n_this_object_header_files; + +EXTERN int n_allocated_this_object_header_files; + +extern struct complaint unknown_symtype_complaint; +extern struct complaint unknown_symchar_complaint; + +extern struct type * +read_type PARAMS ((char **, struct objfile *)); + +extern void +cleanup_undefined_types PARAMS ((void)); + +extern struct type ** +dbx_lookup_type PARAMS ((int [2])); + +extern long +read_number PARAMS ((char **, int)); + +extern void +add_undefined_type PARAMS ((struct type *)); + +extern struct symbol * +define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *)); + +extern void +stabsread_init PARAMS ((void)); + +extern void +stabsread_new_init PARAMS ((void)); + +extern void +start_stabs PARAMS ((void)); + +extern void +end_stabs PARAMS ((void)); + +extern void +finish_global_stabs PARAMS ((struct objfile *objfile)); + +/* Functions exported by dbxread.c. These are not in stabsread.h because + they are only used by some stabs readers. */ + +extern struct partial_symtab * +start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *, + CORE_ADDR, int, struct partial_symbol *, + struct partial_symbol *)); + +extern struct partial_symtab * +end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR, + struct partial_symtab **, int)); + +extern void +process_one_symbol PARAMS ((int, int, CORE_ADDR, char *, + struct section_offsets *, struct objfile *)); + +extern void +elfstab_build_psymtabs PARAMS ((struct objfile *objfile, + struct section_offsets *section_offsets, + int mainline, + file_ptr staboff, unsigned int stabsize, + file_ptr stabstroffset, + unsigned int stabstrsize)); + +extern void +pastab_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *, + int)); + +#undef EXTERN diff --git a/gnu/usr.bin/gdb/gdb/stack.c b/gnu/usr.bin/gdb/gdb/stack.c new file mode 100644 index 00000000000..6fdd8c18124 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/stack.c @@ -0,0 +1,1379 @@ +/* Print and select stack frames for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 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. */ + +#include "defs.h" +#include "value.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "language.h" +#include "frame.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "target.h" +#include "breakpoint.h" +#include "demangle.h" +#include "inferior.h" + +static void +return_command PARAMS ((char *, int)); + +static void +down_command PARAMS ((char *, int)); + +static void +down_silently_command PARAMS ((char *, int)); + +static void +up_command PARAMS ((char *, int)); + +static void +up_silently_command PARAMS ((char *, int)); + +static void +frame_command PARAMS ((char *, int)); + +static void +select_frame_command PARAMS ((char *, int)); + +static void +args_info PARAMS ((char *, int)); + +static void +print_frame_arg_vars PARAMS ((FRAME, FILE *)); + +static void +catch_info PARAMS ((char *, int)); + +static void +locals_info PARAMS ((char *, int)); + +static void +print_frame_label_vars PARAMS ((FRAME, int, FILE *)); + +static void +print_frame_local_vars PARAMS ((FRAME, FILE *)); + +static int +print_block_frame_labels PARAMS ((struct block *, int *, FILE *)); + +static int +print_block_frame_locals PARAMS ((struct block *, FRAME, FILE *)); + +static void +backtrace_command PARAMS ((char *, int)); + +static FRAME +parse_frame_specification PARAMS ((char *)); + +static void +frame_info PARAMS ((char *, int)); + + +extern int addressprint; /* Print addresses, or stay symbolic only? */ +extern int info_verbose; /* Verbosity of symbol reading msgs */ +extern int lines_to_list; /* # of lines "list" command shows by default */ + +/* The "selected" stack frame is used by default for local and arg access. + May be zero, for no selected frame. */ + +FRAME selected_frame; + +/* Level of the selected frame: + 0 for innermost, 1 for its caller, ... + or -1 for frame specified by address with no defined level. */ + +int selected_frame_level; + +/* Nonzero means print the full filename and linenumber + when a frame is printed, and do so in a format programs can parse. */ + +int frame_file_full_name = 0; + + +struct print_stack_frame_args { + struct frame_info *fi; + int level; + int source; + int args; +}; + +static int print_stack_frame_stub PARAMS ((char *)); + +/* Pass the args the way catch_errors wants them. */ +static int +print_stack_frame_stub (args) + char *args; +{ + struct print_stack_frame_args *p = (struct print_stack_frame_args *)args; + print_frame_info (p->fi, p->level, p->source, p->args); + return 0; +} + +/* Print a stack frame briefly. FRAME should be the frame id + and LEVEL should be its level in the stack (or -1 for level not defined). + This prints the level, the function executing, the arguments, + and the file name and line number. + If the pc is not at the beginning of the source line, + the actual pc is printed at the beginning. + + If SOURCE is 1, print the source line as well. + If SOURCE is -1, print ONLY the source line. */ + +void +print_stack_frame (frame, level, source) + FRAME frame; + int level; + int source; +{ + struct print_stack_frame_args args; + + args.fi = get_frame_info (frame); + args.level = level; + args.source = source; + args.args = 1; + + catch_errors (print_stack_frame_stub, (char *)&args, "", RETURN_MASK_ERROR); +} + +struct print_args_args { + struct symbol *func; + struct frame_info *fi; +}; + +static int print_args_stub PARAMS ((char *)); + +/* Pass the args the way catch_errors wants them. */ +static int +print_args_stub (args) + char *args; +{ + int numargs; + struct print_args_args *p = (struct print_args_args *)args; + FRAME_NUM_ARGS (numargs, (p->fi)); + print_frame_args (p->func, p->fi, numargs, stdout); + return 0; +} + +void +print_frame_info (fi, level, source, args) + struct frame_info *fi; + register int level; + int source; + int args; +{ + struct symtab_and_line sal; + struct symbol *func; + register char *funname = 0; + enum language funlang = language_unknown; + char buf[MAX_REGISTER_RAW_SIZE]; + CORE_ADDR sp; + + /* Get the value of SP_REGNUM relative to the frame. */ + get_saved_register (buf, (int *)NULL, (CORE_ADDR *)NULL, + FRAME_INFO_ID (fi), SP_REGNUM, (enum lval_type *)NULL); + sp = extract_address (buf, REGISTER_RAW_SIZE (SP_REGNUM)); + + /* This is not a perfect test, because if a function alloca's some + memory, puts some code there, and then jumps into it, then the test + will succeed even though there is no call dummy. Probably best is + to check for a bp_call_dummy breakpoint. */ + if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame)) + { + /* Do this regardless of SOURCE because we don't have any source + to list for this frame. */ + if (level >= 0) + printf_filtered ("#%-2d ", level); + printf_filtered ("\n"); + return; + } + if (fi->signal_handler_caller) + { + /* Do this regardless of SOURCE because we don't have any source + to list for this frame. */ + if (level >= 0) + printf_filtered ("#%-2d ", level); + printf_filtered ("\n"); + return; + } + + /* If fi is not the innermost frame, that normally means that fi->pc + points to *after* the call instruction, and we want to get the line + containing the call, never the next line. But if the next frame is + a signal_handler_caller frame, then the next frame was not entered + as the result of a call, and we want to get the line containing + fi->pc. */ + sal = + find_pc_line (fi->pc, + fi->next != NULL && fi->next->signal_handler_caller == 0); + + func = find_pc_function (fi->pc); + if (func) + { + /* In certain pathological cases, the symtabs give the wrong + function (when we are in the first function in a file which + is compiled without debugging symbols, the previous function + is compiled with debugging symbols, and the "foo.o" symbol + that is supposed to tell us where the file with debugging symbols + ends has been truncated by ar because it is longer than 15 + characters). This also occurs if the user uses asm() to create + a function but not stabs for it (in a file compiled -g). + + So look in the minimal symbol tables as well, and if it comes + up with a larger address for the function use that instead. + I don't think this can ever cause any problems; there shouldn't + be any minimal symbols in the middle of a function; if this is + ever changed many parts of GDB will need to be changed (and we'll + create a find_pc_minimal_function or some such). */ + + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); + if (msymbol != NULL + && (SYMBOL_VALUE_ADDRESS (msymbol) + > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) + { + /* In this case we have no way of knowing the source file + and line number, so don't print them. */ + sal.symtab = 0; + /* We also don't know anything about the function besides + its address and name. */ + func = 0; + funname = SYMBOL_NAME (msymbol); + funlang = SYMBOL_LANGUAGE (msymbol); + } + else + { + funname = SYMBOL_NAME (func); + funlang = SYMBOL_LANGUAGE (func); + } + } + else + { + register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); + if (msymbol != NULL) + { + funname = SYMBOL_NAME (msymbol); + funlang = SYMBOL_LANGUAGE (msymbol); + } + } + + if (source >= 0 || !sal.symtab) + { + if (level >= 0) + printf_filtered ("#%-2d ", level); + if (addressprint) + if (fi->pc != sal.pc || !sal.symtab) + printf_filtered ("%s in ", local_hex_string((unsigned long) fi->pc)); + fprintf_symbol_filtered (stdout, funname ? funname : "??", funlang, + DMGL_NO_OPTS); + wrap_here (" "); + fputs_filtered (" (", stdout); + if (args) + { + struct print_args_args args; + args.fi = fi; + args.func = func; + catch_errors (print_args_stub, (char *)&args, "", RETURN_MASK_ERROR); + } + printf_filtered (")"); + if (sal.symtab && sal.symtab->filename) + { + wrap_here (" "); + printf_filtered (" at %s:%d", sal.symtab->filename, sal.line); + } + +#ifdef PC_LOAD_SEGMENT + /* If we couldn't print out function name but if can figure out what + load segment this pc value is from, at least print out some info + about its load segment. */ + if (!funname) { + wrap_here (" "); + printf_filtered (" from %s", PC_LOAD_SEGMENT (fi->pc)); + } +#endif + printf_filtered ("\n"); + } + + if ((source != 0) && sal.symtab) + { + int done = 0; + int mid_statement = source < 0 && fi->pc != sal.pc; + if (frame_file_full_name) + done = identify_source_line (sal.symtab, sal.line, mid_statement, + fi->pc); + if (!done) + { + if (addressprint && mid_statement) + printf_filtered ("%s\t", local_hex_string((unsigned long) fi->pc)); + print_source_lines (sal.symtab, sal.line, sal.line + 1, 0); + } + current_source_line = max (sal.line - lines_to_list/2, 1); + } + if (source != 0) + set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); + + fflush (stdout); +} + +/* + * Read a frame specification in whatever the appropriate format is. + * Call error() if the specification is in any way invalid (i.e. + * this function never returns NULL). + */ +static FRAME +parse_frame_specification (frame_exp) + char *frame_exp; +{ + int numargs = 0; +#define MAXARGS 4 + CORE_ADDR args[MAXARGS]; + + if (frame_exp) + { + char *addr_string, *p; + struct cleanup *tmp_cleanup; + + while (*frame_exp == ' ') frame_exp++; + + while (*frame_exp) + { + if (numargs > MAXARGS) + error ("Too many args in frame specification"); + /* Parse an argument. */ + for (p = frame_exp; *p && *p != ' '; p++) + ; + addr_string = savestring(frame_exp, p - frame_exp); + + { + tmp_cleanup = make_cleanup (free, addr_string); + args[numargs++] = parse_and_eval_address (addr_string); + do_cleanups (tmp_cleanup); + } + + /* Skip spaces, move to possible next arg. */ + while (*p == ' ') p++; + frame_exp = p; + } + } + + switch (numargs) + { + case 0: + if (selected_frame == NULL) + error ("No selected frame."); + return selected_frame; + /* NOTREACHED */ + case 1: + { + int level = args[0]; + FRAME fid = find_relative_frame (get_current_frame (), &level); + FRAME tfid; + + if (level == 0) + /* find_relative_frame was successful */ + return fid; + + /* If (s)he specifies the frame with an address, he deserves what + (s)he gets. Still, give the highest one that matches. */ + + for (fid = get_current_frame (); + fid && FRAME_FP (fid) != args[0]; + fid = get_prev_frame (fid)) + ; + + if (fid) + while ((tfid = get_prev_frame (fid)) && + (FRAME_FP (tfid) == args[0])) + fid = tfid; + + /* We couldn't identify the frame as an existing frame, but + perhaps we can create one with a single argument. + Fall through to default case; it's up to SETUP_ARBITRARY_FRAME + to complain if it doesn't like a single arg. */ + } + + default: +#ifdef SETUP_ARBITRARY_FRAME + return SETUP_ARBITRARY_FRAME (numargs, args); +#else + /* Usual case. Do it here rather than have everyone supply + a SETUP_ARBITRARY_FRAME that does this. */ + if (numargs == 1) + return create_new_frame (args[0], 0); + error ("Too many args in frame specification"); +#endif + /* NOTREACHED */ + } + /* NOTREACHED */ +} + +/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except + that if it is unsure about the answer, it returns 0 + instead of guessing (this happens on the VAX and i960, for example). + + On most machines, we never have to guess about the args address, + so FRAME_ARGS_ADDRESS{,_CORRECT} are the same. */ +#if !defined (FRAME_ARGS_ADDRESS_CORRECT) +#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS +#endif + +/* Print verbosely the selected frame or the frame at address ADDR. + This means absolutely all information in the frame is printed. */ + +static void +frame_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ + FRAME frame; + struct frame_info *fi; + struct frame_saved_regs fsr; + struct symtab_and_line sal; + struct symbol *func; + struct symtab *s; + FRAME calling_frame; + int i, count; + char *funname = 0; + enum language funlang = language_unknown; + + if (!target_has_stack) + error ("No stack."); + + frame = parse_frame_specification (addr_exp); + if (!frame) + error ("Invalid frame specified."); + + fi = get_frame_info (frame); + sal = find_pc_line (fi->pc, + fi->next != NULL && fi->next->signal_handler_caller == 0); + func = get_frame_function (frame); + s = find_pc_symtab(fi->pc); + if (func) + { + funname = SYMBOL_NAME (func); + funlang = SYMBOL_LANGUAGE (func); + } + else + { + register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); + if (msymbol != NULL) + { + funname = SYMBOL_NAME (msymbol); + funlang = SYMBOL_LANGUAGE (msymbol); + } + } + calling_frame = get_prev_frame (frame); + + if (!addr_exp && selected_frame_level >= 0) { + printf_filtered ("Stack level %d, frame at %s:\n", + selected_frame_level, + local_hex_string((unsigned long) FRAME_FP(frame))); + } else { + printf_filtered ("Stack frame at %s:\n", + local_hex_string((unsigned long) FRAME_FP(frame))); + } + printf_filtered (" %s = %s", + reg_names[PC_REGNUM], + local_hex_string((unsigned long) fi->pc)); + + wrap_here (" "); + if (funname) + { + printf_filtered (" in "); + fprintf_symbol_filtered (stdout, funname, funlang, + DMGL_ANSI | DMGL_PARAMS); + } + wrap_here (" "); + if (sal.symtab) + printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line); + puts_filtered ("; "); + wrap_here (" "); + printf_filtered ("saved %s %s\n", reg_names[PC_REGNUM], + local_hex_string((unsigned long) FRAME_SAVED_PC (frame))); + + { + int frameless = 0; +#ifdef FRAMELESS_FUNCTION_INVOCATION + FRAMELESS_FUNCTION_INVOCATION (fi, frameless); +#endif + if (frameless) + printf_filtered (" (FRAMELESS),"); + } + + if (calling_frame) + printf_filtered (" called by frame at %s", + local_hex_string((unsigned long) FRAME_FP (calling_frame))); + if (fi->next && calling_frame) + puts_filtered (","); + wrap_here (" "); + if (fi->next) + printf_filtered (" caller of frame at %s", + local_hex_string ((unsigned long) fi->next->frame)); + if (fi->next || calling_frame) + puts_filtered ("\n"); + if (s) + printf_filtered(" source language %s.\n", language_str(s->language)); + +#ifdef PRINT_EXTRA_FRAME_INFO + PRINT_EXTRA_FRAME_INFO (fi); +#endif + + { + /* Address of the argument list for this frame, or 0. */ + CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi); + /* Number of args for this frame, or -1 if unknown. */ + int numargs; + + if (arg_list == 0) + printf_filtered (" Arglist at unknown address.\n"); + else + { + printf_filtered (" Arglist at %s,", + local_hex_string((unsigned long) arg_list)); + + FRAME_NUM_ARGS (numargs, fi); + if (numargs < 0) + puts_filtered (" args: "); + else if (numargs == 0) + puts_filtered (" no args."); + else if (numargs == 1) + puts_filtered (" 1 arg: "); + else + printf_filtered (" %d args: ", numargs); + print_frame_args (func, fi, numargs, stdout); + puts_filtered ("\n"); + } + } + { + /* Address of the local variables for this frame, or 0. */ + CORE_ADDR arg_list = FRAME_LOCALS_ADDRESS (fi); + + if (arg_list == 0) + printf_filtered (" Locals at unknown address,"); + else + printf_filtered (" Locals at %s,", + local_hex_string((unsigned long) arg_list)); + } + +#if defined (FRAME_FIND_SAVED_REGS) + get_frame_saved_regs (fi, &fsr); + /* The sp is special; what's returned isn't the save address, but + actually the value of the previous frame's sp. */ + printf_filtered (" Previous frame's sp is %s\n", + local_hex_string((unsigned long) fsr.regs[SP_REGNUM])); + count = 0; + for (i = 0; i < NUM_REGS; i++) + if (fsr.regs[i] && i != SP_REGNUM) + { + if (count == 0) + puts_filtered (" Saved registers:\n "); + else + puts_filtered (","); + wrap_here (" "); + printf_filtered (" %s at %s", reg_names[i], + local_hex_string((unsigned long) fsr.regs[i])); + count++; + } + if (count) + puts_filtered ("\n"); +#endif /* Have FRAME_FIND_SAVED_REGS. */ +} + +#if 0 +/* Set a limit on the number of frames printed by default in a + backtrace. */ + +static int backtrace_limit; + +static void +set_backtrace_limit_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + int count = parse_and_eval_address (count_exp); + + if (count < 0) + error ("Negative argument not meaningful as backtrace limit."); + + backtrace_limit = count; +} + +static void +backtrace_limit_info (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg) + error ("\"Info backtrace-limit\" takes no arguments."); + + printf ("Backtrace limit: %d.\n", backtrace_limit); +} +#endif + +/* Print briefly all stack frames or just the innermost COUNT frames. */ + +static void +backtrace_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + struct frame_info *fi; + register int count; + register FRAME frame; + register int i; + register FRAME trailing; + register int trailing_level; + + if (!target_has_stack) + error ("No stack."); + + /* The following code must do two things. First, it must + set the variable TRAILING to the frame from which we should start + printing. Second, it must set the variable count to the number + of frames which we should print, or -1 if all of them. */ + trailing = get_current_frame (); + trailing_level = 0; + if (count_exp) + { + count = parse_and_eval_address (count_exp); + if (count < 0) + { + FRAME current; + + count = -count; + + current = trailing; + while (current && count--) + { + QUIT; + current = get_prev_frame (current); + } + + /* Will stop when CURRENT reaches the top of the stack. TRAILING + will be COUNT below it. */ + while (current) + { + QUIT; + trailing = get_prev_frame (trailing); + current = get_prev_frame (current); + trailing_level++; + } + + count = -1; + } + } + else + count = -1; + + if (info_verbose) + { + struct partial_symtab *ps; + + /* Read in symbols for all of the frames. Need to do this in + a separate pass so that "Reading in symbols for xxx" messages + don't screw up the appearance of the backtrace. Also + if people have strong opinions against reading symbols for + backtrace this may have to be an option. */ + i = count; + for (frame = trailing; + frame != NULL && i--; + frame = get_prev_frame (frame)) + { + QUIT; + fi = get_frame_info (frame); + ps = find_pc_psymtab (fi->pc); + if (ps) + PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in */ + } + } + + for (i = 0, frame = trailing; + frame && count--; + i++, frame = get_prev_frame (frame)) + { + QUIT; + fi = get_frame_info (frame); + + /* Don't use print_stack_frame; if an error() occurs it probably + means further attempts to backtrace would fail (on the other + hand, perhaps the code does or could be fixed to make sure + the frame->prev field gets set to NULL in that case). */ + print_frame_info (fi, trailing_level + i, 0, 1); + } + + /* If we've stopped before the end, mention that. */ + if (frame && from_tty) + printf_filtered ("(More stack frames follow...)\n"); +} + +/* Print the local variables of a block B active in FRAME. + Return 1 if any variables were printed; 0 otherwise. */ + +static int +print_block_frame_locals (b, frame, stream) + struct block *b; + register FRAME frame; + register FILE *stream; +{ + int nsyms; + register int i; + register struct symbol *sym; + register int values_printed = 0; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (sym) == LOC_LOCAL + || SYMBOL_CLASS (sym) == LOC_REGISTER + || SYMBOL_CLASS (sym) == LOC_STATIC) + { + values_printed = 1; + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream); + fputs_filtered (" = ", stream); + print_variable_value (sym, frame, stream); + fprintf_filtered (stream, "\n"); + } + } + return values_printed; +} + +/* Same, but print labels. */ + +static int +print_block_frame_labels (b, have_default, stream) + struct block *b; + int *have_default; + register FILE *stream; +{ + int nsyms; + register int i; + register struct symbol *sym; + register int values_printed = 0; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (STREQ (SYMBOL_NAME (sym), "default")) + { + if (*have_default) + continue; + *have_default = 1; + } + if (SYMBOL_CLASS (sym) == LOC_LABEL) + { + struct symtab_and_line sal; + sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0); + values_printed = 1; + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream); + if (addressprint) + fprintf_filtered (stream, " %s", + local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym))); + fprintf_filtered (stream, " in file %s, line %d\n", + sal.symtab->filename, sal.line); + } + } + return values_printed; +} + +/* Print on STREAM all the local variables in frame FRAME, + including all the blocks active in that frame + at its current pc. + + Returns 1 if the job was done, + or 0 if nothing was printed because we have no info + on the function running in FRAME. */ + +static void +print_frame_local_vars (frame, stream) + register FRAME frame; + register FILE *stream; +{ + register struct block *block = get_frame_block (frame); + register int values_printed = 0; + + if (block == 0) + { + fprintf_filtered (stream, "No symbol table info available.\n"); + return; + } + + while (block != 0) + { + if (print_block_frame_locals (block, frame, stream)) + values_printed = 1; + /* After handling the function's top-level block, stop. + Don't continue to its superblock, the block of + per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + + if (!values_printed) + { + fprintf_filtered (stream, "No locals.\n"); + } +} + +/* Same, but print labels. */ + +static void +print_frame_label_vars (frame, this_level_only, stream) + register FRAME frame; + int this_level_only; + register FILE *stream; +{ + register struct blockvector *bl; + register struct block *block = get_frame_block (frame); + register int values_printed = 0; + int index, have_default = 0; + char *blocks_printed; + struct frame_info *fi = get_frame_info (frame); + CORE_ADDR pc = fi->pc; + + if (block == 0) + { + fprintf_filtered (stream, "No symbol table info available.\n"); + return; + } + + bl = blockvector_for_pc (BLOCK_END (block) - 4, &index); + blocks_printed = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); + memset (blocks_printed, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); + + while (block != 0) + { + CORE_ADDR end = BLOCK_END (block) - 4; + int last_index; + + if (bl != blockvector_for_pc (end, &index)) + error ("blockvector blotch"); + if (BLOCKVECTOR_BLOCK (bl, index) != block) + error ("blockvector botch"); + last_index = BLOCKVECTOR_NBLOCKS (bl); + index += 1; + + /* Don't print out blocks that have gone by. */ + while (index < last_index + && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc) + index++; + + while (index < last_index + && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end) + { + if (blocks_printed[index] == 0) + { + if (print_block_frame_labels (BLOCKVECTOR_BLOCK (bl, index), &have_default, stream)) + values_printed = 1; + blocks_printed[index] = 1; + } + index++; + } + if (have_default) + return; + if (values_printed && this_level_only) + return; + + /* After handling the function's top-level block, stop. + Don't continue to its superblock, the block of + per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + + if (!values_printed && !this_level_only) + { + fprintf_filtered (stream, "No catches.\n"); + } +} + +/* ARGSUSED */ +static void +locals_info (args, from_tty) + char *args; + int from_tty; +{ + if (!selected_frame) + error ("No frame selected."); + print_frame_local_vars (selected_frame, stdout); +} + +static void +catch_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + if (!selected_frame) + error ("No frame selected."); + print_frame_label_vars (selected_frame, 0, stdout); +} + +static void +print_frame_arg_vars (frame, stream) + register FRAME frame; + register FILE *stream; +{ + struct symbol *func = get_frame_function (frame); + register struct block *b; + int nsyms; + register int i; + register struct symbol *sym, *sym2; + register int values_printed = 0; + + if (func == 0) + { + fprintf_filtered (stream, "No symbol table info available.\n"); + return; + } + + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_LOCAL_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + values_printed = 1; + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream); + fputs_filtered (" = ", stream); + + /* We have to look up the symbol because arguments can have + two entries (one a parameter, one a local) and the one we + want is the local, which lookup_symbol will find for us. + This includes gcc1 (not gcc2) on the sparc when passing a + small structure and gcc2 when the argument type is float + and it is passed as a double and converted to float by + the prologue (in the latter case the type of the LOC_ARG + symbol is double and the type of the LOC_LOCAL symbol is + float). There are also LOC_ARG/LOC_REGISTER pairs which + are not combined in symbol-reading. */ + + sym2 = lookup_symbol (SYMBOL_NAME (sym), + b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL); + print_variable_value (sym2, frame, stream); + fprintf_filtered (stream, "\n"); + break; + + default: + /* Don't worry about things which aren't arguments. */ + break; + } + } + + if (!values_printed) + { + fprintf_filtered (stream, "No arguments.\n"); + } +} + +static void +args_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + if (!selected_frame) + error ("No frame selected."); + print_frame_arg_vars (selected_frame, stdout); +} + +/* Select frame FRAME, and note that its stack level is LEVEL. + LEVEL may be -1 if an actual level number is not known. */ + +void +select_frame (frame, level) + FRAME frame; + int level; +{ + register struct symtab *s; + + selected_frame = frame; + selected_frame_level = level; + + /* Ensure that symbols for this frame are read in. Also, determine the + source language of this frame, and switch to it if desired. */ + if (frame) + { + s = find_pc_symtab (get_frame_info (frame)->pc); + if (s + && s->language != current_language->la_language + && s->language != language_unknown + && language_mode == language_mode_auto) { + set_language(s->language); + } + } +} + +/* Store the selected frame and its level into *FRAMEP and *LEVELP. + If there is no selected frame, *FRAMEP is set to NULL. */ + +void +record_selected_frame (frameaddrp, levelp) + FRAME_ADDR *frameaddrp; + int *levelp; +{ + *frameaddrp = selected_frame ? FRAME_FP (selected_frame) : 0; + *levelp = selected_frame_level; +} + +/* Return the symbol-block in which the selected frame is executing. + Can return zero under various legitimate circumstances. */ + +struct block * +get_selected_block () +{ + if (!target_has_stack) + return 0; + + if (!selected_frame) + return get_current_block (); + return get_frame_block (selected_frame); +} + +/* Find a frame a certain number of levels away from FRAME. + LEVEL_OFFSET_PTR points to an int containing the number of levels. + Positive means go to earlier frames (up); negative, the reverse. + The int that contains the number of levels is counted toward + zero as the frames for those levels are found. + If the top or bottom frame is reached, that frame is returned, + but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates + how much farther the original request asked to go. */ + +FRAME +find_relative_frame (frame, level_offset_ptr) + register FRAME frame; + register int* level_offset_ptr; +{ + register FRAME prev; + register FRAME frame1; + + /* Going up is simple: just do get_prev_frame enough times + or until initial frame is reached. */ + while (*level_offset_ptr > 0) + { + prev = get_prev_frame (frame); + if (prev == 0) + break; + (*level_offset_ptr)--; + frame = prev; + } + /* Going down is just as simple. */ + if (*level_offset_ptr < 0) + { + while (*level_offset_ptr < 0) { + frame1 = get_next_frame (frame); + if (!frame1) + break; + frame = frame1; + (*level_offset_ptr)++; + } + } + return frame; +} + +/* The "select_frame" command. With no arg, NOP. + With arg LEVEL_EXP, select the frame at level LEVEL if it is a + valid level. Otherwise, treat level_exp as an address expression + and select it. See parse_frame_specification for more info on proper + frame expressions. */ + +/* ARGSUSED */ +static void +select_frame_command (level_exp, from_tty) + char *level_exp; + int from_tty; +{ + register FRAME frame, frame1; + unsigned int level = 0; + + if (!target_has_stack) + error ("No stack."); + + frame = parse_frame_specification (level_exp); + + /* Try to figure out what level this frame is. But if there is + no current stack, don't error out -- let the user set one. */ + frame1 = 0; + if (get_current_frame()) { + for (frame1 = get_prev_frame (0); + frame1 && frame1 != frame; + frame1 = get_prev_frame (frame1)) + level++; + } + + if (!frame1) + level = 0; + + select_frame (frame, level); +} + +/* The "frame" command. With no arg, print selected frame briefly. + With arg, behaves like select_frame and then prints the selected + frame. */ + +static void +frame_command (level_exp, from_tty) + char *level_exp; + int from_tty; +{ + select_frame_command (level_exp, from_tty); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame up one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +/* ARGSUSED */ +static void +up_silently_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + register FRAME frame; + int count = 1, count1; + if (count_exp) + count = parse_and_eval_address (count_exp); + count1 = count; + + if (target_has_stack == 0 || selected_frame == 0) + error ("No stack."); + + frame = find_relative_frame (selected_frame, &count1); + if (count1 != 0 && count_exp == 0) + error ("Initial frame selected; you cannot go up."); + select_frame (frame, selected_frame_level + count - count1); +} + +static void +up_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + up_silently_command (count_exp, from_tty); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame down one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +/* ARGSUSED */ +static void +down_silently_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + register FRAME frame; + int count = -1, count1; + if (count_exp) + count = - parse_and_eval_address (count_exp); + count1 = count; + + if (target_has_stack == 0 || selected_frame == 0) + error ("No stack."); + + frame = find_relative_frame (selected_frame, &count1); + if (count1 != 0 && count_exp == 0) + error ("Bottom (i.e., innermost) frame selected; you cannot go down."); + select_frame (frame, selected_frame_level + count - count1); +} + + +static void +down_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + down_silently_command (count_exp, from_tty); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +static void +return_command (retval_exp, from_tty) + char *retval_exp; + int from_tty; +{ + struct symbol *thisfun; + FRAME_ADDR selected_frame_addr; + CORE_ADDR selected_frame_pc; + FRAME frame; + value return_value = NULL; + + if (selected_frame == NULL) + error ("No selected frame."); + thisfun = get_frame_function (selected_frame); + selected_frame_addr = FRAME_FP (selected_frame); + selected_frame_pc = (get_frame_info (selected_frame))->pc; + + /* Compute the return value (if any -- possibly getting errors here). */ + + if (retval_exp) + { + return_value = parse_and_eval (retval_exp); + + /* Make sure we have fully evaluated it, since + it might live in the stack frame we're about to pop. */ + if (VALUE_LAZY (return_value)) + value_fetch_lazy (return_value); + } + + /* If interactive, require confirmation. */ + + if (from_tty) + { + if (thisfun != 0) + { + if (!query ("Make %s return now? ", SYMBOL_SOURCE_NAME (thisfun))) + { + error ("Not confirmed."); + /* NOTREACHED */ + } + } + else + if (!query ("Make selected stack frame return now? ")) + error ("Not confirmed."); + } + + /* Do the real work. Pop until the specified frame is current. We + use this method because the selected_frame is not valid after + a POP_FRAME. The pc comparison makes this work even if the + selected frame shares its fp with another frame. */ + + while ( selected_frame_addr != FRAME_FP (frame = get_current_frame()) + || selected_frame_pc != (get_frame_info (frame))->pc ) + POP_FRAME; + + /* Then pop that frame. */ + + POP_FRAME; + + /* Compute the return value (if any) and store in the place + for return values. */ + + if (retval_exp) + set_return_value (return_value); + + /* If interactive, print the frame that is now current. */ + + if (from_tty) + frame_command ("0", 1); +} + +/* Gets the language of the current frame. */ +enum language +get_frame_language() +{ + register struct symtab *s; + FRAME fr; + enum language flang; /* The language of the current frame */ + + fr = get_frame_info(selected_frame); + if(fr) + { + s = find_pc_symtab(fr->pc); + if(s) + flang = s->language; + else + flang = language_unknown; + } + else + flang = language_unknown; + + return flang; +} + +void +_initialize_stack () +{ +#if 0 + backtrace_limit = 30; +#endif + + add_com ("return", class_stack, return_command, + "Make selected stack frame return to its caller.\n\ +Control remains in the debugger, but when you continue\n\ +execution will resume in the frame above the one now selected.\n\ +If an argument is given, it is an expression for the value to return."); + + add_com ("up", class_stack, up_command, + "Select and print stack frame that called this one.\n\ +An argument says how many frames up to go."); + add_com ("up-silently", class_support, up_silently_command, + "Same as the `up' command, but does not print anything.\n\ +This is useful in command scripts."); + + add_com ("down", class_stack, down_command, + "Select and print stack frame called by this one.\n\ +An argument says how many frames down to go."); + add_com_alias ("do", "down", class_stack, 1); + add_com_alias ("dow", "down", class_stack, 1); + add_com ("down-silently", class_support, down_silently_command, + "Same as the `down' command, but does not print anything.\n\ +This is useful in command scripts."); + + add_com ("frame", class_stack, frame_command, + "Select and print a stack frame.\n\ +With no argument, print the selected stack frame. (See also \"info frame\").\n\ +An argument specifies the frame to select.\n\ +It can be a stack frame number or the address of the frame.\n\ +With argument, nothing is printed if input is coming from\n\ +a command file or a user-defined command."); + + add_com_alias ("f", "frame", class_stack, 1); + + add_com ("select-frame", class_stack, select_frame_command, + "Select a stack frame without printing anything.\n\ +An argument specifies the frame to select.\n\ +It can be a stack frame number or the address of the frame.\n"); + + add_com ("backtrace", class_stack, backtrace_command, + "Print backtrace of all stack frames, or innermost COUNT frames.\n\ +With a negative argument, print outermost -COUNT frames."); + add_com_alias ("bt", "backtrace", class_stack, 0); + add_com_alias ("where", "backtrace", class_alias, 0); + add_info ("stack", backtrace_command, + "Backtrace of the stack, or innermost COUNT frames."); + add_info_alias ("s", "stack", 1); + add_info ("frame", frame_info, + "All about selected stack frame, or frame at ADDR."); + add_info_alias ("f", "frame", 1); + add_info ("locals", locals_info, + "Local variables of current stack frame."); + add_info ("args", args_info, + "Argument variables of current stack frame."); + add_info ("catch", catch_info, + "Exceptions that can be caught in the current stack frame."); + +#if 0 + add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command, + "Specify maximum number of frames for \"backtrace\" to print by default.", + &setlist); + add_info ("backtrace-limit", backtrace_limit_info, + "The maximum number of frames for \"backtrace\" to print by default."); +#endif +} diff --git a/gnu/usr.bin/gdb/gdb/symfile.c b/gnu/usr.bin/gdb/gdb/symfile.c new file mode 100644 index 00000000000..197c0c3a622 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/symfile.c @@ -0,0 +1,1489 @@ +/* Generic symbol file reading for the GNU debugger, GDB. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "frame.h" +#include "target.h" +#include "value.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcmd.h" +#include "breakpoint.h" +#include "language.h" +#include "complaints.h" +#include "demangle.h" +#include "inferior.h" /* for write_pc */ + +#include +#include + +#include +#include +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* Global variables owned by this file */ + +int readnow_symbol_files; /* Read full symbols immediately */ + +struct complaint oldsyms_complaint = { + "Replacing old symbols for `%s'", 0, 0 +}; + +struct complaint empty_symtab_complaint = { + "Empty symbol table found for `%s'", 0, 0 +}; + +/* External variables and functions referenced. */ + +extern int info_verbose; + +/* Functions this file defines */ + +static void +set_initial_language PARAMS ((void)); + +static void +load_command PARAMS ((char *, int)); + +static void +add_symbol_file_command PARAMS ((char *, int)); + +static void +cashier_psymtab PARAMS ((struct partial_symtab *)); + +static int +compare_psymbols PARAMS ((const void *, const void *)); + +static int +compare_symbols PARAMS ((const void *, const void *)); + +static bfd * +symfile_bfd_open PARAMS ((char *)); + +static void +find_sym_fns PARAMS ((struct objfile *)); + +/* List of all available sym_fns. On gdb startup, each object file reader + calls add_symtab_fns() to register information on each format it is + prepared to read. */ + +static struct sym_fns *symtab_fns = NULL; + +/* Structures with which to manage partial symbol allocation. */ + +struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0}; + +/* Flag for whether user will be reloading symbols multiple times. + Defaults to ON for VxWorks, otherwise OFF. */ + +#ifdef SYMBOL_RELOADING_DEFAULT +int symbol_reloading = SYMBOL_RELOADING_DEFAULT; +#else +int symbol_reloading = 0; +#endif + + +/* Since this function is called from within qsort, in an ANSI environment + it must conform to the prototype for qsort, which specifies that the + comparison function takes two "void *" pointers. */ + +static int +compare_symbols (s1p, s2p) + const PTR s1p; + const PTR s2p; +{ + register struct symbol **s1, **s2; + + s1 = (struct symbol **) s1p; + s2 = (struct symbol **) s2p; + + return (STRCMP (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2))); +} + +/* + +LOCAL FUNCTION + + compare_psymbols -- compare two partial symbols by name + +DESCRIPTION + + Given pointer to two partial symbol table entries, compare + them by name and return -N, 0, or +N (ala strcmp). Typically + used by sorting routines like qsort(). + +NOTES + + Does direct compare of first two characters before punting + and passing to strcmp for longer compares. Note that the + original version had a bug whereby two null strings or two + identically named one character strings would return the + comparison of memory following the null byte. + + */ + +static int +compare_psymbols (s1p, s2p) + const PTR s1p; + const PTR s2p; +{ + register char *st1 = SYMBOL_NAME ((struct partial_symbol *) s1p); + register char *st2 = SYMBOL_NAME ((struct partial_symbol *) s2p); + + if ((st1[0] - st2[0]) || !st1[0]) + { + return (st1[0] - st2[0]); + } + else if ((st1[1] - st2[1]) || !st1[1]) + { + return (st1[1] - st2[1]); + } + else + { + return (STRCMP (st1 + 2, st2 + 2)); + } +} + +void +sort_pst_symbols (pst) + struct partial_symtab *pst; +{ + /* Sort the global list; don't sort the static list */ + + qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset, + pst -> n_global_syms, sizeof (struct partial_symbol), + compare_psymbols); +} + +/* Call sort_block_syms to sort alphabetically the symbols of one block. */ + +void +sort_block_syms (b) + register struct block *b; +{ + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); +} + +/* Call sort_symtab_syms to sort alphabetically + the symbols of each block of one symtab. */ + +void +sort_symtab_syms (s) + register struct symtab *s; +{ + register struct blockvector *bv; + int nbl; + int i; + register struct block *b; + + if (s == 0) + return; + bv = BLOCKVECTOR (s); + nbl = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < nbl; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SHOULD_SORT (b)) + sort_block_syms (b); + } +} + +void +sort_all_symtab_syms () +{ + register struct symtab *s; + register struct objfile *objfile; + + for (objfile = object_files; objfile != NULL; objfile = objfile -> next) + { + for (s = objfile -> symtabs; s != NULL; s = s -> next) + { + sort_symtab_syms (s); + } + } +} + +/* Make a copy of the string at PTR with SIZE characters in the symbol obstack + (and add a null character at the end in the copy). + Returns the address of the copy. */ + +char * +obsavestring (ptr, size, obstackp) + char *ptr; + int size; + struct obstack *obstackp; +{ + register char *p = (char *) obstack_alloc (obstackp, size + 1); + /* Open-coded memcpy--saves function call time. + These strings are usually short. */ + { + register char *p1 = ptr; + register char *p2 = p; + char *end = ptr + size; + while (p1 != end) + *p2++ = *p1++; + } + p[size] = 0; + return p; +} + +/* Concatenate strings S1, S2 and S3; return the new string. + Space is found in the symbol_obstack. */ + +char * +obconcat (obstackp, s1, s2, s3) + struct obstack *obstackp; + const char *s1, *s2, *s3; +{ + register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; + register char *val = (char *) obstack_alloc (obstackp, len); + strcpy (val, s1); + strcat (val, s2); + strcat (val, s3); + return val; +} + +/* Get the symbol table that corresponds to a partial_symtab. + This is fast after the first time you do it. In fact, there + is an even faster macro PSYMTAB_TO_SYMTAB that does the fast + case inline. */ + +struct symtab * +psymtab_to_symtab (pst) + register struct partial_symtab *pst; +{ + /* If it's been looked up before, return it. */ + if (pst->symtab) + return pst->symtab; + + /* If it has not yet been read in, read it. */ + if (!pst->readin) + { + (*pst->read_symtab) (pst); + } + + return pst->symtab; +} + +/* Initialize entry point information for this objfile. */ + +void +init_entry_point_info (objfile) + struct objfile *objfile; +{ + /* Save startup file's range of PC addresses to help blockframe.c + decide where the bottom of the stack is. */ + + if (bfd_get_file_flags (objfile -> obfd) & EXEC_P) + { + /* Executable file -- record its entry point so we'll recognize + the startup file because it contains the entry point. */ + objfile -> ei.entry_point = bfd_get_start_address (objfile -> obfd); + } + else + { + /* Examination of non-executable.o files. Short-circuit this stuff. */ + /* ~0 will not be in any file, we hope. */ + objfile -> ei.entry_point = ~0; + /* set the startup file to be an empty range. */ + objfile -> ei.entry_file_lowpc = 0; + objfile -> ei.entry_file_highpc = 0; + } +} + +/* Get current entry point address. */ + +CORE_ADDR +entry_point_address() +{ + return symfile_objfile ? symfile_objfile->ei.entry_point : 0; +} + +/* Remember the lowest-addressed loadable section we've seen. + This function is called via bfd_map_over_sections. */ + +#if 0 /* Not used yet */ +static void +find_lowest_section (abfd, sect, obj) + bfd *abfd; + asection *sect; + PTR obj; +{ + asection **lowest = (asection **)obj; + + if (0 == (bfd_get_section_flags (abfd, sect) & SEC_LOAD)) + return; + if (!*lowest) + *lowest = sect; /* First loadable section */ + else if (bfd_section_vma (abfd, *lowest) >= bfd_section_vma (abfd, sect)) + *lowest = sect; /* A lower loadable section */ +} +#endif + +/* Process a symbol file, as either the main file or as a dynamically + loaded file. + + NAME is the file name (which will be tilde-expanded and made + absolute herein) (but we don't free or modify NAME itself). + FROM_TTY says how verbose to be. MAINLINE specifies whether this + is the main symbol file, or whether it's an extra symbol file such + as dynamically loaded code. If !mainline, ADDR is the address + where the text segment was loaded. If VERBO, the caller has printed + a verbose message about the symbol reading (and complaints can be + more terse about it). */ + +void +syms_from_objfile (objfile, addr, mainline, verbo) + struct objfile *objfile; + CORE_ADDR addr; + int mainline; + int verbo; +{ + struct section_offsets *section_offsets; + asection *lowest_sect; + struct cleanup *old_chain; + + init_entry_point_info (objfile); + find_sym_fns (objfile); + + /* Make sure that partially constructed symbol tables will be cleaned up + if an error occurs during symbol reading. */ + old_chain = make_cleanup (free_objfile, objfile); + + if (mainline) + { + /* We will modify the main symbol table, make sure that all its users + will be cleaned up if an error occurs during symbol reading. */ + make_cleanup (clear_symtab_users, 0); + + /* Since no error yet, throw away the old symbol table. */ + + if (symfile_objfile != NULL) + { + free_objfile (symfile_objfile); + symfile_objfile = NULL; + } + + (*objfile -> sf -> sym_new_init) (objfile); + } + + /* Convert addr into an offset rather than an absolute address. + We find the lowest address of a loaded segment in the objfile, + and assume that is where that got loaded. Due to historical + precedent, we warn if that doesn't happen to be the ".text" + segment. */ + + if (mainline) + { + addr = 0; /* No offset from objfile addresses. */ + } + else + { + lowest_sect = bfd_get_section_by_name (objfile->obfd, ".text"); +#if 0 + lowest_sect = 0; + bfd_map_over_sections (objfile->obfd, find_lowest_section, + (PTR) &lowest_sect); +#endif + + if (lowest_sect == 0) + warning ("no loadable sections found in added symbol-file %s", + objfile->name); + else if (0 == bfd_get_section_name (objfile->obfd, lowest_sect) + || !STREQ (".text", + bfd_get_section_name (objfile->obfd, lowest_sect))) + warning ("Lowest section in %s is %s at 0x%lx", + objfile->name, + bfd_section_name (objfile->obfd, lowest_sect), + (unsigned long) bfd_section_vma (objfile->obfd, lowest_sect)); + + if (lowest_sect) + addr -= bfd_section_vma (objfile->obfd, lowest_sect); + } + + /* Initialize symbol reading routines for this objfile, allow complaints to + appear for this new file, and record how verbose to be, then do the + initial symbol reading for this file. */ + + (*objfile -> sf -> sym_init) (objfile); + clear_complaints (1, verbo); + + /* If objfile->sf->sym_offsets doesn't set this, we don't care + (currently). */ + objfile->num_sections = 0; /* krp-FIXME: why zero? */ + section_offsets = (*objfile -> sf -> sym_offsets) (objfile, addr); + objfile->section_offsets = section_offsets; + +#ifndef IBM6000_TARGET + /* This is a SVR4/SunOS specific hack, I think. In any event, it + screws RS/6000. sym_offsets should be doing this sort of thing, + because it knows the mapping between bfd sections and + section_offsets. */ + /* This is a hack. As far as I can tell, section offsets are not + target dependent. They are all set to addr with a couple of + exceptions. The exceptions are sysvr4 shared libraries, whose + offsets are kept in solib structures anyway and rs6000 xcoff + which handles shared libraries in a completely unique way. + + Section offsets are built similarly, except that they are built + by adding addr in all cases because there is no clear mapping + from section_offsets into actual sections. Note that solib.c + has a different algorythm for finding section offsets. + + These should probably all be collapsed into some target + independent form of shared library support. FIXME. */ + + if (addr) + { + struct obj_section *s; + + for (s = objfile->sections; s < objfile->sections_end; ++s) + { + s->addr -= s->offset; + s->addr += addr; + s->endaddr -= s->offset; + s->endaddr += addr; + s->offset += addr; + } + } +#endif /* not IBM6000_TARGET */ + + (*objfile -> sf -> sym_read) (objfile, section_offsets, mainline); + + /* Don't allow char * to have a typename (else would get caddr_t.) */ + /* Ditto void *. FIXME should do this for all the builtin types. */ + + TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0; + TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0; + + /* Mark the objfile has having had initial symbol read attempted. Note + that this does not mean we found any symbols... */ + + objfile -> flags |= OBJF_SYMS; + + /* Discard cleanups as symbol reading was successful. */ + + discard_cleanups (old_chain); +} + +/* Perform required actions after either reading in the initial + symbols for a new objfile, or mapping in the symbols from a reusable + objfile. */ + +void +new_symfile_objfile (objfile, mainline, verbo) + struct objfile *objfile; + int mainline; + int verbo; +{ + + /* If this is the main symbol file we have to clean up all users of the + old main symbol file. Otherwise it is sufficient to fixup all the + breakpoints that may have been redefined by this symbol file. */ + if (mainline) + { + /* OK, make it the "real" symbol file. */ + symfile_objfile = objfile; + + clear_symtab_users (); + } + else + { + breakpoint_re_set (); + } + + /* We're done reading the symbol file; finish off complaints. */ + clear_complaints (0, verbo); +} + +/* Process a symbol file, as either the main file or as a dynamically + loaded file. + + NAME is the file name (which will be tilde-expanded and made + absolute herein) (but we don't free or modify NAME itself). + FROM_TTY says how verbose to be. MAINLINE specifies whether this + is the main symbol file, or whether it's an extra symbol file such + as dynamically loaded code. If !mainline, ADDR is the address + where the text segment was loaded. + + Upon success, returns a pointer to the objfile that was added. + Upon failure, jumps back to command level (never returns). */ + +struct objfile * +symbol_file_add (name, from_tty, addr, mainline, mapped, readnow) + char *name; + int from_tty; + CORE_ADDR addr; + int mainline; + int mapped; + int readnow; +{ + struct objfile *objfile; + struct partial_symtab *psymtab; + bfd *abfd; + + /* Open a bfd for the file, and give user a chance to burp if we'd be + interactively wiping out any existing symbols. */ + + abfd = symfile_bfd_open (name); + + if ((have_full_symbols () || have_partial_symbols ()) + && mainline + && from_tty + && !query ("Load new symbol table from \"%s\"? ", name)) + error ("Not confirmed."); + + objfile = allocate_objfile (abfd, mapped); + + /* If the objfile uses a mapped symbol file, and we have a psymtab for + it, then skip reading any symbols at this time. */ + + if ((objfile -> flags & OBJF_MAPPED) && (objfile -> flags & OBJF_SYMS)) + { + /* We mapped in an existing symbol table file that already has had + initial symbol reading performed, so we can skip that part. Notify + the user that instead of reading the symbols, they have been mapped. + */ + if (from_tty || info_verbose) + { + printf_filtered ("Mapped symbols for %s...", name); + wrap_here (""); + fflush (stdout); + } + init_entry_point_info (objfile); + find_sym_fns (objfile); + } + else + { + /* We either created a new mapped symbol table, mapped an existing + symbol table file which has not had initial symbol reading + performed, or need to read an unmapped symbol table. */ + if (from_tty || info_verbose) + { + printf_filtered ("Reading symbols from %s...", name); + wrap_here (""); + fflush (stdout); + } + syms_from_objfile (objfile, addr, mainline, from_tty); + } + + /* We now have at least a partial symbol table. Check to see if the + user requested that all symbols be read on initial access via either + the gdb startup command line or on a per symbol file basis. Expand + all partial symbol tables for this objfile if so. */ + + if (readnow || readnow_symbol_files) + { + if (from_tty || info_verbose) + { + printf_filtered ("expanding to full symbols..."); + wrap_here (""); + fflush (stdout); + } + + for (psymtab = objfile -> psymtabs; + psymtab != NULL; + psymtab = psymtab -> next) + { + psymtab_to_symtab (psymtab); + } + } + + if (from_tty || info_verbose) + { + printf_filtered ("done.\n"); + fflush (stdout); + } + + new_symfile_objfile (objfile, mainline, from_tty); + + /* Getting new symbols may change our opinion about what is + frameless. */ + + reinit_frame_cache (); + + return (objfile); +} + +/* This is the symbol-file command. Read the file, analyze its symbols, + and add a struct symtab to a symtab list. */ + +void +symbol_file_command (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + char *name = NULL; + struct cleanup *cleanups; + int mapped = 0; + int readnow = 0; + + dont_repeat (); + + if (args == NULL) + { + if ((have_full_symbols () || have_partial_symbols ()) + && from_tty + && !query ("Discard symbol table from `%s'? ", + symfile_objfile -> name)) + error ("Not confirmed."); + free_all_objfiles (); + symfile_objfile = NULL; + if (from_tty) + { + printf ("No symbol file now.\n"); + } + } + else + { + if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, (char *) argv); + while (*argv != NULL) + { + if (STREQ (*argv, "-mapped")) + { + mapped = 1; + } + else if (STREQ (*argv, "-readnow")) + { + readnow = 1; + } + else if (**argv == '-') + { + error ("unknown option `%s'", *argv); + } + else + { + name = *argv; + } + argv++; + } + + if (name == NULL) + { + error ("no symbol file name was specified"); + } + else + { + symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow); + set_initial_language (); + } + do_cleanups (cleanups); + } +} + +/* Set the initial language. + + A better solution would be to record the language in the psymtab when reading + partial symbols, and then use it (if known) to set the language. This would + be a win for formats that encode the language in an easily discoverable place, + such as DWARF. For stabs, we can jump through hoops looking for specially + named symbols or try to intuit the language from the specific type of stabs + we find, but we can't do that until later when we read in full symbols. + FIXME. */ + +static void +set_initial_language () +{ + struct partial_symtab *pst; + enum language lang = language_unknown; + + pst = find_main_psymtab (); + if (pst != NULL) + { + if (pst -> filename != NULL) + { + lang = deduce_language_from_filename (pst -> filename); + } + if (lang == language_unknown) + { + /* Make C the default language */ + lang = language_c; + } + set_language (lang); + expected_language = current_language; /* Don't warn the user */ + } +} + +/* Open file specified by NAME and hand it off to BFD for preliminary + analysis. Result is a newly initialized bfd *, which includes a newly + malloc'd` copy of NAME (tilde-expanded and made absolute). + In case of trouble, error() is called. */ + +static bfd * +symfile_bfd_open (name) + char *name; +{ + bfd *sym_bfd; + int desc; + char *absolute_name; + + name = tilde_expand (name); /* Returns 1st new malloc'd copy */ + + /* Look down path for it, allocate 2nd new malloc'd copy. */ + desc = openp (getenv ("PATH"), 1, name, O_RDONLY | O_BINARY, 0, &absolute_name); + if (desc < 0) + { + make_cleanup (free, name); + perror_with_name (name); + } + free (name); /* Free 1st new malloc'd copy */ + name = absolute_name; /* Keep 2nd malloc'd copy in bfd */ + /* It'll be freed in free_objfile(). */ + + sym_bfd = bfd_fdopenr (name, gnutarget, desc); + if (!sym_bfd) + { + close (desc); + make_cleanup (free, name); + error ("\"%s\": can't open to read symbols: %s.", name, + bfd_errmsg (bfd_error)); + } + sym_bfd->cacheable = true; + + if (!bfd_check_format (sym_bfd, bfd_object)) + { + bfd_close (sym_bfd); /* This also closes desc */ + make_cleanup (free, name); + error ("\"%s\": can't read symbols: %s.", name, + bfd_errmsg (bfd_error)); + } + + return (sym_bfd); +} + +/* Link a new symtab_fns into the global symtab_fns list. Called on gdb + startup by the _initialize routine in each object file format reader, + to register information about each format the the reader is prepared + to handle. */ + +void +add_symtab_fns (sf) + struct sym_fns *sf; +{ + sf->next = symtab_fns; + symtab_fns = sf; +} + + +/* Initialize to read symbols from the symbol file sym_bfd. It either + returns or calls error(). The result is an initialized struct sym_fns + in the objfile structure, that contains cached information about the + symbol file. */ + +static void +find_sym_fns (objfile) + struct objfile *objfile; +{ + struct sym_fns *sf; + + for (sf = symtab_fns; sf != NULL; sf = sf -> next) + { + if (strncmp (bfd_get_target (objfile -> obfd), + sf -> sym_name, sf -> sym_namelen) == 0) + { + objfile -> sf = sf; + return; + } + } + error ("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown.", + bfd_get_target (objfile -> obfd)); +} + +/* This function runs the load command of our current target. */ + +static void +load_command (arg, from_tty) + char *arg; + int from_tty; +{ + target_load (arg, from_tty); +} + +/* This version of "load" should be usable for any target. Currently + it is just used for remote targets, not inftarg.c or core files, + on the theory that only in that case is it useful. + + Avoiding xmodem and the like seems like a win (a) because we don't have + to worry about finding it, and (b) On VMS, fork() is very slow and so + we don't want to run a subprocess. On the other hand, I'm not sure how + performance compares. */ +void +generic_load (filename, from_tty) + char *filename; + int from_tty; +{ + struct cleanup *old_cleanups; + asection *s; + bfd *loadfile_bfd = bfd_openr (filename, gnutarget); + if (loadfile_bfd == NULL) + { + perror_with_name (filename); + return; + } + old_cleanups = make_cleanup (bfd_close, loadfile_bfd); + + if (!bfd_check_format (loadfile_bfd, bfd_object)) + { + error ("\"%s\" is not an object file: %s", filename, + bfd_errmsg (bfd_error)); + } + + for (s = loadfile_bfd->sections; s; s = s->next) + { + if (s->flags & SEC_LOAD) + { + bfd_size_type size; + + size = bfd_get_section_size_before_reloc (s); + if (size > 0) + { + char *buffer; + struct cleanup *old_chain; + bfd_vma vma; + + buffer = xmalloc (size); + old_chain = make_cleanup (free, buffer); + + vma = bfd_get_section_vma (loadfile_bfd, s); + + /* Is this really necessary? I guess it gives the user something + to look at during a long download. */ + printf_filtered ("Loading section %s, size 0x%lx vma 0x%lx\n", + bfd_get_section_name (loadfile_bfd, s), + (unsigned long) size, (unsigned long) vma); + + bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size); + + target_write_memory (vma, buffer, size); + + do_cleanups (old_chain); + } + } + } + + /* We were doing this in remote-mips.c, I suspect it is right + for other targets too. */ + write_pc (loadfile_bfd->start_address); + + /* FIXME: are we supposed to call symbol_file_add or not? According to + a comment from remote-mips.c (where a call to symbol_file_add was + commented out), making the call confuses GDB if more than one file is + loaded in. remote-nindy.c had no call to symbol_file_add, but remote-vx.c + does. */ + + do_cleanups (old_cleanups); +} + +/* This function allows the addition of incrementally linked object files. + It does not modify any state in the target, only in the debugger. */ + +/* ARGSUSED */ +static void +add_symbol_file_command (args, from_tty) + char *args; + int from_tty; +{ + char *name = NULL; + CORE_ADDR text_addr; + char *arg; + int readnow = 0; + int mapped = 0; + + dont_repeat (); + + if (args == NULL) + { + error ("add-symbol-file takes a file name and an address"); + } + + /* Make a copy of the string that we can safely write into. */ + + args = strdup (args); + make_cleanup (free, args); + + /* Pick off any -option args and the file name. */ + + while ((*args != '\000') && (name == NULL)) + { + while (isspace (*args)) {args++;} + arg = args; + while ((*args != '\000') && !isspace (*args)) {args++;} + if (*args != '\000') + { + *args++ = '\000'; + } + if (*arg != '-') + { + name = arg; + } + else if (STREQ (arg, "-mapped")) + { + mapped = 1; + } + else if (STREQ (arg, "-readnow")) + { + readnow = 1; + } + else + { + error ("unknown option `%s'", arg); + } + } + + /* After picking off any options and the file name, args should be + left pointing at the remainder of the command line, which should + be the address expression to evaluate. */ + + if ((name == NULL) || (*args == '\000') ) + { + error ("add-symbol-file takes a file name and an address"); + } + name = tilde_expand (name); + make_cleanup (free, name); + + text_addr = parse_and_eval_address (args); + + if (!query ("add symbol table from file \"%s\" at text_addr = %s?\n", + name, local_hex_string ((unsigned long)text_addr))) + error ("Not confirmed."); + + symbol_file_add (name, 0, text_addr, 0, mapped, readnow); +} + +/* Re-read symbols if a symbol-file has changed. */ +void +reread_symbols () +{ + struct objfile *objfile; + long new_modtime; + int reread_one = 0; + struct stat new_statbuf; + int res; + + /* With the addition of shared libraries, this should be modified, + the load time should be saved in the partial symbol tables, since + different tables may come from different source files. FIXME. + This routine should then walk down each partial symbol table + and see if the symbol table that it originates from has been changed */ + +the_big_top: + for (objfile = object_files; objfile; objfile = objfile->next) { + if (objfile->obfd) { +#ifdef IBM6000_TARGET + /* If this object is from a shared library, then you should + stat on the library name, not member name. */ + + if (objfile->obfd->my_archive) + res = stat (objfile->obfd->my_archive->filename, &new_statbuf); + else +#endif + res = stat (objfile->name, &new_statbuf); + if (res != 0) { + /* FIXME, should use print_sys_errmsg but it's not filtered. */ + printf_filtered ("`%s' has disappeared; keeping its symbols.\n", + objfile->name); + continue; + } + new_modtime = new_statbuf.st_mtime; + if (new_modtime != objfile->mtime) { + printf_filtered ("`%s' has changed; re-reading symbols.\n", + objfile->name); + /* FIXME, this should use a different command...that would only + affect this objfile's symbols, and would reset objfile->mtime. + (objfile->mtime = new_modtime;) + HOWEVER, that command isn't written yet -- so call symbol_file_ + command, and restart the scan from the top, because it munges + the object_files list. */ + symbol_file_command (objfile->name, 0); + reread_one = 1; + goto the_big_top; /* Start over. */ + } + } + } + + if (reread_one) + breakpoint_re_set (); +} + + +enum language +deduce_language_from_filename (filename) + char *filename; +{ + char *c; + + if (0 == filename) + ; /* Get default */ + else if (0 == (c = strrchr (filename, '.'))) + ; /* Get default. */ + else if (STREQ(c,".mod")) + return language_m2; + else if (STREQ(c,".c")) + return language_c; + else if (STREQ (c,".cc") || STREQ (c,".C") || STREQ (c, ".cxx")) + return language_cplus; + else if (STREQ (c,".ch") || STREQ (c,".c186") || STREQ (c,".c286")) + return language_chill; + + return language_unknown; /* default */ +} + +/* allocate_symtab: + + Allocate and partly initialize a new symbol table. Return a pointer + to it. error() if no space. + + Caller must set these fields: + LINETABLE(symtab) + symtab->blockvector + symtab->dirname + symtab->free_code + symtab->free_ptr + initialize any EXTRA_SYMTAB_INFO + possibly free_named_symtabs (symtab->filename); + */ + +struct symtab * +allocate_symtab (filename, objfile) + char *filename; + struct objfile *objfile; +{ + register struct symtab *symtab; + + symtab = (struct symtab *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symtab)); + memset (symtab, 0, sizeof (*symtab)); + symtab -> filename = obsavestring (filename, strlen (filename), + &objfile -> symbol_obstack); + symtab -> fullname = NULL; + symtab -> language = deduce_language_from_filename (filename); + + /* Hook it to the objfile it comes from */ + + symtab -> objfile = objfile; + symtab -> next = objfile -> symtabs; + objfile -> symtabs = symtab; + +#ifdef INIT_EXTRA_SYMTAB_INFO + INIT_EXTRA_SYMTAB_INFO (symtab); +#endif + + return (symtab); +} + +struct partial_symtab * +allocate_psymtab (filename, objfile) + char *filename; + struct objfile *objfile; +{ + struct partial_symtab *psymtab; + + if (objfile -> free_psymtabs) + { + psymtab = objfile -> free_psymtabs; + objfile -> free_psymtabs = psymtab -> next; + } + else + psymtab = (struct partial_symtab *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct partial_symtab)); + + memset (psymtab, 0, sizeof (struct partial_symtab)); + psymtab -> filename = obsavestring (filename, strlen (filename), + &objfile -> psymbol_obstack); + psymtab -> symtab = NULL; + + /* Hook it to the objfile it comes from */ + + psymtab -> objfile = objfile; + psymtab -> next = objfile -> psymtabs; + objfile -> psymtabs = psymtab; + + return (psymtab); +} + + +/* Reset all data structures in gdb which may contain references to symbol + table date. */ + +void +clear_symtab_users () +{ + /* Someday, we should do better than this, by only blowing away + the things that really need to be blown. */ + clear_value_history (); + clear_displays (); + clear_internalvars (); + breakpoint_re_set (); + set_default_breakpoint (0, 0, 0, 0); + current_source_symtab = 0; + current_source_line = 0; +} + +/* clear_symtab_users_once: + + This function is run after symbol reading, or from a cleanup. + If an old symbol table was obsoleted, the old symbol table + has been blown away, but the other GDB data structures that may + reference it have not yet been cleared or re-directed. (The old + symtab was zapped, and the cleanup queued, in free_named_symtab() + below.) + + This function can be queued N times as a cleanup, or called + directly; it will do all the work the first time, and then will be a + no-op until the next time it is queued. This works by bumping a + counter at queueing time. Much later when the cleanup is run, or at + the end of symbol processing (in case the cleanup is discarded), if + the queued count is greater than the "done-count", we do the work + and set the done-count to the queued count. If the queued count is + less than or equal to the done-count, we just ignore the call. This + is needed because reading a single .o file will often replace many + symtabs (one per .h file, for example), and we don't want to reset + the breakpoints N times in the user's face. + + The reason we both queue a cleanup, and call it directly after symbol + reading, is because the cleanup protects us in case of errors, but is + discarded if symbol reading is successful. */ + +#if 0 +/* FIXME: As free_named_symtabs is currently a big noop this function + is no longer needed. */ +static void +clear_symtab_users_once PARAMS ((void)); + +static int clear_symtab_users_queued; +static int clear_symtab_users_done; + +static void +clear_symtab_users_once () +{ + /* Enforce once-per-`do_cleanups'-semantics */ + if (clear_symtab_users_queued <= clear_symtab_users_done) + return; + clear_symtab_users_done = clear_symtab_users_queued; + + clear_symtab_users (); +} +#endif + +/* Delete the specified psymtab, and any others that reference it. */ + +static void +cashier_psymtab (pst) + struct partial_symtab *pst; +{ + struct partial_symtab *ps, *pprev = NULL; + int i; + + /* Find its previous psymtab in the chain */ + for (ps = pst->objfile->psymtabs; ps; ps = ps->next) { + if (ps == pst) + break; + pprev = ps; + } + + if (ps) { + /* Unhook it from the chain. */ + if (ps == pst->objfile->psymtabs) + pst->objfile->psymtabs = ps->next; + else + pprev->next = ps->next; + + /* FIXME, we can't conveniently deallocate the entries in the + partial_symbol lists (global_psymbols/static_psymbols) that + this psymtab points to. These just take up space until all + the psymtabs are reclaimed. Ditto the dependencies list and + filename, which are all in the psymbol_obstack. */ + + /* We need to cashier any psymtab that has this one as a dependency... */ +again: + for (ps = pst->objfile->psymtabs; ps; ps = ps->next) { + for (i = 0; i < ps->number_of_dependencies; i++) { + if (ps->dependencies[i] == pst) { + cashier_psymtab (ps); + goto again; /* Must restart, chain has been munged. */ + } + } + } + } +} + +/* If a symtab or psymtab for filename NAME is found, free it along + with any dependent breakpoints, displays, etc. + Used when loading new versions of object modules with the "add-file" + command. This is only called on the top-level symtab or psymtab's name; + it is not called for subsidiary files such as .h files. + + Return value is 1 if we blew away the environment, 0 if not. + FIXME. The return valu appears to never be used. + + FIXME. I think this is not the best way to do this. We should + work on being gentler to the environment while still cleaning up + all stray pointers into the freed symtab. */ + +int +free_named_symtabs (name) + char *name; +{ +#if 0 + /* FIXME: With the new method of each objfile having it's own + psymtab list, this function needs serious rethinking. In particular, + why was it ever necessary to toss psymtabs with specific compilation + unit filenames, as opposed to all psymtabs from a particular symbol + file? -- fnf + Well, the answer is that some systems permit reloading of particular + compilation units. We want to blow away any old info about these + compilation units, regardless of which objfiles they arrived in. --gnu. */ + + register struct symtab *s; + register struct symtab *prev; + register struct partial_symtab *ps; + struct blockvector *bv; + int blewit = 0; + + /* We only wack things if the symbol-reload switch is set. */ + if (!symbol_reloading) + return 0; + + /* Some symbol formats have trouble providing file names... */ + if (name == 0 || *name == '\0') + return 0; + + /* Look for a psymtab with the specified name. */ + +again2: + for (ps = partial_symtab_list; ps; ps = ps->next) { + if (STREQ (name, ps->filename)) { + cashier_psymtab (ps); /* Blow it away...and its little dog, too. */ + goto again2; /* Must restart, chain has been munged */ + } + } + + /* Look for a symtab with the specified name. */ + + for (s = symtab_list; s; s = s->next) + { + if (STREQ (name, s->filename)) + break; + prev = s; + } + + if (s) + { + if (s == symtab_list) + symtab_list = s->next; + else + prev->next = s->next; + + /* For now, queue a delete for all breakpoints, displays, etc., whether + or not they depend on the symtab being freed. This should be + changed so that only those data structures affected are deleted. */ + + /* But don't delete anything if the symtab is empty. + This test is necessary due to a bug in "dbxread.c" that + causes empty symtabs to be created for N_SO symbols that + contain the pathname of the object file. (This problem + has been fixed in GDB 3.9x). */ + + bv = BLOCKVECTOR (s); + if (BLOCKVECTOR_NBLOCKS (bv) > 2 + || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) + || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))) + { + complain (&oldsyms_complaint, name); + + clear_symtab_users_queued++; + make_cleanup (clear_symtab_users_once, 0); + blewit = 1; + } else { + complain (&empty_symtab_complaint, name); + } + + free_symtab (s); + } + else + { + /* It is still possible that some breakpoints will be affected + even though no symtab was found, since the file might have + been compiled without debugging, and hence not be associated + with a symtab. In order to handle this correctly, we would need + to keep a list of text address ranges for undebuggable files. + For now, we do nothing, since this is a fairly obscure case. */ + ; + } + + /* FIXME, what about the minimal symbol table? */ + return blewit; +#else + return (0); +#endif +} + +/* Allocate and partially fill a partial symtab. It will be + completely filled at the end of the symbol list. + + SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR + is the address relative to which its symbols are (incremental) or 0 + (normal). */ + + +struct partial_symtab * +start_psymtab_common (objfile, section_offsets, + filename, textlow, global_syms, static_syms) + struct objfile *objfile; + struct section_offsets *section_offsets; + char *filename; + CORE_ADDR textlow; + struct partial_symbol *global_syms; + struct partial_symbol *static_syms; +{ + struct partial_symtab *psymtab; + + psymtab = allocate_psymtab (filename, objfile); + psymtab -> section_offsets = section_offsets; + psymtab -> textlow = textlow; + psymtab -> texthigh = psymtab -> textlow; /* default */ + psymtab -> globals_offset = global_syms - objfile -> global_psymbols.list; + psymtab -> statics_offset = static_syms - objfile -> static_psymbols.list; + return (psymtab); +} + +/* Debugging versions of functions that are usually inline macros + (see symfile.h). */ + +#if !INLINE_ADD_PSYMBOL + +/* Add a symbol with a long value to a psymtab. + Since one arg is a struct, we pass in a ptr and deref it (sigh). */ + +void +add_psymbol_to_list (name, namelength, namespace, class, list, val, language, + objfile) + char *name; + int namelength; + enum namespace namespace; + enum address_class class; + struct psymbol_allocation_list *list; + long val; + enum language language; + struct objfile *objfile; +{ + register struct partial_symbol *psym; + register char *demangled_name; + + if (list->next >= list->list + list->size) + { + extend_psymbol_list (list,objfile); + } + psym = list->next++; + + SYMBOL_NAME (psym) = + (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1); + memcpy (SYMBOL_NAME (psym), name, namelength); + SYMBOL_NAME (psym)[namelength] = '\0'; + SYMBOL_VALUE (psym) = val; + SYMBOL_LANGUAGE (psym) = language; + PSYMBOL_NAMESPACE (psym) = namespace; + PSYMBOL_CLASS (psym) = class; + SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack); +} + +/* Add a symbol with a CORE_ADDR value to a psymtab. */ + +void +add_psymbol_addr_to_list (name, namelength, namespace, class, list, val, + language, objfile) + char *name; + int namelength; + enum namespace namespace; + enum address_class class; + struct psymbol_allocation_list *list; + CORE_ADDR val; + enum language language; + struct objfile *objfile; +{ + register struct partial_symbol *psym; + register char *demangled_name; + + if (list->next >= list->list + list->size) + { + extend_psymbol_list (list,objfile); + } + psym = list->next++; + + SYMBOL_NAME (psym) = + (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1); + memcpy (SYMBOL_NAME (psym), name, namelength); + SYMBOL_NAME (psym)[namelength] = '\0'; + SYMBOL_VALUE_ADDRESS (psym) = val; + SYMBOL_LANGUAGE (psym) = language; + PSYMBOL_NAMESPACE (psym) = namespace; + PSYMBOL_CLASS (psym) = class; + SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack); +} + +#endif /* !INLINE_ADD_PSYMBOL */ + + +void +_initialize_symfile () +{ + struct cmd_list_element *c; + + c = add_cmd ("symbol-file", class_files, symbol_file_command, + "Load symbol table from executable file FILE.\n\ +The `file' command can also load symbol tables, as well as setting the file\n\ +to execute.", &cmdlist); + c->completer = filename_completer; + + c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command, + "Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\ +The second argument provides the starting address of the file's text.", + &cmdlist); + c->completer = filename_completer; + + c = add_cmd ("load", class_files, load_command, + "Dynamically load FILE into the running program, and record its symbols\n\ +for access from GDB.", &cmdlist); + c->completer = filename_completer; + + add_show_from_set + (add_set_cmd ("symbol-reloading", class_support, var_boolean, + (char *)&symbol_reloading, + "Set dynamic symbol table reloading multiple times in one run.", + &setlist), + &showlist); + +} diff --git a/gnu/usr.bin/gdb/gdb/symfile.h b/gnu/usr.bin/gdb/gdb/symfile.h new file mode 100644 index 00000000000..70bc73db4b0 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/symfile.h @@ -0,0 +1,228 @@ +/* Definitions for reading symbol files into GDB. + Copyright (C) 1990, 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. */ + +#if !defined (SYMFILE_H) +#define SYMFILE_H + +/* This file requires that you first include "bfd.h". */ + +struct psymbol_allocation_list { + struct partial_symbol *list; + struct partial_symbol *next; + int size; +}; + +/* Structure to keep track of symbol reading functions for various + object file types. */ + +struct sym_fns { + + /* is the name, or name prefix, of the BFD "target type" that this + set of functions handles. E.g. "a.out" or "sunOs" or "coff" or "elf". */ + + char *sym_name; + + /* counts how many bytes of sym_name should be checked against the + BFD target type of the file being read. If an exact match is + desired, specify the number of characters in sym_name plus 1 for + the '\0'. If a prefix match is desired, specify the number of + characters in sym_name. */ + + int sym_namelen; + + /* Initializes anything that is global to the entire symbol table. It is + called during symbol_file_add, when we begin debugging an entirely new + program. */ + + void (*sym_new_init) PARAMS ((struct objfile *)); + + /* Reads any initial information from a symbol file, and initializes the + struct sym_fns SF in preparation for sym_read(). It is called every + time we read a symbol file for any reason. */ + + void (*sym_init) PARAMS ((struct objfile *)); + + /* sym_read (objfile, addr, mainline) + Reads a symbol file into a psymtab (or possibly a symtab). + OBJFILE is the objfile struct for the file we are reading. + SECTION_OFFSETS + are the offset between the file's specified section addresses and + their true addresses in memory. + MAINLINE is 1 if this is the + main symbol table being read, and 0 if a secondary + symbol file (e.g. shared library or dynamically loaded file) + is being read. */ + + void (*sym_read) PARAMS ((struct objfile *, struct section_offsets *, int)); + + /* Called when we are finished with an objfile. Should do all cleanup + that is specific to the object file format for the particular objfile. */ + + void (*sym_finish) PARAMS ((struct objfile *)); + + /* This function produces a file-dependent section_offsets structure, + allocated in the objfile's storage, and based on the parameter. + The parameter is currently a CORE_ADDR (FIXME!) for backward compatibility + with the higher levels of GDB. It should probably be changed to + a string, where NULL means the default, and others are parsed in a file + dependent way. The result of this function is handed in to sym_read. */ + + struct section_offsets *(*sym_offsets) PARAMS ((struct objfile *, CORE_ADDR)); + + /* Finds the next struct sym_fns. They are allocated and initialized + in whatever module implements the functions pointed to; an + initializer calls add_symtab_fns to add them to the global chain. */ + + struct sym_fns *next; + +}; + +extern void +extend_psymbol_list PARAMS ((struct psymbol_allocation_list *, + struct objfile *)); + +/* Add any kind of symbol to a psymbol_allocation_list. */ + +#ifndef INLINE_ADD_PSYMBOL +#define INLINE_ADD_PSYMBOL 1 +#endif + +#if !INLINE_ADD_PSYMBOL + +/* Since one arg is a struct, we have to pass in a ptr and deref it (sigh) */ + +#define ADD_PSYMBOL_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \ + add_psymbol_to_list (name, namelength, namespace, class, &list, value, language, objfile) + +#define ADD_PSYMBOL_ADDR_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \ + add_psymbol_addr_to_list (name, namelength, namespace, class, &list, value, language, objfile) + +#else /* !INLINE_ADD_PSYMBOL */ + +#include "demangle.h" + +#define ADD_PSYMBOL_VT_TO_LIST(NAME,NAMELENGTH,NAMESPACE,CLASS,LIST,VALUE,VT,LANGUAGE, OBJFILE) \ + do { \ + register struct partial_symbol *psym; \ + if ((LIST).next >= (LIST).list + (LIST).size) \ + extend_psymbol_list (&(LIST),(OBJFILE)); \ + psym = (LIST).next++; \ + SYMBOL_NAME (psym) = \ + (char *) obstack_alloc (&objfile->psymbol_obstack, \ + (NAMELENGTH) + 1); \ + memcpy (SYMBOL_NAME (psym), (NAME), (NAMELENGTH)); \ + SYMBOL_NAME (psym)[(NAMELENGTH)] = '\0'; \ + SYMBOL_NAMESPACE (psym) = (NAMESPACE); \ + PSYMBOL_CLASS (psym) = (CLASS); \ + VT (psym) = (VALUE); \ + SYMBOL_LANGUAGE (psym) = (LANGUAGE); \ + SYMBOL_INIT_DEMANGLED_NAME (psym, &objfile->psymbol_obstack); \ + } while (0); + +/* Add a symbol with an integer value to a psymtab. */ + +#define ADD_PSYMBOL_TO_LIST(name, namelength, namespace, class, list, value, language, objfile) \ + ADD_PSYMBOL_VT_TO_LIST (name, namelength, namespace, class, list, value, SYMBOL_VALUE, language, objfile) + +/* Add a symbol with a CORE_ADDR value to a psymtab. */ + +#define ADD_PSYMBOL_ADDR_TO_LIST(name, namelength, namespace, class, list, value, language, objfile)\ + ADD_PSYMBOL_VT_TO_LIST (name, namelength, namespace, class, list, value, SYMBOL_VALUE_ADDRESS, language, objfile) + +#endif /* INLINE_ADD_PSYMBOL */ + + /* Functions */ + +extern void +sort_pst_symbols PARAMS ((struct partial_symtab *)); + +extern struct symtab * +allocate_symtab PARAMS ((char *, struct objfile *)); + +extern int +free_named_symtabs PARAMS ((char *)); + +extern void +fill_in_vptr_fieldno PARAMS ((struct type *)); + +extern void +add_symtab_fns PARAMS ((struct sym_fns *)); + +extern void +init_entry_point_info PARAMS ((struct objfile *)); + +extern void +syms_from_objfile PARAMS ((struct objfile *, CORE_ADDR, int, int)); + +extern void +new_symfile_objfile PARAMS ((struct objfile *, int, int)); + +extern struct partial_symtab * +start_psymtab_common PARAMS ((struct objfile *, struct section_offsets *, + char *, CORE_ADDR, + struct partial_symbol *, + struct partial_symbol *)); + +/* Sorting your symbols for fast lookup or alphabetical printing. */ + +extern void +sort_block_syms PARAMS ((struct block *)); + +extern void +sort_symtab_syms PARAMS ((struct symtab *)); + +extern void +sort_all_symtab_syms PARAMS ((void)); + +/* Make a copy of the string at PTR with SIZE characters in the symbol obstack + (and add a null character at the end in the copy). + Returns the address of the copy. */ + +extern char * +obsavestring PARAMS ((char *, int, struct obstack *)); + +/* Concatenate strings S1, S2 and S3; return the new string. + Space is found in the symbol_obstack. */ + +extern char * +obconcat PARAMS ((struct obstack *obstackp, const char *, const char *, + const char *)); + + /* Variables */ + +/* From symfile.c */ + +extern struct partial_symtab * +allocate_psymtab PARAMS ((char *, struct objfile *)); + +/* Remote targets may wish to use this as their load function. */ +extern void generic_load PARAMS ((char *name, int from_tty)); + +/* From dwarfread.c */ + +extern void +dwarf_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *, int, + file_ptr, unsigned int, file_ptr, unsigned int)); + +/* From demangle.c */ + +extern void +set_demangling_style PARAMS ((char *)); + +#endif /* !defined(SYMFILE_H) */ diff --git a/gnu/usr.bin/gdb/gdb/symmisc.c b/gnu/usr.bin/gdb/gdb/symmisc.c new file mode 100644 index 00000000000..411a53bef96 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/symmisc.c @@ -0,0 +1,857 @@ +/* Do various things to symbol tables (other than lookup), for GDB. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "breakpoint.h" +#include "command.h" +#include "obstack.h" +#include "language.h" + +#include + +#ifndef DEV_TTY +#define DEV_TTY "/dev/tty" +#endif + +/* Unfortunately for debugging, stderr is usually a macro. This is painful + when calling functions that take FILE *'s from the debugger. + So we make a variable which has the same value and which is accessible when + debugging GDB with itself. Because stdin et al need not be constants, + we initialize them in the _initialize_symmisc function at the bottom + of the file. */ +FILE *std_in; +FILE *std_out; +FILE *std_err; + +/* Prototypes for local functions */ + +static void +dump_symtab PARAMS ((struct objfile *, struct symtab *, FILE *)); + +static void +dump_psymtab PARAMS ((struct objfile *, struct partial_symtab *, FILE *)); + +static void +dump_msymbols PARAMS ((struct objfile *, FILE *)); + +static void +dump_objfile PARAMS ((struct objfile *)); + +static int +block_depth PARAMS ((struct block *)); + +static void +print_partial_symbol PARAMS ((struct partial_symbol *, int, char *, FILE *)); + +struct print_symbol_args { + struct symbol *symbol; + int depth; + FILE *outfile; +}; + +static int print_symbol PARAMS ((char *)); + +static void +free_symtab_block PARAMS ((struct objfile *, struct block *)); + + +/* Free a struct block <- B and all the symbols defined in that block. */ + +static void +free_symtab_block (objfile, b) + struct objfile *objfile; + struct block *b; +{ + register int i, n; + n = BLOCK_NSYMS (b); + for (i = 0; i < n; i++) + { + mfree (objfile -> md, SYMBOL_NAME (BLOCK_SYM (b, i))); + mfree (objfile -> md, (PTR) BLOCK_SYM (b, i)); + } + mfree (objfile -> md, (PTR) b); +} + +/* Free all the storage associated with the struct symtab <- S. + Note that some symtabs have contents malloc'ed structure by structure, + while some have contents that all live inside one big block of memory, + and some share the contents of another symbol table and so you should + not free the contents on their behalf (except sometimes the linetable, + which maybe per symtab even when the rest is not). + It is s->free_code that says which alternative to use. */ + +void +free_symtab (s) + register struct symtab *s; +{ + register int i, n; + register struct blockvector *bv; + + switch (s->free_code) + { + case free_nothing: + /* All the contents are part of a big block of memory (an obstack), + and some other symtab is in charge of freeing that block. + Therefore, do nothing. */ + break; + + case free_contents: + /* Here all the contents were malloc'ed structure by structure + and must be freed that way. */ + /* First free the blocks (and their symbols. */ + bv = BLOCKVECTOR (s); + n = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < n; i++) + free_symtab_block (s -> objfile, BLOCKVECTOR_BLOCK (bv, i)); + /* Free the blockvector itself. */ + mfree (s -> objfile -> md, (PTR) bv); + /* Also free the linetable. */ + + case free_linetable: + /* Everything will be freed either by our `free_ptr' + or by some other symtab, except for our linetable. + Free that now. */ + if (LINETABLE (s)) + mfree (s -> objfile -> md, (PTR) LINETABLE (s)); + break; + } + + /* If there is a single block of memory to free, free it. */ + if (s -> free_ptr != NULL) + mfree (s -> objfile -> md, s -> free_ptr); + + /* Free source-related stuff */ + if (s -> line_charpos != NULL) + mfree (s -> objfile -> md, (PTR) s -> line_charpos); + if (s -> fullname != NULL) + mfree (s -> objfile -> md, s -> fullname); + mfree (s -> objfile -> md, (PTR) s); +} + +#if MAINTENANCE_CMDS + +static void +dump_objfile (objfile) + struct objfile *objfile; +{ + struct symtab *symtab; + struct partial_symtab *psymtab; + + printf_filtered ("\nObject file %s: ", objfile -> name); + printf_filtered ("Objfile at %lx, bfd at %lx, %d minsyms\n\n", + (unsigned long) objfile, + (unsigned long) objfile -> obfd, + objfile->minimal_symbol_count); + + if (objfile -> psymtabs) + { + printf_filtered ("Psymtabs:\n"); + for (psymtab = objfile -> psymtabs; + psymtab != NULL; + psymtab = psymtab -> next) + { + printf_filtered ("%s at %lx, ", + psymtab -> filename, (unsigned long) psymtab); + if (psymtab -> objfile != objfile) + { + printf_filtered ("NOT ON CHAIN! "); + } + wrap_here (" "); + } + printf_filtered ("\n\n"); + } + + if (objfile -> symtabs) + { + printf_filtered ("Symtabs:\n"); + for (symtab = objfile -> symtabs; + symtab != NULL; + symtab = symtab->next) + { + printf_filtered ("%s at %lx, ", + symtab -> filename, (unsigned long) symtab); + if (symtab -> objfile != objfile) + { + printf_filtered ("NOT ON CHAIN! "); + } + wrap_here (" "); + } + printf_filtered ("\n\n"); + } +} + +/* Print minimal symbols from this objfile. */ + +static void +dump_msymbols (objfile, outfile) + struct objfile *objfile; + FILE *outfile; +{ + struct minimal_symbol *msymbol; + int index; + char ms_type; + + fprintf_filtered (outfile, "\nObject file %s:\n\n", objfile -> name); + if (objfile -> minimal_symbol_count == 0) + { + fprintf_filtered (outfile, "No minimal symbols found.\n"); + return; + } + for (index = 0, msymbol = objfile -> msymbols; + SYMBOL_NAME (msymbol) != NULL; msymbol++, index++) + { + switch (msymbol -> type) + { + case mst_unknown: + ms_type = 'u'; + break; + case mst_text: + ms_type = 'T'; + break; + case mst_data: + ms_type = 'D'; + break; + case mst_bss: + ms_type = 'B'; + break; + case mst_abs: + ms_type = 'A'; + break; + case mst_file_text: + ms_type = 't'; + break; + case mst_file_data: + ms_type = 'd'; + break; + case mst_file_bss: + ms_type = 'b'; + break; + default: + ms_type = '?'; + break; + } + fprintf_filtered (outfile, "[%2d] %c %#10lx %s", index, ms_type, + SYMBOL_VALUE_ADDRESS (msymbol), SYMBOL_NAME (msymbol)); + if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL) + { + fprintf_filtered (outfile, " %s", SYMBOL_DEMANGLED_NAME (msymbol)); + } + fputs_filtered ("\n", outfile); + } + if (objfile -> minimal_symbol_count != index) + { + warning ("internal error: minimal symbol count %d != %d", + objfile -> minimal_symbol_count, index); + } + fprintf_filtered (outfile, "\n"); +} + +static void +dump_psymtab (objfile, psymtab, outfile) + struct objfile *objfile; + struct partial_symtab *psymtab; + FILE *outfile; +{ + int i; + + fprintf_filtered (outfile, "\nPartial symtab for source file %s ", + psymtab -> filename); + fprintf_filtered (outfile, "(object 0x%lx)\n\n", (unsigned long) psymtab); + fprintf (outfile, " Read from object file %s (0x%lx)\n", + objfile -> name, (unsigned long) objfile); + + if (psymtab -> readin) + { + fprintf_filtered (outfile, + " Full symtab was read (at 0x%lx by function at 0x%lx)\n", + (unsigned long) psymtab -> symtab, + (unsigned long) psymtab -> read_symtab); + } + + /* FIXME, we need to be able to print the relocation stuff. */ + /* This prints some garbage for anything but stabs right now. FIXME. */ + if (psymtab->section_offsets) + fprintf_filtered (outfile, + " Relocate symbols by 0x%lx, 0x%lx, 0x%lx, 0x%lx.\n", + (unsigned long) ANOFFSET (psymtab->section_offsets, 0), + (unsigned long) ANOFFSET (psymtab->section_offsets, 1), + (unsigned long) ANOFFSET (psymtab->section_offsets, 2), + (unsigned long) ANOFFSET (psymtab->section_offsets, 3)); + + fprintf_filtered (outfile, " Symbols cover text addresses 0x%lx-0x%lx\n", + (unsigned long) psymtab -> textlow, + (unsigned long) psymtab -> texthigh); + fprintf_filtered (outfile, " Depends on %d other partial symtabs.\n", + psymtab -> number_of_dependencies); + for (i = 0; i < psymtab -> number_of_dependencies; i++) + { + fprintf_filtered (outfile, " %d 0x%lx %s\n", i, + (unsigned long) psymtab -> dependencies[i], + psymtab -> dependencies[i] -> filename); + } + if (psymtab -> n_global_syms > 0) + { + print_partial_symbol (objfile -> global_psymbols.list + + psymtab -> globals_offset, + psymtab -> n_global_syms, "Global", outfile); + } + if (psymtab -> n_static_syms > 0) + { + print_partial_symbol (objfile -> static_psymbols.list + + psymtab -> statics_offset, + psymtab -> n_static_syms, "Static", outfile); + } + fprintf_filtered (outfile, "\n"); +} + +static void +dump_symtab (objfile, symtab, outfile) + struct objfile *objfile; + struct symtab *symtab; + FILE *outfile; +{ + register int i, j; + int len, blen; + register struct linetable *l; + struct blockvector *bv; + register struct block *b; + int depth; + + fprintf (outfile, "\nSymtab for file %s\n", symtab->filename); + fprintf (outfile, "Read from object file %s (%lx)\n", objfile->name, + (unsigned long) objfile); + fprintf (outfile, "Language: %s\n", language_str (symtab -> language)); + + /* First print the line table. */ + l = LINETABLE (symtab); + if (l) { + fprintf (outfile, "\nLine table:\n\n"); + len = l->nitems; + for (i = 0; i < len; i++) + fprintf (outfile, " line %ld at %lx\n", l->item[i].line, + (unsigned long) l->item[i].pc); + } + /* Now print the block info. */ + fprintf (outfile, "\nBlockvector:\n\n"); + bv = BLOCKVECTOR (symtab); + len = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < len; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + depth = block_depth (b) * 2; + print_spaces (depth, outfile); + fprintf (outfile, "block #%03d (object 0x%lx) ", i, (unsigned long) b); + fprintf (outfile, "[0x%lx..0x%lx]", + (unsigned long) BLOCK_START (b), + (unsigned long) BLOCK_END (b)); + if (BLOCK_SUPERBLOCK (b)) + fprintf (outfile, " (under 0x%lx)", + (unsigned long) BLOCK_SUPERBLOCK (b)); + if (BLOCK_FUNCTION (b)) + { + fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b))); + if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL) + { + fprintf (outfile, " %s", + SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b))); + } + } + if (BLOCK_GCC_COMPILED(b)) + fprintf (outfile, " gcc%d compiled", BLOCK_GCC_COMPILED(b)); + fputc ('\n', outfile); + blen = BLOCK_NSYMS (b); + for (j = 0; j < blen; j++) + { + struct print_symbol_args s; + s.symbol = BLOCK_SYM (b, j); + s.depth = depth + 1; + s.outfile = outfile; + catch_errors (print_symbol, &s, "Error printing symbol:\n", + RETURN_MASK_ERROR); + } + } + fprintf (outfile, "\n"); +} + +void +maintenance_print_symbols (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + FILE *outfile; + struct cleanup *cleanups; + char *symname = NULL; + char *filename = DEV_TTY; + struct objfile *objfile; + struct symtab *s; + + dont_repeat (); + + if (args == NULL) + { + error ("print-symbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, (char *) argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + outfile = fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup (fclose, (char *) outfile); + + immediate_quit++; + ALL_SYMTABS (objfile, s) + if (symname == NULL || (STREQ (symname, s -> filename))) + dump_symtab (objfile, s, outfile); + immediate_quit--; + do_cleanups (cleanups); +} + +/* Print symbol ARGS->SYMBOL on ARGS->OUTFILE. ARGS->DEPTH says how + far to indent. ARGS is really a struct print_symbol_args *, but is + declared as char * to get it past catch_errors. Returns 0 for error, + 1 for success. */ + +static int +print_symbol (args) + char *args; +{ + struct symbol *symbol = ((struct print_symbol_args *)args)->symbol; + int depth = ((struct print_symbol_args *)args)->depth; + FILE *outfile = ((struct print_symbol_args *)args)->outfile; + + print_spaces (depth, outfile); + if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE) + { + fprintf (outfile, "label %s at 0x%lx\n", SYMBOL_SOURCE_NAME (symbol), + (unsigned long) SYMBOL_VALUE_ADDRESS (symbol)); + return 1; + } + if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE) + { + if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol))) + { + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + else + { + fprintf (outfile, "%s %s = ", + (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM + ? "enum" + : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT + ? "struct" : "union")), + SYMBOL_NAME (symbol)); + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + fprintf (outfile, ";\n"); + } + else + { + if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF) + fprintf (outfile, "typedef "); + if (SYMBOL_TYPE (symbol)) + { + /* Print details of types, except for enums where it's clutter. */ + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_SOURCE_NAME (symbol), + outfile, + TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM, + depth); + fprintf (outfile, "; "); + } + else + fprintf (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol)); + + switch (SYMBOL_CLASS (symbol)) + { + case LOC_CONST: + fprintf (outfile, "const %ld (0x%lx),", + SYMBOL_VALUE (symbol), + (unsigned long) SYMBOL_VALUE (symbol)); + break; + + case LOC_CONST_BYTES: + fprintf (outfile, "const %u hex bytes:", + TYPE_LENGTH (SYMBOL_TYPE (symbol))); + { + unsigned i; + for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++) + fprintf (outfile, " %02x", + (unsigned)SYMBOL_VALUE_BYTES (symbol) [i]); + fprintf (outfile, ","); + } + break; + + case LOC_STATIC: + fprintf (outfile, "static at 0x%lx,", + (unsigned long) SYMBOL_VALUE_ADDRESS (symbol)); + break; + + case LOC_REGISTER: + fprintf (outfile, "register %ld,", SYMBOL_VALUE (symbol)); + break; + + case LOC_ARG: + fprintf (outfile, "arg at 0x%lx,", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL_ARG: + fprintf (outfile, "arg at offset 0x%lx from fp,", + SYMBOL_VALUE (symbol)); + break; + + case LOC_REF_ARG: + fprintf (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM: + fprintf (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM_ADDR: + fprintf (outfile, "address parameter register %ld,", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL: + fprintf (outfile, "local at 0x%lx,", SYMBOL_VALUE (symbol)); + break; + + case LOC_BASEREG: + fprintf (outfile, "local at 0x%lx from register %d", + SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol)); + break; + + case LOC_BASEREG_ARG: + fprintf (outfile, "arg at 0x%lx from register %d,", + SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol)); + break; + + case LOC_TYPEDEF: + break; + + case LOC_LABEL: + fprintf (outfile, "label at 0x%lx", + (unsigned long) SYMBOL_VALUE_ADDRESS (symbol)); + break; + + case LOC_BLOCK: + fprintf (outfile, "block (object 0x%lx) starting at 0x%lx,", + (unsigned long) SYMBOL_BLOCK_VALUE (symbol), + (unsigned long) BLOCK_START (SYMBOL_BLOCK_VALUE (symbol))); + break; + + case LOC_OPTIMIZED_OUT: + fprintf (outfile, "optimized out"); + break; + + default: + fprintf (outfile, "botched symbol class %x", SYMBOL_CLASS (symbol)); + break; + } + } + fprintf (outfile, "\n"); + return 1; +} + +void +maintenance_print_psymbols (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + FILE *outfile; + struct cleanup *cleanups; + char *symname = NULL; + char *filename = DEV_TTY; + struct objfile *objfile; + struct partial_symtab *ps; + + dont_repeat (); + + if (args == NULL) + { + error ("print-psymbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, (char *) argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + outfile = fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup (fclose, outfile); + + immediate_quit++; + ALL_PSYMTABS (objfile, ps) + if (symname == NULL || (STREQ (symname, ps -> filename))) + dump_psymtab (objfile, ps, outfile); + immediate_quit--; + do_cleanups (cleanups); +} + +static void +print_partial_symbol (p, count, what, outfile) + struct partial_symbol *p; + int count; + char *what; + FILE *outfile; +{ + + fprintf_filtered (outfile, " %s partial symbols:\n", what); + while (count-- > 0) + { + fprintf_filtered (outfile, " `%s'", SYMBOL_NAME(p)); + if (SYMBOL_DEMANGLED_NAME (p) != NULL) + { + fprintf_filtered (outfile, " `%s'", SYMBOL_DEMANGLED_NAME (p)); + } + fputs_filtered (", ", outfile); + switch (SYMBOL_NAMESPACE (p)) + { + case UNDEF_NAMESPACE: + fputs_filtered ("undefined namespace, ", outfile); + break; + case VAR_NAMESPACE: + /* This is the usual thing -- don't print it */ + break; + case STRUCT_NAMESPACE: + fputs_filtered ("struct namespace, ", outfile); + break; + case LABEL_NAMESPACE: + fputs_filtered ("label namespace, ", outfile); + break; + default: + fputs_filtered (", ", outfile); + break; + } + switch (SYMBOL_CLASS (p)) + { + case LOC_UNDEF: + fputs_filtered ("undefined", outfile); + break; + case LOC_CONST: + fputs_filtered ("constant int", outfile); + break; + case LOC_STATIC: + fputs_filtered ("static", outfile); + break; + case LOC_REGISTER: + fputs_filtered ("register", outfile); + break; + case LOC_ARG: + fputs_filtered ("pass by value", outfile); + break; + case LOC_REF_ARG: + fputs_filtered ("pass by reference", outfile); + break; + case LOC_REGPARM: + fputs_filtered ("register parameter", outfile); + break; + case LOC_REGPARM_ADDR: + fputs_filtered ("register address parameter", outfile); + break; + case LOC_LOCAL: + fputs_filtered ("stack parameter", outfile); + break; + case LOC_TYPEDEF: + fputs_filtered ("type", outfile); + break; + case LOC_LABEL: + fputs_filtered ("label", outfile); + break; + case LOC_BLOCK: + fputs_filtered ("function", outfile); + break; + case LOC_CONST_BYTES: + fputs_filtered ("constant bytes", outfile); + break; + case LOC_LOCAL_ARG: + fputs_filtered ("shuffled arg", outfile); + break; + case LOC_OPTIMIZED_OUT: + fputs_filtered ("optimized out", outfile); + break; + default: + fputs_filtered ("", outfile); + break; + } + fputs_filtered (", ", outfile); + fprintf_filtered (outfile, "0x%lx\n", SYMBOL_VALUE (p)); + p++; + } +} + +void +maintenance_print_msymbols (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + FILE *outfile; + struct cleanup *cleanups; + char *filename = DEV_TTY; + char *symname = NULL; + struct objfile *objfile; + + dont_repeat (); + + if (args == NULL) + { + error ("print-msymbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + outfile = fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup (fclose, outfile); + + immediate_quit++; + ALL_OBJFILES (objfile) + if (symname == NULL || (STREQ (symname, objfile -> name))) + dump_msymbols (objfile, outfile); + immediate_quit--; + fprintf_filtered (outfile, "\n\n"); + do_cleanups (cleanups); +} + +void +maintenance_print_objfiles (ignore, from_tty) + char *ignore; + int from_tty; +{ + struct objfile *objfile; + + dont_repeat (); + + immediate_quit++; + ALL_OBJFILES (objfile) + dump_objfile (objfile); + immediate_quit--; +} + + +/* Return the nexting depth of a block within other blocks in its symtab. */ + +static int +block_depth (block) + struct block *block; +{ + register int i = 0; + while ((block = BLOCK_SUPERBLOCK (block)) != NULL) + { + i++; + } + return i; +} + +#endif /* MAINTENANCE_CMDS */ + + +/* Increase the space allocated for LISTP, which is probably + global_psymbol_list or static_psymbol_list. This space will eventually + be freed in free_objfile(). */ + +void +extend_psymbol_list (listp, objfile) + register struct psymbol_allocation_list *listp; + struct objfile *objfile; +{ + int new_size; + if (listp->size == 0) + { + new_size = 255; + listp->list = (struct partial_symbol *) + xmmalloc (objfile -> md, new_size * sizeof (struct partial_symbol)); + } + else + { + new_size = listp->size * 2; + listp->list = (struct partial_symbol *) + xmrealloc (objfile -> md, (char *) listp->list, + new_size * sizeof (struct partial_symbol)); + } + /* Next assumes we only went one over. Should be good if + program works correctly */ + listp->next = listp->list + listp->size; + listp->size = new_size; +} + + +/* Do early runtime initializations. */ +void +_initialize_symmisc () +{ + std_in = stdin; + std_out = stdout; + std_err = stderr; +} diff --git a/gnu/usr.bin/gdb/gdb/symtab.c b/gnu/usr.bin/gdb/gdb/symtab.c new file mode 100644 index 00000000000..0d0255c7317 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/symtab.c @@ -0,0 +1,3035 @@ +/* Symbol table lookup for the GNU debugger, GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "frame.h" +#include "target.h" +#include "value.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcmd.h" +#include "call-cmds.h" +#include "regex.h" +#include "expression.h" +#include "language.h" +#include "demangle.h" + +#include +#include + +#include +#include +#include +#include +#include + +/* Prototypes for local functions */ + +extern int +find_methods PARAMS ((struct type *, char *, struct symbol **)); + +static void +completion_list_add_name PARAMS ((char *, char *, int, char *, char *)); + +static void +build_canonical_line_spec PARAMS ((struct symtab_and_line *, char *, char ***)); + +static struct symtabs_and_lines +decode_line_2 PARAMS ((struct symbol *[], int, int, char ***)); + +static void +rbreak_command PARAMS ((char *, int)); + +static void +types_info PARAMS ((char *, int)); + +static void +functions_info PARAMS ((char *, int)); + +static void +variables_info PARAMS ((char *, int)); + +static void +sources_info PARAMS ((char *, int)); + +static void +list_symbols PARAMS ((char *, int, int)); + +static void +output_source_filename PARAMS ((char *, int *)); + +static char * +operator_chars PARAMS ((char *, char **)); + +static int find_line_common PARAMS ((struct linetable *, int, int *)); + +static struct partial_symbol * +lookup_partial_symbol PARAMS ((struct partial_symtab *, const char *, + int, enum namespace)); + +static struct symtab * +lookup_symtab_1 PARAMS ((char *)); + +/* */ + +/* The single non-language-specific builtin type */ +struct type *builtin_type_error; + +/* Block in which the most recently searched-for symbol was found. + Might be better to make this a parameter to lookup_symbol and + value_of_this. */ + +const struct block *block_found; + +char no_symtab_msg[] = "No symbol table is loaded. Use the \"file\" command."; + +/* While the C++ support is still in flux, issue a possibly helpful hint on + using the new command completion feature on single quoted demangled C++ + symbols. Remove when loose ends are cleaned up. FIXME -fnf */ + +void +cplusplus_hint (name) + char *name; +{ + printf ("Hint: try '%s or '%s\n", name, name); + printf ("(Note leading single quote.)\n"); +} + +/* Check for a symtab of a specific name; first in symtabs, then in + psymtabs. *If* there is no '/' in the name, a match after a '/' + in the symtab filename will also work. */ + +static struct symtab * +lookup_symtab_1 (name) + char *name; +{ + register struct symtab *s; + register struct partial_symtab *ps; + register char *slash; + register struct objfile *objfile; + + got_symtab: + + /* First, search for an exact match */ + + ALL_SYMTABS (objfile, s) + if (STREQ (name, s->filename)) + return s; + + slash = strchr (name, '/'); + + /* Now, search for a matching tail (only if name doesn't have any dirs) */ + + if (!slash) + ALL_SYMTABS (objfile, s) + { + char *p = s -> filename; + char *tail = strrchr (p, '/'); + + if (tail) + p = tail + 1; + + if (STREQ (p, name)) + return s; + } + + /* Same search rules as above apply here, but now we look thru the + psymtabs. */ + + ps = lookup_partial_symtab (name); + if (!ps) + return (NULL); + + if (ps -> readin) + error ("Internal: readin %s pst for `%s' found when no symtab found.", + ps -> filename, name); + + s = PSYMTAB_TO_SYMTAB (ps); + + if (s) + return s; + + /* At this point, we have located the psymtab for this file, but + the conversion to a symtab has failed. This usually happens + when we are looking up an include file. In this case, + PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has + been created. So, we need to run through the symtabs again in + order to find the file. + XXX - This is a crock, and should be fixed inside of the the + symbol parsing routines. */ + goto got_symtab; +} + +/* Lookup the symbol table of a source file named NAME. Try a couple + of variations if the first lookup doesn't work. */ + +struct symtab * +lookup_symtab (name) + char *name; +{ + register struct symtab *s; + register char *copy; + + s = lookup_symtab_1 (name); + if (s) return s; + + /* If name not found as specified, see if adding ".c" helps. */ + /* Why is this? Is it just a user convenience? (If so, it's pretty + questionable in the presence of C++, FORTRAN, etc.). It's not in + the GDB manual. */ + + copy = (char *) alloca (strlen (name) + 3); + strcpy (copy, name); + strcat (copy, ".c"); + s = lookup_symtab_1 (copy); + if (s) return s; + + /* We didn't find anything; die. */ + return 0; +} + +/* Lookup the partial symbol table of a source file named NAME. + *If* there is no '/' in the name, a match after a '/' + in the psymtab filename will also work. */ + +struct partial_symtab * +lookup_partial_symtab (name) +char *name; +{ + register struct partial_symtab *pst; + register struct objfile *objfile; + + ALL_PSYMTABS (objfile, pst) + { + if (STREQ (name, pst -> filename)) + { + return (pst); + } + } + + /* Now, search for a matching tail (only if name doesn't have any dirs) */ + + if (!strchr (name, '/')) + ALL_PSYMTABS (objfile, pst) + { + char *p = pst -> filename; + char *tail = strrchr (p, '/'); + + if (tail) + p = tail + 1; + + if (STREQ (p, name)) + return (pst); + } + + return (NULL); +} + +/* Demangle a GDB method stub type. + Note that this function is g++ specific. */ + +char * +gdb_mangle_name (type, i, j) + struct type *type; + int i, j; +{ + int mangled_name_len; + char *mangled_name; + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + struct fn_field *method = &f[j]; + char *field_name = TYPE_FN_FIELDLIST_NAME (type, i); + char *physname = TYPE_FN_FIELD_PHYSNAME (f, j); + char *newname = type_name_no_tag (type); + int is_constructor; + int is_destructor = DESTRUCTOR_PREFIX_P (physname); + /* Need a new type prefix. */ + char *const_prefix = method->is_const ? "C" : ""; + char *volatile_prefix = method->is_volatile ? "V" : ""; + char buf[20]; + int len = (newname == NULL ? 0 : strlen (newname)); + char *opname; + + is_constructor = newname && STREQ(field_name, newname); + if (!is_constructor) + is_constructor = (physname[0]=='_' && physname[1]=='_' && + (isdigit(physname[2]) || physname[2]=='Q' || physname[2]=='t')); + if (!is_constructor) + is_constructor = (strncmp(physname, "__ct", 4) == 0); + if (!is_destructor) + is_destructor = (strncmp(physname, "__dt", 4) == 0); + +#ifndef GCC_MANGLE_BUG + if (is_destructor) + { + mangled_name = (char*) xmalloc(strlen(physname)+1); + strcpy(mangled_name, physname); + return mangled_name; + } + + if (len == 0) + { + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + if (strcmp(buf, "__") == 0) + buf[0] = '\0'; + } + else + { + sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + } + mangled_name_len = ((is_constructor ? 0 : strlen (field_name)) + + strlen (buf) + len + + strlen (physname) + + 1); + + /* Only needed for GNU-mangled names. ANSI-mangled names + work with the normal mechanisms. */ + if (OPNAME_PREFIX_P (field_name)) + { + char *opname = cplus_mangle_opname (field_name + 3, 0); + if (opname == NULL) + error ("No mangling for \"%s\"", field_name); + mangled_name_len += strlen (opname); + mangled_name = (char *)xmalloc (mangled_name_len); + + strncpy (mangled_name, field_name, 3); + mangled_name[3] = '\0'; + strcat (mangled_name, opname); + } + else + { + mangled_name = (char *)xmalloc (mangled_name_len); + if (is_constructor) + mangled_name[0] = '\0'; + else + strcpy (mangled_name, field_name); + } + strcat (mangled_name, buf); + /* If the class doesn't have a name, i.e. newname NULL, then we just + mangle it using 0 for the length of the class. Thus it gets mangled + as something starting with `::' rather than `classname::'. */ + if (newname != NULL) + strcat (mangled_name, newname); + +#else + + if (is_constructor) + { + buf[0] = '\0'; + } + else + { + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + } + + mangled_name_len = ((is_constructor ? 0 : strlen (field_name)) + + strlen (buf) + strlen (physname) + 1); + + /* Only needed for GNU-mangled names. ANSI-mangled names + work with the normal mechanisms. */ + if (OPNAME_PREFIX_P (field_name)) + { + opname = cplus_mangle_opname (field_name + 3, 0); + if (opname == NULL) + { + error ("No mangling for \"%s\"", field_name); + } + mangled_name_len += strlen (opname); + mangled_name = (char *) xmalloc (mangled_name_len); + + strncpy (mangled_name, field_name, 3); + strcpy (mangled_name + 3, opname); + } + else + { + mangled_name = (char *) xmalloc (mangled_name_len); + if (is_constructor) + { + mangled_name[0] = '\0'; + } + else + { + strcpy (mangled_name, field_name); + } + } + strcat (mangled_name, buf); + +#endif + strcat (mangled_name, physname); + return (mangled_name); +} + + +/* Find which partial symtab on contains PC. Return 0 if none. */ + +struct partial_symtab * +find_pc_psymtab (pc) + register CORE_ADDR pc; +{ + register struct partial_symtab *pst; + register struct objfile *objfile; + + ALL_PSYMTABS (objfile, pst) + { + if (pc >= pst->textlow && pc < pst->texthigh) + return (pst); + } + return (NULL); +} + +/* Find which partial symbol within a psymtab contains PC. Return 0 + if none. Check all psymtabs if PSYMTAB is 0. */ +struct partial_symbol * +find_pc_psymbol (psymtab, pc) + struct partial_symtab *psymtab; + CORE_ADDR pc; +{ + struct partial_symbol *best = NULL, *p; + CORE_ADDR best_pc; + + if (!psymtab) + psymtab = find_pc_psymtab (pc); + if (!psymtab) + return 0; + + best_pc = psymtab->textlow - 1; + + for (p = psymtab->objfile->static_psymbols.list + psymtab->statics_offset; + (p - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset) + < psymtab->n_static_syms); + p++) + if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE + && SYMBOL_CLASS (p) == LOC_BLOCK + && pc >= SYMBOL_VALUE_ADDRESS (p) + && SYMBOL_VALUE_ADDRESS (p) > best_pc) + { + best_pc = SYMBOL_VALUE_ADDRESS (p); + best = p; + } + if (best_pc == psymtab->textlow - 1) + return 0; + return best; +} + + +/* Find the definition for a specified symbol name NAME + in namespace NAMESPACE, visible from lexical block BLOCK. + Returns the struct symbol pointer, or zero if no symbol is found. + If SYMTAB is non-NULL, store the symbol table in which the + symbol was found there, or NULL if not found. + C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if + NAME is a field of the current implied argument `this'. If so set + *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero. + BLOCK_FOUND is set to the block in which NAME is found (in the case of + a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */ + +struct symbol * +lookup_symbol (name, block, namespace, is_a_field_of_this, symtab) + const char *name; + register const struct block *block; + const enum namespace namespace; + int *is_a_field_of_this; + struct symtab **symtab; +{ + register struct symbol *sym; + register struct symtab *s = NULL; + register struct partial_symtab *ps; + struct blockvector *bv; + register struct objfile *objfile; + register struct block *b; + register struct minimal_symbol *msymbol; + + /* Search specified block and its superiors. */ + + while (block != 0) + { + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + { + /* Search the list of symtabs for one which contains the + address of the start of this block. */ + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + if (BLOCK_START (b) <= BLOCK_START (block) + && BLOCK_END (b) > BLOCK_START (block)) + goto found; + } +found: + *symtab = s; + } + + return (sym); + } + block = BLOCK_SUPERBLOCK (block); + } + + /* FIXME: this code is never executed--block is always NULL at this + point. What is it trying to do, anyway? We already should have + checked the STATIC_BLOCK above (it is the superblock of top-level + blocks). Why is VAR_NAMESPACE special-cased? */ + /* Don't need to mess with the psymtabs; if we have a block, + that file is read in. If we don't, then we deal later with + all the psymtab stuff that needs checking. */ + if (namespace == VAR_NAMESPACE && block != NULL) + { + struct block *b; + /* Find the right symtab. */ + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + if (BLOCK_START (b) <= BLOCK_START (block) + && BLOCK_END (b) > BLOCK_START (block)) + { + sym = lookup_block_symbol (b, name, VAR_NAMESPACE); + if (sym) + { + block_found = b; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + } + } + + + /* C++: If requested to do so by the caller, + check to see if NAME is a field of `this'. */ + if (is_a_field_of_this) + { + struct value *v = value_of_this (0); + + *is_a_field_of_this = 0; + if (v && check_field (v, name)) + { + *is_a_field_of_this = 1; + if (symtab != NULL) + *symtab = NULL; + return 0; + } + } + + /* Now search all global blocks. Do the symtab's first, then + check the psymtab's */ + + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + /* Check for the possibility of the symbol being a global function + that is stored in one of the minimal symbol tables. Eventually, all + global symbols might be resolved in this way. */ + + if (namespace == VAR_NAMESPACE) + { + msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL); + if (msymbol != NULL) + { + s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)); + /* If S is NULL, there are no debug symbols for this file. + Skip this stuff and check for matching static symbols below. */ + if (s != NULL) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), + namespace); + /* We kept static functions in minimal symbol table as well as + in static scope. We want to find them in the symbol table. */ + if (!sym) { + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), + namespace); + } + + /* sym == 0 if symbol was found in the minimal symbol table + but not in the symtab. + Return 0 to use the msymbol definition of "foo_". + + This happens for Fortran "foo_" symbols, + which are "foo" in the symtab. + + This can also happen if "asm" is used to make a + regular symbol but not a debugging symbol, e.g. + asm(".globl _main"); + asm("_main:"); + */ + + if (symtab != NULL) + *symtab = s; + return sym; + } + } + } + + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace)) + { + s = PSYMTAB_TO_SYMTAB(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + error ("Internal: global symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + /* Now search all per-file blocks. + Not strictly correct, but more useful than an error. + Do the symtabs first, then check the psymtabs */ + + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace)) + { + s = PSYMTAB_TO_SYMTAB(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + error ("Internal: static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + /* Now search all per-file blocks for static mangled symbols. + Do the symtabs first, then check the psymtabs. */ + + if (namespace == VAR_NAMESPACE) + { + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, VAR_NAMESPACE); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, 0, VAR_NAMESPACE)) + { + s = PSYMTAB_TO_SYMTAB(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, VAR_NAMESPACE); + if (!sym) + error ("Internal: mangled static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); + if (symtab != NULL) + *symtab = s; + return sym; + } + } + } + + if (symtab != NULL) + *symtab = NULL; + return 0; +} + +/* Look, in partial_symtab PST, for symbol NAME. Check the global + symbols if GLOBAL, the static symbols if not */ + +static struct partial_symbol * +lookup_partial_symbol (pst, name, global, namespace) + struct partial_symtab *pst; + const char *name; + int global; + enum namespace namespace; +{ + struct partial_symbol *start, *psym; + struct partial_symbol *top, *bottom, *center; + int length = (global ? pst->n_global_syms : pst->n_static_syms); + int do_linear_search = 1; + + if (length == 0) + { + return (NULL); + } + + start = (global ? + pst->objfile->global_psymbols.list + pst->globals_offset : + pst->objfile->static_psymbols.list + pst->statics_offset ); + + if (global) /* This means we can use a binary search. */ + { + do_linear_search = 0; + + /* Binary search. This search is guaranteed to end with center + pointing at the earliest partial symbol with the correct + name. At that point *all* partial symbols with that name + will be checked against the correct namespace. */ + + bottom = start; + top = start + length - 1; + while (top > bottom) + { + center = bottom + (top - bottom) / 2; + assert (center < top); + if (!do_linear_search && SYMBOL_LANGUAGE (center) == language_cplus) + { + do_linear_search = 1; + } + if (STRCMP (SYMBOL_NAME (center), name) >= 0) + { + top = center; + } + else + { + bottom = center + 1; + } + } + assert (top == bottom); + while (STREQ (SYMBOL_NAME (top), name)) + { + if (SYMBOL_NAMESPACE (top) == namespace) + { + return top; + } + top ++; + } + } + + /* Can't use a binary search or else we found during the binary search that + we should also do a linear search. */ + + if (do_linear_search) + { + for (psym = start; psym < start + length; psym++) + { + if (namespace == SYMBOL_NAMESPACE (psym)) + { + if (SYMBOL_MATCHES_NAME (psym, name)) + { + return (psym); + } + } + } + } + + return (NULL); +} + +/* Find the psymtab containing main(). */ +/* FIXME: What about languages without main() or specially linked + executables that have no main() ? */ + +struct partial_symtab * +find_main_psymtab () +{ + register struct partial_symtab *pst; + register struct objfile *objfile; + + ALL_PSYMTABS (objfile, pst) + { + if (lookup_partial_symbol (pst, "main", 1, VAR_NAMESPACE)) + { + return (pst); + } + } + return (NULL); +} + +/* Search BLOCK for symbol NAME in NAMESPACE. + + Note that if NAME is the demangled form of a C++ symbol, we will fail + to find a match during the binary search of the non-encoded names, but + for now we don't worry about the slight inefficiency of looking for + a match we'll never find, since it will go pretty quick. Once the + binary search terminates, we drop through and do a straight linear + search on the symbols. Each symbol which is marked as being a C++ + symbol (language_cplus set) has both the encoded and non-encoded names + tested for a match. */ + +struct symbol * +lookup_block_symbol (block, name, namespace) + register const struct block *block; + const char *name; + const enum namespace namespace; +{ + register int bot, top, inc; + register struct symbol *sym; + register struct symbol *sym_found = NULL; + register int do_linear_search = 1; + + /* If the blocks's symbols were sorted, start with a binary search. */ + + if (BLOCK_SHOULD_SORT (block)) + { + /* Reset the linear search flag so if the binary search fails, we + won't do the linear search once unless we find some reason to + do so, such as finding a C++ symbol during the binary search. + Note that for C++ modules, ALL the symbols in a block should + end up marked as C++ symbols. */ + + do_linear_search = 0; + top = BLOCK_NSYMS (block); + bot = 0; + + /* Advance BOT to not far before the first symbol whose name is NAME. */ + + while (1) + { + inc = (top - bot + 1); + /* No need to keep binary searching for the last few bits worth. */ + if (inc < 4) + { + break; + } + inc = (inc >> 1) + bot; + sym = BLOCK_SYM (block, inc); + if (!do_linear_search && SYMBOL_LANGUAGE (sym) == language_cplus) + { + do_linear_search = 1; + } + if (SYMBOL_NAME (sym)[0] < name[0]) + { + bot = inc; + } + else if (SYMBOL_NAME (sym)[0] > name[0]) + { + top = inc; + } + else if (STRCMP (SYMBOL_NAME (sym), name) < 0) + { + bot = inc; + } + else + { + top = inc; + } + } + + /* Now scan forward until we run out of symbols, find one whose + name is greater than NAME, or find one we want. If there is + more than one symbol with the right name and namespace, we + return the first one; I believe it is now impossible for us + to encounter two symbols with the same name and namespace + here, because blocks containing argument symbols are no + longer sorted. */ + + top = BLOCK_NSYMS (block); + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + inc = SYMBOL_NAME (sym)[0] - name[0]; + if (inc == 0) + { + inc = STRCMP (SYMBOL_NAME (sym), name); + } + if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace) + { + return (sym); + } + if (inc > 0) + { + break; + } + bot++; + } + } + + /* Here if block isn't sorted, or we fail to find a match during the + binary search above. If during the binary search above, we find a + symbol which is a C++ symbol, then we have re-enabled the linear + search flag which was reset when starting the binary search. + + This loop is equivalent to the loop above, but hacked greatly for speed. + + Note that parameter symbols do not always show up last in the + list; this loop makes sure to take anything else other than + parameter symbols first; it only uses parameter symbols as a + last resort. Note that this only takes up extra computation + time on a match. */ + + if (do_linear_search) + { + top = BLOCK_NSYMS (block); + bot = 0; + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + if (SYMBOL_NAMESPACE (sym) == namespace && + SYMBOL_MATCHES_NAME (sym, name)) + { + sym_found = sym; + if (SYMBOL_CLASS (sym) != LOC_ARG && + SYMBOL_CLASS (sym) != LOC_LOCAL_ARG && + SYMBOL_CLASS (sym) != LOC_REF_ARG && + SYMBOL_CLASS (sym) != LOC_REGPARM && + SYMBOL_CLASS (sym) != LOC_REGPARM_ADDR && + SYMBOL_CLASS (sym) != LOC_BASEREG_ARG) + { + break; + } + } + bot++; + } + } + return (sym_found); /* Will be NULL if not found. */ +} + + +/* Return the symbol for the function which contains a specified + lexical block, described by a struct block BL. */ + +struct symbol * +block_function (bl) + struct block *bl; +{ + while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0) + bl = BLOCK_SUPERBLOCK (bl); + + return BLOCK_FUNCTION (bl); +} + +/* Find the symtab associated with PC. Look through the psymtabs and read in + another symtab if necessary. */ + +struct symtab * +find_pc_symtab (pc) + register CORE_ADDR pc; +{ + register struct block *b; + struct blockvector *bv; + register struct symtab *s = NULL; + register struct symtab *best_s = NULL; + register struct partial_symtab *ps; + register struct objfile *objfile; + int distance = 0; + + /* Search all symtabs for the one whose file contains our address, and which + is the smallest of all the ones containing the address. This is designed + to deal with a case like symtab a is at 0x1000-0x2000 and 0x3000-0x4000 + and symtab b is at 0x2000-0x3000. So the GLOBAL_BLOCK for a is from + 0x1000-0x4000, but for address 0x2345 we want to return symtab b. + This is said to happen for the mips; it might be swifter to create + several symtabs with the same name like xcoff does (I'm not sure). */ + + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc + && (distance == 0 + || BLOCK_END (b) - BLOCK_START (b) < distance)) + { + distance = BLOCK_END (b) - BLOCK_START (b); + best_s = s; + } + } + + if (best_s != NULL) + return(best_s); + + s = NULL; + ps = find_pc_psymtab (pc); + if (ps) + { + if (ps->readin) + /* Might want to error() here (in case symtab is corrupt and + will cause a core dump), but maybe we can successfully + continue, so let's not. */ + warning ("\ +(Internal error: pc 0x%lx in read in psymtab, but not in symtab.)\n", + (unsigned long) pc); + s = PSYMTAB_TO_SYMTAB (ps); + } + return (s); +} + +/* Find the source file and line number for a given PC value. + Return a structure containing a symtab pointer, a line number, + and a pc range for the entire source line. + The value's .pc field is NOT the specified pc. + NOTCURRENT nonzero means, if specified pc is on a line boundary, + use the line that ends there. Otherwise, in that case, the line + that begins there is used. */ + +/* The big complication here is that a line may start in one file, and end just + before the start of another file. This usually occurs when you #include + code in the middle of a subroutine. To properly find the end of a line's PC + range, we must search all symtabs associated with this compilation unit, and + find the one whose first PC is closer than that of the next line in this + symtab. */ + +/* If it's worth the effort, we could be using a binary search. */ + +struct symtab_and_line +find_pc_line (pc, notcurrent) + CORE_ADDR pc; + int notcurrent; +{ + struct symtab *s; + register struct linetable *l; + register int len; + register int i; + register struct linetable_entry *item; + struct symtab_and_line val; + struct blockvector *bv; + + /* Info on best line seen so far, and where it starts, and its file. */ + + struct linetable_entry *best = NULL; + CORE_ADDR best_end = 0; + struct symtab *best_symtab = 0; + + /* Store here the first line number + of a file which contains the line at the smallest pc after PC. + If we don't find a line whose range contains PC, + we will use a line one less than this, + with a range from the start of that file to the first line's pc. */ + struct linetable_entry *alt = NULL; + struct symtab *alt_symtab = 0; + + /* Info on best line seen in this file. */ + + struct linetable_entry *prev; + + /* If this pc is not from the current frame, + it is the address of the end of a call instruction. + Quite likely that is the start of the following statement. + But what we want is the statement containing the instruction. + Fudge the pc to make sure we get that. */ + + if (notcurrent) pc -= 1; + + s = find_pc_symtab (pc); + if (!s) + { + val.symtab = 0; + val.line = 0; + val.pc = pc; + val.end = 0; + return val; + } + + bv = BLOCKVECTOR (s); + + /* Look at all the symtabs that share this blockvector. + They all have the same apriori range, that we found was right; + but they have different line tables. */ + + for (; s && BLOCKVECTOR (s) == bv; s = s->next) + { + /* Find the best line in this symtab. */ + l = LINETABLE (s); + if (!l) + continue; + len = l->nitems; + if (len <= 0) + { + /* I think len can be zero if the symtab lacks line numbers + (e.g. gcc -g1). (Either that or the LINETABLE is NULL; + I'm not sure which, and maybe it depends on the symbol + reader). */ + continue; + } + + prev = NULL; + item = l->item; /* Get first line info */ + + /* Is this file's first line closer than the first lines of other files? + If so, record this file, and its first line, as best alternate. */ + if (item->pc > pc && (!alt || item->pc < alt->pc)) + { + alt = item; + alt_symtab = s; + } + + for (i = 0; i < len; i++, item++) + { + /* Return the last line that did not start after PC. */ + if (item->pc > pc) + break; + + prev = item; + } + + /* At this point, prev points at the line whose start addr is <= pc, and + item points at the next line. If we ran off the end of the linetable + (pc >= start of the last line), then prev == item. If pc < start of + the first line, prev will not be set. */ + + /* Is this file's best line closer than the best in the other files? + If so, record this file, and its best line, as best so far. */ + + if (prev && (!best || prev->pc > best->pc)) + { + best = prev; + best_symtab = s; + /* If another line is in the linetable, and its PC is closer + than the best_end we currently have, take it as best_end. */ + if (i < len && (best_end == 0 || best_end > item->pc)) + best_end = item->pc; + } + } + + if (!best_symtab) + { + if (!alt_symtab) + { /* If we didn't find any line # info, just + return zeros. */ + val.symtab = 0; + val.line = 0; + val.pc = pc; + val.end = 0; + } + else + { + val.symtab = alt_symtab; + val.line = alt->line - 1; + val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + val.end = alt->pc; + } + } + else + { + val.symtab = best_symtab; + val.line = best->line; + val.pc = best->pc; + if (best_end && (!alt || best_end < alt->pc)) + val.end = best_end; + else if (alt) + val.end = alt->pc; + else + val.end = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + } + return val; +} + +static int find_line_symtab PARAMS ((struct symtab *, int, struct linetable **, + int *, int *)); + +/* Find line number LINE in any symtab whose name is the same as + SYMTAB. + + If found, return 1, set *LINETABLE to the linetable in which it was + found, set *INDEX to the index in the linetable of the best entry + found, and set *EXACT_MATCH nonzero if the value returned is an + exact match. + + If not found, return 0. */ + +static int +find_line_symtab (symtab, line, linetable, index, exact_match) + struct symtab *symtab; + int line; + struct linetable **linetable; + int *index; + int *exact_match; +{ + int exact; + + /* BEST_INDEX and BEST_LINETABLE identify the smallest linenumber > LINE + so far seen. */ + + int best_index; + struct linetable *best_linetable; + + /* First try looking it up in the given symtab. */ + best_linetable = LINETABLE (symtab); + best_index = find_line_common (best_linetable, line, &exact); + if (best_index < 0 || !exact) + { + /* Didn't find an exact match. So we better keep looking for + another symtab with the same name. In the case of xcoff, + multiple csects for one source file (produced by IBM's FORTRAN + compiler) produce multiple symtabs (this is unavoidable + assuming csects can be at arbitrary places in memory and that + the GLOBAL_BLOCK of a symtab has a begin and end address). */ + + /* BEST is the smallest linenumber > LINE so far seen, + or 0 if none has been seen so far. + BEST_INDEX and BEST_LINETABLE identify the item for it. */ + int best; + + struct objfile *objfile; + struct symtab *s; + + if (best_index >= 0) + best = best_linetable->item[best_index].line; + else + best = 0; + + ALL_SYMTABS (objfile, s) + { + struct linetable *l; + int ind; + + if (!STREQ (symtab->filename, s->filename)) + continue; + l = LINETABLE (s); + ind = find_line_common (l, line, &exact); + if (ind >= 0) + { + if (exact) + { + best_index = ind; + best_linetable = l; + goto done; + } + if (best == 0 || l->item[ind].line < best) + { + best = l->item[ind].line; + best_index = ind; + best_linetable = l; + } + } + } + } + done: + if (best_index < 0) + return 0; + + if (index) + *index = best_index; + if (linetable) + *linetable = best_linetable; + if (exact_match) + *exact_match = exact; + return 1; +} + +/* Find the PC value for a given source file and line number. + Returns zero for invalid line number. + The source file is specified with a struct symtab. */ + +CORE_ADDR +find_line_pc (symtab, line) + struct symtab *symtab; + int line; +{ + struct linetable *l; + int ind; + + if (symtab == 0) + return 0; + if (find_line_symtab (symtab, line, &l, &ind, NULL)) + return l->item[ind].pc; + else + return 0; +} + +/* Find the range of pc values in a line. + Store the starting pc of the line into *STARTPTR + and the ending pc (start of next line) into *ENDPTR. + Returns 1 to indicate success. + Returns 0 if could not find the specified line. */ + +int +find_line_pc_range (symtab, thisline, startptr, endptr) + struct symtab *symtab; + int thisline; + CORE_ADDR *startptr, *endptr; +{ + struct linetable *l; + int ind; + int exact_match; /* did we get an exact linenumber match */ + + if (symtab == 0) + return 0; + + if (find_line_symtab (symtab, thisline, &l, &ind, &exact_match)) + { + *startptr = l->item[ind].pc; + /* If we have not seen an entry for the specified line, + assume that means the specified line has zero bytes. */ + if (!exact_match || ind == l->nitems-1) + *endptr = *startptr; + else + /* Perhaps the following entry is for the following line. + It's worth a try. */ + if (ind+1 < l->nitems + && l->item[ind+1].line == thisline + 1) + *endptr = l->item[ind+1].pc; + else + *endptr = find_line_pc (symtab, thisline+1); + return 1; + } + + return 0; +} + +/* Given a line table and a line number, return the index into the line + table for the pc of the nearest line whose number is >= the specified one. + Return -1 if none is found. The value is >= 0 if it is an index. + + Set *EXACT_MATCH nonzero if the value returned is an exact match. */ + +static int +find_line_common (l, lineno, exact_match) + register struct linetable *l; + register int lineno; + int *exact_match; +{ + register int i; + register int len; + + /* BEST is the smallest linenumber > LINENO so far seen, + or 0 if none has been seen so far. + BEST_INDEX identifies the item for it. */ + + int best_index = -1; + int best = 0; + + if (lineno <= 0) + return -1; + if (l == 0) + return -1; + + len = l->nitems; + for (i = 0; i < len; i++) + { + register struct linetable_entry *item = &(l->item[i]); + + if (item->line == lineno) + { + /* Return the first (lowest address) entry which matches. */ + *exact_match = 1; + return i; + } + + if (item->line > lineno && (best == 0 || item->line < best)) + { + best = item->line; + best_index = i; + } + } + + /* If we got here, we didn't get an exact match. */ + + *exact_match = 0; + return best_index; +} + +int +find_pc_line_pc_range (pc, startptr, endptr) + CORE_ADDR pc; + CORE_ADDR *startptr, *endptr; +{ + struct symtab_and_line sal; + sal = find_pc_line (pc, 0); + *startptr = sal.pc; + *endptr = sal.end; + return sal.symtab != 0; +} + +/* If P is of the form "operator[ \t]+..." where `...' is + some legitimate operator text, return a pointer to the + beginning of the substring of the operator text. + Otherwise, return "". */ +static char * +operator_chars (p, end) + char *p; + char **end; +{ + *end = ""; + if (strncmp (p, "operator", 8)) + return *end; + p += 8; + + /* Don't get faked out by `operator' being part of a longer + identifier. */ + if (isalpha(*p) || *p == '_' || *p == '$' || *p == '\0') + return *end; + + /* Allow some whitespace between `operator' and the operator symbol. */ + while (*p == ' ' || *p == '\t') + p++; + + /* Recognize 'operator TYPENAME'. */ + + if (isalpha(*p) || *p == '_' || *p == '$') + { + register char *q = p+1; + while (isalnum(*q) || *q == '_' || *q == '$') + q++; + *end = q; + return p; + } + + switch (*p) + { + case '!': + case '=': + case '*': + case '/': + case '%': + case '^': + if (p[1] == '=') + *end = p+2; + else + *end = p+1; + return p; + case '<': + case '>': + case '+': + case '-': + case '&': + case '|': + if (p[1] == '=' || p[1] == p[0]) + *end = p+2; + else + *end = p+1; + return p; + case '~': + case ',': + *end = p+1; + return p; + case '(': + if (p[1] != ')') + error ("`operator ()' must be specified without whitespace in `()'"); + *end = p+2; + return p; + case '?': + if (p[1] != ':') + error ("`operator ?:' must be specified without whitespace in `?:'"); + *end = p+2; + return p; + case '[': + if (p[1] != ']') + error ("`operator []' must be specified without whitespace in `[]'"); + *end = p+2; + return p; + default: + error ("`operator %s' not supported", p); + break; + } + *end = ""; + return *end; +} + +/* Recursive helper function for decode_line_1. + * Look for methods named NAME in type T. + * Return number of matches. + * Put matches in SYM_ARR (which better be big enough!). + * These allocations seem to define "big enough": + * sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*)); + * Note that this function is g++ specific. + */ + +int +find_methods (t, name, sym_arr) + struct type *t; + char *name; + struct symbol **sym_arr; +{ + int i1 = 0; + int ibase; + struct symbol *sym_class; + char *class_name = type_name_no_tag (t); + /* Ignore this class if it doesn't have a name. This is ugly, but + unless we figure out how to get the physname without the name of + the class, then the loop can't do any good. */ + if (class_name + && (sym_class = lookup_symbol (class_name, + (struct block *)NULL, + STRUCT_NAMESPACE, + (int *)NULL, + (struct symtab **)NULL))) + { + int method_counter; + /* FIXME: Shouldn't this just be check_stub_type (t)? */ + t = SYMBOL_TYPE (sym_class); + for (method_counter = TYPE_NFN_FIELDS (t) - 1; + method_counter >= 0; + --method_counter) + { + int field_counter; + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, method_counter); + + char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter); + if (STREQ (name, method_name)) + /* Find all the fields with that name. */ + for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1; + field_counter >= 0; + --field_counter) + { + char *phys_name; + if (TYPE_FN_FIELD_STUB (f, field_counter)) + check_stub_method (t, method_counter, field_counter); + phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter); + /* Destructor is handled by caller, dont add it to the list */ + if (DESTRUCTOR_PREFIX_P (phys_name)) + continue; + + /* FIXME: Why are we looking this up in the + SYMBOL_BLOCK_VALUE (sym_class)? It is intended as a hook + for nested types? If so, it should probably hook to the + type, not the symbol. mipsread.c is the only symbol + reader which sets the SYMBOL_BLOCK_VALUE for types, and + this is not documented in symtab.h. -26Aug93. */ + + sym_arr[i1] = lookup_symbol (phys_name, + SYMBOL_BLOCK_VALUE (sym_class), + VAR_NAMESPACE, + (int *) NULL, + (struct symtab **) NULL); + if (sym_arr[i1]) i1++; + else + { + fputs_filtered("(Cannot find method ", stdout); + fprintf_symbol_filtered (stdout, phys_name, + language_cplus, DMGL_PARAMS); + fputs_filtered(" - possibly inlined.)\n", stdout); + } + } + } + } + + /* Only search baseclasses if there is no match yet, since names in + derived classes override those in baseclasses. + + FIXME: The above is not true; it is only true of member functions + if they have the same number of arguments (??? - section 13.1 of the + ARM says the function members are not in the same scope but doesn't + really spell out the rules in a way I understand. In any case, if + the number of arguments differ this is a case in which we can overload + rather than hiding without any problem, and gcc 2.4.5 does overload + rather than hiding in this case). */ + + if (i1) + return i1; + for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++) + i1 += find_methods(TYPE_BASECLASS(t, ibase), name, + sym_arr + i1); + return i1; +} + +/* Helper function for decode_line_1. + Build a canonical line spec in CANONICAL if it is non-NULL and if + the SAL has a symtab. + If SYMNAME is non-NULL the canonical line spec is `filename:symname'. + If SYMNAME is NULL the line number from SAL is used and the canonical + line spec is `filename:linenum'. */ + +static void +build_canonical_line_spec (sal, symname, canonical) + struct symtab_and_line *sal; + char *symname; + char ***canonical; +{ + char **canonical_arr; + char *canonical_name; + char *filename; + struct symtab *s = sal->symtab; + + if (s == (struct symtab *)NULL + || s->filename == (char *)NULL + || canonical == (char ***)NULL) + return; + + canonical_arr = (char **) xmalloc (sizeof (char *)); + *canonical = canonical_arr; + + filename = s->filename; + if (symname != NULL) + { + canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2); + sprintf (canonical_name, "%s:%s", filename, symname); + } + else + { + canonical_name = xmalloc (strlen (filename) + 30); + sprintf (canonical_name, "%s:%d", filename, sal->line); + } + canonical_arr[0] = canonical_name; +} + +/* Parse a string that specifies a line number. + Pass the address of a char * variable; that variable will be + advanced over the characters actually parsed. + + The string can be: + + LINENUM -- that line number in current file. PC returned is 0. + FILE:LINENUM -- that line in that file. PC returned is 0. + FUNCTION -- line number of openbrace of that function. + PC returned is the start of the function. + VARIABLE -- line number of definition of that variable. + PC returned is 0. + FILE:FUNCTION -- likewise, but prefer functions in that file. + *EXPR -- line in which address EXPR appears. + + FUNCTION may be an undebuggable function found in minimal symbol table. + + If the argument FUNFIRSTLINE is nonzero, we want the first line + of real code inside a function when a function is specified. + + DEFAULT_SYMTAB specifies the file to use if none is specified. + It defaults to current_source_symtab. + DEFAULT_LINE specifies the line number to use for relative + line numbers (that start with signs). Defaults to current_source_line. + If CANONICAL is non-NULL, store an array of strings containing the canonical + line specs there if necessary. Currently overloaded member functions and + line numbers or static functions without a filename yield a canonical + line spec. The array and the line spec strings are allocated on the heap, + it is the callers responsibility to free them. + + Note that it is possible to return zero for the symtab + if no file is validly specified. Callers must check that. + Also, the line number returned may be invalid. */ + +struct symtabs_and_lines +decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical) + char **argptr; + int funfirstline; + struct symtab *default_symtab; + int default_line; + char ***canonical; +{ + struct symtabs_and_lines values; +#ifdef HPPA_COMPILER_BUG + /* FIXME: The native HP 9000/700 compiler has a bug which appears + when optimizing this file with target i960-vxworks. I haven't + been able to construct a simple test case. The problem is that + in the second call to SKIP_PROLOGUE below, the compiler somehow + does not realize that the statement val = find_pc_line (...) will + change the values of the fields of val. It extracts the elements + into registers at the top of the block, and does not update the + registers after the call to find_pc_line. You can check this by + inserting a printf at the end of find_pc_line to show what values + it is returning for val.pc and val.end and another printf after + the call to see what values the function actually got (remember, + this is compiling with cc -O, with this patch removed). You can + also examine the assembly listing: search for the second call to + skip_prologue; the LDO statement before the next call to + find_pc_line loads the address of the structure which + find_pc_line will return; if there is a LDW just before the LDO, + which fetches an element of the structure, then the compiler + still has the bug. + + Setting val to volatile avoids the problem. We must undef + volatile, because the HPPA native compiler does not define + __STDC__, although it does understand volatile, and so volatile + will have been defined away in defs.h. */ +#undef volatile + volatile struct symtab_and_line val; +#define volatile /*nothing*/ +#else + struct symtab_and_line val; +#endif + register char *p, *p1; + char *q, *q1; + register struct symtab *s; + + register struct symbol *sym; + /* The symtab that SYM was found in. */ + struct symtab *sym_symtab; + + register CORE_ADDR pc; + register struct minimal_symbol *msymbol; + char *copy; + struct symbol *sym_class; + int i1; + int is_quoted; + struct symbol **sym_arr; + struct type *t; + char *saved_arg = *argptr; + extern char *gdb_completer_quote_characters; + + /* Defaults have defaults. */ + + if (default_symtab == 0) + { + default_symtab = current_source_symtab; + default_line = current_source_line; + } + + /* See if arg is *PC */ + + if (**argptr == '*') + { + if (**argptr == '*') + { + (*argptr)++; + } + pc = parse_and_eval_address_1 (argptr); + values.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + values.sals[0] = find_pc_line (pc, 0); + values.sals[0].pc = pc; + build_canonical_line_spec (values.sals, NULL, canonical); + return values; + } + + /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */ + + s = NULL; + is_quoted = (strchr (gdb_completer_quote_characters, **argptr) != NULL); + + for (p = *argptr; *p; p++) + { + if (p[0] == ':' || p[0] == ' ' || p[0] == '\t') + break; + } + while (p[0] == ' ' || p[0] == '\t') p++; + + if ((p[0] == ':') && !is_quoted) + { + + /* C++ */ + if (p[1] ==':') + { + /* Extract the class name. */ + p1 = p; + while (p != *argptr && p[-1] == ' ') --p; + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = 0; + + /* Discard the class name from the arg. */ + p = p1 + 2; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0, + (struct symtab **)NULL); + + if (sym_class && + ( TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT + || TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_UNION)) + { + /* Arg token is not digits => try it as a function name + Find the next token (everything up to end or next whitespace). */ + p = *argptr; + while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p !=':') p++; + q = operator_chars (*argptr, &q1); + + if (q1 - q) + { + char *opname; + char *tmp = alloca (q1 - q + 1); + memcpy (tmp, q, q1 - q); + tmp[q1 - q] = '\0'; + opname = cplus_mangle_opname (tmp, DMGL_ANSI); + if (opname == NULL) + { + warning ("no mangling for \"%s\"", tmp); + cplusplus_hint (saved_arg); + return_to_top_level (RETURN_ERROR); + } + copy = (char*) alloca (3 + strlen(opname)); + sprintf (copy, "__%s", opname); + p = q1; + } + else + { + copy = (char *) alloca (p - *argptr + 1 + (q1 - q)); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = '\0'; + } + + /* no line number may be specified */ + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + sym = 0; + i1 = 0; /* counter for the symbol array */ + t = SYMBOL_TYPE (sym_class); + sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*)); + + /* Cfront objects don't have fieldlists. */ + if (destructor_name_p (copy, t) && TYPE_FN_FIELDLISTS (t) != NULL) + { + /* destructors are a special case. */ + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0); + int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1; + /* gcc 1.x puts destructor in last field, + gcc 2.x puts destructor in first field. */ + char *phys_name = TYPE_FN_FIELD_PHYSNAME (f, len); + if (!DESTRUCTOR_PREFIX_P (phys_name)) + { + phys_name = TYPE_FN_FIELD_PHYSNAME (f, 0); + if (!DESTRUCTOR_PREFIX_P (phys_name)) + phys_name = ""; + } + sym_arr[i1] = + lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), + VAR_NAMESPACE, 0, (struct symtab **)NULL); + if (sym_arr[i1]) i1++; + } + else + i1 = find_methods (t, copy, sym_arr); + if (i1 == 1) + { + /* There is exactly one field with that name. */ + sym = sym_arr[0]; + + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* Arg is the name of a function */ + pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (pc); + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + values.sals[0] = find_pc_line (pc, 0); + values.sals[0].pc = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc; + } + else + { + values.nelts = 0; + } + return values; + } + if (i1 > 0) + { + /* There is more than one field with that name + (overloaded). Ask the user which one to use. */ + return decode_line_2 (sym_arr, i1, funfirstline, canonical); + } + else + { + char *tmp; + + if (OPNAME_PREFIX_P (copy)) + { + tmp = (char *)alloca (strlen (copy+3) + 9); + strcpy (tmp, "operator "); + strcat (tmp, copy+3); + } + else + tmp = copy; + if (tmp[0] == '~') + warning ("the class `%s' does not have destructor defined", + SYMBOL_SOURCE_NAME(sym_class)); + else + warning ("the class %s does not have any method named %s", + SYMBOL_SOURCE_NAME(sym_class), tmp); + cplusplus_hint (saved_arg); + return_to_top_level (RETURN_ERROR); + } + } + else + { + /* The quotes are important if copy is empty. */ + warning ("can't find class, struct, or union named \"%s\"", + copy); + cplusplus_hint (saved_arg); + return_to_top_level (RETURN_ERROR); + } + } + /* end of C++ */ + + + /* Extract the file name. */ + p1 = p; + while (p != *argptr && p[-1] == ' ') --p; + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = 0; + + /* Find that file's data. */ + s = lookup_symtab (copy); + if (s == 0) + { + if (!have_full_symbols () && !have_partial_symbols ()) + error (no_symtab_msg); + error ("No source file named %s.", copy); + } + + /* Discard the file name from the arg. */ + p = p1 + 1; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + } + + /* S is specified file's symtab, or 0 if no file specified. + arg no longer contains the file name. */ + + /* Check whether arg is all digits (and sign) */ + + p = *argptr; + if (*p == '-' || *p == '+') p++; + while (*p >= '0' && *p <= '9') + p++; + + if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ',')) + { + /* We found a token consisting of all digits -- at least one digit. */ + enum sign {none, plus, minus} sign = none; + + /* We might need a canonical line spec if no file was specified. */ + int need_canonical = (s == 0) ? 1 : 0; + + /* This is where we need to make sure that we have good defaults. + We must guarantee that this section of code is never executed + when we are called with just a function name, since + select_source_symtab calls us with such an argument */ + + if (s == 0 && default_symtab == 0) + { + select_source_symtab (0); + default_symtab = current_source_symtab; + default_line = current_source_line; + } + + if (**argptr == '+') + sign = plus, (*argptr)++; + else if (**argptr == '-') + sign = minus, (*argptr)++; + val.line = atoi (*argptr); + switch (sign) + { + case plus: + if (p == *argptr) + val.line = 5; + if (s == 0) + val.line = default_line + val.line; + break; + case minus: + if (p == *argptr) + val.line = 15; + if (s == 0) + val.line = default_line - val.line; + else + val.line = 1; + break; + case none: + break; /* No need to adjust val.line. */ + } + + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + if (s == 0) + s = default_symtab; + val.symtab = s; + val.pc = 0; + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.sals[0] = val; + values.nelts = 1; + if (need_canonical) + build_canonical_line_spec (values.sals, NULL, canonical); + return values; + } + + /* Arg token is not digits => try it as a variable name + Find the next token (everything up to end or next whitespace). */ + + p = skip_quoted (*argptr); + if (is_quoted && p[-1] != '\'') + error ("Unmatched single quote."); + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = '\0'; + if ((copy[0] == copy [p - *argptr - 1]) + && strchr (gdb_completer_quote_characters, copy[0]) != NULL) + { + copy [p - *argptr - 1] = '\0'; + copy++; + } + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + /* Look up that token as a variable. + If file specified, use that file's per-file block to start with. */ + + sym = lookup_symbol (copy, + (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) + : get_selected_block ()), + VAR_NAMESPACE, 0, &sym_symtab); + + if (sym != NULL) + { + if (SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* Arg is the name of a function */ + pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (pc); + val = find_pc_line (pc, 0); +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* Convex: no need to suppress code on first line, if any */ + val.pc = pc; +#else + /* Check if SKIP_PROLOGUE left us in mid-line, and the next + line is still part of the same function. */ + if (val.pc != pc + && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= val.end + && val.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym))) + { + /* First pc of next line */ + pc = val.end; + /* Recalculate the line number (might not be N+1). */ + val = find_pc_line (pc, 0); + } + val.pc = pc; +#endif + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.sals[0] = val; + values.nelts = 1; + + /* I think this is always the same as the line that + we calculate above, but the general principle is + "trust the symbols more than stuff like + SKIP_PROLOGUE". */ + if (SYMBOL_LINE (sym) != 0) + values.sals[0].line = SYMBOL_LINE (sym); + + /* We might need a canonical line spec if it is a static function. */ + if (s == 0) + { + struct blockvector *bv = BLOCKVECTOR (sym_symtab); + struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + if (lookup_block_symbol (b, copy, VAR_NAMESPACE) != NULL) + build_canonical_line_spec (values.sals, copy, canonical); + } + return values; + } + else if (SYMBOL_LINE (sym) != 0) + { + /* We know its line number. */ + values.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + memset (&values.sals[0], 0, sizeof (values.sals[0])); + values.sals[0].symtab = sym_symtab; + values.sals[0].line = SYMBOL_LINE (sym); + return values; + } + else + /* This can happen if it is compiled with a compiler which doesn't + put out line numbers for variables. */ + /* FIXME: Shouldn't we just set .line and .symtab to zero and + return? For example, "info line foo" could print the address. */ + error ("Line number not known for symbol \"%s\"", copy); + } + + msymbol = lookup_minimal_symbol (copy, (struct objfile *) NULL); + if (msymbol != NULL) + { + val.symtab = 0; + val.line = 0; + val.pc = SYMBOL_VALUE_ADDRESS (msymbol) + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (val.pc); + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.sals[0] = val; + values.nelts = 1; + return values; + } + + if (!have_full_symbols () && + !have_partial_symbols () && !have_minimal_symbols ()) + error (no_symtab_msg); + + error ("Function \"%s\" not defined.", copy); + return values; /* for lint */ +} + +struct symtabs_and_lines +decode_line_spec (string, funfirstline) + char *string; + int funfirstline; +{ + struct symtabs_and_lines sals; + if (string == 0) + error ("Empty line specification."); + sals = decode_line_1 (&string, funfirstline, + current_source_symtab, current_source_line, + (char ***)NULL); + if (*string) + error ("Junk at end of line specification: %s", string); + return sals; +} + +/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to + operate on (ask user if necessary). + If CANONICAL is non-NULL return a corresponding array of mangled names + as canonical line specs there. */ + +static struct symtabs_and_lines +decode_line_2 (sym_arr, nelts, funfirstline, canonical) + struct symbol *sym_arr[]; + int nelts; + int funfirstline; + char ***canonical; +{ + struct symtabs_and_lines values, return_values; + register CORE_ADDR pc; + char *args, *arg1; + int i; + char *prompt; + char *symname; + struct cleanup *old_chain; + char **canonical_arr = (char **)NULL; + + values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line)); + return_values.sals = (struct symtab_and_line *) xmalloc (nelts * sizeof(struct symtab_and_line)); + old_chain = make_cleanup (free, return_values.sals); + + if (canonical) + { + canonical_arr = (char **) xmalloc (nelts * sizeof (char *)); + make_cleanup (free, canonical_arr); + memset (canonical_arr, 0, nelts * sizeof (char *)); + *canonical = canonical_arr; + } + + i = 0; + printf("[0] cancel\n[1] all\n"); + while (i < nelts) + { + if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK) + { + /* Arg is the name of a function */ + pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i])) + + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (pc); + values.sals[i] = find_pc_line (pc, 0); + values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ? + values.sals[i].end : pc; + printf("[%d] %s at %s:%d\n", (i+2), SYMBOL_SOURCE_NAME (sym_arr[i]), + values.sals[i].symtab->filename, values.sals[i].line); + } + else printf ("?HERE\n"); + i++; + } + + if ((prompt = getenv ("PS2")) == NULL) + { + prompt = ">"; + } + printf("%s ",prompt); + fflush(stdout); + + args = command_line_input ((char *) NULL, 0); + + if (args == 0 || *args == 0) + error_no_arg ("one or more choice numbers"); + + i = 0; + while (*args) + { + int num; + + arg1 = args; + while (*arg1 >= '0' && *arg1 <= '9') arg1++; + if (*arg1 && *arg1 != ' ' && *arg1 != '\t') + error ("Arguments must be choice numbers."); + + num = atoi (args); + + if (num == 0) + error ("cancelled"); + else if (num == 1) + { + if (canonical_arr) + { + for (i = 0; i < nelts; i++) + { + if (canonical_arr[i] == NULL) + { + symname = SYMBOL_NAME (sym_arr[i]); + canonical_arr[i] = savestring (symname, strlen (symname)); + } + } + } + memcpy (return_values.sals, values.sals, + (nelts * sizeof(struct symtab_and_line))); + return_values.nelts = nelts; + discard_cleanups (old_chain); + return return_values; + } + + if (num > nelts + 2) + { + printf ("No choice number %d.\n", num); + } + else + { + num -= 2; + if (values.sals[num].pc) + { + if (canonical_arr) + { + symname = SYMBOL_NAME (sym_arr[num]); + make_cleanup (free, symname); + canonical_arr[i] = savestring (symname, strlen (symname)); + } + return_values.sals[i++] = values.sals[num]; + values.sals[num].pc = 0; + } + else + { + printf ("duplicate request for %d ignored.\n", num); + } + } + + args = arg1; + while (*args == ' ' || *args == '\t') args++; + } + return_values.nelts = i; + discard_cleanups (old_chain); + return return_values; +} + + +/* Slave routine for sources_info. Force line breaks at ,'s. + NAME is the name to print and *FIRST is nonzero if this is the first + name printed. Set *FIRST to zero. */ +static void +output_source_filename (name, first) + char *name; + int *first; +{ + /* Table of files printed so far. Since a single source file can + result in several partial symbol tables, we need to avoid printing + it more than once. Note: if some of the psymtabs are read in and + some are not, it gets printed both under "Source files for which + symbols have been read" and "Source files for which symbols will + be read in on demand". I consider this a reasonable way to deal + with the situation. I'm not sure whether this can also happen for + symtabs; it doesn't hurt to check. */ + static char **tab = NULL; + /* Allocated size of tab in elements. + Start with one 256-byte block (when using GNU malloc.c). + 24 is the malloc overhead when range checking is in effect. */ + static int tab_alloc_size = (256 - 24) / sizeof (char *); + /* Current size of tab in elements. */ + static int tab_cur_size; + + char **p; + + if (*first) + { + if (tab == NULL) + tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab)); + tab_cur_size = 0; + } + + /* Is NAME in tab? */ + for (p = tab; p < tab + tab_cur_size; p++) + if (STREQ (*p, name)) + /* Yes; don't print it again. */ + return; + /* No; add it to tab. */ + if (tab_cur_size == tab_alloc_size) + { + tab_alloc_size *= 2; + tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab)); + } + tab[tab_cur_size++] = name; + + if (*first) + { + *first = 0; + } + else + { + printf_filtered (", "); + } + + wrap_here (""); + fputs_filtered (name, stdout); +} + +static void +sources_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct symtab *s; + register struct partial_symtab *ps; + register struct objfile *objfile; + int first; + + if (!have_full_symbols () && !have_partial_symbols ()) + { + error (no_symtab_msg); + } + + printf_filtered ("Source files for which symbols have been read in:\n\n"); + + first = 1; + ALL_SYMTABS (objfile, s) + { + output_source_filename (s -> filename, &first); + } + printf_filtered ("\n\n"); + + printf_filtered ("Source files for which symbols will be read in on demand:\n\n"); + + first = 1; + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin) + { + output_source_filename (ps -> filename, &first); + } + } + printf_filtered ("\n"); +} + +/* List all symbols (if REGEXP is NULL) or all symbols matching REGEXP. + If CLASS is zero, list all symbols except functions, type names, and + constants (enums). + If CLASS is 1, list only functions. + If CLASS is 2, list only type names. + If CLASS is 3, list only method names. + + BPT is non-zero if we should set a breakpoint at the functions + we find. */ + +static void +list_symbols (regexp, class, bpt) + char *regexp; + int class; + int bpt; +{ + register struct symtab *s; + register struct partial_symtab *ps; + register struct blockvector *bv; + struct blockvector *prev_bv = 0; + register struct block *b; + register int i, j; + register struct symbol *sym; + struct partial_symbol *psym; + struct objfile *objfile; + struct minimal_symbol *msymbol; + char *val; + static char *classnames[] + = {"variable", "function", "type", "method"}; + int found_in_file = 0; + int found_misc = 0; + static enum minimal_symbol_type types[] + = {mst_data, mst_text, mst_abs, mst_unknown}; + static enum minimal_symbol_type types2[] + = {mst_bss, mst_text, mst_abs, mst_unknown}; + enum minimal_symbol_type ourtype = types[class]; + enum minimal_symbol_type ourtype2 = types2[class]; + + if (regexp != NULL) + { + /* Make sure spacing is right for C++ operators. + This is just a courtesy to make the matching less sensitive + to how many spaces the user leaves between 'operator' + and or . */ + char *opend; + char *opname = operator_chars (regexp, &opend); + if (*opname) + { + int fix = -1; /* -1 means ok; otherwise number of spaces needed. */ + if (isalpha(*opname) || *opname == '_' || *opname == '$') + { + /* There should 1 space between 'operator' and 'TYPENAME'. */ + if (opname[-1] != ' ' || opname[-2] == ' ') + fix = 1; + } + else + { + /* There should 0 spaces between 'operator' and 'OPERATOR'. */ + if (opname[-1] == ' ') + fix = 0; + } + /* If wrong number of spaces, fix it. */ + if (fix >= 0) + { + char *tmp = (char*) alloca(opend-opname+10); + sprintf(tmp, "operator%.*s%s", fix, " ", opname); + regexp = tmp; + } + } + + if (0 != (val = re_comp (regexp))) + error ("Invalid regexp (%s): %s", val, regexp); + } + + /* Search through the partial symtabs *first* for all symbols + matching the regexp. That way we don't have to reproduce all of + the machinery below. */ + + ALL_PSYMTABS (objfile, ps) + { + struct partial_symbol *bound, *gbound, *sbound; + int keep_going = 1; + + if (ps->readin) continue; + + gbound = objfile->global_psymbols.list + ps->globals_offset + ps->n_global_syms; + sbound = objfile->static_psymbols.list + ps->statics_offset + ps->n_static_syms; + bound = gbound; + + /* Go through all of the symbols stored in a partial + symtab in one loop. */ + psym = objfile->global_psymbols.list + ps->globals_offset; + while (keep_going) + { + if (psym >= bound) + { + if (bound == gbound && ps->n_static_syms != 0) + { + psym = objfile->static_psymbols.list + ps->statics_offset; + bound = sbound; + } + else + keep_going = 0; + continue; + } + else + { + QUIT; + + /* If it would match (logic taken from loop below) + load the file and go on to the next one */ + if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (psym)) + && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF + && SYMBOL_CLASS (psym) != LOC_BLOCK) + || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF) + || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK))) + { + PSYMTAB_TO_SYMTAB(ps); + keep_going = 0; + } + } + psym++; + } + } + + /* Here, we search through the minimal symbol tables for functions that + match, and call find_pc_symtab on them to force their symbols to + be read. The symbol will then be found during the scan of symtabs + below. If find_pc_symtab fails, set found_misc so that we will + rescan to print any matching symbols without debug info. */ + + if (class == 1) + { + ALL_MSYMBOLS (objfile, msymbol) + { + if (MSYMBOL_TYPE (msymbol) == ourtype || + MSYMBOL_TYPE (msymbol) == ourtype2) + { + if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) + { + if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))) + { + found_misc = 1; + } + } + } + } + } + + /* Printout here so as to get after the "Reading in symbols" + messages which will be generated above. */ + if (!bpt) + printf_filtered (regexp + ? "All %ss matching regular expression \"%s\":\n" + : "All defined %ss:\n", + classnames[class], + regexp); + + ALL_SYMTABS (objfile, s) + { + found_in_file = 0; + bv = BLOCKVECTOR (s); + /* Often many files share a blockvector. + Scan each blockvector only once so that + we don't get every symbol many times. + It happens that the first symtab in the list + for any given blockvector is the main file. */ + if (bv != prev_bv) + for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + /* Skip the sort if this block is always sorted. */ + if (!BLOCK_SHOULD_SORT (b)) + sort_block_syms (b); + for (j = 0; j < BLOCK_NSYMS (b); j++) + { + QUIT; + sym = BLOCK_SYM (b, j); + if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym)) + && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK + && SYMBOL_CLASS (sym) != LOC_CONST) + || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK))) + { + if (bpt) + { + /* Set a breakpoint here, if it's a function */ + if (class == 1) + { + /* There may be more than one function with the + same name but in different files. In order to + set breakpoints on all of them, we must give + both the file name and the function name to + break_command. */ + char *string = + (char *) alloca (strlen (s->filename) + + strlen (SYMBOL_NAME(sym)) + + 2); + strcpy (string, s->filename); + strcat (string, ":"); + strcat (string, SYMBOL_NAME(sym)); + break_command (string, 0); + } + } + else if (!found_in_file) + { + fputs_filtered ("\nFile ", stdout); + fputs_filtered (s->filename, stdout); + fputs_filtered (":\n", stdout); + } + found_in_file = 1; + + if (class != 2 && i == STATIC_BLOCK) + printf_filtered ("static "); + + /* Typedef that is not a C++ class */ + if (class == 2 + && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE) + c_typedef_print (SYMBOL_TYPE(sym), sym, stdout); + /* variable, func, or typedef-that-is-c++-class */ + else if (class < 2 || + (class == 2 && + SYMBOL_NAMESPACE(sym) == STRUCT_NAMESPACE)) + { + type_print (SYMBOL_TYPE (sym), + (SYMBOL_CLASS (sym) == LOC_TYPEDEF + ? "" : SYMBOL_SOURCE_NAME (sym)), + stdout, 0); + + printf_filtered (";\n"); + } + else + { +# if 0 /* FIXME, why is this zapped out? */ + char buf[1024]; + c_type_print_base (TYPE_FN_FIELD_TYPE(t, i), + stdout, 0, 0); + c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i), + stdout, 0); + sprintf (buf, " %s::", type_name_no_tag (t)); + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (t, i), + buf, name, stdout); +# endif + } + } + } + } + prev_bv = bv; + } + + /* If there are no eyes, avoid all contact. I mean, if there are + no debug symbols, then print directly from the msymbol_vector. */ + + if (found_misc || class != 1) + { + found_in_file = 0; + ALL_MSYMBOLS (objfile, msymbol) + { + if (MSYMBOL_TYPE (msymbol) == ourtype || + MSYMBOL_TYPE (msymbol) == ourtype2) + { + if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) + { + /* Functions: Look up by address. */ + if (class != 1 || + (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))) + { + /* Variables/Absolutes: Look up by name */ + if (lookup_symbol (SYMBOL_NAME (msymbol), + (struct block *) NULL, VAR_NAMESPACE, + 0, (struct symtab **) NULL) == NULL) + { + if (!found_in_file) + { + printf_filtered ("\nNon-debugging symbols:\n"); + found_in_file = 1; + } + printf_filtered (" %08lx %s\n", + (unsigned long) SYMBOL_VALUE_ADDRESS (msymbol), + SYMBOL_SOURCE_NAME (msymbol)); + } + } + } + } + } + } +} + +static void +variables_info (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 0, 0); +} + +static void +functions_info (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 1, 0); +} + +static void +types_info (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 2, 0); +} + +#if 0 +/* Tiemann says: "info methods was never implemented." */ +static void +methods_info (regexp) + char *regexp; +{ + list_symbols (regexp, 3, 0); +} +#endif /* 0 */ + +/* Breakpoint all functions matching regular expression. */ +static void +rbreak_command (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 1, 1); +} + + +/* Return Nonzero if block a is lexically nested within block b, + or if a and b have the same pc range. + Return zero otherwise. */ +int +contained_in (a, b) + struct block *a, *b; +{ + if (!a || !b) + return 0; + return BLOCK_START (a) >= BLOCK_START (b) + && BLOCK_END (a) <= BLOCK_END (b); +} + + +/* Helper routine for make_symbol_completion_list. */ + +static int return_val_size; +static int return_val_index; +static char **return_val; + +#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \ + do { \ + if (SYMBOL_DEMANGLED_NAME (symbol) != NULL) \ + /* Put only the mangled name on the list. */ \ + /* Advantage: "b foo" completes to "b foo(int, int)" */ \ + /* Disadvantage: "b foo__i" doesn't complete. */ \ + completion_list_add_name \ + (SYMBOL_DEMANGLED_NAME (symbol), (sym_text), (len), (text), (word)); \ + else \ + completion_list_add_name \ + (SYMBOL_NAME (symbol), (sym_text), (len), (text), (word)); \ + } while (0) + +/* Test to see if the symbol specified by SYMNAME (which is already + demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN + characters. If so, add it to the current completion list. */ + +static void +completion_list_add_name (symname, sym_text, sym_text_len, text, word) + char *symname; + char *sym_text; + int sym_text_len; + char *text; + char *word; +{ + int newsize; + int i; + + /* clip symbols that cannot match */ + + if (strncmp (symname, sym_text, sym_text_len) != 0) + { + return; + } + + /* Clip any symbol names that we've already considered. (This is a + time optimization) */ + + for (i = 0; i < return_val_index; ++i) + { + if (STREQ (symname, return_val[i])) + { + return; + } + } + + /* We have a match for a completion, so add SYMNAME to the current list + of matches. Note that the name is moved to freshly malloc'd space. */ + + { + char *new; + if (word == sym_text) + { + new = xmalloc (strlen (symname) + 5); + strcpy (new, symname); + } + else if (word > sym_text) + { + /* Return some portion of symname. */ + new = xmalloc (strlen (symname) + 5); + strcpy (new, symname + (word - sym_text)); + } + else + { + /* Return some of SYM_TEXT plus symname. */ + new = xmalloc (strlen (symname) + (sym_text - word) + 5); + strncpy (new, word, sym_text - word); + new[sym_text - word] = '\0'; + strcat (new, symname); + } + + if (return_val_index + 3 > return_val_size) + { + newsize = (return_val_size *= 2) * sizeof (char *); + return_val = (char **) xrealloc ((char *) return_val, newsize); + } + return_val[return_val_index++] = new; + return_val[return_val_index] = NULL; + } +} + +/* Return a NULL terminated array of all symbols (regardless of class) which + begin by matching TEXT. If the answer is no symbols, then the return value + is an array which contains only a NULL pointer. + + Problem: All of the symbols have to be copied because readline frees them. + I'm not going to worry about this; hopefully there won't be that many. */ + +char ** +make_symbol_completion_list (text, word) + char *text; + char *word; +{ + register struct symbol *sym; + register struct symtab *s; + register struct partial_symtab *ps; + register struct minimal_symbol *msymbol; + register struct objfile *objfile; + register struct block *b, *surrounding_static_block = 0; + register int i, j; + struct partial_symbol *psym; + /* The symbol we are completing on. Points in same buffer as text. */ + char *sym_text; + /* Length of sym_text. */ + int sym_text_len; + + /* Now look for the symbol we are supposed to complete on. + FIXME: This should be language-specific. */ + { + char *p; + char quote_found; + char *quote_pos = NULL; + + /* First see if this is a quoted string. */ + quote_found = '\0'; + for (p = text; *p != '\0'; ++p) + { + if (quote_found != '\0') + { + if (*p == quote_found) + /* Found close quote. */ + quote_found = '\0'; + else if (*p == '\\' && p[1] == quote_found) + /* A backslash followed by the quote character + doesn't end the string. */ + ++p; + } + else if (*p == '\'' || *p == '"') + { + quote_found = *p; + quote_pos = p; + } + } + if (quote_found == '\'') + /* A string within single quotes can be a symbol, so complete on it. */ + sym_text = quote_pos + 1; + else if (quote_found == '"') + /* A double-quoted string is never a symbol, nor does it make sense + to complete it any other way. */ + return NULL; + else + { + /* It is not a quoted string. Break it based on the characters + which are in symbols. */ + while (p > text) + { + if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0') + --p; + else + break; + } + sym_text = p; + } + } + + sym_text_len = strlen (sym_text); + + return_val_size = 100; + return_val_index = 0; + return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *)); + return_val[0] = NULL; + + /* Look through the partial symtabs for all symbols which begin + by matching SYM_TEXT. Add each one that you find to the list. */ + + ALL_PSYMTABS (objfile, ps) + { + /* If the psymtab's been read in we'll get it when we search + through the blockvector. */ + if (ps->readin) continue; + + for (psym = objfile->global_psymbols.list + ps->globals_offset; + psym < (objfile->global_psymbols.list + ps->globals_offset + + ps->n_global_syms); + psym++) + { + /* If interrupted, then quit. */ + QUIT; + COMPLETION_LIST_ADD_SYMBOL (psym, sym_text, sym_text_len, text, word); + } + + for (psym = objfile->static_psymbols.list + ps->statics_offset; + psym < (objfile->static_psymbols.list + ps->statics_offset + + ps->n_static_syms); + psym++) + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (psym, sym_text, sym_text_len, text, word); + } + } + + /* At this point scan through the misc symbol vectors and add each + symbol you find to the list. Eventually we want to ignore + anything that isn't a text symbol (everything else will be + handled by the psymtab code above). */ + + ALL_MSYMBOLS (objfile, msymbol) + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word); + } + + /* Search upwards from currently selected frame (so that we can + complete on local vars. */ + + for (b = get_selected_block (); b != NULL; b = BLOCK_SUPERBLOCK (b)) + { + if (!BLOCK_SUPERBLOCK (b)) + { + surrounding_static_block = b; /* For elmin of dups */ + } + + /* Also catch fields of types defined in this places which match our + text string. Only complete on types visible from current context. */ + + for (i = 0; i < BLOCK_NSYMS (b); i++) + { + sym = BLOCK_SYM (b, i); + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + struct type *t = SYMBOL_TYPE (sym); + enum type_code c = TYPE_CODE (t); + + if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT) + { + for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++) + { + if (TYPE_FIELD_NAME (t, j)) + { + completion_list_add_name (TYPE_FIELD_NAME (t, j), + sym_text, sym_text_len, text, word); + } + } + } + } + } + } + + /* Go through the symtabs and check the externs and statics for + symbols which match. */ + + ALL_SYMTABS (objfile, s) + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + for (i = 0; i < BLOCK_NSYMS (b); i++) + { + sym = BLOCK_SYM (b, i); + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + } + + ALL_SYMTABS (objfile, s) + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + /* Don't do this block twice. */ + if (b == surrounding_static_block) continue; + for (i = 0; i < BLOCK_NSYMS (b); i++) + { + sym = BLOCK_SYM (b, i); + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + } + + return (return_val); +} + + +#if 0 +/* Add the type of the symbol sym to the type of the current + function whose block we are in (assumed). The type of + this current function is contained in *TYPE. + + This basically works as follows: When we find a function + symbol (N_FUNC with a 'f' or 'F' in the symbol name), we record + a pointer to its type in the global in_function_type. Every + time we come across a parameter symbol ('p' in its name), then + this procedure adds the name and type of that parameter + to the function type pointed to by *TYPE. (Which should correspond + to in_function_type if it was called correctly). + + Note that since we are modifying a type, the result of + lookup_function_type() should be memcpy()ed before calling + this. When not in strict typing mode, the expression + evaluator can choose to ignore this. + + Assumption: All of a function's parameter symbols will + appear before another function symbol is found. The parameters + appear in the same order in the argument list as they do in the + symbol table. */ + +void +add_param_to_type (type,sym) + struct type **type; + struct symbol *sym; +{ + int num = ++(TYPE_NFIELDS(*type)); + + if(TYPE_NFIELDS(*type)-1) + TYPE_FIELDS(*type) = (struct field *) + (*current_objfile->xrealloc) ((char *)(TYPE_FIELDS(*type)), + num*sizeof(struct field)); + else + TYPE_FIELDS(*type) = (struct field *) + (*current_objfile->xmalloc) (num*sizeof(struct field)); + + TYPE_FIELD_BITPOS(*type,num-1) = num-1; + TYPE_FIELD_BITSIZE(*type,num-1) = 0; + TYPE_FIELD_TYPE(*type,num-1) = SYMBOL_TYPE(sym); + TYPE_FIELD_NAME(*type,num-1) = SYMBOL_NAME(sym); +} +#endif + +void +_initialize_symtab () +{ + add_info ("variables", variables_info, + "All global and static variable names, or those matching REGEXP."); + add_info ("functions", functions_info, + "All function names, or those matching REGEXP."); + + /* FIXME: This command has at least the following problems: + 1. It prints builtin types (in a very strange and confusing fashion). + 2. It doesn't print right, e.g. with + typedef struct foo *FOO + type_print prints "FOO" when we want to make it (in this situation) + print "struct foo *". + I also think "ptype" or "whatis" is more likely to be useful (but if + there is much disagreement "info types" can be fixed). */ + add_info ("types", types_info, + "All type names, or those matching REGEXP."); + +#if 0 + add_info ("methods", methods_info, + "All method names, or those matching REGEXP::REGEXP.\n\ +If the class qualifier is omitted, it is assumed to be the current scope.\n\ +If the first REGEXP is omitted, then all methods matching the second REGEXP\n\ +are listed."); +#endif + add_info ("sources", sources_info, + "Source files in the program."); + + add_com ("rbreak", no_class, rbreak_command, + "Set a breakpoint for all functions matching REGEXP."); + + /* Initialize the one built-in type that isn't language dependent... */ + builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0, + "", (struct objfile *) NULL); +} diff --git a/gnu/usr.bin/gdb/gdb/symtab.h b/gnu/usr.bin/gdb/gdb/symtab.h new file mode 100644 index 00000000000..9570b393adb --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/symtab.h @@ -0,0 +1,1124 @@ +/* Symbol table definitions for GDB. + Copyright (C) 1986, 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. */ + +#if !defined (SYMTAB_H) +#define SYMTAB_H 1 + +/* Some definitions and declarations to go with use of obstacks. */ + +#include "obstack.h" +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +/* Define a structure for the information that is common to all symbol types, + including minimal symbols, partial symbols, and full symbols. In a + multilanguage environment, some language specific information may need to + be recorded along with each symbol. */ + +struct general_symbol_info +{ + /* Name of the symbol. This is a required field. Storage for the name is + allocated on the psymbol_obstack or symbol_obstack for the associated + objfile. */ + + char *name; + + /* Value of the symbol. Which member of this union to use, and what + it means, depends on what kind of symbol this is and its + SYMBOL_CLASS. See comments there for more details. All of these + are in host byte order (though what they point to might be in + target byte order, e.g. LOC_CONST_BYTES). */ + + union + { + long value; + + struct block *block; + + char *bytes; + + CORE_ADDR address; + + /* for opaque typedef struct chain */ + + struct symbol *chain; + } + value; + + /* Record the source code language that applies to this symbol. + This is used to select one of the fields from the language specific + union below. */ + + enum language language; + + /* Since one and only one language can apply, wrap the language specific + information inside a union. */ + + union + { + struct cplus_specific /* For C++ */ + { + char *demangled_name; + } cplus_specific; + struct chill_specific /* For Chill */ + { + char *demangled_name; + } chill_specific; + } language_specific; + + /* Which section is this symbol in? This is an index into + section_offsets for this objfile. Negative means that the symbol + does not get relocated relative to a section. + Disclaimer: currently this is just used for xcoff, so don't + expect all symbol-reading code to set it correctly (the ELF code + also tries to set it correctly). */ + + int section; +}; + +#define SYMBOL_NAME(symbol) (symbol)->ginfo.name +#define SYMBOL_VALUE(symbol) (symbol)->ginfo.value.value +#define SYMBOL_VALUE_ADDRESS(symbol) (symbol)->ginfo.value.address +#define SYMBOL_VALUE_BYTES(symbol) (symbol)->ginfo.value.bytes +#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->ginfo.value.block +#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->ginfo.value.chain +#define SYMBOL_LANGUAGE(symbol) (symbol)->ginfo.language +#define SYMBOL_SECTION(symbol) (symbol)->ginfo.section + +#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \ + (symbol)->ginfo.language_specific.cplus_specific.demangled_name + + +extern int demangle; /* We reference it, so go ahead and declare it. */ + +/* Macro that initializes the language dependent portion of a symbol + depending upon the language for the symbol. */ + +#define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \ + do { \ + SYMBOL_LANGUAGE (symbol) = language; \ + if (SYMBOL_LANGUAGE (symbol) == language_cplus) \ + { \ + SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \ + } \ + else if (SYMBOL_LANGUAGE (symbol) == language_chill) \ + { \ + SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \ + } \ + else \ + { \ + memset (&(symbol)->ginfo.language_specific, 0, \ + sizeof ((symbol)->ginfo.language_specific)); \ + } \ + } while (0) + +/* Macro that attempts to initialize the demangled name for a symbol, + based on the language of that symbol. If the language is set to + language_auto, it will attempt to find any demangling algorithm + that works and then set the language appropriately. If no demangling + of any kind is found, the language is set back to language_unknown, + so we can avoid doing this work again the next time we encounter + the symbol. Any required space to store the name is obtained from the + specified obstack. */ + +#define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack) \ + do { \ + char *demangled = NULL; \ + if (SYMBOL_LANGUAGE (symbol) == language_cplus \ + || SYMBOL_LANGUAGE (symbol) == language_auto) \ + { \ + demangled = \ + cplus_demangle (SYMBOL_NAME (symbol), DMGL_PARAMS | DMGL_ANSI);\ + if (demangled != NULL) \ + { \ + SYMBOL_LANGUAGE (symbol) = language_cplus; \ + SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = \ + obsavestring (demangled, strlen (demangled), (obstack)); \ + free (demangled); \ + } \ + else \ + { \ + SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \ + } \ + } \ + if (demangled == NULL \ + && (SYMBOL_LANGUAGE (symbol) == language_chill \ + || SYMBOL_LANGUAGE (symbol) == language_auto)) \ + { \ + demangled = \ + chill_demangle (SYMBOL_NAME (symbol)); \ + if (demangled != NULL) \ + { \ + SYMBOL_LANGUAGE (symbol) = language_chill; \ + SYMBOL_CHILL_DEMANGLED_NAME (symbol) = \ + obsavestring (demangled, strlen (demangled), (obstack)); \ + free (demangled); \ + } \ + else \ + { \ + SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \ + } \ + } \ + if (SYMBOL_LANGUAGE (symbol) == language_auto) \ + { \ + SYMBOL_LANGUAGE (symbol) = language_unknown; \ + } \ + } while (0) + +/* Macro that returns the demangled name for a symbol based on the language + for that symbol. If no demangled name exists, returns NULL. */ + +#define SYMBOL_DEMANGLED_NAME(symbol) \ + (SYMBOL_LANGUAGE (symbol) == language_cplus \ + ? SYMBOL_CPLUS_DEMANGLED_NAME (symbol) \ + : (SYMBOL_LANGUAGE (symbol) == language_chill \ + ? SYMBOL_CHILL_DEMANGLED_NAME (symbol) \ + : NULL)) + +#define SYMBOL_CHILL_DEMANGLED_NAME(symbol) \ + (symbol)->ginfo.language_specific.chill_specific.demangled_name + +/* Macro that returns the "natural source name" of a symbol. In C++ this is + the "demangled" form of the name if demangle is on and the "mangled" form + of the name if demangle is off. In other languages this is just the + symbol name. The result should never be NULL. */ + +#define SYMBOL_SOURCE_NAME(symbol) \ + (demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + ? SYMBOL_DEMANGLED_NAME (symbol) \ + : SYMBOL_NAME (symbol)) + +/* Macro that returns the "natural assembly name" of a symbol. In C++ this is + the "mangled" form of the name if demangle is off, or if demangle is on and + asm_demangle is off. Otherwise if asm_demangle is on it is the "demangled" + form. In other languages this is just the symbol name. The result should + never be NULL. */ + +#define SYMBOL_LINKAGE_NAME(symbol) \ + (demangle && asm_demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + ? SYMBOL_DEMANGLED_NAME (symbol) \ + : SYMBOL_NAME (symbol)) + +/* From utils.c. */ +extern int demangle; +extern int asm_demangle; + +/* Macro that tests a symbol for a match against a specified name string. + First test the unencoded name, then looks for and test a C++ encoded + name if it exists. Note that whitespace is ignored while attempting to + match a C++ encoded name, so that "foo::bar(int,long)" is the same as + "foo :: bar (int, long)". + Evaluates to zero if the match fails, or nonzero if it succeeds. */ + +#define SYMBOL_MATCHES_NAME(symbol, name) \ + (STREQ (SYMBOL_NAME (symbol), (name)) \ + || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + && strcmp_iw (SYMBOL_DEMANGLED_NAME (symbol), (name)) == 0)) + +/* Macro that tests a symbol for an re-match against the last compiled regular + expression. First test the unencoded name, then look for and test a C++ + encoded name if it exists. + Evaluates to zero if the match fails, or nonzero if it succeeds. */ + +#define SYMBOL_MATCHES_REGEXP(symbol) \ + (re_exec (SYMBOL_NAME (symbol)) != 0 \ + || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + && re_exec (SYMBOL_DEMANGLED_NAME (symbol)) != 0)) + +/* Define a simple structure used to hold some very basic information about + all defined global symbols (text, data, bss, abs, etc). The only required + information is the general_symbol_info. + + In many cases, even if a file was compiled with no special options for + debugging at all, as long as was not stripped it will contain sufficient + information to build a useful minimal symbol table using this structure. + Even when a file contains enough debugging information to build a full + symbol table, these minimal symbols are still useful for quickly mapping + between names and addresses, and vice versa. They are also sometimes + used to figure out what full symbol table entries need to be read in. */ + +struct minimal_symbol +{ + + /* The general symbol info required for all types of symbols. + + The SYMBOL_VALUE_ADDRESS contains the address that this symbol + corresponds to. */ + + struct general_symbol_info ginfo; + + /* The info field is available for caching machine-specific information that + The AMD 29000 tdep.c uses it to remember things it has decoded from the + instructions in the function header, so it doesn't have to rederive the + info constantly (over a serial line). It is initialized to zero and + stays that way until target-dependent code sets it. Storage for any data + pointed to by this field should be allocated on the symbol_obstack for + the associated objfile. The type would be "void *" except for reasons + of compatibility with older compilers. This field is optional. */ + + char *info; + + /* Classification types for this symbol. These should be taken as "advisory + only", since if gdb can't easily figure out a classification it simply + selects mst_unknown. It may also have to guess when it can't figure out + which is a better match between two types (mst_data versus mst_bss) for + example. Since the minimal symbol info is sometimes derived from the + BFD library's view of a file, we need to live with what information bfd + supplies. */ + + enum minimal_symbol_type + { + mst_unknown = 0, /* Unknown type, the default */ + mst_text, /* Generally executable instructions */ + mst_data, /* Generally initialized data */ + mst_bss, /* Generally uninitialized data */ + mst_abs, /* Generally absolute (nonrelocatable) */ + /* For the mst_file* types, the names are only guaranteed to be unique + within a given .o file. */ + mst_file_text, /* Static version of mst_text */ + mst_file_data, /* Static version of mst_data */ + mst_file_bss /* Static version of mst_bss */ + } type; + +}; + +#define MSYMBOL_INFO(msymbol) (msymbol)->info +#define MSYMBOL_TYPE(msymbol) (msymbol)->type + + +/* All of the name-scope contours of the program + are represented by `struct block' objects. + All of these objects are pointed to by the blockvector. + + Each block represents one name scope. + Each lexical context has its own block. + + The blockvector begins with some special blocks. + The GLOBAL_BLOCK contains all the symbols defined in this compilation + whose scope is the entire program linked together. + The STATIC_BLOCK contains all the symbols whose scope is the + entire compilation excluding other separate compilations. + Blocks starting with the FIRST_LOCAL_BLOCK are not special. + + Each block records a range of core addresses for the code that + is in the scope of the block. The STATIC_BLOCK and GLOBAL_BLOCK + give, for the range of code, the entire range of code produced + by the compilation that the symbol segment belongs to. + + The blocks appear in the blockvector + in order of increasing starting-address, + and, within that, in order of decreasing ending-address. + + This implies that within the body of one function + the blocks appear in the order of a depth-first tree walk. */ + +struct blockvector +{ + /* Number of blocks in the list. */ + int nblocks; + /* The blocks themselves. */ + struct block *block[1]; +}; + +#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks +#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n] + +/* Special block numbers */ + +#define GLOBAL_BLOCK 0 +#define STATIC_BLOCK 1 +#define FIRST_LOCAL_BLOCK 2 + +struct block +{ + + /* Addresses in the executable code that are in this block. */ + + CORE_ADDR startaddr; + CORE_ADDR endaddr; + + /* The symbol that names this block, if the block is the body of a + function; otherwise, zero. */ + + struct symbol *function; + + /* The `struct block' for the containing block, or 0 if none. + + The superblock of a top-level local block (i.e. a function in the + case of C) is the STATIC_BLOCK. The superblock of the + STATIC_BLOCK is the GLOBAL_BLOCK. */ + + struct block *superblock; + + /* Version of GCC used to compile the function corresponding + to this block, or 0 if not compiled with GCC. When possible, + GCC should be compatible with the native compiler, or if that + is not feasible, the differences should be fixed during symbol + reading. As of 16 Apr 93, this flag is never used to distinguish + between gcc2 and the native compiler. + + If there is no function corresponding to this block, this meaning + of this flag is undefined. */ + + unsigned char gcc_compile_flag; + + /* Number of local symbols. */ + + int nsyms; + + /* The symbols. If some of them are arguments, then they must be + in the order in which we would like to print them. */ + + struct symbol *sym[1]; +}; + +#define BLOCK_START(bl) (bl)->startaddr +#define BLOCK_END(bl) (bl)->endaddr +#define BLOCK_NSYMS(bl) (bl)->nsyms +#define BLOCK_SYM(bl, n) (bl)->sym[n] +#define BLOCK_FUNCTION(bl) (bl)->function +#define BLOCK_SUPERBLOCK(bl) (bl)->superblock +#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag + +/* Nonzero if symbols of block BL should be sorted alphabetically. + Don't sort a block which corresponds to a function. If we did the + sorting would have to preserve the order of the symbols for the + arguments. */ + +#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40 && BLOCK_FUNCTION (bl) == NULL) + + +/* Represent one symbol name; a variable, constant, function or typedef. */ + +/* Different name spaces for symbols. Looking up a symbol specifies a + namespace and ignores symbol definitions in other name spaces. */ + +enum namespace +{ + /* UNDEF_NAMESPACE is used when a namespace has not been discovered or + none of the following apply. This usually indicates an error either + in the symbol information or in gdb's handling of symbols. */ + + UNDEF_NAMESPACE, + + /* VAR_NAMESPACE is the usual namespace. In C, this contains variables, + function names, typedef names and enum type values. */ + + VAR_NAMESPACE, + + /* STRUCT_NAMESPACE is used in C to hold struct, union and enum type names. + Thus, if `struct foo' is used in a C program, it produces a symbol named + `foo' in the STRUCT_NAMESPACE. */ + + STRUCT_NAMESPACE, + + /* LABEL_NAMESPACE may be used for names of labels (for gotos); + currently it is not used and labels are not recorded at all. */ + + LABEL_NAMESPACE +}; + +/* An address-class says where to find the value of a symbol. */ + +enum address_class +{ + /* Not used; catches errors */ + + LOC_UNDEF, + + /* Value is constant int SYMBOL_VALUE, host byteorder */ + + LOC_CONST, + + /* Value is at fixed address SYMBOL_VALUE_ADDRESS */ + + LOC_STATIC, + + /* Value is in register. SYMBOL_VALUE is the register number. */ + + LOC_REGISTER, + + /* It's an argument; the value is at SYMBOL_VALUE offset in arglist. */ + + LOC_ARG, + + /* Value address is at SYMBOL_VALUE offset in arglist. */ + + LOC_REF_ARG, + + /* Value is in register number SYMBOL_VALUE. Just like LOC_REGISTER + except this is an argument. Probably the cleaner way to handle + this would be to separate address_class (which would include + separate ARG and LOCAL to deal with FRAME_ARGS_ADDRESS versus + FRAME_LOCALS_ADDRESS), and an is_argument flag. + + For some symbol formats (stabs, for some compilers at least), + the compiler generates two symbols, an argument and a register. + In some cases we combine them to a single LOC_REGPARM in symbol + reading, but currently not for all cases (e.g. it's passed on the + stack and then loaded into a register). */ + + LOC_REGPARM, + + /* Value is in specified register. Just like LOC_REGPARM except the + register holds the address of the argument instead of the argument + itself. This is currently used for the passing of structs and unions + on sparc and hppa. It is also used for call by reference where the + address is in a register, at least by mipsread.c. */ + + LOC_REGPARM_ADDR, + + /* Value is a local variable at SYMBOL_VALUE offset in stack frame. */ + + LOC_LOCAL, + + /* Value not used; definition in SYMBOL_TYPE. Symbols in the namespace + STRUCT_NAMESPACE all have this class. */ + + LOC_TYPEDEF, + + /* Value is address SYMBOL_VALUE_ADDRESS in the code */ + + LOC_LABEL, + + /* In a symbol table, value is SYMBOL_BLOCK_VALUE of a `struct block'. + In a partial symbol table, SYMBOL_VALUE_ADDRESS is the start address + of the block. Function names have this class. */ + + LOC_BLOCK, + + /* Value is a constant byte-sequence pointed to by SYMBOL_VALUE_BYTES, in + target byte order. */ + + LOC_CONST_BYTES, + + /* Value is arg at SYMBOL_VALUE offset in stack frame. Differs from + LOC_LOCAL in that symbol is an argument; differs from LOC_ARG in + that we find it in the frame (FRAME_LOCALS_ADDRESS), not in the + arglist (FRAME_ARGS_ADDRESS). Added for i960, which passes args + in regs then copies to frame. */ + + LOC_LOCAL_ARG, + + /* Value is at SYMBOL_VALUE offset from the current value of + register number SYMBOL_BASEREG. This exists mainly for the same + things that LOC_LOCAL and LOC_ARG do; but we need to do this + instead because on 88k DWARF gives us the offset from the + frame/stack pointer, rather than the offset from the "canonical + frame address" used by COFF, stabs, etc., and we don't know how + to convert between these until we start examining prologues. + + Note that LOC_BASEREG is much less general than a DWARF expression. + We don't need the generality (at least not yet), and storing a general + DWARF expression would presumably take up more space than the existing + scheme. */ + + LOC_BASEREG, + + /* Same as LOC_BASEREG but it is an argument. */ + + LOC_BASEREG_ARG, + + /* The variable does not actually exist in the program. + The value is ignored. */ + + LOC_OPTIMIZED_OUT +}; + +struct symbol +{ + + /* The general symbol info required for all types of symbols. */ + + struct general_symbol_info ginfo; + + /* Name space code. */ + + enum namespace namespace; + + /* Address class */ + + enum address_class class; + + /* Data type of value */ + + struct type *type; + + /* Line number of definition. FIXME: Should we really make the assumption + that nobody will try to debug files longer than 64K lines? What about + machine generated programs? */ + + unsigned short line; + + /* Some symbols require an additional value to be recorded on a per- + symbol basis. Stash those values here. */ + + union + { + /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */ + short basereg; + } + aux_value; + +}; + +#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace +#define SYMBOL_CLASS(symbol) (symbol)->class +#define SYMBOL_TYPE(symbol) (symbol)->type +#define SYMBOL_LINE(symbol) (symbol)->line +#define SYMBOL_BASEREG(symbol) (symbol)->aux_value.basereg + +/* A partial_symbol records the name, namespace, and address class of + symbols whose types we have not parsed yet. For functions, it also + contains their memory address, so we can find them from a PC value. + Each partial_symbol sits in a partial_symtab, all of which are chained + on a partial symtab list and which points to the corresponding + normal symtab once the partial_symtab has been referenced. */ + +struct partial_symbol +{ + + /* The general symbol info required for all types of symbols. */ + + struct general_symbol_info ginfo; + + /* Name space code. */ + + enum namespace namespace; + + /* Address class (for info_symbols) */ + + enum address_class class; + +}; + +#define PSYMBOL_NAMESPACE(psymbol) (psymbol)->namespace +#define PSYMBOL_CLASS(psymbol) (psymbol)->class + + +/* Source-file information. This describes the relation between source files, + ine numbers and addresses in the program text. */ + +struct sourcevector +{ + int length; /* Number of source files described */ + struct source *source[1]; /* Descriptions of the files */ +}; + +/* Each item represents a line-->pc (or the reverse) mapping. This is + somewhat more wasteful of space than one might wish, but since only + the files which are actually debugged are read in to core, we don't + waste much space. */ + +struct linetable_entry +{ + int line; + CORE_ADDR pc; +}; + +/* The order of entries in the linetable is significant. They should + be sorted by increasing values of the pc field. If there is more than + one entry for a given pc, then I'm not sure what should happen (and + I not sure whether we currently handle it the best way). + + Example: a C for statement generally looks like this + + 10 0x100 - for the init/test part of a for stmt. + 20 0x200 + 30 0x300 + 10 0x400 - for the increment part of a for stmt. + + */ + +struct linetable +{ + int nitems; + + /* Actually NITEMS elements. If you don't like this use of the + `struct hack', you can shove it up your ANSI (seriously, if the + committee tells us how to do it, we can probably go along). */ + struct linetable_entry item[1]; +}; + +/* All the information on one source file. */ + +struct source +{ + char *name; /* Name of file */ + struct linetable contents; +}; + +/* How to relocate the symbols from each section in a symbol file. + Each struct contains an array of offsets. + The ordering and meaning of the offsets is file-type-dependent; + typically it is indexed by section numbers or symbol types or + something like that. + + To give us flexibility in changing the internal representation + of these offsets, the ANOFFSET macro must be used to insert and + extract offset values in the struct. */ + +struct section_offsets + { + CORE_ADDR offsets[1]; /* As many as needed. */ + }; + +#define ANOFFSET(secoff, whichone) (secoff->offsets[whichone]) + +/* Each source file or header is represented by a struct symtab. + These objects are chained through the `next' field. */ + +struct symtab + { + + /* Chain of all existing symtabs. */ + + struct symtab *next; + + /* List of all symbol scope blocks for this symtab. May be shared + between different symtabs (and normally is for all the symtabs + in a given compilation unit). */ + + struct blockvector *blockvector; + + /* Table mapping core addresses to line numbers for this file. + Can be NULL if none. Never shared between different symtabs. */ + + struct linetable *linetable; + + /* Section in objfile->section_offsets for the blockvector and + the linetable. */ + + int block_line_section; + + /* If several symtabs share a blockvector, exactly one of them + should be designed the primary, so that the blockvector + is relocated exactly once by objfile_relocate. */ + + int primary; + + /* Name of this source file. */ + + char *filename; + + /* Directory in which it was compiled, or NULL if we don't know. */ + + char *dirname; + + /* This component says how to free the data we point to: + free_contents => do a tree walk and free each object. + free_nothing => do nothing; some other symtab will free + the data this one uses. + free_linetable => free just the linetable. FIXME: Is this redundant + with the primary field? */ + + enum free_code + { + free_nothing, free_contents, free_linetable + } + free_code; + + /* Pointer to one block of storage to be freed, if nonzero. */ + /* This is IN ADDITION to the action indicated by free_code. */ + + char *free_ptr; + + /* Total number of lines found in source file. */ + + int nlines; + + /* line_charpos[N] is the position of the (N-1)th line of the + source file. "position" means something we can lseek() to; it + is not guaranteed to be useful any other way. */ + + int *line_charpos; + + /* Language of this source file. */ + + enum language language; + + /* String of version information. May be zero. */ + + char *version; + + /* Full name of file as found by searching the source path. + NULL if not yet known. */ + + char *fullname; + + /* Object file from which this symbol information was read. */ + + struct objfile *objfile; + + /* Anything extra for this symtab. This is for target machines + with special debugging info of some sort (which cannot just + be represented in a normal symtab). */ + +#if defined (EXTRA_SYMTAB_INFO) + EXTRA_SYMTAB_INFO +#endif + + }; + +#define BLOCKVECTOR(symtab) (symtab)->blockvector +#define LINETABLE(symtab) (symtab)->linetable + + +/* Each source file that has not been fully read in is represented by + a partial_symtab. This contains the information on where in the + executable the debugging symbols for a specific file are, and a + list of names of global symbols which are located in this file. + They are all chained on partial symtab lists. + + Even after the source file has been read into a symtab, the + partial_symtab remains around. They are allocated on an obstack, + psymbol_obstack. FIXME, this is bad for dynamic linking or VxWorks- + style execution of a bunch of .o's. */ + +struct partial_symtab +{ + + /* Chain of all existing partial symtabs. */ + + struct partial_symtab *next; + + /* Name of the source file which this partial_symtab defines */ + + char *filename; + + /* Information about the object file from which symbols should be read. */ + + struct objfile *objfile; + + /* Set of relocation offsets to apply to each section. */ + + struct section_offsets *section_offsets; + + /* Range of text addresses covered by this file; texthigh is the + beginning of the next section. */ + + CORE_ADDR textlow; + CORE_ADDR texthigh; + + /* Array of pointers to all of the partial_symtab's which this one + depends on. Since this array can only be set to previous or + the current (?) psymtab, this dependency tree is guaranteed not + to have any loops. "depends on" means that symbols must be read + for the dependencies before being read for this psymtab; this is + for type references in stabs, where if foo.c includes foo.h, declarations + in foo.h may use type numbers defined in foo.c. For other debugging + formats there may be no need to use dependencies. */ + + struct partial_symtab **dependencies; + + int number_of_dependencies; + + /* Global symbol list. This list will be sorted after readin to + improve access. Binary search will be the usual method of + finding a symbol within it. globals_offset is an integer offset + within global_psymbols[]. */ + + int globals_offset; + int n_global_syms; + + /* Static symbol list. This list will *not* be sorted after readin; + to find a symbol in it, exhaustive search must be used. This is + reasonable because searches through this list will eventually + lead to either the read in of a files symbols for real (assumed + to take a *lot* of time; check) or an error (and we don't care + how long errors take). This is an offset and size within + static_psymbols[]. */ + + int statics_offset; + int n_static_syms; + + /* Pointer to symtab eventually allocated for this source file, 0 if + !readin or if we haven't looked for the symtab after it was readin. */ + + struct symtab *symtab; + + /* Pointer to function which will read in the symtab corresponding to + this psymtab. */ + + void (*read_symtab) PARAMS ((struct partial_symtab *)); + + /* Information that lets read_symtab() locate the part of the symbol table + that this psymtab corresponds to. This information is private to the + format-dependent symbol reading routines. For further detail examine + the various symbol reading modules. Should really be (void *) but is + (char *) as with other such gdb variables. (FIXME) */ + + char *read_symtab_private; + + /* Non-zero if the symtab corresponding to this psymtab has been readin */ + + unsigned char readin; +}; + +/* A fast way to get from a psymtab to its symtab (after the first time). */ +#define PSYMTAB_TO_SYMTAB(pst) \ + ((pst) -> symtab != NULL ? (pst) -> symtab : psymtab_to_symtab (pst)) + + +/* The virtual function table is now an array of structures which have the + form { int16 offset, delta; void *pfn; }. + + In normal virtual function tables, OFFSET is unused. + DELTA is the amount which is added to the apparent object's base + address in order to point to the actual object to which the + virtual function should be applied. + PFN is a pointer to the virtual function. + + Note that this macro is g++ specific (FIXME). */ + +#define VTBL_FNADDR_OFFSET 2 + +/* Macro that yields non-zero value iff NAME is the prefix for C++ operator + names. If you leave out the parenthesis here you will lose! + Currently 'o' 'p' CPLUS_MARKER is used for both the symbol in the + symbol-file and the names in gdb's symbol table. + Note that this macro is g++ specific (FIXME). */ + +#define OPNAME_PREFIX_P(NAME) \ + ((NAME)[0] == 'o' && (NAME)[1] == 'p' && (NAME)[2] == CPLUS_MARKER) + +/* Macro that yields non-zero value iff NAME is the prefix for C++ vtbl + names. Note that this macro is g++ specific (FIXME). */ + +#define VTBL_PREFIX_P(NAME) \ + ((NAME)[3] == CPLUS_MARKER && !strncmp ((NAME), "_vt", 3)) + +/* Macro that yields non-zero value iff NAME is the prefix for C++ destructor + names. Note that this macro is g++ specific (FIXME). */ + +#define DESTRUCTOR_PREFIX_P(NAME) \ + ((NAME)[0] == '_' && (NAME)[1] == CPLUS_MARKER && (NAME)[2] == '_') + + +/* External variables and functions for the objects described above. */ + +/* This symtab variable specifies the current file for printing source lines */ + +extern struct symtab *current_source_symtab; + +/* This is the next line to print for listing source lines. */ + +extern int current_source_line; + +/* See the comment in symfile.c about how current_objfile is used. */ + +extern struct objfile *current_objfile; + +extern struct symtab * +lookup_symtab PARAMS ((char *)); + +extern struct symbol * +lookup_symbol PARAMS ((const char *, const struct block *, + const enum namespace, int *, struct symtab **)); + +extern struct symbol * +lookup_block_symbol PARAMS ((const struct block *, const char *, + const enum namespace)); + +extern struct type * +lookup_struct PARAMS ((char *, struct block *)); + +extern struct type * +lookup_union PARAMS ((char *, struct block *)); + +extern struct type * +lookup_enum PARAMS ((char *, struct block *)); + +extern struct symbol * +block_function PARAMS ((struct block *)); + +extern struct symbol * +find_pc_function PARAMS ((CORE_ADDR)); + +extern int find_pc_partial_function + PARAMS ((CORE_ADDR, char **, CORE_ADDR *, CORE_ADDR *)); + +extern void +clear_pc_function_cache PARAMS ((void)); + +extern struct partial_symtab * +lookup_partial_symtab PARAMS ((char *)); + +extern struct partial_symtab * +find_pc_psymtab PARAMS ((CORE_ADDR)); + +extern struct symtab * +find_pc_symtab PARAMS ((CORE_ADDR)); + +extern struct partial_symbol * +find_pc_psymbol PARAMS ((struct partial_symtab *, CORE_ADDR)); + +extern int +find_pc_line_pc_range PARAMS ((CORE_ADDR, CORE_ADDR *, CORE_ADDR *)); + +extern int +contained_in PARAMS ((struct block *, struct block *)); + +extern void +reread_symbols PARAMS ((void)); + +/* Functions for dealing with the minimal symbol table, really a misc + address<->symbol mapping for things we don't have debug symbols for. */ + +extern void +prim_record_minimal_symbol PARAMS ((const char *, CORE_ADDR, + enum minimal_symbol_type)); + +extern void +prim_record_minimal_symbol_and_info PARAMS ((const char *, CORE_ADDR, + enum minimal_symbol_type, + char *info, int section)); + +extern struct minimal_symbol * +lookup_minimal_symbol PARAMS ((const char *, struct objfile *)); + +extern struct minimal_symbol * +lookup_minimal_symbol_by_pc PARAMS ((CORE_ADDR)); + +extern void +init_minimal_symbol_collection PARAMS ((void)); + +extern void +discard_minimal_symbols PARAMS ((int)); + +extern void +install_minimal_symbols PARAMS ((struct objfile *)); + +struct symtab_and_line +{ + struct symtab *symtab; + + /* Line number. Line numbers start at 1 and proceed through symtab->nlines. + 0 is never a valid line number; it is used to indicate that line number + information is not available. */ + int line; + + CORE_ADDR pc; + CORE_ADDR end; +}; + +struct symtabs_and_lines +{ + struct symtab_and_line *sals; + int nelts; +}; + +/* Given a pc value, return line number it is in. Second arg nonzero means + if pc is on the boundary use the previous statement's line number. */ + +extern struct symtab_and_line +find_pc_line PARAMS ((CORE_ADDR, int)); + +/* Given a symtab and line number, return the pc there. */ + +extern CORE_ADDR +find_line_pc PARAMS ((struct symtab *, int)); + +extern int +find_line_pc_range PARAMS ((struct symtab *, int, CORE_ADDR *, CORE_ADDR *)); + +extern void +resolve_sal_pc PARAMS ((struct symtab_and_line *)); + +/* Given a string, return the line specified by it. For commands like "list" + and "breakpoint". */ + +extern struct symtabs_and_lines +decode_line_spec PARAMS ((char *, int)); + +extern struct symtabs_and_lines +decode_line_spec_1 PARAMS ((char *, int)); + +extern struct symtabs_and_lines +decode_line_1 PARAMS ((char **, int, struct symtab *, int, char ***)); + +/* Symmisc.c */ + +#if MAINTENANCE_CMDS + +void +maintenance_print_symbols PARAMS ((char *, int)); + +void +maintenance_print_psymbols PARAMS ((char *, int)); + +void +maintenance_print_msymbols PARAMS ((char *, int)); + +void +maintenance_print_objfiles PARAMS ((char *, int)); + +#endif + +extern void +free_symtab PARAMS ((struct symtab *)); + +/* Symbol-reading stuff in symfile.c and solib.c. */ + +extern struct symtab * +psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +extern void +clear_solib PARAMS ((void)); + +extern struct objfile * +symbol_file_add PARAMS ((char *, int, CORE_ADDR, int, int, int)); + +/* source.c */ + +extern int frame_file_full_name; /* in stack.c */ + +extern int +identify_source_line PARAMS ((struct symtab *, int, int, CORE_ADDR)); + +extern void +print_source_lines PARAMS ((struct symtab *, int, int, int)); + +extern void +forget_cached_source_info PARAMS ((void)); + +extern void +select_source_symtab PARAMS ((struct symtab *)); + +extern char **make_symbol_completion_list PARAMS ((char *, char *)); + +/* symtab.c */ + +extern struct partial_symtab * +find_main_psymtab PARAMS ((void)); + +/* blockframe.c */ + +extern struct blockvector * +blockvector_for_pc PARAMS ((CORE_ADDR, int *)); + +/* symfile.c */ + +extern void +clear_symtab_users PARAMS ((void)); + +extern enum language +deduce_language_from_filename PARAMS ((char *)); + +#endif /* !defined(SYMTAB_H) */ diff --git a/gnu/usr.bin/gdb/gdb/target.c b/gnu/usr.bin/gdb/gdb/target.c new file mode 100644 index 00000000000..ea1bd93ca3b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/target.c @@ -0,0 +1,789 @@ +/* Select target systems and architectures at runtime for GDB. + Copyright 1990, 1992, 1993 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +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. */ + +#include "defs.h" +#include +#include +#include "target.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" + +extern int errno; + +static void +target_info PARAMS ((char *, int)); + +static void +cleanup_target PARAMS ((struct target_ops *)); + +static void +maybe_kill_then_create_inferior PARAMS ((char *, char *, char **)); + +static void +maybe_kill_then_attach PARAMS ((char *, int)); + +static void +kill_or_be_killed PARAMS ((int)); + +static void +default_terminal_info PARAMS ((char *, int)); + +static int +nosymbol PARAMS ((char *, CORE_ADDR *)); + +static void +tcomplain PARAMS ((void)); + +static int +nomemory PARAMS ((CORE_ADDR, char *, int, int)); + +static int +return_zero PARAMS ((void)); + +static void +ignore PARAMS ((void)); + +static void +target_command PARAMS ((char *, int)); + +static struct target_ops * +find_default_run_target PARAMS ((char *)); + +/* Pointer to array of target architecture structures; the size of the + array; the current index into the array; the allocated size of the + array. */ +struct target_ops **target_structs; +unsigned target_struct_size; +unsigned target_struct_index; +unsigned target_struct_allocsize; +#define DEFAULT_ALLOCSIZE 10 + +/* The initial current target, so that there is always a semi-valid + current target. */ + +struct target_ops dummy_target = {"None", "None", "", + 0, 0, /* open, close */ + find_default_attach, 0, /* attach, detach */ + 0, 0, /* resume, wait */ + 0, 0, 0, /* registers */ + 0, 0, /* memory */ + 0, 0, /* bkpts */ + 0, 0, 0, 0, 0, /* terminal */ + 0, 0, /* kill, load */ + 0, /* lookup_symbol */ + find_default_create_inferior, /* create_inferior */ + 0, /* mourn_inferior */ + 0, /* can_run */ + 0, /* notice_signals */ + dummy_stratum, 0, /* stratum, next */ + 0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + 0, 0, /* section pointers */ + OPS_MAGIC, +}; + +/* The target structure we are currently using to talk to a process + or file or whatever "inferior" we have. */ + +struct target_ops *current_target; + +/* The stack of target structures that have been pushed. */ + +struct target_ops **current_target_stack; + +/* Command list for target. */ + +static struct cmd_list_element *targetlist = NULL; + +/* The user just typed 'target' without the name of a target. */ + +/* ARGSUSED */ +static void +target_command (arg, from_tty) + char *arg; + int from_tty; +{ + fputs_filtered ("Argument required (target name). Try `help target'\n", + stdout); +} + +/* Add a possible target architecture to the list. */ + +void +add_target (t) + struct target_ops *t; +{ + if (t->to_magic != OPS_MAGIC) + { + fprintf(stderr, "Magic number of %s target struct wrong\n", + t->to_shortname); + abort(); + } + + if (!target_structs) + { + target_struct_allocsize = DEFAULT_ALLOCSIZE; + target_structs = (struct target_ops **) xmalloc + (target_struct_allocsize * sizeof (*target_structs)); + } + if (target_struct_size >= target_struct_allocsize) + { + target_struct_allocsize *= 2; + target_structs = (struct target_ops **) + xrealloc ((char *) target_structs, + target_struct_allocsize * sizeof (*target_structs)); + } + target_structs[target_struct_size++] = t; + cleanup_target (t); + + if (targetlist == NULL) + add_prefix_cmd ("target", class_run, target_command, + "Connect to a target machine or process.\n\ +The first argument is the type or protocol of the target machine.\n\ +Remaining arguments are interpreted by the target protocol. For more\n\ +information on the arguments for a particular protocol, type\n\ +`help target ' followed by the protocol name.", + &targetlist, "target ", 0, &cmdlist); + add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist); +} + +/* Stub functions */ + +static void +ignore () +{ +} + +/* ARGSUSED */ +static int +nomemory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + errno = EIO; /* Can't read/write this location */ + return 0; /* No bytes handled */ +} + +static void +tcomplain () +{ + error ("You can't do that when your target is `%s'", + current_target->to_shortname); +} + +void +noprocess () +{ + error ("You can't do that without a process to debug"); +} + +/* ARGSUSED */ +static int +nosymbol (name, addrp) + char *name; + CORE_ADDR *addrp; +{ + return 1; /* Symbol does not exist in target env */ +} + +/* ARGSUSED */ +static void +default_terminal_info (args, from_tty) + char *args; + int from_tty; +{ + printf("No saved terminal information.\n"); +} + +#if 0 +/* With strata, this function is no longer needed. FIXME. */ +/* This is the default target_create_inferior function. It looks up + the stack for some target that cares to create inferiors, then + calls it -- or complains if not found. */ + +static void +upstack_create_inferior (exec, args, env) + char *exec; + char *args; + char **env; +{ + struct target_ops *t; + + for (t = current_target; + t; + t = t->to_next) + { + if (t->to_create_inferior != upstack_create_inferior) + { + t->to_create_inferior (exec, args, env); + return; + } + + } + tcomplain(); +} +#endif + +/* This is the default target_create_inferior and target_attach function. + If the current target is executing, it asks whether to kill it off. + If this function returns without calling error(), it has killed off + the target, and the operation should be attempted. */ + +static void +kill_or_be_killed (from_tty) + int from_tty; +{ + if (target_has_execution) + { + printf ("You are already running a program:\n"); + target_files_info (); + if (query ("Kill it? ")) { + target_kill (); + if (target_has_execution) + error ("Killing the program did not help."); + return; + } else { + error ("Program not killed."); + } + } + tcomplain(); +} + +static void +maybe_kill_then_attach (args, from_tty) + char *args; + int from_tty; +{ + kill_or_be_killed (from_tty); + target_attach (args, from_tty); +} + +static void +maybe_kill_then_create_inferior (exec, args, env) + char *exec; + char *args; + char **env; +{ + kill_or_be_killed (0); + target_create_inferior (exec, args, env); +} + +/* Clean up a target struct so it no longer has any zero pointers in it. + We default entries, at least to stubs that print error messages. */ + +static void +cleanup_target (t) + struct target_ops *t; +{ + + /* Check magic number. If wrong, it probably means someone changed + the struct definition, but not all the places that initialize one. */ + if (t->to_magic != OPS_MAGIC) + { + fprintf(stderr, "Magic number of %s target struct wrong\n", + t->to_shortname); + abort(); + } + +#define de_fault(field, value) \ + if (!t->field) t->field = value + + /* FIELD DEFAULT VALUE */ + + de_fault (to_open, (void (*)())tcomplain); + de_fault (to_close, (void (*)())ignore); + de_fault (to_attach, maybe_kill_then_attach); + de_fault (to_detach, (void (*)())ignore); + de_fault (to_resume, (void (*)())noprocess); + de_fault (to_wait, (int (*)())noprocess); + de_fault (to_fetch_registers, (void (*)())ignore); + de_fault (to_store_registers, (void (*)())noprocess); + de_fault (to_prepare_to_store, (void (*)())noprocess); + de_fault (to_xfer_memory, (int (*)())nomemory); + de_fault (to_files_info, (void (*)())ignore); + de_fault (to_insert_breakpoint, memory_insert_breakpoint); + de_fault (to_remove_breakpoint, memory_remove_breakpoint); + de_fault (to_terminal_init, ignore); + de_fault (to_terminal_inferior, ignore); + de_fault (to_terminal_ours_for_output,ignore); + de_fault (to_terminal_ours, ignore); + de_fault (to_terminal_info, default_terminal_info); + de_fault (to_kill, (void (*)())noprocess); + de_fault (to_load, (void (*)())tcomplain); + de_fault (to_lookup_symbol, nosymbol); + de_fault (to_create_inferior, maybe_kill_then_create_inferior); + de_fault (to_mourn_inferior, (void (*)())noprocess); + de_fault (to_can_run, return_zero); + de_fault (to_notice_signals, (void (*)())ignore); + de_fault (to_next, 0); + de_fault (to_has_all_memory, 0); + de_fault (to_has_memory, 0); + de_fault (to_has_stack, 0); + de_fault (to_has_registers, 0); + de_fault (to_has_execution, 0); + +#undef de_fault +} + +/* Push a new target type into the stack of the existing target accessors, + possibly superseding some of the existing accessors. + + Result is zero if the pushed target ended up on top of the stack, + nonzero if at least one target is on top of it. + + Rather than allow an empty stack, we always have the dummy target at + the bottom stratum, so we can call the function vectors without + checking them. */ + +int +push_target (t) + struct target_ops *t; +{ + struct target_ops *st, *prev; + + for (prev = 0, st = current_target; + st; + prev = st, st = st->to_next) { + if ((int)(t->to_stratum) >= (int)(st->to_stratum)) + break; + } + + while (t->to_stratum == st->to_stratum) { + /* There's already something on this stratum. Close it off. */ + (st->to_close) (0); + if (prev) + prev->to_next = st->to_next; /* Unchain old target_ops */ + else + current_target = st->to_next; /* Unchain first on list */ + st = st->to_next; + } + + /* We have removed all targets in our stratum, now add ourself. */ + t->to_next = st; + if (prev) + prev->to_next = t; + else + current_target = t; + + cleanup_target (current_target); + return prev != 0; +} + +/* Remove a target_ops vector from the stack, wherever it may be. + Return how many times it was removed (0 or 1 unless bug). */ + +int +unpush_target (t) + struct target_ops *t; +{ + struct target_ops *u, *v; + int result = 0; + + for (u = current_target, v = 0; + u; + v = u, u = u->to_next) + if (u == t) + { + if (v == 0) + pop_target(); /* unchain top copy */ + else { + (t->to_close)(0); /* Let it clean up */ + v->to_next = t->to_next; /* unchain middle copy */ + } + result++; + } + return result; +} + +void +pop_target () +{ + (current_target->to_close)(0); /* Let it clean up */ + current_target = current_target->to_next; +#if 0 + /* This will dump core if ever called--push_target expects current_target + to be non-NULL. But I don't think it's needed; I don't see how the + dummy_target could ever be removed from the stack. */ + if (!current_target) /* At bottom, push dummy. */ + push_target (&dummy_target); +#endif +} + +#undef MIN +#define MIN(A, B) (((A) <= (B)) ? (A) : (B)) + +/* target_read_string -- read a null terminated string from MEMADDR in target. + The read may also be terminated early by getting an error from target_xfer_ + memory. + LEN is the size of the buffer pointed to by MYADDR. Note that a terminating + null will only be written if there is sufficient room. The return value is + is the number of bytes (including the null) actually transferred. +*/ + +int +target_read_string (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int tlen, origlen, offset, i; + char buf[4]; + + origlen = len; + + while (len > 0) + { + tlen = MIN (len, 4 - (memaddr & 3)); + offset = memaddr & 3; + + if (target_xfer_memory (memaddr & ~3, buf, 4, 0)) + return origlen - len; + + for (i = 0; i < tlen; i++) + { + *myaddr++ = buf[i + offset]; + if (buf[i + offset] == '\000') + return (origlen - len) + i + 1; + } + + memaddr += tlen; + len -= tlen; + } + return origlen; +} + +/* Read LEN bytes of target memory at address MEMADDR, placing the results in + GDB's memory at MYADDR. Returns either 0 for success or an errno value + if any error occurs. + + If an error occurs, no guarantee is made about the contents of the data at + MYADDR. In particular, the caller should not depend upon partial reads + filling the buffer with good data. There is no way for the caller to know + how much good data might have been transfered anyway. Callers that can + deal with partial reads should call target_read_memory_partial. */ + +int +target_read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + return target_xfer_memory (memaddr, myaddr, len, 0); +} + +/* Read LEN bytes of target memory at address MEMADDR, placing the results + in GDB's memory at MYADDR. Returns a count of the bytes actually read, + and optionally an errno value in the location pointed to by ERRNOPTR + if ERRNOPTR is non-null. */ + +int +target_read_memory_partial (memaddr, myaddr, len, errnoptr) + CORE_ADDR memaddr; + char *myaddr; + int len; + int *errnoptr; +{ + int nread; /* Number of bytes actually read. */ + int errcode; /* Error from last read. */ + + /* First try a complete read. */ + errcode = target_xfer_memory (memaddr, myaddr, len, 0); + if (errcode == 0) + { + /* Got it all. */ + nread = len; + } + else + { + /* Loop, reading one byte at a time until we get as much as we can. */ + for (errcode = 0, nread = 0; len > 0 && errcode == 0; nread++, len--) + { + errcode = target_xfer_memory (memaddr++, myaddr++, 1, 0); + } + /* If an error, the last read was unsuccessful, so adjust count. */ + if (errcode != 0) + { + nread--; + } + } + if (errnoptr != NULL) + { + *errnoptr = errcode; + } + return (nread); +} + +int +target_write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + return target_xfer_memory (memaddr, myaddr, len, 1); +} + +/* Move memory to or from the targets. Iterate until all of it has + been moved, if necessary. The top target gets priority; anything + it doesn't want, is offered to the next one down, etc. Note the + business with curlen: if an early target says "no, but I have a + boundary overlapping this xfer" then we shorten what we offer to + the subsequent targets so the early guy will get a chance at the + tail before the subsequent ones do. + + Result is 0 or errno value. */ + +int +target_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + int curlen; + int res; + struct target_ops *t; + + /* to_xfer_memory is not guaranteed to set errno, even when it returns + 0. */ + errno = 0; + + /* The quick case is that the top target does it all. */ + res = current_target->to_xfer_memory + (memaddr, myaddr, len, write, current_target); + if (res == len) + return 0; + + if (res > 0) + goto bump; + /* If res <= 0 then we call it again in the loop. Ah well. */ + + for (; len > 0;) + { + curlen = len; /* Want to do it all */ + for (t = current_target; + t; + t = t->to_has_all_memory? 0: t->to_next) + { + res = t->to_xfer_memory(memaddr, myaddr, curlen, write, t); + if (res > 0) break; /* Handled all or part of xfer */ + if (res == 0) continue; /* Handled none */ + curlen = -res; /* Could handle once we get past res bytes */ + } + if (res <= 0) + { + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. Return error. */ + if (!write) + memset (myaddr, 0, len); + if (errno == 0) + return EIO; + else + return errno; + } +bump: + memaddr += res; + myaddr += res; + len -= res; + } + return 0; /* We managed to cover it all somehow. */ +} + + +/* ARGSUSED */ +static void +target_info (args, from_tty) + char *args; + int from_tty; +{ + struct target_ops *t; + int has_all_mem = 0; + + if (symfile_objfile != NULL) + printf ("Symbols from \"%s\".\n", symfile_objfile->name); + +#ifdef FILES_INFO_HOOK + if (FILES_INFO_HOOK ()) + return; +#endif + + for (t = current_target; + t; + t = t->to_next) + { + if ((int)(t->to_stratum) <= (int)dummy_stratum) + continue; + if (has_all_mem) + printf("\tWhile running this, gdb does not access memory from...\n"); + printf("%s:\n", t->to_longname); + (t->to_files_info)(t); + has_all_mem = t->to_has_all_memory; + } +} + +/* This is to be called by the open routine before it does + anything. */ + +void +target_preopen (from_tty) + int from_tty; +{ + dont_repeat(); + + if (target_has_execution) + { + if (query ("A program is being debugged already. Kill it? ")) + target_kill (); + else + error ("Program not killed."); + } +} + +/* Detach a target after doing deferred register stores. */ + +void +target_detach (args, from_tty) + char *args; + int from_tty; +{ + /* Handle any optimized stores to the inferior. */ +#ifdef DO_DEFERRED_STORES + DO_DEFERRED_STORES; +#endif + (current_target->to_detach) (args, from_tty); +} + +/* Look through the list of possible targets for a target that can + execute a run or attach command without any other data. This is + used to locate the default process stratum. + + Result is always valid (error() is called for errors). */ + +static struct target_ops * +find_default_run_target (do_mesg) + char *do_mesg; +{ + struct target_ops **t; + struct target_ops *runable = NULL; + int count; + + count = 0; + + for (t = target_structs; t < target_structs + target_struct_size; + ++t) + { + if (target_can_run(*t)) + { + runable = *t; + ++count; + } + } + + if (count != 1) + error ("Don't know how to %s. Try \"help target\".", do_mesg); + + return runable; +} + +void +find_default_attach (args, from_tty) + char *args; + int from_tty; +{ + struct target_ops *t; + + t = find_default_run_target("attach"); + (t->to_attach) (args, from_tty); + return; +} + +void +find_default_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + struct target_ops *t; + + t = find_default_run_target("run"); + (t->to_create_inferior) (exec_file, allargs, env); + return; +} + +static int +return_zero () +{ + return 0; +} + +struct target_ops * +find_core_target () +{ + struct target_ops **t; + struct target_ops *runable = NULL; + int count; + + count = 0; + + for (t = target_structs; t < target_structs + target_struct_size; + ++t) + { + if ((*t)->to_stratum == core_stratum) + { + runable = *t; + ++count; + } + } + + return(count == 1 ? runable : NULL); +} + +/* Convert a normal process ID to a string. Returns the string in a static + buffer. */ + +char * +normal_pid_to_str (pid) + int pid; +{ + static char buf[30]; + + sprintf (buf, "process %d", pid); + + return buf; +} + +static char targ_desc[] = + "Names of targets and files being debugged.\n\ +Shows the entire stack of targets currently in use (including the exec-file,\n\ +core-file, and process, if any), as well as the symbol file name."; + +void +_initialize_targets () +{ + current_target = &dummy_target; + cleanup_target (current_target); + + add_info ("target", target_info, targ_desc); + add_info ("files", target_info, targ_desc); +} diff --git a/gnu/usr.bin/gdb/gdb/target.h b/gnu/usr.bin/gdb/gdb/target.h new file mode 100644 index 00000000000..c112b4ac122 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/target.h @@ -0,0 +1,465 @@ +/* Interface between GDB and target environments, including files and processes + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +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. */ + +#if !defined (TARGET_H) +#define TARGET_H + +/* This include file defines the interface between the main part + of the debugger, and the part which is target-specific, or + specific to the communications interface between us and the + target. + + A TARGET is an interface between the debugger and a particular + kind of file or process. Targets can be STACKED in STRATA, + so that more than one target can potentially respond to a request. + In particular, memory accesses will walk down the stack of targets + until they find a target that is interested in handling that particular + address. STRATA are artificial boundaries on the stack, within + which particular kinds of targets live. Strata exist so that + people don't get confused by pushing e.g. a process target and then + a file target, and wondering why they can't see the current values + of variables any more (the file target is handling them and they + never get to the process target). So when you push a file target, + it goes into the file stratum, which is always below the process + stratum. */ + +#include "bfd.h" + +enum strata { + dummy_stratum, /* The lowest of the low */ + file_stratum, /* Executable files, etc */ + core_stratum, /* Core dump files */ + process_stratum /* Executing processes */ +}; + +struct target_ops +{ + char *to_shortname; /* Name this target type */ + char *to_longname; /* Name for printing */ + char *to_doc; /* Documentation. Does not include trailing + newline, and starts with a one-line descrip- + tion (probably similar to to_longname). */ + void (*to_open) PARAMS ((char *, int)); + void (*to_close) PARAMS ((int)); + void (*to_attach) PARAMS ((char *, int)); + void (*to_detach) PARAMS ((char *, int)); + void (*to_resume) PARAMS ((int, int, int)); + int (*to_wait) PARAMS ((int, int *)); + void (*to_fetch_registers) PARAMS ((int)); + void (*to_store_registers) PARAMS ((int)); + void (*to_prepare_to_store) PARAMS ((void)); + + /* Transfer LEN bytes of memory between GDB address MYADDR and + target address MEMADDR. If WRITE, transfer them to the target, else + transfer them from the target. TARGET is the target from which we + get this function. + + Return value, N, is one of the following: + + 0 means that we can't handle this. If errno has been set, it is the + error which prevented us from doing it (FIXME: What about bfd_error?). + + positive (call it N) means that we have transferred N bytes + starting at MEMADDR. We might be able to handle more bytes + beyond this length, but no promises. + + negative (call its absolute value N) means that we cannot + transfer right at MEMADDR, but we could transfer at least + something at MEMADDR + N. */ + + int (*to_xfer_memory) PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int write, + struct target_ops * target)); + + void (*to_files_info) PARAMS ((struct target_ops *)); + int (*to_insert_breakpoint) PARAMS ((CORE_ADDR, char *)); + int (*to_remove_breakpoint) PARAMS ((CORE_ADDR, char *)); + void (*to_terminal_init) PARAMS ((void)); + void (*to_terminal_inferior) PARAMS ((void)); + void (*to_terminal_ours_for_output) PARAMS ((void)); + void (*to_terminal_ours) PARAMS ((void)); + void (*to_terminal_info) PARAMS ((char *, int)); + void (*to_kill) PARAMS ((void)); + void (*to_load) PARAMS ((char *, int)); + int (*to_lookup_symbol) PARAMS ((char *, CORE_ADDR *)); + void (*to_create_inferior) PARAMS ((char *, char *, char **)); + void (*to_mourn_inferior) PARAMS ((void)); + int (*to_can_run) PARAMS ((void)); + void (*to_notice_signals) PARAMS ((int pid)); + enum strata to_stratum; + struct target_ops + *to_next; + int to_has_all_memory; + int to_has_memory; + int to_has_stack; + int to_has_registers; + int to_has_execution; + struct section_table + *to_sections; + struct section_table + *to_sections_end; + int to_magic; + /* Need sub-structure for target machine related rather than comm related? */ +}; + +/* Magic number for checking ops size. If a struct doesn't end with this + number, somebody changed the declaration but didn't change all the + places that initialize one. */ + +#define OPS_MAGIC 3840 + +/* The ops structure for our "current" target process. This should + never be NULL. If there is no target, it points to the dummy_target. */ + +extern struct target_ops *current_target; + +/* Define easy words for doing these operations on our current target. */ + +#define target_shortname (current_target->to_shortname) +#define target_longname (current_target->to_longname) + +/* The open routine takes the rest of the parameters from the command, + and (if successful) pushes a new target onto the stack. + Targets should supply this routine, if only to provide an error message. */ +#define target_open(name, from_tty) \ + (*current_target->to_open) (name, from_tty) + +/* Does whatever cleanup is required for a target that we are no longer + going to be calling. Argument says whether we are quitting gdb and + should not get hung in case of errors, or whether we want a clean + termination even if it takes a while. This routine is automatically + always called just before a routine is popped off the target stack. + Closing file descriptors and freeing memory are typical things it should + do. */ + +#define target_close(quitting) \ + (*current_target->to_close) (quitting) + +/* Attaches to a process on the target side. Arguments are as passed + to the `attach' command by the user. This routine can be called + when the target is not on the target-stack, if the target_can_run + routine returns 1; in that case, it must push itself onto the stack. + Upon exit, the target should be ready for normal operations, and + should be ready to deliver the status of the process immediately + (without waiting) to an upcoming target_wait call. */ + +#define target_attach(args, from_tty) \ + (*current_target->to_attach) (args, from_tty) + +/* Takes a program previously attached to and detaches it. + The program may resume execution (some targets do, some don't) and will + no longer stop on signals, etc. We better not have left any breakpoints + in the program or it'll die when it hits one. ARGS is arguments + typed by the user (e.g. a signal to send the process). FROM_TTY + says whether to be verbose or not. */ + +extern void +target_detach PARAMS ((char *, int)); + +/* Resume execution of the target process PID. STEP says whether to + single-step or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be + given to the target, or zero for no signal. */ + +#define target_resume(pid, step, siggnal) \ + (*current_target->to_resume) (pid, step, siggnal) + +/* Wait for process pid to do something. Pid = -1 to wait for any pid to do + something. Return pid of child, or -1 in case of error; store status + through argument pointer STATUS. */ + +#define target_wait(pid, status) \ + (*current_target->to_wait) (pid, status) + +/* Fetch register REGNO, or all regs if regno == -1. No result. */ + +#define target_fetch_registers(regno) \ + (*current_target->to_fetch_registers) (regno) + +/* Store at least register REGNO, or all regs if REGNO == -1. + It can store as many registers as it wants to, so target_prepare_to_store + must have been previously called. Calls error() if there are problems. */ + +#define target_store_registers(regs) \ + (*current_target->to_store_registers) (regs) + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that REGISTERS contains all the registers from the program being + debugged. */ + +#define target_prepare_to_store() \ + (*current_target->to_prepare_to_store) () + +extern int +target_read_string PARAMS ((CORE_ADDR, char *, int)); + +extern int +target_read_memory PARAMS ((CORE_ADDR, char *, int)); + +extern int +target_read_memory_partial PARAMS ((CORE_ADDR, char *, int, int *)); + +extern int +target_write_memory PARAMS ((CORE_ADDR, char *, int)); + +extern int +xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +extern int +child_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +/* Transfer LEN bytes between target address MEMADDR and GDB address MYADDR. + Returns 0 for success, errno code for failure (which includes partial + transfers--if you want a more useful response to partial transfers, try + target_read_memory_partial). */ + +extern int target_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int write)); + +/* From exec.c */ + +extern void +print_section_info PARAMS ((struct target_ops *, bfd *)); + +/* Print a line about the current target. */ + +#define target_files_info() \ + (*current_target->to_files_info) (current_target) + +/* Insert a breakpoint at address ADDR in the target machine. + SAVE is a pointer to memory allocated for saving the + target contents. It is guaranteed by the caller to be long enough + to save "sizeof BREAKPOINT" bytes. Result is 0 for success, or + an errno value. */ + +#define target_insert_breakpoint(addr, save) \ + (*current_target->to_insert_breakpoint) (addr, save) + +/* Remove a breakpoint at address ADDR in the target machine. + SAVE is a pointer to the same save area + that was previously passed to target_insert_breakpoint. + Result is 0 for success, or an errno value. */ + +#define target_remove_breakpoint(addr, save) \ + (*current_target->to_remove_breakpoint) (addr, save) + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +#define target_terminal_init() \ + (*current_target->to_terminal_init) () + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +#define target_terminal_inferior() \ + (*current_target->to_terminal_inferior) () + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +#define target_terminal_ours_for_output() \ + (*current_target->to_terminal_ours_for_output) () + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +#define target_terminal_ours() \ + (*current_target->to_terminal_ours) () + +/* Print useful information about our terminal status, if such a thing + exists. */ + +#define target_terminal_info(arg, from_tty) \ + (*current_target->to_terminal_info) (arg, from_tty) + +/* Kill the inferior process. Make it go away. */ + +#define target_kill() \ + (*current_target->to_kill) () + +/* Load an executable file into the target process. This is expected to + not only bring new code into the target process, but also to update + GDB's symbol tables to match. */ + +#define target_load(arg, from_tty) \ + (*current_target->to_load) (arg, from_tty) + +/* Look up a symbol in the target's symbol table. NAME is the symbol + name. ADDRP is a CORE_ADDR * pointing to where the value of the symbol + should be returned. The result is 0 if successful, nonzero if the + symbol does not exist in the target environment. This function should + not call error() if communication with the target is interrupted, since + it is called from symbol reading, but should return nonzero, possibly + doing a complain(). */ + +#define target_lookup_symbol(name, addrp) \ + (*current_target->to_lookup_symbol) (name, addrp) + +/* Start an inferior process and set inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). + On VxWorks and various standalone systems, we ignore exec_file. */ + +#define target_create_inferior(exec_file, args, env) \ + (*current_target->to_create_inferior) (exec_file, args, env) + +/* The inferior process has died. Do what is right. */ + +#define target_mourn_inferior() \ + (*current_target->to_mourn_inferior) () + +/* Does target have enough data to do a run or attach command? */ + +#define target_can_run(t) \ + ((t)->to_can_run) () + +/* post process changes to signal handling in the inferior. */ + +#define target_notice_signals(pid) \ + (*current_target->to_notice_signals) (pid) + +/* Pointer to next target in the chain, e.g. a core file and an exec file. */ + +#define target_next \ + (current_target->to_next) + +/* Does the target include all of memory, or only part of it? This + determines whether we look up the target chain for other parts of + memory if this target can't satisfy a request. */ + +#define target_has_all_memory \ + (current_target->to_has_all_memory) + +/* Does the target include memory? (Dummy targets don't.) */ + +#define target_has_memory \ + (current_target->to_has_memory) + +/* Does the target have a stack? (Exec files don't, VxWorks doesn't, until + we start a process.) */ + +#define target_has_stack \ + (current_target->to_has_stack) + +/* Does the target have registers? (Exec files don't.) */ + +#define target_has_registers \ + (current_target->to_has_registers) + +/* Does the target have execution? Can we make it jump (through + hoops), or pop its stack a few times? FIXME: If this is to work that + way, it needs to check whether an inferior actually exists. + remote-udi.c and probably other targets can be the current target + when the inferior doesn't actually exist at the moment. Right now + this just tells us whether this target is *capable* of execution. */ + +#define target_has_execution \ + (current_target->to_has_execution) + +/* Converts a process id to a string. Usually, the string just contains + `process xyz', but on some systems it may contain + `process xyz thread abc'. */ + +#ifndef target_pid_to_str +#define target_pid_to_str(PID) \ + normal_pid_to_str (PID) +extern char *normal_pid_to_str PARAMS ((int pid)); +#endif + +/* Routines for maintenance of the target structures... + + add_target: Add a target to the list of all possible targets. + + push_target: Make this target the top of the stack of currently used + targets, within its particular stratum of the stack. Result + is 0 if now atop the stack, nonzero if not on top (maybe + should warn user). + + unpush_target: Remove this from the stack of currently used targets, + no matter where it is on the list. Returns 0 if no + change, 1 if removed from stack. + + pop_target: Remove the top thing on the stack of current targets. */ + +extern void +add_target PARAMS ((struct target_ops *)); + +extern int +push_target PARAMS ((struct target_ops *)); + +extern int +unpush_target PARAMS ((struct target_ops *)); + +extern void +target_preopen PARAMS ((int)); + +extern void +pop_target PARAMS ((void)); + +/* Struct section_table maps address ranges to file sections. It is + mostly used with BFD files, but can be used without (e.g. for handling + raw disks, or files not in formats handled by BFD). */ + +struct section_table { + CORE_ADDR addr; /* Lowest address in section */ + CORE_ADDR endaddr; /* 1+highest address in section */ + sec_ptr sec_ptr; /* BFD section pointer */ + bfd *bfd; /* BFD file pointer */ +}; + +/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. + Returns 0 if OK, 1 on error. */ + +extern int +build_section_table PARAMS ((bfd *, struct section_table **, + struct section_table **)); + +/* From mem-break.c */ + +extern int +memory_remove_breakpoint PARAMS ((CORE_ADDR, char *)); + +extern int +memory_insert_breakpoint PARAMS ((CORE_ADDR, char *)); + +/* From target.c */ + +void +noprocess PARAMS ((void)); + +void +find_default_attach PARAMS ((char *, int)); + +void +find_default_create_inferior PARAMS ((char *, char *, char **)); + +struct target_ops * +find_core_target PARAMS ((void)); + +#endif /* !defined (TARGET_H) */ diff --git a/gnu/usr.bin/gdb/gdb/terminal.h b/gnu/usr.bin/gdb/gdb/terminal.h new file mode 100644 index 00000000000..f76fa903133 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/terminal.h @@ -0,0 +1,62 @@ +/* Terminal interface definitions for GDB, the GNU Debugger. + Copyright 1986, 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. */ + +#if !defined (TERMINAL_H) +#define TERMINAL_H 1 + +#if !defined(__GO32__) && !defined (HAVE_TERMIOS) + +/* Define a common set of macros -- BSD based -- and redefine whatever + the system offers to make it look like that. FIXME: serial.h and + ser-*.c deal with this in a much cleaner fashion; as soon as stuff + is converted to use them, can get rid of this crap. */ + +#ifdef HAVE_TERMIO + +#include + +#undef TIOCGETP +#define TIOCGETP TCGETA +#undef TIOCSETN +#define TIOCSETN TCSETA +#undef TIOCSETP +#define TIOCSETP TCSETAF +#define TERMINAL struct termio + +#else /* sgtty */ + +#include +#include +#include +#define TERMINAL struct sgttyb + +#endif /* sgtty */ +#endif /* termio or sgtty */ + +extern void new_tty PARAMS ((void)); + +/* Do we have job control? Can be assumed to always be the same within + a given run of GDB. In inflow.c. */ +extern int job_control; + +/* Set the process group of the caller to its own pid, or do nothing if + we lack job control. */ +extern int gdb_setpgid PARAMS ((void)); + +#endif /* !defined (TERMINAL_H) */ diff --git a/gnu/usr.bin/gdb/gdb/thread.c b/gnu/usr.bin/gdb/gdb/thread.c new file mode 100644 index 00000000000..f14b41fc041 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/thread.c @@ -0,0 +1,248 @@ +/* Multi-process/thread control for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1993 + + Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. + 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. */ + +#include "defs.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" +#include "target.h" +#include "thread.h" +#include "command.h" + +#include +#include + +/*#include "lynxos-core.h"*/ + +struct thread_info +{ + struct thread_info *next; + int pid; /* Actual process id */ + int num; /* Convenient handle */ +}; + +static struct thread_info *thread_list = NULL; +static int highest_thread_num; + +static void thread_command PARAMS ((char * tidstr, int from_tty)); + +static void prune_threads PARAMS ((void)); + +static void thread_switch PARAMS ((int pid)); + +static struct thread_info * find_thread_id PARAMS ((int num)); + +void +init_thread_list () +{ + struct thread_info *tp, *tpnext; + + if (!thread_list) + return; + + for (tp = thread_list; tp; tp = tpnext) + { + tpnext = tp->next; + free (tp); + } + + thread_list = NULL; + highest_thread_num = 0; +} + +void +add_thread (pid) + int pid; +{ + struct thread_info *tp; + + tp = (struct thread_info *) xmalloc (sizeof (struct thread_info)); + + tp->pid = pid; + tp->num = ++highest_thread_num; + tp->next = thread_list; + thread_list = tp; +} + +static struct thread_info * +find_thread_id (num) + int num; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->num == num) + return tp; + + return NULL; +} + +int +valid_thread_id (num) + int num; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->num == num) + return 1; + + return 0; +} + +int +pid_to_thread_id (pid) + int pid; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->pid == pid) + return tp->num; + + return 0; +} + +int +in_thread_list (pid) + int pid; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->pid == pid) + return 1; + + return 0; /* Never heard of 'im */ +} + +static void +prune_threads () +{ + struct thread_info *tp, *tpprev; + + tpprev = 0; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->pid == -1) + { + if (tpprev) + tpprev->next = tp->next; + else + thread_list = NULL; + + free (tp); + } + else + tpprev = tp; +} + +/* Print information about currently known threads */ + +static void +info_threads_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct thread_info *tp; + int current_pid = inferior_pid; + + for (tp = thread_list; tp; tp = tp->next) + { + if (target_has_execution + && kill (tp->pid, 0) == -1) + { + tp->pid = -1; /* Mark it as dead */ + continue; + } + + if (tp->pid == current_pid) + printf_filtered ("* "); + else + printf_filtered (" "); + + printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid)); + + thread_switch (tp->pid); + print_stack_frame (selected_frame, -1, 0); + } + + thread_switch (current_pid); + prune_threads (); +} + +/* Switch from one thread to another. */ + +static void +thread_switch (pid) + int pid; +{ + if (pid == inferior_pid) + return; + + inferior_pid = pid; + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc(); + set_current_frame (create_new_frame (read_fp (), stop_pc)); + stop_frame_address = FRAME_FP (get_current_frame ()); + select_frame (get_current_frame (), 0); +} + +static void +thread_command (tidstr, from_tty) + char *tidstr; + int from_tty; +{ + int num; + struct thread_info *tp; + + if (!tidstr) + error ("Please specify a thread ID. Use the \"info threads\" command to\n\ +see the IDs of currently known threads."); + + + num = atoi (tidstr); + + tp = find_thread_id (num); + + if (!tp) + error ("Thread ID %d not known. Use the \"info threads\" command to\n\ +see the IDs of currently known threads.", num); + + thread_switch (tp->pid); + + printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid)); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +void +_initialize_thread () +{ + add_info ("threads", info_threads_command, + "IDs of currently known threads."); + add_com ("thread", class_info, thread_command, + "Use this command to switch between threads.\n\ +The new thread ID must be currently known."); +} diff --git a/gnu/usr.bin/gdb/gdb/thread.h b/gnu/usr.bin/gdb/gdb/thread.h new file mode 100644 index 00000000000..2ec94fc5c5e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/thread.h @@ -0,0 +1,36 @@ +/* Multi-process/thread control defs for GDB, the GNU debugger. + Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993 + + Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. + 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. */ + +#ifndef THREAD_H +#define THREAD_H + +extern void init_thread_list PARAMS ((void)); + +extern void add_thread PARAMS ((int pid)); + +extern int in_thread_list PARAMS ((int pid)); + +extern int pid_to_thread_id PARAMS ((int pid)); + +extern int valid_thread_id PARAMS ((int thread)); + +#endif /* THREAD_H */ diff --git a/gnu/usr.bin/gdb/gdb/tm-i386v.h b/gnu/usr.bin/gdb/gdb/tm-i386v.h new file mode 100644 index 00000000000..f80f5192148 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/tm-i386v.h @@ -0,0 +1,309 @@ +/* Macro definitions for i386, Unix System V. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 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. */ + +#if !defined (TM_I386V_H) +#define TM_I386V_H 1 + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* turn this on when rest of gdb is ready */ +#define IEEE_FLOAT + +/* number of traps that happen between exec'ing the shell + * to run an inferior, and when we finally get to + * the inferior code. This is 2 on most implementations. + */ +#ifndef START_INFERIOR_TRAPS_EXPECTED +#define START_INFERIOR_TRAPS_EXPECTED 4 +#endif + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));} + +extern int +i386_skip_prologue PARAMS ((int)); + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + (read_memory_integer (read_register (SP_REGNUM), 4)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#ifndef DECR_PC_AFTER_BREAK +#define DECR_PC_AFTER_BREAK 1 +#endif + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the 386. */ + +#define INVALID_FLOAT(p, len) (0) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 16 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "ps", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define FP_REGNUM 5 /* Contains address of executing stack frame */ +#define SP_REGNUM 4 /* Contains address of top of stack */ + +#define PC_REGNUM 8 +#define PS_REGNUM 9 + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS * 4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N)*4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ + {memcpy ((TO), (FROM), 4);} + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ + {memcpy ((TO), (FROM), 4);} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +/* Perhaps si and di should go here, but potentially they could be + used for things other than address. */ +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) == PC_REGNUM || (N) == FP_REGNUM || (N) == SP_REGNUM ? \ + lookup_pointer_type (builtin_type_void) : builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), (char *) &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + memcpy ((VALBUF), (REGBUF), TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. */ + +#define FRAME_CHAIN(thisframe) \ + (!inside_entry_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +/* Define other aspects of the stack frame. */ + +/* 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. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = -1 + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct frame_info; +struct frame_saved_regs; +#endif + +extern int +i386_frame_num_args PARAMS ((struct frame_info *)); + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + +extern void +i386_frame_find_saved_regs PARAMS ((struct frame_info *, + struct frame_saved_regs *)); + + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); } + +extern void +i386_push_dummy_frame PARAMS ((void)); + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME { i386_pop_frame (); } + +extern void +i386_pop_frame PARAMS ((void)); + +/* this is + * call 11223344 (32 bit relative) + * int3 + */ + +#define CALL_DUMMY { 0x223344e8, 0xcc11 } + +#define CALL_DUMMY_LENGTH 8 + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + int from, to, delta, loc; \ + loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \ + from = loc + 5; \ + to = (int)(fun); \ + delta = to - from; \ + *((char *)(dummyname) + 1) = (delta & 0xff); \ + *((char *)(dummyname) + 2) = ((delta >> 8) & 0xff); \ + *((char *)(dummyname) + 3) = ((delta >> 16) & 0xff); \ + *((char *)(dummyname) + 4) = ((delta >> 24) & 0xff); \ +} + +extern void +print_387_control_word PARAMS ((unsigned int)); + +extern void +print_387_status_word PARAMS ((unsigned int)); + +/* Offset from SP to first arg on stack at first instruction of a function */ + +#define SP_ARG0 (1 * 4) + +#endif /* !defined (TM_I386V_H) */ diff --git a/gnu/usr.bin/gdb/gdb/tm.h b/gnu/usr.bin/gdb/gdb/tm.h new file mode 100644 index 00000000000..25b66c709de --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/tm.h @@ -0,0 +1,76 @@ +/* Macro definitions for i386 running under BSD Unix. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 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. */ + +/* Override number of expected traps from sysv. */ +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* Most definitions from sysv could be used. */ +#include "tm-i386v.h" + +/* 386BSD cannot handle the segment registers. */ +/* BSDI can't handle them either. */ +#undef NUM_REGS +#define NUM_REGS 10 + +/* 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 + +/* 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. */ + +/* 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 +#define FRAME_CHAIN(thisframe) \ + (thisframe->signal_handler_caller \ + ? thisframe->frame \ + : (!inside_entry_file ((thisframe)->pc) \ + ? 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 . */ +#define SIGCONTEXT_PC_OFFSET 20 + +#undef FRAME_SAVED_PC(FRAME) +#define FRAME_SAVED_PC(FRAME) \ + (((FRAME)->signal_handler_caller \ + ? sigtramp_saved_pc (FRAME) \ + : read_memory_integer ((FRAME)->frame + 4, 4)) \ + ) diff --git a/gnu/usr.bin/gdb/gdb/typeprint.c b/gnu/usr.bin/gdb/gdb/typeprint.c new file mode 100644 index 00000000000..5e13e07fb4d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/typeprint.c @@ -0,0 +1,297 @@ +/* Language independent support for printing types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993 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. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "command.h" +#include "gdbcmd.h" +#include "target.h" +#include "language.h" +#include "demangle.h" + +#include +#include + +static void +ptype_command PARAMS ((char *, int)); + +static struct type * +ptype_eval PARAMS ((struct expression *)); + +static void +whatis_command PARAMS ((char *, int)); + +static void +whatis_exp PARAMS ((char *, int)); + +/* Print a description of a type TYPE in the form of a declaration of a + variable named VARSTRING. (VARSTRING is demangled if necessary.) + Output goes to STREAM (via stdio). + If SHOW is positive, we show the contents of the outermost level + of structure even if there is a type name that could be used instead. + If SHOW is negative, we never show the details of elements' types. */ + +void +type_print (type, varstring, stream, show) + struct type *type; + char *varstring; + FILE *stream; + int show; +{ + LA_PRINT_TYPE (type, varstring, stream, show, 0); +} + +/* Print type of EXP, or last thing in value history if EXP == NULL. + show is passed to type_print. */ + +static void +whatis_exp (exp, show) + char *exp; + int show; +{ + struct expression *expr; + register value val; + register struct cleanup *old_chain = NULL; + + if (exp) + { + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + val = evaluate_type (expr); + } + else + val = access_value_history (0); + + printf_filtered ("type = "); + type_print (VALUE_TYPE (val), "", stdout, show); + printf_filtered ("\n"); + + if (exp) + do_cleanups (old_chain); +} + +/* ARGSUSED */ +static void +whatis_command (exp, from_tty) + char *exp; + int from_tty; +{ + /* Most of the time users do not want to see all the fields + in a structure. If they do they can use the "ptype" command. + Hence the "-1" below. */ + whatis_exp (exp, -1); +} + +/* Simple subroutine for ptype_command. */ + +static struct type * +ptype_eval (exp) + struct expression *exp; +{ + if (exp->elts[0].opcode == OP_TYPE) + { + return (exp->elts[1].type); + } + else + { + return (NULL); + } +} + +/* TYPENAME is either the name of a type, or an expression. */ + +/* ARGSUSED */ +static void +ptype_command (typename, from_tty) + char *typename; + int from_tty; +{ + register struct type *type; + struct expression *expr; + register struct cleanup *old_chain; + + if (typename == NULL) + { + /* Print type of last thing in value history. */ + whatis_exp (typename, 1); + } + else + { + expr = parse_expression (typename); + old_chain = make_cleanup (free_current_contents, &expr); + type = ptype_eval (expr); + if (type != NULL) + { + /* User did "ptype " */ + printf_filtered ("type = "); + type_print (type, "", stdout, 1); + printf_filtered ("\n"); + do_cleanups (old_chain); + } + else + { + /* User did "ptype " */ + do_cleanups (old_chain); + whatis_exp (typename, 1); + } + } +} + +/* Print integral scalar data VAL, of type TYPE, onto stdio stream STREAM. + Used to print data from type structures in a specified type. For example, + array bounds may be characters or booleans in some languages, and this + allows the ranges to be printed in their "natural" form rather than as + decimal integer values. + + FIXME: This is here simply because only the type printing routines + currently use it, and it wasn't clear if it really belonged somewhere + else (like printcmd.c). There are a lot of other gdb routines that do + something similar, but they are generally concerned with printing values + that come from the inferior in target byte order and target size. */ + +void +print_type_scalar (type, val, stream) + struct type *type; + LONGEST val; + FILE *stream; +{ + unsigned int i; + unsigned len; + + switch (TYPE_CODE (type)) + { + + case TYPE_CODE_ENUM: + len = TYPE_NFIELDS (type); + for (i = 0; i < len; i++) + { + if (TYPE_FIELD_BITPOS (type, i) == val) + { + break; + } + } + if (i < len) + { + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + } + else + { + print_longest (stream, 'd', 0, val); + } + break; + + case TYPE_CODE_INT: + print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val); + break; + + case TYPE_CODE_CHAR: + LA_PRINT_CHAR ((unsigned char) val, stream); + break; + + case TYPE_CODE_BOOL: + fprintf_filtered (stream, val ? "TRUE" : "FALSE"); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_PTR: + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_STRING: + case TYPE_CODE_ERROR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + case TYPE_CODE_REF: + error ("internal error: unhandled type in print_type_scalar"); + break; + + default: + error ("Invalid type code in symbol table."); + } + fflush (stream); +} + +#if MAINTENANCE_CMDS + +/* Dump details of a type specified either directly or indirectly. + Uses the same sort of type lookup mechanism as ptype_command() + and whatis_command(). */ + +void +maintenance_print_type (typename, from_tty) + char *typename; + int from_tty; +{ + register value val; + register struct type *type; + register struct cleanup *old_chain; + struct expression *expr; + + if (typename != NULL) + { + expr = parse_expression (typename); + old_chain = make_cleanup (free_current_contents, &expr); + if (expr -> elts[0].opcode == OP_TYPE) + { + /* The user expression names a type directly, just use that type. */ + type = expr -> elts[1].type; + } + else + { + /* The user expression may name a type indirectly by naming an + object of that type. Find that indirectly named type. */ + val = evaluate_type (expr); + type = VALUE_TYPE (val); + } + if (type != NULL) + { + recursive_dump_type (type, 0); + } + do_cleanups (old_chain); + } +} + +#endif /* MAINTENANCE_CMDS */ + + +void +_initialize_typeprint () +{ + + add_com ("ptype", class_vars, ptype_command, + "Print definition of type TYPE.\n\ +Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\ +or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\ +The selected stack frame's lexical context is used to look up the name."); + + add_com ("whatis", class_vars, whatis_command, + "Print data type of expression EXP."); + +} diff --git a/gnu/usr.bin/gdb/gdb/typeprint.h b/gnu/usr.bin/gdb/gdb/typeprint.h new file mode 100644 index 00000000000..e6740db7c29 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/typeprint.h @@ -0,0 +1,21 @@ +/* Language independent support for printing types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993 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. */ + +void +print_type_scalar PARAMS ((struct type *type, LONGEST, FILE *)); diff --git a/gnu/usr.bin/gdb/gdb/utils.c b/gnu/usr.bin/gdb/gdb/utils.c new file mode 100644 index 00000000000..38010e323e6 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/utils.c @@ -0,0 +1,1547 @@ +/* General utility routines for GDB, the GNU debugger. + Copyright 1986, 1989, 1990, 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. */ + +#include "defs.h" +#if !defined(__GO32__) +#include +#include +#include +#endif +#include +#include +#include + +#include "signals.h" +#include "gdbcmd.h" +#include "serial.h" +#include "terminal.h" /* For job_control */ +#include "bfd.h" +#include "target.h" +#include "demangle.h" +#include "expression.h" +#include "language.h" + +/* Prototypes for local functions */ + +#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK) +#else + +static void +malloc_botch PARAMS ((void)); + +#endif /* NO_MMALLOC, etc */ + +static void +fatal_dump_core (); /* Can't prototype with usage... */ + +static void +prompt_for_continue PARAMS ((void)); + +static void +set_width_command PARAMS ((char *, int, struct cmd_list_element *)); + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) +#endif + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, rather + than waiting until QUIT is executed. Be careful in setting this; + code which executes with immediate_quit set has to be very careful + about being able to deal with being interrupted at any time. It is + almost always better to use QUIT; the only exception I can think of + is being able to quit out of a system call (using EINTR loses if + the SIGINT happens between the previous QUIT and the system call). + To immediately quit in the case in which a SIGINT happens between + the previous QUIT and setting immediate_quit (desirable anytime we + expect to block), call QUIT after setting immediate_quit. */ + +int immediate_quit; + +/* Nonzero means that encoded C++ names should be printed out in their + C++ form rather than raw. */ + +int demangle = 1; + +/* Nonzero means that encoded C++ names should be printed out in their + C++ form even in assembler language displays. If this is set, but + DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls. */ + +int asm_demangle = 0; + +/* Nonzero means that strings with character values >0x7F should be printed + as octal escapes. Zero means just print the value (e.g. it's an + international character, and the terminal or window can cope.) */ + +int sevenbit_strings = 0; + +/* String to be printed before error messages, if any. */ + +char *error_pre_print; +char *warning_pre_print = "\nwarning: "; + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (function, arg) + void (*function) PARAMS ((PTR)); + PTR arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; /* Do this first incase recursion */ + (*ptr->function) (ptr->arg); + free (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +discard_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free ((PTR)ptr); + } +} + +/* Set the cleanup_chain to 0, and return the old cleanup chain. */ +struct cleanup * +save_cleanups () +{ + struct cleanup *old_chain = cleanup_chain; + + cleanup_chain = 0; + return old_chain; +} + +/* Restore the cleanup chain from a previously saved chain. */ +void +restore_cleanups (chain) + struct cleanup *chain; +{ + cleanup_chain = chain; +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Provide a known function that does nothing, to use as a base for + for a possibly long chain of cleanups. This is useful where we + use the cleanup chain for handling normal cleanups as well as dealing + with cleanups that need to be done as a result of a call to error(). + In such cases, we may not be certain where the first cleanup is, unless + we have a do-nothing one to always use as the base. */ + +/* ARGSUSED */ +void +null_cleanup (arg) + char **arg; +{ +} + + +/* Provide a hook for modules wishing to print their own warning messages + to set up the terminal state in a compatible way, without them having + to import all the target_<...> macros. */ + +void +warning_setup () +{ + target_terminal_ours (); + wrap_here(""); /* Force out any buffered output */ + fflush (stdout); +} + +/* Print a warning message. + The first argument STRING is the warning message, used as a fprintf string, + and the remaining args are passed as arguments to it. + The primary difference between warnings and errors is that a warning + does not force the return to command level. */ + +/* VARARGS */ +void +warning (va_alist) + va_dcl +{ + va_list args; + char *string; + + va_start (args); + target_terminal_ours (); + wrap_here(""); /* Force out any buffered output */ + fflush (stdout); + if (warning_pre_print) + fprintf (stderr, warning_pre_print); + string = va_arg (args, char *); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); +} + +/* Print an error message and return to command level. + The first argument STRING is the error message, used as a fprintf string, + and the remaining args are passed as arguments to it. */ + +/* VARARGS */ +NORETURN void +error (va_alist) + va_dcl +{ + va_list args; + char *string; + + va_start (args); + target_terminal_ours (); + wrap_here(""); /* Force out any buffered output */ + fflush (stdout); + if (error_pre_print) + fprintf_filtered (stderr, error_pre_print); + string = va_arg (args, char *); + vfprintf_filtered (stderr, string, args); + fprintf_filtered (stderr, "\n"); + va_end (args); + return_to_top_level (RETURN_ERROR); +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + The arguments are printed a la printf. + + This function cannot be declared volatile (NORETURN) in an + ANSI environment because exit() is not declared volatile. */ + +/* VARARGS */ +NORETURN void +fatal (va_alist) + va_dcl +{ + va_list args; + char *string; + + va_start (args); + string = va_arg (args, char *); + fprintf (stderr, "\ngdb: "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); + exit (1); +} + +/* Print an error message and exit, dumping core. + The arguments are printed a la printf (). */ + +/* VARARGS */ +static void +fatal_dump_core (va_alist) + va_dcl +{ + va_list args; + char *string; + + va_start (args); + string = va_arg (args, char *); + /* "internal error" is always correct, since GDB should never dump + core, no matter what the input. */ + fprintf (stderr, "\ngdb internal error: "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); + + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + /* We should never get here, but just in case... */ + exit (1); +} + +/* The strerror() function can return NULL for errno values that are + out of range. Provide a "safe" version that always returns a + printable string. */ + +char * +safe_strerror (errnum) + int errnum; +{ + char *msg; + static char buf[32]; + + if ((msg = strerror (errnum)) == NULL) + { + sprintf (buf, "(undocumented errno %d)", errnum); + msg = buf; + } + return (msg); +} + +/* The strsignal() function can return NULL for signal values that are + out of range. Provide a "safe" version that always returns a + printable string. */ + +char * +safe_strsignal (signo) + int signo; +{ + char *msg; + static char buf[32]; + + if ((msg = strsignal (signo)) == NULL) + { + sprintf (buf, "(undocumented signal %d)", signo); + msg = buf; + } + return (msg); +} + + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + char *err; + char *combined; + + err = safe_strerror (errno); + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + /* I understand setting these is a matter of taste. Still, some people + may clear errno but not know about bfd_error. Doing this here is not + unreasonable. */ + bfd_error = no_error; + errno = 0; + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + char *err; + char *combined; + + err = safe_strerror (errcode); + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + fprintf (stderr, "%s.\n", combined); +} + +/* Control C eventually causes this to be called, at a convenient time. */ + +void +quit () +{ + serial_t stdout_serial = serial_fdopen (1); + + target_terminal_ours (); + wrap_here ((char *)0); /* Force out any pending output */ + + SERIAL_FLUSH_OUTPUT (stdout_serial); + + SERIAL_UN_FDOPEN (stdout_serial); + + /* Don't use *_filtered; we don't want to prompt the user to continue. */ + if (error_pre_print) + fprintf (stderr, error_pre_print); + + if (job_control + /* If there is no terminal switching for this target, then we can't + possibly get screwed by the lack of job control. */ + || current_target->to_terminal_ours == NULL) + fprintf (stderr, "Quit\n"); + else + fprintf (stderr, + "Quit (expect signal SIGINT when the program is resumed)\n"); + return_to_top_level (RETURN_QUIT); +} + + +#ifdef __GO32__ + +/* In the absence of signals, poll keyboard for a quit. + Called from #define QUIT pollquit() in xm-go32.h. */ + +void +pollquit() +{ + if (kbhit ()) + { + int k = getkey (); + if (k == 1) + quit_flag = 1; + else if (k == 2) + immediate_quit = 1; + quit (); + } +} + +#endif + +/* Control C comes here */ + +void +request_quit (signo) + int signo; +{ + quit_flag = 1; + +#ifdef USG + /* Restore the signal handler. */ + signal (signo, request_quit); +#endif + + if (immediate_quit) + quit (); +} + + +/* Memory management stuff (malloc friends). */ + +#if defined (NO_MMALLOC) + +PTR +mmalloc (md, size) + PTR md; + long size; +{ + return (malloc (size)); +} + +PTR +mrealloc (md, ptr, size) + PTR md; + PTR ptr; + long size; +{ + if (ptr == 0) /* Guard against old realloc's */ + return malloc (size); + else + return realloc (ptr, size); +} + +void +mfree (md, ptr) + PTR md; + PTR ptr; +{ + free (ptr); +} + +#endif /* NO_MMALLOC */ + +#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK) + +void +init_malloc (md) + PTR md; +{ +} + +#else /* have mmalloc and want corruption checking */ + +static void +malloc_botch () +{ + fatal_dump_core ("Memory corruption"); +} + +/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified + by MD, to detect memory corruption. Note that MD may be NULL to specify + the default heap that grows via sbrk. + + Note that for freshly created regions, we must call mmcheck prior to any + mallocs in the region. Otherwise, any region which was allocated prior to + installing the checking hooks, which is later reallocated or freed, will + fail the checks! The mmcheck function only allows initial hooks to be + installed before the first mmalloc. However, anytime after we have called + mmcheck the first time to install the checking hooks, we can call it again + to update the function pointer to the memory corruption handler. + + Returns zero on failure, non-zero on success. */ + +void +init_malloc (md) + PTR md; +{ + if (!mmcheck (md, malloc_botch)) + { + warning ("internal error: failed to install memory consistency checks"); + } + + mmtrace (); +} + +#endif /* Have mmalloc and want corruption checking */ + +/* Called when a memory allocation fails, with the number of bytes of + memory requested in SIZE. */ + +NORETURN void +nomem (size) + long size; +{ + if (size > 0) + { + fatal ("virtual memory exhausted: can't allocate %ld bytes.", size); + } + else + { + fatal ("virtual memory exhausted."); + } +} + +/* Like mmalloc but get error if no storage available, and protect against + the caller wanting to allocate zero bytes. Whether to return NULL for + a zero byte request, or translate the request into a request for one + byte of zero'd storage, is a religious issue. */ + +PTR +xmmalloc (md, size) + PTR md; + long size; +{ + register PTR val; + + if (size == 0) + { + val = NULL; + } + else if ((val = mmalloc (md, size)) == NULL) + { + nomem (size); + } + return (val); +} + +/* Like mrealloc but get error if no storage available. */ + +PTR +xmrealloc (md, ptr, size) + PTR md; + PTR ptr; + long size; +{ + register PTR val; + + if (ptr != NULL) + { + val = mrealloc (md, ptr, size); + } + else + { + val = mmalloc (md, size); + } + if (val == NULL) + { + nomem (size); + } + return (val); +} + +/* Like malloc but get error if no storage available, and protect against + the caller wanting to allocate zero bytes. */ + +PTR +xmalloc (size) + long size; +{ + return (xmmalloc ((PTR) NULL, size)); +} + +/* Like mrealloc but get error if no storage available. */ + +PTR +xrealloc (ptr, size) + PTR ptr; + long size; +{ + return (xmrealloc ((PTR) NULL, ptr, size)); +} + + +/* My replacement for the read system call. + Used like `read' but keeps going if `read' returns too soon. */ + +int +myread (desc, addr, len) + int desc; + char *addr; + int len; +{ + register int val; + int orglen = len; + + while (len > 0) + { + val = read (desc, addr, len); + if (val < 0) + return val; + if (val == 0) + return orglen - len; + len -= val; + addr += val; + } + return orglen; +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char * +savestring (ptr, size) + const char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + memcpy (p, ptr, size); + p[size] = 0; + return p; +} + +char * +msavestring (md, ptr, size) + PTR md; + const char *ptr; + int size; +{ + register char *p = (char *) xmmalloc (md, size + 1); + memcpy (p, ptr, size); + p[size] = 0; + return p; +} + +/* The "const" is so it compiles under DGUX (which prototypes strsave + in . FIXME: This should be named "xstrsave", shouldn't it? + Doesn't real strsave return NULL if out of memory? */ +char * +strsave (ptr) + const char *ptr; +{ + return savestring (ptr, strlen (ptr)); +} + +char * +mstrsave (md, ptr) + PTR md; + const char *ptr; +{ + return (msavestring (md, ptr, strlen (ptr))); +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +/* VARARGS */ +int +query (va_alist) + va_dcl +{ + va_list args; + char *ctlstr; + register int answer; + register int ans2; + + /* Automatically answer "yes" if input is not from a terminal. */ + if (!input_from_terminal_p ()) + return 1; + + while (1) + { + wrap_here (""); /* Flush any buffered output */ + fflush (stdout); + va_start (args); + ctlstr = va_arg (args, char *); + vfprintf_filtered (stdout, ctlstr, args); + va_end (args); + printf_filtered ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer == EOF) /* C-d */ + return 1; + if (answer != '\n') /* Eat rest of input line, to EOF or newline */ + do + { + ans2 = fgetc (stdin); + clearerr (stdin); + } + while (ans2 != EOF && ans2 != '\n'); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + return 1; + if (answer == 'N') + return 0; + printf_filtered ("Please answer y or n.\n"); + } +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + should point to the character after the \. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return 007; /* Bell (alert) char */ + case 'b': + return '\b'; + case 'e': /* Escape character */ + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +/* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that this routine should only + be call for printing things which are independent of the language + of the program being debugged. */ + +void +gdb_printchar (c, stream, quoter) + register int c; + FILE *stream; + int quoter; +{ + + c &= 0xFF; /* Avoid sign bit follies */ + + if ( c < 0x20 || /* Low control chars */ + (c >= 0x7F && c < 0xA0) || /* DEL, High controls */ + (sevenbit_strings && c >= 0x80)) { /* high order bit set */ + switch (c) + { + case '\n': + fputs_filtered ("\\n", stream); + break; + case '\b': + fputs_filtered ("\\b", stream); + break; + case '\t': + fputs_filtered ("\\t", stream); + break; + case '\f': + fputs_filtered ("\\f", stream); + break; + case '\r': + fputs_filtered ("\\r", stream); + break; + case '\033': + fputs_filtered ("\\e", stream); + break; + case '\007': + fputs_filtered ("\\a", stream); + break; + default: + fprintf_filtered (stream, "\\%.3o", (unsigned int) c); + break; + } + } else { + if (c == '\\' || c == quoter) + fputs_filtered ("\\", stream); + fprintf_filtered (stream, "%c", c); + } +} + +/* Number of lines per page or UINT_MAX if paging is disabled. */ +static unsigned int lines_per_page; +/* Number of chars per line or UNIT_MAX is line folding is disabled. */ +static unsigned int chars_per_line; +/* Current count of lines printed on this page, chars on this line. */ +static unsigned int lines_printed, chars_printed; + +/* Buffer and start column of buffered text, for doing smarter word- + wrapping. When someone calls wrap_here(), we start buffering output + that comes through fputs_filtered(). If we see a newline, we just + spit it out and forget about the wrap_here(). If we see another + wrap_here(), we spit it out and remember the newer one. If we see + the end of the line, we spit out a newline, the indent, and then + the buffered output. */ + +/* Malloc'd buffer with chars_per_line+2 bytes. Contains characters which + are waiting to be output (they have already been counted in chars_printed). + When wrap_buffer[0] is null, the buffer is empty. */ +static char *wrap_buffer; + +/* Pointer in wrap_buffer to the next character to fill. */ +static char *wrap_pointer; + +/* String to indent by if the wrap occurs. Must not be NULL if wrap_column + is non-zero. */ +static char *wrap_indent; + +/* Column number on the screen where wrap_buffer begins, or 0 if wrapping + is not in effect. */ +static int wrap_column; + +/* ARGSUSED */ +static void +set_width_command (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + if (!wrap_buffer) + { + wrap_buffer = (char *) xmalloc (chars_per_line + 2); + wrap_buffer[0] = '\0'; + } + else + wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2); + wrap_pointer = wrap_buffer; /* Start it at the beginning */ +} + +/* Wait, so the user can read what's on the screen. Prompt the user + to continue by pressing RETURN. */ + +static void +prompt_for_continue () +{ + char *ignore; + + /* We must do this *before* we call gdb_readline, else it will eventually + call us -- thinking that we're trying to print beyond the end of the + screen. */ + reinitialize_more_filter (); + + immediate_quit++; + /* On a real operating system, the user can quit with SIGINT. + But not on GO32. + + 'q' is provided on all systems so users don't have to change habits + from system to system, and because telling them what to do in + the prompt is more user-friendly than expecting them to think of + SIGINT. */ + ignore = + gdb_readline ("---Type to continue, or q to quit---"); + if (ignore) + { + char *p = ignore; + while (*p == ' ' || *p == '\t') + ++p; + if (p[0] == 'q') + request_quit (SIGINT); + free (ignore); + } + immediate_quit--; + + /* Now we have to do this again, so that GDB will know that it doesn't + need to save the ---Type --- line at the top of the screen. */ + reinitialize_more_filter (); + + dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */ +} + +/* Reinitialize filter; ie. tell it to reset to original values. */ + +void +reinitialize_more_filter () +{ + lines_printed = 0; + chars_printed = 0; +} + +/* Indicate that if the next sequence of characters overflows the line, + a newline should be inserted here rather than when it hits the end. + If INDENT is non-null, it is a string to be printed to indent the + wrapped part on the next line. INDENT must remain accessible until + the next call to wrap_here() or until a newline is printed through + fputs_filtered(). + + If the line is already overfull, we immediately print a newline and + the indentation, and disable further wrapping. + + If we don't know the width of lines, but we know the page height, + we must not wrap words, but should still keep track of newlines + that were explicitly printed. + + INDENT should not contain tabs, as that will mess up the char count + on the next line. FIXME. + + This routine is guaranteed to force out any output which has been + squirreled away in the wrap_buffer, so wrap_here ((char *)0) can be + used to force out output from the wrap_buffer. */ + +void +wrap_here(indent) + char *indent; +{ + if (wrap_buffer[0]) + { + *wrap_pointer = '\0'; + fputs (wrap_buffer, stdout); + } + wrap_pointer = wrap_buffer; + wrap_buffer[0] = '\0'; + if (chars_per_line == UINT_MAX) /* No line overflow checking */ + { + wrap_column = 0; + } + else if (chars_printed >= chars_per_line) + { + puts_filtered ("\n"); + if (indent != NULL) + puts_filtered (indent); + wrap_column = 0; + } + else + { + wrap_column = chars_printed; + if (indent == NULL) + wrap_indent = ""; + else + wrap_indent = indent; + } +} + +/* Ensure that whatever gets printed next, using the filtered output + commands, starts at the beginning of the line. I.E. if there is + any pending output for the current line, flush it and start a new + line. Otherwise do nothing. */ + +void +begin_line () +{ + if (chars_printed > 0) + { + puts_filtered ("\n"); + } +} + +/* Like fputs but pause after every screenful, and can wrap at points + other than the final character of a line. + Unlike fputs, fputs_filtered does not return a value. + It is OK for LINEBUFFER to be NULL, in which case just don't print + anything. + + Note that a longjmp to top level may occur in this routine + (since prompt_for_continue may do so) so this routine should not be + called when cleanups are not in place. */ + +void +fputs_filtered (linebuffer, stream) + const char *linebuffer; + FILE *stream; +{ + const char *lineptr; + + if (linebuffer == 0) + return; + + /* Don't do any filtering if it is disabled. */ + if (stream != stdout + || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)) + { + fputs (linebuffer, stream); + return; + } + + /* Go through and output each character. Show line extension + when this is necessary; prompt user for new page when this is + necessary. */ + + lineptr = linebuffer; + while (*lineptr) + { + /* Possible new page. */ + if (lines_printed >= lines_per_page - 1) + prompt_for_continue (); + + while (*lineptr && *lineptr != '\n') + { + /* Print a single line. */ + if (*lineptr == '\t') + { + if (wrap_column) + *wrap_pointer++ = '\t'; + else + putc ('\t', stream); + /* Shifting right by 3 produces the number of tab stops + we have already passed, and then adding one and + shifting left 3 advances to the next tab stop. */ + chars_printed = ((chars_printed >> 3) + 1) << 3; + lineptr++; + } + else + { + if (wrap_column) + *wrap_pointer++ = *lineptr; + else + putc (*lineptr, stream); + chars_printed++; + lineptr++; + } + + if (chars_printed >= chars_per_line) + { + unsigned int save_chars = chars_printed; + + chars_printed = 0; + lines_printed++; + /* If we aren't actually wrapping, don't output newline -- + if chars_per_line is right, we probably just overflowed + anyway; if it's wrong, let us keep going. */ + if (wrap_column) + putc ('\n', stream); + + /* Possible new page. */ + if (lines_printed >= lines_per_page - 1) + prompt_for_continue (); + + /* Now output indentation and wrapped string */ + if (wrap_column) + { + fputs (wrap_indent, stream); + *wrap_pointer = '\0'; /* Null-terminate saved stuff */ + fputs (wrap_buffer, stream); /* and eject it */ + /* FIXME, this strlen is what prevents wrap_indent from + containing tabs. However, if we recurse to print it + and count its chars, we risk trouble if wrap_indent is + longer than (the user settable) chars_per_line. + Note also that this can set chars_printed > chars_per_line + if we are printing a long string. */ + chars_printed = strlen (wrap_indent) + + (save_chars - wrap_column); + wrap_pointer = wrap_buffer; /* Reset buffer */ + wrap_buffer[0] = '\0'; + wrap_column = 0; /* And disable fancy wrap */ + } + } + } + + if (*lineptr == '\n') + { + chars_printed = 0; + wrap_here ((char *)0); /* Spit out chars, cancel further wraps */ + lines_printed++; + putc ('\n', stream); + lineptr++; + } + } +} + +/* Print a variable number of ARGS using format FORMAT. If this + information is going to put the amount written (since the last call + to REINITIALIZE_MORE_FILTER or the last page break) over the page size, + print out a pause message and do a gdb_readline to get the users + permision to continue. + + Unlike fprintf, this function does not return a value. + + We implement three variants, vfprintf (takes a vararg list and stream), + fprintf (takes a stream to write on), and printf (the usual). + + Note that this routine has a restriction that the length of the + final output line must be less than 255 characters *or* it must be + less than twice the size of the format string. This is a very + arbitrary restriction, but it is an internal restriction, so I'll + put it in. This means that the %s format specifier is almost + useless; unless the caller can GUARANTEE that the string is short + enough, fputs_filtered should be used instead. + + Note also that a longjmp to top level may occur in this routine + (since prompt_for_continue may do so) so this routine should not be + called when cleanups are not in place. */ + +#define MIN_LINEBUF 255 + +void +vfprintf_filtered (stream, format, args) + FILE *stream; + char *format; + va_list args; +{ + char line_buf[MIN_LINEBUF+10]; + char *linebuffer = line_buf; + int format_length; + + format_length = strlen (format); + + /* Reallocate buffer to a larger size if this is necessary. */ + if (format_length * 2 > MIN_LINEBUF) + { + linebuffer = alloca (10 + format_length * 2); + } + + /* This won't blow up if the restrictions described above are + followed. */ + vsprintf (linebuffer, format, args); + + fputs_filtered (linebuffer, stream); +} + +void +vprintf_filtered (format, args) + char *format; + va_list args; +{ + vfprintf_filtered (stdout, format, args); +} + +/* VARARGS */ +void +fprintf_filtered (va_alist) + va_dcl +{ + va_list args; + FILE *stream; + char *format; + + va_start (args); + stream = va_arg (args, FILE *); + format = va_arg (args, char *); + + /* This won't blow up if the restrictions described above are + followed. */ + vfprintf_filtered (stream, format, args); + va_end (args); +} + +/* Like fprintf_filtered, but prints it's result indent. + Called as fprintfi_filtered (spaces, stream, format, ...); */ + +/* VARARGS */ +void +fprintfi_filtered (va_alist) + va_dcl +{ + va_list args; + int spaces; + FILE *stream; + char *format; + + va_start (args); + spaces = va_arg (args, int); + stream = va_arg (args, FILE *); + format = va_arg (args, char *); + print_spaces_filtered (spaces, stream); + + /* This won't blow up if the restrictions described above are + followed. */ + vfprintf_filtered (stream, format, args); + va_end (args); +} + +/* VARARGS */ +void +printf_filtered (va_alist) + va_dcl +{ + va_list args; + char *format; + + va_start (args); + format = va_arg (args, char *); + + vfprintf_filtered (stdout, format, args); + va_end (args); +} + +/* Like printf_filtered, but prints it's result indented. + Called as printfi_filtered (spaces, format, ...); */ + +/* VARARGS */ +void +printfi_filtered (va_alist) + va_dcl +{ + va_list args; + int spaces; + char *format; + + va_start (args); + spaces = va_arg (args, int); + format = va_arg (args, char *); + print_spaces_filtered (spaces, stdout); + vfprintf_filtered (stdout, format, args); + va_end (args); +} + +/* Easy -- but watch out! + + This routine is *not* a replacement for puts()! puts() appends a newline. + This one doesn't, and had better not! */ + +void +puts_filtered (string) + char *string; +{ + fputs_filtered (string, stdout); +} + +/* Return a pointer to N spaces and a null. The pointer is good + until the next call to here. */ +char * +n_spaces (n) + int n; +{ + register char *t; + static char *spaces; + static int max_spaces; + + if (n > max_spaces) + { + if (spaces) + free (spaces); + spaces = (char *) xmalloc (n+1); + for (t = spaces+n; t != spaces;) + *--t = ' '; + spaces[n] = '\0'; + max_spaces = n; + } + + return spaces + max_spaces - n; +} + +/* Print N spaces. */ +void +print_spaces_filtered (n, stream) + int n; + FILE *stream; +{ + fputs_filtered (n_spaces (n), stream); +} + +/* C++ demangler stuff. */ + +/* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language + LANG, using demangling args ARG_MODE, and print it filtered to STREAM. + If the name is not mangled, or the language for the name is unknown, or + demangling is off, the name is printed in its "raw" form. */ + +void +fprintf_symbol_filtered (stream, name, lang, arg_mode) + FILE *stream; + char *name; + enum language lang; + int arg_mode; +{ + char *demangled; + + if (name != NULL) + { + /* If user wants to see raw output, no problem. */ + if (!demangle) + { + fputs_filtered (name, stream); + } + else + { + switch (lang) + { + case language_cplus: + demangled = cplus_demangle (name, arg_mode); + break; + case language_chill: + demangled = chill_demangle (name); + break; + default: + demangled = NULL; + break; + } + fputs_filtered (demangled ? demangled : name, stream); + if (demangled != NULL) + { + free (demangled); + } + } + } +} + +/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any + differences in whitespace. Returns 0 if they match, non-zero if they + don't (slightly different than strcmp()'s range of return values). + + As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO". + This "feature" is useful when searching for matching C++ function names + (such as if the user types 'break FOO', where FOO is a mangled C++ + function). */ + +int +strcmp_iw (string1, string2) + const char *string1; + const char *string2; +{ + while ((*string1 != '\0') && (*string2 != '\0')) + { + while (isspace (*string1)) + { + string1++; + } + while (isspace (*string2)) + { + string2++; + } + if (*string1 != *string2) + { + break; + } + if (*string1 != '\0') + { + string1++; + string2++; + } + } + return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0'); +} + + +void +_initialize_utils () +{ + struct cmd_list_element *c; + + c = add_set_cmd ("width", class_support, var_uinteger, + (char *)&chars_per_line, + "Set number of characters gdb thinks are in a line.", + &setlist); + add_show_from_set (c, &showlist); + c->function.sfunc = set_width_command; + + add_show_from_set + (add_set_cmd ("height", class_support, + var_uinteger, (char *)&lines_per_page, + "Set number of lines gdb thinks are in a page.", &setlist), + &showlist); + + /* These defaults will be used if we are unable to get the correct + values from termcap. */ +#if defined(__GO32__) + lines_per_page = ScreenRows(); + chars_per_line = ScreenCols(); +#else + lines_per_page = 24; + chars_per_line = 80; + /* Initialize the screen height and width from termcap. */ + { + char *termtype = getenv ("TERM"); + + /* Positive means success, nonpositive means failure. */ + int status; + + /* 2048 is large enough for all known terminals, according to the + GNU termcap manual. */ + char term_buffer[2048]; + + if (termtype) + { + status = tgetent (term_buffer, termtype); + if (status > 0) + { + int val; + + val = tgetnum ("li"); + if (val >= 0) + lines_per_page = val; + else + /* The number of lines per page is not mentioned + in the terminal description. This probably means + that paging is not useful (e.g. emacs shell window), + so disable paging. */ + lines_per_page = UINT_MAX; + + val = tgetnum ("co"); + if (val >= 0) + chars_per_line = val; + } + } + } + +#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) + + /* If there is a better way to determine the window size, use it. */ + SIGWINCH_HANDLER (); +#endif +#endif + /* If the output is not a terminal, don't paginate it. */ + if (!ISATTY (stdout)) + lines_per_page = UINT_MAX; + + set_width_command ((char *)NULL, 0, c); + + add_show_from_set + (add_set_cmd ("demangle", class_support, var_boolean, + (char *)&demangle, + "Set demangling of encoded C++ names when displaying symbols.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("sevenbit-strings", class_support, var_boolean, + (char *)&sevenbit_strings, + "Set printing of 8-bit characters in strings as \\nnn.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("asm-demangle", class_support, var_boolean, + (char *)&asm_demangle, + "Set demangling of C++ names in disassembly listings.", + &setprintlist), + &showprintlist); +} + +/* Machine specific function to handle SIGWINCH signal. */ + +#ifdef SIGWINCH_HANDLER_BODY + SIGWINCH_HANDLER_BODY +#endif + diff --git a/gnu/usr.bin/gdb/gdb/valarith.c b/gnu/usr.bin/gdb/gdb/valarith.c new file mode 100644 index 00000000000..3711a150d28 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/valarith.c @@ -0,0 +1,969 @@ +/* Perform arithmetic and other operations on values, for GDB. + Copyright 1986, 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. */ + +#include "defs.h" +#include "value.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "target.h" +#include "language.h" +#include + +/* Define whether or not the C operator '/' truncates towards zero for + differently signed operands (truncation direction is undefined in C). */ + +#ifndef TRUNCATION_TOWARDS_ZERO +#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2) +#endif + +static value +value_subscripted_rvalue PARAMS ((value, value)); + + +value +value_add (arg1, arg2) + value arg1, arg2; +{ + register value valint, valptr; + register int len; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR) + && + (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT + || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)) + /* Exactly one argument is a pointer, and one is an integer. */ + { + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) + { + valptr = arg1; + valint = arg2; + } + else + { + valptr = arg2; + valint = arg1; + } + len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr))); + if (len == 0) len = 1; /* For (void *) */ + return value_from_longest (VALUE_TYPE (valptr), + value_as_long (valptr) + + (len * value_as_long (valint))); + } + + return value_binop (arg1, arg2, BINOP_ADD); +} + +value +value_sub (arg1, arg2) + value arg1, arg2; +{ + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) + { + if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT) + { + /* pointer - integer. */ + return value_from_longest + (VALUE_TYPE (arg1), + value_as_long (arg1) + - (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) + * value_as_long (arg2))); + } + else if (VALUE_TYPE (arg1) == VALUE_TYPE (arg2)) + { + /* pointer to - pointer to . */ + return value_from_longest + (builtin_type_long, /* FIXME -- should be ptrdiff_t */ + (value_as_long (arg1) - value_as_long (arg2)) + / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))); + } + else + { + error ("\ +First argument of `-' is a pointer and second argument is neither\n\ +an integer nor a pointer of the same type."); + } + } + + return value_binop (arg1, arg2, BINOP_SUB); +} + +/* Return the value of ARRAY[IDX]. + See comments in value_coerce_array() for rationale for reason for + doing lower bounds adjustment here rather than there. + FIXME: Perhaps we should validate that the index is valid and if + verbosity is set, warn about invalid indices (but still use them). */ + +value +value_subscript (array, idx) + value array, idx; +{ + int lowerbound; + value bound; + struct type *range_type; + + COERCE_REF (array); + + if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY) + { + range_type = TYPE_FIELD_TYPE (VALUE_TYPE (array), 0); + lowerbound = TYPE_FIELD_BITPOS (range_type, 0); + if (lowerbound != 0) + { + bound = value_from_longest (builtin_type_int, (LONGEST) lowerbound); + idx = value_sub (idx, bound); + } + if (VALUE_LVAL (array) != lval_memory) + { + return value_subscripted_rvalue (array, idx); + } + } + return value_ind (value_add (array, idx)); +} + +/* Return the value of EXPR[IDX], expr an aggregate rvalue + (eg, a vector register). This routine used to promote floats + to doubles, but no longer does. */ + +static value +value_subscripted_rvalue (array, idx) + value array, idx; +{ + struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array)); + int elt_size = TYPE_LENGTH (elt_type); + int elt_offs = elt_size * longest_to_int (value_as_long (idx)); + value v; + + if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array))) + error ("no such vector element"); + + v = allocate_value (elt_type); + memcpy (VALUE_CONTENTS (v), VALUE_CONTENTS (array) + elt_offs, elt_size); + + if (VALUE_LVAL (array) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + else + VALUE_LVAL (v) = not_lval; + VALUE_ADDRESS (v) = VALUE_ADDRESS (array); + VALUE_OFFSET (v) = VALUE_OFFSET (array) + elt_offs; + VALUE_BITSIZE (v) = elt_size * 8; + return v; +} + +/* Check to see if either argument is a structure. This is called so + we know whether to go ahead with the normal binop or look for a + user defined function instead. + + For now, we do not overload the `=' operator. */ + +int +binop_user_defined_p (op, arg1, arg2) + enum exp_opcode op; + value arg1, arg2; +{ + if (op == BINOP_ASSIGN) + return 0; + return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT + || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_STRUCT + || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF + && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT) + || (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_REF + && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_STRUCT)); +} + +/* Check to see if argument is a structure. This is called so + we know whether to go ahead with the normal unop or look for a + user defined function instead. + + For now, we do not overload the `&' operator. */ + +int unop_user_defined_p (op, arg1) + enum exp_opcode op; + value arg1; +{ + if (op == UNOP_ADDR) + return 0; + return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT + || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF + && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT)); +} + +/* We know either arg1 or arg2 is a structure, so try to find the right + user defined function. Create an argument vector that calls + arg1.operator @ (arg1,arg2) and return that value (where '@' is any + binary operator which is legal for GNU C++). + + OP is the operatore, and if it is BINOP_ASSIGN_MODIFY, then OTHEROP + is the opcode saying how to modify it. Otherwise, OTHEROP is + unused. */ + +value +value_x_binop (arg1, arg2, op, otherop) + value arg1, arg2; + enum exp_opcode op, otherop; +{ + value * argvec; + char *ptr; + char tstr[13]; + int static_memfuncp; + + COERCE_REF (arg1); + COERCE_REF (arg2); + COERCE_ENUM (arg1); + COERCE_ENUM (arg2); + + /* now we know that what we have to do is construct our + arg vector and find the right function to call it with. */ + + if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT) + error ("Can't do that binary op on that type"); /* FIXME be explicit */ + + argvec = (value *) alloca (sizeof (value) * 4); + argvec[1] = value_addr (arg1); + argvec[2] = arg2; + argvec[3] = 0; + + /* make the right function name up */ + strcpy(tstr, "operator__"); + ptr = tstr+8; + switch (op) + { + case BINOP_ADD: strcpy(ptr,"+"); break; + case BINOP_SUB: strcpy(ptr,"-"); break; + case BINOP_MUL: strcpy(ptr,"*"); break; + case BINOP_DIV: strcpy(ptr,"/"); break; + case BINOP_REM: strcpy(ptr,"%"); break; + case BINOP_LSH: strcpy(ptr,"<<"); break; + case BINOP_RSH: strcpy(ptr,">>"); break; + case BINOP_BITWISE_AND: strcpy(ptr,"&"); break; + case BINOP_BITWISE_IOR: strcpy(ptr,"|"); break; + case BINOP_BITWISE_XOR: strcpy(ptr,"^"); break; + case BINOP_LOGICAL_AND: strcpy(ptr,"&&"); break; + case BINOP_LOGICAL_OR: strcpy(ptr,"||"); break; + case BINOP_MIN: strcpy(ptr,"?"); break; + case BINOP_ASSIGN: strcpy(ptr,"="); break; + case BINOP_ASSIGN_MODIFY: + switch (otherop) + { + case BINOP_ADD: strcpy(ptr,"+="); break; + case BINOP_SUB: strcpy(ptr,"-="); break; + case BINOP_MUL: strcpy(ptr,"*="); break; + case BINOP_DIV: strcpy(ptr,"/="); break; + case BINOP_REM: strcpy(ptr,"%="); break; + case BINOP_BITWISE_AND: strcpy(ptr,"&="); break; + case BINOP_BITWISE_IOR: strcpy(ptr,"|="); break; + case BINOP_BITWISE_XOR: strcpy(ptr,"^="); break; + case BINOP_MOD: /* invalid */ + default: + error ("Invalid binary operation specified."); + } + break; + case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break; + case BINOP_EQUAL: strcpy(ptr,"=="); break; + case BINOP_NOTEQUAL: strcpy(ptr,"!="); break; + case BINOP_LESS: strcpy(ptr,"<"); break; + case BINOP_GTR: strcpy(ptr,">"); break; + case BINOP_GEQ: strcpy(ptr,">="); break; + case BINOP_LEQ: strcpy(ptr,"<="); break; + case BINOP_MOD: /* invalid */ + default: + error ("Invalid binary operation specified."); + } + argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure"); + if (argvec[0]) + { + if (static_memfuncp) + { + argvec[1] = argvec[0]; + argvec++; + } + return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1); + } + error ("member function %s not found", tstr); +#ifdef lint + return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1); +#endif +} + +/* We know that arg1 is a structure, so try to find a unary user + defined operator that matches the operator in question. + Create an argument vector that calls arg1.operator @ (arg1) + and return that value (where '@' is (almost) any unary operator which + is legal for GNU C++). */ + +value +value_x_unop (arg1, op) + value arg1; + enum exp_opcode op; +{ + value * argvec; + char *ptr; + char tstr[13]; + int static_memfuncp; + + COERCE_ENUM (arg1); + + /* now we know that what we have to do is construct our + arg vector and find the right function to call it with. */ + + if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT) + error ("Can't do that unary op on that type"); /* FIXME be explicit */ + + argvec = (value *) alloca (sizeof (value) * 3); + argvec[1] = value_addr (arg1); + argvec[2] = 0; + + /* make the right function name up */ + strcpy(tstr,"operator__"); + ptr = tstr+8; + switch (op) + { + case UNOP_PREINCREMENT: strcpy(ptr,"++"); break; + case UNOP_PREDECREMENT: strcpy(ptr,"++"); break; + case UNOP_POSTINCREMENT: strcpy(ptr,"++"); break; + case UNOP_POSTDECREMENT: strcpy(ptr,"++"); break; + case UNOP_LOGICAL_NOT: strcpy(ptr,"!"); break; + case UNOP_COMPLEMENT: strcpy(ptr,"~"); break; + case UNOP_NEG: strcpy(ptr,"-"); break; + default: + error ("Invalid binary operation specified."); + } + argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure"); + if (argvec[0]) + { + if (static_memfuncp) + { + argvec[1] = argvec[0]; + argvec++; + } + return call_function_by_hand (argvec[0], 1 - static_memfuncp, argvec + 1); + } + error ("member function %s not found", tstr); + return 0; /* For lint -- never reached */ +} + + +/* Concatenate two values with the following conditions: + + (1) Both values must be either bitstring values or character string + values and the resulting value consists of the concatenation of + ARG1 followed by ARG2. + + or + + One value must be an integer value and the other value must be + either a bitstring value or character string value, which is + to be repeated by the number of times specified by the integer + value. + + + (2) Boolean values are also allowed and are treated as bit string + values of length 1. + + (3) Character values are also allowed and are treated as character + string values of length 1. +*/ + +value +value_concat (arg1, arg2) + value arg1, arg2; +{ + register value inval1, inval2, outval; + int inval1len, inval2len; + int count, idx; + char *ptr; + char inchar; + + /* First figure out if we are dealing with two values to be concatenated + or a repeat count and a value to be repeated. INVAL1 is set to the + first of two concatenated values, or the repeat count. INVAL2 is set + to the second of the two concatenated values or the value to be + repeated. */ + + if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT) + { + inval1 = arg2; + inval2 = arg1; + } + else + { + inval1 = arg1; + inval2 = arg2; + } + + /* Now process the input values. */ + + if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_INT) + { + /* We have a repeat count. Validate the second value and then + construct a value repeated that many times. */ + if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_STRING + || TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR) + { + count = longest_to_int (value_as_long (inval1)); + inval2len = TYPE_LENGTH (VALUE_TYPE (inval2)); + ptr = (char *) alloca (count * inval2len); + if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR) + { + inchar = (char) unpack_long (VALUE_TYPE (inval2), + VALUE_CONTENTS (inval2)); + for (idx = 0; idx < count; idx++) + { + *(ptr + idx) = inchar; + } + } + else + { + for (idx = 0; idx < count; idx++) + { + memcpy (ptr + (idx * inval2len), VALUE_CONTENTS (inval2), + inval2len); + } + } + outval = value_string (ptr, count * inval2len); + } + else if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_BITSTRING + || TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_BOOL) + { + error ("unimplemented support for bitstring/boolean repeats"); + } + else + { + error ("can't repeat values of that type"); + } + } + else if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_STRING + || TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_CHAR) + { + /* We have two character strings to concatenate. */ + if (TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_STRING + && TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_CHAR) + { + error ("Strings can only be concatenated with other strings."); + } + inval1len = TYPE_LENGTH (VALUE_TYPE (inval1)); + inval2len = TYPE_LENGTH (VALUE_TYPE (inval2)); + ptr = (char *) alloca (inval1len + inval2len); + if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_CHAR) + { + *ptr = (char) unpack_long (VALUE_TYPE (inval1), VALUE_CONTENTS (inval1)); + } + else + { + memcpy (ptr, VALUE_CONTENTS (inval1), inval1len); + } + if (TYPE_CODE (VALUE_TYPE (inval2)) == TYPE_CODE_CHAR) + { + *(ptr + inval1len) = + (char) unpack_long (VALUE_TYPE (inval2), VALUE_CONTENTS (inval2)); + } + else + { + memcpy (ptr + inval1len, VALUE_CONTENTS (inval2), inval2len); + } + outval = value_string (ptr, inval1len + inval2len); + } + else if (TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_BITSTRING + || TYPE_CODE (VALUE_TYPE (inval1)) == TYPE_CODE_BOOL) + { + /* We have two bitstrings to concatenate. */ + if (TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_BITSTRING + && TYPE_CODE (VALUE_TYPE (inval2)) != TYPE_CODE_BOOL) + { + error ("Bitstrings or booleans can only be concatenated with other bitstrings or booleans."); + } + error ("unimplemented support for bitstring/boolean concatenation."); + } + else + { + /* We don't know how to concatenate these operands. */ + error ("illegal operands for concatenation."); + } + return (outval); +} + + +/* Perform a binary operation on two operands which have reasonable + representations as integers or floats. This includes booleans, + characters, integers, or floats. + Does not support addition and subtraction on pointers; + use value_add or value_sub if you want to handle those possibilities. */ + +value +value_binop (arg1, arg2, op) + value arg1, arg2; + enum exp_opcode op; +{ + register value val; + + COERCE_ENUM (arg1); + COERCE_ENUM (arg2); + + if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT + && + TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_CHAR + && + TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT + && + TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_BOOL) + || + (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT + && + TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_CHAR + && + TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT + && + TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_BOOL)) + error ("Argument to arithmetic operation not a number or boolean."); + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT + || + TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT) + { + double v1, v2, v; + v1 = value_as_double (arg1); + v2 = value_as_double (arg2); + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + default: + error ("Integer-only operation on floating point number."); + } + + val = allocate_value (builtin_type_double); + SWAP_TARGET_AND_HOST (&v, sizeof (v)); + *(double *) VALUE_CONTENTS_RAW (val) = v; + } + else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_BOOL + && + TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_BOOL) + { + LONGEST v1, v2, v; + v1 = value_as_long (arg1); + v2 = value_as_long (arg2); + + switch (op) + { + case BINOP_BITWISE_AND: + v = v1 & v2; + break; + + case BINOP_BITWISE_IOR: + v = v1 | v2; + break; + + case BINOP_BITWISE_XOR: + v = v1 ^ v2; + break; + + default: + error ("Invalid operation on booleans."); + } + + val = allocate_value (builtin_type_chill_bool); + store_signed_integer (VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val)), + v); + } + else + /* Integral operations here. */ + /* FIXME: Also mixed integral/booleans, with result an integer. */ + { + /* Should we promote to unsigned longest? */ + if ((TYPE_UNSIGNED (VALUE_TYPE (arg1)) + || TYPE_UNSIGNED (VALUE_TYPE (arg2))) + && (TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST) + || TYPE_LENGTH (VALUE_TYPE (arg2)) >= sizeof (unsigned LONGEST))) + { + unsigned LONGEST v1, v2, v; + v1 = (unsigned LONGEST) value_as_long (arg1); + v2 = (unsigned LONGEST) value_as_long (arg2); + + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + case BINOP_REM: + v = v1 % v2; + break; + + case BINOP_MOD: + /* Knuth 1.2.4, integer only. Note that unlike the C '%' op, + v1 mod 0 has a defined value, v1. */ + /* Chill specifies that v2 must be > 0, so check for that. */ + if (current_language -> la_language == language_chill + && value_as_long (arg2) <= 0) + { + error ("Second operand of MOD must be greater than zero."); + } + if (v2 == 0) + { + v = v1; + } + else + { + v = v1/v2; + /* Note floor(v1/v2) == v1/v2 for unsigned. */ + v = v1 - (v2 * v); + } + break; + + case BINOP_LSH: + v = v1 << v2; + break; + + case BINOP_RSH: + v = v1 >> v2; + break; + + case BINOP_BITWISE_AND: + v = v1 & v2; + break; + + case BINOP_BITWISE_IOR: + v = v1 | v2; + break; + + case BINOP_BITWISE_XOR: + v = v1 ^ v2; + break; + + case BINOP_LOGICAL_AND: + v = v1 && v2; + break; + + case BINOP_LOGICAL_OR: + v = v1 || v2; + break; + + case BINOP_MIN: + v = v1 < v2 ? v1 : v2; + break; + + case BINOP_MAX: + v = v1 > v2 ? v1 : v2; + break; + + default: + error ("Invalid binary operation on numbers."); + } + + val = allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST); + store_unsigned_integer (VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val)), + v); + } + else + { + LONGEST v1, v2, v; + v1 = value_as_long (arg1); + v2 = value_as_long (arg2); + + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + case BINOP_REM: + v = v1 % v2; + break; + + case BINOP_MOD: + /* Knuth 1.2.4, integer only. Note that unlike the C '%' op, + X mod 0 has a defined value, X. */ + /* Chill specifies that v2 must be > 0, so check for that. */ + if (current_language -> la_language == language_chill + && v2 <= 0) + { + error ("Second operand of MOD must be greater than zero."); + } + if (v2 == 0) + { + v = v1; + } + else + { + v = v1/v2; + /* Compute floor. */ + if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0)) + { + v--; + } + v = v1 - (v2 * v); + } + break; + + case BINOP_LSH: + v = v1 << v2; + break; + + case BINOP_RSH: + v = v1 >> v2; + break; + + case BINOP_BITWISE_AND: + v = v1 & v2; + break; + + case BINOP_BITWISE_IOR: + v = v1 | v2; + break; + + case BINOP_BITWISE_XOR: + v = v1 ^ v2; + break; + + case BINOP_LOGICAL_AND: + v = v1 && v2; + break; + + case BINOP_LOGICAL_OR: + v = v1 || v2; + break; + + case BINOP_MIN: + v = v1 < v2 ? v1 : v2; + break; + + case BINOP_MAX: + v = v1 > v2 ? v1 : v2; + break; + + default: + error ("Invalid binary operation on numbers."); + } + + val = allocate_value (BUILTIN_TYPE_LONGEST); + store_signed_integer (VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val)), + v); + } + } + + return val; +} + +/* Simulate the C operator ! -- return 1 if ARG1 contains zero. */ + +int +value_logical_not (arg1) + value arg1; +{ + register int len; + register char *p; + + COERCE_ARRAY (arg1); + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT) + return 0 == value_as_double (arg1); + + len = TYPE_LENGTH (VALUE_TYPE (arg1)); + p = VALUE_CONTENTS (arg1); + + while (--len >= 0) + { + if (*p++) + break; + } + + return len < 0; +} + +/* Simulate the C operator == by returning a 1 + iff ARG1 and ARG2 have equal contents. */ + +int +value_equal (arg1, arg2) + register value arg1, arg2; + +{ + register int len; + register char *p1, *p2; + enum type_code code1; + enum type_code code2; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + code1 = TYPE_CODE (VALUE_TYPE (arg1)); + code2 = TYPE_CODE (VALUE_TYPE (arg2)); + + if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) + return value_as_long (arg1) == value_as_long (arg2); + else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) + return value_as_double (arg1) == value_as_double (arg2); + + /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever + is bigger. */ + else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT) + return value_as_pointer (arg1) == (CORE_ADDR) value_as_long (arg2); + else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT) + return (CORE_ADDR) value_as_long (arg1) == value_as_pointer (arg2); + + else if (code1 == code2 + && ((len = TYPE_LENGTH (VALUE_TYPE (arg1))) + == TYPE_LENGTH (VALUE_TYPE (arg2)))) + { + p1 = VALUE_CONTENTS (arg1); + p2 = VALUE_CONTENTS (arg2); + while (--len >= 0) + { + if (*p1++ != *p2++) + break; + } + return len < 0; + } + else + { + error ("Invalid type combination in equality test."); + return 0; /* For lint -- never reached */ + } +} + +/* Simulate the C operator < by returning 1 + iff ARG1's contents are less than ARG2's. */ + +int +value_less (arg1, arg2) + register value arg1, arg2; +{ + register enum type_code code1; + register enum type_code code2; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + code1 = TYPE_CODE (VALUE_TYPE (arg1)); + code2 = TYPE_CODE (VALUE_TYPE (arg2)); + + if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) + { + if (TYPE_UNSIGNED (VALUE_TYPE (arg1)) + || TYPE_UNSIGNED (VALUE_TYPE (arg2))) + return ((unsigned LONGEST) value_as_long (arg1) + < (unsigned LONGEST) value_as_long (arg2)); + else + return value_as_long (arg1) < value_as_long (arg2); + } + else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) + return value_as_double (arg1) < value_as_double (arg2); + else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) + return value_as_pointer (arg1) < value_as_pointer (arg2); + + /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever + is bigger. */ + else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT) + return value_as_pointer (arg1) < (CORE_ADDR) value_as_long (arg2); + else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT) + return (CORE_ADDR) value_as_long (arg1) < value_as_pointer (arg2); + + else + { + error ("Invalid type combination in ordering comparison."); + return 0; + } +} + +/* The unary operators - and ~. Both free the argument ARG1. */ + +value +value_neg (arg1) + register value arg1; +{ + register struct type *type; + + COERCE_ENUM (arg1); + + type = VALUE_TYPE (arg1); + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + return value_from_double (type, - value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_INT) + return value_from_longest (type, - value_as_long (arg1)); + else { + error ("Argument to negate operation not a number."); + return 0; /* For lint -- never reached */ + } +} + +value +value_complement (arg1) + register value arg1; +{ + COERCE_ENUM (arg1); + + if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT) + error ("Argument to complement operation not an integer."); + + return value_from_longest (VALUE_TYPE (arg1), ~ value_as_long (arg1)); +} + diff --git a/gnu/usr.bin/gdb/gdb/valops.c b/gnu/usr.bin/gdb/gdb/valops.c new file mode 100644 index 00000000000..dc4d82a8651 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/valops.c @@ -0,0 +1,1819 @@ +/* Perform non-arithmetic operations on values, for GDB. + Copyright 1986, 1987, 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" +#include "demangle.h" +#include "language.h" + +#include + +/* Local functions. */ + +static int +typecmp PARAMS ((int staticp, struct type *t1[], value t2[])); + +static CORE_ADDR +find_function_addr PARAMS ((value, struct type **)); + +static CORE_ADDR +value_push PARAMS ((CORE_ADDR, value)); + +static CORE_ADDR +value_arg_push PARAMS ((CORE_ADDR, value)); + +static value +search_struct_field PARAMS ((char *, value, int, struct type *, int)); + +static value +search_struct_method PARAMS ((char *, value *, value *, int, int *, + struct type *)); + +static int +check_field_in PARAMS ((struct type *, const char *)); + +static CORE_ADDR +allocate_space_in_inferior PARAMS ((int)); + + +/* Allocate NBYTES of space in the inferior using the inferior's malloc + and return a value that is a pointer to the allocated space. */ + +static CORE_ADDR +allocate_space_in_inferior (len) + int len; +{ + register value val; + register struct symbol *sym; + struct minimal_symbol *msymbol; + struct type *type; + value blocklen; + LONGEST maddr; + + /* Find the address of malloc in the inferior. */ + + sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE, 0, NULL); + if (sym != NULL) + { + if (SYMBOL_CLASS (sym) != LOC_BLOCK) + { + error ("\"malloc\" exists in this program but is not a function."); + } + val = value_of_variable (sym, NULL); + } + else + { + msymbol = lookup_minimal_symbol ("malloc", (struct objfile *) NULL); + if (msymbol != NULL) + { + type = lookup_pointer_type (builtin_type_char); + type = lookup_function_type (type); + type = lookup_pointer_type (type); + maddr = (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol); + val = value_from_longest (type, maddr); + } + else + { + error ("evaluation of this expression requires the program to have a function \"malloc\"."); + } + } + + blocklen = value_from_longest (builtin_type_int, (LONGEST) len); + val = call_function_by_hand (val, 1, &blocklen); + if (value_logical_not (val)) + { + error ("No memory available to program."); + } + return (value_as_long (val)); +} + +/* Cast value ARG2 to type TYPE and return as a value. + More general than a C cast: accepts any two types of the same length, + and if ARG2 is an lvalue it can be cast into anything at all. */ +/* In C++, casts may change pointer or object representations. */ + +value +value_cast (type, arg2) + struct type *type; + register value arg2; +{ + register enum type_code code1; + register enum type_code code2; + register int scalar; + + /* Coerce arrays but not enums. Enums will work as-is + and coercing them would cause an infinite recursion. */ + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_ENUM) + COERCE_ARRAY (arg2); + + code1 = TYPE_CODE (type); + code2 = TYPE_CODE (VALUE_TYPE (arg2)); + scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT + || code2 == TYPE_CODE_ENUM); + + if ( code1 == TYPE_CODE_STRUCT + && code2 == TYPE_CODE_STRUCT + && TYPE_NAME (type) != 0) + { + /* Look in the type of the source to see if it contains the + type of the target as a superclass. If so, we'll need to + offset the object in addition to changing its type. */ + value v = search_struct_field (type_name_no_tag (type), + arg2, 0, VALUE_TYPE (arg2), 1); + if (v) + { + VALUE_TYPE (v) = type; + return v; + } + } + if (code1 == TYPE_CODE_FLT && scalar) + return value_from_double (type, value_as_double (arg2)); + else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM) + && (scalar || code2 == TYPE_CODE_PTR)) + return value_from_longest (type, value_as_long (arg2)); + else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2))) + { + if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) + { + /* Look in the type of the source to see if it contains the + type of the target as a superclass. If so, we'll need to + offset the pointer rather than just change its type. */ + struct type *t1 = TYPE_TARGET_TYPE (type); + struct type *t2 = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); + if ( TYPE_CODE (t1) == TYPE_CODE_STRUCT + && TYPE_CODE (t2) == TYPE_CODE_STRUCT + && TYPE_NAME (t1) != 0) /* if name unknown, can't have supercl */ + { + value v = search_struct_field (type_name_no_tag (t1), + value_ind (arg2), 0, t2, 1); + if (v) + { + v = value_addr (v); + VALUE_TYPE (v) = type; + return v; + } + } + /* No superclass found, just fall through to change ptr type. */ + } + VALUE_TYPE (arg2) = type; + return arg2; + } + else if (VALUE_LVAL (arg2) == lval_memory) + { + return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); + } + else if (code1 == TYPE_CODE_VOID) + { + return value_zero (builtin_type_void, not_lval); + } + else + { + error ("Invalid cast."); + return 0; + } +} + +/* Create a value of type TYPE that is zero, and return it. */ + +value +value_zero (type, lv) + struct type *type; + enum lval_type lv; +{ + register value val = allocate_value (type); + + memset (VALUE_CONTENTS (val), 0, TYPE_LENGTH (type)); + VALUE_LVAL (val) = lv; + + return val; +} + +/* Return a value with type TYPE located at ADDR. + + Call value_at only if the data needs to be fetched immediately; + if we can be 'lazy' and defer the fetch, perhaps indefinately, call + value_at_lazy instead. value_at_lazy simply records the address of + the data and sets the lazy-evaluation-required flag. The lazy flag + is tested in the VALUE_CONTENTS macro, which is used if and when + the contents are actually required. */ + +value +value_at (type, addr) + struct type *type; + CORE_ADDR addr; +{ + register value val = allocate_value (type); + + read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type)); + + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + + return val; +} + +/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */ + +value +value_at_lazy (type, addr) + struct type *type; + CORE_ADDR addr; +{ + register value val = allocate_value (type); + + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + VALUE_LAZY (val) = 1; + + return val; +} + +/* Called only from the VALUE_CONTENTS macro, if the current data for + a variable needs to be loaded into VALUE_CONTENTS(VAL). Fetches the + data from the user's process, and clears the lazy flag to indicate + that the data in the buffer is valid. + + If the value is zero-length, we avoid calling read_memory, which would + abort. We mark the value as fetched anyway -- all 0 bytes of it. + + This function returns a value because it is used in the VALUE_CONTENTS + macro as part of an expression, where a void would not work. The + value is ignored. */ + +int +value_fetch_lazy (val) + register value val; +{ + CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val); + + if (TYPE_LENGTH (VALUE_TYPE (val))) + read_memory (addr, VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val))); + VALUE_LAZY (val) = 0; + return 0; +} + + +/* Store the contents of FROMVAL into the location of TOVAL. + Return a new value with the location of TOVAL and contents of FROMVAL. */ + +value +value_assign (toval, fromval) + register value toval, fromval; +{ + register struct type *type = VALUE_TYPE (toval); + register value val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + int use_buffer = 0; + + COERCE_ARRAY (fromval); + COERCE_REF (toval); + + if (VALUE_LVAL (toval) != lval_internalvar) + fromval = value_cast (type, fromval); + + /* If TOVAL is a special machine register requiring conversion + of program values to a special raw format, + convert FROMVAL's contents now, with result in `raw_buffer', + and set USE_BUFFER to the number of bytes to write. */ + + if (VALUE_REGNO (toval) >= 0 + && REGISTER_CONVERTIBLE (VALUE_REGNO (toval))) + { + int regno = VALUE_REGNO (toval); + if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno)) + fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval); + memcpy (virtual_buffer, VALUE_CONTENTS (fromval), + REGISTER_VIRTUAL_SIZE (regno)); + REGISTER_CONVERT_TO_RAW (regno, virtual_buffer, raw_buffer); + use_buffer = REGISTER_RAW_SIZE (regno); + } + + switch (VALUE_LVAL (toval)) + { + case lval_internalvar: + set_internalvar (VALUE_INTERNALVAR (toval), fromval); + break; + + case lval_internalvar_component: + set_internalvar_component (VALUE_INTERNALVAR (toval), + VALUE_OFFSET (toval), + VALUE_BITPOS (toval), + VALUE_BITSIZE (toval), + fromval); + break; + + case lval_memory: + if (VALUE_BITSIZE (toval)) + { + int v; /* FIXME, this won't work for large bitfields */ + read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + (char *) &v, sizeof v); + modify_field ((char *) &v, value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + (char *)&v, sizeof v); + } + else if (use_buffer) + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, use_buffer); + else + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); + break; + + case lval_register: + if (VALUE_BITSIZE (toval)) + { + int v; + + read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + (char *) &v, sizeof v); + modify_field ((char *) &v, value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + (char *) &v, sizeof v); + } + else if (use_buffer) + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, use_buffer); + else + { + /* Do any conversion necessary when storing this type to more + than one register. */ +#ifdef REGISTER_CONVERT_FROM_TYPE + memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); + REGISTER_CONVERT_FROM_TYPE(VALUE_REGNO (toval), type, raw_buffer); + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, TYPE_LENGTH (type)); +#else + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); +#endif + } + break; + + case lval_reg_frame_relative: + { + /* value is stored in a series of registers in the frame + specified by the structure. Copy that value out, modify + it, and copy it back in. */ + int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type)); + int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval)); + int byte_offset = VALUE_OFFSET (toval) % reg_size; + int reg_offset = VALUE_OFFSET (toval) / reg_size; + int amount_copied; + char *buffer = (char *) alloca (amount_to_copy); + int regno; + FRAME frame; + + /* Figure out which frame this is in currently. */ + for (frame = get_current_frame (); + frame && FRAME_FP (frame) != VALUE_FRAME (toval); + frame = get_prev_frame (frame)) + ; + + if (!frame) + error ("Value being assigned to is no longer active."); + + amount_to_copy += (reg_size - amount_to_copy % reg_size); + + /* Copy it out. */ + for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, + amount_copied = 0); + amount_copied < amount_to_copy; + amount_copied += reg_size, regno++) + { + get_saved_register (buffer + amount_copied, + (int *)NULL, (CORE_ADDR *)NULL, + frame, regno, (enum lval_type *)NULL); + } + + /* Modify what needs to be modified. */ + if (VALUE_BITSIZE (toval)) + modify_field (buffer + byte_offset, + value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + else if (use_buffer) + memcpy (buffer + byte_offset, raw_buffer, use_buffer); + else + memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval), + TYPE_LENGTH (type)); + + /* Copy it back. */ + for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, + amount_copied = 0); + amount_copied < amount_to_copy; + amount_copied += reg_size, regno++) + { + enum lval_type lval; + CORE_ADDR addr; + int optim; + + /* Just find out where to put it. */ + get_saved_register ((char *)NULL, + &optim, &addr, frame, regno, &lval); + + if (optim) + error ("Attempt to assign to a value that was optimized out."); + if (lval == lval_memory) + write_memory (addr, buffer + amount_copied, reg_size); + else if (lval == lval_register) + write_register_bytes (addr, buffer + amount_copied, reg_size); + else + error ("Attempt to assign to an unmodifiable value."); + } + } + break; + + + default: + error ("Left side of = operation is not an lvalue."); + } + + /* Return a value just like TOVAL except with the contents of FROMVAL + (except in the case of the type if TOVAL is an internalvar). */ + + if (VALUE_LVAL (toval) == lval_internalvar + || VALUE_LVAL (toval) == lval_internalvar_component) + { + type = VALUE_TYPE (fromval); + } + + /* FIXME: This loses if fromval is a different size than toval, for + example because fromval got cast in the REGISTER_CONVERTIBLE case + above. */ + val = allocate_value (type); + memcpy (val, toval, VALUE_CONTENTS_RAW (val) - (char *) val); + memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval), + TYPE_LENGTH (type)); + VALUE_TYPE (val) = type; + + return val; +} + +/* Extend a value VAL to COUNT repetitions of its type. */ + +value +value_repeat (arg1, count) + value arg1; + int count; +{ + register value val; + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Only values in memory can be extended with '@'."); + if (count < 1) + error ("Invalid number %d of repetitions.", count); + + val = allocate_repeat_value (VALUE_TYPE (arg1), count); + + read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), + VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val)) * count); + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1); + + return val; +} + +value +value_of_variable (var, b) + struct symbol *var; + struct block *b; +{ + value val; + FRAME fr; + + if (b == NULL) + /* Use selected frame. */ + fr = NULL; + else + { + fr = block_innermost_frame (b); + if (fr == NULL && symbol_read_needs_frame (var)) + { + if (BLOCK_FUNCTION (b) != NULL + && SYMBOL_NAME (BLOCK_FUNCTION (b)) != NULL) + error ("No frame is currently executing in block %s.", + SYMBOL_NAME (BLOCK_FUNCTION (b))); + else + error ("No frame is currently executing in specified block"); + } + } + val = read_var_value (var, fr); + if (val == 0) + error ("Address of symbol \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var)); + return val; +} + +/* Given a value which is an array, return a value which is a pointer to its + first element, regardless of whether or not the array has a nonzero lower + bound. + + FIXME: A previous comment here indicated that this routine should be + substracting the array's lower bound. It's not clear to me that this + is correct. Given an array subscripting operation, it would certainly + work to do the adjustment here, essentially computing: + + (&array[0] - (lowerbound * sizeof array[0])) + (index * sizeof array[0]) + + However I believe a more appropriate and logical place to account for + the lower bound is to do so in value_subscript, essentially computing: + + (&array[0] + ((index - lowerbound) * sizeof array[0])) + + As further evidence consider what would happen with operations other + than array subscripting, where the caller would get back a value that + had an address somewhere before the actual first element of the array, + and the information about the lower bound would be lost because of + the coercion to pointer type. + */ + +value +value_coerce_array (arg1) + value arg1; +{ + register struct type *type; + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + /* Get type of elements. */ + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY) + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + else + /* A phony array made by value_repeat. + Its type is the type of the elements, not an array type. */ + type = VALUE_TYPE (arg1); + + return value_from_longest (lookup_pointer_type (type), + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); +} + +/* Given a value which is a function, return a value which is a pointer + to it. */ + +value +value_coerce_function (arg1) + value arg1; +{ + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + return value_from_longest (lookup_pointer_type (VALUE_TYPE (arg1)), + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); +} + +/* Return a pointer value for the object for which ARG1 is the contents. */ + +value +value_addr (arg1) + value arg1; +{ + struct type *type = VALUE_TYPE (arg1); + if (TYPE_CODE (type) == TYPE_CODE_REF) + { + /* Copy the value, but change the type from (T&) to (T*). + We keep the same location information, which is efficient, + and allows &(&X) to get the location containing the reference. */ + value arg2 = value_copy (arg1); + VALUE_TYPE (arg2) = lookup_pointer_type (TYPE_TARGET_TYPE (type)); + return arg2; + } + if (VALUE_REPEATED (arg1) + || TYPE_CODE (type) == TYPE_CODE_ARRAY) + return value_coerce_array (arg1); + if (TYPE_CODE (type) == TYPE_CODE_FUNC) + return value_coerce_function (arg1); + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + return value_from_longest (lookup_pointer_type (type), + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); +} + +/* Given a value of a pointer type, apply the C unary * operator to it. */ + +value +value_ind (arg1) + value arg1; +{ + COERCE_ARRAY (arg1); + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_MEMBER) + error ("not implemented: member types in value_ind"); + + /* Allow * on an integer so we can cast it to whatever we want. + This returns an int, which seems like the most C-like thing + to do. "long long" variables are rare enough that + BUILTIN_TYPE_LONGEST would seem to be a mistake. */ + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT) + return value_at (builtin_type_int, + (CORE_ADDR) value_as_long (arg1)); + else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) + return value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + value_as_pointer (arg1)); + error ("Attempt to take contents of a non-pointer value."); + return 0; /* For lint -- never reached */ +} + +/* Pushing small parts of stack frames. */ + +/* Push one word (the size of object that a register holds). */ + +CORE_ADDR +push_word (sp, word) + CORE_ADDR sp; + REGISTER_TYPE word; +{ + register int len = sizeof (REGISTER_TYPE); + char buffer[MAX_REGISTER_RAW_SIZE]; + + store_unsigned_integer (buffer, len, word); +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, buffer, len); +#else /* stack grows upward */ + write_memory (sp, buffer, len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Push LEN bytes with data at BUFFER. */ + +CORE_ADDR +push_bytes (sp, buffer, len) + CORE_ADDR sp; + char *buffer; + int len; +{ +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, buffer, len); +#else /* stack grows upward */ + write_memory (sp, buffer, len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Push onto the stack the specified value VALUE. */ + +static CORE_ADDR +value_push (sp, arg) + register CORE_ADDR sp; + value arg; +{ + register int len = TYPE_LENGTH (VALUE_TYPE (arg)); + +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, VALUE_CONTENTS (arg), len); +#else /* stack grows upward */ + write_memory (sp, VALUE_CONTENTS (arg), len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Perform the standard coercions that are specified + for arguments to be passed to C functions. */ + +value +value_arg_coerce (arg) + value arg; +{ + register struct type *type; + + /* FIXME: We should coerce this according to the prototype (if we have + one). Right now we do a little bit of this in typecmp(), but that + doesn't always get called. For example, if passing a ref to a function + without a prototype, we probably should de-reference it. Currently + we don't. */ + + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) + arg = value_cast (builtin_type_unsigned_int, arg); + +#if 1 /* FIXME: This is only a temporary patch. -fnf */ + if (VALUE_REPEATED (arg) + || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) + arg = value_coerce_array (arg); + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) + arg = value_coerce_function (arg); +#endif + + type = VALUE_TYPE (arg); + + if (TYPE_CODE (type) == TYPE_CODE_INT + && TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int)) + return value_cast (builtin_type_int, arg); + + if (TYPE_CODE (type) == TYPE_CODE_FLT + && TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double)) + return value_cast (builtin_type_double, arg); + + return arg; +} + +/* Push the value ARG, first coercing it as an argument + to a C function. */ + +static CORE_ADDR +value_arg_push (sp, arg) + register CORE_ADDR sp; + value arg; +{ + return value_push (sp, value_arg_coerce (arg)); +} + +/* Determine a function's address and its return type from its value. + Calls error() if the function is not valid for calling. */ + +static CORE_ADDR +find_function_addr (function, retval_type) + value function; + struct type **retval_type; +{ + register struct type *ftype = VALUE_TYPE (function); + register enum type_code code = TYPE_CODE (ftype); + struct type *value_type; + CORE_ADDR funaddr; + + /* If it's a member function, just look at the function + part of it. */ + + /* Determine address to call. */ + if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) + { + funaddr = VALUE_ADDRESS (function); + value_type = TYPE_TARGET_TYPE (ftype); + } + else if (code == TYPE_CODE_PTR) + { + funaddr = value_as_pointer (function); + if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_FUNC + || TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_METHOD) + value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)); + else + value_type = builtin_type_int; + } + else if (code == TYPE_CODE_INT) + { + /* Handle the case of functions lacking debugging info. + Their values are characters since their addresses are char */ + if (TYPE_LENGTH (ftype) == 1) + funaddr = value_as_pointer (value_addr (function)); + else + /* Handle integer used as address of a function. */ + funaddr = (CORE_ADDR) value_as_long (function); + + value_type = builtin_type_int; + } + else + error ("Invalid data type for function to be called."); + + *retval_type = value_type; + return funaddr; +} + +#if defined (CALL_DUMMY) +/* All this stuff with a dummy frame may seem unnecessarily complicated + (why not just save registers in GDB?). The purpose of pushing a dummy + frame which looks just like a real frame is so that if you call a + function and then hit a breakpoint (get a signal, etc), "backtrace" + will look right. Whether the backtrace needs to actually show the + stack at the time the inferior function was called is debatable, but + it certainly needs to not display garbage. So if you are contemplating + making dummy frames be different from normal frames, consider that. */ + +/* Perform a function call in the inferior. + ARGS is a vector of values of arguments (NARGS of them). + FUNCTION is a value, the function to be called. + Returns a value representing what the function returned. + May fail to return, if a breakpoint or signal is hit + during the execution of the function. */ + +value +call_function_by_hand (function, nargs, args) + value function; + int nargs; + value *args; +{ + register CORE_ADDR sp; + register int i; + CORE_ADDR start_sp; + /* CALL_DUMMY is an array of words (REGISTER_TYPE), but each word + is in host byte order. It is switched to target byte order before calling + FIX_CALL_DUMMY. */ + static REGISTER_TYPE dummy[] = CALL_DUMMY; + REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)]; + CORE_ADDR old_sp; + struct type *value_type; + unsigned char struct_return; + CORE_ADDR struct_addr; + struct inferior_status inf_status; + struct cleanup *old_chain; + CORE_ADDR funaddr; + int using_gcc; + CORE_ADDR real_pc; + + if (!target_has_execution) + noprocess(); + + save_inferior_status (&inf_status, 1); + old_chain = make_cleanup (restore_inferior_status, &inf_status); + + /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers + (and POP_FRAME for restoring them). (At least on most machines) + they are saved on the stack in the inferior. */ + PUSH_DUMMY_FRAME; + + old_sp = sp = read_sp (); + +#if 1 INNER_THAN 2 /* Stack grows down */ + sp -= sizeof dummy; + start_sp = sp; +#else /* Stack grows up */ + start_sp = sp; + sp += sizeof dummy; +#endif + + funaddr = find_function_addr (function, &value_type); + + { + struct block *b = block_for_pc (funaddr); + /* If compiled without -g, assume GCC. */ + using_gcc = b == NULL || BLOCK_GCC_COMPILED (b); + } + + /* Are we returning a value using a structure return or a normal + value return? */ + + struct_return = using_struct_return (function, funaddr, value_type, + using_gcc); + + /* Create a call sequence customized for this function + and the number of arguments for it. */ + for (i = 0; i < sizeof dummy / sizeof (REGISTER_TYPE); i++) + store_unsigned_integer (&dummy1[i], sizeof (REGISTER_TYPE), + (unsigned LONGEST)dummy[i]); + +#ifdef GDB_TARGET_IS_HPPA + real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, + value_type, using_gcc); +#else + FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, + value_type, using_gcc); + real_pc = start_sp; +#endif + +#if CALL_DUMMY_LOCATION == ON_STACK + write_memory (start_sp, (char *)dummy1, sizeof dummy); +#endif /* On stack. */ + +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END + /* Convex Unix prohibits executing in the stack segment. */ + /* Hope there is empty room at the top of the text segment. */ + { + extern CORE_ADDR text_end; + static checked = 0; + if (!checked) + for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp) + if (read_memory_integer (start_sp, 1) != 0) + error ("text segment full -- no place to put call"); + checked = 1; + sp = old_sp; + real_pc = text_end - sizeof dummy; + write_memory (real_pc, (char *)dummy1, sizeof dummy); + } +#endif /* Before text_end. */ + +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END + { + extern CORE_ADDR text_end; + int errcode; + sp = old_sp; + real_pc = text_end; + errcode = target_write_memory (real_pc, (char *)dummy1, sizeof dummy); + if (errcode != 0) + error ("Cannot write text segment -- call_function failed"); + } +#endif /* After text_end. */ + +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + real_pc = funaddr; +#endif /* At entry point. */ + +#ifdef lint + sp = old_sp; /* It really is used, for some ifdef's... */ +#endif + +#ifdef STACK_ALIGN + /* If stack grows down, we must leave a hole at the top. */ + { + int len = 0; + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + len += TYPE_LENGTH (value_type); + + for (i = nargs - 1; i >= 0; i--) + len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i]))); +#ifdef CALL_DUMMY_STACK_ADJUST + len += CALL_DUMMY_STACK_ADJUST; +#endif +#if 1 INNER_THAN 2 + sp -= STACK_ALIGN (len) - len; +#else + sp += STACK_ALIGN (len) - len; +#endif + } +#endif /* STACK_ALIGN */ + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + { +#if 1 INNER_THAN 2 + sp -= TYPE_LENGTH (value_type); + struct_addr = sp; +#else + struct_addr = sp; + sp += TYPE_LENGTH (value_type); +#endif + } + +#if defined (REG_STRUCT_HAS_ADDR) + { + /* This is a machine like the sparc, where we need to pass a pointer + to the structure, not the structure itself. */ + if (REG_STRUCT_HAS_ADDR (using_gcc)) + for (i = nargs - 1; i >= 0; i--) + if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT) + { + CORE_ADDR addr; +#if !(1 INNER_THAN 2) + /* The stack grows up, so the address of the thing we push + is the stack pointer before we push it. */ + addr = sp; +#endif + /* Push the structure. */ + sp = value_push (sp, args[i]); +#if 1 INNER_THAN 2 + /* The stack grows down, so the address of the thing we push + is the stack pointer after we push it. */ + addr = sp; +#endif + /* The value we're going to pass is the address of the thing + we just pushed. */ + args[i] = value_from_longest (lookup_pointer_type (value_type), + (LONGEST) addr); + } + } +#endif /* REG_STRUCT_HAS_ADDR. */ + +#ifdef PUSH_ARGUMENTS + PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr); +#else /* !PUSH_ARGUMENTS */ + for (i = nargs - 1; i >= 0; i--) + sp = value_arg_push (sp, args[i]); +#endif /* !PUSH_ARGUMENTS */ + +#ifdef CALL_DUMMY_STACK_ADJUST +#if 1 INNER_THAN 2 + sp -= CALL_DUMMY_STACK_ADJUST; +#else + sp += CALL_DUMMY_STACK_ADJUST; +#endif +#endif /* CALL_DUMMY_STACK_ADJUST */ + + /* Store the address at which the structure is supposed to be + written. Note that this (and the code which reserved the space + above) assumes that gcc was used to compile this function. Since + it doesn't cost us anything but space and if the function is pcc + it will ignore this value, we will make that assumption. + + Also note that on some machines (like the sparc) pcc uses a + convention like gcc's. */ + + if (struct_return) + STORE_STRUCT_RETURN (struct_addr, sp); + + /* Write the stack pointer. This is here because the statements above + might fool with it. On SPARC, this write also stores the register + window into the right place in the new stack frame, which otherwise + wouldn't happen. (See store_inferior_registers in sparc-nat.c.) */ + write_sp (sp); + + { + char retbuf[REGISTER_BYTES]; + char *name; + struct symbol *symbol; + + name = NULL; + symbol = find_pc_function (funaddr); + if (symbol) + { + name = SYMBOL_SOURCE_NAME (symbol); + } + else + { + /* Try the minimal symbols. */ + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr); + + if (msymbol) + { + name = SYMBOL_SOURCE_NAME (msymbol); + } + } + if (name == NULL) + { + char format[80]; + sprintf (format, "at %s", local_hex_format ()); + name = alloca (80); + sprintf (name, format, (unsigned long) funaddr); + } + + /* Execute the stack dummy routine, calling FUNCTION. + When it is done, discard the empty frame + after storing the contents of all regs into retbuf. */ + if (run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf)) + { + /* We stopped somewhere besides the call dummy. */ + + /* If we did the cleanups, we would print a spurious error message + (Unable to restore previously selected frame), would write the + registers from the inf_status (which is wrong), and would do other + wrong things (like set stop_bpstat to the wrong thing). */ + discard_cleanups (old_chain); + /* Prevent memory leak. */ + bpstat_clear (&inf_status.stop_bpstat); + + /* The following error message used to say "The expression + which contained the function call has been discarded." It + is a hard concept to explain in a few words. Ideally, GDB + would be able to resume evaluation of the expression when + the function finally is done executing. Perhaps someday + this will be implemented (it would not be easy). */ + + /* FIXME: Insert a bunch of wrap_here; name can be very long if it's + a C++ name with arguments and stuff. */ + error ("\ +The program being debugged stopped while in a function called from GDB.\n\ +When the function (%s) is done executing, GDB will silently\n\ +stop (instead of continuing to evaluate the expression containing\n\ +the function call).", name); + } + + do_cleanups (old_chain); + + /* Figure out the value returned by the function. */ + return value_being_returned (value_type, retbuf, struct_return); + } +} +#else /* no CALL_DUMMY. */ +value +call_function_by_hand (function, nargs, args) + value function; + int nargs; + value *args; +{ + error ("Cannot invoke functions on this machine."); +} +#endif /* no CALL_DUMMY. */ + + +/* Create a value for an array by allocating space in the inferior, copying + the data into that space, and then setting up an array value. + + The array bounds are set from LOWBOUND and HIGHBOUND, and the array is + populated from the values passed in ELEMVEC. + + The element type of the array is inherited from the type of the + first element, and all elements must have the same size (though we + don't currently enforce any restriction on their types). */ + +value +value_array (lowbound, highbound, elemvec) + int lowbound; + int highbound; + value *elemvec; +{ + int nelem; + int idx; + int typelength; + value val; + struct type *rangetype; + struct type *arraytype; + CORE_ADDR addr; + + /* Validate that the bounds are reasonable and that each of the elements + have the same size. */ + + nelem = highbound - lowbound + 1; + if (nelem <= 0) + { + error ("bad array bounds (%d, %d)", lowbound, highbound); + } + typelength = TYPE_LENGTH (VALUE_TYPE (elemvec[0])); + for (idx = 0; idx < nelem; idx++) + { + if (TYPE_LENGTH (VALUE_TYPE (elemvec[idx])) != typelength) + { + error ("array elements must all be the same size"); + } + } + + /* Allocate space to store the array in the inferior, and then initialize + it by copying in each element. FIXME: Is it worth it to create a + local buffer in which to collect each value and then write all the + bytes in one operation? */ + + addr = allocate_space_in_inferior (nelem * typelength); + for (idx = 0; idx < nelem; idx++) + { + write_memory (addr + (idx * typelength), VALUE_CONTENTS (elemvec[idx]), + typelength); + } + + /* Create the array type and set up an array value to be evaluated lazily. */ + + rangetype = create_range_type ((struct type *) NULL, builtin_type_int, + lowbound, highbound); + arraytype = create_array_type ((struct type *) NULL, + VALUE_TYPE (elemvec[0]), rangetype); + val = value_at_lazy (arraytype, addr); + return (val); +} + +/* Create a value for a string constant by allocating space in the inferior, + copying the data into that space, and returning the address with type + TYPE_CODE_STRING. PTR points to the string constant data; LEN is number + of characters. + Note that string types are like array of char types with a lower bound of + zero and an upper bound of LEN - 1. Also note that the string may contain + embedded null bytes. */ + +value +value_string (ptr, len) + char *ptr; + int len; +{ + value val; + struct type *rangetype; + struct type *stringtype; + CORE_ADDR addr; + + /* Allocate space to store the string in the inferior, and then + copy LEN bytes from PTR in gdb to that address in the inferior. */ + + addr = allocate_space_in_inferior (len); + write_memory (addr, ptr, len); + + /* Create the string type and set up a string value to be evaluated + lazily. */ + + rangetype = create_range_type ((struct type *) NULL, builtin_type_int, + 0, len - 1); + stringtype = create_string_type ((struct type *) NULL, rangetype); + val = value_at_lazy (stringtype, addr); + return (val); +} + +/* See if we can pass arguments in T2 to a function which takes arguments + of types T1. Both t1 and t2 are NULL-terminated vectors. If some + arguments need coercion of some sort, then the coerced values are written + into T2. Return value is 0 if the arguments could be matched, or the + position at which they differ if not. + + STATICP is nonzero if the T1 argument list came from a + static member function. + + For non-static member functions, we ignore the first argument, + which is the type of the instance variable. This is because we want + to handle calls with objects from derived classes. This is not + entirely correct: we should actually check to make sure that a + requested operation is type secure, shouldn't we? FIXME. */ + +static int +typecmp (staticp, t1, t2) + int staticp; + struct type *t1[]; + value t2[]; +{ + int i; + + if (t2 == 0) + return 1; + if (staticp && t1 == 0) + return t2[1] != 0; + if (t1 == 0) + return 1; + if (TYPE_CODE (t1[0]) == TYPE_CODE_VOID) return 0; + if (t1[!staticp] == 0) return 0; + for (i = !staticp; t1[i] && TYPE_CODE (t1[i]) != TYPE_CODE_VOID; i++) + { + if (! t2[i]) + return i+1; + if (TYPE_CODE (t1[i]) == TYPE_CODE_REF + /* We should be doing hairy argument matching, as below. */ + && (TYPE_CODE (TYPE_TARGET_TYPE (t1[i])) + == TYPE_CODE (VALUE_TYPE (t2[i])))) + { + t2[i] = value_addr (t2[i]); + continue; + } + + if (TYPE_CODE (t1[i]) == TYPE_CODE_PTR + && TYPE_CODE (VALUE_TYPE (t2[i])) == TYPE_CODE_ARRAY) + /* Array to pointer is a `trivial conversion' according to the ARM. */ + continue; + + /* We should be doing much hairier argument matching (see section 13.2 + of the ARM), but as a quick kludge, just check for the same type + code. */ + if (TYPE_CODE (t1[i]) != TYPE_CODE (VALUE_TYPE (t2[i]))) + return i+1; + } + if (!t1[i]) return 0; + return t2[i] ? i+1 : 0; +} + +/* Helper function used by value_struct_elt to recurse through baseclasses. + Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, + and search in it assuming it has (class) type TYPE. + If found, return value, else return NULL. + + If LOOKING_FOR_BASECLASS, then instead of looking for struct fields, + look for a baseclass named NAME. */ + +static value +search_struct_field (name, arg1, offset, type, looking_for_baseclass) + char *name; + register value arg1; + int offset; + register struct type *type; + int looking_for_baseclass; +{ + int i; + + check_stub_type (type); + + if (! looking_for_baseclass) + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name && STREQ (t_field_name, name)) + { + value v; + if (TYPE_FIELD_STATIC (type, i)) + { + char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, i); + struct symbol *sym = + lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (sym == NULL) + error ("Internal error: could not find physical static variable named %s", + phys_name); + v = value_at (TYPE_FIELD_TYPE (type, i), + (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + } + else + v = value_primitive_field (arg1, offset, i, type); + if (v == 0) + error("there is no field named %s", name); + return v; + } + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + value v; + /* If we are looking for baseclasses, this is what we get when we + hit them. But it could happen that the base part's member name + is not yet filled in. */ + int found_baseclass = (looking_for_baseclass + && TYPE_BASECLASS_NAME (type, i) != NULL + && STREQ (name, TYPE_BASECLASS_NAME (type, i))); + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + value v2; + /* Fix to use baseclass_offset instead. FIXME */ + baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, + &v2, (int *)NULL); + if (v2 == 0) + error ("virtual baseclass botch"); + if (found_baseclass) + return v2; + v = search_struct_field (name, v2, 0, TYPE_BASECLASS (type, i), + looking_for_baseclass); + } + else if (found_baseclass) + v = value_primitive_field (arg1, offset, i, type); + else + v = search_struct_field (name, arg1, + offset + TYPE_BASECLASS_BITPOS (type, i) / 8, + TYPE_BASECLASS (type, i), + looking_for_baseclass); + if (v) return v; + } + return NULL; +} + +/* Helper function used by value_struct_elt to recurse through baseclasses. + Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, + and search in it assuming it has (class) type TYPE. + If found, return value, else if name matched and args not return (value)-1, + else return NULL. */ + +static value +search_struct_method (name, arg1p, args, offset, static_memfuncp, type) + char *name; + register value *arg1p, *args; + int offset, *static_memfuncp; + register struct type *type; +{ + int i; + static int name_matched = 0; + + check_stub_type (type); + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--) + { + char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i); + if (t_field_name && STREQ (t_field_name, name)) + { + int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1; + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + name_matched = 1; + + if (j > 0 && args == 0) + error ("cannot resolve overloaded method `%s'", name); + while (j >= 0) + { + if (TYPE_FN_FIELD_STUB (f, j)) + check_stub_method (type, i, j); + if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j), + TYPE_FN_FIELD_ARGS (f, j), args)) + { + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + return (value)value_virtual_fn_field (arg1p, f, j, type, offset); + if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp) + *static_memfuncp = 1; + return (value)value_fn_field (arg1p, f, j, type, offset); + } + j--; + } + } + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + value v; + int base_offset; + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + base_offset = baseclass_offset (type, i, *arg1p, offset); + if (base_offset == -1) + error ("virtual baseclass botch"); + } + else + { + base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8; + } + v = search_struct_method (name, arg1p, args, base_offset + offset, + static_memfuncp, TYPE_BASECLASS (type, i)); + if (v == (value) -1) + { + name_matched = 1; + } + else if (v) + { +/* FIXME-bothner: Why is this commented out? Why is it here? */ +/* *arg1p = arg1_tmp;*/ + return v; + } + } + if (name_matched) return (value) -1; + else return NULL; +} + +/* Given *ARGP, a value of type (pointer to a)* structure/union, + extract the component named NAME from the ultimate target structure/union + and return it as a value with its appropriate type. + ERR is used in the error message if *ARGP's type is wrong. + + C++: ARGS is a list of argument types to aid in the selection of + an appropriate method. Also, handle derived types. + + STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location + where the truthvalue of whether the function that was resolved was + a static member function or not is stored. + + ERR is an error message to be printed in case the field is not found. */ + +value +value_struct_elt (argp, args, name, static_memfuncp, err) + register value *argp, *args; + char *name; + int *static_memfuncp; + char *err; +{ + register struct type *t; + value v; + + COERCE_ARRAY (*argp); + + t = VALUE_TYPE (*argp); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + { + *argp = value_ind (*argp); + /* Don't coerce fn pointer to fn and then back again! */ + if (TYPE_CODE (VALUE_TYPE (*argp)) != TYPE_CODE_FUNC) + COERCE_ARRAY (*argp); + t = VALUE_TYPE (*argp); + } + + if (TYPE_CODE (t) == TYPE_CODE_MEMBER) + error ("not implemented: member type in value_struct_elt"); + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Attempt to extract a component of a value that is not a %s.", err); + + /* Assume it's not, unless we see that it is. */ + if (static_memfuncp) + *static_memfuncp =0; + + if (!args) + { + /* if there are no arguments ...do this... */ + + /* Try as a field first, because if we succeed, there + is less work to be done. */ + v = search_struct_field (name, *argp, 0, t, 0); + if (v) + return v; + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + if (destructor_name_p (name, t)) + error ("Cannot get value of destructor"); + + v = search_struct_method (name, argp, args, 0, static_memfuncp, t); + + if (v == 0) + { + if (TYPE_NFN_FIELDS (t)) + error ("There is no member or method named %s.", name); + else + error ("There is no member named %s.", name); + } + return v; + } + + if (destructor_name_p (name, t)) + { + if (!args[1]) + { + /* destructors are a special case. */ + return (value)value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, 0), + TYPE_FN_FIELDLIST_LENGTH (t, 0), + 0, 0); + } + else + { + error ("destructor should not have any argument"); + } + } + else + v = search_struct_method (name, argp, args, 0, static_memfuncp, t); + + if (v == (value) -1) + { + error("Argument list of %s mismatch with component in the structure.", name); + } + else if (v == 0) + { + /* See if user tried to invoke data as function. If so, + hand it back. If it's not callable (i.e., a pointer to function), + gdb should give an error. */ + v = search_struct_field (name, *argp, 0, t, 0); + } + + if (!v) + error ("Structure has no component named %s.", name); + return v; +} + +/* C++: return 1 is NAME is a legitimate name for the destructor + of type TYPE. If TYPE does not have a destructor, or + if NAME is inappropriate for TYPE, an error is signaled. */ +int +destructor_name_p (name, type) + const char *name; + const struct type *type; +{ + /* destructors are a special case. */ + + if (name[0] == '~') + { + char *dname = type_name_no_tag (type); + if (!STREQ (dname, name+1)) + error ("name of destructor must equal name of class"); + else + return 1; + } + return 0; +} + +/* Helper function for check_field: Given TYPE, a structure/union, + return 1 if the component named NAME from the ultimate + target structure/union is defined, otherwise, return 0. */ + +static int +check_field_in (type, name) + register struct type *type; + const char *name; +{ + register int i; + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + if (t_field_name && STREQ (t_field_name, name)) + return 1; + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + /* Destructors are a special case. */ + if (destructor_name_p (name, type)) + return 1; + + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i) + { + if (STREQ (TYPE_FN_FIELDLIST_NAME (type, i), name)) + return 1; + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + if (check_field_in (TYPE_BASECLASS (type, i), name)) + return 1; + + return 0; +} + + +/* C++: Given ARG1, a value of type (pointer to a)* structure/union, + return 1 if the component named NAME from the ultimate + target structure/union is defined, otherwise, return 0. */ + +int +check_field (arg1, name) + register value arg1; + const char *name; +{ + register struct type *t; + + COERCE_ARRAY (arg1); + + t = VALUE_TYPE (arg1); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + t = TYPE_TARGET_TYPE (t); + + if (TYPE_CODE (t) == TYPE_CODE_MEMBER) + error ("not implemented: member type in check_field"); + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Internal error: `this' is not an aggregate"); + + return check_field_in (t, name); +} + +/* C++: Given an aggregate type CURTYPE, and a member name NAME, + return the address of this member as a "pointer to member" + type. If INTYPE is non-null, then it will be the type + of the member we are looking for. This will help us resolve + "pointers to member functions". This function is used + to resolve user expressions of the form "DOMAIN::NAME". */ + +value +value_struct_elt_for_reference (domain, offset, curtype, name, intype) + struct type *domain, *curtype, *intype; + int offset; + char *name; +{ + register struct type *t = curtype; + register int i; + value v; + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Internal error: non-aggregate type to value_struct_elt_for_reference"); + + for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--) + { + char *t_field_name = TYPE_FIELD_NAME (t, i); + + if (t_field_name && STREQ (t_field_name, name)) + { + if (TYPE_FIELD_STATIC (t, i)) + { + char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (t, i); + struct symbol *sym = + lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (sym == NULL) + error ("Internal error: could not find physical static variable named %s", + phys_name); + return value_at (SYMBOL_TYPE (sym), + (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + } + if (TYPE_FIELD_PACKED (t, i)) + error ("pointers to bitfield members not allowed"); + + return value_from_longest + (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i), + domain)), + offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3)); + } + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + /* Destructors are a special case. */ + if (destructor_name_p (name, t)) + { + error ("member pointers to destructors not implemented yet"); + } + + /* Perform all necessary dereferencing. */ + while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR) + intype = TYPE_TARGET_TYPE (intype); + + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i) + { + if (STREQ (TYPE_FN_FIELDLIST_NAME (t, i), name)) + { + int j = TYPE_FN_FIELDLIST_LENGTH (t, i); + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); + + if (intype == 0 && j > 1) + error ("non-unique member `%s' requires type instantiation", name); + if (intype) + { + while (j--) + if (TYPE_FN_FIELD_TYPE (f, j) == intype) + break; + if (j < 0) + error ("no member function matches that type instantiation"); + } + else + j = 0; + + if (TYPE_FN_FIELD_STUB (f, j)) + check_stub_method (t, i, j); + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + { + return value_from_longest + (lookup_reference_type + (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), + domain)), + (LONGEST) METHOD_PTR_FROM_VOFFSET + (TYPE_FN_FIELD_VOFFSET (f, j))); + } + else + { + struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), + 0, VAR_NAMESPACE, 0, NULL); + if (s == NULL) + { + v = 0; + } + else + { + v = read_var_value (s, 0); +#if 0 + VALUE_TYPE (v) = lookup_reference_type + (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), + domain)); +#endif + } + return v; + } + } + } + for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--) + { + value v; + int base_offset; + + if (BASETYPE_VIA_VIRTUAL (t, i)) + base_offset = 0; + else + base_offset = TYPE_BASECLASS_BITPOS (t, i) / 8; + v = value_struct_elt_for_reference (domain, + offset + base_offset, + TYPE_BASECLASS (t, i), + name, + intype); + if (v) + return v; + } + return 0; +} + +/* C++: return the value of the class instance variable, if one exists. + Flag COMPLAIN signals an error if the request is made in an + inappropriate context. */ +value +value_of_this (complain) + int complain; +{ + extern FRAME selected_frame; + struct symbol *func, *sym; + struct block *b; + int i; + static const char funny_this[] = "this"; + value this; + + if (selected_frame == 0) + if (complain) + error ("no frame selected"); + else return 0; + + func = get_frame_function (selected_frame); + if (!func) + { + if (complain) + error ("no `this' in nameless context"); + else return 0; + } + + b = SYMBOL_BLOCK_VALUE (func); + i = BLOCK_NSYMS (b); + if (i <= 0) + if (complain) + error ("no args, no `this'"); + else return 0; + + /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER + symbol instead of the LOC_ARG one (if both exist). */ + sym = lookup_block_symbol (b, funny_this, VAR_NAMESPACE); + if (sym == NULL) + { + if (complain) + error ("current stack frame not in method"); + else + return NULL; + } + + this = read_var_value (sym, selected_frame); + if (this == 0 && complain) + error ("`this' argument at unknown address"); + return this; +} diff --git a/gnu/usr.bin/gdb/gdb/valprint.c b/gnu/usr.bin/gdb/gdb/valprint.c new file mode 100644 index 00000000000..b805645a4ce --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/valprint.c @@ -0,0 +1,1063 @@ +/* Print values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + +#include "defs.h" +#include +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "target.h" +#include "obstack.h" +#include "language.h" +#include "demangle.h" + +#include + +/* Prototypes for local functions */ + +static void +print_hex_chars PARAMS ((FILE *, unsigned char *, unsigned int)); + +static void +show_print PARAMS ((char *, int)); + +static void +set_print PARAMS ((char *, int)); + +static void +set_radix PARAMS ((char *, int)); + +static void +show_radix PARAMS ((char *, int)); + +static void +set_input_radix PARAMS ((char *, int, struct cmd_list_element *)); + +static void +set_input_radix_1 PARAMS ((int, unsigned)); + +static void +set_output_radix PARAMS ((char *, int, struct cmd_list_element *)); + +static void +set_output_radix_1 PARAMS ((int, unsigned)); + +static void +value_print_array_elements PARAMS ((value, FILE *, int, enum val_prettyprint)); + +/* Maximum number of chars to print for a string pointer value or vector + contents, or UINT_MAX for no limit. Note that "set print elements 0" + stores UINT_MAX in print_max, which displays in a show command as + "unlimited". */ + +unsigned int print_max; +#define PRINT_MAX_DEFAULT 200 /* Start print_max off at this value. */ + +/* Default input and output radixes, and output format letter. */ + +unsigned input_radix = 10; +unsigned output_radix = 10; +int output_format = 0; + +/* Print repeat counts if there are more than this many repetitions of an + element in an array. Referenced by the low level language dependent + print routines. */ + +unsigned int repeat_count_threshold = 10; + +int prettyprint_structs; /* Controls pretty printing of structures */ +int prettyprint_arrays; /* Controls pretty printing of arrays. */ + +/* If nonzero, causes unions inside structures or other unions to be + printed. */ + +int unionprint; /* Controls printing of nested unions. */ + +/* If nonzero, causes machine addresses to be printed in certain contexts. */ + +int addressprint; /* Controls printing of machine addresses */ + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter, or 0 for natural format using TYPE). + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. + + If the data are a string pointer, returns the number of string characters + printed. + + FIXME: The data at VALADDR is in target byte order. If gdb is ever + enhanced to be able to debug more than the single target it was compiled + for (specific CPU type and thus specific target byte ordering), then + either the print routines are going to have to take this into account, + or the data is going to have to be passed into here already converted + to the host byte ordering, whichever is more convenient. */ + + +int +val_print (type, valaddr, address, stream, format, deref_ref, recurse, pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + if (pretty == Val_pretty_default) + { + pretty = prettyprint_structs ? Val_prettyprint : Val_no_prettyprint; + } + + QUIT; + + /* Ensure that the type is complete and not just a stub. If the type is + only a stub and we can't find and substitute its complete type, then + print appropriate string and return. Typical types that my be stubs + are structs, unions, and C++ methods. */ + + check_stub_type (type); + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + fprintf_filtered (stream, ""); + fflush (stream); + return (0); + } + + return (LA_VAL_PRINT (type, valaddr, address, stream, format, deref_ref, + recurse, pretty)); +} + +/* Print the value VAL in C-ish syntax on stream STREAM. + FORMAT is a format-letter, or 0 for print in natural format of data type. + If the object printed is a string pointer, returns + the number of string bytes printed. */ + +int +value_print (val, stream, format, pretty) + value val; + FILE *stream; + int format; + enum val_prettyprint pretty; +{ + register unsigned int n, typelen; + + if (val == 0) + { + printf_filtered ("
"); + return 0; + } + if (VALUE_OPTIMIZED_OUT (val)) + { + printf_filtered (""); + return 0; + } + + /* A "repeated" value really contains several values in a row. + They are made by the @ operator. + Print such values as if they were arrays. */ + + if (VALUE_REPEATED (val)) + { + n = VALUE_REPETITIONS (val); + typelen = TYPE_LENGTH (VALUE_TYPE (val)); + fprintf_filtered (stream, "{"); + /* Print arrays of characters using string syntax. */ + if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT + && format == 0) + LA_PRINT_STRING (stream, VALUE_CONTENTS (val), n, 0); + else + { + value_print_array_elements (val, stream, format, pretty); + } + fprintf_filtered (stream, "}"); + return (n * typelen); + } + else + { + struct type *type = VALUE_TYPE (val); + + /* If it is a pointer, indicate what it points to. + + Print type also if it is a reference. + + C++: if it is a member pointer, we will take care + of that when we print it. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR || + TYPE_CODE (type) == TYPE_CODE_REF) + { + /* Hack: remove (char *) for char strings. Their + type is indicated by the quoted string anyway. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof(char) && + TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT && + !TYPE_UNSIGNED (TYPE_TARGET_TYPE (type))) + { + /* Print nothing */ + } + else + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") "); + } + } + return (val_print (type, VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, 1, 0, pretty)); + } +} + +/* Called by various _val_print routines to print TYPE_CODE_INT's */ + +void +val_print_type_code_int (type, valaddr, stream) + struct type *type; + char *valaddr; + FILE *stream; +{ + char *p; + /* Pointer to first (i.e. lowest address) nonzero character. */ + char *first_addr; + unsigned int len; + + if (TYPE_LENGTH (type) > sizeof (LONGEST)) + { + if (TYPE_UNSIGNED (type)) + { + /* First figure out whether the number in fact has zeros + in all its bytes more significant than least significant + sizeof (LONGEST) ones. */ + len = TYPE_LENGTH (type); + +#if TARGET_BYTE_ORDER == BIG_ENDIAN + for (p = valaddr; + len > sizeof (LONGEST) && p < valaddr + TYPE_LENGTH (type); + p++) +#else /* Little endian. */ + first_addr = valaddr; + for (p = valaddr + TYPE_LENGTH (type) - 1; + len > sizeof (LONGEST) && p >= valaddr; + p--) +#endif /* Little endian. */ + { + if (*p == 0) + { + len--; + } + else + { + break; + } + } +#if TARGET_BYTE_ORDER == BIG_ENDIAN + first_addr = p; +#endif + if (len <= sizeof (LONGEST)) + { + /* We can print it in decimal. */ + print_longest (stream, 'u', 0, + unpack_long (BUILTIN_TYPE_LONGEST, first_addr)); + } + else + { + /* It is big, so print it in hex. */ + print_hex_chars (stream, (unsigned char *) first_addr, len); + } + } + else + { + /* Signed. One could assume two's complement (a reasonable + assumption, I think) and do better than this. */ + print_hex_chars (stream, (unsigned char *) valaddr, + TYPE_LENGTH (type)); + } + } + else + { +#ifdef PRINT_TYPELESS_INTEGER + PRINT_TYPELESS_INTEGER (stream, type, unpack_long (type, valaddr)); +#else + print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, + unpack_long (type, valaddr)); +#endif + } +} + +/* Print a number according to FORMAT which is one of d,u,x,o,b,h,w,g. + The raison d'etre of this function is to consolidate printing of LONG_LONG's + into this one function. Some platforms have long longs but don't have a + printf() that supports "ll" in the format string. We handle these by seeing + if the number is actually a long, and if not we just bail out and print the + number in hex. The format chars b,h,w,g are from + print_scalar_formatted(). USE_LOCAL says whether or not to call the + local formatting routine to get the format. */ + +void +print_longest (stream, format, use_local, val_long) + FILE *stream; + int format; + int use_local; + LONGEST val_long; +{ +#if defined (CC_HAS_LONG_LONG) && !defined (PRINTF_HAS_LONG_LONG) + long vtop, vbot; + + vtop = val_long >> (sizeof (long) * HOST_CHAR_BIT); + vbot = (long) val_long; + + if ((format == 'd' && (val_long < INT_MIN || val_long > INT_MAX)) + || ((format == 'u' || format == 'x') && val_long > UINT_MAX)) + { + fprintf_filtered (stream, "0x%lx%08lx", vtop, vbot); + return; + } +#endif + +#ifdef PRINTF_HAS_LONG_LONG + switch (format) + { + case 'd': + fprintf_filtered (stream, + use_local ? local_decimal_format_custom ("ll") + : "%lld", + val_long); + break; + case 'u': + fprintf_filtered (stream, "%llu", val_long); + break; + case 'x': + fprintf_filtered (stream, + use_local ? local_hex_format_custom ("ll") + : "%llx", + val_long); + break; + case 'o': + fprintf_filtered (stream, + use_local ? local_octal_format_custom ("ll") + : "%llo", + break; + case 'b': + fprintf_filtered (stream, local_hex_format_custom ("02ll"), val_long); + break; + case 'h': + fprintf_filtered (stream, local_hex_format_custom ("04ll"), val_long); + break; + case 'w': + fprintf_filtered (stream, local_hex_format_custom ("08ll"), val_long); + break; + case 'g': + fprintf_filtered (stream, local_hex_format_custom ("016ll"), val_long); + break; + default: + abort (); + } +#else /* !PRINTF_HAS_LONG_LONG */ + /* In the following it is important to coerce (val_long) to a long. It does + nothing if !LONG_LONG, but it will chop off the top half (which we know + we can ignore) if the host supports long longs. */ + + switch (format) + { + case 'd': + fprintf_filtered (stream, + use_local ? local_decimal_format_custom ("l") + : "%ld", + (long) val_long); + break; + case 'u': + fprintf_filtered (stream, "%lu", (unsigned long) val_long); + break; + case 'x': + fprintf_filtered (stream, + use_local ? local_hex_format_custom ("l") + : "%lx", + (long) val_long); + break; + case 'o': + fprintf_filtered (stream, + use_local ? local_octal_format_custom ("l") + : "%lo", + (long) val_long); + break; + case 'b': + fprintf_filtered (stream, local_hex_format_custom ("02l"), + (long) val_long); + break; + case 'h': + fprintf_filtered (stream, local_hex_format_custom ("04l"), + (long) val_long); + break; + case 'w': + fprintf_filtered (stream, local_hex_format_custom ("08l"), + (long) val_long); + break; + case 'g': + fprintf_filtered (stream, local_hex_format_custom ("016l"), + (long) val_long); + break; + default: + abort (); + } +#endif /* !PRINTF_HAS_LONG_LONG */ +} + +/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR, + on STREAM. */ + +void +print_floating (valaddr, type, stream) + char *valaddr; + struct type *type; + FILE *stream; +{ + double doub; + int inv; + unsigned len = TYPE_LENGTH (type); + +#if defined (IEEE_FLOAT) + + /* Check for NaN's. Note that this code does not depend on us being + on an IEEE conforming system. It only depends on the target + machine using IEEE representation. This means (a) + cross-debugging works right, and (2) IEEE_FLOAT can (and should) + be defined for systems like the 68881, which uses IEEE + representation, but is not IEEE conforming. */ + + { + long low, high; + /* Is the sign bit 0? */ + int nonnegative; + /* Is it is a NaN (i.e. the exponent is all ones and + the fraction is nonzero)? */ + int is_nan; + + if (len == sizeof (float)) + { + /* It's single precision. */ + memcpy ((char *) &low, valaddr, sizeof (low)); + /* target -> host. */ + SWAP_TARGET_AND_HOST (&low, sizeof (float)); + nonnegative = low >= 0; + is_nan = ((((low >> 23) & 0xFF) == 0xFF) + && 0 != (low & 0x7FFFFF)); + low &= 0x7fffff; + high = 0; + } + else + { + /* It's double precision. Get the high and low words. */ + +#if TARGET_BYTE_ORDER == BIG_ENDIAN + memcpy (&low, valaddr+4, sizeof (low)); + memcpy (&high, valaddr+0, sizeof (high)); +#else + memcpy (&low, valaddr+0, sizeof (low)); + memcpy (&high, valaddr+4, sizeof (high)); +#endif + SWAP_TARGET_AND_HOST (&low, sizeof (low)); + SWAP_TARGET_AND_HOST (&high, sizeof (high)); + nonnegative = high >= 0; + is_nan = (((high >> 20) & 0x7ff) == 0x7ff + && ! ((((high & 0xfffff) == 0)) && (low == 0))); + high &= 0xfffff; + } + + if (is_nan) + { + /* The meaning of the sign and fraction is not defined by IEEE. + But the user might know what they mean. For example, they + (in an implementation-defined manner) distinguish between + signaling and quiet NaN's. */ + if (high) + fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonnegative, + high, low); + else + fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low); + return; + } + } +#endif /* IEEE_FLOAT. */ + + doub = unpack_double (type, valaddr, &inv); + if (inv) + fprintf_filtered (stream, ""); + else + fprintf_filtered (stream, len <= sizeof(float) ? "%.9g" : "%.17g", doub); +} + +/* VALADDR points to an integer of LEN bytes. Print it in hex on stream. */ + +static void +print_hex_chars (stream, valaddr, len) + FILE *stream; + unsigned char *valaddr; + unsigned len; +{ + unsigned char *p; + + /* FIXME: We should be not printing leading zeroes in most cases. */ + + fprintf_filtered (stream, local_hex_format_prefix ()); +#if TARGET_BYTE_ORDER == BIG_ENDIAN + for (p = valaddr; + p < valaddr + len; + p++) +#else /* Little endian. */ + for (p = valaddr + len - 1; + p >= valaddr; + p--) +#endif + { + fprintf_filtered (stream, "%02x", *p); + } + fprintf_filtered (stream, local_hex_format_suffix ()); +} + +/* Called by various _val_print routines to print elements of an + array in the form ", , , ...". + + (FIXME?) Assumes array element separator is a comma, which is correct + for all languages currently handled. + (FIXME?) Some languages have a notation for repeated array elements, + perhaps we should try to use that notation when appropriate. + */ + +void +val_print_array_elements (type, valaddr, address, stream, format, deref_ref, + recurse, pretty, i) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; + unsigned int i; +{ + unsigned int things_printed = 0; + unsigned len; + struct type *elttype; + unsigned eltlen; + /* Position of the array element we are examining to see + whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + + for (; i < len && things_printed < print_max; i++) + { + if (i != 0) + { + if (prettyprint_arrays) + { + fprintf_filtered (stream, ",\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + fprintf_filtered (stream, ", "); + } + } + wrap_here (n_spaces (2 + 2 * recurse)); + + rep1 = i + 1; + reps = 1; + while ((rep1 < len) && + !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen)) + { + ++reps; + ++rep1; + } + + if (reps > repeat_count_threshold) + { + val_print (elttype, valaddr + i * eltlen, 0, stream, format, + deref_ref, recurse + 1, pretty); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + } + else + { + val_print (elttype, valaddr + i * eltlen, 0, stream, format, + deref_ref, recurse + 1, pretty); + things_printed++; + } + } + if (i < len) + { + fprintf_filtered (stream, "..."); + } +} + +static void +value_print_array_elements (val, stream, format, pretty) + value val; + FILE *stream; + int format; + enum val_prettyprint pretty; +{ + unsigned int things_printed = 0; + register unsigned int i, n, typelen; + /* Position of the array elem we are examining to see if it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + n = VALUE_REPETITIONS (val); + typelen = TYPE_LENGTH (VALUE_TYPE (val)); + for (i = 0; i < n && things_printed < print_max; i++) + { + if (i != 0) + { + fprintf_filtered (stream, ", "); + } + wrap_here (""); + + rep1 = i + 1; + reps = 1; + while (rep1 < n && !memcmp (VALUE_CONTENTS (val) + typelen * i, + VALUE_CONTENTS (val) + typelen * rep1, + typelen)) + { + ++reps; + ++rep1; + } + + if (reps > repeat_count_threshold) + { + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i, + VALUE_ADDRESS (val) + typelen * i, stream, format, 1, + 0, pretty); + fprintf (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + } + else + { + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i, + VALUE_ADDRESS (val) + typelen * i, stream, format, 1, + 0, pretty); + things_printed++; + } + } + if (i < n) + { + fprintf_filtered (stream, "..."); + } +} + +/* Print a string from the inferior, starting at ADDR and printing up to LEN + characters, to STREAM. If LEN is zero, printing stops at the first null + byte, otherwise printing proceeds (including null bytes) until either + print_max or LEN characters have been printed, whichever is smaller. */ + +int +val_print_string (addr, len, stream) + CORE_ADDR addr; + unsigned int len; + FILE *stream; +{ + int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */ + int errcode; /* Errno returned from bad reads. */ + unsigned int fetchlimit; /* Maximum number of bytes to fetch. */ + unsigned int nfetch; /* Bytes to fetch / bytes fetched. */ + unsigned int chunksize; /* Size of each fetch, in bytes. */ + int bufsize; /* Size of current fetch buffer. */ + char *buffer = NULL; /* Dynamically growable fetch buffer. */ + char *bufptr; /* Pointer to next available byte in buffer. */ + char *limit; /* First location past end of fetch buffer. */ + struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */ + char peekchar; /* Place into which we can read one char. */ + + /* First we need to figure out the limit on the number of characters we are + going to attempt to fetch and print. This is actually pretty simple. If + LEN is nonzero, then the limit is the minimum of LEN and print_max. If + LEN is zero, then the limit is print_max. This is true regardless of + whether print_max is zero, UINT_MAX (unlimited), or something in between, + because finding the null byte (or available memory) is what actually + limits the fetch. */ + + fetchlimit = (len == 0 ? print_max : min (len, print_max)); + + /* Now decide how large of chunks to try to read in one operation. This + is also pretty simple. If LEN is nonzero, then we want fetchlimit bytes, + so we might as well read them all in one operation. If LEN is zero, we + are looking for a null terminator to end the fetching, so we might as + well read in blocks that are large enough to be efficient, but not so + large as to be slow if fetchlimit happens to be large. So we choose the + minimum of DEFAULT_PRINT_MAX and fetchlimit. */ + + chunksize = (len == 0 ? min (PRINT_MAX_DEFAULT, fetchlimit) : fetchlimit); + + /* Loop until we either have all the characters to print, or we encounter + some error, such as bumping into the end of the address space. */ + + bufsize = 0; + do { + QUIT; + /* Figure out how much to fetch this time, and grow the buffer to fit. */ + nfetch = min (chunksize, fetchlimit - bufsize); + bufsize += nfetch; + if (buffer == NULL) + { + buffer = (char *) xmalloc (bufsize); + bufptr = buffer; + } + else + { + discard_cleanups (old_chain); + buffer = (char *) xrealloc (buffer, bufsize); + bufptr = buffer + bufsize - nfetch; + } + old_chain = make_cleanup (free, buffer); + + /* Read as much as we can. */ + nfetch = target_read_memory_partial (addr, bufptr, nfetch, &errcode); + if (len != 0) + { + addr += nfetch; + bufptr += nfetch; + } + else + { + /* Scan this chunk for the null byte that terminates the string + to print. If found, we don't need to fetch any more. Note + that bufptr is explicitly left pointing at the next character + after the null byte, or at the next character after the end of + the buffer. */ + limit = bufptr + nfetch; + do { + addr++; + bufptr++; + } while (bufptr < limit && *(bufptr - 1) != '\0'); + } + } while (errcode == 0 /* no error */ + && bufptr < buffer + fetchlimit /* no overrun */ + && !(len == 0 && *(bufptr - 1) == '\0')); /* no null term */ + + /* We now have either successfully filled the buffer to fetchlimit, or + terminated early due to an error or finding a null byte when LEN is + zero. */ + + if (len == 0 && *(bufptr - 1) != '\0') + { + /* We didn't find a null terminator we were looking for. Attempt + to peek at the next character. If not successful, or it is not + a null byte, then force ellipsis to be printed. */ + if (target_read_memory (addr, &peekchar, 1) != 0 || peekchar != '\0') + { + force_ellipsis = 1; + } + } + else if ((len != 0 && errcode != 0) || (len > bufptr - buffer)) + { + /* Getting an error when we have a requested length, or fetching less + than the number of characters actually requested, always make us + print ellipsis. */ + force_ellipsis = 1; + } + + QUIT; + + if (addressprint) + { + fputs_filtered (" ", stream); + } + LA_PRINT_STRING (stream, buffer, bufptr - buffer, force_ellipsis); + + if (errcode != 0 && force_ellipsis) + { + if (errcode == EIO) + { + fprintf_filtered (stream, + "
", + (unsigned long) addr); + } + else + { + error ("Error reading memory address 0x%lx: %s.", + (unsigned long) addr, + safe_strerror (errcode)); + } + } + fflush (stream); + do_cleanups (old_chain); + return (bufptr - buffer); +} + + +/* Validate an input or output radix setting, and make sure the user + knows what they really did here. Radix setting is confusing, e.g. + setting the input radix to "10" never changes it! */ + +/* ARGSUSED */ +static void +set_input_radix (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + set_input_radix_1 (from_tty, *(unsigned *)c->var); +} + +/* ARGSUSED */ +static void +set_input_radix_1 (from_tty, radix) + int from_tty; + unsigned radix; +{ + /* We don't currently disallow any input radix except 0 or 1, which don't + make any mathematical sense. In theory, we can deal with any input + radix greater than 1, even if we don't have unique digits for every + value from 0 to radix-1, but in practice we lose on large radix values. + We should either fix the lossage or restrict the radix range more. + (FIXME). */ + + if (radix < 2) + { + error ("Nonsense input radix ``decimal %u''; input radix unchanged.", + radix); + } + input_radix = radix; + if (from_tty) + { + printf_filtered ("Input radix now set to decimal %u, hex %x, octal %o.\n", + radix, radix, radix); + } +} + +/* ARGSUSED */ +static void +set_output_radix (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + set_output_radix_1 (from_tty, *(unsigned *)c->var); +} + +static void +set_output_radix_1 (from_tty, radix) + int from_tty; + unsigned radix; +{ + /* Validate the radix and disallow ones that we aren't prepared to + handle correctly, leaving the radix unchanged. */ + switch (radix) + { + case 16: + output_format = 'x'; /* hex */ + break; + case 10: + output_format = 0; /* decimal */ + break; + case 8: + output_format = 'o'; /* octal */ + break; + default: + error ("Unsupported output radix ``decimal %u''; output radix unchanged.", + radix); + } + output_radix = radix; + if (from_tty) + { + printf_filtered ("Output radix now set to decimal %u, hex %x, octal %o.\n", + radix, radix, radix); + } +} + +/* Set both the input and output radix at once. Try to set the output radix + first, since it has the most restrictive range. An radix that is valid as + an output radix is also valid as an input radix. + + It may be useful to have an unusual input radix. If the user wishes to + set an input radix that is not valid as an output radix, he needs to use + the 'set input-radix' command. */ + +static void +set_radix (arg, from_tty) + char *arg; + int from_tty; +{ + unsigned radix; + + radix = (arg == NULL) ? 10 : parse_and_eval_address (arg); + set_output_radix_1 (0, radix); + set_input_radix_1 (0, radix); + if (from_tty) + { + printf_filtered ("Input and output radices now set to decimal %u, hex %x, octal %o.\n", + radix, radix, radix); + } +} + +/* Show both the input and output radices. */ + +/*ARGSUSED*/ +static void +show_radix (arg, from_tty) + char *arg; + int from_tty; +{ + if (from_tty) + { + if (input_radix == output_radix) + { + printf_filtered ("Input and output radices set to decimal %u, hex %x, octal %o.\n", + input_radix, input_radix, input_radix); + } + else + { + printf_filtered ("Input radix set to decimal %u, hex %x, octal %o.\n", + input_radix, input_radix, input_radix); + printf_filtered ("Output radix set to decimal %u, hex %x, octal %o.\n", + output_radix, output_radix, output_radix); + } + } +} + + +/*ARGSUSED*/ +static void +set_print (arg, from_tty) + char *arg; + int from_tty; +{ + printf ( +"\"set print\" must be followed by the name of a print subcommand.\n"); + help_list (setprintlist, "set print ", -1, stdout); +} + +/*ARGSUSED*/ +static void +show_print (args, from_tty) + char *args; + int from_tty; +{ + cmd_show_list (showprintlist, from_tty, ""); +} + +void +_initialize_valprint () +{ + struct cmd_list_element *c; + + add_prefix_cmd ("print", no_class, set_print, + "Generic command for setting how things print.", + &setprintlist, "set print ", 0, &setlist); + add_alias_cmd ("p", "print", no_class, 1, &setlist); + /* prefer set print to set prompt */ + add_alias_cmd ("pr", "print", no_class, 1, &setlist); + + add_prefix_cmd ("print", no_class, show_print, + "Generic command for showing print settings.", + &showprintlist, "show print ", 0, &showlist); + add_alias_cmd ("p", "print", no_class, 1, &showlist); + add_alias_cmd ("pr", "print", no_class, 1, &showlist); + + add_show_from_set + (add_set_cmd ("elements", no_class, var_uinteger, (char *)&print_max, + "Set limit on string chars or array elements to print.\n\ +\"set print elements 0\" causes there to be no limit.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("repeats", no_class, var_uinteger, + (char *)&repeat_count_threshold, + "Set threshold for repeated print elements.\n\ +\"set print repeats 0\" causes all elements to be individually printed.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("pretty", class_support, var_boolean, + (char *)&prettyprint_structs, + "Set prettyprinting of structures.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("union", class_support, var_boolean, (char *)&unionprint, + "Set printing of unions interior to structures.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("array", class_support, var_boolean, + (char *)&prettyprint_arrays, + "Set prettyprinting of arrays.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("address", class_support, var_boolean, (char *)&addressprint, + "Set printing of addresses.", + &setprintlist), + &showprintlist); + + c = add_set_cmd ("input-radix", class_support, var_uinteger, + (char *)&input_radix, + "Set default input radix for entering numbers.", + &setlist); + add_show_from_set (c, &showlist); + c->function.sfunc = set_input_radix; + + c = add_set_cmd ("output-radix", class_support, var_uinteger, + (char *)&output_radix, + "Set default output radix for printing of values.", + &setlist); + add_show_from_set (c, &showlist); + c->function.sfunc = set_output_radix; + + /* The "set radix" and "show radix" commands are special in that they are + like normal set and show commands but allow two normally independent + variables to be either set or shown with a single command. So the + usual add_set_cmd() and add_show_from_set() commands aren't really + appropriate. */ + add_cmd ("radix", class_support, set_radix, + "Set default input and output number radices.\n\ +Use 'set input-radix' or 'set output-radix' to independently set each.\n\ +Without an argument, sets both radices back to the default value of 10.", + &setlist); + add_cmd ("radix", class_support, show_radix, + "Show the default input and output number radices.\n\ +Use 'show input-radix' or 'show output-radix' to independently show each.", + &showlist); + + /* Give people the defaults which they are used to. */ + prettyprint_structs = 0; + prettyprint_arrays = 0; + unionprint = 1; + addressprint = 1; + print_max = PRINT_MAX_DEFAULT; +} diff --git a/gnu/usr.bin/gdb/gdb/valprint.h b/gnu/usr.bin/gdb/gdb/valprint.h new file mode 100644 index 00000000000..5918def07e6 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/valprint.h @@ -0,0 +1,40 @@ +/* Declarations for value printing routines for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 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. */ + + +extern int prettyprint_arrays; /* Controls pretty printing of arrays. */ +extern int prettyprint_structs; /* Controls pretty printing of structures */ +extern int prettyprint_arrays; /* Controls pretty printing of arrays. */ + +extern int vtblprint; /* Controls printing of vtbl's */ +extern int unionprint; /* Controls printing of nested unions. */ +extern int addressprint; /* Controls pretty printing of addresses. */ +extern int objectprint; /* Controls looking up an object's derived type + using what we find in its vtables. */ + +extern unsigned int print_max; /* Max # of chars for strings/vectors */ +extern int output_format; + +extern void +val_print_array_elements PARAMS ((struct type *, char *, CORE_ADDR, FILE *, + int, int, int, enum val_prettyprint, int)); + +extern void +val_print_type_code_int PARAMS ((struct type *, char *, FILE *)); + diff --git a/gnu/usr.bin/gdb/gdb/value.h b/gnu/usr.bin/gdb/gdb/value.h new file mode 100644 index 00000000000..b8e16761e5d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/value.h @@ -0,0 +1,502 @@ +/* Definitions for values of C expressions, for GDB. + Copyright 1986, 1987, 1989, 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. */ + +#if !defined (VALUE_H) +#define VALUE_H 1 + +/* + * The structure which defines the type of a value. It should never + * be possible for a program lval value to survive over a call to the inferior + * (ie to be put into the history list or an internal variable). + */ +enum lval_type { + /* Not an lval. */ + not_lval, + /* In memory. Could be a saved register. */ + lval_memory, + /* In a register. */ + lval_register, + /* In a gdb internal variable. */ + lval_internalvar, + /* Part of a gdb internal variable (structure field). */ + lval_internalvar_component, + /* In a register series in a frame not the current one, which may have been + partially saved or saved in different places (otherwise would be + lval_register or lval_memory). */ + lval_reg_frame_relative +}; + +struct value + { + /* Type of value; either not an lval, or one of the various + different possible kinds of lval. */ + enum lval_type lval; + /* Location of value (if lval). */ + union + { + /* Address in inferior or byte of registers structure. */ + CORE_ADDR address; + /* Pointer to internal variable. */ + struct internalvar *internalvar; + /* Number of register. Only used with + lval_reg_frame_relative. */ + int regnum; + } location; + /* Describes offset of a value within lval a structure in bytes. */ + int offset; + /* Only used for bitfields; number of bits contained in them. */ + int bitsize; + /* Only used for bitfields; position of start of field. + For BITS_BIG_ENDIAN=0 targets, it is the position of the LSB. + For BITS_BIG_ENDIAN=1 targets, it is the position of the MSB. */ + int bitpos; + /* Frame value is relative to. In practice, this address is only + used if the value is stored in several registers in other than + the current frame, and these registers have not all been saved + at the same place in memory. This will be described in the + lval enum above as "lval_reg_frame_relative". */ + CORE_ADDR frame_addr; + /* Type of the value. */ + struct type *type; + /* Values are stored in a chain, so that they can be deleted + easily over calls to the inferior. Values assigned to internal + variables or put into the value history are taken off this + list. */ + struct value *next; + /* If an lval is forced to repeat, a new value is created with + these fields set. The new value is not an lval. */ + short repeated; + short repetitions; + /* Register number if the value is from a register. Is not kept + if you take a field of a structure that is stored in a + register. Shouldn't it be? */ + short regno; + /* If zero, contents of this value are in the contents field. + If nonzero, contents are in inferior memory at address + in the location.address field plus the offset field + (and the lval field should be lval_memory). */ + char lazy; + /* If nonzero, this is the value of a variable which does not + actually exist in the program. */ + char optimized_out; + /* Actual contents of the value. For use of this value; setting + it uses the stuff above. Not valid if lazy is nonzero. + Target byte-order. We force it to be aligned properly for any + possible value. */ + union { + long contents[1]; + double force_double_align; +#ifdef CC_HAS_LONG_LONG + long long force_longlong_align; +#endif + } aligner; + + }; + +typedef struct value *value; + +#define VALUE_TYPE(val) (val)->type +#define VALUE_LAZY(val) (val)->lazy +/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of + the gdb buffer used to hold a copy of the contents of the lval. + VALUE_CONTENTS is used when the contents of the buffer are needed -- + it uses value_fetch_lazy() to load the buffer from the process being + debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is + used when data is being stored into the buffer, or when it is + certain that the contents of the buffer are valid. */ +#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents) +#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\ + VALUE_CONTENTS_RAW(val)) +extern int +value_fetch_lazy PARAMS ((value val)); + +#define VALUE_LVAL(val) (val)->lval +#define VALUE_ADDRESS(val) (val)->location.address +#define VALUE_INTERNALVAR(val) (val)->location.internalvar +#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum) +#define VALUE_FRAME(val) ((val)->frame_addr) +#define VALUE_OFFSET(val) (val)->offset +#define VALUE_BITSIZE(val) (val)->bitsize +#define VALUE_BITPOS(val) (val)->bitpos +#define VALUE_NEXT(val) (val)->next +#define VALUE_REPEATED(val) (val)->repeated +#define VALUE_REPETITIONS(val) (val)->repetitions +#define VALUE_REGNO(val) (val)->regno +#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out) + +/* Convert a REF to the object referenced. */ + +#define COERCE_REF(arg) \ +{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_REF) \ + arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)), \ + unpack_long (VALUE_TYPE (arg), \ + VALUE_CONTENTS (arg)));} + +/* If ARG is an array, convert it to a pointer. + If ARG is an enum, convert it to an integer. + If ARG is a function, convert it to a function pointer. + + References are dereferenced. */ + +#define COERCE_ARRAY(arg) \ +{ COERCE_REF(arg); \ + if (VALUE_REPEATED (arg) \ + || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \ + arg = value_coerce_array (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \ + arg = value_coerce_function (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* If ARG is an enum, convert it to an integer. */ + +#define COERCE_ENUM(arg) \ +{ COERCE_REF (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* Internal variables (variables for convenience of use of debugger) + are recorded as a chain of these structures. */ + +struct internalvar +{ + struct internalvar *next; + char *name; + value value; +}; + +/* Pointer to member function. Depends on compiler implementation. */ + +#define METHOD_PTR_IS_VIRTUAL(ADDR) ((ADDR) & 0x80000000) +#define METHOD_PTR_FROM_VOFFSET(OFFSET) (0x80000000 + (OFFSET)) +#define METHOD_PTR_TO_VOFFSET(ADDR) (~0x80000000 & (ADDR)) + + +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" + +#ifdef __STDC__ +struct frame_info; +struct fn_field; +#endif + +extern void +print_address_demangle PARAMS ((CORE_ADDR, FILE *, int)); + +extern LONGEST +value_as_long PARAMS ((value val)); + +extern double +value_as_double PARAMS ((value val)); + +extern CORE_ADDR +value_as_pointer PARAMS ((value val)); + +extern LONGEST +unpack_long PARAMS ((struct type *type, char *valaddr)); + +extern double +unpack_double PARAMS ((struct type *type, char *valaddr, int *invp)); + +extern CORE_ADDR unpack_pointer PARAMS ((struct type *type, char *valaddr)); + +extern LONGEST unpack_field_as_long PARAMS ((struct type *type, char *valaddr, + int fieldno)); + +extern value value_from_longest PARAMS ((struct type *type, LONGEST num)); + +extern value value_from_double PARAMS ((struct type *type, double num)); + +extern value value_at PARAMS ((struct type *type, CORE_ADDR addr)); + +extern value value_at_lazy PARAMS ((struct type *type, CORE_ADDR addr)); + +/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */ +extern value value_from_register PARAMS ((struct type *type, int regnum, + struct frame_info * frame)); + +extern value value_of_variable PARAMS ((struct symbol *var, struct block *b)); + +extern value value_of_register PARAMS ((int regnum)); + +extern int symbol_read_needs_frame PARAMS ((struct symbol *)); + +/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */ +extern value read_var_value PARAMS ((struct symbol *var, + struct frame_info *frame)); + +/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */ +extern value locate_var_value PARAMS ((struct symbol *var, + struct frame_info *frame)); + +extern value allocate_value PARAMS ((struct type *type)); + +extern value allocate_repeat_value PARAMS ((struct type *type, int count)); + +extern value value_mark PARAMS ((void)); + +extern void value_free_to_mark PARAMS ((value mark)); + +extern value value_string PARAMS ((char *ptr, int len)); + +extern value value_array PARAMS ((int lowbound, int highbound, + value *elemvec)); + +extern value value_concat PARAMS ((value arg1, value arg2)); + +extern value value_binop PARAMS ((value arg1, value arg2, enum exp_opcode op)); + +extern value value_add PARAMS ((value arg1, value arg2)); + +extern value value_sub PARAMS ((value arg1, value arg2)); + +extern value value_coerce_array PARAMS ((value arg1)); + +extern value value_coerce_function PARAMS ((value arg1)); + +extern value value_ind PARAMS ((value arg1)); + +extern value value_addr PARAMS ((value arg1)); + +extern value value_assign PARAMS ((value toval, value fromval)); + +extern value value_neg PARAMS ((value arg1)); + +extern value value_complement PARAMS ((value arg1)); + +extern value value_struct_elt PARAMS ((value *argp, value *args, char *name, + int *static_memfuncp, char *err)); + +extern value value_struct_elt_for_reference PARAMS ((struct type *domain, + int offset, + struct type *curtype, + char *name, + struct type *intype)); + +extern value value_field PARAMS ((value arg1, int fieldno)); + +extern value value_primitive_field PARAMS ((value arg1, int offset, + int fieldno, + struct type *arg_type)); + +extern value value_cast PARAMS ((struct type *type, value arg2)); + +extern value value_zero PARAMS ((struct type *type, enum lval_type lv)); + +extern value value_repeat PARAMS ((value arg1, int count)); + +extern value value_subscript PARAMS ((value array, value idx)); + +extern value value_from_vtable_info PARAMS ((value arg, struct type *type)); + +extern value value_being_returned PARAMS ((struct type *valtype, + char retbuf[REGISTER_BYTES], + int struct_return)); + +extern int +using_struct_return PARAMS ((value function, CORE_ADDR funcaddr, + struct type *value_type, int gcc_p)); + +extern void +set_return_value PARAMS ((value val)); + +extern value +evaluate_expression PARAMS ((struct expression *exp)); + +extern value +evaluate_type PARAMS ((struct expression *exp)); + +extern value +parse_and_eval PARAMS ((char *exp)); + +extern value +parse_to_comma_and_eval PARAMS ((char **expp)); + +extern struct type * +parse_and_eval_type PARAMS ((char *p, int length)); + +extern CORE_ADDR +parse_and_eval_address PARAMS ((char *exp)); + +extern CORE_ADDR +parse_and_eval_address_1 PARAMS ((char **expptr)); + +extern value +access_value_history PARAMS ((int num)); + +extern value +value_of_internalvar PARAMS ((struct internalvar *var)); + +extern void +set_internalvar PARAMS ((struct internalvar *var, value val)); + +extern void +set_internalvar_component PARAMS ((struct internalvar *var, int offset, + int bitpos, int bitsize, + value newvalue)); + +extern struct internalvar * +lookup_internalvar PARAMS ((char *name)); + +extern int +value_equal PARAMS ((value arg1, value arg2)); + +extern int +value_less PARAMS ((value arg1, value arg2)); + +extern int +value_logical_not PARAMS ((value arg1)); + +/* C++ */ + +extern value +value_of_this PARAMS ((int complain)); + +extern value +value_x_binop PARAMS ((value arg1, value arg2, enum exp_opcode op, + enum exp_opcode otherop)); + +extern value +value_x_unop PARAMS ((value arg1, enum exp_opcode op)); + +extern value +value_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j, + struct type* type, int offset)); + +extern value +value_virtual_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j, + struct type *type, int offset)); + +extern int +binop_user_defined_p PARAMS ((enum exp_opcode op, value arg1, value arg2)); + +extern int +unop_user_defined_p PARAMS ((enum exp_opcode op, value arg1)); + +extern int +destructor_name_p PARAMS ((const char *name, const struct type *type)); + +#define value_free(val) free ((PTR)val) + +extern void +free_all_values PARAMS ((void)); + +extern void +release_value PARAMS ((value val)); + +extern int +record_latest_value PARAMS ((value val)); + +extern void +registers_changed PARAMS ((void)); + +extern void +read_register_bytes PARAMS ((int regbyte, char *myaddr, int len)); + +extern void +write_register_bytes PARAMS ((int regbyte, char *myaddr, int len)); + +extern void +read_register_gen PARAMS ((int regno, char *myaddr)); + +extern CORE_ADDR +read_register PARAMS ((int regno)); + +extern void +write_register PARAMS ((int regno, LONGEST val)); + +extern void +supply_register PARAMS ((int regno, char *val)); + +/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */ +extern void +get_saved_register PARAMS ((char *raw_buffer, int *optimized, + CORE_ADDR *addrp, struct frame_info *frame, + int regnum, enum lval_type *lval)); + +extern void +modify_field PARAMS ((char *addr, LONGEST fieldval, int bitpos, int bitsize)); + +extern void +type_print PARAMS ((struct type *type, char *varstring, FILE *stream, + int show)); + +extern char * +baseclass_addr PARAMS ((struct type *type, int index, char *valaddr, + value *valuep, int *errp)); + +extern void +print_longest PARAMS ((FILE *stream, int format, int use_local, + LONGEST value)); + +extern void +print_floating PARAMS ((char *valaddr, struct type *type, FILE *stream)); + +extern int +value_print PARAMS ((value val, FILE *stream, int format, + enum val_prettyprint pretty)); + +extern int +val_print PARAMS ((struct type *type, char *valaddr, CORE_ADDR address, + FILE *stream, int format, int deref_ref, + int recurse, enum val_prettyprint pretty)); + +extern int +val_print_string PARAMS ((CORE_ADDR addr, unsigned int len, FILE *stream)); + +/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */ +extern void +print_variable_value PARAMS ((struct symbol *var, struct frame_info *frame, + FILE *stream)); + +extern value +value_arg_coerce PARAMS ((value)); + +extern int +check_field PARAMS ((value, const char *)); + +extern void +c_typedef_print PARAMS ((struct type *type, struct symbol *new, FILE *stream)); + +extern char * +internalvar_name PARAMS ((struct internalvar *var)); + +extern void +clear_value_history PARAMS ((void)); + +extern void +clear_internalvars PARAMS ((void)); + +/* From values.c */ + +extern value +value_copy PARAMS ((value)); + +extern int +baseclass_offset PARAMS ((struct type *, int, value, int)); + +/* From valops.c */ + +extern value +call_function_by_hand PARAMS ((value, int, value *)); + +#endif /* !defined (VALUE_H) */ diff --git a/gnu/usr.bin/gdb/gdb/values.c b/gnu/usr.bin/gdb/gdb/values.c new file mode 100644 index 00000000000..a592f9eeca9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/values.c @@ -0,0 +1,1502 @@ +/* Low level packing and unpacking of values for GDB, the GNU Debugger. + Copyright 1986, 1987, 1989, 1991 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. */ + +#include "defs.h" +#include +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "gdbcore.h" +#include "frame.h" +#include "command.h" +#include "gdbcmd.h" +#include "target.h" +#include "demangle.h" + +/* Local function prototypes. */ + +static value +value_headof PARAMS ((value, struct type *, struct type *)); + +static void +show_values PARAMS ((char *, int)); + +static void +show_convenience PARAMS ((char *, int)); + +/* The value-history records all the values printed + by print commands during this session. Each chunk + records 60 consecutive values. The first chunk on + the chain records the most recent values. + The total number of values is in value_history_count. */ + +#define VALUE_HISTORY_CHUNK 60 + +struct value_history_chunk +{ + struct value_history_chunk *next; + value values[VALUE_HISTORY_CHUNK]; +}; + +/* Chain of chunks now in use. */ + +static struct value_history_chunk *value_history_chain; + +static int value_history_count; /* Abs number of last entry stored */ + +/* List of all value objects currently allocated + (except for those released by calls to release_value) + This is so they can be freed after each command. */ + +static value all_values; + +/* Allocate a value that has the correct length for type TYPE. */ + +value +allocate_value (type) + struct type *type; +{ + register value val; + + check_stub_type (type); + + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type)); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_FRAME (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 0; + VALUE_REPETITIONS (val) = 0; + VALUE_REGNO (val) = -1; + VALUE_LAZY (val) = 0; + VALUE_OPTIMIZED_OUT (val) = 0; + return val; +} + +/* Allocate a value that has the correct length + for COUNT repetitions type TYPE. */ + +value +allocate_repeat_value (type, count) + struct type *type; + int count; +{ + register value val; + + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_FRAME (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 1; + VALUE_REPETITIONS (val) = count; + VALUE_REGNO (val) = -1; + VALUE_LAZY (val) = 0; + VALUE_OPTIMIZED_OUT (val) = 0; + return val; +} + +/* Return a mark in the value chain. All values allocated after the + mark is obtained (except for those released) are subject to being freed + if a subsequent value_free_to_mark is passed the mark. */ +value +value_mark () +{ + return all_values; +} + +/* Free all values allocated since MARK was obtained by value_mark + (except for those released). */ +void +value_free_to_mark (mark) + value mark; +{ + value val, next; + + for (val = all_values; val && val != mark; val = next) + { + next = VALUE_NEXT (val); + value_free (val); + } + all_values = val; +} + +/* Free all the values that have been allocated (except for those released). + Called after each command, successful or not. */ + +void +free_all_values () +{ + register value val, next; + + for (val = all_values; val; val = next) + { + next = VALUE_NEXT (val); + value_free (val); + } + + all_values = 0; +} + +/* Remove VAL from the chain all_values + so it will not be freed automatically. */ + +void +release_value (val) + register value val; +{ + register value v; + + if (all_values == val) + { + all_values = val->next; + return; + } + + for (v = all_values; v; v = v->next) + { + if (v->next == val) + { + v->next = val->next; + break; + } + } +} + +/* Return a copy of the value ARG. + It contains the same contents, for same memory address, + but it's a different block of storage. */ + +value +value_copy (arg) + value arg; +{ + register value val; + register struct type *type = VALUE_TYPE (arg); + if (VALUE_REPEATED (arg)) + val = allocate_repeat_value (type, VALUE_REPETITIONS (arg)); + else + val = allocate_value (type); + VALUE_LVAL (val) = VALUE_LVAL (arg); + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg); + VALUE_OFFSET (val) = VALUE_OFFSET (arg); + VALUE_BITPOS (val) = VALUE_BITPOS (arg); + VALUE_BITSIZE (val) = VALUE_BITSIZE (arg); + VALUE_REGNO (val) = VALUE_REGNO (arg); + VALUE_LAZY (val) = VALUE_LAZY (arg); + if (!VALUE_LAZY (val)) + { + memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS_RAW (arg), + TYPE_LENGTH (VALUE_TYPE (arg)) + * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1)); + } + return val; +} + +/* Access to the value history. */ + +/* Record a new value in the value history. + Returns the absolute history index of the entry. + Result of -1 indicates the value was not saved; otherwise it is the + value history index of this new item. */ + +int +record_latest_value (val) + value val; +{ + int i; + + /* Check error now if about to store an invalid float. We return -1 + to the caller, but allow them to continue, e.g. to print it as "Nan". */ + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) + { + unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i); + if (i) return -1; /* Indicate value not saved in history */ + } + + /* Here we treat value_history_count as origin-zero + and applying to the value being stored now. */ + + i = value_history_count % VALUE_HISTORY_CHUNK; + if (i == 0) + { + register struct value_history_chunk *new + = (struct value_history_chunk *) + xmalloc (sizeof (struct value_history_chunk)); + memset (new->values, 0, sizeof new->values); + new->next = value_history_chain; + value_history_chain = new; + } + + value_history_chain->values[i] = val; + + /* We don't want this value to have anything to do with the inferior anymore. + In particular, "set $1 = 50" should not affect the variable from which + the value was taken, and fast watchpoints should be able to assume that + a value on the value history never changes. */ + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + VALUE_LVAL (val) = not_lval; + release_value (val); + + /* Now we regard value_history_count as origin-one + and applying to the value just stored. */ + + return ++value_history_count; +} + +/* Return a copy of the value in the history with sequence number NUM. */ + +value +access_value_history (num) + int num; +{ + register struct value_history_chunk *chunk; + register int i; + register int absnum = num; + + if (absnum <= 0) + absnum += value_history_count; + + if (absnum <= 0) + { + if (num == 0) + error ("The history is empty."); + else if (num == 1) + error ("There is only one value in the history."); + else + error ("History does not go back to $$%d.", -num); + } + if (absnum > value_history_count) + error ("History has not yet reached $%d.", absnum); + + absnum--; + + /* Now absnum is always absolute and origin zero. */ + + chunk = value_history_chain; + for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; + i > 0; i--) + chunk = chunk->next; + + return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]); +} + +/* Clear the value history entirely. + Must be done when new symbol tables are loaded, + because the type pointers become invalid. */ + +void +clear_value_history () +{ + register struct value_history_chunk *next; + register int i; + register value val; + + while (value_history_chain) + { + for (i = 0; i < VALUE_HISTORY_CHUNK; i++) + if ((val = value_history_chain->values[i]) != NULL) + free ((PTR)val); + next = value_history_chain->next; + free ((PTR)value_history_chain); + value_history_chain = next; + } + value_history_count = 0; +} + +static void +show_values (num_exp, from_tty) + char *num_exp; + int from_tty; +{ + register int i; + register value val; + static int num = 1; + + if (num_exp) + { + /* "info history +" should print from the stored position. + "info history " should print around value number . */ + if (num_exp[0] != '+' || num_exp[1] != '\0') + num = parse_and_eval_address (num_exp) - 5; + } + else + { + /* "info history" means print the last 10 values. */ + num = value_history_count - 9; + } + + if (num <= 0) + num = 1; + + for (i = num; i < num + 10 && i <= value_history_count; i++) + { + val = access_value_history (i); + printf_filtered ("$%d = ", i); + value_print (val, stdout, 0, Val_pretty_default); + printf_filtered ("\n"); + } + + /* The next "info history +" should start after what we just printed. */ + num += 10; + + /* Hitting just return after this command should do the same thing as + "info history +". If num_exp is null, this is unnecessary, since + "info history +" is not useful after "info history". */ + if (from_tty && num_exp) + { + num_exp[0] = '+'; + num_exp[1] = '\0'; + } +} + +/* Internal variables. These are variables within the debugger + that hold values assigned by debugger commands. + The user refers to them with a '$' prefix + that does not appear in the variable names stored internally. */ + +static struct internalvar *internalvars; + +/* Look up an internal variable with name NAME. NAME should not + normally include a dollar sign. + + If the specified internal variable does not exist, + one is created, with a void value. */ + +struct internalvar * +lookup_internalvar (name) + char *name; +{ + register struct internalvar *var; + + for (var = internalvars; var; var = var->next) + if (STREQ (var->name, name)) + return var; + + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, NULL); + var->value = allocate_value (builtin_type_void); + release_value (var->value); + var->next = internalvars; + internalvars = var; + return var; +} + +value +value_of_internalvar (var) + struct internalvar *var; +{ + register value val; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + return VALUE_OF_TRAPPED_INTERNALVAR (var); +#endif + + val = value_copy (var->value); + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; + return val; +} + +void +set_internalvar_component (var, offset, bitpos, bitsize, newval) + struct internalvar *var; + int offset, bitpos, bitsize; + value newval; +{ + register char *addr = VALUE_CONTENTS (var->value) + offset; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset); +#endif + + if (bitsize) + modify_field (addr, value_as_long (newval), + bitpos, bitsize); + else + memcpy (addr, VALUE_CONTENTS (newval), TYPE_LENGTH (VALUE_TYPE (newval))); +} + +void +set_internalvar (var, val) + struct internalvar *var; + value val; +{ +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0); +#endif + + free ((PTR)var->value); + var->value = value_copy (val); + /* Force the value to be fetched from the target now, to avoid problems + later when this internalvar is referenced and the target is gone or + has changed. */ + if (VALUE_LAZY (var->value)) + value_fetch_lazy (var->value); + release_value (var->value); +} + +char * +internalvar_name (var) + struct internalvar *var; +{ + return var->name; +} + +/* Free all internalvars. Done when new symtabs are loaded, + because that makes the values invalid. */ + +void +clear_internalvars () +{ + register struct internalvar *var; + + while (internalvars) + { + var = internalvars; + internalvars = var->next; + free ((PTR)var->name); + free ((PTR)var->value); + free ((PTR)var); + } +} + +static void +show_convenience (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct internalvar *var; + int varseen = 0; + + for (var = internalvars; var; var = var->next) + { +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + continue; +#endif + if (!varseen) + { + varseen = 1; + } + printf_filtered ("$%s = ", var->name); + value_print (var->value, stdout, 0, Val_pretty_default); + printf_filtered ("\n"); + } + if (!varseen) + printf ("No debugger convenience variables now defined.\n\ +Convenience variables have names starting with \"$\";\n\ +use \"set\" as in \"set $foo = 5\" to define them.\n"); +} + +/* Extract a value as a C number (either long or double). + Knows how to convert fixed values to double, or + floating values to long. + Does not deallocate the value. */ + +LONGEST +value_as_long (val) + register value val; +{ + /* This coerces arrays and functions, which is necessary (e.g. + in disassemble_command). It also dereferences references, which + I suspect is the most logical thing to do. */ + if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_ENUM) + COERCE_ARRAY (val); + return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); +} + +double +value_as_double (val) + register value val; +{ + double foo; + int inv; + + foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv); + if (inv) + error ("Invalid floating value found in program."); + return foo; +} +/* Extract a value as a C pointer. + Does not deallocate the value. */ +CORE_ADDR +value_as_pointer (val) + value val; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ +#if 0 + /* ADDR_BITS_REMOVE is wrong if we are being called for a + non-address (e.g. argument to "signal", "info break", etc.), or + for pointers to char, in which the low bits *are* significant. */ + return ADDR_BITS_REMOVE(value_as_long (val)); +#else + return value_as_long (val); +#endif +} + +/* Unpack raw data (copied from debugee, target byte order) at VALADDR + as a long, or as a double, assuming the raw data is described + by type TYPE. Knows how to convert different sizes of values + and can convert between fixed and floating point. We don't assume + any alignment for the raw data. Return value is in host byte order. + + If you want functions and arrays to be coerced to pointers, and + references to be dereferenced, call value_as_long() instead. + + C++: It is assumed that the front-end has taken care of + all matters concerning pointers to members. A pointer + to member which reaches here is considered to be equivalent + to an INT (or some size). After all, it is only an offset. */ + +/* FIXME: This should be rewritten as a switch statement for speed and + ease of comprehension. */ + +LONGEST +unpack_long (type, valaddr) + struct type *type; + char *valaddr; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + if (code == TYPE_CODE_ENUM || code == TYPE_CODE_BOOL) + code = TYPE_CODE_INT; + if (code == TYPE_CODE_FLT) + { + if (len == sizeof (float)) + { + float retval; + memcpy (&retval, valaddr, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (double)) + { + double retval; + memcpy (&retval, valaddr, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + else + { + error ("Unexpected type of floating point number."); + } + } + else if ((code == TYPE_CODE_INT || code == TYPE_CODE_CHAR) && nosign) + { + return extract_unsigned_integer (valaddr, len); + } + else if (code == TYPE_CODE_INT || code == TYPE_CODE_CHAR) + { + return extract_signed_integer (valaddr, len); + } + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + else if (code == TYPE_CODE_PTR || code == TYPE_CODE_REF) + { + return extract_address (valaddr, len); + } + else if (code == TYPE_CODE_MEMBER) + error ("not implemented: member types in unpack_long"); + + error ("Value not integer or pointer."); + return 0; /* For lint -- never reached */ +} + +/* Return a double value from the specified type and address. + INVP points to an int which is set to 0 for valid value, + 1 for invalid value (bad float format). In either case, + the returned double is OK to use. Argument is in target + format, result is in host format. */ + +double +unpack_double (type, valaddr, invp) + struct type *type; + char *valaddr; + int *invp; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + *invp = 0; /* Assume valid. */ + if (code == TYPE_CODE_FLT) + { + if (INVALID_FLOAT (valaddr, len)) + { + *invp = 1; + return 1.234567891011121314; + } + + if (len == sizeof (float)) + { + float retval; + memcpy (&retval, valaddr, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (double)) + { + double retval; + memcpy (&retval, valaddr, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + else + { + error ("Unexpected type of floating point number."); + return 0; /* Placate lint. */ + } + } + else if (nosign) { + /* Unsigned -- be sure we compensate for signed LONGEST. */ + return (unsigned LONGEST) unpack_long (type, valaddr); + } else { + /* Signed -- we are OK with unpack_long. */ + return unpack_long (type, valaddr); + } +} + +/* Unpack raw data (copied from debugee, target byte order) at VALADDR + as a CORE_ADDR, assuming the raw data is described by type TYPE. + We don't assume any alignment for the raw data. Return value is in + host byte order. + + If you want functions and arrays to be coerced to pointers, and + references to be dereferenced, call value_as_pointer() instead. + + C++: It is assumed that the front-end has taken care of + all matters concerning pointers to members. A pointer + to member which reaches here is considered to be equivalent + to an INT (or some size). After all, it is only an offset. */ + +CORE_ADDR +unpack_pointer (type, valaddr) + struct type *type; + char *valaddr; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + return unpack_long (type, valaddr); +} + +/* Given a value ARG1 (offset by OFFSET bytes) + of a struct or union type ARG_TYPE, + extract and return the value of one of its fields. + FIELDNO says which field. + + For C++, must also be able to return values from static fields */ + +value +value_primitive_field (arg1, offset, fieldno, arg_type) + register value arg1; + int offset; + register int fieldno; + register struct type *arg_type; +{ + register value v; + register struct type *type; + + check_stub_type (arg_type); + type = TYPE_FIELD_TYPE (arg_type, fieldno); + + /* Handle packed fields */ + + offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; + if (TYPE_FIELD_BITSIZE (arg_type, fieldno)) + { + v = value_from_longest (type, + unpack_field_as_long (arg_type, + VALUE_CONTENTS (arg1), + fieldno)); + VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8; + VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno); + } + else + { + v = allocate_value (type); + if (VALUE_LAZY (arg1)) + VALUE_LAZY (v) = 1; + else + memcpy (VALUE_CONTENTS_RAW (v), VALUE_CONTENTS_RAW (arg1) + offset, + TYPE_LENGTH (type)); + } + VALUE_LVAL (v) = VALUE_LVAL (arg1); + if (VALUE_LVAL (arg1) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1); + VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1); + return v; +} + +/* Given a value ARG1 of a struct or union type, + extract and return the value of one of its fields. + FIELDNO says which field. + + For C++, must also be able to return values from static fields */ + +value +value_field (arg1, fieldno) + register value arg1; + register int fieldno; +{ + return value_primitive_field (arg1, 0, fieldno, VALUE_TYPE (arg1)); +} + +/* Return a non-virtual function as a value. + F is the list of member functions which contains the desired method. + J is an index into F which provides the desired method. */ + +value +value_fn_field (arg1p, f, j, type, offset) + value *arg1p; + struct fn_field *f; + int j; + struct type *type; + int offset; +{ + register value v; + register struct type *ftype = TYPE_FN_FIELD_TYPE (f, j); + struct symbol *sym; + + sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), + 0, VAR_NAMESPACE, 0, NULL); + if (! sym) error ("Internal error: could not find physical method named %s", + TYPE_FN_FIELD_PHYSNAME (f, j)); + + v = allocate_value (ftype); + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + VALUE_TYPE (v) = ftype; + + if (arg1p) + { + if (type != VALUE_TYPE (*arg1p)) + *arg1p = value_ind (value_cast (lookup_pointer_type (type), + value_addr (*arg1p))); + + /* Move the `this' pointer according to the offset. + VALUE_OFFSET (*arg1p) += offset; + */ + } + + return v; +} + +/* Return a virtual function as a value. + ARG1 is the object which provides the virtual function + table pointer. *ARG1P is side-effected in calling this function. + F is the list of member functions which contains the desired virtual + function. + J is an index into F which provides the desired virtual function. + + TYPE is the type in which F is located. */ +value +value_virtual_fn_field (arg1p, f, j, type, offset) + value *arg1p; + struct fn_field *f; + int j; + struct type *type; + int offset; +{ + value arg1 = *arg1p; + /* First, get the virtual function table pointer. That comes + with a strange type, so cast it to type `pointer to long' (which + should serve just fine as a function type). Then, index into + the table, and convert final value to appropriate function type. */ + value entry, vfn, vtbl; + value vi = value_from_longest (builtin_type_int, + (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); + struct type *fcontext = TYPE_FN_FIELD_FCONTEXT (f, j); + struct type *context; + if (fcontext == NULL) + /* We don't have an fcontext (e.g. the program was compiled with + g++ version 1). Try to get the vtbl from the TYPE_VPTR_BASETYPE. + This won't work right for multiple inheritance, but at least we + should do as well as GDB 3.x did. */ + fcontext = TYPE_VPTR_BASETYPE (type); + context = lookup_pointer_type (fcontext); + /* Now context is a pointer to the basetype containing the vtbl. */ + if (TYPE_TARGET_TYPE (context) != VALUE_TYPE (arg1)) + arg1 = value_ind (value_cast (context, value_addr (arg1))); + + context = VALUE_TYPE (arg1); + /* Now context is the basetype containing the vtbl. */ + + /* This type may have been defined before its virtual function table + was. If so, fill in the virtual function table entry for the + type now. */ + if (TYPE_VPTR_FIELDNO (context) < 0) + fill_in_vptr_fieldno (context); + + /* The virtual function table is now an array of structures + which have the form { int16 offset, delta; void *pfn; }. */ + vtbl = value_ind (value_primitive_field (arg1, 0, + TYPE_VPTR_FIELDNO (context), + TYPE_VPTR_BASETYPE (context))); + + /* Index into the virtual function table. This is hard-coded because + looking up a field is not cheap, and it may be important to save + time, e.g. if the user has set a conditional breakpoint calling + a virtual function. */ + entry = value_subscript (vtbl, vi); + + /* Move the `this' pointer according to the virtual function table. */ + VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0))/* + offset*/; + + if (! VALUE_LAZY (arg1)) + { + VALUE_LAZY (arg1) = 1; + value_fetch_lazy (arg1); + } + + vfn = value_field (entry, 2); + /* Reinstantiate the function pointer with the correct type. */ + VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)); + + *arg1p = arg1; + return vfn; +} + +/* ARG is a pointer to an object we know to be at least + a DTYPE. BTYPE is the most derived basetype that has + already been searched (and need not be searched again). + After looking at the vtables between BTYPE and DTYPE, + return the most derived type we find. The caller must + be satisfied when the return value == DTYPE. + + FIXME-tiemann: should work with dossier entries as well. */ + +static value +value_headof (in_arg, btype, dtype) + value in_arg; + struct type *btype, *dtype; +{ + /* First collect the vtables we must look at for this object. */ + /* FIXME-tiemann: right now, just look at top-most vtable. */ + value arg, vtbl, entry, best_entry = 0; + int i, nelems; + int offset, best_offset = 0; + struct symbol *sym; + CORE_ADDR pc_for_sym; + char *demangled_name; + struct minimal_symbol *msymbol; + + btype = TYPE_VPTR_BASETYPE (dtype); + check_stub_type (btype); + arg = in_arg; + if (btype != dtype) + arg = value_cast (lookup_pointer_type (btype), arg); + vtbl = value_ind (value_field (value_ind (arg), TYPE_VPTR_FIELDNO (btype))); + + /* Check that VTBL looks like it points to a virtual function table. */ + msymbol = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtbl)); + if (msymbol == NULL + || !VTBL_PREFIX_P (demangled_name = SYMBOL_NAME (msymbol))) + { + /* If we expected to find a vtable, but did not, let the user + know that we aren't happy, but don't throw an error. + FIXME: there has to be a better way to do this. */ + struct type *error_type = (struct type *)xmalloc (sizeof (struct type)); + memcpy (error_type, VALUE_TYPE (in_arg), sizeof (struct type)); + TYPE_NAME (error_type) = savestring ("suspicious *", sizeof ("suspicious *")); + VALUE_TYPE (in_arg) = error_type; + return in_arg; + } + + /* Now search through the virtual function table. */ + entry = value_ind (vtbl); + nelems = longest_to_int (value_as_long (value_field (entry, 2))); + for (i = 1; i <= nelems; i++) + { + entry = value_subscript (vtbl, value_from_longest (builtin_type_int, + (LONGEST) i)); + offset = longest_to_int (value_as_long (value_field (entry, 0))); + /* If we use '<=' we can handle single inheritance + * where all offsets are zero - just use the first entry found. */ + if (offset <= best_offset) + { + best_offset = offset; + best_entry = entry; + } + } + /* Move the pointer according to BEST_ENTRY's offset, and figure + out what type we should return as the new pointer. */ + if (best_entry == 0) + { + /* An alternative method (which should no longer be necessary). + * But we leave it in for future use, when we will hopefully + * have optimizes the vtable to use thunks instead of offsets. */ + /* Use the name of vtable itself to extract a base type. */ + demangled_name += 4; /* Skip _vt$ prefix. */ + } + else + { + pc_for_sym = value_as_pointer (value_field (best_entry, 2)); + sym = find_pc_function (pc_for_sym); + demangled_name = cplus_demangle (SYMBOL_NAME (sym), DMGL_ANSI); + *(strchr (demangled_name, ':')) = '\0'; + } + sym = lookup_symbol (demangled_name, 0, VAR_NAMESPACE, 0, 0); + if (sym == NULL) + error ("could not find type declaration for `%s'", demangled_name); + if (best_entry) + { + free (demangled_name); + arg = value_add (value_cast (builtin_type_int, arg), + value_field (best_entry, 0)); + } + else arg = in_arg; + VALUE_TYPE (arg) = lookup_pointer_type (SYMBOL_TYPE (sym)); + return arg; +} + +/* ARG is a pointer object of type TYPE. If TYPE has virtual + function tables, probe ARG's tables (including the vtables + of its baseclasses) to figure out the most derived type that ARG + could actually be a pointer to. */ + +value +value_from_vtable_info (arg, type) + value arg; + struct type *type; +{ + /* Take care of preliminaries. */ + if (TYPE_VPTR_FIELDNO (type) < 0) + fill_in_vptr_fieldno (type); + if (TYPE_VPTR_FIELDNO (type) < 0 || VALUE_REPEATED (arg)) + return 0; + + return value_headof (arg, 0, type); +} + +/* Return true if the INDEXth field of TYPE is a virtual baseclass + pointer which is for the base class whose type is BASECLASS. */ + +static int +vb_match (type, index, basetype) + struct type *type; + int index; + struct type *basetype; +{ + struct type *fieldtype; + char *name = TYPE_FIELD_NAME (type, index); + char *field_class_name = NULL; + + if (*name != '_') + return 0; + /* gcc 2.4 uses _vb$. */ + if (name[1] == 'v' && name[2] == 'b' && name[3] == CPLUS_MARKER) + field_class_name = name + 4; + /* gcc 2.5 will use __vb_. */ + if (name[1] == '_' && name[2] == 'v' && name[3] == 'b' && name[4] == '_') + field_class_name = name + 5; + + if (field_class_name == NULL) + /* This field is not a virtual base class pointer. */ + return 0; + + /* It's a virtual baseclass pointer, now we just need to find out whether + it is for this baseclass. */ + fieldtype = TYPE_FIELD_TYPE (type, index); + if (fieldtype == NULL + || TYPE_CODE (fieldtype) != TYPE_CODE_PTR) + /* "Can't happen". */ + return 0; + + /* What we check for is that either the types are equal (needed for + nameless types) or have the same name. This is ugly, and a more + elegant solution should be devised (which would probably just push + the ugliness into symbol reading unless we change the stabs format). */ + if (TYPE_TARGET_TYPE (fieldtype) == basetype) + return 1; + + if (TYPE_NAME (basetype) != NULL + && TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)) != NULL + && STREQ (TYPE_NAME (basetype), + TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)))) + return 1; + return 0; +} + +/* Compute the offset of the baseclass which is + the INDEXth baseclass of class TYPE, for a value ARG, + wih extra offset of OFFSET. + The result is the offste of the baseclass value relative + to (the address of)(ARG) + OFFSET. + + -1 is returned on error. */ + +int +baseclass_offset (type, index, arg, offset) + struct type *type; + int index; + value arg; + int offset; +{ + struct type *basetype = TYPE_BASECLASS (type, index); + + if (BASETYPE_VIA_VIRTUAL (type, index)) + { + /* Must hunt for the pointer to this virtual baseclass. */ + register int i, len = TYPE_NFIELDS (type); + register int n_baseclasses = TYPE_N_BASECLASSES (type); + + /* First look for the virtual baseclass pointer + in the fields. */ + for (i = n_baseclasses; i < len; i++) + { + if (vb_match (type, i, basetype)) + { + CORE_ADDR addr + = unpack_pointer (TYPE_FIELD_TYPE (type, i), + VALUE_CONTENTS (arg) + VALUE_OFFSET (arg) + + offset + + (TYPE_FIELD_BITPOS (type, i) / 8)); + + if (VALUE_LVAL (arg) != lval_memory) + return -1; + + return addr - + (LONGEST) (VALUE_ADDRESS (arg) + VALUE_OFFSET (arg) + offset); + } + } + /* Not in the fields, so try looking through the baseclasses. */ + for (i = index+1; i < n_baseclasses; i++) + { + int boffset = + baseclass_offset (type, i, arg, offset); + if (boffset) + return boffset; + } + /* Not found. */ + return -1; + } + + /* Baseclass is easily computed. */ + return TYPE_BASECLASS_BITPOS (type, index) / 8; +} + +/* Compute the address of the baseclass which is + the INDEXth baseclass of class TYPE. The TYPE base + of the object is at VALADDR. + + If ERRP is non-NULL, set *ERRP to be the errno code of any error, + or 0 if no error. In that case the return value is not the address + of the baseclasss, but the address which could not be read + successfully. */ + +/* FIXME Fix remaining uses of baseclass_addr to use baseclass_offset */ + +char * +baseclass_addr (type, index, valaddr, valuep, errp) + struct type *type; + int index; + char *valaddr; + value *valuep; + int *errp; +{ + struct type *basetype = TYPE_BASECLASS (type, index); + + if (errp) + *errp = 0; + + if (BASETYPE_VIA_VIRTUAL (type, index)) + { + /* Must hunt for the pointer to this virtual baseclass. */ + register int i, len = TYPE_NFIELDS (type); + register int n_baseclasses = TYPE_N_BASECLASSES (type); + + /* First look for the virtual baseclass pointer + in the fields. */ + for (i = n_baseclasses; i < len; i++) + { + if (vb_match (type, i, basetype)) + { + value val = allocate_value (basetype); + CORE_ADDR addr; + int status; + + addr + = unpack_pointer (TYPE_FIELD_TYPE (type, i), + valaddr + (TYPE_FIELD_BITPOS (type, i) / 8)); + + status = target_read_memory (addr, + VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (basetype)); + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + + if (status != 0) + { + if (valuep) + *valuep = NULL; + release_value (val); + value_free (val); + if (errp) + *errp = status; + return (char *)addr; + } + else + { + if (valuep) + *valuep = val; + return (char *) VALUE_CONTENTS (val); + } + } + } + /* Not in the fields, so try looking through the baseclasses. */ + for (i = index+1; i < n_baseclasses; i++) + { + char *baddr; + + baddr = baseclass_addr (type, i, valaddr, valuep, errp); + if (baddr) + return baddr; + } + /* Not found. */ + if (valuep) + *valuep = 0; + return 0; + } + + /* Baseclass is easily computed. */ + if (valuep) + *valuep = 0; + return valaddr + TYPE_BASECLASS_BITPOS (type, index) / 8; +} + +/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at + VALADDR. + + Extracting bits depends on endianness of the machine. Compute the + number of least significant bits to discard. For big endian machines, + we compute the total number of bits in the anonymous object, subtract + off the bit count from the MSB of the object to the MSB of the + bitfield, then the size of the bitfield, which leaves the LSB discard + count. For little endian machines, the discard count is simply the + number of bits from the LSB of the anonymous object to the LSB of the + bitfield. + + If the field is signed, we also do sign extension. */ + +LONGEST +unpack_field_as_long (type, valaddr, fieldno) + struct type *type; + char *valaddr; + int fieldno; +{ + unsigned LONGEST val; + unsigned LONGEST valmask; + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + int lsbcount; + + val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val)); + + /* Extract bits. See comment above. */ + +#if BITS_BIG_ENDIAN + lsbcount = (sizeof val * 8 - bitpos % 8 - bitsize); +#else + lsbcount = (bitpos % 8); +#endif + val >>= lsbcount; + + /* If the field does not entirely fill a LONGEST, then zero the sign bits. + If the field is signed, and is negative, then sign extend. */ + + if ((bitsize > 0) && (bitsize < 8 * sizeof (val))) + { + valmask = (((unsigned LONGEST) 1) << bitsize) - 1; + val &= valmask; + if (!TYPE_UNSIGNED (TYPE_FIELD_TYPE (type, fieldno))) + { + if (val & (valmask ^ (valmask >> 1))) + { + val |= ~valmask; + } + } + } + return (val); +} + +/* Modify the value of a bitfield. ADDR points to a block of memory in + target byte order; the bitfield starts in the byte pointed to. FIELDVAL + is the desired value of the field, in host byte order. BITPOS and BITSIZE + indicate which bits (in target bit order) comprise the bitfield. */ + +void +modify_field (addr, fieldval, bitpos, bitsize) + char *addr; + LONGEST fieldval; + int bitpos, bitsize; +{ + LONGEST oword; + + /* Reject values too big to fit in the field in question, + otherwise adjoining fields may be corrupted. */ + if (bitsize < (8 * sizeof (fieldval)) + && 0 != (fieldval & ~((1<= size of oword */ + if (bitsize < 8 * sizeof (oword)) + oword &= ~(((((unsigned LONGEST)1) << bitsize) - 1) << bitpos); + else + oword &= ~((~(unsigned LONGEST)0) << bitpos); + oword |= fieldval << bitpos; + + store_signed_integer (addr, sizeof oword, oword); +} + +/* Convert C numbers into newly allocated values */ + +value +value_from_longest (type, num) + struct type *type; + register LONGEST num; +{ + register value val = allocate_value (type); + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + + switch (code) + { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_BOOL: + store_signed_integer (VALUE_CONTENTS_RAW (val), len, num); + break; + + case TYPE_CODE_REF: + case TYPE_CODE_PTR: + /* This assumes that all pointers of a given length + have the same form. */ + store_address (VALUE_CONTENTS_RAW (val), len, (CORE_ADDR) num); + break; + + default: + error ("Unexpected type encountered for integer constant."); + } + return val; +} + +value +value_from_double (type, num) + struct type *type; + double num; +{ + register value val = allocate_value (type); + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + + if (code == TYPE_CODE_FLT) + { + if (len == sizeof (float)) + * (float *) VALUE_CONTENTS_RAW (val) = num; + else if (len == sizeof (double)) + * (double *) VALUE_CONTENTS_RAW (val) = num; + else + error ("Floating type encountered with unexpected data length."); + } + else + error ("Unexpected type encountered for floating constant."); + + /* num was in host byte order. So now put the value's contents + into target byte order. */ + SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (val), len); + + return val; +} + +/* Deal with the value that is "about to be returned". */ + +/* Return the value that a function returning now + would be returning to its caller, assuming its type is VALTYPE. + RETBUF is where we look for what ought to be the contents + of the registers (in raw form). This is because it is often + desirable to restore old values to those registers + after saving the contents of interest, and then call + this function using the saved values. + struct_return is non-zero when the function in question is + using the structure return conventions on the machine in question; + 0 when it is using the value returning conventions (this often + means returning pointer to where structure is vs. returning value). */ + +value +value_being_returned (valtype, retbuf, struct_return) + register struct type *valtype; + char retbuf[REGISTER_BYTES]; + int struct_return; + /*ARGSUSED*/ +{ + register value val; + CORE_ADDR addr; + +#if defined (EXTRACT_STRUCT_VALUE_ADDRESS) + /* If this is not defined, just use EXTRACT_RETURN_VALUE instead. */ + if (struct_return) { + addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf); + if (!addr) + error ("Function return value unknown"); + return value_at (valtype, addr); + } +#endif + + val = allocate_value (valtype); + EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val)); + + return val; +} + +/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of + EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc + and TYPE is the type (which is known to be struct, union or array). + + On most machines, the struct convention is used unless we are + using gcc and the type is of a special size. */ +/* As of about 31 Mar 93, GCC was changed to be compatible with the + native compiler. GCC 2.3.3 was the last release that did it the + old way. Since gcc2_compiled was not changed, we have no + way to correctly win in all cases, so we just do the right thing + for gcc1 and for gcc2 after this change. Thus it loses for gcc + 2.0-2.3.3. This is somewhat unfortunate, but changing gcc2_compiled + would cause more chaos than dealing with some struct returns being + handled wrong. */ +#if !defined (USE_STRUCT_CONVENTION) +#define USE_STRUCT_CONVENTION(gcc_p, type)\ + (!((gcc_p == 1) && (TYPE_LENGTH (value_type) == 1 \ + || TYPE_LENGTH (value_type) == 2 \ + || TYPE_LENGTH (value_type) == 4 \ + || TYPE_LENGTH (value_type) == 8 \ + ) \ + )) +#endif + +/* Return true if the function specified is using the structure returning + convention on this machine to return arguments, or 0 if it is using + the value returning convention. FUNCTION is the value representing + the function, FUNCADDR is the address of the function, and VALUE_TYPE + is the type returned by the function. GCC_P is nonzero if compiled + with GCC. */ + +int +using_struct_return (function, funcaddr, value_type, gcc_p) + value function; + CORE_ADDR funcaddr; + struct type *value_type; + int gcc_p; + /*ARGSUSED*/ +{ + register enum type_code code = TYPE_CODE (value_type); + + if (code == TYPE_CODE_ERROR) + error ("Function return type unknown."); + + if (code == TYPE_CODE_STRUCT || + code == TYPE_CODE_UNION || + code == TYPE_CODE_ARRAY) + return USE_STRUCT_CONVENTION (gcc_p, value_type); + + return 0; +} + +/* Store VAL so it will be returned if a function returns now. + Does not verify that VAL's type matches what the current + function wants to return. */ + +void +set_return_value (val) + value val; +{ + register enum type_code code = TYPE_CODE (VALUE_TYPE (val)); + double dbuf; + LONGEST lbuf; + + if (code == TYPE_CODE_ERROR) + error ("Function return type unknown."); + + if ( code == TYPE_CODE_STRUCT + || code == TYPE_CODE_UNION) /* FIXME, implement struct return. */ + error ("GDB does not support specifying a struct or union return value."); + + /* FIXME, this is bogus. We don't know what the return conventions + are, or how values should be promoted.... */ + if (code == TYPE_CODE_FLT) + { + dbuf = value_as_double (val); + + STORE_RETURN_VALUE (VALUE_TYPE (val), (char *)&dbuf); + } + else + { + lbuf = value_as_long (val); + STORE_RETURN_VALUE (VALUE_TYPE (val), (char *)&lbuf); + } +} + +void +_initialize_values () +{ + add_cmd ("convenience", no_class, show_convenience, + "Debugger convenience (\"$foo\") variables.\n\ +These variables are created when you assign them values;\n\ +thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\ +A few convenience variables are given values automatically:\n\ +\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\ +\"$__\" holds the contents of the last address examined with \"x\".", + &showlist); + + add_cmd ("values", no_class, show_values, + "Elements of value history around item number IDX (or last ten).", + &showlist); +} diff --git a/gnu/usr.bin/gdb/gdb/version.c b/gnu/usr.bin/gdb/gdb/version.c new file mode 100644 index 00000000000..d32e958a2dd --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/version.c @@ -0,0 +1,3 @@ +char *version = "4.11"; +char *host_canonical = "i386-unknown-freebsd"; +char *target_canonical = "i386-unknown-freebsd"; diff --git a/gnu/usr.bin/gdb/gdb/wait.h b/gnu/usr.bin/gdb/gdb/wait.h new file mode 100644 index 00000000000..a72943cd9ee --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/wait.h @@ -0,0 +1,38 @@ +/* Define how to access the int that the wait system call stores. + This has been compatible in all Unix systems since time immemorial, + but various well-meaning people have defined various different + words for the same old bits in the same old int (sometimes claimed + to be a struct). We just know it's an int and we use these macros + to access the bits. */ + +/* The following macros are defined equivalently to their definitions + in POSIX.1. We fail to define WNOHANG and WUNTRACED, which POSIX.1 + defines, since our code does not use waitpid(). We + also fail to declare wait() and waitpid(). */ + +#define WIFEXITED(w) (((w)&0377) == 0) +#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) +#ifdef IBM6000 + +/* Unfortunately, the above comment (about being compatible in all Unix + systems) is not quite correct for AIX, sigh. And AIX 3.2 can generate + status words like 0x57c (sigtrap received after load), and gdb would + choke on it. */ + +#define WIFSTOPPED(w) ((w)&0x40) + +#else +#define WIFSTOPPED(w) (((w)&0377) == 0177) +#endif + +#define WEXITSTATUS(w) (((w) >> 8) & 0377) /* same as WRETCODE */ +#define WTERMSIG(w) ((w) & 0177) +#define WSTOPSIG WEXITSTATUS + +/* These are not defined in POSIX, but are used by our programs. */ + +#define WAITTYPE int + +#define WCOREDUMP(w) (((w)&0200) != 0) +#define WSETEXIT(w,status) ((w) = (0 | ((status) << 8))) +#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8))) diff --git a/gnu/usr.bin/gdb/gdb/xm.h b/gnu/usr.bin/gdb/gdb/xm.h new file mode 100644 index 00000000000..8d28df0b713 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/xm.h @@ -0,0 +1,31 @@ +/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 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. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#include /* for INT_MIN, to avoid "INT_MIN + redefined" warnings from defs.h */ + +/* psignal() is in . */ + +#define PSIGNAL_IN_SIGNAL_H + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE diff --git a/gnu/usr.bin/gdb/gdb/y.tab.h b/gnu/usr.bin/gdb/gdb/y.tab.h new file mode 100644 index 00000000000..62e0883efec --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/y.tab.h @@ -0,0 +1,65 @@ +#define INT 257 +#define HEX 258 +#define ERROR 259 +#define UINT 260 +#define M2_TRUE 261 +#define M2_FALSE 262 +#define CHAR 263 +#define FLOAT 264 +#define STRING 265 +#define NAME 266 +#define BLOCKNAME 267 +#define IDENT 268 +#define VARNAME 269 +#define TYPENAME 270 +#define SIZE 271 +#define CAP 272 +#define ORD 273 +#define HIGH 274 +#define ABS 275 +#define MIN_FUNC 276 +#define MAX_FUNC 277 +#define FLOAT_FUNC 278 +#define VAL 279 +#define CHR 280 +#define ODD 281 +#define TRUNC 282 +#define INC 283 +#define DEC 284 +#define INCL 285 +#define EXCL 286 +#define COLONCOLON 287 +#define LAST 288 +#define REGNAME 289 +#define INTERNAL_VAR 290 +#define ABOVE_COMMA 291 +#define ASSIGN 292 +#define LEQ 293 +#define GEQ 294 +#define NOTEQUAL 295 +#define IN 296 +#define OROR 297 +#define LOGICAL_AND 298 +#define DIV 299 +#define MOD 300 +#define UNARY 301 +#define DOT 302 +#define NOT 303 +#define QID 304 +typedef union + { + LONGEST lval; + unsigned LONGEST ulval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } YYSTYPE; +extern YYSTYPE m2_lval; diff --git a/gnu/usr.bin/gdb/libiberty/COPYING.LIB b/gnu/usr.bin/gdb/libiberty/COPYING.LIB new file mode 100644 index 00000000000..eb685a5ec98 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/usr.bin/gdb/libiberty/Makefile b/gnu/usr.bin/gdb/libiberty/Makefile new file mode 100644 index 00000000000..838781295e8 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/Makefile @@ -0,0 +1,13 @@ +LIB= iberty +SRCS= argv.c basename.c concat.c cplus-dem.c fdmatch.c getopt.c \ + getopt1.c ieee-float.c obstack.c spaces.c strerror.c strsignal.c \ + xmalloc.c + +CFLAGS+= -I$(.CURDIR)/../gdb/. +NOPROFILE=no +NOPIC=no + +install: + @echo -n + +.include diff --git a/gnu/usr.bin/gdb/libiberty/README.FreeBSD b/gnu/usr.bin/gdb/libiberty/README.FreeBSD new file mode 100644 index 00000000000..573fa0a9a80 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/README.FreeBSD @@ -0,0 +1,7 @@ +This is a greatly pared down libiberty directory. Only what's required to build +gdb-4.12 on FreeBSD was kept. + +This is temporary. In FreeBSD 2.0 a fully ported libiberty will likely appear +as a system library for use by all the build tools. + +paul@freefall.cdrom.com diff --git a/gnu/usr.bin/gdb/libiberty/alloca-conf.h b/gnu/usr.bin/gdb/libiberty/alloca-conf.h new file mode 100644 index 00000000000..e1d9177893a --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/alloca-conf.h @@ -0,0 +1,11 @@ +/* "Normal" configuration for alloca. */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#ifdef sparc +#include +#else +char *alloca (); +#endif /* sparc */ +#endif /* not __GNUC__ */ diff --git a/gnu/usr.bin/gdb/libiberty/argv.c b/gnu/usr.bin/gdb/libiberty/argv.c new file mode 100644 index 00000000000..fed46e7d797 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/argv.c @@ -0,0 +1,332 @@ +/* Create and destroy argument vectors (argv's) + Copyright (C) 1992 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + + +/* Create and destroy argument vectors. An argument vector is simply an + array of string pointers, terminated by a NULL pointer. */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#ifdef sparc +#include +extern char *__builtin_alloca(); /* Stupid include file doesn't declare it */ +#else +#ifdef _AIX + #pragma alloca +#else +char *alloca (); +#endif +#endif /* sparc */ +#endif /* not __GNUC__ */ + +#define isspace(ch) ((ch) == ' ' || (ch) == '\t') + +#include "alloca-conf.h" + +/* Routines imported from standard C runtime libraries. */ + +#ifdef __STDC__ + +#include +extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */ +extern size_t strlen (const char *s); /* 4.11.6.3 */ +extern void *malloc (size_t size); /* 4.10.3.3 */ +extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */ +extern void free (void *ptr); /* 4.10.3.2 */ +extern char *strdup (const char *s); /* Non-ANSI */ + +#else /* !__STDC__ */ + +extern char *memcpy (); /* Copy memory region */ +extern int strlen (); /* Count length of string */ +extern char *malloc (); /* Standard memory allocater */ +extern char *realloc (); /* Standard memory reallocator */ +extern void free (); /* Free malloc'd memory */ +extern char *strdup (); /* Duplicate a string */ + +#endif /* __STDC__ */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOS +#define EOS '\0' +#endif + +#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ + + +/* + +NAME + + freeargv -- free an argument vector + +SYNOPSIS + + void freeargv (vector) + char **vector; + +DESCRIPTION + + Free an argument vector that was built using buildargv. Simply scans + through the vector, freeing the memory for each argument until the + terminating NULL is found, and then frees the vector itself. + +RETURNS + + No value. + +*/ + +void freeargv (vector) +char **vector; +{ + register char **scan; + + if (vector != NULL) + { + for (scan = vector; *scan != NULL; scan++) + { + free (*scan); + } + free (vector); + } +} + +/* + +NAME + + buildargv -- build an argument vector from a string + +SYNOPSIS + + char **buildargv (sp) + char *sp; + +DESCRIPTION + + Given a pointer to a string, parse the string extracting fields + separated by whitespace and optionally enclosed within either single + or double quotes (which are stripped off), and build a vector of + pointers to copies of the string for each field. The input string + remains unchanged. + + All of the memory for the pointer array and copies of the string + is obtained from malloc. All of the memory can be returned to the + system with the single function call freeargv, which takes the + returned result of buildargv, as it's argument. + + The memory for the argv array is dynamically expanded as necessary. + +RETURNS + + Returns a pointer to the argument vector if successful. Returns NULL + if the input string pointer is NULL or if there is insufficient + memory to complete building the argument vector. + +NOTES + + In order to provide a working buffer for extracting arguments into, + with appropriate stripping of quotes and translation of backslash + sequences, we allocate a working buffer at least as long as the input + string. This ensures that we always have enough space in which to + work, since the extracted arg is never larger than the input string. + + If the input is a null string (as opposed to a NULL pointer), then + buildarg returns an argv that has one arg, a null string. + + Argv is always kept terminated with a NULL arg pointer, so it can + be passed to freeargv at any time, or returned, as appropriate. +*/ + +char **buildargv (input) +char *input; +{ + char *arg; + char *copybuf; + int squote = 0; + int dquote = 0; + int bsquote = 0; + int argc = 0; + int maxargc = 0; + char **argv = NULL; + char **nargv; + + if (input != NULL) + { + copybuf = alloca (strlen (input) + 1); + /* Is a do{}while to always execute the loop once. Always return an + argv, even for null strings. See NOTES above, test case below. */ + do + { + /* Pick off argv[argc] */ + while (isspace (*input)) + { + input++; + } + if ((maxargc == 0) || (argc >= (maxargc - 1))) + { + /* argv needs initialization, or expansion */ + if (argv == NULL) + { + maxargc = INITIAL_MAXARGC; + nargv = (char **) malloc (maxargc * sizeof (char *)); + } + else + { + maxargc *= 2; + nargv = (char **) realloc (argv, maxargc * sizeof (char *)); + } + if (nargv == NULL) + { + if (argv != NULL) + { + freeargv (argv); + argv = NULL; + } + break; + } + argv = nargv; + argv[argc] = NULL; + } + /* Begin scanning arg */ + arg = copybuf; + while (*input != EOS) + { + if (isspace (*input) && !squote && !dquote && !bsquote) + { + break; + } + else + { + if (bsquote) + { + bsquote = 0; + *arg++ = *input; + } + else if (*input == '\\') + { + bsquote = 1; + } + else if (squote) + { + if (*input == '\'') + { + squote = 0; + } + else + { + *arg++ = *input; + } + } + else if (dquote) + { + if (*input == '"') + { + dquote = 0; + } + else + { + *arg++ = *input; + } + } + else + { + if (*input == '\'') + { + squote = 1; + } + else if (*input == '"') + { + dquote = 1; + } + else + { + *arg++ = *input; + } + } + input++; + } + } + *arg = EOS; + argv[argc] = strdup (copybuf); + if (argv[argc] == NULL) + { + freeargv (argv); + argv = NULL; + break; + } + argc++; + argv[argc] = NULL; + } + while (*input != EOS); + } + return (argv); +} + +#ifdef MAIN + +/* Simple little test driver. */ + +static char *tests[] = +{ + "a simple command line", + "arg 'foo' is single quoted", + "arg \"bar\" is double quoted", + "arg \"foo bar\" has embedded whitespace", + "arg 'Jack said \\'hi\\'' has single quotes", + "arg 'Jack said \\\"hi\\\"' has double quotes", + "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9", + "", + NULL +}; + +main () +{ + char **argv; + char **test; + char **targs; + + for (test = tests; *test != NULL; test++) + { + printf ("buildargv(\"%s\")\n", *test); + if ((argv = buildargv (*test)) == NULL) + { + printf ("failed!\n\n"); + } + else + { + for (targs = argv; *targs != NULL; targs++) + { + printf ("\t\"%s\"\n", *targs); + } + printf ("\n"); + } + freeargv (argv); + } + +} + +#endif /* MAIN */ diff --git a/gnu/usr.bin/gdb/libiberty/basename.c b/gnu/usr.bin/gdb/libiberty/basename.c new file mode 100644 index 00000000000..f61a308e9b5 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/basename.c @@ -0,0 +1,56 @@ +/* Return the basename of a pathname. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + +NAME + + basename -- return pointer to last component of a pathname + +SYNOPSIS + + char *basename (char *name) + +DESCRIPTION + + Given a pointer to a string containing a typical pathname + (/usr/src/cmd/ls/ls.c for example), returns a pointer to the + last component of the pathname ("ls.c" in this case). + +BUGS + + Presumes a UNIX style path with UNIX style separators. +*/ + + +char * +basename (name) + char *name; +{ + char *base = name; + + while (*name) + { + if (*name++ == '/') + { + base = name; + } + } + return (base); +} diff --git a/gnu/usr.bin/gdb/libiberty/concat.c b/gnu/usr.bin/gdb/libiberty/concat.c new file mode 100644 index 00000000000..61f7d97481c --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/concat.c @@ -0,0 +1,118 @@ +/* Concatenate variable number of strings. + Copyright (C) 1991 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + + +/* + +NAME + + concat -- concatenate a variable number of strings + +SYNOPSIS + + #include + + char *concat (s1, s2, s3, ..., NULL) + +DESCRIPTION + + Concatenate a variable number of strings and return the result + in freshly malloc'd memory. + + Returns NULL if insufficient memory is available. The argument + list is terminated by the first NULL pointer encountered. Pointers + to empty strings are ignored. + +NOTES + + This function uses xmalloc() which is expected to be a front end + function to malloc() that deals with low memory situations. In + typical use, if malloc() returns NULL then xmalloc() diverts to an + error handler routine which never returns, and thus xmalloc will + never return a NULL pointer. If the client application wishes to + deal with low memory situations itself, it should supply an xmalloc + that just directly invokes malloc and blindly returns whatever + malloc returns. +*/ + + +#include + +#define NULLP (char *)0 + +extern char *xmalloc (); + +/* VARARGS */ +char * +concat (va_alist) + va_dcl +{ + register int length = 0; + register char *newstr; + register char *end; + register char *arg; + va_list args; + + /* First compute the size of the result and get sufficient memory. */ + + va_start (args); + while ((arg = va_arg (args, char *)) != NULLP) + { + length += strlen (arg); + } + newstr = (char *) xmalloc (length + 1); + va_end (args); + + /* Now copy the individual pieces to the result string. */ + + if (newstr != NULLP) + { + va_start (args); + end = newstr; + while ((arg = va_arg (args, char *)) != NULLP) + { + while (*arg) + { + *end++ = *arg++; + } + } + *end = '\000'; + va_end (args); + } + + return (newstr); +} + +#ifdef MAIN + +/* Simple little test driver. */ + +main () +{ + printf ("\"\" = \"%s\"\n", concat (NULLP)); + printf ("\"a\" = \"%s\"\n", concat ("a", NULLP)); + printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP)); + printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP)); + printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP)); + printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP)); + printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP)); +} + +#endif diff --git a/gnu/usr.bin/gdb/libiberty/config.h b/gnu/usr.bin/gdb/libiberty/config.h new file mode 100644 index 00000000000..b37ee84a78a --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/config.h @@ -0,0 +1 @@ +/* !Automatically generated from ./functions.def - DO NOT EDIT! */ diff --git a/gnu/usr.bin/gdb/libiberty/cplus-dem.c b/gnu/usr.bin/gdb/libiberty/cplus-dem.c new file mode 100644 index 00000000000..2ad0e971487 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/cplus-dem.c @@ -0,0 +1,2669 @@ +/* Demangler for GNU C++ + Copyright 1989, 1991 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.uucp) + Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* This file exports two functions; cplus_mangle_opname and cplus_demangle. + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +#include +#undef CURRENT_DEMANGLING_STYLE +#define CURRENT_DEMANGLING_STYLE work->options +#include +#include +#include + +extern char *xmalloc PARAMS((long)); +extern char *xrealloc PARAMS((PTR, long)); +extern char *strstr PARAMS ((const char *, const char *)); +extern void free PARAMS((PTR)); + +/* In order to allow a single demangler executable to demangle strings + using various common values of CPLUS_MARKER, as well as any specific + one set at compile time, we maintain a string containing all the + commonly used ones, and check to see if the marker we are looking for + is in that string. CPLUS_MARKER is usually '$' on systems where the + assembler can deal with that. Where the assembler can't, it's usually + '.' (but on many systems '.' is used for other things). We put the + current defined CPLUS_MARKER first (which defaults to '$'), followed + by the next most common value, followed by an explicit '$' in case + the value of CPLUS_MARKER is not '$'. + + We could avoid this if we could just get g++ to tell us what the actual + cplus marker character is as part of the debug information, perhaps by + ensuring that it is the character that terminates the gcc_compiled + marker symbol (FIXME). */ + +#if !defined (CPLUS_MARKER) +#define CPLUS_MARKER '$' +#endif + +enum demangling_styles current_demangling_style = gnu_demangling; + +static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; + +void +set_cplus_marker_for_demangling (ch) + int ch; +{ + cplus_markers[0] = ch; +} + +/* Stuff that is shared between sub-routines. + * Using a shared structure allows cplus_demangle to be reentrant. */ + +struct work_stuff +{ + int options; + char **typevec; + int ntypes; + int typevec_size; + int constructor; + int destructor; + int static_type; /* A static member function */ + int const_type; /* A const member function */ +}; + +#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) + +static CONST struct optable +{ + CONST char *in; + CONST char *out; + int flags; +} optable[] = { + {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ + {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ + {"new", " new", 0}, /* old (1.91, and 1.x) */ + {"delete", " delete", 0}, /* old (1.91, and 1.x) */ + {"as", "=", DMGL_ANSI}, /* ansi */ + {"ne", "!=", DMGL_ANSI}, /* old, ansi */ + {"eq", "==", DMGL_ANSI}, /* old, ansi */ + {"ge", ">=", DMGL_ANSI}, /* old, ansi */ + {"gt", ">", DMGL_ANSI}, /* old, ansi */ + {"le", "<=", DMGL_ANSI}, /* old, ansi */ + {"lt", "<", DMGL_ANSI}, /* old, ansi */ + {"plus", "+", 0}, /* old */ + {"pl", "+", DMGL_ANSI}, /* ansi */ + {"apl", "+=", DMGL_ANSI}, /* ansi */ + {"minus", "-", 0}, /* old */ + {"mi", "-", DMGL_ANSI}, /* ansi */ + {"ami", "-=", DMGL_ANSI}, /* ansi */ + {"mult", "*", 0}, /* old */ + {"ml", "*", DMGL_ANSI}, /* ansi */ + {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ + {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ + {"convert", "+", 0}, /* old (unary +) */ + {"negate", "-", 0}, /* old (unary -) */ + {"trunc_mod", "%", 0}, /* old */ + {"md", "%", DMGL_ANSI}, /* ansi */ + {"amd", "%=", DMGL_ANSI}, /* ansi */ + {"trunc_div", "/", 0}, /* old */ + {"dv", "/", DMGL_ANSI}, /* ansi */ + {"adv", "/=", DMGL_ANSI}, /* ansi */ + {"truth_andif", "&&", 0}, /* old */ + {"aa", "&&", DMGL_ANSI}, /* ansi */ + {"truth_orif", "||", 0}, /* old */ + {"oo", "||", DMGL_ANSI}, /* ansi */ + {"truth_not", "!", 0}, /* old */ + {"nt", "!", DMGL_ANSI}, /* ansi */ + {"postincrement","++", 0}, /* old */ + {"pp", "++", DMGL_ANSI}, /* ansi */ + {"postdecrement","--", 0}, /* old */ + {"mm", "--", DMGL_ANSI}, /* ansi */ + {"bit_ior", "|", 0}, /* old */ + {"or", "|", DMGL_ANSI}, /* ansi */ + {"aor", "|=", DMGL_ANSI}, /* ansi */ + {"bit_xor", "^", 0}, /* old */ + {"er", "^", DMGL_ANSI}, /* ansi */ + {"aer", "^=", DMGL_ANSI}, /* ansi */ + {"bit_and", "&", 0}, /* old */ + {"ad", "&", DMGL_ANSI}, /* ansi */ + {"aad", "&=", DMGL_ANSI}, /* ansi */ + {"bit_not", "~", 0}, /* old */ + {"co", "~", DMGL_ANSI}, /* ansi */ + {"call", "()", 0}, /* old */ + {"cl", "()", DMGL_ANSI}, /* ansi */ + {"alshift", "<<", 0}, /* old */ + {"ls", "<<", DMGL_ANSI}, /* ansi */ + {"als", "<<=", DMGL_ANSI}, /* ansi */ + {"arshift", ">>", 0}, /* old */ + {"rs", ">>", DMGL_ANSI}, /* ansi */ + {"ars", ">>=", DMGL_ANSI}, /* ansi */ + {"component", "->", 0}, /* old */ + {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ + {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ + {"indirect", "*", 0}, /* old */ + {"method_call", "->()", 0}, /* old */ + {"addr", "&", 0}, /* old (unary &) */ + {"array", "[]", 0}, /* old */ + {"vc", "[]", DMGL_ANSI}, /* ansi */ + {"compound", ", ", 0}, /* old */ + {"cm", ", ", DMGL_ANSI}, /* ansi */ + {"cond", "?:", 0}, /* old */ + {"cn", "?:", DMGL_ANSI}, /* psuedo-ansi */ + {"max", ">?", 0}, /* old */ + {"mx", ">?", DMGL_ANSI}, /* psuedo-ansi */ + {"min", "*", DMGL_ANSI} /* ansi */ +}; + + +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +#define STRING_EMPTY(str) ((str) -> b == (str) -> p) +#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_prepend(str, " ");} +#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_append(str, " ");} + +#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ +#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ + +/* Prototypes for local functions */ + +static char * +mop_up PARAMS ((struct work_stuff *, string *, int)); + +#if 0 +static int +demangle_method_args PARAMS ((struct work_stuff *work, CONST char **, string *)); +#endif + +static int +demangle_template PARAMS ((struct work_stuff *work, CONST char **, string *, + string *)); + +static int +demangle_qualified PARAMS ((struct work_stuff *, CONST char **, string *, + int, int)); + +static int +demangle_class PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +demangle_fund_type PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +demangle_signature PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +demangle_prefix PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +gnu_special PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +arm_special PARAMS ((struct work_stuff *, CONST char **, string *)); + +static void +string_need PARAMS ((string *, int)); + +static void +string_delete PARAMS ((string *)); + +static void +string_init PARAMS ((string *)); + +static void +string_clear PARAMS ((string *)); + +#if 0 +static int +string_empty PARAMS ((string *)); +#endif + +static void +string_append PARAMS ((string *, CONST char *)); + +static void +string_appends PARAMS ((string *, string *)); + +static void +string_appendn PARAMS ((string *, CONST char *, int)); + +static void +string_prepend PARAMS ((string *, CONST char *)); + +static void +string_prependn PARAMS ((string *, CONST char *, int)); + +static int +get_count PARAMS ((CONST char **, int *)); + +static int +consume_count PARAMS ((CONST char **)); + +static int +demangle_args PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +do_type PARAMS ((struct work_stuff *, CONST char **, string *)); + +static int +do_arg PARAMS ((struct work_stuff *, CONST char **, string *)); + +static void +demangle_function_name PARAMS ((struct work_stuff *, CONST char **, string *, + CONST char *)); + +static void +remember_type PARAMS ((struct work_stuff *, CONST char *, int)); + +static void +forget_types PARAMS ((struct work_stuff *)); + +static void +string_prepends PARAMS ((string *, string *)); + +/* Translate count to integer, consuming tokens in the process. + Conversion terminates on the first non-digit character. + Trying to consume something that isn't a count results in + no consumption of input and a return of 0. */ + +static int +consume_count (type) + CONST char **type; +{ + int count = 0; + + while (isdigit (**type)) + { + count *= 10; + count += **type - '0'; + (*type)++; + } + return (count); +} + +/* Takes operator name as e.g. "++" and returns mangled + operator name (e.g. "postincrement_expr"), or NULL if not found. + + If OPTIONS & DMGL_ANSI == 1, return the ANSI name; + if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ + +char * +cplus_mangle_opname (opname, options) + char *opname; + int options; +{ + int i; + int len; + + len = strlen (opname); + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].out) == len + && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) + && memcmp (optable[i].out, opname, len) == 0) + return ((char *)optable[i].in); + } + return (0); +} + +/* check to see whether MANGLED can match TEXT in the first TEXT_LEN + characters. */ + +int cplus_match (mangled, text, text_len) + CONST char *mangled; + char *text; + int text_len; +{ + if (strncmp (mangled, text, text_len) != 0) { + return(0); /* cannot match either */ + } else { + return(1); /* matches mangled, may match demangled */ + } +} + +/* char *cplus_demangle (const char *name, int options) + + If NAME is a mangled function name produced by GNU C++, then + a pointer to a malloced string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + The OPTIONS arg may contain one or more of the following bits: + + DMGL_ANSI ANSI qualifiers such as `const' and `void' are + included. + DMGL_PARAMS Function parameters are included. + + For example, + + cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" + cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 0) => "A::foo" + + cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 0) => "A::foo" + + Note that any leading underscores, or other such characters prepended by + the compilation system, are presumed to have already been stripped from + TYPE. */ + +char * +cplus_demangle (mangled, options) + CONST char *mangled; + int options; +{ + string decl; + int success = 0; + struct work_stuff work[1]; + char *demangled = NULL; + + if ((mangled != NULL) && (*mangled != '\0')) + { + memset ((char *) work, 0, sizeof (work)); + work -> options = options; + if ((work->options & DMGL_STYLE_MASK) == 0) + work->options |= (int)current_demangling_style & DMGL_STYLE_MASK; + + string_init (&decl); + + /* First check to see if gnu style demangling is active and if the + string to be demangled contains a CPLUS_MARKER. If so, attempt to + recognize one of the gnu special forms rather than looking for a + standard prefix. In particular, don't worry about whether there + is a "__" string in the mangled string. Consider "_$_5__foo" for + example. */ + + if ((AUTO_DEMANGLING || GNU_DEMANGLING)) + { + success = gnu_special (work, &mangled, &decl); + } + if (!success) + { + success = demangle_prefix (work, &mangled, &decl); + } + if (success && (*mangled != '\0')) + { + success = demangle_signature (work, &mangled, &decl); + } + if (work->constructor == 2) + { + string_prepend(&decl, "global constructors keyed to "); + work->constructor = 0; + } + else if (work->destructor == 2) + { + string_prepend(&decl, "global destructors keyed to "); + work->destructor = 0; + } + demangled = mop_up (work, &decl, success); + } + return (demangled); +} + +static char * +mop_up (work, declp, success) + struct work_stuff *work; + string *declp; + int success; +{ + char *demangled = NULL; + + /* Discard the remembered types, if any. */ + + forget_types (work); + if (work -> typevec != NULL) + { + free ((char *) work -> typevec); + } + + /* If demangling was successful, ensure that the demangled string is null + terminated and return it. Otherwise, free the demangling decl. */ + + if (!success) + { + string_delete (declp); + } + else + { + string_appendn (declp, "", 1); + demangled = declp -> b; + } + return (demangled); +} + +/* + +LOCAL FUNCTION + + demangle_signature -- demangle the signature part of a mangled name + +SYNOPSIS + + static int + demangle_signature (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the signature portion of the mangled name. + + DECLP is the string where demangled output is being built. At + entry it contains the demangled root name from the mangled name + prefix. I.E. either a demangled operator name or the root function + name. In some special cases, it may contain nothing. + + *MANGLED points to the current unconsumed location in the mangled + name. As tokens are consumed and demangling is performed, the + pointer is updated to continuously point at the next token to + be consumed. + + Demangling GNU style mangled names is nasty because there is no + explicit token that marks the start of the outermost function + argument list. +*/ + +static int +demangle_signature (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int success = 1; + int func_done = 0; + int expect_func = 0; + CONST char *oldmangled = NULL; + string trawname; + string tname; + + while (success && (**mangled != '\0')) + { + switch (**mangled) + { + case 'Q': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'S': + /* Static member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> static_type = 1; + break; + + case 'C': + /* a const member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> const_type = 1; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + success = demangle_class (work, mangled, declp); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'F': + /* Function */ + /* ARM style demangling includes a specific 'F' character after + the class name. For GNU style, it is just implied. So we can + safely just consume any 'F' at this point and be compatible + with either style. */ + + oldmangled = NULL; + func_done = 1; + (*mangled)++; + + /* For lucid/ARM style we have to forget any types we might + have remembered up to this point, since they were not argument + types. GNU style considers all types seen as available for + back references. See comment in demangle_args() */ + + if (LUCID_DEMANGLING || ARM_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + break; + + case 't': + /* G++ Template */ + string_init(&trawname); + string_init(&tname); + success = demangle_template (work, mangled, &tname, &trawname); + string_append(&tname, "::"); + string_prepends(declp, &tname); + if (work -> destructor & 1) + { + string_prepend (&trawname, "~"); + string_appends (declp, &trawname); + work->destructor -= 1; + } + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_appends (declp, &trawname); + work->constructor -= 1; + } + string_delete(&trawname); + string_delete(&tname); + expect_func = 1; + break; + + case '_': + /* At the outermost level, we cannot have a return type specified, + so if we run into another '_' at this point we are dealing with + a mangled name that is either bogus, or has been mangled by + some algorithm we don't know how to deal with. So just + reject the entire demangling. */ + success = 0; + break; + + default: + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = 1; + success = demangle_args (work, mangled, declp); + } + else + { + /* Non-GNU demanglers use a specific token to mark the start + of the outermost function argument tokens. Typically 'F', + for ARM-demangling, for example. So if we find something + we are not prepared for, it must be an error. */ + success = 0; + } + break; + } + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + if (success && expect_func) + { + func_done = 1; + success = demangle_args (work, mangled, declp); + } + } + } + if (success && !func_done) + { + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added to + the current declp. Note that with ARM, the first case + represents the name of a static data member 'foo::bar', + which is in the current declp, so we leave it alone. */ + success = demangle_args (work, mangled, declp); + } + } + if (success && work -> static_type && PRINT_ARG_TYPES) + { + string_append (declp, " static"); + } + if (success && work -> const_type && PRINT_ARG_TYPES) + { + string_append (declp, " const"); + } + return (success); +} + +#if 0 + +static int +demangle_method_args (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int success = 0; + + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + return (success); +} + +#endif + +static int +demangle_template (work, mangled, tname, trawname) + struct work_stuff *work; + CONST char **mangled; + string *tname; + string *trawname; +{ + int i; + int is_pointer; + int is_real; + int is_integral; + int r; + int need_comma = 0; + int success = 0; + int done; + CONST char *old_p; + CONST char *start; + int symbol_len; + string temp; + + (*mangled)++; + start = *mangled; + /* get template name */ + if ((r = consume_count (mangled)) == 0) + { + return (0); + } + if (trawname) + string_appendn (trawname, *mangled, r); + string_appendn (tname, *mangled, r); + *mangled += r; + string_append (tname, "<"); + /* get size of template parameter list */ + if (!get_count (mangled, &r)) + { + return (0); + } + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + } + else + { + /* otherwise, value parameter */ + old_p = *mangled; + is_pointer = 0; + is_real = 0; + is_integral = 0; + done = 0; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + string_append (tname, "="); + while (*old_p && !done) + { + switch (*old_p) + { + case 'P': + case 'R': + done = is_pointer = 1; + break; + case 'C': /* const */ + case 'S': /* explicitly signed [char] */ + case 'U': /* unsigned */ + case 'V': /* volatile */ + case 'F': /* function */ + case 'M': /* member function */ + case 'O': /* ??? */ + old_p++; + continue; + case 'Q': /* repetition of following */ + case 'T': /* remembered type */ + abort (); + break; + case 'v': /* void */ + abort (); + break; + case 'x': /* long long */ + case 'l': /* long */ + case 'i': /* int */ + case 's': /* short */ + case 'c': /* char */ + case 'w': /* wchar_t */ + done = is_integral = 1; + break; + case 'r': /* long double */ + case 'd': /* double */ + case 'f': /* float */ + done = is_real = 1; + break; + default: + abort (); + } + } + if (is_integral) + { + if (**mangled == 'm') + { + string_appendn (tname, "-", 1); + (*mangled)++; + } + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + } + else if (is_real) + { + if (**mangled == 'm') + { + string_appendn (tname, "-", 1); + (*mangled)++; + } + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + if (**mangled == '.') /* fraction */ + { + string_appendn (tname, ".", 1); + (*mangled)++; + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + } + if (**mangled == 'e') /* exponent */ + { + string_appendn (tname, "e", 1); + (*mangled)++; + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + } + } + else if (is_pointer) + { + if (!get_count (mangled, &symbol_len)) + { + success = 0; + break; + } + string_appendn (tname, *mangled, symbol_len); + *mangled += symbol_len; + } + } + need_comma = 1; + } + string_append (tname, ">"); + +/* + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + } +*/ + return (success); +} + +static int +arm_pt (work, mangled, n, anchor, args) + struct work_stuff *work; + CONST char *mangled; + int n; + CONST char **anchor, **args; +{ + /* ARM template? */ + if (ARM_DEMANGLING && (*anchor = strstr(mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + return 0; +} + +static int +demangle_class_name (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int n; + int success = 0; + + n = consume_count (mangled); + if (strlen (*mangled) >= n) + { + CONST char *p; + CONST char *args; + CONST char *e = *mangled + n; + /* ARM template? */ + if (arm_pt (work, *mangled, n, &p, &args)) + { + string arg; + string_init (&arg); + string_appendn (declp, *mangled, p - *mangled); + string_append (declp, "<"); + /* should do error checking here */ + while (args < e) { + string_clear (&arg); + do_type (work, &args, &arg); + string_appends (declp, &arg); + string_append (declp, ","); + } + string_delete (&arg); + --declp->p; + string_append (declp, ">"); + } + else + { + string_appendn (declp, *mangled, n); + } + *mangled += n; + success = 1; + } + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_class -- demangle a mangled class sequence + +SYNOPSIS + + static int + demangle_class (struct work_stuff *work, const char **mangled, + strint *declp) + +DESCRIPTION + + DECLP points to the buffer into which demangling is being done. + + *MANGLED points to the current token to be demangled. On input, + it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) + On exit, it points to the next token after the mangled class on + success, or the first unconsumed token on failure. + + If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then + we are demangling a constructor or destructor. In this case + we prepend "class::class" or "class::~class" to DECLP. + + Otherwise, we prepend "class::" to the current DECLP. + + Reset the constructor/destructor flags once they have been + "consumed". This allows demangle_class to be called later during + the same demangling, to do normal class demangling. + + Returns 1 if demangling is successful, 0 otherwise. + +*/ + +static int +demangle_class (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int success = 0; + string class_name; + + string_init (&class_name); + if (demangle_class_name (work, mangled, &class_name)) + { + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_prepends (declp, &class_name); + if (work -> destructor & 1) + { + string_prepend (declp, "~"); + work -> destructor -= 1; + } + else + { + work -> constructor -= 1; + } + } + string_prepend (declp, "::"); + string_prepends (declp, &class_name); + success = 1; + } + string_delete (&class_name); + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_prefix -- consume the mangled name prefix and find signature + +SYNOPSIS + + static int + demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the prefix of the mangled name. + + DECLP points to the string buffer into which demangled output is + placed. On entry, the buffer is empty. On exit it contains + the root function name, the demangled operator name, or in some + special cases either nothing or the completely demangled result. + + MANGLED points to the current pointer into the mangled name. As each + token of the mangled name is consumed, it is updated. Upon entry + the current mangled name pointer points to the first character of + the mangled name. Upon exit, it should point to the first character + of the signature if demangling was successful, or to the first + unconsumed character if demangling of the prefix was unsuccessful. + + Returns 1 on success, 0 otherwise. + */ + +static int +demangle_prefix (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int success = 1; + CONST char *scan; + int i; + + if (strncmp(*mangled, "_GLOBAL_$D$", 11) == 0) + { + /* it's a GNU global destructor to be executed at program exit */ + (*mangled) += 11; + work->destructor = 2; + } + else if (strncmp(*mangled, "_GLOBAL_$I$", 11) == 0) + { + /* it's a GNU global constructor to be executed at program initial */ + (*mangled) += 11; + work->constructor = 2; + } + else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0) + { + /* it's a ARM global destructor to be executed at program exit */ + (*mangled) += 7; + work->destructor = 2; + } + else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0) + { + /* it's a ARM global constructor to be executed at program initial */ + (*mangled) += 7; + work->constructor = 2; + } + +/* This block of code is a reduction in strength time optimization + of: + scan = strstr (*mangled, "__"); */ + + { + scan = *mangled; + + do { + scan = strchr (scan, '_'); + } while (scan != NULL && *++scan != '_'); + + if (scan != NULL) --scan; + } + + if (scan != NULL) + { + /* We found a sequence of two or more '_', ensure that we start at + the last pair in the sequence. */ + i = strspn (scan, "_"); + if (i > 2) + { + scan += (i - 2); + } + } + + if (scan == NULL) + { + success = 0; + } + else if (work -> static_type) + { + if (!isdigit (scan[0]) && (scan[0] != 't')) + { + success = 0; + } + } + else if ((scan == *mangled) && + (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't'))) + { + /* The ARM says nothing about the mangling of local variables. + But cfront mangles local variables by prepending __ + to them. As an extension to ARM demangling we handle this case. */ + if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2])) + { + *mangled = scan + 2; + consume_count (mangled); + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + else + { + /* A GNU style constructor starts with "__[0-9Qt]. */ + work -> constructor += 1; + *mangled = scan + 2; + } + } + else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't')) + { + /* Mangled name starts with "__". Skip over any leading '_' characters, + then find the next "__" that separates the prefix from the signature. + */ + if (!(ARM_DEMANGLING || LUCID_DEMANGLING) + || (arm_special (work, mangled, declp) == 0)) + { + while (*scan == '_') + { + scan++; + } + if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) + { + /* No separator (I.E. "__not_mangled"), or empty signature + (I.E. "__not_mangled_either__") */ + success = 0; + } + else + { + demangle_function_name (work, mangled, declp, scan); + } + } + } + else if (*(scan + 2) != '\0') + { + /* Mangled name does not start with "__" but does have one somewhere + in there with non empty stuff after it. Looks like a global + function name. */ + demangle_function_name (work, mangled, declp, scan); + } + else + { + /* Doesn't look like a mangled name */ + success = 0; + } + + if (!success && (work->constructor == 2 || work->destructor == 2)) + { + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + return (success); +} + +/* + +LOCAL FUNCTION + + gnu_special -- special handling of gnu mangled strings + +SYNOPSIS + + static int + gnu_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special GNU style mangling forms that don't fit + the normal pattern. For example: + + _$_3foo (destructor for class foo) + _vt$foo (foo virtual table) + _vt$foo$bar (foo::bar virtual table) + _3foo$varname (static data member) + _Q22rs2tu$vw (static data member) + __t6vector1Zii (constructor with template) + */ + +static int +gnu_special (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int n; + int success = 1; + CONST char *p; + + if ((*mangled)[0] == '_' + && strchr (cplus_markers, (*mangled)[1]) != NULL + && (*mangled)[2] == '_') + { + /* Found a GNU style destructor, get past "__" */ + (*mangled) += 3; + work -> destructor += 1; + } + else if ((*mangled)[0] == '_' + && (*mangled)[1] == 'v' + && (*mangled)[2] == 't' + && strchr (cplus_markers, (*mangled)[3]) != NULL) + { + /* Found a GNU style virtual table, get past "_vt" + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + (*mangled) += 4; + while (**mangled != '\0') + { + if (isdigit(*mangled[0])) + { + n = consume_count(mangled); + } + else + { + n = strcspn (*mangled, cplus_markers); + } + string_appendn (declp, *mangled, n); + (*mangled) += n; + + if (**mangled != '\0') + { + string_append (declp, "::"); + (*mangled)++; + } + } + string_append (declp, " virtual table"); + } + else if ((*mangled)[0] == '_' + && (strchr("0123456789Qt", (*mangled)[1]) != NULL) + && (p = strpbrk (*mangled, cplus_markers)) != NULL) + { + /* static data member, "_3foo$varname" for example */ + (*mangled)++; + switch (**mangled) + { + case 'Q': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0); + break; + default: + n = consume_count (mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + if (success && (p == *mangled)) + { + /* Consumed everything up to the cplus_marker, append the + variable name. */ + (*mangled)++; + string_append (declp, "::"); + n = strlen (*mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + else + { + success = 0; + } + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + arm_special -- special handling of ARM/lucid mangled strings + +SYNOPSIS + + static int + arm_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special ARM style mangling forms that don't fit + the normal pattern. For example: + + __vtbl__3foo (foo virtual table) + __vtbl__3foo__3bar (bar::foo virtual table) + + */ + +static int +arm_special (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + int n; + int success = 1; + CONST char *scan; + + if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) + { + /* Found a ARM style virtual table, get past ARM_VTABLE_STRING + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + scan = *mangled + ARM_VTABLE_STRLEN; + while (*scan != '\0') /* first check it can be demangled */ + { + n = consume_count (&scan); + if (n==0) + { + return (0); /* no good */ + } + scan += n; + if (scan[0] == '_' && scan[1] == '_') + { + scan += 2; + } + } + (*mangled) += ARM_VTABLE_STRLEN; + while (**mangled != '\0') + { + n = consume_count (mangled); + string_prependn (declp, *mangled, n); + (*mangled) += n; + if ((*mangled)[0] == '_' && (*mangled)[1] == '_') + { + string_prepend (declp, "::"); + (*mangled) += 2; + } + } + string_append (declp, " virtual table"); + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_qualified -- demangle 'Q' qualified name strings + +SYNOPSIS + + static int + demangle_qualified (struct work_stuff *, const char *mangled, + string *result, int isfuncname, int append); + +DESCRIPTION + + Demangle a qualified name, such as "Q25Outer5Inner" which is + the mangled form of "Outer::Inner". The demangled output is + prepended or appended to the result string according to the + state of the append flag. + + If isfuncname is nonzero, then the qualified name we are building + is going to be used as a member function name, so if it is a + constructor or destructor function, append an appropriate + constructor or destructor name. I.E. for the above example, + the result for use as a constructor is "Outer::Inner::Inner" + and the result for use as a destructor is "Outer::Inner::~Inner". + +BUGS + + Numeric conversion is ASCII dependent (FIXME). + + */ + +static int +demangle_qualified (work, mangled, result, isfuncname, append) + struct work_stuff *work; + CONST char **mangled; + string *result; + int isfuncname; + int append; +{ + int qualifiers; + int namelength; + int success = 1; + CONST char *p; + char num[2]; + string temp; + + string_init (&temp); + switch ((*mangled)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is preceded + by an underscore (to distinguish it from the <= 9 case) and followed + by an underscore. */ + p = *mangled + 2; + qualifiers = atoi (p); + if (!isdigit (*p) || *p == '0') + success = 0; + + /* Skip the digits. */ + while (isdigit (*p)) + ++p; + + if (*p != '_') + success = 0; + + *mangled = p + 1; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* The count is in a single digit. */ + num[0] = (*mangled)[1]; + num[1] = '\0'; + qualifiers = atoi (num); + + /* If there is an underscore after the digit, skip it. This is + said to be for ARM-qualified names, but the ARM makes no + mention of such an underscore. Perhaps cfront uses one. */ + if ((*mangled)[2] == '_') + { + (*mangled)++; + } + (*mangled) += 2; + break; + + case '0': + default: + success = 0; + } + + if (!success) + return success; + + /* Pick off the names and collect them in the temp buffer in the order + in which they are found, separated by '::'. */ + + while (qualifiers-- > 0) + { + if (*mangled[0] == 't') + { + success = demangle_template(work, mangled, &temp, 0); + if (!success) break; + } + else + { + namelength = consume_count (mangled); + if (strlen (*mangled) < namelength) + { + /* Simple sanity check failed */ + success = 0; + break; + } + string_appendn (&temp, *mangled, namelength); + *mangled += namelength; + } + if (qualifiers > 0) + { + string_appendn (&temp, "::", 2); + } + } + + /* If we are using the result as a function name, we need to append + the appropriate '::' separated constructor or destructor name. + We do this here because this is the most convenient place, where + we already have a pointer to the name and the length of the name. */ + + if (isfuncname && (work->constructor & 1 || work->destructor & 1)) + { + string_appendn (&temp, "::", 2); + if (work -> destructor & 1) + { + string_append (&temp, "~"); + } + string_appendn (&temp, (*mangled) - namelength, namelength); + } + + /* Now either prepend the temp buffer to the result, or append it, + depending upon the state of the append flag. */ + + if (append) + { + string_appends (result, &temp); + } + else + { + if (!STRING_EMPTY (result)) + { + string_appendn (&temp, "::", 2); + } + string_prepends (result, &temp); + } + + string_delete (&temp); + return (success); +} + +/* + +LOCAL FUNCTION + + get_count -- convert an ascii count to integer, consuming tokens + +SYNOPSIS + + static int + get_count (const char **type, int *count) + +DESCRIPTION + + Return 0 if no conversion is performed, 1 if a string is converted. +*/ + +static int +get_count (type, count) + CONST char **type; + int *count; +{ + CONST char *p; + int n; + + if (!isdigit (**type)) + { + return (0); + } + else + { + *count = **type - '0'; + (*type)++; + if (isdigit (**type)) + { + p = *type; + n = *count; + do + { + n *= 10; + n += *p - '0'; + p++; + } + while (isdigit (*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + } + return (1); +} + +/* result will be initialised here; it will be freed on failure */ + +static int +do_type (work, mangled, result) + struct work_stuff *work; + CONST char **mangled; + string *result; +{ + int n; + int done; + int success; + string decl; + CONST char *remembered_type; + int constp; + int volatilep; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**mangled) + { + + /* A pointer type */ + case 'P': + (*mangled)++; + string_prepend (&decl, "*"); + break; + + /* A reference type */ + case 'R': + (*mangled)++; + string_prepend (&decl, "&"); + break; + + /* An array */ + case 'A': + { + CONST char *p = ++(*mangled); + + string_prepend (&decl, "("); + string_append (&decl, ")["); + /* Copy anything up until the next underscore (the size of the + array). */ + while (**mangled && **mangled != '_') + ++(*mangled); + if (**mangled == '_') + { + string_appendn (&decl, p, *mangled - p); + string_append (&decl, "]"); + *mangled += 1; + } + else + success = 0; + break; + } + + /* A back reference to a previously seen type */ + case 'T': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> ntypes) + { + success = 0; + } + else + { + remembered_type = work -> typevec[n]; + mangled = &remembered_type; + } + break; + + /* A function */ + case 'F': + (*mangled)++; + if (!STRING_EMPTY (&decl) && decl.b[0] == '*') + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + /* After picking off the function args, we expect to either find the + function return type (preceded by an '_') or the end of the + string. */ + if (!demangle_args (work, mangled, &decl) + || (**mangled != '_' && **mangled != '\0')) + { + success = 0; + } + if (success && (**mangled == '_')) + { + (*mangled)++; + } + break; + + case 'M': + case 'O': + { + constp = 0; + volatilep = 0; + + member = **mangled == 'M'; + (*mangled)++; + if (!isdigit (**mangled)) + { + success = 0; + break; + } + n = consume_count (mangled); + if (strlen (*mangled) < n) + { + success = 0; + break; + } + string_append (&decl, ")"); + string_prepend (&decl, "::"); + string_prependn (&decl, *mangled, n); + string_prepend (&decl, "("); + *mangled += n; + if (member) + { + if (**mangled == 'C') + { + (*mangled)++; + constp = 1; + } + if (**mangled == 'V') + { + (*mangled)++; + volatilep = 1; + } + if (*(*mangled)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !demangle_args (work, mangled, &decl)) + || **mangled != '_') + { + success = 0; + break; + } + (*mangled)++; + if (! PRINT_ANSI_QUALIFIERS) + { + break; + } + if (constp) + { + APPEND_BLANK (&decl); + string_append (&decl, "const"); + } + if (volatilep) + { + APPEND_BLANK (&decl); + string_append (&decl, "volatile"); + } + break; + } + case 'G': + (*mangled)++; + break; + + case 'C': + (*mangled)++; +/* + if ((*mangled)[1] == 'P') + { +*/ + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (&decl)) + { + string_prepend (&decl, " "); + } + string_prepend (&decl, "const"); + } + break; +/* + } +*/ + + /* fall through */ + default: + done = 1; + break; + } + } + + switch (**mangled) + { + /* A qualified name, such as "Outer::Inner". */ + case 'Q': + success = demangle_qualified (work, mangled, result, 0, 1); + break; + + default: + success = demangle_fund_type (work, mangled, result); + break; + } + + if (success) + { + if (!STRING_EMPTY (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + } + else + { + string_delete (result); + } + string_delete (&decl); + return (success); +} + +/* Given a pointer to a type string that represents a fundamental type + argument (int, long, unsigned int, etc) in TYPE, a pointer to the + string in which the demangled output is being built in RESULT, and + the WORK structure, decode the types and add them to the result. + + For example: + + "Ci" => "const int" + "Sl" => "signed long" + "CUs" => "const unsigned short" + + */ + +static int +demangle_fund_type (work, mangled, result) + struct work_stuff *work; + CONST char **mangled; + string *result; +{ + int done = 0; + int success = 1; + + /* First pick off any type qualifiers. There can be more than one. */ + + while (!done) + { + switch (**mangled) + { + case 'C': + (*mangled)++; + if (PRINT_ANSI_QUALIFIERS) + { + APPEND_BLANK (result); + string_append (result, "const"); + } + break; + case 'U': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "unsigned"); + break; + case 'S': /* signed char only */ + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "signed"); + break; + case 'V': + (*mangled)++; + if (PRINT_ANSI_QUALIFIERS) + { + APPEND_BLANK (result); + string_append (result, "volatile"); + } + break; + default: + done = 1; + break; + } + } + + /* Now pick off the fundamental type. There can be only one. */ + + switch (**mangled) + { + case '\0': + case '_': + break; + case 'v': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "void"); + break; + case 'x': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long long"); + break; + case 'l': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long"); + break; + case 'i': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "int"); + break; + case 's': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "short"); + break; + case 'c': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "char"); + break; + case 'w': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "wchar_t"); + break; + case 'r': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long double"); + break; + case 'd': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "double"); + break; + case 'f': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "float"); + break; + case 'G': + (*mangled)++; + if (!isdigit (**mangled)) + { + success = 0; + break; + } + /* fall through */ + /* An explicit type, such as "6mytype" or "7integer" */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + APPEND_BLANK (result); + if (!demangle_class_name (work, mangled, result)) { + --result->p; + success = 0; + } + break; + case 't': + success = demangle_template(work,mangled, result, 0); + break; + default: + success = 0; + break; + } + + return (success); +} + +/* `result' will be initialized in do_type; it will be freed on failure */ + +static int +do_arg (work, mangled, result) + struct work_stuff *work; + CONST char **mangled; + string *result; +{ + CONST char *start = *mangled; + + if (!do_type (work, mangled, result)) + { + return (0); + } + else + { + remember_type (work, start, *mangled - start); + return (1); + } +} + +static void +remember_type (work, start, len) + struct work_stuff *work; + CONST char *start; + int len; +{ + char *tem; + + if (work -> ntypes >= work -> typevec_size) + { + if (work -> typevec_size == 0) + { + work -> typevec_size = 3; + work -> typevec = + (char **) xmalloc (sizeof (char *) * work -> typevec_size); + } + else + { + work -> typevec_size *= 2; + work -> typevec = + (char **) xrealloc ((char *)work -> typevec, + sizeof (char *) * work -> typevec_size); + } + } + tem = xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> typevec[work -> ntypes++] = tem; +} + +/* Forget the remembered types, but not the type vector itself. */ + +static void +forget_types (work) + struct work_stuff *work; +{ + int i; + + while (work -> ntypes > 0) + { + i = --(work -> ntypes); + if (work -> typevec[i] != NULL) + { + free (work -> typevec[i]); + work -> typevec[i] = NULL; + } + } +} + +/* Process the argument list part of the signature, after any class spec + has been consumed, as well as the first 'F' character (if any). For + example: + + "__als__3fooRT0" => process "RT0" + "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" + + DECLP must be already initialised, usually non-empty. It won't be freed + on failure. + + Note that g++ differs significantly from ARM and lucid style mangling + with regards to references to previously seen types. For example, given + the source fragment: + + class foo { + public: + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); + }; + + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + + g++ produces the names: + + __3fooiRT0iT2iT2 + foo__FiR3fooiT1iT1 + + while lcc (and presumably other ARM style compilers as well) produces: + + foo__FiR3fooT1T2T1T2 + __ct__3fooFiR3fooT1T2T1T2 + + Note that g++ bases it's type numbers starting at zero and counts all + previously seen types, while lucid/ARM bases it's type numbers starting + at one and only considers types after it has seen the 'F' character + indicating the start of the function args. For lucid/ARM style, we + account for this difference by discarding any previously seen types when + we see the 'F' character, and subtracting one from the type number + reference. + + */ + +static int +demangle_args (work, mangled, declp) + struct work_stuff *work; + CONST char **mangled; + string *declp; +{ + string arg; + int need_comma = 0; + int r; + int t; + CONST char *tem; + char temptype; + + if (PRINT_ARG_TYPES) + { + string_append (declp, "("); + if (**mangled == '\0') + { + string_append (declp, "void"); + } + } + + while (**mangled != '_' && **mangled != '\0' && **mangled != 'e') + { + if ((**mangled == 'N') || (**mangled == 'T')) + { + temptype = *(*mangled)++; + + if (temptype == 'N') + { + if (!get_count (mangled, &r)) + { + return (0); + } + } + else + { + r = 1; + } + if (!get_count (mangled, &t)) + { + return (0); + } + if (LUCID_DEMANGLING || ARM_DEMANGLING) + { + t--; + } + /* Validate the type index. Protect against illegal indices from + malformed type strings. */ + if ((t < 0) || (t >= work -> ntypes)) + { + return (0); + } + while (--r >= 0) + { + tem = work -> typevec[t]; + if (need_comma && PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + if (!do_arg (work, &tem, &arg)) + { + return (0); + } + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma & PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + if (!do_arg (work, mangled, &arg)) + { + return (0); + } + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + + if (**mangled == 'e') + { + (*mangled)++; + if (PRINT_ARG_TYPES) + { + if (need_comma) + { + string_append (declp, ","); + } + string_append (declp, "..."); + } + } + + if (PRINT_ARG_TYPES) + { + string_append (declp, ")"); + } + return (1); +} + +static void +demangle_function_name (work, mangled, declp, scan) + struct work_stuff *work; + CONST char **mangled; + string *declp; + CONST char *scan; +{ + int i; + int len; + string type; + CONST char *tem; + + string_appendn (declp, (*mangled), scan - (*mangled)); + string_need (declp, 1); + *(declp -> p) = '\0'; + + /* Consume the function name, including the "__" separating the name + from the signature. We are guaranteed that SCAN points to the + separator. */ + + (*mangled) = scan + 2; + + if (LUCID_DEMANGLING || ARM_DEMANGLING) + { + + /* See if we have an ARM style constructor or destructor operator. + If so, then just record it, clear the decl, and return. + We can't build the actual constructor/destructor decl until later, + when we recover the class name from the signature. */ + + if (strcmp (declp -> b, "__ct") == 0) + { + work -> constructor += 1; + string_clear (declp); + return; + } + else if (strcmp (declp -> b, "__dt") == 0) + { + work -> destructor += 1; + string_clear (declp); + return; + } + } + + if (declp->p - declp->b >= 3 + && declp->b[0] == 'o' + && declp->b[1] == 'p' + && strchr (cplus_markers, declp->b[2]) != NULL) + { + /* see if it's an assignment expression */ + if (declp->p - declp->b >= 10 /* op$assign_ */ + && memcmp (declp->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + len = declp->p - declp->b - 10; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 10, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + string_append (declp, "="); + break; + } + } + } + else + { + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + int len = declp->p - declp->b - 3; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 3, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type$", 5) == 0) + { + /* type conversion operator */ + tem = declp->b + 5; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] == 'o' && declp->b[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = declp->b + 4; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] >= 'a' && declp->b[2] <= 'z' + && declp->b[3] >= 'a' && declp->b[3] <= 'z') + { + if (declp->b[4] == '\0') + { + /* Operator. */ + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, declp->b + 2, 2) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + else + { + if (declp->b[2] == 'a' && declp->b[5] == '\0') + { + /* Assignment. */ + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, declp->b + 2, 3) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + } +} + +/* a mini string-handling package */ + +static void +string_need (s, n) + string *s; + int n; +{ + int tem; + + if (s->b == NULL) + { + if (n < 32) + { + n = 32; + } + s->p = s->b = xmalloc (n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + tem = s->p - s->b; + n += tem; + n *= 2; + s->b = xrealloc (s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (s) + string *s; +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (s) + string *s; +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (s) + string *s; +{ + s->p = s->b; +} + +#if 0 + +static int +string_empty (s) + string *s; +{ + return (s->b == s->p); +} + +#endif + +static void +string_append (p, s) + string *p; + CONST char *s; +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (p, s) + string *p, *s; +{ + int n; + + if (s->b != s->p) + { + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; + } +} + +static void +string_appendn (p, s, n) + string *p; + CONST char *s; + int n; +{ + if (n != 0) + { + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; + } +} + +static void +string_prepend (p, s) + string *p; + CONST char *s; +{ + if (s != NULL && *s != '\0') + { + string_prependn (p, s, strlen (s)); + } +} + +static void +string_prepends (p, s) + string *p, *s; +{ + if (s->b != s->p) + { + string_prependn (p, s->b, s->p - s->b); + } +} + +static void +string_prependn (p, s, n) + string *p; + CONST char *s; + int n; +{ + char *q; + + if (n != 0) + { + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + { + q[n] = q[0]; + } + memcpy (p->b, s, n); + p->p += n; + } +} + +/* To generate a standalone demangler program for testing purposes, just + compile and link this file with -DMAIN. When run, it demangles each + command line arg, or each stdin string, and prints the result on stdout. */ + +#ifdef MAIN + +static void +demangle_it (mangled_name) + char *mangled_name; +{ + char *result; + + result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI); + if (result == NULL) + { + printf ("%s\n", mangled_name); + } + else + { + printf ("%s\n", result); + free (result); + } +} + +char * +xmalloc (size) + long size; +{ + char * newmem; + + if ((newmem = (char *) malloc ((int) size)) == NULL) + { + fprintf (stderr, "\nCan't allocate %u bytes\n", size); + exit (1); + } + return (newmem); +} + +char * +xrealloc (oldmem, size) + PTR oldmem; + long size; +{ + char * newmem; + + if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL) + { + fprintf (stderr, "\nCan't reallocate %u bytes\n", size); + exit (1); + } + return (newmem); +} + +#include "getopt.h" + +static char *program_name; +extern char *program_version; + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, "\ +Usage: %s [-_] [-s {gnu,lucid,arm}] [--strip-underscores]\n\ + [--format={gnu,lucid,arm}] [--help] [--version] [arg...]\n", + program_name); + exit (status); +} + +#define MBUF_SIZE 512 +char mbuffer[MBUF_SIZE]; + +/* Defined in the automatically-generated ../binutils/underscore.c. */ +extern int prepends_underscore; + +int strip_underscore = 0; + +static struct option long_options[] = { + {"strip-underscores", no_argument, 0, '_'}, + {"format", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, + {0, no_argument, 0, 0} +}; + +int +main (argc, argv) + int argc; + char **argv; +{ + char *result; + int c; + + program_name = argv[0]; + strip_underscore = prepends_underscore; + + while ((c = getopt_long (argc, argv, "_s:", long_options, (int *) 0)) != EOF) + { + switch (c) + { + case '?': + usage (stderr, 1); + break; + case 'h': + usage (stdout, 0); + case 'v': + printf ("GNU %s version %s\n", program_name, program_version); + exit (0); + case '_': + strip_underscore = 1; + break; + case 's': + if (strcmp (optarg, "gnu") == 0) + { + current_demangling_style = gnu_demangling; + } + else if (strcmp (optarg, "lucid") == 0) + { + current_demangling_style = lucid_demangling; + } + else if (strcmp (optarg, "arm") == 0) + { + current_demangling_style = arm_demangling; + } + else + { + fprintf (stderr, "%s: unknown demangling style `%s'\n", + program_name, optarg); + exit (1); + } + break; + } + } + + if (optind < argc) + { + for ( ; optind < argc; optind++) + { + demangle_it (argv[optind]); + } + } + else + { + for (;;) + { + int i = 0; + c = getchar (); + /* Try to read a label. */ + while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.')) + { + if (i >= MBUF_SIZE-1) + break; + mbuffer[i++] = c; + c = getchar (); + } + if (i > 0) + { + int skip_first = strip_underscore && i > 1 && mbuffer[0] == '_'; + mbuffer[i] = 0; + + result = cplus_demangle (mbuffer+skip_first, + DMGL_PARAMS | DMGL_ANSI); + if (result) + { + fputs (result, stdout); + free (result); + } + else + fputs (mbuffer + skip_first, stdout); + } + if (c == EOF) + break; + putchar (c); + } + } + + exit (0); +} + +#endif /* main */ diff --git a/gnu/usr.bin/gdb/libiberty/fdmatch.c b/gnu/usr.bin/gdb/libiberty/fdmatch.c new file mode 100644 index 00000000000..0a6de2af0fd --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/fdmatch.c @@ -0,0 +1,71 @@ +/* Compare two open file descriptors to see if they refer to the same file. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + + +/* + +NAME + + fdmatch -- see if two file descriptors refer to same file + +SYNOPSIS + + int fdmatch (int fd1, int fd2) + +DESCRIPTION + + Check to see if two open file descriptors refer to the same file. + This is useful, for example, when we have an open file descriptor + for an unnamed file, and the name of a file that we believe to + correspond to that fd. This can happen when we are exec'd with + an already open file (stdout for example) or from the SVR4 /proc + calls that return open file descriptors for mapped address spaces. + All we have to do is open the file by name and check the two file + descriptors for a match, which is done by comparing major&minor + device numbers and inode numbers. + +BUGS + + (FIXME: does this work for networks?) + It works for NFS, which assigns a device number to each mount. + +*/ + +#include +#include + +int fdmatch (fd1, fd2) + int fd1; + int fd2; +{ + struct stat sbuf1; + struct stat sbuf2; + + if ((fstat (fd1, &sbuf1) == 0) && + (fstat (fd2, &sbuf2) == 0) && + (sbuf1.st_dev == sbuf2.st_dev) && + (sbuf1.st_ino == sbuf2.st_ino)) + { + return (1); + } + else + { + return (0); + } +} diff --git a/gnu/usr.bin/gdb/libiberty/getopt.c b/gnu/usr.bin/gdb/libiberty/getopt.c new file mode 100644 index 00000000000..c7a8b032641 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/getopt.c @@ -0,0 +1,750 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +/* This tells Alpha OSF/1 not to define a getopt prototype in . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#endif /* GNU C library. */ + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +/* #define GETOPT_COMPAT */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. + (Supposedly there are some machines where it might get a warning, + but changing this conditional to __STDC__ is too risky.) */ +#ifdef __GNUC__ +#ifdef IN_GCC +#include "gstddef.h" +#else +#include +#endif +extern size_t strlen (const char *); +#endif + +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { +#if 0 + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); +#endif + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { +#if 0 + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/gnu/usr.bin/gdb/libiberty/getopt1.c b/gnu/usr.bin/gdb/libiberty/getopt1.c new file mode 100644 index 00000000000..6806da5f983 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/getopt1.c @@ -0,0 +1,180 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#else +char *getenv (); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/gnu/usr.bin/gdb/libiberty/ieee-float.c b/gnu/usr.bin/gdb/libiberty/ieee-float.c new file mode 100644 index 00000000000..b50eb859a1c --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/ieee-float.c @@ -0,0 +1,150 @@ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright (C) 1991 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. */ + +#include "ieee-float.h" +#include /* ldexp */ + +/* Convert an IEEE extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +ieee_extended_to_double (ext_format, from, to) + CONST struct ext_format *ext_format; + char *from; + double *to; +{ + unsigned char *ufrom = (unsigned char *)from; + double dto; + unsigned long mant0, mant1, exponent; + + memcpy (&mant0, &from[MANBYTE_H], 4); + memcpy (&mant1, &from[MANBYTE_L], 4); + exponent = ((ufrom[EXPBYTE_H] & (unsigned char)~SIGNMASK) << 8) | ufrom[EXPBYTE_L]; + +#if 0 + /* We can't do anything useful with a NaN anyway, so ignore its + difference. It will end up as Infinity or something close. */ + if (exponent == EXT_EXP_NAN) { + /* We have a NaN source. */ + dto = 0.123456789; /* Not much else useful to do -- we don't know if + the host system even *has* NaNs, nor how to + generate an innocuous one if it does. */ + } else +#endif + if (exponent == 0 && mant0 == 0 && mant1 == 0) { + dto = 0; + } else { + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + mant0 |= 0x80000000; + dto = ldexp ((double)mant0, exponent - EXT_EXP_BIAS - 31); + dto += ldexp ((double)mant1, exponent - EXT_EXP_BIAS - 31 - 32); + if (ufrom[EXPBYTE_H] & SIGNMASK) /* If negative... */ + dto = -dto; /* ...negate. */ + } + memcpy (to, &dto, sizeof (dto)); +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +double_to_ieee_extended (ext_format, from, to) + CONST struct ext_format *ext_format; + double *from; + char *to; +{ + double dfrom; + unsigned long twolongs[2]; + unsigned long mant0, mant1, exponent; + unsigned char tobytes[8]; + + memcpy (&dfrom, from, sizeof (dfrom)); + memset (to, 0, TOTALSIZE); + if (dfrom == 0) + return; /* Result is zero */ + if (dfrom != dfrom) { + /* From is NaN */ + to[EXPBYTE_H] = (unsigned char)(EXT_EXP_NAN >> 8); + to[EXPBYTE_L] = (unsigned char)EXT_EXP_NAN; + to[MANBYTE_H] = 1; /* Be sure it's not infinity, but NaN value is irrel */ + return; /* Result is NaN */ + } + if (dfrom < 0) + to[SIGNBYTE] |= SIGNMASK; /* Set negative sign */ + /* How to tell an infinity from an ordinary number? FIXME-someday */ + + /* The following code assumes that the host has IEEE doubles. FIXME-someday. + It also assumes longs are 32 bits! FIXME-someday. */ + memcpy (twolongs, from, 8); + memcpy (tobytes, from, 8); +#if HOST_BYTE_ORDER == BIG_ENDIAN + exponent = ((tobytes[1] & 0xF0) >> 4) | (tobytes[0] & 0x7F) << 4; + mant0 = (twolongs[0] << 11) | twolongs[1] >> 21; + mant1 = (twolongs[1] << 11); +#else + exponent = ((tobytes[6] & 0xF0) >> 4) | (tobytes[7] & 0x7F) << 4; + mant0 = (twolongs[1] << 11) | twolongs[0] >> 21; + mant1 = (twolongs[0] << 11); +#endif + + /* Fiddle with leading 1-bit, implied in double, explicit in extended. */ + if (exponent == 0) + mant0 &= 0x7FFFFFFF; + else + mant0 |= 0x80000000; + + exponent -= DBL_EXP_BIAS; /* Get integer exp */ + exponent += EXT_EXP_BIAS; /* Offset for extended */ + + /* OK, now store it in extended format. */ + to[EXPBYTE_H] |= (unsigned char)(exponent >> 8); /* Retain sign */ + to[EXPBYTE_L] = (unsigned char) exponent; + + memcpy (&to[MANBYTE_H], &mant0, 4); + memcpy (&to[MANBYTE_L], &mant1, 4); +} + + +#ifdef IEEE_DEBUG + +/* Test some numbers to see that extended/double conversion works for them. */ + +ieee_test (n) + int n; +{ + union { double d; int i[2]; } di; + double result; + int i; + char exten[16]; + extern struct ext_format ext_format_68881; + + for (i = 0; i < n; i++) { + di.i[0] = (random() << 16) | (random() & 0xffff); + di.i[1] = (random() << 16) | (random() & 0xffff); + double_to_ieee_extended (&ext_format_68881, &di.d, exten); + ieee_extended_to_double (&ext_format_68881, exten, &result); + if (di.d != result) + printf ("Differ: %x %x %g => %x %x %g\n", di.d, di.d, result, result); + } +} + +#endif diff --git a/gnu/usr.bin/gdb/libiberty/ieee-float.h b/gnu/usr.bin/gdb/libiberty/ieee-float.h new file mode 100644 index 00000000000..68ef23b40fd --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/ieee-float.h @@ -0,0 +1,65 @@ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright (C) 1991 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. */ + +#if !defined (IEEE_FLOAT_H) +#define IEEE_FLOAT_H 1 + +#include "ansidecl.h" + +/* Parameters for extended float format: */ + +struct ext_format { + unsigned totalsize; /* Total size of extended number */ + unsigned signbyte; /* Byte number of sign bit */ + unsigned char signmask; /* Mask for sign bit */ + unsigned expbyte_h; /* High byte of exponent */ + unsigned expbyte_l; /* Low byte of exponent */ + unsigned manbyte_h; /* High byte of mantissa */ + unsigned manbyte_l; /* Low byte of mantissa */ +}; + +#define TOTALSIZE ext_format->totalsize +#define SIGNBYTE ext_format->signbyte +#define SIGNMASK ext_format->signmask +#define EXPBYTE_H ext_format->expbyte_h +#define EXPBYTE_L ext_format->expbyte_l +#define MANBYTE_H ext_format->manbyte_h +#define MANBYTE_L ext_format->manbyte_l + +/* Actual ext_format structs for various machines are in the *-tdep.c file + for each machine. */ + +#define EXT_EXP_NAN 0x7FFF /* Exponent value that indicates NaN */ +#define EXT_EXP_BIAS 0x3FFF /* Amount added to "true" exponent for ext */ +#define DBL_EXP_BIAS 0x3FF /* Ditto, for doubles */ + +/* Convert an IEEE extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +ieee_extended_to_double PARAMS ((const struct ext_format *, char *, double *)); + +/* The converse: convert the double *FROM to an extended float + and store where TO points. */ + +extern void +double_to_ieee_extended PARAMS ((const struct ext_format *, double *, char *)); + +#endif /* defined (IEEE_FLOAT_H) */ diff --git a/gnu/usr.bin/gdb/libiberty/obstack.c b/gnu/usr.bin/gdb/libiberty/obstack.c new file mode 100644 index 00000000000..4297bbbd51f --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/obstack.c @@ -0,0 +1,460 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988, 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Library General Public License as published by the +Free Software Foundation; either version 2, 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 Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "obstack.h" + +/* This is just to get __GNU_LIBRARY__ defined. */ +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#ifdef __STDC__ +#define POINTER void * +#else +#define POINTER char * +#endif + +/* Determine default alignment. */ +struct fooalign {char x; double d;}; +#define DEFAULT_ALIGNMENT \ + ((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0)) +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +union fooround {long x; double d;}; +#define DEFAULT_ROUNDING (sizeof (union fooround)) + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +#ifndef COPYING_UNIT +#define COPYING_UNIT int +#endif + +/* The non-GNU-C macros copy the obstack into this global variable + to avoid multiple evaluation. */ + +struct obstack *_obstack; + +/* Define a macro that either calls functions with the traditional malloc/free + calling interface, or calls functions with the mmalloc/mfree interface + (that adds an extra first argument), based on the state of use_extra_arg. + For free, do not use ?:, since some compilers, like the MIPS compilers, + do not allow (expr) ? void : void. */ + +#define CALL_CHUNKFUN(h, size) \ + (((h) -> use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(h)->chunkfun) ((size))) + +#define CALL_FREEFUN(h, old_chunk) \ + do { \ + if ((h) -> use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(h)->freefun) ((old_chunk)); \ + } while (0) + + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. */ + +void +_obstack_begin (h, size, alignment, chunkfun, freefun) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->use_extra_arg = 0; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; +} + +void +_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); + POINTER arg; +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->extra_arg = arg; + h->use_extra_arg = 1; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (h, length) + struct obstack *h; + int length; +{ + register struct _obstack_chunk* old_chunk = h->chunk; + register struct _obstack_chunk* new_chunk; + register long new_size; + register int obj_size = h->next_free - h->object_base; + register int i; + int already; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = h->chunk = CALL_CHUNKFUN (h, new_size); + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)new_chunk->contents)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + new_chunk->contents[i] = h->object_base[i]; + + /* If the object just copied was the only data in OLD_CHUNK, + free that chunk and remove it from the chain. + But not if that chunk might contain an empty object. */ + if (h->object_base == old_chunk->contents && ! h->maybe_empty_object) + { + new_chunk->prev = old_chunk->prev; + CALL_FREEFUN (h, old_chunk); + } + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; + /* The new chunk certainly contains no empty object yet. */ + h->maybe_empty_object = 0; +} + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +#ifdef __STDC__ +/* Suppress -Wmissing-prototypes warning. We don't want to declare this in + obstack.h because it is just for debugging. */ +int _obstack_allocated_p (struct obstack *h, POINTER obj); +#endif + +int +_obstack_allocated_p (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= rather than > since the object cannot be exactly at + the beginning of the chunk but might be an empty object exactly + at the end of an adjacent chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp->prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +#undef obstack_free + +/* This function has two names with identical definitions. + This is the first one, called from non-ANSI code. */ + +void +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *)(obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +/* This function is used from ANSI code. */ + +void +obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *)(obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +#if 0 +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +#ifdef __STDC__ +/* These function definitions do not work with non-ANSI preprocessors; + they won't pass through the macro names in parentheses. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (obstack) + struct obstack *obstack; +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (obstack) + struct obstack *obstack; +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (obstack) + struct obstack *obstack; +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (obstack) + struct obstack *obstack; +{ + return obstack_room (obstack); +} + +void (obstack_grow) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (obstack) + struct obstack *obstack; +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (obstack, length) + struct obstack *obstack; + int length; +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* __STDC__ */ + +#endif /* 0 */ + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gnu/usr.bin/gdb/libiberty/sigsetmask.c b/gnu/usr.bin/gdb/libiberty/sigsetmask.c new file mode 100644 index 00000000000..545b12e57b3 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/sigsetmask.c @@ -0,0 +1,44 @@ +/* Version of sigsetmask.c + Copyright 1991, 1992 Free Software Foundation, Inc. + Written by Steve Chamberlain (sac@cygnus.com). + Contributed by Cygnus Support. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Set the current signal mask to the set provided, and return the + previous value */ + +#define _POSIX_SOURCE +#include +#include + +#ifdef SIG_SETMASK +int +DEFUN(sigsetmask,(set), + int set) +{ + sigset_t new; + sigset_t old; + + sigemptyset (&new); + if (set != 0) { + abort(); /* FIXME, we don't know how to translate old mask to new */ + } + sigprocmask(SIG_SETMASK, &new, &old); + return 1; /* FIXME, we always return 1 as old value. */ +} +#endif diff --git a/gnu/usr.bin/gdb/libiberty/spaces.c b/gnu/usr.bin/gdb/libiberty/spaces.c new file mode 100644 index 00000000000..28f07462d37 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/spaces.c @@ -0,0 +1,67 @@ +/* Allocate memory region filled with spaces. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + +NAME + + spaces -- return a pointer to a buffer full of spaces + +SYNOPSIS + + char *spaces (int count) + +DESCRIPTION + + Returns a pointer to a memory region filled with the specified + number of spaces and null terminated. The returned pointer is + valid until at least the next call. + +BUGS + +*/ + + +char * +spaces (count) + int count; +{ + register char *t; + static char *buf; + static int maxsize; + extern char *malloc (); + extern void free (); + + if (count > maxsize) + { + if (buf) + { + free (buf); + } + buf = malloc (count + 1); + for (t = buf + count ; t != buf ; ) + { + *--t = ' '; + } + maxsize = count; + buf[count] = '\0'; + } + return (buf + maxsize - count); +} + diff --git a/gnu/usr.bin/gdb/libiberty/strerror.c b/gnu/usr.bin/gdb/libiberty/strerror.c new file mode 100644 index 00000000000..f377311a4f5 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/strerror.c @@ -0,0 +1,811 @@ +/* Extended support for using errno values. + Copyright (C) 1992 Free Software Foundation, Inc. + Written by Fred Fish. fnf@cygnus.com + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include "config.h" + +#ifndef NEED_sys_errlist +/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least) + might declare sys_errlist in a way that the compiler might consider + incompatible with our later declaration, perhaps by using const + attributes. So we hide the declaration in errno.h (if any) using a + macro. */ +#define sys_errlist sys_errlist__ +#endif + +#include +#include + +#ifndef NEED_sys_errlist +#undef sys_errlist +#endif + +/* Routines imported from standard C runtime libraries. */ + +#ifdef __STDC__ +#include +extern void *malloc (size_t size); /* 4.10.3.3 */ +extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ +#else /* !__STDC__ */ +#ifndef const +#define const +#endif +extern char *malloc (); /* Standard memory allocater */ +extern char *memset (); +#endif /* __STDC__ */ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* Translation table for errno values. See intro(2) in most UNIX systems + Programmers Reference Manuals. + + Note that this table is generally only accessed when it is used at runtime + to initialize errno name and message tables that are indexed by errno + value. + + Not all of these errnos will exist on all systems. This table is the only + thing that should have to be updated as new error numbers are introduced. + It's sort of ugly, but at least its portable. */ + +struct error_info +{ + int value; /* The numeric value from */ + char *name; /* The equivalent symbolic value */ + char *msg; /* Short message about this value */ +}; + +static const struct error_info error_table[] = +{ +#if defined (EPERM) + {EPERM, "EPERM", "Not owner"}, +#endif +#if defined (ENOENT) + {ENOENT, "ENOENT", "No such file or directory"}, +#endif +#if defined (ESRCH) + {ESRCH, "ESRCH", "No such process"}, +#endif +#if defined (EINTR) + {EINTR, "EINTR", "Interrupted system call"}, +#endif +#if defined (EIO) + {EIO, "EIO", "I/O error"}, +#endif +#if defined (ENXIO) + {ENXIO, "ENXIO", "No such device or address"}, +#endif +#if defined (E2BIG) + {E2BIG, "E2BIG", "Arg list too long"}, +#endif +#if defined (ENOEXEC) + {ENOEXEC, "ENOEXEC", "Exec format error"}, +#endif +#if defined (EBADF) + {EBADF, "EBADF", "Bad file number"}, +#endif +#if defined (ECHILD) + {ECHILD, "ECHILD", "No child processes"}, +#endif +#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ + {EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"}, +#endif +#if defined (EAGAIN) + {EAGAIN, "EAGAIN", "No more processes"}, +#endif +#if defined (ENOMEM) + {ENOMEM, "ENOMEM", "Not enough space"}, +#endif +#if defined (EACCES) + {EACCES, "EACCES", "Permission denied"}, +#endif +#if defined (EFAULT) + {EFAULT, "EFAULT", "Bad address"}, +#endif +#if defined (ENOTBLK) + {ENOTBLK, "ENOTBLK", "Block device required"}, +#endif +#if defined (EBUSY) + {EBUSY, "EBUSY", "Device busy"}, +#endif +#if defined (EEXIST) + {EEXIST, "EEXIST", "File exists"}, +#endif +#if defined (EXDEV) + {EXDEV, "EXDEV", "Cross-device link"}, +#endif +#if defined (ENODEV) + {ENODEV, "ENODEV", "No such device"}, +#endif +#if defined (ENOTDIR) + {ENOTDIR, "ENOTDIR", "Not a directory"}, +#endif +#if defined (EISDIR) + {EISDIR, "EISDIR", "Is a directory"}, +#endif +#if defined (EINVAL) + {EINVAL, "EINVAL", "Invalid argument"}, +#endif +#if defined (ENFILE) + {ENFILE, "ENFILE", "File table overflow"}, +#endif +#if defined (EMFILE) + {EMFILE, "EMFILE", "Too many open files"}, +#endif +#if defined (ENOTTY) + {ENOTTY, "ENOTTY", "Not a typewriter"}, +#endif +#if defined (ETXTBSY) + {ETXTBSY, "ETXTBSY", "Text file busy"}, +#endif +#if defined (EFBIG) + {EFBIG, "EFBIG", "File too large"}, +#endif +#if defined (ENOSPC) + {ENOSPC, "ENOSPC", "No space left on device"}, +#endif +#if defined (ESPIPE) + {ESPIPE, "ESPIPE", "Illegal seek"}, +#endif +#if defined (EROFS) + {EROFS, "EROFS", "Read-only file system"}, +#endif +#if defined (EMLINK) + {EMLINK, "EMLINK", "Too many links"}, +#endif +#if defined (EPIPE) + {EPIPE, "EPIPE", "Broken pipe"}, +#endif +#if defined (EDOM) + {EDOM, "EDOM", "Math argument out of domain of func"}, +#endif +#if defined (ERANGE) + {ERANGE, "ERANGE", "Math result not representable"}, +#endif +#if defined (ENOMSG) + {ENOMSG, "ENOMSG", "No message of desired type"}, +#endif +#if defined (EIDRM) + {EIDRM, "EIDRM", "Identifier removed"}, +#endif +#if defined (ECHRNG) + {ECHRNG, "ECHRNG", "Channel number out of range"}, +#endif +#if defined (EL2NSYNC) + {EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"}, +#endif +#if defined (EL3HLT) + {EL3HLT, "EL3HLT", "Level 3 halted"}, +#endif +#if defined (EL3RST) + {EL3RST, "EL3RST", "Level 3 reset"}, +#endif +#if defined (ELNRNG) + {ELNRNG, "ELNRNG", "Link number out of range"}, +#endif +#if defined (EUNATCH) + {EUNATCH, "EUNATCH", "Protocol driver not attached"}, +#endif +#if defined (ENOCSI) + {ENOCSI, "ENOCSI", "No CSI structure available"}, +#endif +#if defined (EL2HLT) + {EL2HLT, "EL2HLT", "Level 2 halted"}, +#endif +#if defined (EDEADLK) + {EDEADLK, "EDEADLK", "Deadlock condition"}, +#endif +#if defined (ENOLCK) + {ENOLCK, "ENOLCK", "No record locks available"}, +#endif +#if defined (EBADE) + {EBADE, "EBADE", "Invalid exchange"}, +#endif +#if defined (EBADR) + {EBADR, "EBADR", "Invalid request descriptor"}, +#endif +#if defined (EXFULL) + {EXFULL, "EXFULL", "Exchange full"}, +#endif +#if defined (ENOANO) + {ENOANO, "ENOANO", "No anode"}, +#endif +#if defined (EBADRQC) + {EBADRQC, "EBADRQC", "Invalid request code"}, +#endif +#if defined (EBADSLT) + {EBADSLT, "EBADSLT", "Invalid slot"}, +#endif +#if defined (EDEADLOCK) + {EDEADLOCK, "EDEADLOCK", "File locking deadlock error"}, +#endif +#if defined (EBFONT) + {EBFONT, "EBFONT", "Bad font file format"}, +#endif +#if defined (ENOSTR) + {ENOSTR, "ENOSTR", "Device not a stream"}, +#endif +#if defined (ENODATA) + {ENODATA, "ENODATA", "No data available"}, +#endif +#if defined (ETIME) + {ETIME, "ETIME", "Timer expired"}, +#endif +#if defined (ENOSR) + {ENOSR, "ENOSR", "Out of streams resources"}, +#endif +#if defined (ENONET) + {ENONET, "ENONET", "Machine is not on the network"}, +#endif +#if defined (ENOPKG) + {ENOPKG, "ENOPKG", "Package not installed"}, +#endif +#if defined (EREMOTE) + {EREMOTE, "EREMOTE", "Object is remote"}, +#endif +#if defined (ENOLINK) + {ENOLINK, "ENOLINK", "Link has been severed"}, +#endif +#if defined (EADV) + {EADV, "EADV", "Advertise error"}, +#endif +#if defined (ESRMNT) + {ESRMNT, "ESRMNT", "Srmount error"}, +#endif +#if defined (ECOMM) + {ECOMM, "ECOMM", "Communication error on send"}, +#endif +#if defined (EPROTO) + {EPROTO, "EPROTO", "Protocol error"}, +#endif +#if defined (EMULTIHOP) + {EMULTIHOP, "EMULTIHOP", "Multihop attempted"}, +#endif +#if defined (EDOTDOT) + {EDOTDOT, "EDOTDOT", "RFS specific error"}, +#endif +#if defined (EBADMSG) + {EBADMSG, "EBADMSG", "Not a data message"}, +#endif +#if defined (ENAMETOOLONG) + {ENAMETOOLONG, "ENAMETOOLONG", "File name too long"}, +#endif +#if defined (EOVERFLOW) + {EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"}, +#endif +#if defined (ENOTUNIQ) + {ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"}, +#endif +#if defined (EBADFD) + {EBADFD, "EBADFD", "File descriptor in bad state"}, +#endif +#if defined (EREMCHG) + {EREMCHG, "EREMCHG", "Remote address changed"}, +#endif +#if defined (ELIBACC) + {ELIBACC, "ELIBACC", "Can not access a needed shared library"}, +#endif +#if defined (ELIBBAD) + {ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"}, +#endif +#if defined (ELIBSCN) + {ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"}, +#endif +#if defined (ELIBMAX) + {ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"}, +#endif +#if defined (ELIBEXEC) + {ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"}, +#endif +#if defined (EILSEQ) + {EILSEQ, "EILSEQ", "Illegal byte sequence"}, +#endif +#if defined (ENOSYS) + {ENOSYS, "ENOSYS", "Operation not applicable"}, +#endif +#if defined (ELOOP) + {ELOOP, "ELOOP", "Too many symbolic links encountered"}, +#endif +#if defined (ERESTART) + {ERESTART, "ERESTART", "Interrupted system call should be restarted"}, +#endif +#if defined (ESTRPIPE) + {ESTRPIPE, "ESTRPIPE", "Streams pipe error"}, +#endif +#if defined (ENOTEMPTY) + {ENOTEMPTY, "ENOTEMPTY", "Directory not empty"}, +#endif +#if defined (EUSERS) + {EUSERS, "EUSERS", "Too many users"}, +#endif +#if defined (ENOTSOCK) + {ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"}, +#endif +#if defined (EDESTADDRREQ) + {EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"}, +#endif +#if defined (EMSGSIZE) + {EMSGSIZE, "EMSGSIZE", "Message too long"}, +#endif +#if defined (EPROTOTYPE) + {EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"}, +#endif +#if defined (ENOPROTOOPT) + {ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"}, +#endif +#if defined (EPROTONOSUPPORT) + {EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"}, +#endif +#if defined (ESOCKTNOSUPPORT) + {ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"}, +#endif +#if defined (EOPNOTSUPP) + {EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"}, +#endif +#if defined (EPFNOSUPPORT) + {EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"}, +#endif +#if defined (EAFNOSUPPORT) + {EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"}, +#endif +#if defined (EADDRINUSE) + {EADDRINUSE, "EADDRINUSE", "Address already in use"}, +#endif +#if defined (EADDRNOTAVAIL) + {EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"}, +#endif +#if defined (ENETDOWN) + {ENETDOWN, "ENETDOWN", "Network is down"}, +#endif +#if defined (ENETUNREACH) + {ENETUNREACH, "ENETUNREACH", "Network is unreachable"}, +#endif +#if defined (ENETRESET) + {ENETRESET, "ENETRESET", "Network dropped connection because of reset"}, +#endif +#if defined (ECONNABORTED) + {ECONNABORTED, "ECONNABORTED", "Software caused connection abort"}, +#endif +#if defined (ECONNRESET) + {ECONNRESET, "ECONNRESET", "Connection reset by peer"}, +#endif +#if defined (ENOBUFS) + {ENOBUFS, "ENOBUFS", "No buffer space available"}, +#endif +#if defined (EISCONN) + {EISCONN, "EISCONN", "Transport endpoint is already connected"}, +#endif +#if defined (ENOTCONN) + {ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"}, +#endif +#if defined (ESHUTDOWN) + {ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"}, +#endif +#if defined (ETOOMANYREFS) + {ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"}, +#endif +#if defined (ETIMEDOUT) + {ETIMEDOUT, "ETIMEDOUT", "Connection timed out"}, +#endif +#if defined (ECONNREFUSED) + {ECONNREFUSED, "ECONNREFUSED", "Connection refused"}, +#endif +#if defined (EHOSTDOWN) + {EHOSTDOWN, "EHOSTDOWN", "Host is down"}, +#endif +#if defined (EHOSTUNREACH) + {EHOSTUNREACH, "EHOSTUNREACH", "No route to host"}, +#endif +#if defined (EALREADY) + {EALREADY, "EALREADY", "Operation already in progress"}, +#endif +#if defined (EINPROGRESS) + {EINPROGRESS, "EINPROGRESS", "Operation now in progress"}, +#endif +#if defined (ESTALE) + {ESTALE, "ESTALE", "Stale NFS file handle"}, +#endif +#if defined (EUCLEAN) + {EUCLEAN, "EUCLEAN", "Structure needs cleaning"}, +#endif +#if defined (ENOTNAM) + {ENOTNAM, "ENOTNAM", "Not a XENIX named type file"}, +#endif +#if defined (ENAVAIL) + {ENAVAIL, "ENAVAIL", "No XENIX semaphores available"}, +#endif +#if defined (EISNAM) + {EISNAM, "EISNAM", "Is a named type file"}, +#endif +#if defined (EREMOTEIO) + {EREMOTEIO, "EREMOTEIO", "Remote I/O error"}, +#endif + {0, NULL, NULL} +}; + +/* Translation table allocated and initialized at runtime. Indexed by the + errno value to find the equivalent symbolic value. */ + +static char **error_names; +static int num_error_names = 0; + +/* Translation table allocated and initialized at runtime, if it does not + already exist in the host environment. Indexed by the errno value to find + the descriptive string. + + We don't export it for use in other modules because even though it has the + same name, it differs from other implementations in that it is dynamically + initialized rather than statically initialized. */ + +#ifdef NEED_sys_errlist + +static int sys_nerr; +static char **sys_errlist; + +#else + +extern int sys_nerr; +extern char *sys_errlist[]; + +#endif + + +/* + +NAME + + init_error_tables -- initialize the name and message tables + +SYNOPSIS + + static void init_error_tables (); + +DESCRIPTION + + Using the error_table, which is initialized at compile time, generate + the error_names and the sys_errlist (if needed) tables, which are + indexed at runtime by a specific errno value. + +BUGS + + The initialization of the tables may fail under low memory conditions, + in which case we don't do anything particularly useful, but we don't + bomb either. Who knows, it might succeed at a later point if we free + some memory in the meantime. In any case, the other routines know + how to deal with lack of a table after trying to initialize it. This + may or may not be considered to be a bug, that we don't specifically + warn about this particular failure mode. + +*/ + +static void +init_error_tables () +{ + const struct error_info *eip; + int nbytes; + + /* If we haven't already scanned the error_table once to find the maximum + errno value, then go find it now. */ + + if (num_error_names == 0) + { + for (eip = error_table; eip -> name != NULL; eip++) + { + if (eip -> value >= num_error_names) + { + num_error_names = eip -> value + 1; + } + } + } + + /* Now attempt to allocate the error_names table, zero it out, and then + initialize it from the statically initialized error_table. */ + + if (error_names == NULL) + { + nbytes = num_error_names * sizeof (char *); + if ((error_names = (char **) malloc (nbytes)) != NULL) + { + memset (error_names, 0, nbytes); + for (eip = error_table; eip -> name != NULL; eip++) + { + error_names[eip -> value] = eip -> name; + } + } + } + +#ifdef NEED_sys_errlist + + /* Now attempt to allocate the sys_errlist table, zero it out, and then + initialize it from the statically initialized error_table. */ + + if (sys_errlist == NULL) + { + nbytes = num_error_names * sizeof (char *); + if ((sys_errlist = (char **) malloc (nbytes)) != NULL) + { + memset (sys_errlist, 0, nbytes); + sys_nerr = num_error_names; + for (eip = error_table; eip -> name != NULL; eip++) + { + sys_errlist[eip -> value] = eip -> msg; + } + } + } + +#endif + +} + +/* + +NAME + + errno_max -- return the max errno value + +SYNOPSIS + + int errno_max (); + +DESCRIPTION + + Returns the maximum errno value for which a corresponding symbolic + name or message is available. Note that in the case where + we use the sys_errlist supplied by the system, it is possible for + there to be more symbolic names than messages, or vice versa. + In fact, the manual page for perror(3C) explicitly warns that one + should check the size of the table (sys_nerr) before indexing it, + since new error codes may be added to the system before they are + added to the table. Thus sys_nerr might be smaller than value + implied by the largest errno value defined in . + + We return the maximum value that can be used to obtain a meaningful + symbolic name or message. + +*/ + +int +errno_max () +{ + int maxsize; + + if (error_names == NULL) + { + init_error_tables (); + } + maxsize = MAX (sys_nerr, num_error_names); + return (maxsize - 1); +} + +#ifdef NEED_strerror + +/* + +NAME + + strerror -- map an error number to an error message string + +SYNOPSIS + + char *strerror (int errnoval) + +DESCRIPTION + + Maps an errno number to an error message string, the contents of + which are implementation defined. On systems which have the external + variables sys_nerr and sys_errlist, these strings will be the same + as the ones used by perror(). + + If the supplied error number is within the valid range of indices + for the sys_errlist, but no message is available for the particular + error number, then returns the string "Error NUM", where NUM is the + error number. + + If the supplied error number is not a valid index into sys_errlist, + returns NULL. + + The returned string is only guaranteed to be valid only until the + next call to strerror. + +*/ + +char * +strerror (errnoval) + int errnoval; +{ + char *msg; + static char buf[32]; + +#ifdef NEED_sys_errlist + + if (error_names == NULL) + { + init_error_tables (); + } + +#endif + + if ((errnoval < 0) || (errnoval >= sys_nerr)) + { + /* Out of range, just return NULL */ + msg = NULL; + } + else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL)) + { + /* In range, but no sys_errlist or no entry at this index. */ + sprintf (buf, "Error %d", errnoval); + msg = buf; + } + else + { + /* In range, and a valid message. Just return the message. */ + msg = sys_errlist[errnoval]; + } + + return (msg); +} + +#endif /* NEED_strerror */ + + +/* + +NAME + + strerrno -- map an error number to a symbolic name string + +SYNOPSIS + + char *strerrno (int errnoval) + +DESCRIPTION + + Given an error number returned from a system call (typically + returned in errno), returns a pointer to a string containing the + symbolic name of that error number, as found in . + + If the supplied error number is within the valid range of indices + for symbolic names, but no name is available for the particular + error number, then returns the string "Error NUM", where NUM is + the error number. + + If the supplied error number is not within the range of valid + indices, then returns NULL. + +BUGS + + The contents of the location pointed to are only guaranteed to be + valid until the next call to strerrno. + +*/ + +char * +strerrno (errnoval) + int errnoval; +{ + char *name; + static char buf[32]; + + if (error_names == NULL) + { + init_error_tables (); + } + + if ((errnoval < 0) || (errnoval >= num_error_names)) + { + /* Out of range, just return NULL */ + name = NULL; + } + else if ((error_names == NULL) || (error_names[errnoval] == NULL)) + { + /* In range, but no error_names or no entry at this index. */ + sprintf (buf, "Error %d", errnoval); + name = buf; + } + else + { + /* In range, and a valid name. Just return the name. */ + name = error_names[errnoval]; + } + + return (name); +} + +/* + +NAME + + strtoerrno -- map a symbolic errno name to a numeric value + +SYNOPSIS + + int strtoerrno (char *name) + +DESCRIPTION + + Given the symbolic name of a error number, map it to an errno value. + If no translation is found, returns 0. + +*/ + +int +strtoerrno (name) + char *name; +{ + int errnoval = 0; + + if (name != NULL) + { + if (error_names == NULL) + { + init_error_tables (); + } + for (errnoval = 0; errnoval < num_error_names; errnoval++) + { + if ((error_names[errnoval] != NULL) && + (strcmp (name, error_names[errnoval]) == 0)) + { + break; + } + } + if (errnoval == num_error_names) + { + errnoval = 0; + } + } + return (errnoval); +} + + +/* A simple little main that does nothing but print all the errno translations + if MAIN is defined and this file is compiled and linked. */ + +#ifdef MAIN + +main () +{ + int errn; + int errnmax; + char *name; + char *msg; + char *strerrno (); + char *strerror (); + + errnmax = errno_max (); + printf ("%d entries in names table.\n", num_error_names); + printf ("%d entries in messages table.\n", sys_nerr); + printf ("%d is max useful index.\n", errnmax); + + /* Keep printing values until we get to the end of *both* tables, not + *either* table. Note that knowing the maximum useful index does *not* + relieve us of the responsibility of testing the return pointer for + NULL. */ + + for (errn = 0; errn <= errnmax; errn++) + { + name = strerrno (errn); + name = (name == NULL) ? "" : name; + msg = strerror (errn); + msg = (msg == NULL) ? "" : msg; + printf ("%-4d%-18s%s\n", errn, name, msg); + } +} + +#endif diff --git a/gnu/usr.bin/gdb/libiberty/strsignal.c b/gnu/usr.bin/gdb/libiberty/strsignal.c new file mode 100644 index 00000000000..15411ff496c --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/strsignal.c @@ -0,0 +1,634 @@ +/* Extended support for using signal values. + Copyright (C) 1992 Free Software Foundation, Inc. + Written by Fred Fish. fnf@cygnus.com + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include + +#include "config.h" + +#ifdef LOSING_SYS_SIGLIST +#define sys_siglist no_such_symbol +#endif + +#include +#include + +/* Routines imported from standard C runtime libraries. */ + +#ifdef __STDC__ +#include +extern void *malloc (size_t size); /* 4.10.3.3 */ +extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ +#else /* !__STDC__ */ +#ifndef const +#define const +#endif +extern char *malloc (); /* Standard memory allocater */ +extern char *memset (); +#endif /* __STDC__ */ + +#ifdef LOSING_SYS_SIGLIST +#undef sys_siglist +#endif + + +#ifndef NULL +# ifdef __STDC__ +# define NULL (void *) 0 +# else +# define NULL 0 +# endif +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* Translation table for signal values. + + Note that this table is generally only accessed when it is used at runtime + to initialize signal name and message tables that are indexed by signal + value. + + Not all of these signals will exist on all systems. This table is the only + thing that should have to be updated as new signal numbers are introduced. + It's sort of ugly, but at least its portable. */ + +struct signal_info +{ + int value; /* The numeric value from */ + char *name; /* The equivalent symbolic value */ + char *msg; /* Short message about this value */ +}; + +static const struct signal_info signal_table[] = +{ +#if defined (SIGHUP) + {SIGHUP, "SIGHUP", "Hangup"}, +#endif +#if defined (SIGINT) + {SIGINT, "SIGINT", "Interrupt"}, +#endif +#if defined (SIGQUIT) + {SIGQUIT, "SIGQUIT", "Quit"}, +#endif +#if defined (SIGILL) + {SIGILL, "SIGILL", "Illegal instruction"}, +#endif +#if defined (SIGTRAP) + {SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"}, +#endif +/* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT + overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */ +#if defined (SIGIOT) + {SIGIOT, "SIGIOT", "IOT trap"}, +#endif +#if defined (SIGABRT) + {SIGABRT, "SIGABRT", "Aborted"}, +#endif +#if defined (SIGEMT) + {SIGEMT, "SIGEMT", "Emulation trap"}, +#endif +#if defined (SIGFPE) + {SIGFPE, "SIGFPE", "Arithmetic exception"}, +#endif +#if defined (SIGKILL) + {SIGKILL, "SIGKILL", "Killed"}, +#endif +#if defined (SIGBUS) + {SIGBUS, "SIGBUS", "Bus error"}, +#endif +#if defined (SIGSEGV) + {SIGSEGV, "SIGSEGV", "Segmentation fault"}, +#endif +#if defined (SIGSYS) + {SIGSYS, "SIGSYS", "Bad system call"}, +#endif +#if defined (SIGPIPE) + {SIGPIPE, "SIGPIPE", "Broken pipe"}, +#endif +#if defined (SIGALRM) + {SIGALRM, "SIGALRM", "Alarm clock"}, +#endif +#if defined (SIGTERM) + {SIGTERM, "SIGTERM", "Terminated"}, +#endif +#if defined (SIGUSR1) + {SIGUSR1, "SIGUSR1", "User defined signal 1"}, +#endif +#if defined (SIGUSR2) + {SIGUSR2, "SIGUSR2", "User defined signal 2"}, +#endif +/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD + overrides SIGCLD. SIGCHLD is in POXIX.1 */ +#if defined (SIGCLD) + {SIGCLD, "SIGCLD", "Child status changed"}, +#endif +#if defined (SIGCHLD) + {SIGCHLD, "SIGCHLD", "Child status changed"}, +#endif +#if defined (SIGPWR) + {SIGPWR, "SIGPWR", "Power fail/restart"}, +#endif +#if defined (SIGWINCH) + {SIGWINCH, "SIGWINCH", "Window size changed"}, +#endif +#if defined (SIGURG) + {SIGURG, "SIGURG", "Urgent I/O condition"}, +#endif +#if defined (SIGIO) + /* "I/O pending" has also been suggested, but is misleading since the + signal only happens when the process has asked for it, not everytime + I/O is pending. */ + {SIGIO, "SIGIO", "I/O possible"}, +#endif +#if defined (SIGPOLL) + {SIGPOLL, "SIGPOLL", "Pollable event occurred"}, +#endif +#if defined (SIGSTOP) + {SIGSTOP, "SIGSTOP", "Stopped (signal)"}, +#endif +#if defined (SIGTSTP) + {SIGTSTP, "SIGTSTP", "Stopped (user)"}, +#endif +#if defined (SIGCONT) + {SIGCONT, "SIGCONT", "Continued"}, +#endif +#if defined (SIGTTIN) + {SIGTTIN, "SIGTTIN", "Stopped (tty input)"}, +#endif +#if defined (SIGTTOU) + {SIGTTOU, "SIGTTOU", "Stopped (tty output)"}, +#endif +#if defined (SIGVTALRM) + {SIGVTALRM, "SIGVTALRM", "Virtual timer expired"}, +#endif +#if defined (SIGPROF) + {SIGPROF, "SIGPROF", "Profiling timer expired"}, +#endif +#if defined (SIGXCPU) + {SIGXCPU, "SIGXCPU", "CPU time limit exceeded"}, +#endif +#if defined (SIGXFSZ) + {SIGXFSZ, "SIGXFSZ", "File size limit exceeded"}, +#endif +#if defined (SIGWIND) + {SIGWIND, "SIGWIND", "SIGWIND"}, +#endif +#if defined (SIGPHONE) + {SIGPHONE, "SIGPHONE", "SIGPHONE"}, +#endif +#if defined (SIGLOST) + {SIGLOST, "SIGLOST", "Resource lost"}, +#endif +#if defined (SIGWAITING) + {SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"}, +#endif +#if defined (SIGLWP) + {SIGLWP, "SIGLWP", "Signal LWP"}, +#endif +#if defined (SIGDANGER) + {SIGDANGER, "SIGDANGER", "Swap space dangerously low"}, +#endif +#if defined (SIGGRANT) + {SIGGRANT, "SIGGRANT", "Monitor mode granted"}, +#endif +#if defined (SIGRETRACT) + {SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"}, +#endif +#if defined (SIGMSG) + {SIGMSG, "SIGMSG", "Monitor mode data available"}, +#endif +#if defined (SIGSOUND) + {SIGSOUND, "SIGSOUND", "Sound completed"}, +#endif +#if defined (SIGSAK) + {SIGSAK, "SIGSAK", "Secure attention"}, +#endif + {0, NULL, NULL} +}; + +/* Translation table allocated and initialized at runtime. Indexed by the + signal value to find the equivalent symbolic value. */ + +static char **signal_names; +static int num_signal_names = 0; + +/* Translation table allocated and initialized at runtime, if it does not + already exist in the host environment. Indexed by the signal value to find + the descriptive string. + + We don't export it for use in other modules because even though it has the + same name, it differs from other implementations in that it is dynamically + initialized rather than statically initialized. */ + +#ifdef NEED_sys_siglist + +static int sys_nsig; +static char **sys_siglist; + +#else + +static int sys_nsig = NSIG; +extern const char * const sys_siglist[]; + +#endif + + +/* + +NAME + + init_signal_tables -- initialize the name and message tables + +SYNOPSIS + + static void init_signal_tables (); + +DESCRIPTION + + Using the signal_table, which is initialized at compile time, generate + the signal_names and the sys_siglist (if needed) tables, which are + indexed at runtime by a specific signal value. + +BUGS + + The initialization of the tables may fail under low memory conditions, + in which case we don't do anything particularly useful, but we don't + bomb either. Who knows, it might succeed at a later point if we free + some memory in the meantime. In any case, the other routines know + how to deal with lack of a table after trying to initialize it. This + may or may not be considered to be a bug, that we don't specifically + warn about this particular failure mode. + +*/ + +static void +init_signal_tables () +{ + const struct signal_info *eip; + int nbytes; + + /* If we haven't already scanned the signal_table once to find the maximum + signal value, then go find it now. */ + + if (num_signal_names == 0) + { + for (eip = signal_table; eip -> name != NULL; eip++) + { + if (eip -> value >= num_signal_names) + { + num_signal_names = eip -> value + 1; + } + } + } + + /* Now attempt to allocate the signal_names table, zero it out, and then + initialize it from the statically initialized signal_table. */ + + if (signal_names == NULL) + { + nbytes = num_signal_names * sizeof (char *); + if ((signal_names = (char **) malloc (nbytes)) != NULL) + { + memset (signal_names, 0, nbytes); + for (eip = signal_table; eip -> name != NULL; eip++) + { + signal_names[eip -> value] = eip -> name; + } + } + } + +#ifdef NEED_sys_siglist + + /* Now attempt to allocate the sys_siglist table, zero it out, and then + initialize it from the statically initialized signal_table. */ + + if (sys_siglist == NULL) + { + nbytes = num_signal_names * sizeof (char *); + if ((sys_siglist = (char **) malloc (nbytes)) != NULL) + { + memset (sys_siglist, 0, nbytes); + sys_nsig = num_signal_names; + for (eip = signal_table; eip -> name != NULL; eip++) + { + sys_siglist[eip -> value] = eip -> msg; + } + } + } + +#endif + +} + + +/* + +NAME + + signo_max -- return the max signo value + +SYNOPSIS + + int signo_max (); + +DESCRIPTION + + Returns the maximum signo value for which a corresponding symbolic + name or message is available. Note that in the case where + we use the sys_siglist supplied by the system, it is possible for + there to be more symbolic names than messages, or vice versa. + In fact, the manual page for psignal(3b) explicitly warns that one + should check the size of the table (NSIG) before indexing it, + since new signal codes may be added to the system before they are + added to the table. Thus NSIG might be smaller than value + implied by the largest signo value defined in . + + We return the maximum value that can be used to obtain a meaningful + symbolic name or message. + +*/ + +int +signo_max () +{ + int maxsize; + + if (signal_names == NULL) + { + init_signal_tables (); + } + maxsize = MAX (sys_nsig, num_signal_names); + return (maxsize - 1); +} + + +/* + +NAME + + strsignal -- map a signal number to a signal message string + +SYNOPSIS + + char *strsignal (int signo) + +DESCRIPTION + + Maps an signal number to an signal message string, the contents of + which are implementation defined. On systems which have the external + variable sys_siglist, these strings will be the same as the ones used + by psignal(). + + If the supplied signal number is within the valid range of indices + for the sys_siglist, but no message is available for the particular + signal number, then returns the string "Signal NUM", where NUM is the + signal number. + + If the supplied signal number is not a valid index into sys_siglist, + returns NULL. + + The returned string is only guaranteed to be valid only until the + next call to strsignal. + +*/ + +char * +strsignal (signo) + int signo; +{ + char *msg; + static char buf[32]; + +#ifdef NEED_sys_siglist + + if (signal_names == NULL) + { + init_signal_tables (); + } + +#endif + + if ((signo < 0) || (signo >= sys_nsig)) + { + /* Out of range, just return NULL */ + msg = NULL; + } + else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL)) + { + /* In range, but no sys_siglist or no entry at this index. */ + sprintf (buf, "Signal %d", signo); + msg = buf; + } + else + { + /* In range, and a valid message. Just return the message. */ + msg = (char*)sys_siglist[signo]; + } + + return (msg); +} + + +/* + +NAME + + strsigno -- map an signal number to a symbolic name string + +SYNOPSIS + + char *strsigno (int signo) + +DESCRIPTION + + Given an signal number, returns a pointer to a string containing + the symbolic name of that signal number, as found in . + + If the supplied signal number is within the valid range of indices + for symbolic names, but no name is available for the particular + signal number, then returns the string "Signal NUM", where NUM is + the signal number. + + If the supplied signal number is not within the range of valid + indices, then returns NULL. + +BUGS + + The contents of the location pointed to are only guaranteed to be + valid until the next call to strsigno. + +*/ + +char * +strsigno (signo) + int signo; +{ + char *name; + static char buf[32]; + + if (signal_names == NULL) + { + init_signal_tables (); + } + + if ((signo < 0) || (signo >= num_signal_names)) + { + /* Out of range, just return NULL */ + name = NULL; + } + else if ((signal_names == NULL) || (signal_names[signo] == NULL)) + { + /* In range, but no signal_names or no entry at this index. */ + sprintf (buf, "Signal %d", signo); + name = buf; + } + else + { + /* In range, and a valid name. Just return the name. */ + name = signal_names[signo]; + } + + return (name); +} + + +/* + +NAME + + strtosigno -- map a symbolic signal name to a numeric value + +SYNOPSIS + + int strtosigno (char *name) + +DESCRIPTION + + Given the symbolic name of a signal, map it to a signal number. + If no translation is found, returns 0. + +*/ + +int +strtosigno (name) + char *name; +{ + int signo = 0; + + if (name != NULL) + { + if (signal_names == NULL) + { + init_signal_tables (); + } + for (signo = 0; signo < num_signal_names; signo++) + { + if ((signal_names[signo] != NULL) && + (strcmp (name, signal_names[signo]) == 0)) + { + break; + } + } + if (signo == num_signal_names) + { + signo = 0; + } + } + return (signo); +} + + +/* + +NAME + + psignal -- print message about signal to stderr + +SYNOPSIS + + void psignal (unsigned signo, char *message); + +DESCRIPTION + + Print to the standard error the message, followed by a colon, + followed by the description of the signal specified by signo, + followed by a newline. +*/ + +#ifdef NEED_psignal + +void +psignal (signo, message) + unsigned signo; + char *message; +{ + if (signal_names == NULL) + { + init_signal_tables (); + } + if ((signo <= 0) || (signo >= sys_nsig)) + { + fprintf (stderr, "%s: unknown signal\n", message); + } + else + { + fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]); + } +} + +#endif /* NEED_psignal */ + + +/* A simple little main that does nothing but print all the signal translations + if MAIN is defined and this file is compiled and linked. */ + +#ifdef MAIN + +main () +{ + int signo; + int maxsigno; + char *name; + char *msg; + char *strsigno (); + char *strsignal (); + + maxsigno = signo_max (); + printf ("%d entries in names table.\n", num_signal_names); + printf ("%d entries in messages table.\n", sys_nsig); + printf ("%d is max useful index.\n", maxsigno); + + /* Keep printing values until we get to the end of *both* tables, not + *either* table. Note that knowing the maximum useful index does *not* + relieve us of the responsibility of testing the return pointer for + NULL. */ + + for (signo = 0; signo <= maxsigno; signo++) + { + name = strsigno (signo); + name = (name == NULL) ? "" : name; + msg = strsignal (signo); + msg = (msg == NULL) ? "" : msg; + printf ("%-4d%-18s%s\n", signo, name, msg); + } +} + +#endif diff --git a/gnu/usr.bin/gdb/libiberty/xmalloc.c b/gnu/usr.bin/gdb/libiberty/xmalloc.c new file mode 100644 index 00000000000..be0c7aa9319 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/xmalloc.c @@ -0,0 +1,58 @@ +/* memory allocation routines with error checking. + Copyright 1989, 1991, 1993 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include + +#include + +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + + +PTR +xmalloc (size) + size_t size; +{ + char * newmem; + + if ((newmem = (char *) malloc ((int) size)) == NULL) + { + fprintf (stderr, "\nCan't allocate %u bytes\n", size); + exit (1); + } + return (newmem); +} + +PTR +xrealloc (oldmem, size) + PTR oldmem; + size_t size; +{ + char * newmem; + + if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL) + { + fprintf (stderr, "\nCan't reallocate %u bytes\n", size); + exit (1); + } + return (newmem); +} diff --git a/gnu/usr.bin/gdb/mmalloc/Makefile b/gnu/usr.bin/gdb/mmalloc/Makefile new file mode 100644 index 00000000000..1ef0d1dd0e3 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/Makefile @@ -0,0 +1,10 @@ +LIB= mmalloc +SRCS= mcalloc.c mfree.c mmalloc.c mmcheck.c mmemalign.c mmstats.c \ + mmtrace.c mrealloc.c mvalloc.c mmap-sup.c attach.c detach.c keys.c \ + sbrk-sup.c + +NOPROFILE=no +NOPIC=no +install: + @echo -n +.include diff --git a/gnu/usr.bin/gdb/mmalloc/README.FreeBSD b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD new file mode 100644 index 00000000000..338400ffa88 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD @@ -0,0 +1,7 @@ +This is a greatly pared down libmmalloc directory. Only what's required to build +gdb-4.12 on FreeBSD was kept. + +This is temporary. In FreeBSD 2.0 a fully ported libmmalloc will likely appear +as a system library for use by all the build tools. + +paul@freefall.cdrom.com diff --git a/gnu/usr.bin/gdb/mmalloc/attach.c b/gnu/usr.bin/gdb/mmalloc/attach.c new file mode 100644 index 00000000000..6737fca3872 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/attach.c @@ -0,0 +1,218 @@ +/* Initialization for access to a mmap'd malloc managed region. + Copyright 1992 Free Software Foundation, Inc. + + Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include /* After sys/types.h, at least for dpx/2. */ +#include +#include +#include "mmalloc.h" + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + + +#if defined(HAVE_MMAP) + +/* Forward declarations/prototypes for local functions */ + +static struct mdesc *reuse PARAMS ((int)); + +/* Initialize access to a mmalloc managed region. + + If FD is a valid file descriptor for an open file then data for the + mmalloc managed region is mapped to that file, otherwise "/dev/zero" + is used and the data will not exist in any filesystem object. + + If the open file corresponding to FD is from a previous use of + mmalloc and passes some basic sanity checks to ensure that it is + compatible with the current mmalloc package, then it's data is + mapped in and is immediately accessible at the same addresses in + the current process as the process that created the file. + + If BASEADDR is not NULL, the mapping is established starting at the + specified address in the process address space. If BASEADDR is NULL, + the mmalloc package chooses a suitable address at which to start the + mapped region, which will be the value of the previous mapping if + opening an existing file which was previously built by mmalloc, or + for new files will be a value chosen by mmap. + + Specifying BASEADDR provides more control over where the regions + start and how big they can be before bumping into existing mapped + regions or future mapped regions. + + On success, returns a "malloc descriptor" which is used in subsequent + calls to other mmalloc package functions. It is explicitly "void *" + ("char *" for systems that don't fully support void) so that users + of the package don't have to worry about the actual implementation + details. + + On failure returns NULL. */ + +PTR +mmalloc_attach (fd, baseaddr) + int fd; + PTR baseaddr; +{ + struct mdesc mtemp; + struct mdesc *mdp; + PTR mbase; + struct stat sbuf; + + /* First check to see if FD is a valid file descriptor, and if so, see + if the file has any current contents (size > 0). If it does, then + attempt to reuse the file. If we can't reuse the file, either + because it isn't a valid mmalloc produced file, was produced by an + obsolete version, or any other reason, then we fail to attach to + this file. */ + + if (fd >= 0) + { + if (fstat (fd, &sbuf) < 0) + { + return (NULL); + } + else if (sbuf.st_size > 0) + { + return ((PTR) reuse (fd)); + } + } + + /* We start off with the malloc descriptor allocated on the stack, until + we build it up enough to call _mmalloc_mmap_morecore() to allocate the + first page of the region and copy it there. Ensure that it is zero'd and + then initialize the fields that we know values for. */ + + mdp = &mtemp; + memset ((char *) mdp, 0, sizeof (mtemp)); + strncpy (mdp -> magic, MMALLOC_MAGIC, MMALLOC_MAGIC_SIZE); + mdp -> headersize = sizeof (mtemp); + mdp -> version = MMALLOC_VERSION; + mdp -> morecore = __mmalloc_mmap_morecore; + mdp -> fd = fd; + mdp -> base = mdp -> breakval = mdp -> top = baseaddr; + + /* If we have not been passed a valid open file descriptor for the file + to map to, then open /dev/zero and use that to map to. */ + + if (mdp -> fd < 0) + { + if ((mdp -> fd = open ("/dev/zero", O_RDWR)) < 0) + { + return (NULL); + } + else + { + mdp -> flags |= MMALLOC_DEVZERO; + } + } + + /* Now try to map in the first page, copy the malloc descriptor structure + there, and arrange to return a pointer to this new copy. If the mapping + fails, then close the file descriptor if it was opened by us, and arrange + to return a NULL. */ + + if ((mbase = mdp -> morecore (mdp, sizeof (mtemp))) != NULL) + { + memcpy (mbase, mdp, sizeof (mtemp)); + mdp = (struct mdesc *) mbase; + } + else + { + if (mdp -> flags & MMALLOC_DEVZERO) + { + close (mdp -> fd); + } + mdp = NULL; + } + + return ((PTR) mdp); +} + +/* Given an valid file descriptor on an open file, test to see if that file + is a valid mmalloc produced file, and if so, attempt to remap it into the + current process at the same address to which it was previously mapped. + + Note that we have to update the file descriptor number in the malloc- + descriptor read from the file to match the current valid one, before + trying to map the file in, and again after a successful mapping and + after we've switched over to using the mapped in malloc descriptor + rather than the temporary one on the stack. + + Once we've switched over to using the mapped in malloc descriptor, we + have to update the pointer to the morecore function, since it almost + certainly will be at a different address if the process reusing the + mapped region is from a different executable. + + Also note that if the heap being remapped previously used the mmcheck() + routines, we need to update the hooks since their target functions + will have certainly moved if the executable has changed in any way. + We do this by calling mmcheck() internally. + + Returns a pointer to the malloc descriptor if successful, or NULL if + unsuccessful for some reason. */ + +static struct mdesc * +reuse (fd) + int fd; +{ + struct mdesc mtemp; + struct mdesc *mdp = NULL; + + if ((lseek (fd, 0L, SEEK_SET) == 0) && + (read (fd, (char *) &mtemp, sizeof (mtemp)) == sizeof (mtemp)) && + (mtemp.headersize == sizeof (mtemp)) && + (strcmp (mtemp.magic, MMALLOC_MAGIC) == 0) && + (mtemp.version <= MMALLOC_VERSION)) + { + mtemp.fd = fd; + if (__mmalloc_remap_core (&mtemp) == mtemp.base) + { + mdp = (struct mdesc *) mtemp.base; + mdp -> fd = fd; + mdp -> morecore = __mmalloc_mmap_morecore; + if (mdp -> mfree_hook != NULL) + { + mmcheck ((PTR) mdp, (void (*) PARAMS ((void))) NULL); + } + } + } + return (mdp); +} + +#else /* !defined (HAVE_MMAP) */ + +/* For systems without mmap, the library still supplies an entry point + to link to, but trying to initialize access to an mmap'd managed region + always fails. */ + +/* ARGSUSED */ +PTR +mmalloc_attach (fd, baseaddr) + int fd; + PTR baseaddr; +{ + return (NULL); +} + +#endif /* defined (HAVE_MMAP) */ + diff --git a/gnu/usr.bin/gdb/mmalloc/detach.c b/gnu/usr.bin/gdb/mmalloc/detach.c new file mode 100644 index 00000000000..03d632c2060 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/detach.c @@ -0,0 +1,71 @@ +/* Finish access to a mmap'd malloc managed region. + Copyright 1992 Free Software Foundation, Inc. + + Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include /* After sys/types.h, at least for dpx/2. */ +#include "mmalloc.h" + +/* Terminate access to a mmalloc managed region by unmapping all memory pages + associated with the region, and closing the file descriptor if it is one + that we opened. + + Returns NULL on success. + + Returns the malloc descriptor on failure, which can subsequently be used + for further action, such as obtaining more information about the nature of + the failure by examining the preserved errno value. + + Note that the malloc descriptor that we are using is currently located in + region we are about to unmap, so we first make a local copy of it on the + stack and use the copy. */ + +PTR +mmalloc_detach (md) + PTR md; +{ + struct mdesc mtemp; + + if (md != NULL) + { + + mtemp = *(struct mdesc *) md; + + /* Now unmap all the pages associated with this region by asking for a + negative increment equal to the current size of the region. */ + + if ((mtemp.morecore (&mtemp, mtemp.base - mtemp.top)) == NULL) + { + /* Update the original malloc descriptor with any changes */ + *(struct mdesc *) md = mtemp; + } + else + { + if (mtemp.flags & MMALLOC_DEVZERO) + { + close (mtemp.fd); + } + md = NULL; + } + } + + return (md); +} diff --git a/gnu/usr.bin/gdb/mmalloc/keys.c b/gnu/usr.bin/gdb/mmalloc/keys.c new file mode 100644 index 00000000000..69d41b97739 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/keys.c @@ -0,0 +1,66 @@ +/* Access for application keys in mmap'd malloc managed region. + Copyright 1992 Free Software Foundation, Inc. + + Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* This module provides access to some keys that the application can use to + provide persistent access to locations in the mapped memory section. + The intent is that these keys are to be used sparingly as sort of + persistent global variables which the application can use to reinitialize + access to data in the mapped region. + + For the moment, these keys are simply stored in the malloc descriptor + itself, in an array of fixed length. This should be fixed so that there + can be an unlimited number of keys, possibly using a multilevel access + scheme of some sort. */ + +#include "mmalloc.h" + +int +mmalloc_setkey (md, keynum, key) + PTR md; + int keynum; + PTR key; +{ + struct mdesc *mdp = (struct mdesc *) md; + int result = 0; + + if ((mdp != NULL) && (keynum >= 0) && (keynum < MMALLOC_KEYS)) + { + mdp -> keys [keynum] = key; + result++; + } + return (result); +} + +PTR +mmalloc_getkey (md, keynum) + PTR md; + int keynum; +{ + struct mdesc *mdp = (struct mdesc *) md; + PTR keyval = NULL; + + if ((mdp != NULL) && (keynum >= 0) && (keynum < MMALLOC_KEYS)) + { + keyval = mdp -> keys [keynum]; + } + return (keyval); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mcalloc.c b/gnu/usr.bin/gdb/mmalloc/mcalloc.c new file mode 100644 index 00000000000..08f07bfe1c7 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mcalloc.c @@ -0,0 +1,53 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include /* Prototypes for memcpy, memmove, memset, etc */ + +#include "mmalloc.h" + +/* Allocate an array of NMEMB elements each SIZE bytes long. + The entire array is initialized to zeros. */ + +PTR +mcalloc (md, nmemb, size) + PTR md; + register size_t nmemb; + register size_t size; +{ + register PTR result; + + if ((result = mmalloc (md, nmemb * size)) != NULL) + { + memset (result, 0, nmemb * size); + } + return (result); +} + +/* When using this package, provide a version of malloc/realloc/free built + on top of it, so that if we use the default sbrk() region we will not + collide with another malloc package trying to do the same thing, if + the application contains any "hidden" calls to malloc/realloc/free (such + as inside a system library). */ + +PTR +calloc (nmemb, size) + size_t nmemb; + size_t size; +{ + return (mcalloc ((PTR) NULL, nmemb, size)); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mfree.c b/gnu/usr.bin/gdb/mmalloc/mfree.c new file mode 100644 index 00000000000..aee43aad15b --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mfree.c @@ -0,0 +1,247 @@ +/* Free a block of memory allocated by `mmalloc'. + Copyright 1990, 1991, 1992 Free Software Foundation + + Written May 1989 by Mike Haertel. + Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com) + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include "mmalloc.h" + +/* Return memory to the heap. + Like `mfree' but don't call a mfree_hook if there is one. */ + +void +__mmalloc_free (mdp, ptr) + struct mdesc *mdp; + PTR ptr; +{ + int type; + size_t block, blocks; + register size_t i; + struct list *prev, *next; + + block = BLOCK (ptr); + + type = mdp -> heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + mdp -> heapstats.chunks_used--; + mdp -> heapstats.bytes_used -= + mdp -> heapinfo[block].busy.info.size * BLOCKSIZE; + mdp -> heapstats.bytes_free += + mdp -> heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = mdp -> heapindex; + if (i > block) + { + while (i > block) + { + i = mdp -> heapinfo[i].free.prev; + } + } + else + { + do + { + i = mdp -> heapinfo[i].free.next; + } + while ((i != 0) && (i < block)); + i = mdp -> heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + mdp -> heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + mdp -> heapinfo[i].free.size += + mdp -> heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + mdp -> heapinfo[block].free.size = + mdp -> heapinfo[block].busy.info.size; + mdp -> heapinfo[block].free.next = mdp -> heapinfo[i].free.next; + mdp -> heapinfo[block].free.prev = i; + mdp -> heapinfo[i].free.next = block; + mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block; + mdp -> heapstats.chunks_free++; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + mdp -> heapinfo[block].free.size == + mdp -> heapinfo[block].free.next) + { + mdp -> heapinfo[block].free.size + += mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.size; + mdp -> heapinfo[block].free.next + = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.next; + mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block; + mdp -> heapstats.chunks_free--; + } + + /* Now see if we can return stuff to the system. */ + blocks = mdp -> heapinfo[block].free.size; + if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit + && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks)) + { + register size_t bytes = blocks * BLOCKSIZE; + mdp -> heaplimit -= blocks; + mdp -> morecore (mdp, -bytes); + mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next + = mdp -> heapinfo[block].free.next; + mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev + = mdp -> heapinfo[block].free.prev; + block = mdp -> heapinfo[block].free.prev; + mdp -> heapstats.chunks_free--; + mdp -> heapstats.bytes_free -= bytes; + } + + /* Set the next search to begin at this block. */ + mdp -> heapindex = block; + break; + + default: + /* Do some of the statistics. */ + mdp -> heapstats.chunks_used--; + mdp -> heapstats.bytes_used -= 1 << type; + mdp -> heapstats.chunks_free++; + mdp -> heapstats.bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) + ((char *) ADDRESS(block) + + (mdp -> heapinfo[block].busy.info.frag.first << type)); + + if (mdp -> heapinfo[block].busy.info.frag.nfree == + (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) + { + next = next -> next; + } + prev -> prev -> next = next; + if (next != NULL) + { + next -> prev = prev -> prev; + } + mdp -> heapinfo[block].busy.type = 0; + mdp -> heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + mdp -> heapstats.chunks_used++; + mdp -> heapstats.bytes_used += BLOCKSIZE; + mdp -> heapstats.chunks_free -= BLOCKSIZE >> type; + mdp -> heapstats.bytes_free -= BLOCKSIZE; + + mfree ((PTR) mdp, (PTR) ADDRESS(block)); + } + else if (mdp -> heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next -> next = prev -> next; + next -> prev = prev; + prev -> next = next; + if (next -> next != NULL) + { + next -> next -> prev = next; + } + ++mdp -> heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + mdp -> heapinfo[block].busy.info.frag.nfree = 1; + mdp -> heapinfo[block].busy.info.frag.first = + RESIDUAL (ptr, BLOCKSIZE) >> type; + prev -> next = mdp -> fraghead[type].next; + prev -> prev = &mdp -> fraghead[type]; + prev -> prev -> next = prev; + if (prev -> next != NULL) + { + prev -> next -> prev = prev; + } + } + break; + } +} + +/* Return memory to the heap. */ + +void +mfree (md, ptr) + PTR md; + PTR ptr; +{ + struct mdesc *mdp; + register struct alignlist *l; + + if (ptr != NULL) + { + mdp = MD_TO_MDP (md); + for (l = mdp -> aligned_blocks; l != NULL; l = l -> next) + { + if (l -> aligned == ptr) + { + l -> aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l -> exact; + break; + } + } + if (mdp -> mfree_hook != NULL) + { + (*mdp -> mfree_hook) (md, ptr); + } + else + { + __mmalloc_free (mdp, ptr); + } + } +} + +/* When using this package, provide a version of malloc/realloc/free built + on top of it, so that if we use the default sbrk() region we will not + collide with another malloc package trying to do the same thing, if + the application contains any "hidden" calls to malloc/realloc/free (such + as inside a system library). */ + +void +free (ptr) + PTR ptr; +{ + mfree ((PTR) NULL, ptr); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.c b/gnu/usr.bin/gdb/mmalloc/mmalloc.c new file mode 100644 index 00000000000..46b450e8513 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.c @@ -0,0 +1,334 @@ +/* Memory allocator `malloc'. + Copyright 1990, 1991, 1992 Free Software Foundation + + Written May 1989 by Mike Haertel. + Heavily modified Mar 1992 by Fred Fish for mmap'd version. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include /* Prototypes for memcpy, memmove, memset, etc */ + +#include "mmalloc.h" + +/* Prototypes for local functions */ + +static int initialize PARAMS ((struct mdesc *)); +static PTR morecore PARAMS ((struct mdesc *, size_t)); +static PTR align PARAMS ((struct mdesc *, size_t)); + +/* Aligned allocation. */ + +static PTR +align (mdp, size) + struct mdesc *mdp; + size_t size; +{ + PTR result; + unsigned long int adj; + + result = mdp -> morecore (mdp, size); + adj = RESIDUAL (result, BLOCKSIZE); + if (adj != 0) + { + adj = BLOCKSIZE - adj; + mdp -> morecore (mdp, adj); + result = (char *) result + adj; + } + return (result); +} + +/* Set everything up and remember that we have. */ + +static int +initialize (mdp) + struct mdesc *mdp; +{ + mdp -> heapsize = HEAP / BLOCKSIZE; + mdp -> heapinfo = (malloc_info *) + align (mdp, mdp -> heapsize * sizeof (malloc_info)); + if (mdp -> heapinfo == NULL) + { + return (0); + } + memset ((PTR)mdp -> heapinfo, 0, mdp -> heapsize * sizeof (malloc_info)); + mdp -> heapinfo[0].free.size = 0; + mdp -> heapinfo[0].free.next = mdp -> heapinfo[0].free.prev = 0; + mdp -> heapindex = 0; + mdp -> heapbase = (char *) mdp -> heapinfo; + mdp -> flags |= MMALLOC_INITIALIZED; + return (1); +} + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ + +static PTR +morecore (mdp, size) + struct mdesc *mdp; + size_t size; +{ + PTR result; + malloc_info *newinfo, *oldinfo; + size_t newsize; + + result = align (mdp, size); + if (result == NULL) + { + return (NULL); + } + + /* Check if we need to grow the info table. */ + if ((size_t) BLOCK ((char *) result + size) > mdp -> heapsize) + { + newsize = mdp -> heapsize; + while ((size_t) BLOCK ((char *) result + size) > newsize) + { + newsize *= 2; + } + newinfo = (malloc_info *) align (mdp, newsize * sizeof (malloc_info)); + if (newinfo == NULL) + { + mdp -> morecore (mdp, -size); + return (NULL); + } + memset ((PTR) newinfo, 0, newsize * sizeof (malloc_info)); + memcpy ((PTR) newinfo, (PTR) mdp -> heapinfo, + mdp -> heapsize * sizeof (malloc_info)); + oldinfo = mdp -> heapinfo; + newinfo[BLOCK (oldinfo)].busy.type = 0; + newinfo[BLOCK (oldinfo)].busy.info.size + = BLOCKIFY (mdp -> heapsize * sizeof (malloc_info)); + mdp -> heapinfo = newinfo; + __mmalloc_free (mdp, (PTR)oldinfo); + mdp -> heapsize = newsize; + } + + mdp -> heaplimit = BLOCK ((char *) result + size); + return (result); +} + +/* Allocate memory from the heap. */ + +PTR +mmalloc (md, size) + PTR md; + size_t size; +{ + struct mdesc *mdp; + PTR result; + size_t block, blocks, lastblocks, start; + register size_t i; + struct list *next; + register size_t log; + + if (size == 0) + { + return (NULL); + } + + mdp = MD_TO_MDP (md); + + if (mdp -> mmalloc_hook != NULL) + { + return ((*mdp -> mmalloc_hook) (md, size)); + } + + if (!(mdp -> flags & MMALLOC_INITIALIZED)) + { + if (!initialize (mdp)) + { + return (NULL); + } + } + + if (size < sizeof (struct list)) + { + size = sizeof (struct list); + } + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + log = 1; + --size; + while ((size /= 2) != 0) + { + ++log; + } + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = mdp -> fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (PTR) next; + next -> prev -> next = next -> next; + if (next -> next != NULL) + { + next -> next -> prev = next -> prev; + } + block = BLOCK (result); + if (--mdp -> heapinfo[block].busy.info.frag.nfree != 0) + { + mdp -> heapinfo[block].busy.info.frag.first = + RESIDUAL (next -> next, BLOCKSIZE) >> log; + } + + /* Update the statistics. */ + mdp -> heapstats.chunks_used++; + mdp -> heapstats.bytes_used += 1 << log; + mdp -> heapstats.chunks_free--; + mdp -> heapstats.bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = mmalloc (md, BLOCKSIZE); + if (result == NULL) + { + return (NULL); + } + + /* Link all fragments but the first into the free list. */ + for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next -> next = mdp -> fraghead[log].next; + next -> prev = &mdp -> fraghead[log]; + next -> prev -> next = next; + if (next -> next != NULL) + { + next -> next -> prev = next; + } + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK (result); + mdp -> heapinfo[block].busy.type = log; + mdp -> heapinfo[block].busy.info.frag.nfree = i - 1; + mdp -> heapinfo[block].busy.info.frag.first = i - 1; + + mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1; + mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log); + mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY(size); + start = block = MALLOC_SEARCH_START; + while (mdp -> heapinfo[block].free.size < blocks) + { + block = mdp -> heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Check to see if + the new core will be contiguous with the final free + block; if so we don't need to get as much. */ + block = mdp -> heapinfo[0].free.prev; + lastblocks = mdp -> heapinfo[block].free.size; + if (mdp -> heaplimit != 0 && + block + lastblocks == mdp -> heaplimit && + mdp -> morecore (mdp, 0) == ADDRESS(block + lastblocks) && + (morecore (mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL) + { + /* Which block we are extending (the `final free + block' referred to above) might have changed, if + it got combined with a freed info table. */ + block = mdp -> heapinfo[0].free.prev; + + mdp -> heapinfo[block].free.size += (blocks - lastblocks); + mdp -> heapstats.bytes_free += + (blocks - lastblocks) * BLOCKSIZE; + continue; + } + result = morecore(mdp, blocks * BLOCKSIZE); + if (result == NULL) + { + return (NULL); + } + block = BLOCK (result); + mdp -> heapinfo[block].busy.type = 0; + mdp -> heapinfo[block].busy.info.size = blocks; + mdp -> heapstats.chunks_used++; + mdp -> heapstats.bytes_used += blocks * BLOCKSIZE; + return (result); + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS(block); + if (mdp -> heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + mdp -> heapinfo[block + blocks].free.size + = mdp -> heapinfo[block].free.size - blocks; + mdp -> heapinfo[block + blocks].free.next + = mdp -> heapinfo[block].free.next; + mdp -> heapinfo[block + blocks].free.prev + = mdp -> heapinfo[block].free.prev; + mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next + = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev + = mdp -> heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev + = mdp -> heapinfo[block].free.prev; + mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next + = mdp -> heapindex = mdp -> heapinfo[block].free.next; + mdp -> heapstats.chunks_free--; + } + + mdp -> heapinfo[block].busy.type = 0; + mdp -> heapinfo[block].busy.info.size = blocks; + mdp -> heapstats.chunks_used++; + mdp -> heapstats.bytes_used += blocks * BLOCKSIZE; + mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE; + } + + return (result); +} + +/* When using this package, provide a version of malloc/realloc/free built + on top of it, so that if we use the default sbrk() region we will not + collide with another malloc package trying to do the same thing, if + the application contains any "hidden" calls to malloc/realloc/free (such + as inside a system library). */ + +PTR +malloc (size) + size_t size; +{ + return (mmalloc ((PTR) NULL, size)); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.h b/gnu/usr.bin/gdb/mmalloc/mmalloc.h new file mode 100644 index 00000000000..54b6ed654dc --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.h @@ -0,0 +1,390 @@ +/* Declarations for `mmalloc' and friends. + Copyright 1990, 1991, 1992 Free Software Foundation + + Written May 1989 by Mike Haertel. + Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com) + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + + +#ifndef __MMALLOC_H +#define __MMALLOC_H 1 + +#ifdef __STDC__ +# include +# define PTR void * +# define CONST const +# define PARAMS(paramlist) paramlist +# include +# ifndef NULL +# define NULL (void *) 0 +# endif +#else +# define PTR char * +# define CONST /* nothing */ +# define PARAMS(paramlist) () +# ifndef size_t +# define size_t unsigned int +# endif +# ifndef CHAR_BIT +# define CHAR_BIT 8 +# endif +# ifndef NULL +# define NULL 0 +# endif +#endif + +#ifndef MIN +# define MIN(A, B) ((A) < (B) ? (A) : (B)) +#endif + +#define MMALLOC_MAGIC "mmalloc" /* Mapped file magic number */ +#define MMALLOC_MAGIC_SIZE 8 /* Size of magic number buf */ +#define MMALLOC_VERSION 1 /* Current mmalloc version */ +#define MMALLOC_KEYS 16 /* Keys for application use */ + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ + +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE ((unsigned int) 1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* The difference between two pointers is a signed int. On machines where + the data addresses have the high bit set, we need to ensure that the + difference becomes an unsigned int when we are using the address as an + integral value. In addition, when using with the '%' operator, the + sign of the result is machine dependent for negative values, so force + it to be treated as an unsigned int. */ + +#define ADDR2UINT(addr) ((unsigned int) ((char *) (addr) - (char *) NULL)) +#define RESIDUAL(addr,bsize) ((unsigned int) (ADDR2UINT (addr) % (bsize))) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ + +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ + +#define FINAL_FREE_BLOCKS 8 + +/* Where to start searching the free list when looking for new memory. + The two possible values are 0 and heapindex. Starting at 0 seems + to reduce total memory usage, while starting at heapindex seems to + run faster. */ + +#define MALLOC_SEARCH_START mdp -> heapindex + +/* Address to block number and vice versa. */ + +#define BLOCK(A) (((char *) (A) - mdp -> heapbase) / BLOCKSIZE + 1) + +#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + mdp -> heapbase)) + +/* Data structure giving per-block information. */ + +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large block, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + size_t nfree; /* Free fragments in a fragmented block. */ + size_t first; /* First free fragment of the block. */ + } frag; + /* Size (in blocks) of a large cluster. */ + size_t size; + } info; + } busy; + /* Heap information for a free block (that may be the first of + a free cluster). */ + struct + { + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* List of blocks allocated with `mmemalign' (or `mvalloc'). */ + +struct alignlist + { + struct alignlist *next; + PTR aligned; /* The address that mmemaligned returned. */ + PTR exact; /* The address that malloc returned. */ + }; + +/* Doubly linked lists of free fragments. */ + +struct list + { + struct list *next; + struct list *prev; + }; + +/* Statistics available to the user. + FIXME: By design, the internals of the malloc package are no longer + exported to the user via an include file, so access to this data needs + to be via some other mechanism, such as mmstat_ where the + return value is the the user is interested in. */ + +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Internal structure that defines the format of the malloc-descriptor. + This gets written to the base address of the region that mmalloc is + managing, and thus also becomes the file header for the mapped file, + if such a file exists. */ + +struct mdesc +{ + /* The "magic number" for an mmalloc file. */ + + char magic[MMALLOC_MAGIC_SIZE]; + + /* The size in bytes of this structure, used as a sanity check when reusing + a previously created mapped file. */ + + unsigned int headersize; + + /* The version number of the mmalloc package that created this file. */ + + unsigned char version; + + /* Some flag bits to keep track of various internal things. */ + + unsigned int flags; + + /* If a system call made by the mmalloc package fails, the errno is + preserved for future examination. */ + + int saved_errno; + + /* Pointer to the function that is used to get more core, or return core + to the system, for requests using this malloc descriptor. For memory + mapped regions, this is the mmap() based routine. There may also be + a single malloc descriptor that points to an sbrk() based routine + for systems without mmap() or for applications that call the mmalloc() + package with a NULL malloc descriptor. + + FIXME: For mapped regions shared by more than one process, this + needs to be maintained on a per-process basis. */ + + PTR (*morecore) PARAMS ((struct mdesc *, int)); + + /* Pointer to the function that causes an abort when the memory checking + features are activated. By default this is set to abort(), but can + be set to another function by the application using mmalloc(). + + FIXME: For mapped regions shared by more than one process, this + needs to be maintained on a per-process basis. */ + + void (*abortfunc) PARAMS ((void)); + + /* Debugging hook for free. + + FIXME: For mapped regions shared by more than one process, this + needs to be maintained on a per-process basis. */ + + void (*mfree_hook) PARAMS ((PTR, PTR)); + + /* Debugging hook for `malloc'. + + FIXME: For mapped regions shared by more than one process, this + needs to be maintained on a per-process basis. */ + + PTR (*mmalloc_hook) PARAMS ((PTR, size_t)); + + /* Debugging hook for realloc. + + FIXME: For mapped regions shared by more than one process, this + needs to be maintained on a per-process basis. */ + + PTR (*mrealloc_hook) PARAMS ((PTR, PTR, size_t)); + + /* Number of info entries. */ + + size_t heapsize; + + /* Pointer to first block of the heap (base of the first block). */ + + char *heapbase; + + /* Current search index for the heap table. */ + /* Search index in the info table. */ + + size_t heapindex; + + /* Limit of valid info table indices. */ + + size_t heaplimit; + + /* Block information table. + Allocated with malign/__mmalloc_free (not mmalloc/mfree). */ + /* Table indexed by block number giving per-block information. */ + + malloc_info *heapinfo; + + /* Instrumentation. */ + + struct mstats heapstats; + + /* Free list headers for each fragment size. */ + /* Free lists for each fragment size. */ + + struct list fraghead[BLOCKLOG]; + + /* List of blocks allocated by memalign. */ + + struct alignlist *aligned_blocks; + + /* The base address of the memory region for this malloc heap. This + is the location where the bookkeeping data for mmap and for malloc + begins. */ + + char *base; + + /* The current location in the memory region for this malloc heap which + represents the end of memory in use. */ + + char *breakval; + + /* The end of the current memory region for this malloc heap. This is + the first location past the end of mapped memory. */ + + char *top; + + /* Open file descriptor for the file to which this malloc heap is mapped. + This will always be a valid file descriptor, since /dev/zero is used + by default if no open file is supplied by the client. Also note that + it may change each time the region is mapped and unmapped. */ + + int fd; + + /* An array of keys to data within the mapped region, for use by the + application. */ + + PTR keys[MMALLOC_KEYS]; + +}; + +/* Bits to look at in the malloc descriptor flags word */ + +#define MMALLOC_DEVZERO (1 << 0) /* Have mapped to /dev/zero */ +#define MMALLOC_INITIALIZED (1 << 1) /* Initialized mmalloc */ +#define MMALLOC_MMCHECK_USED (1 << 2) /* mmcheck() called already */ + +/* Allocate SIZE bytes of memory. */ + +extern PTR mmalloc PARAMS ((PTR, size_t)); + +/* Re-allocate the previously allocated block in PTR, making the new block + SIZE bytes long. */ + +extern PTR mrealloc PARAMS ((PTR, PTR, size_t)); + +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ + +extern PTR mcalloc PARAMS ((PTR, size_t, size_t)); + +/* Free a block allocated by `mmalloc', `mrealloc' or `mcalloc'. */ + +extern void mfree PARAMS ((PTR, PTR)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ + +extern PTR mmemalign PARAMS ((PTR, size_t, size_t)); + +/* Allocate SIZE bytes on a page boundary. */ + +extern PTR mvalloc PARAMS ((PTR, size_t)); + +/* Activate a standard collection of debugging hooks. */ + +extern int mmcheck PARAMS ((PTR, void (*) (void))); + +/* Pick up the current statistics. (see FIXME elsewhere) */ + +extern struct mstats mmstats PARAMS ((PTR)); + +/* Internal version of `mfree' used in `morecore'. */ + +extern void __mmalloc_free PARAMS ((struct mdesc *, PTR)); + +/* Hooks for debugging versions. */ + +extern void (*__mfree_hook) PARAMS ((PTR, PTR)); +extern PTR (*__mmalloc_hook) PARAMS ((PTR, size_t)); +extern PTR (*__mrealloc_hook) PARAMS ((PTR, PTR, size_t)); + +/* A default malloc descriptor for the single sbrk() managed region. */ + +extern struct mdesc *__mmalloc_default_mdp; + +/* Initialize the first use of the default malloc descriptor, which uses + an sbrk() region. */ + +extern struct mdesc *__mmalloc_sbrk_init PARAMS ((void)); + +/* Grow or shrink a contiguous mapped region using mmap(). + Works much like sbrk() */ + +#if defined(HAVE_MMAP) + +extern PTR __mmalloc_mmap_morecore PARAMS ((struct mdesc *, int)); + +#endif + +/* Remap a mmalloc region that was previously mapped. */ + +extern PTR __mmalloc_remap_core PARAMS ((struct mdesc *)); + +/* Macro to convert from a user supplied malloc descriptor to pointer to the + internal malloc descriptor. If the user supplied descriptor is NULL, then + use the default internal version, initializing it if necessary. Otherwise + just cast the user supplied version (which is void *) to the proper type + (struct mdesc *). */ + +#define MD_TO_MDP(md) \ + ((md) == NULL \ + ? (__mmalloc_default_mdp == NULL \ + ? __mmalloc_sbrk_init () \ + : __mmalloc_default_mdp) \ + : (struct mdesc *) (md)) + +#endif /* __MMALLOC_H */ diff --git a/gnu/usr.bin/gdb/mmalloc/mmalloc.texi b/gnu/usr.bin/gdb/mmalloc/mmalloc.texi new file mode 100644 index 00000000000..5e28398c334 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmalloc.texi @@ -0,0 +1,258 @@ +\input texinfo @c -*- Texinfo -*- +@setfilename mmalloc.info + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Mmalloc: (mmalloc). The GNU mapped-malloc package. +END-INFO-DIR-ENTRY +@end format + +This file documents the GNU mmalloc (mapped-malloc) package, written by +fnf@@cygnus.com, based on GNU malloc written by mike@@ai.mit.edu. + +Copyright (C) 1992 Free Software Foundation, Inc. + +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. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo +@iftex +@c @finalout +@setchapternewpage odd +@settitle MMALLOC, the GNU memory-mapped malloc package +@titlepage +@title mmalloc +@subtitle The GNU memory-mapped malloc package +@author Fred Fish +@author Cygnus Support +@author Mike Haertel +@author Free Software Foundation +@page + +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 1.1.1.1 $} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill fnf\@cygnus.com\par +\hfill {\it MMALLOC, the GNU memory-mapped malloc package}, \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1992 Free Software Foundation, Inc. + +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. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage +@end iftex + +@ifinfo +@node Top, Overview, (dir), (dir) +@top mmalloc +This file documents the GNU memory-mapped malloc package mmalloc. + +@menu +* Overview:: Overall Description +* Implementation:: Implementation + + --- The Detailed Node Listing --- + +Implementation + +* Compatibility:: Backwards Compatibility +* Functions:: Function Descriptions +@end menu + +@end ifinfo + +@node Overview, Implementation, Top, Top +@chapter Overall Description + +This is a heavily modified version of GNU @code{malloc}. It uses +@code{mmap} as the basic mechanism for for obtaining memory from the +system, rather than @code{sbrk}. This gives it several advantages over the +more traditional malloc: + +@itemize @bullet +@item +Several different heaps can be used, each of them growing +or shinking under control of @code{mmap}, with the @code{mmalloc} functions +using a specific heap on a call by call basis. + +@item +By using @code{mmap}, it is easy to create heaps which are intended to +be persistent and exist as a filesystem object after the creating +process has gone away. + +@item +Because multiple heaps can be managed, data used for a +specific purpose can be allocated into its own heap, making +it easier to allow applications to ``dump'' and ``restore'' initialized +malloc-managed memory regions. For example, the ``unexec'' hack popularized +by GNU Emacs could potentially go away. +@end itemize + +@node Implementation, , Overview, Top +@chapter Implementation + +The @code{mmalloc} functions contain no internal static state. All +@code{mmalloc} internal data is allocated in the mapped in region, along +with the user data that it manages. This allows it to manage multiple +such regions and to ``pick up where it left off'' when such regions are +later dynamically mapped back in. + +In some sense, malloc has been ``purified'' to contain no internal state +information and generalized to use multiple memory regions rather than a +single region managed by @code{sbrk}. However the new routines now need an +extra parameter which informs @code{mmalloc} which memory region it is dealing +with (along with other information). This parameter is called the +@dfn{malloc descriptor}. + +The functions initially provided by @code{mmalloc} are: + +@example +void *mmalloc_attach (int fd, void *baseaddr); +void *mmalloc_detach (void *md); +int mmalloc_errno (void *md); +int mmalloc_setkey (void *md, int keynum, void *key); +void *mmalloc_getkey (void *md, int keynum); + +void *mmalloc (void *md, size_t size); +void *mrealloc (void *md, void *ptr, size_t size); +void *mvalloc (void *md, size_t size); +void mfree (void *md, void *ptr); +@end example + +@menu +* Compatibility:: Backwards Compatibility +* Functions:: Function Descriptions +@end menu + +@node Compatibility, Functions, Implementation, Implementation +@section Backwards Compatibility + +To allow a single malloc package to be used in a given application, +provision is made for the traditional @code{malloc}, @code{realloc}, and +@code{free} functions to be implemented as special cases of the +@code{mmalloc} functions. In particular, if any of the functions that +expect malloc descriptors are called with a @code{NULL} pointer rather than a +valid malloc descriptor, then they default to using an @code{sbrk} managed +region. +The @code{mmalloc} package provides compatible @code{malloc}, @code{realloc}, +and @code{free} functions using this mechanism internally. +Applications can avoid this extra interface layer by simply including the +following defines: + +@example +#define malloc(size) mmalloc ((void *)0, (size)) +#define realloc(ptr,size) mrealloc ((void *)0, (ptr), (size)); +#define free(ptr) mfree ((void *)0, (ptr)) +@end example + +@noindent +or replace the existing @code{malloc}, @code{realloc}, and @code{free} +calls with the above patterns if using @code{#define} causes problems. + +@node Functions, , Compatibility, Implementation +@section Function Descriptions + +These are the details on the functions that make up the @code{mmalloc} +package. + +@table @code +@item void *mmalloc_attach (int @var{fd}, void *@var{baseaddr}); +Initialize access to a @code{mmalloc} managed region. + +If @var{fd} is a valid file descriptor for an open file, then data for the +@code{mmalloc} managed region is mapped to that file. Otherwise +@file{/dev/zero} is used and the data will not exist in any filesystem object. + +If the open file corresponding to @var{fd} is from a previous use of +@code{mmalloc} and passes some basic sanity checks to ensure that it is +compatible with the current @code{mmalloc} package, then its data is +mapped in and is immediately accessible at the same addresses in +the current process as the process that created the file. + +If @var{baseaddr} is not @code{NULL}, the mapping is established +starting at the specified address in the process address space. If +@var{baseaddr} is @code{NULL}, the @code{mmalloc} package chooses a +suitable address at which to start the mapped region, which will be the +value of the previous mapping if opening an existing file which was +previously built by @code{mmalloc}, or for new files will be a value +chosen by @code{mmap}. + +Specifying @var{baseaddr} provides more control over where the regions +start and how big they can be before bumping into existing mapped +regions or future mapped regions. + +On success, returns a malloc descriptor which is used in subsequent +calls to other @code{mmalloc} package functions. It is explicitly +@samp{void *} (@samp{char *} for systems that don't fully support +@code{void}) so that users of the package don't have to worry about the +actual implementation details. + +On failure returns @code{NULL}. + +@item void *mmalloc_detach (void *@var{md}); +Terminate access to a @code{mmalloc} managed region identified by the +descriptor @var{md}, by closing the base file and unmapping all memory +pages associated with the region. + +Returns @code{NULL} on success. + +Returns the malloc descriptor on failure, which can subsequently +be used for further action (such as obtaining more information about +the nature of the failure). + +@item void *mmalloc (void *@var{md}, size_t @var{size}); +Given an @code{mmalloc} descriptor @var{md}, allocate additional memory of +@var{size} bytes in the associated mapped region. + +@item *mrealloc (void *@var{md}, void *@var{ptr}, size_t @var{size}); +Given an @code{mmalloc} descriptor @var{md} and a pointer to memory +previously allocated by @code{mmalloc} in @var{ptr}, reallocate the +memory to be @var{size} bytes long, possibly moving the existing +contents of memory if necessary. + +@item void *mvalloc (void *@var{md}, size_t @var{size}); +Like @code{mmalloc} but the resulting memory is aligned on a page boundary. + +@item void mfree (void *@var{md}, void *@var{ptr}); +Given an @code{mmalloc} descriptor @var{md} and a pointer to memory previously +allocated by @code{mmalloc} in @var{ptr}, free the previously allocated memory. + +@item int mmalloc_errno (void *@var{md}); +Given a @code{mmalloc} descriptor, if the last @code{mmalloc} operation +failed for some reason due to a system call failure, then +returns the associated @code{errno}. Returns 0 otherwise. +(This function is not yet implemented). +@end table + +@bye diff --git a/gnu/usr.bin/gdb/mmalloc/mmap-sup.c b/gnu/usr.bin/gdb/mmalloc/mmap-sup.c new file mode 100644 index 00000000000..37b307905c5 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmap-sup.c @@ -0,0 +1,144 @@ +/* Support for an sbrk-like function that uses mmap. + Copyright 1992 Free Software Foundation, Inc. + + Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#if defined(HAVE_MMAP) + +#include +#include +#include + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#include "mmalloc.h" + +extern int munmap PARAMS ((caddr_t, size_t)); /* Not in any header file */ + +/* Cache the pagesize for the current host machine. Note that if the host + does not readily provide a getpagesize() function, we need to emulate it + elsewhere, not clutter up this file with lots of kluges to try to figure + it out. */ + +static size_t pagesize; +extern int getpagesize PARAMS ((void)); + +#define PAGE_ALIGN(addr) (caddr_t) (((long)(addr) + pagesize - 1) & \ + ~(pagesize - 1)) + +/* Get core for the memory region specified by MDP, using SIZE as the + amount to either add to or subtract from the existing region. Works + like sbrk(), but using mmap(). */ + +PTR +__mmalloc_mmap_morecore (mdp, size) + struct mdesc *mdp; + int size; +{ + PTR result = NULL; + off_t foffset; /* File offset at which new mapping will start */ + size_t mapbytes; /* Number of bytes to map */ + caddr_t moveto; /* Address where we wish to move "break value" to */ + caddr_t mapto; /* Address we actually mapped to */ + char buf = 0; /* Single byte to write to extend mapped file */ + + if (pagesize == 0) + { + pagesize = getpagesize (); + } + if (size == 0) + { + /* Just return the current "break" value. */ + result = mdp -> breakval; + } + else if (size < 0) + { + /* We are deallocating memory. If the amount requested would cause + us to try to deallocate back past the base of the mmap'd region + then do nothing, and return NULL. Otherwise, deallocate the + memory and return the old break value. */ + if (mdp -> breakval + size >= mdp -> base) + { + result = (PTR) mdp -> breakval; + mdp -> breakval += size; + moveto = PAGE_ALIGN (mdp -> breakval); + munmap (moveto, (size_t) (mdp -> top - moveto)); + mdp -> top = moveto; + } + } + else + { + /* We are allocating memory. Make sure we have an open file + descriptor and then go on to get the memory. */ + if (mdp -> fd < 0) + { + result = NULL; + } + else if (mdp -> breakval + size > mdp -> top) + { + /* The request would move us past the end of the currently + mapped memory, so map in enough more memory to satisfy + the request. This means we also have to grow the mapped-to + file by an appropriate amount, since mmap cannot be used + to extend a file. */ + moveto = PAGE_ALIGN (mdp -> breakval + size); + mapbytes = moveto - mdp -> top; + foffset = mdp -> top - mdp -> base; + /* FIXME: Test results of lseek() and write() */ + lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET); + write (mdp -> fd, &buf, 1); + mapto = mmap (mdp -> top, mapbytes, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, mdp -> fd, foffset); + if (mapto == mdp -> top) + { + mdp -> top = moveto; + result = (PTR) mdp -> breakval; + mdp -> breakval += size; + } + } + else + { + result = (PTR) mdp -> breakval; + mdp -> breakval += size; + } + } + return (result); +} + +PTR +__mmalloc_remap_core (mdp) + struct mdesc *mdp; +{ + caddr_t base; + + /* FIXME: Quick hack, needs error checking and other attention. */ + + base = mmap (mdp -> base, mdp -> top - mdp -> base, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + mdp -> fd, 0); + return ((PTR) base); +} + +#else /* defined(HAVE_MMAP) */ +/* Prevent "empty translation unit" warnings from the idiots at X3J11. */ +static char ansi_c_idiots = 69; +#endif /* defined(HAVE_MMAP) */ diff --git a/gnu/usr.bin/gdb/mmalloc/mmcheck.c b/gnu/usr.bin/gdb/mmalloc/mmcheck.c new file mode 100644 index 00000000000..c3e29d3b3d7 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmcheck.c @@ -0,0 +1,196 @@ +/* Standard debugging hooks for `mmalloc'. + Copyright 1990, 1991, 1992 Free Software Foundation + + Written May 1989 by Mike Haertel. + Heavily modified Mar 1992 by Fred Fish (fnf@cygnus.com) + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include "mmalloc.h" + +/* Default function to call when something awful happens. The application + can specify an alternate function to be called instead (and probably will + want to). */ + +extern void abort PARAMS ((void)); + +/* Arbitrary magical numbers. */ + +#define MAGICWORD (unsigned int) 0xfedabeeb /* Active chunk */ +#define MAGICWORDFREE (unsigned int) 0xdeadbeef /* Inactive chunk */ +#define MAGICBYTE ((char) 0xd7) + +/* Each memory allocation is bounded by a header structure and a trailer + byte. I.E. + + + + The pointer returned to the user points to the first byte in the + user's allocation area. The magic word can be tested to detect + buffer underruns and the magic byte can be tested to detect overruns. */ + +struct hdr + { + size_t size; /* Exact size requested by user. */ + unsigned long int magic; /* Magic number to check header integrity. */ + }; + +/* Check the magicword and magicbyte, and if either is corrupted then + call the emergency abort function specified for the heap in use. */ + +static void +checkhdr (mdp, hdr) + struct mdesc *mdp; + CONST struct hdr *hdr; +{ + if (hdr -> magic != MAGICWORD || + ((char *) &hdr[1])[hdr -> size] != MAGICBYTE) + { + (*mdp -> abortfunc)(); + } +} + +static void +mfree_check (md, ptr) + PTR md; + PTR ptr; +{ + struct hdr *hdr = ((struct hdr *) ptr) - 1; + struct mdesc *mdp; + + mdp = MD_TO_MDP (md); + checkhdr (mdp, hdr); + hdr -> magic = MAGICWORDFREE; + mdp -> mfree_hook = NULL; + mfree (md, (PTR)hdr); + mdp -> mfree_hook = mfree_check; +} + +static PTR +mmalloc_check (md, size) + PTR md; + size_t size; +{ + struct hdr *hdr; + struct mdesc *mdp; + size_t nbytes; + + mdp = MD_TO_MDP (md); + mdp -> mmalloc_hook = NULL; + nbytes = sizeof (struct hdr) + size + 1; + hdr = (struct hdr *) mmalloc (md, nbytes); + mdp -> mmalloc_hook = mmalloc_check; + if (hdr != NULL) + { + hdr -> size = size; + hdr -> magic = MAGICWORD; + hdr++; + *((char *) hdr + size) = MAGICBYTE; + } + return ((PTR) hdr); +} + +static PTR +mrealloc_check (md, ptr, size) + PTR md; + PTR ptr; + size_t size; +{ + struct hdr *hdr = ((struct hdr *) ptr) - 1; + struct mdesc *mdp; + size_t nbytes; + + mdp = MD_TO_MDP (md); + checkhdr (mdp, hdr); + mdp -> mfree_hook = NULL; + mdp -> mmalloc_hook = NULL; + mdp -> mrealloc_hook = NULL; + nbytes = sizeof (struct hdr) + size + 1; + hdr = (struct hdr *) mrealloc (md, (PTR) hdr, nbytes); + mdp -> mfree_hook = mfree_check; + mdp -> mmalloc_hook = mmalloc_check; + mdp -> mrealloc_hook = mrealloc_check; + if (hdr != NULL) + { + hdr -> size = size; + hdr++; + *((char *) hdr + size) = MAGICBYTE; + } + return ((PTR) hdr); +} + +/* Turn on default checking for mmalloc/mrealloc/mfree, for the heap specified + by MD. If FUNC is non-NULL, it is a pointer to the function to call + to abort whenever memory corruption is detected. By default, this is the + standard library function abort(). + + Note that we disallow installation of initial checking hooks if mmalloc + has been called at any time for this particular heap, since if any region + that is allocated prior to installation of the hooks is subsequently + reallocated or freed after installation of the hooks, it is guaranteed + to trigger a memory corruption error. We do this by checking the state + of the MMALLOC_INITIALIZED flag. + + However, we can call this function at any time after the initial call, + to update the function pointers to the checking routines and to the + user defined corruption handler routine, as long as these function pointers + have been previously extablished by the initial call. Note that we + do this automatically when remapping an previously used heap, to ensure + that the hooks get updated to the correct values, although the corruption + handler pointer gets set back to the default. The application can then + call mmcheck to use a different corruption handler if desired. + + Returns non-zero if checking is successfully enabled, zero otherwise. */ + +int +mmcheck (md, func) + PTR md; + void (*func) PARAMS ((void)); +{ + struct mdesc *mdp; + int rtnval; + + mdp = MD_TO_MDP (md); + + /* We can safely set or update the abort function at any time, regardless + of whether or not we successfully do anything else. */ + + mdp -> abortfunc = (func != NULL ? func : abort); + + /* If we haven't yet called mmalloc the first time for this heap, or if we + have hooks that were previously installed, then allow the hooks to be + initialized or updated. */ + + if (1 /* FIXME: Always allow installation for now. */ || + !(mdp -> flags & MMALLOC_INITIALIZED) || + (mdp -> mfree_hook != NULL)) + { + mdp -> mfree_hook = mfree_check; + mdp -> mmalloc_hook = mmalloc_check; + mdp -> mrealloc_hook = mrealloc_check; + mdp -> flags |= MMALLOC_MMCHECK_USED; + rtnval = 1; + } + else + { + rtnval = 0; + } + + return (rtnval); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mmemalign.c b/gnu/usr.bin/gdb/mmalloc/mmemalign.c new file mode 100644 index 00000000000..63350a215cd --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmemalign.c @@ -0,0 +1,64 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include "mmalloc.h" + +PTR +mmemalign (md, alignment, size) + PTR md; + size_t alignment; + size_t size; +{ + PTR result; + unsigned long int adj; + struct alignlist *l; + struct mdesc *mdp; + + size = ((size + alignment - 1) / alignment) * alignment; + + if ((result = mmalloc (md, size)) != NULL) + { + adj = RESIDUAL (result, alignment); + if (adj != 0) + { + mdp = MD_TO_MDP (md); + for (l = mdp -> aligned_blocks; l != NULL; l = l -> next) + { + if (l -> aligned == NULL) + { + /* This slot is free. Use it. */ + break; + } + } + if (l == NULL) + { + l = (struct alignlist *) mmalloc (md, sizeof (struct alignlist)); + if (l == NULL) + { + mfree (md, result); + return (NULL); + } + } + l -> exact = result; + result = l -> aligned = (char *) result + alignment - adj; + l -> next = mdp -> aligned_blocks; + mdp -> aligned_blocks = l; + } + } + return (result); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mmstats.c b/gnu/usr.bin/gdb/mmalloc/mmstats.c new file mode 100644 index 00000000000..d3846eb2dbe --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmstats.c @@ -0,0 +1,46 @@ +/* Access the statistics maintained by `mmalloc'. + Copyright 1990, 1991, 1992 Free Software Foundation + + Written May 1989 by Mike Haertel. + Modified Mar 1992 by Fred Fish. (fnf@cygnus.com) + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include "mmalloc.h" + +/* FIXME: See the comment in mmalloc.h where struct mstats is defined. + None of the internal mmalloc structures should be externally visible + outside the library. */ + +struct mstats +mmstats (md) + PTR md; +{ + struct mstats result; + struct mdesc *mdp; + + mdp = MD_TO_MDP (md); + result.bytes_total = + (char *) mdp -> morecore (mdp, 0) - mdp -> heapbase; + result.chunks_used = mdp -> heapstats.chunks_used; + result.bytes_used = mdp -> heapstats.bytes_used; + result.chunks_free = mdp -> heapstats.chunks_free; + result.bytes_free = mdp -> heapstats.bytes_free; + return (result); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mmtrace.c b/gnu/usr.bin/gdb/mmalloc/mmtrace.c new file mode 100644 index 00000000000..73368a1b57a --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mmtrace.c @@ -0,0 +1,166 @@ +/* More debugging hooks for `mmalloc'. + Copyright 1991, 1992 Free Software Foundation + + Written April 2, 1991 by John Gilmore of Cygnus Support + Based on mcheck.c by Mike Haertel. + Modified Mar 1992 by Fred Fish. (fnf@cygnus.com) + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include "mmalloc.h" + +#ifndef __GNU_LIBRARY__ +extern char *getenv (); +#endif + +static FILE *mallstream; + +#if 0 /* FIXME: Disabled for now. */ +static char mallenv[] = "MALLOC_TRACE"; +static char mallbuf[BUFSIZ]; /* Buffer for the output. */ +#endif + +/* Address to breakpoint on accesses to... */ +static PTR mallwatch; + +/* Old hook values. */ + +static void (*old_mfree_hook) PARAMS ((PTR, PTR)); +static PTR (*old_mmalloc_hook) PARAMS ((PTR, size_t)); +static PTR (*old_mrealloc_hook) PARAMS ((PTR, PTR, size_t)); + +/* This function is called when the block being alloc'd, realloc'd, or + freed has an address matching the variable "mallwatch". In a debugger, + set "mallwatch" to the address of interest, then put a breakpoint on + tr_break. */ + +static void +tr_break () +{ +} + +static void +tr_freehook (md, ptr) + PTR md; + PTR ptr; +{ + struct mdesc *mdp; + + mdp = MD_TO_MDP (md); + /* Be sure to print it first. */ + fprintf (mallstream, "- %08x\n", (unsigned int) ptr); + if (ptr == mallwatch) + tr_break (); + mdp -> mfree_hook = old_mfree_hook; + mfree (md, ptr); + mdp -> mfree_hook = tr_freehook; +} + +static PTR +tr_mallochook (md, size) + PTR md; + size_t size; +{ + PTR hdr; + struct mdesc *mdp; + + mdp = MD_TO_MDP (md); + mdp -> mmalloc_hook = old_mmalloc_hook; + hdr = (PTR) mmalloc (md, size); + mdp -> mmalloc_hook = tr_mallochook; + + /* We could be printing a NULL here; that's OK. */ + fprintf (mallstream, "+ %08x %x\n", (unsigned int) hdr, size); + + if (hdr == mallwatch) + tr_break (); + + return (hdr); +} + +static PTR +tr_reallochook (md, ptr, size) + PTR md; + PTR ptr; + size_t size; +{ + PTR hdr; + struct mdesc *mdp; + + mdp = MD_TO_MDP (md); + + if (ptr == mallwatch) + tr_break (); + + mdp -> mfree_hook = old_mfree_hook; + mdp -> mmalloc_hook = old_mmalloc_hook; + mdp -> mrealloc_hook = old_mrealloc_hook; + hdr = (PTR) mrealloc (md, ptr, size); + mdp -> mfree_hook = tr_freehook; + mdp -> mmalloc_hook = tr_mallochook; + mdp -> mrealloc_hook = tr_reallochook; + if (hdr == NULL) + /* Failed realloc. */ + fprintf (mallstream, "! %08x %x\n", (unsigned int) ptr, size); + else + fprintf (mallstream, "< %08x\n> %08x %x\n", (unsigned int) ptr, + (unsigned int) hdr, size); + + if (hdr == mallwatch) + tr_break (); + + return hdr; +} + +/* We enable tracing if either the environment variable MALLOC_TRACE + is set, or if the variable mallwatch has been patched to an address + that the debugging user wants us to stop on. When patching mallwatch, + don't forget to set a breakpoint on tr_break! */ + +int +mmtrace () +{ +#if 0 /* FIXME! This is disabled for now until we figure out how to + maintain a stack of hooks per heap, since we might have other + hooks (such as set by mmcheck) active also. */ + char *mallfile; + + mallfile = getenv (mallenv); + if (mallfile != NULL || mallwatch != NULL) + { + mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w"); + if (mallstream != NULL) + { + /* Be sure it doesn't mmalloc its buffer! */ + setbuf (mallstream, mallbuf); + fprintf (mallstream, "= Start\n"); + old_mfree_hook = mdp -> mfree_hook; + mdp -> mfree_hook = tr_freehook; + old_mmalloc_hook = mdp -> mmalloc_hook; + mdp -> mmalloc_hook = tr_mallochook; + old_mrealloc_hook = mdp -> mrealloc_hook; + mdp -> mrealloc_hook = tr_reallochook; + } + } + +#endif /* 0 */ + + return (1); +} + diff --git a/gnu/usr.bin/gdb/mmalloc/mrealloc.c b/gnu/usr.bin/gdb/mmalloc/mrealloc.c new file mode 100644 index 00000000000..85bec565dad --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mrealloc.c @@ -0,0 +1,160 @@ +/* Change the size of a block allocated by `mmalloc'. + Copyright 1990, 1991 Free Software Foundation + Written May 1989 by Mike Haertel. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include /* Prototypes for memcpy, memmove, memset, etc */ + +#include "mmalloc.h" + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both mfree and mmalloc. */ + +PTR +mrealloc (md, ptr, size) + PTR md; + PTR ptr; + size_t size; +{ + struct mdesc *mdp; + PTR result; + int type; + size_t block, blocks, oldlimit; + + if (size == 0) + { + mfree (md, ptr); + return (mmalloc (md, 0)); + } + else if (ptr == NULL) + { + return (mmalloc (md, size)); + } + + mdp = MD_TO_MDP (md); + + if (mdp -> mrealloc_hook != NULL) + { + return ((*mdp -> mrealloc_hook) (md, ptr, size)); + } + + block = BLOCK (ptr); + + type = mdp -> heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = mmalloc (md, size); + if (result != NULL) + { + memcpy (result, ptr, size); + mfree (md, ptr); + return (result); + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY (size); + if (blocks < mdp -> heapinfo[block].busy.info.size) + { + /* The new size is smaller; return excess memory to the free list. */ + mdp -> heapinfo[block + blocks].busy.type = 0; + mdp -> heapinfo[block + blocks].busy.info.size + = mdp -> heapinfo[block].busy.info.size - blocks; + mdp -> heapinfo[block].busy.info.size = blocks; + mfree (md, ADDRESS (block + blocks)); + result = ptr; + } + else if (blocks == mdp -> heapinfo[block].busy.info.size) + { + /* No size change necessary. */ + result = ptr; + } + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = mdp -> heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = mdp -> heaplimit; + mdp -> heaplimit = 0; + mfree (md, ptr); + mdp -> heaplimit = oldlimit; + result = mmalloc (md, size); + if (result == NULL) + { + mmalloc (md, blocks * BLOCKSIZE); + return (NULL); + } + if (ptr != result) + { + memmove (result, ptr, blocks * BLOCKSIZE); + } + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) + { + /* The new size is the same kind of fragment. */ + result = ptr; + } + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = mmalloc (md, size); + if (result == NULL) + { + return (NULL); + } + memcpy (result, ptr, MIN (size, (size_t) 1 << type)); + mfree (md, ptr); + } + break; + } + + return (result); +} + +/* When using this package, provide a version of malloc/realloc/free built + on top of it, so that if we use the default sbrk() region we will not + collide with another malloc package trying to do the same thing, if + the application contains any "hidden" calls to malloc/realloc/free (such + as inside a system library). */ + +PTR +realloc (ptr, size) + PTR ptr; + size_t size; +{ + return (mrealloc ((PTR) NULL, ptr, size)); +} diff --git a/gnu/usr.bin/gdb/mmalloc/mvalloc.c b/gnu/usr.bin/gdb/mmalloc/mvalloc.c new file mode 100644 index 00000000000..1ffba7865cf --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/mvalloc.c @@ -0,0 +1,40 @@ +/* Allocate memory on a page boundary. + Copyright (C) 1991 Free Software Foundation, Inc. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include "mmalloc.h" + +/* Cache the pagesize for the current host machine. Note that if the host + does not readily provide a getpagesize() function, we need to emulate it + elsewhere, not clutter up this file with lots of kluges to try to figure + it out. */ + +static size_t pagesize; +extern int getpagesize PARAMS ((void)); + +PTR +mvalloc (md, size) + PTR md; + size_t size; +{ + if (pagesize == 0) + { + pagesize = getpagesize (); + } + + return (mmemalign (md, pagesize, size)); +} diff --git a/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c b/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c new file mode 100644 index 00000000000..e6a57d6ccad --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/sbrk-sup.c @@ -0,0 +1,96 @@ +/* Support for sbrk() regions. + Copyright 1992 Free Software Foundation, Inc. + Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include /* Prototypes for memcpy, memmove, memset, etc */ + +#include "mmalloc.h" + +extern PTR sbrk (); + +/* The mmalloc() package can use a single implicit malloc descriptor + for mmalloc/mrealloc/mfree operations which do not supply an explicit + descriptor. For these operations, sbrk() is used to obtain more core + from the system, or return core. This allows mmalloc() to provide + backwards compatibility with the non-mmap'd version. */ + +struct mdesc *__mmalloc_default_mdp; + +/* Use sbrk() to get more core. */ + +static PTR +sbrk_morecore (mdp, size) + struct mdesc *mdp; + int size; +{ + PTR result; + + if ((result = sbrk (size)) == (PTR) -1) + { + result = NULL; + } + else + { + mdp -> breakval += size; + mdp -> top += size; + } + return (result); +} + +/* Initialize the default malloc descriptor if this is the first time + a request has been made to use the default sbrk'd region. + + Since no alignment guarantees are made about the initial value returned + by sbrk, test the initial value and (if necessary) sbrk enough additional + memory to start off with alignment to BLOCKSIZE. We actually only need + it aligned to an alignment suitable for any object, so this is overkill. + But at most it wastes just part of one BLOCKSIZE chunk of memory and + minimizes portability problems by avoiding us having to figure out + what the actual minimal alignment is. The rest of the malloc code + avoids this as well, by always aligning to the minimum of the requested + size rounded up to a power of two, or to BLOCKSIZE. + + Note that we are going to use some memory starting at this initial sbrk + address for the sbrk region malloc descriptor, which is a struct, so the + base address must be suitably aligned. */ + +struct mdesc * +__mmalloc_sbrk_init () +{ + PTR base; + unsigned int adj; + + base = sbrk (0); + adj = RESIDUAL (base, BLOCKSIZE); + if (adj != 0) + { + sbrk (BLOCKSIZE - adj); + base = sbrk (0); + } + __mmalloc_default_mdp = (struct mdesc *) sbrk (sizeof (struct mdesc)); + memset ((char *) __mmalloc_default_mdp, 0, sizeof (struct mdesc)); + __mmalloc_default_mdp -> morecore = sbrk_morecore; + __mmalloc_default_mdp -> base = base; + __mmalloc_default_mdp -> breakval = __mmalloc_default_mdp -> top = sbrk (0); + __mmalloc_default_mdp -> fd = -1; + return (__mmalloc_default_mdp); +} + +