Thread View: gnu.gdb.bug
1 messages
1 total messages
Started by Kevin Boyes
Mon, 26 Jun 1989 13:52
(none)
Author: Kevin Boyes
Date: Mon, 26 Jun 1989 13:52
Date: Mon, 26 Jun 1989 13:52
1222 lines
35889 bytes
35889 bytes
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 <sys/types.h>
#include <sys/fcntl.h>
#endif
#include <stdio.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
/* May be unnecessary since many parts of inflow.c
have migrated to *-infdep.c */
#ifdef USG
#include <sys/user.h>
#endif
#ifdef HAVE_TERMIO
#include <termio.h>
#undef TIOCGETP
#define TIOCGETP TCGETA
#undef TIOCSETN
#define TIOCSETN TCSETA
#undef TIOCSETP
#define TIOCSETP TCSETAF
#define TERMINAL struct termio
#else
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sgtty.h>
#define TERMINAL struct sgttyb
#endif
#ifdef SET_STACK_LIMIT_HUGE
#include <sys/time.h>
#include <sys/resource.h>
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
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads