Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!sparkles.dcss.mcmaster.ca!kevinb From: kevinb@sparkles.dcss.mcmaster.ca (Kevin Boyes) Newsgroups: gnu.gdb.bug Subject: (none) Message-ID: <8906261352.AA01111@sparkles.dcss.mcmaster.ca> Date: 26 Jun 89 13:52:24 GMT Sender: daemon@tut.cis.ohio-state.edu Distribution: gnu Organization: GNUs Not Usenet Lines: 1222 A bug report for gdb 3.1.1. See the enclosed shar, in particular what.happened. #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # what.happened # blockframe.c # inflow.c # This archive created: Mon Jun 26 09:49:44 1989 export PATH; PATH=/bin:$PATH if test -f 'what.happened' then echo shar: will not over-write existing file "'what.happened'" else cat << \SHAR_EOF > 'what.happened' Hello, While installing gdb on our Sun4/280 I came across a bug. It involves dereferencing a NULL pointer in get_frame_block in the file blockframe.c What follows is a log of the compile and dbx (sorry) run on gdb. I will also include the file blockframe.c and the file inflow.c where I got a complaint and made a fix. The fix provided for blockframe.c is a hack as I do not have time to spend with the code. As I said above I am running on a Sun4/280 with SunOS Release 4.0.1_Export If anymore information is required just ask. Maybe gcc should recognize -sun4 or -msun4 option ??? Kevin Boyes =============================================================================== Script started on Fri Jun 23 16:27:09 1989 /u0/staff/kevinb/tmp/gnu/gdb/3.1.1 [1]] config.gdb Usage: config.gdb machine [operating-system] Available machine types: hp9k320 i386 i386gas isi merlin news npl pn sparc sun2 sun2os4 sun3 sun3os4 sun4os4 umax vax /u0/staff/kevinb/tmp/gnu/gdb/3.1.1 [2]] config.gdb sparc sunos4 Linked `param.h' to `m-sparc.h'. Linked `pinsn.c' to `sparc-pinsn.c'. Linked `opcode.h' to `sparc-opcode.h'. Linked `dep.c' to `sparc-dep.c'. Links are now set up for use with a sparc. /u0/staff/kevinb/tmp/gnu/gdb/3.1.1 [3]] make gcc -I. -g -sun4 -c main.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c blockframe.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c breakpoint.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c findvar.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c stack.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c source.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c values.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c eval.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c valops.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c valarith.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c valprint.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c printcmd.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c symtab.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c symmisc.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c coffread.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c dbxread.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c infcmd.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c infrun.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c remote.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c command.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c utils.c gcc: unrecognized option `-sun4' gcc -c -I. -g expread.tab.c mv expread.tab.o expread.o gcc -I. -g -sun4 -c expprint.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c pinsn.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c environ.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c version.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c core.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c inflow.c inflow.c: In function terminal_ours_1: inflow.c:204: warning: assignment between incompatible pointer types gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c dep.c gcc: unrecognized option `-sun4' gcc -I. -g -sun4 -c obstack.c gcc: unrecognized option `-sun4' rm init.c rm: init.c: No such file or directory *** Error code 1 (ignored) ./munch main.o blockframe.o breakpoint.o findvar.o stack.o source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o command.o utils.o expread.o expprint.o pinsn.o environ.o version.o core.o inflow.o dep.o > init.c gcc -g -o gdb init.c main.o blockframe.o breakpoint.o findvar.o stack.o source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o command.o utils.o expread.o expprint.o pinsn.o environ.o version.o core.o inflow.o dep.o obstack.o /u0/staff/kevinb/tmp/gnu/gdb/3.1.1 [4]] exit script done on Fri Jun 23 16:31:34 1989 ======================================= after fixing inflow.c ^^^^^^^^^^^^^^^^^^^^^ gcc -I. -g -sun4 -c inflow.c gcc: unrecognized option `-sun4' rm init.c ./munch main.o blockframe.o breakpoint.o findvar.o stack.o source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o command.o utils.o expread.o expprint.o pinsn.o environ.o version.o core.o inflow.o dep.o > init.c gcc -g -o gdb init.c main.o blockframe.o breakpoint.o findvar.o stack.o source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o command.o utils.o expread.o expprint.o pinsn.o environ.o version.o core.o inflow.o dep.o obstack.o ======================================= Script started on Fri Jun 23 16:40:14 1989 /u0/staff/kevinb/tmp/gnu/gdb/3.1.1 [1]] dbx gdb Reading symbolic information... Read 19494 symbols (dbx) run Running: gdb GDB 3.1.1, Copyright (C) 1988 Free Software Foundation, Inc. There is ABSOLUTELY NO WARRANTY for GDB; type "info warranty" for details. GDB is free software and you are welcome to distribute copies of it under certain conditions; type "info copying" to see the conditions. Function fatal not defined. Type "help" for a list of commands. (gdb) info args signal SEGV (segmentation violation) in get_frame_block at line 357 in file "/blockframe.c" 357 return block_for_pc (fi->pc); (dbx) where get_frame_block(frame = (nil)), line 357 in "blockframe.c" get_frame_function(frame = (nil)), line 389 in "blockframe.c" print_frame_arg_vars(), line 500 in "stack.c" args_info(), line 530 in "stack.c" execute_command(p = 0x69df1 "", from_tty = 1), line 423 in "main.c" command_loop(), line 447 in "main.c" main(argc = 1, argv = 0xf7fffe24, envp = 0xf7fffe2c), line 376 in "main.c" (dbx) print fi `blockframe`get_frame_block`fi = (nil) (dbx) quit /u0/staff/kevinb/tmp/gnu/gdb/3.1.1 [2]] exit script done on Fri Jun 23 16:42:17 1989 SHAR_EOF fi # end of overwriting check if test -f 'blockframe.c' then echo shar: will not over-write existing file "'blockframe.c'" else cat << \SHAR_EOF > 'blockframe.c' /* Get info from stack frames; convert between frames, blocks, functions and pc values. Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc. GDB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the GDB General Public License for full details. Everyone is granted permission to copy, modify and redistribute GDB, but only under the conditions described in the GDB General Public License. A copy of this license is supposed to have been given to you along with GDB so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. In other words, go ahead and share GDB, but don't try to stop anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" #include "param.h" #include "symtab.h" #include "frame.h" /* Address of end of first object file. This file is assumed to be a startup file and frames with pc's inside it are treated as nonexistent. */ CORE_ADDR first_object_file_end; /* Address of innermost stack frame (contents of FP register) */ static FRAME current_frame; struct block *block_for_pc (); CORE_ADDR get_pc_function_start (); /* * 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 */ 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->next_frame = 0; /* Since arbitrary */ fci->pc = pc; #ifdef INIT_EXTRA_FRAME_INFO INIT_EXTRA_FRAME_INFO (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); } /* * 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 */ } /* 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; } /* Return a structure containing various interesting information about the frame that called NEXT_FRAME. */ struct frame_info * get_prev_frame_info (next_frame) FRAME next_frame; { FRAME_ADDR address; struct frame_info *prev; int fromleaf = 0; /* If we are within "start" right now, don't go any higher. */ if (next_frame && next_frame->pc < first_object_file_end) return 0; /* 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 (!current_frame) fatal ("get_prev_frame_info: Called before cache primed"); return current_frame; } else { /* If we have the prev one, return it */ if (next_frame->prev) return next_frame->prev; /* There is a questionable, but probably always correct assumption being made here. The assumption is that if functions on a specific machine has a FUNCTION_START_OFFSET, then this is used by the function call instruction for some purpose. If the function call instruction has this much hair in it, it probably also sets up the frame pointer automatically (ie. we'll never have what I am calling a "leaf node", one which shares a frame pointer with it's calling function). This is true on a vax. The only other way to find this out would be to setup a seperate macro "FUNCTION_HAS_FRAME_POINTER", which would often be equivalent to SKIP_PROLOGUE modifying a pc value. */ #if FUNCTION_START_OFFSET == 0 if (!(next_frame->next)) { /* Innermost */ CORE_ADDR func_start, after_prologue; func_start = (get_pc_function_start (next_frame->pc) + FUNCTION_START_OFFSET); after_prologue = func_start; SKIP_PROLOGUE (after_prologue); if (after_prologue == func_start) { fromleaf = 1; address = next_frame->frame; } } #endif if (!fromleaf) { /* Two macros defined in param.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. */ address = FRAME_CHAIN (next_frame); if (!FRAME_CHAIN_VALID (address, next_frame)) return 0; /* If frame has a caller, combine the chain pointer and the frame's own address to get the address of the caller. */ address = FRAME_CHAIN_COMBINE (address, next_frame); } } 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->next_frame = prev->next ? prev->next->frame : 0; #ifdef INIT_EXTRA_FRAME_INFO INIT_EXTRA_FRAME_INFO(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 m-sparc.h). We want the pc saved in the inferior frame. */ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) : next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ()); return prev; } CORE_ADDR get_frame_pc (frame) FRAME frame; { struct frame_info *fi; fi = get_frame_info (frame); return fi->pc; } /* 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; { #if 1 FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr); #else { register int regnum; register int regmask; register CORE_ADDR next_addr; register CORE_ADDR pc; int nextinsn; bzero (&*saved_regs_addr, sizeof *saved_regs_addr); if ((frame_info_addr)->pc >= ((frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4) && (frame_info_addr)->pc <= (frame_info_addr)->frame) { next_addr = (frame_info_addr)->frame; pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; } else { pc = get_pc_function_start ((frame_info_addr)->pc); /* Verify we have a link a6 instruction next; if not we lose. If we win, find the address above the saved regs using the amount of storage from the link instruction. */ if (044016 == read_memory_integer (pc, 2)) { next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4); pc += 4; } else if (047126 == read_memory_integer (pc, 2)) { next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2); pc+=2; } else goto lose; /* If have an addal #-n, sp next, adjust next_addr. */ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) { next_addr += read_memory_integer (pc += 2, 4); pc += 4; } } /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ regmask = read_memory_integer (pc + 2, 2); /* But before that can come an fmovem. Check for it. */ nextinsn = 0xffff & read_memory_integer (pc, 2); if (0xf227 == nextinsn && (regmask & 0xff00) == 0xe000) { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) if (regmask & 1) (*saved_regs_addr).regs[regnum] = (next_addr -= 12); regmask = read_memory_integer (pc + 2, 2); } if (0044327 == read_memory_integer (pc, 2)) { pc += 4; /* Regmask's low bit is for register 0, the first written */ for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) if (regmask & 1) (*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4; } else if (0044347 == read_memory_integer (pc, 2)) { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) if (regmask & 1) (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } /* fmovemx to index of sp may follow. */ regmask = read_memory_integer (pc + 2, 2); nextinsn = 0xffff & read_memory_integer (pc, 2); if (0xf236 == nextinsn && (regmask & 0xff00) == 0xf000) { pc += 10; /* Regmask's low bit is for register fp0, the first written */ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) if (regmask & 1) (*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12; regmask = read_memory_integer (pc + 2, 2); } /* clrw -(sp); movw ccr,-(sp) may follow. */ if (0x426742e7 == read_memory_integer (pc, 4)) (*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4); lose: ; (*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8; (*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame; (*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4; } #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; fi = get_frame_info (frame); /* -- bug -- ** when gdb is first run frame is not initialized ** and is NULL. Dereferencing it is a no-no and causes core ** -- fix -- (hack) ** check fi here and if NULL return zero ** because that is what block_for_pc returns on failure */ if (fi == (struct frame_info *)0) return(0); return block_for_pc (fi->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 = block_for_pc (pc); register struct symbol *symbol; if (bl == 0 || (symbol = block_function (bl)) == 0) { register int misc_index = find_pc_misc_function (pc); if (misc_index >= 0) return misc_function_vector[misc_index].address; return 0; } bl = SYMBOL_BLOCK_VALUE (symbol); return BLOCK_START (bl); } /* 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 innermost lexical block containing the specified pc value, or 0 if there is none. */ extern struct symtab *psymtab_to_symtab (); struct block * block_for_pc (pc) register CORE_ADDR pc; { register struct block *b; register int bot, top, half; register struct symtab *s; register struct partial_symtab *ps; struct blockvector *bl; /* First search all symtabs for one whose file contains our pc */ for (s = symtab_list; s; s = s->next) { bl = BLOCKVECTOR (s); b = BLOCKVECTOR_BLOCK (bl, 0); if (BLOCK_START (b) <= pc && BLOCK_END (b) > pc) break; } if (s == 0) for (ps = partial_symtab_list; ps; ps = ps->next) { if (ps->textlow <= pc && ps->texthigh > pc) { s = psymtab_to_symtab (ps); bl = BLOCKVECTOR (s); b = BLOCKVECTOR_BLOCK (bl, 0); break; } } if (s == 0) return 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) return b; bot--; } 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); } /* Find the misc function whose address is the largest while being less than PC. Return its index in misc_function_vector. Returns -1 if PC is not in suitable range. */ int find_pc_misc_function (pc) register CORE_ADDR pc; { register int lo = 0; register int hi = misc_function_count-1; register int new; register int distance; /* Note that the last thing in the vector is always _etext. */ /* Above statement is not *always* true - fix for case where there are */ /* no misc functions at all (ie no symbol table has been read). */ if (hi < 0) return -1; /* no misc functions recorded */ /* trivial reject range test */ if (pc < misc_function_vector[0].address || pc > misc_function_vector[hi].address) return -1; do { new = (lo + hi) >> 1; distance = misc_function_vector[new].address - pc; if (distance == 0) return new; /* an exact match */ else if (distance > 0) hi = new; else lo = new; } while (hi-lo != 1); /* if here, we had no exact match, so return the lower choice */ return lo; } /* Return the innermost stack frame executing inside of the specified block, or zero if there is no such frame. */ FRAME block_innermost_frame (block) struct block *block; { struct frame_info *fi; register FRAME frame; register CORE_ADDR start = BLOCK_START (block); register CORE_ADDR 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; } } void _initialize_blockframe () { obstack_init (&frame_cache_obstack); } SHAR_EOF fi # end of overwriting check if test -f 'inflow.c' then echo shar: will not over-write existing file "'inflow.c'" else cat << \SHAR_EOF > 'inflow.c' /* Low level interface to ptrace, for GDB when running under Unix. Copyright (C) 1986, 1987 Free Software Foundation, Inc. GDB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the GDB General Public License for full details. Everyone is granted permission to copy, modify and redistribute GDB, but only under the conditions described in the GDB General Public License. A copy of this license is supposed to have been given to you along with GDB so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. In other words, go ahead and share GDB, but don't try to stop anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" #include "param.h" #include "frame.h" #include "inferior.h" #ifdef USG #include #include #endif #include #include #include #include /* May be unnecessary since many parts of inflow.c have migrated to *-infdep.c */ #ifdef USG #include #endif #ifdef HAVE_TERMIO #include #undef TIOCGETP #define TIOCGETP TCGETA #undef TIOCSETN #define TIOCSETN TCSETA #undef TIOCSETP #define TIOCSETP TCSETAF #define TERMINAL struct termio #else #include #include #include #define TERMINAL struct sgttyb #endif #ifdef SET_STACK_LIMIT_HUGE #include #include extern int original_stack_limit; #endif /* SET_STACK_LIMIT_HUGE */ extern int errno; /* 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 TERMINAL sg_inferior; static TERMINAL sg_ours; static int tflags_inferior; static int tflags_ours; #ifdef TIOCGLTC static struct tchars tc_inferior; static struct tchars tc_ours; static struct ltchars ltc_inferior; static struct ltchars ltc_ours; static int lmode_inferior; static int lmode_ours; #endif /* TIOCGLTC */ #ifdef TIOCGPGRP static int pgrp_inferior; static int pgrp_ours; #else static int (*sigint_ours) (); static int (*sigquit_ours) (); #endif /* TIOCGPGRP */ /* Copy of inferior_io_terminal when inferior was last started. */ static char *inferior_thisrun_terminal; static void terminal_ours_1 (); /* Nonzero if our terminal settings are in effect. Zero if the inferior's settings are in effect. */ static int terminal_is_ours; /* Initialize the terminal settings we record for the inferior, before we actually run the inferior. */ void terminal_init_inferior () { if (remote_debugging) return; sg_inferior = sg_ours; tflags_inferior = tflags_ours; #ifdef TIOCGLTC tc_inferior = tc_ours; ltc_inferior = ltc_ours; lmode_inferior = lmode_ours; #endif /* TIOCGLTC */ #ifdef TIOCGPGRP pgrp_inferior = inferior_pid; #endif /* TIOCGPGRP */ 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 (remote_debugging) return; if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ { fcntl (0, F_SETFL, tflags_inferior); fcntl (0, F_SETFL, tflags_inferior); ioctl (0, TIOCSETN, &sg_inferior); #ifdef TIOCGLTC ioctl (0, TIOCSETC, &tc_inferior); ioctl (0, TIOCSLTC, <c_inferior); ioctl (0, TIOCLSET, &lmode_inferior); #endif /* TIOCGLTC */ #ifdef TIOCGPGRP ioctl (0, TIOCSPGRP, &pgrp_inferior); #else sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN); sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN); #endif /* TIOCGPGRP */ } 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 () { if (remote_debugging) return; 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 () { if (remote_debugging) return; terminal_ours_1 (0); } static void terminal_ours_1 (output_only) int output_only; { #ifdef TIOCGPGRP /* Ignore this signal since it will happen when we try to set the pgrp. */ /* was int (*osigttou) (); ** but signal wants a pointer to a function returning void */ void (*osigttou) (); #endif /* TIOCGPGRP */ if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ { terminal_is_ours = 1; #ifdef TIOCGPGRP osigttou = signal (SIGTTOU, SIG_IGN); ioctl (0, TIOCGPGRP, &pgrp_inferior); ioctl (0, TIOCSPGRP, &pgrp_ours); signal (SIGTTOU, osigttou); #else signal (SIGINT, sigint_ours); signal (SIGQUIT, sigquit_ours); #endif /* TIOCGPGRP */ tflags_inferior = fcntl (0, F_GETFL, 0); ioctl (0, TIOCGETP, &sg_inferior); #ifdef TIOCGLTC ioctl (0, TIOCGETC, &tc_inferior); ioctl (0, TIOCGLTC, <c_inferior); ioctl (0, TIOCLGET, &lmode_inferior); #endif /* TIOCGLTC */ } #ifdef HAVE_TERMIO sg_ours.c_lflag |= ICANON; if (output_only && !(sg_inferior.c_lflag & ICANON)) sg_ours.c_lflag &= ~ICANON; #else /* not HAVE_TERMIO */ sg_ours.sg_flags &= ~RAW & ~CBREAK; if (output_only) sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags; #endif /* not HAVE_TERMIO */ fcntl (0, F_SETFL, tflags_ours); fcntl (0, F_SETFL, tflags_ours); ioctl (0, TIOCSETN, &sg_ours); #ifdef TIOCGLTC ioctl (0, TIOCSETC, &tc_ours); ioctl (0, TIOCSLTC, <c_ours); ioctl (0, TIOCLSET, &lmode_ours); #endif /* TIOCGLTC */ #ifdef HAVE_TERMIO sg_ours.c_lflag |= ICANON; #else /* not HAVE_TERMIO */ sg_ours.sg_flags &= ~RAW & ~CBREAK; #endif /* not HAVE_TERMIO */ } static void term_status_command () { register int i; if (remote_debugging) { printf ("No terminal status when remote debugging.\n"); return; } printf ("Inferior's terminal status (currently saved by GDB):\n"); #ifdef HAVE_TERMIO printf ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n", tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag); printf ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line); printf ("c_cc: "); for (i = 0; (i < NCC); i += 1) printf ("0x%x ", sg_inferior.c_cc[i]); printf ("\n"); #else /* not HAVE_TERMIO */ printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n", tflags_inferior, lmode_inferior, sg_inferior.sg_flags, pgrp_inferior); printf ("tchars: "); for (i = 0; i < sizeof (struct tchars); i++) printf ("0x%x ", ((char *)&tc_inferior)[i]); printf ("\n"); printf ("ltchars: "); for (i = 0; i < sizeof (struct ltchars); i++) printf ("0x%x ", ((char *)<c_inferior)[i]); printf ("\n"); #endif /* not HAVE_TERMIO */ } static void new_tty (ttyname) char *ttyname; { register int tty; register int fd; #ifdef TIOCNOTTY /* Disconnect the child process from our controlling terminal. */ tty = open("/dev/tty", O_RDWR); if (tty > 0) { ioctl(tty, TIOCNOTTY, 0); close(tty); } #endif /* Now open the specified new terminal. */ tty = open(ttyname, O_RDWR); if (tty == -1) _exit(1); dup2(tty, 0); dup2(tty, 1); dup2(tty, 2); close(tty); } /* Start an inferior process and returns its pid. ALLARGS is a string containing shell command to run the program. ENV is the environment vector to pass. */ #ifndef SHELL_FILE #define SHELL_FILE "/bin/sh" #endif int create_inferior (allargs, env) char *allargs; char **env; { int pid; char *shell_command; extern int sys_nerr; extern char *sys_errlist[]; extern int errno; /* 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) + strlen (allargs) + 1); strcpy (shell_command, SHELL_COMMAND_CONCAT); strcat (shell_command, allargs); #else shell_command = allargs; #endif /* exec is said to fail if the executable is open. */ close_exec_file (); pid = vfork (); if (pid < 0) perror_with_name ("vfork"); if (pid == 0) { #ifdef TIOCGPGRP /* Run inferior in a separate process group. */ setpgrp (getpid (), getpid ()); #endif /* TIOCGPGRP */ #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 */ inferior_thisrun_terminal = inferior_io_terminal; if (inferior_io_terminal != 0) new_tty (inferior_io_terminal); /* Not needed on Sun, at least, and loses there because it clobbers the superior. */ /*??? signal (SIGQUIT, SIG_DFL); signal (SIGINT, SIG_DFL); */ call_ptrace (0); execle (SHELL_FILE, "sh", "-c", shell_command, 0, env); fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE, errno < sys_nerr ? sys_errlist[errno] : "unknown error"); fflush (stderr); _exit (0177); } return pid; } /* Kill the inferior process. Make us have no inferior. */ static void kill_command () { if (remote_debugging) return; if (inferior_pid == 0) error ("The program is not being run."); if (!query ("Kill the inferior process? ")) error ("Not confirmed."); kill_inferior (); } void inferior_died () { inferior_pid = 0; attach_flag = 0; mark_breakpoints_out (); reopen_exec_file (); if (have_core_file_p ()) set_current_frame ( create_new_frame (read_register (FP_REGNUM), read_pc ())); } static void try_writing_regs_command () { register int i; register int value; extern int errno; if (inferior_pid == 0) error ("There is no inferior process now."); for (i = 0; ; i += 2) { QUIT; errno = 0; value = call_ptrace (3, inferior_pid, i, 0); call_ptrace (6, inferior_pid, i, value); if (errno == 0) { printf (" Succeeded with address 0x%x; value 0x%x (%d).\n", i, value, value); } else if ((i & 0377) == 0) printf (" Failed at 0x%x.\n", i); } } void _initialize_inflow () { add_com ("term-status", class_obscure, term_status_command, "Print info on inferior's saved terminal status."); add_com ("try-writing-regs", class_obscure, try_writing_regs_command, "Try writing all locations in inferior's system block.\n\ Report which ones can be written."); add_com ("kill", class_run, kill_command, "Kill execution of program being debugged."); inferior_pid = 0; ioctl (0, TIOCGETP, &sg_ours); fcntl (0, F_GETFL, tflags_ours); #ifdef TIOCGLTC ioctl (0, TIOCGETC, &tc_ours); ioctl (0, TIOCGLTC, <c_ours); ioctl (0, TIOCLGET, &lmode_ours); #endif /* TIOCGLTC */ #ifdef TIOCGPGRP ioctl (0, TIOCGPGRP, &pgrp_ours); #endif /* TIOCGPGRP */ terminal_is_ours = 1; } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0 -- Kevin Boyes kevinb@sparkles.dcss.McMaster.CA McMaster University ...!uunet!utai!utgpu!sparkles!kevinb