mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-22 02:21:19 +00:00
import gdb-2000-01-31 snapshot
This commit is contained in:
parent
557537a556
commit
da59e08184
108
gdb/ChangeLog
108
gdb/ChangeLog
@ -1,3 +1,111 @@
|
||||
2000-01-31 Jason Molenda (jsm@bugshack.cygnus.com)
|
||||
|
||||
* config/alpha/alpha-osf2.mh, config/alpha/alpha-osf3.mh,
|
||||
config/i386/i386dgux.mh, config/i386/i386sol2.mh,
|
||||
config/i386/i386v4.mh, config/i386/i386v42mp.mh,
|
||||
config/i386/ncr3000.mh, config/m68k/m68kv4.mh,
|
||||
config/m88k/delta88v4.mh, config/mips/irix4.mh,
|
||||
config/mips/irix5.mh, config/mips/mipsv4.mh,
|
||||
config/powerpc/solaris.mh (NATDEPFILES): Change references to
|
||||
proc_api.o, proc_events.o, proc_flags.o, and proc_why.o to
|
||||
proc-api.o, proc-events.o, proc-flags.o, and proc-why.o.
|
||||
|
||||
Mon Jan 31 17:14:52 2000 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* top.c (fputs_unfiltered_hook): Moved to tui/tui-file.c.
|
||||
|
||||
* main.c (captured_main): Only use the legacy tui_file code when
|
||||
linking in older code such as the TUI.
|
||||
|
||||
* gdb-file.h, gdb-file.c: New files.
|
||||
* utils.c, defs.h (struct gdb_file, gdb_file_new, gdb_file_delete,
|
||||
null_file_isatty, null_file_rewind, null_file_put,
|
||||
null_file_flush, null_file_write, null_file_fputs,
|
||||
null_file_delete, gdb_file_data, gdb_flush, gdb_file_isatty,
|
||||
gdb_file_rewind, gdb_file_put, gdb_file_write, fputs_unfiltered,
|
||||
set_gdb_file_flush, set_gdb_file_isatty, set_gdb_file_rewind,
|
||||
set_gdb_file_put, set_gdb_file_write, set_gdb_file_fputs,
|
||||
set_gdb_file_data, struct accumulated_gdb_file,
|
||||
do_gdb_file_xstrdup, gdb_file_xstrdup, struct mem_file):
|
||||
mem_file_new, mem_file_delete, mem_fileopen, mem_file_rewind,
|
||||
mem_file_put, mem_file_write, struct stdio_file): stdio_file_new,
|
||||
stdio_file_delete, stdio_file_flush, stdio_file_write,
|
||||
stdio_file_fputs, stdio_file_isatty, stdio_fileopen, gdb_fopen):
|
||||
Moved to gdb-file.h and gdb-file.c.
|
||||
* utils.c (enum streamtype, struct tui_stream, tui_file_new,
|
||||
tui_file_delete, tui_fileopen, tui_sfileopen, tui_file_isatty,
|
||||
tui_file_rewind, tui_file_put, tui_file_fputs,
|
||||
tui_file_get_strbuf, tui_file_adjust_strbuf, tui_file_flush,
|
||||
fputs_unfiltered_hook):
|
||||
Moved to tui/tui-file.c and tui/tui-file.h.
|
||||
|
||||
* Makefile.in (COMMON_OBS): Add gdb-file.o, tui-file.o.
|
||||
(tui-file.o, gdb-file.o): Add dependencies.
|
||||
(corefile.o, main.o, utils.o, simmisc.o): Update dependencies.
|
||||
* main.c: #include tui/tui-file.h.
|
||||
|
||||
2000-01-28 Fred Fish <fnf@cygnus.com>
|
||||
|
||||
* findvar.c (value_from_register): Special case handling of D10V
|
||||
pointer values fetched from registers.
|
||||
|
||||
2000-01-28 Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* arm-tdep.c (thumb_skip_prologue, thumb_scan_prologue): Add
|
||||
support for new style thumb prologues.
|
||||
|
||||
2000-01-28 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* arm-tdep.c: Remove extraneous dash at start of strings
|
||||
introduced in previous delta.
|
||||
|
||||
2000-01-27 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* arm-tdep.c: Replace uses of arm_toggle_renames() with
|
||||
parse_arm_disassembler_option().
|
||||
|
||||
2000-01-27 Jim Blandy <jimb@cygnus.com>
|
||||
|
||||
* symtab.c (decode_line_1): Don't let commas that are within
|
||||
quotes or parenthesis terminate the line spec. Don't use pp when
|
||||
removing the final double quote of a double-quoted string. Don't
|
||||
forget to skip the opening double quote. I have no clue whether
|
||||
this change is correct; probably we've just moved this function
|
||||
from one buggy place to another buggy place, and never came within
|
||||
an outhouse whiff of correctness.
|
||||
(find_toplevel_char): New function.
|
||||
|
||||
2000-01-27 Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* arm-tdep.c (arm_push_arguments): Set the thumb mode bit when
|
||||
passing the pointer to a thumb function as an argument.
|
||||
|
||||
2000-01-27 Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* remote-rdi.c (arm_rdi_mourn_inferior): Make sure breakpoints
|
||||
are reinserted for another run.
|
||||
|
||||
2000-01-27 Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* infcmd.c (run_stack_dummy): Account for a random signal stopping
|
||||
the inferior as well as breakpoints being hit while performing an
|
||||
inferior function call.
|
||||
* valops.c (hand_function_call): Ditto.
|
||||
|
||||
2000-01-27 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
|
||||
|
||||
From Mark Kettenis <kettenis@gnu.org>
|
||||
|
||||
* config/i386/tm-i386gnu.h (THREAD_STATE_FLAVOR): Define to
|
||||
i386_REGS_SEGS_STATE.
|
||||
(HAVE_I387_REGS): Define.
|
||||
(FLOAT_INFO): Remove.
|
||||
* i386gnu-nat.c: Almost completely rewritten to use new i386
|
||||
register layout and `float info' implementation.
|
||||
* gnu-nat.c (inf_update_procs, proc_get_state, proc_string):
|
||||
Move prototypes from here.
|
||||
* gnu-nat.h: To here.
|
||||
|
||||
2000-01-24 Kevin Buettner <kevinb@redhat.com>
|
||||
|
||||
* utils.c (get_field, put_field): Fix buffer underruns and
|
||||
|
@ -229,7 +229,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \
|
||||
ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
|
||||
ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
|
||||
|
||||
VERSION = 20000126
|
||||
VERSION = 20000131
|
||||
DIST=gdb
|
||||
|
||||
LINT=/usr/5bin/lint
|
||||
@ -402,7 +402,9 @@ SFILES = ax-general.c ax-gdb.c bcache.c blockframe.c breakpoint.c \
|
||||
tui/tuiGeneralWin.h tui/tuiIO.c tui/tuiIO.h tui/tuiLayout.c \
|
||||
tui/tuiLayout.h tui/tuiRegs.c tui/tuiRegs.h tui/tuiSource.c \
|
||||
tui/tuiSource.h tui/tuiSourceWin.c tui/tuiSourceWin.h \
|
||||
tui/tuiStack.c tui/tuiStack.h tui/tuiWin.c tui/tuiWin.h
|
||||
tui/tuiStack.c tui/tuiStack.h tui/tuiWin.c tui/tuiWin.h \
|
||||
tui/tui-file.h tui/tui-file.c \
|
||||
gdb-file.h gdb-file.c
|
||||
|
||||
LINTFILES = $(SFILES) $(YYFILES) @CONFIG_SRCS@ init.c
|
||||
|
||||
@ -451,7 +453,7 @@ command_h = command.h
|
||||
gdbcmd_h = gdbcmd.h $(command_h)
|
||||
|
||||
call_cmds_h = call-cmds.h
|
||||
defs_h = defs.h xm.h tm.h nm.h config.status config.h gdbarch.h
|
||||
defs_h = defs.h xm.h tm.h nm.h config.status config.h gdbarch.h gdb-file.h
|
||||
|
||||
top_h = top.h
|
||||
inferior_h = inferior.h $(breakpoint_h)
|
||||
@ -532,7 +534,8 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o stack.o thread.o \
|
||||
scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \
|
||||
c-typeprint.o ch-typeprint.o f-typeprint.o m2-typeprint.o \
|
||||
c-valprint.o cp-valprint.o ch-valprint.o f-valprint.o m2-valprint.o \
|
||||
nlmread.o serial.o mdebugread.o os9kread.o top.o utils.o
|
||||
nlmread.o serial.o mdebugread.o os9kread.o top.o utils.o \
|
||||
gdb-file.o tui-file.o
|
||||
|
||||
OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
|
||||
|
||||
@ -1300,7 +1303,7 @@ m88k-tdep.o: m88k-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h)
|
||||
|
||||
mac-nat.o: mac-nat.c $(defs_h) gdb_string.h
|
||||
|
||||
main.o: main.c top.h $(defs_h) gdb_string.h $(event_loop_h)
|
||||
main.o: main.c top.h $(defs_h) gdb_string.h $(event_loop_h) tui/tui-file.h
|
||||
|
||||
maint.o: maint.c $(defs_h) $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) language.h \
|
||||
$(expression_h) objfiles.h symfile.h
|
||||
@ -1602,6 +1605,10 @@ stabsread.o: stabsread.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \
|
||||
stack.o: stack.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \
|
||||
language.h target.h gdb_string.h
|
||||
|
||||
gdb-file.o: gdb-file.c $(defs_h) gdb-file.h
|
||||
tui-file.o: $(srcdir)/tui/tui-file.c $(defs_h) $(srcdir)/tui/tui-file.h
|
||||
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/tui/tui-file.c
|
||||
|
||||
ax-general.o: ax-general.c $(ax_h) $(defs_h) $(value_h)
|
||||
ax-gdb.o: ax-gdb.c $(defs_h) $(symtab_h) symfile.h $(gdbtypes_h) \
|
||||
$(value_h) $(expression_h) $(command_h) $(ax_h) $(gdbcmd_h) ax-gdb.h
|
||||
|
153
gdb/arm-tdep.c
153
gdb/arm-tdep.c
@ -1,5 +1,5 @@
|
||||
/* Common target dependent code for GDB on ARM systems.
|
||||
Copyright 1988, 1989, 1991, 1992, 1993, 1995-1999
|
||||
Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -45,33 +45,33 @@ extern void _initialize_arm_tdep (void);
|
||||
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
|
||||
|
||||
/* Default register names as specified by APCS. */
|
||||
static char *apcs_register_names[] =
|
||||
static char * atpcs_register_names[] =
|
||||
{"a1", "a2", "a3", "a4", /* 0 1 2 3 */
|
||||
"v1", "v2", "v3", "v4", /* 4 5 6 7 */
|
||||
"v5", "v6", "sl", "fp", /* 8 9 10 11 */
|
||||
"ip", "sp", "lr", "pc", /* 12 13 14 15 */
|
||||
"v5", "v6", "v7", "v8", /* 8 9 10 11 */
|
||||
"IP", "SP", "LR", "PC", /* 12 13 14 15 */
|
||||
"f0", "f1", "f2", "f3", /* 16 17 18 19 */
|
||||
"f4", "f5", "f6", "f7", /* 20 21 22 23 */
|
||||
"fps", "ps"} /* 24 25 */ ;
|
||||
"FPS", "PS" }; /* 24 25 */
|
||||
|
||||
/* Alternate set of registers names used by GCC. */
|
||||
static char *additional_register_names[] =
|
||||
{"r0", "r1", "r2", "r3", /* 0 1 2 3 */
|
||||
"r4", "r5", "r6", "r7", /* 4 5 6 7 */
|
||||
"r8", "r9", "r10", "r11", /* 8 9 10 11 */
|
||||
"r12", "r13", "r14", "pc", /* 12 13 14 15 */
|
||||
"f0", "f1", "f2", "f3", /* 16 17 18 19 */
|
||||
"f4", "f5", "f6", "f7", /* 20 21 22 23 */
|
||||
"fps", "ps"} /* 24 25 */ ;
|
||||
static char * additional_register_names[] =
|
||||
{"r0", "r1", "r2", "r3", /* 0 1 2 3 */
|
||||
"r4", "r5", "r6", "r7", /* 4 5 6 7 */
|
||||
"r8", "r9", "r10", "r11", /* 8 9 10 11 */
|
||||
"r12", "sp", "lr", "pc", /* 12 13 14 15 */
|
||||
"f0", "f1", "f2", "f3", /* 16 17 18 19 */
|
||||
"f4", "f5", "f6", "f7", /* 20 21 22 23 */
|
||||
"fps", "ps" }; /* 24 25 */
|
||||
|
||||
/* This is the variable that is set with "set disassembly-flavor".
|
||||
By default use the APCS registers names. */
|
||||
char **arm_register_names = apcs_register_names;
|
||||
char ** arm_register_names = atpcs_register_names;
|
||||
|
||||
/* Valid register name flavours. */
|
||||
static char apcs_flavor[] = "apcs";
|
||||
static char r_prefix_flavor[] = "r-prefix";
|
||||
static char *valid_flavors[] =
|
||||
static char * valid_flavors[] =
|
||||
{
|
||||
apcs_flavor,
|
||||
r_prefix_flavor,
|
||||
@ -296,24 +296,65 @@ arm_frameless_function_invocation (struct frame_info *fi)
|
||||
add sp, sp, #-28
|
||||
add r7, sp, #12
|
||||
Sometimes the latter instruction may be replaced by:
|
||||
mov r7, sp
|
||||
mov r7, sp
|
||||
|
||||
or like this:
|
||||
push {r7, lr}
|
||||
mov r7, sp
|
||||
sub sp, #12
|
||||
|
||||
or, on tpcs, like this:
|
||||
sub sp,#16
|
||||
push {r7, lr}
|
||||
(many instructions)
|
||||
mov r7, sp
|
||||
sub sp, #12
|
||||
|
||||
There is always one instruction of three classes:
|
||||
1 - push
|
||||
2 - setting of r7
|
||||
3 - adjusting of sp
|
||||
|
||||
When we have found at least one of each class we are done with the prolog.
|
||||
Note that the "sub sp, #NN" before the push does not count.
|
||||
*/
|
||||
|
||||
static CORE_ADDR
|
||||
thumb_skip_prologue (CORE_ADDR pc)
|
||||
{
|
||||
CORE_ADDR current_pc;
|
||||
int findmask = 0; /* findmask:
|
||||
bit 0 - push { rlist }
|
||||
bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7)
|
||||
bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp)
|
||||
*/
|
||||
|
||||
for (current_pc = pc; current_pc < pc + 20; current_pc += 2)
|
||||
for (current_pc = pc; current_pc < pc + 40; current_pc += 2)
|
||||
{
|
||||
unsigned short insn = read_memory_unsigned_integer (current_pc, 2);
|
||||
|
||||
if ((insn & 0xfe00) != 0xb400 /* push {..., r7, lr} */
|
||||
&& (insn & 0xff00) != 0xb000 /* add sp, #simm */
|
||||
&& (insn & 0xff00) != 0xaf00 /* add r7, sp, #imm */
|
||||
&& insn != 0x466f /* mov r7, sp */
|
||||
&& (insn & 0xffc0) != 0x4640) /* mov r0-r7, r8-r15 */
|
||||
break;
|
||||
if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
|
||||
{
|
||||
findmask |= 1; /* push found */
|
||||
}
|
||||
else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */
|
||||
{
|
||||
if ((findmask & 1) == 0) /* before push ? */
|
||||
continue;
|
||||
else
|
||||
findmask |= 4; /* add/sub sp found */
|
||||
}
|
||||
else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
|
||||
{
|
||||
findmask |= 2; /* setting of r7 found */
|
||||
}
|
||||
else if (insn == 0x466f) /* mov r7, sp */
|
||||
{
|
||||
findmask |= 2; /* setting of r7 found */
|
||||
}
|
||||
else
|
||||
continue; /* something in the prolog that we don't care about or some
|
||||
instruction from outside the prolog scheduled here for optimization */
|
||||
}
|
||||
|
||||
return current_pc;
|
||||
@ -408,18 +449,18 @@ arm_skip_prologue (CORE_ADDR pc)
|
||||
4) the offset from the stack pointer to the frame pointer
|
||||
This information is stored in the "extra" fields of the frame_info.
|
||||
|
||||
A typical Thumb function prologue might look like this:
|
||||
push {r7, lr}
|
||||
sub sp, #28,
|
||||
add r7, sp, #12
|
||||
Which would create this stack frame (offsets relative to FP)
|
||||
A typical Thumb function prologue would create this stack frame
|
||||
(offsets relative to FP)
|
||||
old SP -> 24 stack parameters
|
||||
20 LR
|
||||
16 R7
|
||||
R7 -> 0 local variables (16 bytes)
|
||||
SP -> -12 additional stack space (12 bytes)
|
||||
The frame size would thus be 36 bytes, and the frame offset would be
|
||||
12 bytes. The frame register is R7. */
|
||||
12 bytes. The frame register is R7.
|
||||
|
||||
The comments for thumb_skip_prolog() describe the algorithm we use to detect
|
||||
the end of the prolog */
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static void
|
||||
@ -429,6 +470,11 @@ thumb_scan_prologue (struct frame_info *fi)
|
||||
CORE_ADDR prologue_end;
|
||||
CORE_ADDR current_pc;
|
||||
int saved_reg[16]; /* which register has been copied to register n? */
|
||||
int findmask = 0; /* findmask:
|
||||
bit 0 - push { rlist }
|
||||
bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7)
|
||||
bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp)
|
||||
*/
|
||||
int i;
|
||||
|
||||
if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end))
|
||||
@ -452,10 +498,13 @@ thumb_scan_prologue (struct frame_info *fi)
|
||||
saved_reg[i] = i;
|
||||
|
||||
/* Search the prologue looking for instructions that set up the
|
||||
frame pointer, adjust the stack pointer, and save registers. */
|
||||
frame pointer, adjust the stack pointer, and save registers.
|
||||
Do this until all basic prolog instructions are found. */
|
||||
|
||||
fi->framesize = 0;
|
||||
for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 2)
|
||||
for (current_pc = prologue_start;
|
||||
(current_pc < prologue_end) && ((findmask & 7) != 7);
|
||||
current_pc += 2)
|
||||
{
|
||||
unsigned short insn;
|
||||
int regno;
|
||||
@ -465,9 +514,11 @@ thumb_scan_prologue (struct frame_info *fi)
|
||||
|
||||
if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
|
||||
{
|
||||
int mask;
|
||||
findmask |= 1; /* push found */
|
||||
/* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
|
||||
whether to save LR (R14). */
|
||||
int mask = (insn & 0xff) | ((insn & 0x100) << 6);
|
||||
mask = (insn & 0xff) | ((insn & 0x100) << 6);
|
||||
|
||||
/* Calculate offsets of saved R0-R7 and LR. */
|
||||
for (regno = LR_REGNUM; regno >= 0; regno--)
|
||||
@ -478,20 +529,30 @@ thumb_scan_prologue (struct frame_info *fi)
|
||||
saved_reg[regno] = regno; /* reset saved register map */
|
||||
}
|
||||
}
|
||||
else if ((insn & 0xff00) == 0xb000) /* add sp, #simm */
|
||||
else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */
|
||||
{
|
||||
if ((findmask & 1) == 0) /* before push ? */
|
||||
continue;
|
||||
else
|
||||
findmask |= 4; /* add/sub sp found */
|
||||
|
||||
offset = (insn & 0x7f) << 2; /* get scaled offset */
|
||||
if (insn & 0x80) /* is it signed? */
|
||||
offset = -offset;
|
||||
if (insn & 0x80) /* is it signed? (==subtracting) */
|
||||
{
|
||||
fi->frameoffset += offset;
|
||||
offset = -offset;
|
||||
}
|
||||
fi->framesize -= offset;
|
||||
}
|
||||
else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
|
||||
{
|
||||
findmask |= 2; /* setting of r7 found */
|
||||
fi->framereg = THUMB_FP_REGNUM;
|
||||
fi->frameoffset = (insn & 0xff) << 2; /* get scaled offset */
|
||||
}
|
||||
else if (insn == 0x466f) /* mov r7, sp */
|
||||
else if (insn == 0x466f) /* mov r7, sp */
|
||||
{
|
||||
findmask |= 2; /* setting of r7 found */
|
||||
fi->framereg = THUMB_FP_REGNUM;
|
||||
fi->frameoffset = 0;
|
||||
saved_reg[THUMB_FP_REGNUM] = SP_REGNUM;
|
||||
@ -503,7 +564,8 @@ thumb_scan_prologue (struct frame_info *fi)
|
||||
saved_reg[lo_reg] = hi_reg; /* remember hi reg was saved */
|
||||
}
|
||||
else
|
||||
break; /* anything else isn't prologue */
|
||||
continue; /* something in the prolog that we don't care about or some
|
||||
instruction from outside the prolog scheduled here for optimization */
|
||||
}
|
||||
}
|
||||
|
||||
@ -1170,7 +1232,10 @@ arm_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp,
|
||||
val = (char *) &dbl_arg;
|
||||
len = sizeof (double);
|
||||
}
|
||||
#if 0
|
||||
#if 1
|
||||
/* I don't know why this code was disable. The only logical use
|
||||
for a function pointer is to call that function, so setting
|
||||
the mode bit is perfectly fine. FN */
|
||||
/* If the argument is a pointer to a function, and it is a Thumb
|
||||
function, set the low bit of the pointer. */
|
||||
if (TYPE_CODE_PTR == typecode
|
||||
@ -1278,14 +1343,12 @@ set_disassembly_flavor (void)
|
||||
{
|
||||
if (disassembly_flavor == apcs_flavor)
|
||||
{
|
||||
if (arm_toggle_regnames () == 0)
|
||||
arm_toggle_regnames ();
|
||||
arm_register_names = apcs_register_names;
|
||||
parse_arm_disassembler_option ("reg-names-atpcs");
|
||||
arm_register_names = atpcs_register_names;
|
||||
}
|
||||
else if (disassembly_flavor == r_prefix_flavor)
|
||||
{
|
||||
if (arm_toggle_regnames () == 1)
|
||||
arm_toggle_regnames ();
|
||||
parse_arm_disassembler_option ("reg-names-std");
|
||||
arm_register_names = additional_register_names;
|
||||
}
|
||||
}
|
||||
@ -1917,9 +1980,7 @@ _initialize_arm_tdep (void)
|
||||
tm_print_insn = gdb_print_insn_arm;
|
||||
|
||||
/* Sync the opcode insn printer with our register viewer: */
|
||||
|
||||
if (arm_toggle_regnames () != 1)
|
||||
arm_toggle_regnames ();
|
||||
parse_arm_disassembler_option ("reg-names-atpcs");
|
||||
|
||||
/* Add the deprecated "othernames" command */
|
||||
|
||||
|
@ -3,4 +3,4 @@ XDEPFILES=
|
||||
XM_FILE= xm-alphaosf.h
|
||||
NAT_FILE= nm-osf2.h
|
||||
NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
|
||||
osfsolib.o procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
osfsolib.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -3,5 +3,5 @@ XDEPFILES=
|
||||
XM_FILE= xm-alphaosf.h
|
||||
NAT_FILE= nm-osf3.h
|
||||
NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
|
||||
osfsolib.o procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
osfsolib.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
||||
|
@ -7,4 +7,4 @@ XM_CLIBS= -lsocket -lnsl
|
||||
|
||||
NAT_FILE= nm-i386v4.h
|
||||
NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o i386v4-nat.o \
|
||||
procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -5,4 +5,4 @@ XDEPFILES=
|
||||
|
||||
NAT_FILE= nm-i386sol2.h
|
||||
NATDEPFILES= core-regset.o fork-child.o i386v4-nat.o corelow.o procfs.o \
|
||||
proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -7,4 +7,4 @@ XM_CLIBS= -lsocket -lnsl
|
||||
|
||||
NAT_FILE= nm-i386v4.h
|
||||
NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o i386v4-nat.o \
|
||||
procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -9,5 +9,5 @@ XM_CLIBS= -lsocket -lnsl
|
||||
# appropriate for i386v42mp
|
||||
NAT_FILE= nm-i386v42mp.h
|
||||
NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o i386v4-nat.o \
|
||||
procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o uw-thread.o
|
||||
procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o uw-thread.o
|
||||
|
||||
|
@ -14,4 +14,4 @@ XDEPFILES=
|
||||
|
||||
NAT_FILE= nm-i386v4.h
|
||||
NATDEPFILES= corelow.o core-regset.o fork-child.o i386v4-nat.o procfs.o \
|
||||
proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Macro definitions for i386, GNU Hurd
|
||||
/* Macro definitions for i386 running the GNU Hurd.
|
||||
Copyright (C) 1992, 1999 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -21,27 +21,27 @@
|
||||
#ifndef TM_I386GNU_H
|
||||
#define TM_I386GNU_H 1
|
||||
|
||||
/* Include common definitions for gnu systems */
|
||||
/* Include common definitions for GNU systems.
|
||||
FIXME: This does not belong here since this is supposed to contain
|
||||
only native-dependent information. */
|
||||
#include "nm-gnu.h"
|
||||
|
||||
/* Thread flavors used in re-setting the T bit.
|
||||
* @@ this is also bad for cross debugging.
|
||||
*/
|
||||
#define THREAD_STATE_FLAVOR i386_THREAD_STATE
|
||||
FIXME: This is native-dependent. */
|
||||
#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE
|
||||
#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT
|
||||
#define THREAD_STATE_SET_TRACED(state) \
|
||||
((struct i386_thread_state *)state)->efl |= 0x100
|
||||
#define THREAD_STATE_CLEAR_TRACED(state) \
|
||||
((((struct i386_thread_state *)state)->efl &= ~0x100), 1)
|
||||
|
||||
/* we can do it */
|
||||
/* We can attach and detach.
|
||||
FIXME: This is probably native-dependent too. */
|
||||
#define ATTACH_DETACH 1
|
||||
|
||||
#define HAVE_I387_REGS
|
||||
#include "i386/tm-i386.h"
|
||||
|
||||
#undef FLOAT_INFO
|
||||
#define FLOAT_INFO { i386_mach3_float_info (); }
|
||||
|
||||
/* Offset to saved PC in sigcontext. */
|
||||
#define SIGCONTEXT_PC_OFFSET 68
|
||||
|
||||
|
@ -5,4 +5,4 @@ XDEPFILES=
|
||||
|
||||
NAT_FILE= nm-sysv4.h
|
||||
NATDEPFILES= corelow.o core-regset.o solib.o fork-child.o procfs.o \
|
||||
proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -5,4 +5,4 @@ XDEPFILES=
|
||||
|
||||
NAT_FILE= nm-delta88v4.h
|
||||
NATDEPFILES= fork-child.o m88k-nat.o corelow.o core-regset.o solib.o \
|
||||
procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -3,7 +3,7 @@ XDEPFILES= ser-tcp.o
|
||||
XM_FILE= xm-irix4.h
|
||||
NAT_FILE= nm-irix4.h
|
||||
NATDEPFILES= fork-child.o irix4-nat.o corelow.o procfs.o \
|
||||
proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
||||
|
||||
XM_CLIBS=-lbsd -lsun
|
||||
|
@ -3,6 +3,6 @@ XDEPFILES= ser-tcp.o
|
||||
XM_FILE= xm-irix5.h
|
||||
NAT_FILE= nm-irix5.h
|
||||
NATDEPFILES= fork-child.o irix5-nat.o corelow.o procfs.o \
|
||||
proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
||||
XM_CLIBS=-lbsd -lsun
|
||||
|
@ -2,4 +2,4 @@
|
||||
XM_FILE= xm-mipsv4.h
|
||||
NAT_FILE= ../nm-sysv4.h
|
||||
NATDEPFILES= fork-child.o mipsv4-nat.o corelow.o core-regset.o solib.o \
|
||||
procfs.o proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
@ -6,7 +6,7 @@ XM_CLIBS= -lsocket -lnsl
|
||||
|
||||
NAT_FILE= nm-solaris.h
|
||||
NATDEPFILES= corelow.o core-sol2.o solib.o fork-child.o procfs.o \
|
||||
proc_api.o proc_events.o proc_flags.o proc_why.o
|
||||
proc-api.o proc-events.o proc-flags.o proc-why.o
|
||||
|
||||
# If you are compiling with Sun's compiler, add the -xs option to CC
|
||||
# (e.g. `make CC="cc -xs"').
|
||||
|
76
gdb/defs.h
76
gdb/defs.h
@ -386,68 +386,7 @@ extern GDB_FILE *gdb_stdtarg;
|
||||
#include "tuiWin.h"
|
||||
#endif
|
||||
|
||||
/* Create a generic gdb_file object with null methods. */
|
||||
|
||||
extern struct gdb_file *gdb_file_new (void);
|
||||
|
||||
/* Override methods used by specific implementations of a GDB_FILE
|
||||
object. */
|
||||
|
||||
typedef void (gdb_file_flush_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_flush (struct gdb_file *stream, gdb_file_flush_ftype * flush);
|
||||
|
||||
/* NOTE: Both fputs and write methods are available. Default
|
||||
implementations that mapping one onto the other are included. */
|
||||
typedef void (gdb_file_write_ftype) (struct gdb_file * stream, const char *buf, long length_buf);
|
||||
extern void set_gdb_file_write (struct gdb_file *stream, gdb_file_write_ftype *fputs);
|
||||
|
||||
typedef void (gdb_file_fputs_ftype) (const char *, struct gdb_file * stream);
|
||||
extern void set_gdb_file_fputs (struct gdb_file *stream, gdb_file_fputs_ftype * fputs);
|
||||
|
||||
typedef int (gdb_file_isatty_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_isatty (struct gdb_file *stream, gdb_file_isatty_ftype * isatty);
|
||||
|
||||
typedef void (gdb_file_rewind_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_rewind (struct gdb_file *stream, gdb_file_rewind_ftype * rewind);
|
||||
|
||||
typedef void (gdb_file_put_method_ftype) (void *object, const char *buffer, long length_buffer);
|
||||
typedef void (gdb_file_put_ftype) (struct gdb_file *stream, gdb_file_put_method_ftype * method, void *context);
|
||||
extern void set_gdb_file_put (struct gdb_file *stream, gdb_file_put_ftype * put);
|
||||
|
||||
typedef void (gdb_file_delete_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_data (struct gdb_file *stream, void *data, gdb_file_delete_ftype * delete);
|
||||
|
||||
extern void *gdb_file_data (struct gdb_file *file);
|
||||
|
||||
|
||||
/* Open the specified FILE as a gdb_file. */
|
||||
extern struct gdb_file *stdio_fileopen (FILE *file);
|
||||
|
||||
/* Open NAME returning a GDB_FILE. */
|
||||
extern GDB_FILE *gdb_fopen (char *name, char *mode);
|
||||
|
||||
/* Create/open a memory based file. Can be used as a scratch
|
||||
buffer for collecting output. */
|
||||
extern struct gdb_file *mem_fileopen (void);
|
||||
|
||||
extern void gdb_flush (GDB_FILE *);
|
||||
|
||||
extern void gdb_file_delete (struct gdb_file *stream);
|
||||
|
||||
extern void gdb_file_rewind (struct gdb_file *stream);
|
||||
|
||||
extern int gdb_file_isatty (GDB_FILE *);
|
||||
|
||||
extern void gdb_file_write (struct gdb_file *file, const char *buf, long length_buf);
|
||||
|
||||
/* NOTE: copies left to right */
|
||||
extern void gdb_file_put (struct gdb_file *src, gdb_file_put_method_ftype *write, void *dest);
|
||||
|
||||
/* Returns a freshly allocated buffer containing the entire contents
|
||||
of FILE (as determined by gdb_file_put()) with a NUL character
|
||||
appended. LENGTH is set to the size of the buffer minus that
|
||||
appended NUL. */
|
||||
extern char *gdb_file_xstrdup (struct gdb_file *file, long *length);
|
||||
#include "gdb-file.h"
|
||||
|
||||
/* More generic printf like operations */
|
||||
|
||||
@ -487,14 +426,6 @@ extern void fprintf_unfiltered (GDB_FILE *, const char *, ...) ATTR_FORMAT (prin
|
||||
|
||||
extern void printf_unfiltered (const char *, ...) ATTR_FORMAT (printf, 1, 2);
|
||||
|
||||
/* #if defined (TUI) */
|
||||
/* DEPRECATED: Only the TUI should use these methods. */
|
||||
extern struct gdb_file *tui_fileopen (FILE *);
|
||||
extern struct gdb_file *tui_sfileopen (int);
|
||||
extern char *tui_file_get_strbuf (struct gdb_file *);
|
||||
extern void tui_file_adjust_strbuf (int, struct gdb_file *);
|
||||
/* #endif */
|
||||
|
||||
extern void print_spaces (int, GDB_FILE *);
|
||||
|
||||
extern void print_spaces_filtered (int, GDB_FILE *);
|
||||
@ -1199,11 +1130,6 @@ extern void (*show_load_progress) (const char *section,
|
||||
unsigned long section_size,
|
||||
unsigned long total_sent,
|
||||
unsigned long total_size);
|
||||
/* NOTE: cagney/1999-10-14: fputs_unfiltered_hook is deprecated.
|
||||
Instead code wanting to control GDB's output should be overriding
|
||||
the gdb_std* files. */
|
||||
extern void (*fputs_unfiltered_hook) (const char *linebuffer,
|
||||
GDB_FILE * stream);
|
||||
extern void (*print_frame_info_listing_hook) (struct symtab * s,
|
||||
int line, int stopline,
|
||||
int noerror);
|
||||
|
@ -1545,6 +1545,39 @@ A function that inserts or removes (dependant on
|
||||
the next instruction. See @code{sparc-tdep.c} and @code{rs6000-tdep.c}
|
||||
for examples.
|
||||
|
||||
@item SOFUN_ADDRESS_MAYBE_MISSING
|
||||
|
||||
Somebody clever observed that, the more actual addresses you have in the
|
||||
debug information, the more time the linker has to spend relocating
|
||||
them. So whenever there's some other way the debugger could find the
|
||||
address it needs, you should omit it from the debug info, to make
|
||||
linking faster.
|
||||
|
||||
@code{SOFUN_ADDRESS_MAYBE_MISSING} indicates that a particular set of
|
||||
hacks of this sort are in use, affecting @code{N_SO} and @code{N_FUN}
|
||||
entries in stabs-format debugging information. @code{N_SO} stabs mark
|
||||
the beginning and ending addresses of compilation units in the text
|
||||
segment. @code{N_FUN} stabs mark the starts and ends of functions.
|
||||
|
||||
@code{SOFUN_ADDRESS_MAYBE_MISSING} means two things:
|
||||
@itemize @bullet
|
||||
|
||||
@item
|
||||
@code{N_FUN} stabs have an address of zero. Instead, you should find the
|
||||
addresses where the function starts by taking the function name from
|
||||
the stab, and then looking that up in the minsyms (the linker/
|
||||
assembler symbol table). In other words, the stab has the name, and
|
||||
the linker / assembler symbol table is the only place that carries
|
||||
the address.
|
||||
|
||||
@item
|
||||
@code{N_SO} stabs have an address of zero, too. You just look at the
|
||||
@code{N_FUN} stabs that appear before and after the @code{N_SO} stab,
|
||||
and guess the starting and ending addresses of the compilation unit from
|
||||
them.
|
||||
|
||||
@end itemize
|
||||
|
||||
@item PCC_SOL_BROKEN
|
||||
(Used only in the Convex target.)
|
||||
|
||||
|
@ -1454,6 +1454,10 @@ value_from_register (type, regnum, frame)
|
||||
CHECK_TYPEDEF (type);
|
||||
len = TYPE_LENGTH (type);
|
||||
|
||||
/* Pointers on D10V are really only 16 bits, but we lie to gdb elsewhere... */
|
||||
if (GDB_TARGET_IS_D10V && TYPE_CODE (type) == TYPE_CODE_PTR)
|
||||
len = 2;
|
||||
|
||||
VALUE_REGNO (v) = regnum;
|
||||
|
||||
num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
|
||||
@ -1652,6 +1656,29 @@ value_from_register (type, regnum, frame)
|
||||
memcpy (VALUE_CONTENTS_RAW (v), raw_buffer + VALUE_OFFSET (v), len);
|
||||
}
|
||||
|
||||
if (GDB_TARGET_IS_D10V
|
||||
&& TYPE_CODE (type) == TYPE_CODE_PTR
|
||||
&& TYPE_TARGET_TYPE (type)
|
||||
&& (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC))
|
||||
{
|
||||
/* pointer to function */
|
||||
unsigned long num;
|
||||
unsigned short snum;
|
||||
snum = (unsigned short) extract_unsigned_integer (VALUE_CONTENTS_RAW (v), 2);
|
||||
num = D10V_MAKE_IADDR (snum);
|
||||
store_address (VALUE_CONTENTS_RAW (v), 4, num);
|
||||
}
|
||||
else if (GDB_TARGET_IS_D10V
|
||||
&& TYPE_CODE (type) == TYPE_CODE_PTR)
|
||||
{
|
||||
/* pointer to data */
|
||||
unsigned long num;
|
||||
unsigned short snum;
|
||||
snum = (unsigned short) extract_unsigned_integer (VALUE_CONTENTS_RAW (v), 2);
|
||||
num = D10V_MAKE_DADDR (snum);
|
||||
store_address (VALUE_CONTENTS_RAW (v), 4, num);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
511
gdb/gdb-file.c
Normal file
511
gdb/gdb-file.c
Normal file
@ -0,0 +1,511 @@
|
||||
/* GDB_FILE - a generic STDIO like output stream.
|
||||
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Implement the ``struct gdb_file'' object. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb-file.h"
|
||||
|
||||
#undef XMALLOC
|
||||
#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
|
||||
|
||||
static gdb_file_isatty_ftype null_file_isatty;
|
||||
static gdb_file_write_ftype null_file_write;
|
||||
static gdb_file_fputs_ftype null_file_fputs;
|
||||
static gdb_file_flush_ftype null_file_flush;
|
||||
static gdb_file_delete_ftype null_file_delete;
|
||||
static gdb_file_rewind_ftype null_file_rewind;
|
||||
static gdb_file_put_ftype null_file_put;
|
||||
|
||||
struct gdb_file
|
||||
{
|
||||
int *magic;
|
||||
gdb_file_flush_ftype *to_flush;
|
||||
gdb_file_write_ftype *to_write;
|
||||
gdb_file_fputs_ftype *to_fputs;
|
||||
gdb_file_delete_ftype *to_delete;
|
||||
gdb_file_isatty_ftype *to_isatty;
|
||||
gdb_file_rewind_ftype *to_rewind;
|
||||
gdb_file_put_ftype *to_put;
|
||||
void *to_data;
|
||||
};
|
||||
int gdb_file_magic;
|
||||
|
||||
struct gdb_file *
|
||||
gdb_file_new ()
|
||||
{
|
||||
struct gdb_file *file = xmalloc (sizeof (struct gdb_file));
|
||||
file->magic = &gdb_file_magic;
|
||||
set_gdb_file_data (file, NULL, null_file_delete);
|
||||
set_gdb_file_flush (file, null_file_flush);
|
||||
set_gdb_file_write (file, null_file_write);
|
||||
set_gdb_file_fputs (file, null_file_fputs);
|
||||
set_gdb_file_isatty (file, null_file_isatty);
|
||||
set_gdb_file_rewind (file, null_file_rewind);
|
||||
set_gdb_file_put (file, null_file_put);
|
||||
return file;
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_delete (file);
|
||||
free (file);
|
||||
}
|
||||
|
||||
static int
|
||||
null_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_rewind (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_flush (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_write (struct gdb_file *file,
|
||||
const char *buf,
|
||||
long sizeof_buf)
|
||||
{
|
||||
if (file->to_fputs == null_file_fputs)
|
||||
/* Both the write and fputs methods are null. Discard the
|
||||
request. */
|
||||
return;
|
||||
else
|
||||
{
|
||||
/* The fputs method isn't null, slowly pass the write request
|
||||
onto that. FYI, this isn't as bad as it may look - the
|
||||
current (as of 1999-11-07) printf_* function calls fputc and
|
||||
fputc does exactly the below. By having a write function it
|
||||
is possible to clean up that code. */
|
||||
int i;
|
||||
char b[2];
|
||||
b[1] = '\0';
|
||||
for (i = 0; i < sizeof_buf; i++)
|
||||
{
|
||||
b[0] = buf[i];
|
||||
file->to_fputs (b, file);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_fputs (buf, file)
|
||||
const char *buf;
|
||||
struct gdb_file *file;
|
||||
{
|
||||
if (file->to_write == null_file_write)
|
||||
/* Both the write and fputs methods are null. Discard the
|
||||
request. */
|
||||
return;
|
||||
else
|
||||
{
|
||||
/* The write method was implemented, use that. */
|
||||
file->to_write (file, buf, strlen (buf));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
gdb_file_data (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
if (file->magic != &gdb_file_magic)
|
||||
internal_error ("gdb_file_data: bad magic number");
|
||||
return file->to_data;
|
||||
}
|
||||
|
||||
void
|
||||
gdb_flush (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_flush (file);
|
||||
}
|
||||
|
||||
int
|
||||
gdb_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return file->to_isatty (file);
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_rewind (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_rewind (file);
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
file->to_put (file, write, dest);
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_write (struct gdb_file *file,
|
||||
const char *buf,
|
||||
long length_buf)
|
||||
{
|
||||
file->to_write (file, buf, length_buf);
|
||||
}
|
||||
|
||||
void
|
||||
fputs_unfiltered (buf, file)
|
||||
const char *buf;
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_fputs (buf, file);
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_flush (file, flush)
|
||||
struct gdb_file *file;
|
||||
gdb_file_flush_ftype *flush;
|
||||
{
|
||||
file->to_flush = flush;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_isatty (file, isatty)
|
||||
struct gdb_file *file;
|
||||
gdb_file_isatty_ftype *isatty;
|
||||
{
|
||||
file->to_isatty = isatty;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_rewind (file, rewind)
|
||||
struct gdb_file *file;
|
||||
gdb_file_rewind_ftype *rewind;
|
||||
{
|
||||
file->to_rewind = rewind;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_put (file, put)
|
||||
struct gdb_file *file;
|
||||
gdb_file_put_ftype *put;
|
||||
{
|
||||
file->to_put = put;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_write (struct gdb_file *file,
|
||||
gdb_file_write_ftype *write)
|
||||
{
|
||||
file->to_write = write;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_fputs (file, fputs)
|
||||
struct gdb_file *file;
|
||||
gdb_file_fputs_ftype *fputs;
|
||||
{
|
||||
file->to_fputs = fputs;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_data (file, data, delete)
|
||||
struct gdb_file *file;
|
||||
void *data;
|
||||
gdb_file_delete_ftype *delete;
|
||||
{
|
||||
file->to_data = data;
|
||||
file->to_delete = delete;
|
||||
}
|
||||
|
||||
/* gdb_file utility function for converting a ``struct gdb_file'' into
|
||||
a memory buffer''. */
|
||||
|
||||
struct accumulated_gdb_file
|
||||
{
|
||||
char *buffer;
|
||||
long length;
|
||||
};
|
||||
|
||||
static void
|
||||
do_gdb_file_xstrdup (void *context, const char *buffer, long length)
|
||||
{
|
||||
struct accumulated_gdb_file *acc = context;
|
||||
if (acc->buffer == NULL)
|
||||
acc->buffer = xmalloc (length + 1);
|
||||
else
|
||||
acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
|
||||
memcpy (acc->buffer + acc->length, buffer, length);
|
||||
acc->length += length;
|
||||
acc->buffer[acc->length] = '\0';
|
||||
}
|
||||
|
||||
char *
|
||||
gdb_file_xstrdup (struct gdb_file *file,
|
||||
long *length)
|
||||
{
|
||||
struct accumulated_gdb_file acc;
|
||||
acc.buffer = NULL;
|
||||
acc.length = 0;
|
||||
gdb_file_put (file, do_gdb_file_xstrdup, &acc);
|
||||
if (acc.buffer == NULL)
|
||||
acc.buffer = xstrdup ("");
|
||||
*length = acc.length;
|
||||
return acc.buffer;
|
||||
}
|
||||
|
||||
/* A pure memory based ``struct gdb_file'' that can be used an output
|
||||
buffer. The buffers accumulated contents are available via
|
||||
gdb_file_put(). */
|
||||
|
||||
struct mem_file
|
||||
{
|
||||
int *magic;
|
||||
char *buffer;
|
||||
int sizeof_buffer;
|
||||
int length_buffer;
|
||||
};
|
||||
|
||||
static gdb_file_rewind_ftype mem_file_rewind;
|
||||
static gdb_file_put_ftype mem_file_put;
|
||||
static gdb_file_write_ftype mem_file_write;
|
||||
static gdb_file_delete_ftype mem_file_delete;
|
||||
static struct gdb_file *mem_file_new PARAMS ((void));
|
||||
static int mem_file_magic;
|
||||
|
||||
static struct gdb_file *
|
||||
mem_file_new (void)
|
||||
{
|
||||
struct mem_file *stream = XMALLOC (struct mem_file);
|
||||
struct gdb_file *file = gdb_file_new ();
|
||||
set_gdb_file_data (file, stream, mem_file_delete);
|
||||
set_gdb_file_rewind (file, mem_file_rewind);
|
||||
set_gdb_file_put (file, mem_file_put);
|
||||
set_gdb_file_write (file, mem_file_write);
|
||||
stream->magic = &mem_file_magic;
|
||||
stream->buffer = NULL;
|
||||
stream->sizeof_buffer = 0;
|
||||
stream->length_buffer = 0;
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
mem_file_delete (struct gdb_file *file)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_delete: bad magic number");
|
||||
if (stream->buffer != NULL)
|
||||
free (stream->buffer);
|
||||
free (stream);
|
||||
}
|
||||
|
||||
struct gdb_file *
|
||||
mem_fileopen (void)
|
||||
{
|
||||
return mem_file_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
mem_file_rewind (struct gdb_file *file)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_rewind: bad magic number");
|
||||
stream->length_buffer = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mem_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_put: bad magic number");
|
||||
if (stream->length_buffer > 0)
|
||||
write (dest, stream->buffer, stream->length_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
mem_file_write (struct gdb_file *file,
|
||||
const char *buffer,
|
||||
long length_buffer)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_write: bad magic number");
|
||||
if (stream->buffer == NULL)
|
||||
{
|
||||
stream->length_buffer = length_buffer;
|
||||
stream->sizeof_buffer = length_buffer;
|
||||
stream->buffer = xmalloc (stream->sizeof_buffer);
|
||||
memcpy (stream->buffer, buffer, length_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
int new_length = stream->length_buffer + length_buffer;
|
||||
if (new_length >= stream->sizeof_buffer)
|
||||
{
|
||||
stream->sizeof_buffer = new_length;
|
||||
stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
|
||||
}
|
||||
memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
|
||||
stream->length_buffer = new_length;
|
||||
}
|
||||
}
|
||||
|
||||
/* ``struct gdb_file'' implementation that maps directly onto
|
||||
<stdio.h>'s FILE. */
|
||||
|
||||
static gdb_file_write_ftype stdio_file_write;
|
||||
static gdb_file_fputs_ftype stdio_file_fputs;
|
||||
static gdb_file_isatty_ftype stdio_file_isatty;
|
||||
static gdb_file_delete_ftype stdio_file_delete;
|
||||
static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p));
|
||||
static gdb_file_flush_ftype stdio_file_flush;
|
||||
|
||||
static int stdio_file_magic;
|
||||
|
||||
struct stdio_file
|
||||
{
|
||||
int *magic;
|
||||
FILE *file;
|
||||
int close_p;
|
||||
};
|
||||
|
||||
static struct gdb_file *
|
||||
stdio_file_new (file, close_p)
|
||||
FILE *file;
|
||||
int close_p;
|
||||
{
|
||||
struct gdb_file *gdb_file = gdb_file_new ();
|
||||
struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
|
||||
stdio->magic = &stdio_file_magic;
|
||||
stdio->file = file;
|
||||
stdio->close_p = close_p;
|
||||
set_gdb_file_data (gdb_file, stdio, stdio_file_delete);
|
||||
set_gdb_file_flush (gdb_file, stdio_file_flush);
|
||||
set_gdb_file_write (gdb_file, stdio_file_write);
|
||||
set_gdb_file_fputs (gdb_file, stdio_file_fputs);
|
||||
set_gdb_file_isatty (gdb_file, stdio_file_isatty);
|
||||
return gdb_file;
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_delete: bad magic number");
|
||||
if (stdio->close_p)
|
||||
{
|
||||
fclose (stdio->file);
|
||||
}
|
||||
free (stdio);
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_flush (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_flush: bad magic number");
|
||||
fflush (stdio->file);
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_write (struct gdb_file *file, const char *buf, long length_buf)
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_write: bad magic number");
|
||||
fwrite (buf, length_buf, 1, stdio->file);
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_fputs (linebuffer, file)
|
||||
const char *linebuffer;
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_fputs: bad magic number");
|
||||
fputs (linebuffer, stdio->file);
|
||||
}
|
||||
|
||||
static int
|
||||
stdio_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_isatty: bad magic number");
|
||||
return (isatty (fileno (stdio->file)));
|
||||
}
|
||||
|
||||
/* Like fdopen(). Create a gdb_file from a previously opened FILE. */
|
||||
|
||||
struct gdb_file *
|
||||
stdio_fileopen (file)
|
||||
FILE *file;
|
||||
{
|
||||
return stdio_file_new (file, 0);
|
||||
}
|
||||
|
||||
GDB_FILE *
|
||||
gdb_fopen (name, mode)
|
||||
char *name;
|
||||
char *mode;
|
||||
{
|
||||
FILE *f = fopen (name, mode);
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
return stdio_file_new (f, 1);
|
||||
}
|
93
gdb/gdb-file.h
Normal file
93
gdb/gdb-file.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* GDB_FILE - a generic STDIO like output stream.
|
||||
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef GDB_FILE_H
|
||||
#define GDB_FILE_H
|
||||
|
||||
struct gdb_file;
|
||||
|
||||
/* Create a generic gdb_file object with null methods. */
|
||||
|
||||
extern struct gdb_file *gdb_file_new (void);
|
||||
|
||||
/* Override methods used by specific implementations of a GDB_FILE
|
||||
object. */
|
||||
|
||||
typedef void (gdb_file_flush_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_flush (struct gdb_file *stream, gdb_file_flush_ftype * flush);
|
||||
|
||||
/* NOTE: Both fputs and write methods are available. Default
|
||||
implementations that mapping one onto the other are included. */
|
||||
typedef void (gdb_file_write_ftype) (struct gdb_file * stream, const char *buf, long length_buf);
|
||||
extern void set_gdb_file_write (struct gdb_file *stream, gdb_file_write_ftype *fputs);
|
||||
|
||||
typedef void (gdb_file_fputs_ftype) (const char *, struct gdb_file * stream);
|
||||
extern void set_gdb_file_fputs (struct gdb_file *stream, gdb_file_fputs_ftype * fputs);
|
||||
|
||||
typedef int (gdb_file_isatty_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_isatty (struct gdb_file *stream, gdb_file_isatty_ftype * isatty);
|
||||
|
||||
typedef void (gdb_file_rewind_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_rewind (struct gdb_file *stream, gdb_file_rewind_ftype * rewind);
|
||||
|
||||
typedef void (gdb_file_put_method_ftype) (void *object, const char *buffer, long length_buffer);
|
||||
typedef void (gdb_file_put_ftype) (struct gdb_file *stream, gdb_file_put_method_ftype * method, void *context);
|
||||
extern void set_gdb_file_put (struct gdb_file *stream, gdb_file_put_ftype * put);
|
||||
|
||||
typedef void (gdb_file_delete_ftype) (struct gdb_file * stream);
|
||||
extern void set_gdb_file_data (struct gdb_file *stream, void *data, gdb_file_delete_ftype * delete);
|
||||
|
||||
extern void *gdb_file_data (struct gdb_file *file);
|
||||
|
||||
|
||||
extern void gdb_flush (struct gdb_file *);
|
||||
|
||||
extern void gdb_file_delete (struct gdb_file *stream);
|
||||
|
||||
extern void gdb_file_rewind (struct gdb_file *stream);
|
||||
|
||||
extern int gdb_file_isatty (struct gdb_file *);
|
||||
|
||||
extern void gdb_file_write (struct gdb_file *file, const char *buf, long length_buf);
|
||||
|
||||
/* NOTE: copies left to right */
|
||||
extern void gdb_file_put (struct gdb_file *src, gdb_file_put_method_ftype *write, void *dest);
|
||||
|
||||
/* Returns a freshly allocated buffer containing the entire contents
|
||||
of FILE (as determined by gdb_file_put()) with a NUL character
|
||||
appended. LENGTH is set to the size of the buffer minus that
|
||||
appended NUL. */
|
||||
extern char *gdb_file_xstrdup (struct gdb_file *file, long *length);
|
||||
|
||||
|
||||
|
||||
/* Create/open a memory based file. Can be used as a scratch buffer
|
||||
for collecting output. */
|
||||
extern struct gdb_file *mem_fileopen (void);
|
||||
|
||||
|
||||
|
||||
/* Open/create a an STDIO based GDB_FILE using the already open FILE. */
|
||||
extern struct gdb_file *stdio_fileopen (FILE *file);
|
||||
|
||||
/* Open NAME returning an STDIO based GDB_FILE. */
|
||||
extern GDB_FILE *gdb_fopen (char *name, char *mode);
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
/* Interface GDB to the GNU Hurd
|
||||
/* Interface GDB to the GNU Hurd.
|
||||
Copyright (C) 1992, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -88,7 +88,6 @@ int gnu_debug_flag = 0;
|
||||
|
||||
extern struct target_ops gnu_ops;
|
||||
|
||||
int inf_update_procs (struct inf *inf);
|
||||
struct inf *make_inf ();
|
||||
void inf_clear_wait (struct inf *inf);
|
||||
void inf_cleanup (struct inf *inf);
|
||||
@ -116,7 +115,6 @@ void inf_continue (struct inf *inf);
|
||||
debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0)
|
||||
|
||||
void proc_abort (struct proc *proc, int force);
|
||||
thread_state_t proc_get_state (struct proc *proc, int force);
|
||||
struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
|
||||
struct proc *_proc_free (struct proc *proc);
|
||||
int proc_update_sc (struct proc *proc);
|
||||
@ -126,7 +124,6 @@ static mach_port_t _proc_get_exc_port (struct proc *proc);
|
||||
void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
|
||||
void proc_restore_exc_port (struct proc *proc);
|
||||
int proc_trace (struct proc *proc, int set);
|
||||
char *proc_string (struct proc *proc);
|
||||
|
||||
/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound
|
||||
to INF's msg port and task port respectively. If it has no msg port,
|
||||
|
@ -31,6 +31,9 @@ extern struct inf *current_inferior;
|
||||
/* Converts a GDB pid to a struct proc. */
|
||||
struct proc *inf_tid_to_thread (struct inf *inf, int tid);
|
||||
|
||||
/* Makes sure that INF's thread list is synced with the actual process. */
|
||||
int inf_update_procs (struct inf *inf);
|
||||
|
||||
/* A proc is either a thread, or the task (there can only be one task proc
|
||||
because it always has the same TID, PROC_TID_TASK). */
|
||||
struct proc
|
||||
@ -75,8 +78,15 @@ struct proc
|
||||
|
||||
extern int __proc_pid (struct proc *proc);
|
||||
|
||||
/* Make sure that the state field in PROC is up to date, and return a
|
||||
pointer to it, or 0 if something is wrong. If WILL_MODIFY is true,
|
||||
makes sure that the thread is stopped and aborted first, and sets
|
||||
the state_changed field in PROC to true. */
|
||||
extern thread_state_t proc_get_state (struct proc *proc, int will_modify);
|
||||
|
||||
/* Return printable description of proc. */
|
||||
extern char *proc_string (struct proc *proc);
|
||||
|
||||
#define proc_debug(_proc, msg, args...) \
|
||||
do { struct proc *__proc = (_proc); \
|
||||
debug ("{proc %d/%d %p}: " msg, \
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Low level interface to I386 running the GNU Hurd
|
||||
/* Low level interface to i386 running the GNU Hurd.
|
||||
Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -22,171 +22,18 @@
|
||||
#include "inferior.h"
|
||||
#include "floatformat.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <mach.h>
|
||||
#include <mach_error.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/exception.h>
|
||||
#include <mach_error.h>
|
||||
|
||||
#include "gnu-nat.h"
|
||||
|
||||
/* Hmmm... Should this not be here?
|
||||
* Now for i386_float_info() target_has_execution
|
||||
*/
|
||||
#include <target.h>
|
||||
|
||||
/* @@@ Should move print_387_status() to i387-tdep.c */
|
||||
extern void print_387_control_word (); /* i387-tdep.h */
|
||||
extern void print_387_status_word ();
|
||||
|
||||
/* Find offsets to thread states at compile time.
|
||||
* If your compiler does not grok this, calculate offsets
|
||||
* offsets yourself and use them (or get a compatible compiler :-)
|
||||
*/
|
||||
|
||||
#define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg)
|
||||
|
||||
/* at reg_offset[i] is the offset to the i386_thread_state
|
||||
* location where the gdb registers[i] is stored.
|
||||
*/
|
||||
|
||||
static int reg_offset[] =
|
||||
{
|
||||
REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx),
|
||||
REG_OFFSET (uesp), REG_OFFSET (ebp), REG_OFFSET (esi), REG_OFFSET (edi),
|
||||
REG_OFFSET (eip), REG_OFFSET (efl), REG_OFFSET (cs), REG_OFFSET (ss),
|
||||
REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs)
|
||||
};
|
||||
|
||||
#define REG_ADDR(state,regnum) ((char *)(state)+reg_offset[regnum])
|
||||
|
||||
/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
|
||||
* Caller knows that the regs handled in one transaction are of same size.
|
||||
*/
|
||||
#define FETCH_REGS(state, regnum, count) \
|
||||
memcpy (®isters[REGISTER_BYTE (regnum)], \
|
||||
REG_ADDR (state, regnum), \
|
||||
count * REGISTER_RAW_SIZE (regnum))
|
||||
|
||||
/* Store COUNT contiguous registers to thread STATE starting from REGNUM */
|
||||
#define STORE_REGS(state, regnum, count) \
|
||||
memcpy (REG_ADDR (state, regnum), \
|
||||
®isters[REGISTER_BYTE (regnum)], \
|
||||
count * REGISTER_RAW_SIZE (regnum))
|
||||
|
||||
/*
|
||||
* Fetch inferiors registers for gdb.
|
||||
* REG specifies which (as gdb views it) register, -1 for all.
|
||||
*/
|
||||
void
|
||||
gnu_fetch_registers (int reg)
|
||||
{
|
||||
struct proc *thread;
|
||||
thread_state_t state;
|
||||
|
||||
inf_update_procs (current_inferior); /* Make sure we know about new threads. */
|
||||
|
||||
thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
if (!thread)
|
||||
error ("fetch inferior registers: %d: Invalid thread", inferior_pid);
|
||||
|
||||
state = proc_get_state (thread, 0);
|
||||
|
||||
if (!state)
|
||||
warning ("Couldn't fetch register %s from %s (invalid thread).",
|
||||
REGISTER_NAME (reg), proc_string (thread));
|
||||
else if (reg >= 0)
|
||||
{
|
||||
proc_debug (thread, "fetching register: %s", REGISTER_NAME (reg));
|
||||
supply_register (reg, REG_ADDR (state, reg));
|
||||
thread->fetched_regs |= (1 << reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_debug (thread, "fetching all registers");
|
||||
for (reg = 0; reg < NUM_REGS; reg++)
|
||||
supply_register (reg, REG_ADDR (state, reg));
|
||||
thread->fetched_regs = ~0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
* If REG is -1, do this for all registers.
|
||||
* Otherwise, REG specifies which register
|
||||
*
|
||||
* On mach3 all registers are always saved in one call.
|
||||
*/
|
||||
void
|
||||
gnu_store_registers (reg)
|
||||
int reg;
|
||||
{
|
||||
struct proc *thread;
|
||||
int was_aborted, was_valid;
|
||||
thread_state_t state;
|
||||
thread_state_data_t old_state;
|
||||
|
||||
inf_update_procs (current_inferior); /* Make sure we know about new threads. */
|
||||
|
||||
thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
if (!thread)
|
||||
error ("store inferior registers: %d: Invalid thread", inferior_pid);
|
||||
|
||||
proc_debug (thread, "storing register %s.", REGISTER_NAME (reg));
|
||||
|
||||
was_aborted = thread->aborted;
|
||||
was_valid = thread->state_valid;
|
||||
if (!was_aborted && was_valid)
|
||||
bcopy (&thread->state, &old_state, sizeof (old_state));
|
||||
|
||||
state = proc_get_state (thread, 1);
|
||||
|
||||
if (!state)
|
||||
warning ("Couldn't store register %s from %s (invalid thread).",
|
||||
REGISTER_NAME (reg), proc_string (thread));
|
||||
else
|
||||
{
|
||||
if (!was_aborted && was_valid)
|
||||
/* See which registers have changed after aborting the thread. */
|
||||
{
|
||||
int check_reg;
|
||||
for (check_reg = 0; check_reg < NUM_REGS; check_reg++)
|
||||
if ((thread->fetched_regs & (1 << check_reg))
|
||||
&& bcmp (REG_ADDR (&old_state, check_reg),
|
||||
REG_ADDR (state, check_reg),
|
||||
REGISTER_RAW_SIZE (check_reg)))
|
||||
/* Register CHECK_REG has changed! Ack! */
|
||||
{
|
||||
warning ("Register %s changed after thread was aborted.",
|
||||
REGISTER_NAME (check_reg));
|
||||
if (reg >= 0 && reg != check_reg)
|
||||
/* Update gdb's copy of the register. */
|
||||
supply_register (check_reg, REG_ADDR (state, check_reg));
|
||||
else
|
||||
warning ("... also writing this register! Suspicious...");
|
||||
}
|
||||
}
|
||||
|
||||
if (reg >= 0)
|
||||
{
|
||||
proc_debug (thread, "storing register: %s", REGISTER_NAME (reg));
|
||||
STORE_REGS (state, reg, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_debug (thread, "storing all registers");
|
||||
for (reg = 0; reg < NUM_REGS; reg++)
|
||||
STORE_REGS (state, reg, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* jtv@hut.fi: I copied and modified this 387 code from
|
||||
* gdb/i386-xdep.c. Modifications for Mach 3.0.
|
||||
*
|
||||
* i387 status dumper. See also i387-tdep.c
|
||||
*/
|
||||
/* The FPU hardware state. */
|
||||
struct env387
|
||||
{
|
||||
unsigned short control;
|
||||
@ -203,166 +50,283 @@ struct env387
|
||||
unsigned short r3;
|
||||
unsigned char regs[8][10];
|
||||
};
|
||||
/* This routine is machine independent?
|
||||
* Should move it to i387-tdep.c but you need to export struct env387
|
||||
*/
|
||||
static
|
||||
print_387_status (status, ep)
|
||||
unsigned short status;
|
||||
struct env387 *ep;
|
||||
|
||||
|
||||
/* Offset to the thread_state_t location where REG is stored. */
|
||||
#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
|
||||
|
||||
/* At reg_offset[i] is the offset to the thread_state_t location where
|
||||
the gdb registers[i] is stored. */
|
||||
static int reg_offset[] =
|
||||
{
|
||||
int i;
|
||||
int bothstatus;
|
||||
int top;
|
||||
int fpreg;
|
||||
unsigned char *p;
|
||||
REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx),
|
||||
REG_OFFSET (uesp), REG_OFFSET (ebp), REG_OFFSET (esi), REG_OFFSET (edi),
|
||||
REG_OFFSET (eip), REG_OFFSET (efl), REG_OFFSET (cs), REG_OFFSET (ss),
|
||||
REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs)
|
||||
};
|
||||
|
||||
bothstatus = ((status != 0) && (ep->status != 0));
|
||||
if (status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("u: ");
|
||||
print_387_status_word (status);
|
||||
}
|
||||
#define REG_ADDR(state, regnum) ((char *)(state) + reg_offset[regnum])
|
||||
|
||||
if (ep->status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("e: ");
|
||||
print_387_status_word (ep->status);
|
||||
}
|
||||
|
||||
print_387_control_word (ep->control);
|
||||
printf_unfiltered ("last exception: ");
|
||||
printf_unfiltered ("opcode %s; ", local_hex_string (ep->opcode));
|
||||
printf_unfiltered ("pc %s:", local_hex_string (ep->code_seg));
|
||||
printf_unfiltered ("%s; ", local_hex_string (ep->eip));
|
||||
printf_unfiltered ("operand %s", local_hex_string (ep->operand_seg));
|
||||
printf_unfiltered (":%s\n", local_hex_string (ep->operand));
|
||||
|
||||
top = (ep->status >> 11) & 7;
|
||||
|
||||
printf_unfiltered ("regno tag msb lsb value\n");
|
||||
for (fpreg = 7; fpreg >= 0; fpreg--)
|
||||
{
|
||||
double val;
|
||||
|
||||
printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
|
||||
|
||||
switch ((ep->tag >> (fpreg * 2)) & 3)
|
||||
{
|
||||
case 0:
|
||||
printf_unfiltered ("valid ");
|
||||
break;
|
||||
case 1:
|
||||
printf_unfiltered ("zero ");
|
||||
break;
|
||||
case 2:
|
||||
printf_unfiltered ("trap ");
|
||||
break;
|
||||
case 3:
|
||||
printf_unfiltered ("empty ");
|
||||
break;
|
||||
}
|
||||
for (i = 9; i >= 0; i--)
|
||||
printf_unfiltered ("%02x", ep->regs[fpreg][i]);
|
||||
|
||||
floatformat_to_double (&floatformat_i387_ext, (char *) ep->regs[fpreg],
|
||||
&val);
|
||||
printf_unfiltered (" %g\n", val);
|
||||
}
|
||||
if (ep->r0)
|
||||
printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string (ep->r0));
|
||||
if (ep->r1)
|
||||
printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string (ep->r1));
|
||||
if (ep->r2)
|
||||
printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string (ep->r2));
|
||||
if (ep->r3)
|
||||
printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string (ep->r3));
|
||||
}
|
||||
|
||||
/*
|
||||
* values that go into fp_kind (from <i386/fpreg.h>)
|
||||
*/
|
||||
#define FP_NO 0 /* no fp chip, no emulator (no fp support) */
|
||||
#define FP_SW 1 /* no fp chip, using software emulator */
|
||||
#define FP_HW 2 /* chip present bit */
|
||||
#define FP_287 2 /* 80287 chip present */
|
||||
#define FP_387 3 /* 80387 chip present */
|
||||
|
||||
typedef struct fpstate
|
||||
{
|
||||
#if 1
|
||||
unsigned char state[FP_STATE_BYTES]; /* "hardware" state */
|
||||
#else
|
||||
struct env387 state; /* Actually this */
|
||||
#endif
|
||||
int status; /* Duplicate status */
|
||||
}
|
||||
*fpstate_t;
|
||||
|
||||
/* Mach 3 specific routines.
|
||||
*/
|
||||
static int
|
||||
get_i387_state (fstate)
|
||||
struct fpstate *fstate;
|
||||
|
||||
/* Get the whole floating-point state of THREAD and record the
|
||||
values of the corresponding (pseudo) registers. */
|
||||
static void
|
||||
fetch_fpregs (struct proc *thread)
|
||||
{
|
||||
mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
|
||||
struct i386_float_state state;
|
||||
struct env387 *ep = (struct env387 *) state.hw_state;
|
||||
error_t err;
|
||||
thread_state_data_t state;
|
||||
unsigned int fsCnt = i386_FLOAT_STATE_COUNT;
|
||||
struct i386_float_state *fsp;
|
||||
struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
int i;
|
||||
|
||||
if (!thread)
|
||||
error ("get_i387_state: Invalid thread");
|
||||
|
||||
proc_abort (thread, 0); /* Make sure THREAD's in a reasonable state. */
|
||||
|
||||
err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt);
|
||||
err = thread_get_state (thread->port, i386_FLOAT_STATE,
|
||||
(thread_state_t) &state, &count);
|
||||
if (err)
|
||||
{
|
||||
warning ("Can not get live floating point state: %s",
|
||||
mach_error_string (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
fsp = (struct i386_float_state *) state;
|
||||
/* The 387 chip (also 486 counts) or a software emulator? */
|
||||
if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW))
|
||||
return 0;
|
||||
|
||||
/* Clear the target then copy thread's float state there.
|
||||
Make a copy of the status word, for some reason?
|
||||
*/
|
||||
memset (fstate, 0, sizeof (struct fpstate));
|
||||
|
||||
fstate->status = fsp->exc_status;
|
||||
|
||||
memcpy (fstate->state, (char *) &fsp->hw_state, FP_STATE_BYTES);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by "info float" command
|
||||
*/
|
||||
void
|
||||
i386_mach3_float_info ()
|
||||
{
|
||||
char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
|
||||
int valid = 0;
|
||||
fpstate_t fps;
|
||||
|
||||
if (target_has_execution)
|
||||
valid = get_i387_state (buf);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
warning ("no floating point status saved");
|
||||
warning ("Couldn't fetch floating-point state from %s",
|
||||
proc_string (thread));
|
||||
return;
|
||||
}
|
||||
|
||||
fps = (fpstate_t) buf;
|
||||
if (! state.initialized)
|
||||
/* The floating-point state isn't initialized. */
|
||||
{
|
||||
for (i = FP0_REGNUM; i <= FP7_REGNUM; i++)
|
||||
supply_register (i, NULL);
|
||||
for (i = FIRST_FPU_CTRL_REGNUM; i <= LAST_FPU_CTRL_REGNUM; i++)
|
||||
supply_register (i, NULL);
|
||||
|
||||
print_387_status (fps->status, (struct env387 *) fps->state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Supply the floating-point registers. */
|
||||
for (i = 0; i < 8; i++)
|
||||
supply_register (FP0_REGNUM + i, ep->regs[i]);
|
||||
|
||||
supply_register (FCTRL_REGNUM, (char *) &ep->control);
|
||||
supply_register (FSTAT_REGNUM, (char *) &ep->status);
|
||||
supply_register (FTAG_REGNUM, (char *) &ep->tag);
|
||||
supply_register (FCOFF_REGNUM, (char *) &ep->eip);
|
||||
supply_register (FDS_REGNUM, (char *) &ep->operand_seg);
|
||||
supply_register (FDOFF_REGNUM, (char *) &ep->operand);
|
||||
|
||||
/* Store the code segment and opcode pseudo registers. */
|
||||
{
|
||||
long l;
|
||||
|
||||
l = ep->code_seg;
|
||||
supply_register (FCS_REGNUM, (char *) &l);
|
||||
l = ep->opcode & ((1 << 11) - 1);
|
||||
supply_register (FOP_REGNUM, (char *) &l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch register REGNO, or all regs if REGNO is -1. */
|
||||
void
|
||||
gnu_fetch_registers (int regno)
|
||||
{
|
||||
struct proc *thread;
|
||||
|
||||
/* Make sure we know about new threads. */
|
||||
inf_update_procs (current_inferior);
|
||||
|
||||
thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
if (!thread)
|
||||
error ("Can't fetch registers from thread %d: No such thread",
|
||||
inferior_pid);
|
||||
|
||||
if (regno < NUM_GREGS || regno == -1)
|
||||
{
|
||||
thread_state_t state;
|
||||
|
||||
/* This does the dirty work for us. */
|
||||
state = proc_get_state (thread, 0);
|
||||
if (!state)
|
||||
{
|
||||
warning ("Couldn't fetch registers from %s",
|
||||
proc_string (thread));
|
||||
return;
|
||||
}
|
||||
|
||||
if (regno == -1)
|
||||
{
|
||||
int i;
|
||||
|
||||
proc_debug (thread, "fetching all register");
|
||||
|
||||
for (i = 0; i < NUM_GREGS; i++)
|
||||
supply_register (i, REG_ADDR (state, i));
|
||||
thread->fetched_regs = ~0;
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_debug (thread, "fetching register %s", REGISTER_NAME (regno));
|
||||
|
||||
supply_register (regno, REG_ADDR (state, regno));
|
||||
thread->fetched_regs |= (1 << regno);
|
||||
}
|
||||
}
|
||||
|
||||
if (regno >= NUM_GREGS || regno == -1)
|
||||
{
|
||||
proc_debug (thread, "fetching floating-point registers");
|
||||
|
||||
fetch_fpregs (thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Fill the i387 hardware state EP with selected data from the set of
|
||||
(pseudo) registers specified by REGS and VALID. VALID is an array
|
||||
indicating which registers in REGS are valid. If VALID is zero,
|
||||
all registers are assumed to be valid. */
|
||||
static void
|
||||
convert_to_env387 (struct env387 *ep, char *regs, signed char *valid)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Fill in the floating-point registers. */
|
||||
for (i = 0; i < 8; i++)
|
||||
if (!valid || valid[i])
|
||||
memcpy (ep->regs[i], ®s[REGISTER_BYTE (FP0_REGNUM + i)],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM + i));
|
||||
|
||||
#define fill(member, regno) \
|
||||
if (!valid || valid[(regno)]) \
|
||||
memcpy (&ep->member, ®s[REGISTER_BYTE (regno)], \
|
||||
sizeof (ep->member));
|
||||
|
||||
fill (control, FCTRL_REGNUM);
|
||||
fill (status, FSTAT_REGNUM);
|
||||
fill (tag, FTAG_REGNUM);
|
||||
fill (eip, FCOFF_REGNUM);
|
||||
fill (operand, FDOFF_REGNUM);
|
||||
fill (operand_seg, FDS_REGNUM);
|
||||
|
||||
#undef fill
|
||||
|
||||
if (!valid || valid[FCS_REGNUM])
|
||||
ep->code_seg =
|
||||
(* (int *) ®isters[REGISTER_BYTE (FCS_REGNUM)] & 0xffff);
|
||||
|
||||
if (!valid || valid[FOP_REGNUM])
|
||||
ep->opcode =
|
||||
((* (int *) ®isters[REGISTER_BYTE (FOP_REGNUM)] & ((1 << 11) - 1)));
|
||||
}
|
||||
|
||||
/* Store the whole floating-point state into THREAD using information
|
||||
from the corresponding (pseudo) registers. */
|
||||
static void
|
||||
store_fpregs (struct proc *thread)
|
||||
{
|
||||
mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
|
||||
struct i386_float_state state;
|
||||
error_t err;
|
||||
|
||||
err = thread_get_state (thread->port, i386_FLOAT_STATE,
|
||||
(thread_state_t) &state, &count);
|
||||
if (err)
|
||||
{
|
||||
warning ("Couldn't fetch floating-point state from %s",
|
||||
proc_string (thread));
|
||||
return;
|
||||
}
|
||||
|
||||
convert_to_env387 ((struct env387 *) state.hw_state,
|
||||
registers, register_valid);
|
||||
|
||||
err = thread_set_state (thread->port, i386_FLOAT_STATE,
|
||||
(thread_state_t) &state, i386_FLOAT_STATE_COUNT);
|
||||
if (err)
|
||||
{
|
||||
warning ("Couldn't store floating-point state into %s",
|
||||
proc_string (thread));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store at least register REGNO, or all regs if REGNO == -1. */
|
||||
void
|
||||
gnu_store_registers (int regno)
|
||||
{
|
||||
struct proc *thread;
|
||||
|
||||
/* Make sure we know about new threads. */
|
||||
inf_update_procs (current_inferior);
|
||||
|
||||
thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
if (!thread)
|
||||
error ("Couldn't store registers into thread %d: No such thread",
|
||||
inferior_pid);
|
||||
|
||||
if (regno < NUM_GREGS || regno == -1)
|
||||
{
|
||||
thread_state_t state;
|
||||
thread_state_data_t old_state;
|
||||
int was_aborted = thread->aborted;
|
||||
int was_valid = thread->state_valid;
|
||||
|
||||
if (!was_aborted && was_valid)
|
||||
memcpy (&old_state, &thread->state, sizeof (old_state));
|
||||
|
||||
state = proc_get_state (thread, 1);
|
||||
if (!state)
|
||||
{
|
||||
warning ("Couldn't store registers into %s", proc_string (thread));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!was_aborted && was_valid)
|
||||
/* See which registers have changed after aborting the thread. */
|
||||
{
|
||||
int check_regno;
|
||||
|
||||
for (check_regno = 0; check_regno < NUM_GREGS; check_regno++)
|
||||
if ((thread->fetched_regs & (1 << check_regno))
|
||||
&& memcpy (REG_ADDR (&old_state, check_regno),
|
||||
REG_ADDR (state, check_regno),
|
||||
REGISTER_RAW_SIZE (check_regno)))
|
||||
/* Register CHECK_REGNO has changed! Ack! */
|
||||
{
|
||||
warning ("Register %s changed after the thread was aborted",
|
||||
REGISTER_NAME (check_regno));
|
||||
if (regno >= 0 && regno != check_regno)
|
||||
/* Update gdb's copy of the register. */
|
||||
supply_register (check_regno, REG_ADDR (state, check_regno));
|
||||
else
|
||||
warning ("... also writing this register! Suspicious...");
|
||||
}
|
||||
}
|
||||
|
||||
#define fill(state, regno) \
|
||||
memcpy (REG_ADDR(state, regno), ®isters[REGISTER_BYTE (regno)], \
|
||||
REGISTER_RAW_SIZE (regno))
|
||||
|
||||
if (regno == -1)
|
||||
{
|
||||
int i;
|
||||
|
||||
proc_debug (thread, "storing all registers");
|
||||
|
||||
for (i = 0; i < NUM_GREGS; i++)
|
||||
if (register_valid[i])
|
||||
fill (state, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_debug (thread, "storing register %s", REGISTER_NAME (regno));
|
||||
|
||||
assert (register_valid[regno]);
|
||||
fill (state, regno);
|
||||
}
|
||||
}
|
||||
|
||||
#undef fill
|
||||
|
||||
if (regno >= NUM_GREGS || regno == -1)
|
||||
{
|
||||
proc_debug (thread, "storing floating-point registers");
|
||||
|
||||
store_fpregs (thread);
|
||||
}
|
||||
}
|
||||
|
27
gdb/infcmd.c
27
gdb/infcmd.c
@ -838,8 +838,13 @@ breakpoint_auto_delete_contents (arg)
|
||||
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). */
|
||||
|
||||
Otherwise, run_stack-dummy returns a non-zero value.
|
||||
If the called function receives a random signal, we do not allow the user
|
||||
to continue executing it as this may not work. The dummy frame is poped
|
||||
and we return 1.
|
||||
If we hit a breakpoint, we leave the frame in place and return 2 (the frame
|
||||
will eventually be popped when we do hit the dummy end breakpoint). */
|
||||
|
||||
int
|
||||
run_stack_dummy (addr, buffer)
|
||||
@ -907,10 +912,24 @@ run_stack_dummy (addr, buffer)
|
||||
|
||||
discard_cleanups (old_cleanups);
|
||||
|
||||
if (stopped_by_random_signal)
|
||||
{
|
||||
/* If the inferior execution fails we need to restore our
|
||||
stack. It is not done by proceed() in this case. */
|
||||
/* 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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We may also stop prematurely because we hit a breakpoint in the
|
||||
called routine. We do not pop the frame as the user may wish
|
||||
to single step or continue from there. */
|
||||
if (!stop_stack_dummy)
|
||||
return 1;
|
||||
return 2;
|
||||
|
||||
/* On return, the stack dummy has been popped already. */
|
||||
/* On normal return, the stack dummy has been popped already. */
|
||||
|
||||
memcpy (buffer, stop_registers, REGISTER_BYTES);
|
||||
return 0;
|
||||
|
21
gdb/main.c
21
gdb/main.c
@ -33,6 +33,11 @@
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include "event-loop.h"
|
||||
#if defined (TUI) || defined (GDBTK)
|
||||
/* FIXME: cagney/2000-01-31: This #include is to allow older code such
|
||||
as that found in the TUI to continue to build. */
|
||||
#include "tui/tui-file.h"
|
||||
#endif
|
||||
|
||||
/* If nonzero, display time usage both at startup and for each command. */
|
||||
|
||||
@ -187,17 +192,19 @@ captured_main (void *data)
|
||||
getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
|
||||
current_directory = gdb_dirbuf;
|
||||
|
||||
#if 0
|
||||
/* not yet */
|
||||
gdb_stdout = stdio_fileopen (stdout);
|
||||
gdb_stderr = stdio_fileopen (stderr);
|
||||
gdb_stdlog = gdb_stderr; /* for moment */
|
||||
gdb_stdtarg = gdb_stderr; /* for moment */
|
||||
#else
|
||||
#if defined (TUI) || defined (GDBTK)
|
||||
/* Older code uses the tui_file and fputs_unfiltered_hook(). It
|
||||
should be using a customized GDB_FILE object and re-initializing
|
||||
within its own _initialize function. */
|
||||
gdb_stdout = tui_fileopen (stdout);
|
||||
gdb_stderr = tui_fileopen (stderr);
|
||||
gdb_stdlog = gdb_stdout; /* for moment */
|
||||
gdb_stdtarg = gdb_stderr; /* for moment */
|
||||
#else
|
||||
gdb_stdout = stdio_fileopen (stdout);
|
||||
gdb_stderr = stdio_fileopen (stderr);
|
||||
gdb_stdlog = gdb_stderr; /* for moment */
|
||||
gdb_stdtarg = gdb_stderr; /* for moment */
|
||||
#endif
|
||||
|
||||
/* initialize error() */
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "gdb-stabs.h"
|
||||
#include "gdbthread.h"
|
||||
#include "gdbcore.h"
|
||||
#include "breakpoint.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
@ -738,6 +739,12 @@ arm_rdi_kill ()
|
||||
static void
|
||||
arm_rdi_mourn_inferior ()
|
||||
{
|
||||
/* We remove the inserted breakpoints in case the user wants to
|
||||
issue another target and load commands to rerun his application;
|
||||
This is something that wouldn't work on a native target, for instance,
|
||||
as the process goes away when the inferior exits, but it works with
|
||||
some remote targets like this one. That is why this is done here. */
|
||||
remove_breakpoints();
|
||||
unpush_target (&arm_rdi_ops);
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
|
61
gdb/symtab.c
61
gdb/symtab.c
@ -2400,6 +2400,43 @@ build_canonical_line_spec (sal, symname, canonical)
|
||||
canonical_arr[0] = canonical_name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Find an instance of the character C in the string S that is outside
|
||||
of all parenthesis pairs, single-quoted strings, and double-quoted
|
||||
strings. */
|
||||
static char *
|
||||
find_toplevel_char (char *s, char c)
|
||||
{
|
||||
int quoted = 0; /* zero if we're not in quotes;
|
||||
'"' if we're in a double-quoted string;
|
||||
'\'' if we're in a single-quoted string. */
|
||||
int depth = 0; /* number of unclosed parens we've seen */
|
||||
char *scan;
|
||||
|
||||
for (scan = s; *scan; scan++)
|
||||
{
|
||||
if (quoted)
|
||||
{
|
||||
if (*scan == quoted)
|
||||
quoted = 0;
|
||||
else if (*scan == '\\' && *(scan + 1))
|
||||
scan++;
|
||||
}
|
||||
else if (*scan == c && ! quoted && depth == 0)
|
||||
return scan;
|
||||
else if (*scan == '"' || *scan == '\'')
|
||||
quoted = *scan;
|
||||
else if (*scan == '(')
|
||||
depth++;
|
||||
else if (*scan == ')' && depth > 0)
|
||||
depth--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
@ -2576,9 +2613,14 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical)
|
||||
|
||||
/* Maybe we were called with a line range FILENAME:LINENUM,FILENAME:LINENUM
|
||||
and we must isolate the first half. Outer layers will call again later
|
||||
for the second half */
|
||||
if ((ii = strchr (*argptr, ',')) != NULL)
|
||||
has_comma = 1;
|
||||
for the second half.
|
||||
|
||||
Don't count commas that appear in argument lists of overloaded
|
||||
functions, or in quoted strings. It's stupid to go to this much
|
||||
trouble when the rest of the function is such an obvious roach hotel. */
|
||||
ii = find_toplevel_char (*argptr, ',');
|
||||
has_comma = (ii != 0);
|
||||
|
||||
/* Temporarily zap out second half to not
|
||||
* confuse the code below.
|
||||
* This is undone below. Do not change ii!!
|
||||
@ -2632,10 +2674,14 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical)
|
||||
}
|
||||
while (p[0] == ' ' || p[0] == '\t')
|
||||
p++;
|
||||
|
||||
/* if the closing double quote was left at the end, remove it */
|
||||
if (is_quote_enclosed && ((pp = strchr (p, '"')) != NULL))
|
||||
if (!*(pp + 1))
|
||||
*pp = '\0';
|
||||
if (is_quote_enclosed)
|
||||
{
|
||||
char *closing_quote = strchr (p, '"');
|
||||
if (closing_quote && closing_quote[1] == '\0')
|
||||
*closing_quote = '\0';
|
||||
}
|
||||
|
||||
/* Now that we've safely parsed the first half,
|
||||
* put back ',' so outer layers can see it
|
||||
@ -3068,6 +3114,9 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical)
|
||||
p = skip_quoted (*argptr);
|
||||
}
|
||||
|
||||
if (is_quote_enclosed && **argptr == '"')
|
||||
(*argptr)++;
|
||||
|
||||
copy = (char *) alloca (p - *argptr + 1);
|
||||
memcpy (copy, *argptr, p - *argptr);
|
||||
copy[p - *argptr] = '\0';
|
||||
|
@ -376,10 +376,6 @@ int (*ui_loop_hook) PARAMS ((int));
|
||||
void (*command_loop_hook) PARAMS ((void));
|
||||
|
||||
|
||||
/* Called instead of fputs for all output. */
|
||||
|
||||
void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, GDB_FILE * stream));
|
||||
|
||||
/* Called from print_frame_info to list the line we stopped in. */
|
||||
|
||||
void (*print_frame_info_listing_hook) PARAMS ((struct symtab * s, int line,
|
||||
|
@ -1,3 +1,13 @@
|
||||
Mon Jan 31 18:12:43 2000 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* tui-file.c (enum streamtype, struct tui_stream, tui_file_new,
|
||||
tui_file_delete, tui_fileopen, tui_sfileopen, tui_file_isatty,
|
||||
tui_file_rewind, tui_file_put, tui_file_fputs,
|
||||
tui_file_get_strbuf, tui_file_adjust_strbuf, tui_file_flush,
|
||||
fputs_unfiltered_hook): Move to here from ../utils.c
|
||||
|
||||
* tui-file.h, tui-file.c: New files.
|
||||
|
||||
Mon Nov 8 17:47:37 1999 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* tuiRegs.c (_tuiRegisterFormat), tuiDisassem.c
|
||||
|
298
gdb/tui/tui-file.c
Normal file
298
gdb/tui/tui-file.c
Normal file
@ -0,0 +1,298 @@
|
||||
/* GDB_FILE - a generic STDIO like output stream.
|
||||
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb-file.h"
|
||||
#include "tui/tui-file.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Called instead of fputs for all TUI_FILE output. */
|
||||
|
||||
void (*fputs_unfiltered_hook) (const char *linebuffer, GDB_FILE * stream);
|
||||
|
||||
/* A ``struct gdb_file'' that is compatible with all the legacy
|
||||
code. */
|
||||
|
||||
/* new */
|
||||
enum streamtype
|
||||
{
|
||||
afile,
|
||||
astring
|
||||
};
|
||||
|
||||
/* new */
|
||||
struct tui_stream
|
||||
{
|
||||
int *ts_magic;
|
||||
enum streamtype ts_streamtype;
|
||||
FILE *ts_filestream;
|
||||
char *ts_strbuf;
|
||||
int ts_buflen;
|
||||
};
|
||||
|
||||
static gdb_file_flush_ftype tui_file_flush;
|
||||
extern gdb_file_fputs_ftype tui_file_fputs;
|
||||
static gdb_file_isatty_ftype tui_file_isatty;
|
||||
static gdb_file_rewind_ftype tui_file_rewind;
|
||||
static gdb_file_put_ftype tui_file_put;
|
||||
static gdb_file_delete_ftype tui_file_delete;
|
||||
static struct gdb_file *tui_file_new PARAMS ((void));
|
||||
static int tui_file_magic;
|
||||
|
||||
static struct gdb_file *
|
||||
tui_file_new ()
|
||||
{
|
||||
struct tui_stream *tui = xmalloc (sizeof (struct tui_stream));
|
||||
struct gdb_file *file = gdb_file_new ();
|
||||
set_gdb_file_data (file, tui, tui_file_delete);
|
||||
set_gdb_file_flush (file, tui_file_flush);
|
||||
set_gdb_file_fputs (file, tui_file_fputs);
|
||||
set_gdb_file_isatty (file, tui_file_isatty);
|
||||
set_gdb_file_rewind (file, tui_file_rewind);
|
||||
set_gdb_file_put (file, tui_file_put);
|
||||
tui->ts_magic = &tui_file_magic;
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct tui_stream *tmpstream = gdb_file_data (file);
|
||||
if (tmpstream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_delete: bad magic number");
|
||||
if ((tmpstream->ts_streamtype == astring) &&
|
||||
(tmpstream->ts_strbuf != NULL))
|
||||
{
|
||||
free (tmpstream->ts_strbuf);
|
||||
}
|
||||
free (tmpstream);
|
||||
}
|
||||
|
||||
struct gdb_file *
|
||||
tui_fileopen (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
struct gdb_file *file = tui_file_new ();
|
||||
struct tui_stream *tmpstream = gdb_file_data (file);
|
||||
tmpstream->ts_streamtype = afile;
|
||||
tmpstream->ts_filestream = stream;
|
||||
tmpstream->ts_strbuf = NULL;
|
||||
tmpstream->ts_buflen = 0;
|
||||
return file;
|
||||
}
|
||||
|
||||
struct gdb_file *
|
||||
tui_sfileopen (n)
|
||||
int n;
|
||||
{
|
||||
struct gdb_file *file = tui_file_new ();
|
||||
struct tui_stream *tmpstream = gdb_file_data (file);
|
||||
tmpstream->ts_streamtype = astring;
|
||||
tmpstream->ts_filestream = NULL;
|
||||
if (n > 0)
|
||||
{
|
||||
tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
|
||||
tmpstream->ts_strbuf[0] = '\0';
|
||||
}
|
||||
else
|
||||
/* Do not allocate the buffer now. The first time something is printed
|
||||
one will be allocated by tui_file_adjust_strbuf() */
|
||||
tmpstream->ts_strbuf = NULL;
|
||||
tmpstream->ts_buflen = n;
|
||||
return file;
|
||||
}
|
||||
|
||||
static int
|
||||
tui_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_isatty: bad magic number");
|
||||
if (stream->ts_streamtype == afile)
|
||||
return (isatty (fileno (stream->ts_filestream)));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_rewind (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_rewind: bad magic number");
|
||||
stream->ts_strbuf[0] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_put: bad magic number");
|
||||
if (stream->ts_streamtype == astring)
|
||||
write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
|
||||
}
|
||||
|
||||
/* All TUI I/O sent to the *_filtered and *_unfiltered functions
|
||||
eventually ends up here. The fputs_unfiltered_hook is primarily
|
||||
used by GUIs to collect all output and send it to the GUI, instead
|
||||
of the controlling terminal. Only output to gdb_stdout and
|
||||
gdb_stderr are sent to the hook. Everything else is sent on to
|
||||
fputs to allow file I/O to be handled appropriately. */
|
||||
|
||||
/* FIXME: Should be broken up and moved to a TUI specific file. */
|
||||
|
||||
void
|
||||
tui_file_fputs (linebuffer, file)
|
||||
const char *linebuffer;
|
||||
GDB_FILE *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
#if defined(TUI)
|
||||
extern int tui_owns_terminal;
|
||||
#endif
|
||||
/* NOTE: cagney/1999-10-13: The use of fputs_unfiltered_hook is
|
||||
seriously discouraged. Those wanting to hook output should
|
||||
instead implement their own gdb_file object and install that. See
|
||||
also tui_file_flush(). */
|
||||
if (fputs_unfiltered_hook
|
||||
&& (file == gdb_stdout
|
||||
|| file == gdb_stderr))
|
||||
fputs_unfiltered_hook (linebuffer, file);
|
||||
else
|
||||
{
|
||||
#if defined(TUI)
|
||||
if (tui_version && tui_owns_terminal)
|
||||
{
|
||||
/* If we get here somehow while updating the TUI (from
|
||||
* within a tuiDo(), then we need to temporarily
|
||||
* set up the terminal for GDB output. This probably just
|
||||
* happens on error output.
|
||||
*/
|
||||
|
||||
if (stream->ts_streamtype == astring)
|
||||
{
|
||||
tui_file_adjust_strbuf (strlen (linebuffer), stream);
|
||||
strcat (stream->ts_strbuf, linebuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
tuiTermUnsetup (0, (tui_version) ? cmdWin->detail.commandInfo.curch : 0);
|
||||
fputs (linebuffer, stream->ts_filestream);
|
||||
tuiTermSetup (0);
|
||||
if (linebuffer[strlen (linebuffer) - 1] == '\n')
|
||||
tuiClearCommandCharCount ();
|
||||
else
|
||||
tuiIncrCommandCharCountBy (strlen (linebuffer));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The normal case - just do a fputs() */
|
||||
if (stream->ts_streamtype == astring)
|
||||
{
|
||||
tui_file_adjust_strbuf (strlen (linebuffer), stream);
|
||||
strcat (stream->ts_strbuf, linebuffer);
|
||||
}
|
||||
else
|
||||
fputs (linebuffer, stream->ts_filestream);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
if (stream->ts_streamtype == astring)
|
||||
{
|
||||
tui_file_adjust_strbuf (strlen (linebuffer), file);
|
||||
strcat (stream->ts_strbuf, linebuffer);
|
||||
}
|
||||
else
|
||||
fputs (linebuffer, stream->ts_filestream);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
tui_file_get_strbuf (struct gdb_file *file)
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_get_strbuf: bad magic number");
|
||||
return (stream->ts_strbuf);
|
||||
}
|
||||
|
||||
/* adjust the length of the buffer by the amount necessary
|
||||
to accomodate appending a string of length N to the buffer contents */
|
||||
void
|
||||
tui_file_adjust_strbuf (int n, struct gdb_file *file)
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
int non_null_chars;
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_adjust_strbuf: bad magic number");
|
||||
|
||||
if (stream->ts_streamtype != astring)
|
||||
return;
|
||||
|
||||
if (stream->ts_strbuf)
|
||||
{
|
||||
/* There is already a buffer allocated */
|
||||
non_null_chars = strlen (stream->ts_strbuf);
|
||||
|
||||
if (n > (stream->ts_buflen - non_null_chars - 1))
|
||||
{
|
||||
stream->ts_buflen = n + non_null_chars + 1;
|
||||
stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* No buffer yet, so allocate one of the desired size */
|
||||
stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_flush (file)
|
||||
GDB_FILE *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_flush: bad magic number");
|
||||
|
||||
/* NOTE: cagney/1999-10-12: If we've been linked with code that uses
|
||||
fputs_unfiltered_hook then we assume that it doesn't need to know
|
||||
about flushes. Code that does need to know about flushes can
|
||||
implement a proper gdb_file object. */
|
||||
if (fputs_unfiltered_hook)
|
||||
return;
|
||||
|
||||
switch (stream->ts_streamtype)
|
||||
{
|
||||
case astring:
|
||||
break;
|
||||
case afile:
|
||||
fflush (stream->ts_filestream);
|
||||
break;
|
||||
}
|
||||
}
|
34
gdb/tui/tui-file.h
Normal file
34
gdb/tui/tui-file.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* GDB_FILE - a generic STDIO like output stream.
|
||||
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef TUI_FILE_H
|
||||
#define TUI_FILE_H
|
||||
|
||||
extern struct gdb_file *tui_fileopen (FILE *);
|
||||
extern struct gdb_file *tui_sfileopen (int);
|
||||
extern char *tui_file_get_strbuf (struct gdb_file *);
|
||||
extern void tui_file_adjust_strbuf (int, struct gdb_file *);
|
||||
|
||||
/* NOTE: cagney/1999-10-14: fputs_unfiltered_hook is deprecated. Code
|
||||
wanting to control GDB's output should override the gdb_std...
|
||||
files. */
|
||||
extern void (*fputs_unfiltered_hook) (const char *linebuffer,
|
||||
GDB_FILE * stream);
|
||||
#endif
|
757
gdb/utils.c
757
gdb/utils.c
@ -1772,763 +1772,6 @@ begin_line ()
|
||||
}
|
||||
|
||||
|
||||
/* ``struct gdb_file'' implementation that maps directly onto
|
||||
<stdio.h>'s FILE. */
|
||||
|
||||
static gdb_file_write_ftype stdio_file_write;
|
||||
static gdb_file_fputs_ftype stdio_file_fputs;
|
||||
static gdb_file_isatty_ftype stdio_file_isatty;
|
||||
static gdb_file_delete_ftype stdio_file_delete;
|
||||
static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p));
|
||||
static gdb_file_flush_ftype stdio_file_flush;
|
||||
|
||||
static int stdio_file_magic;
|
||||
|
||||
struct stdio_file
|
||||
{
|
||||
int *magic;
|
||||
FILE *file;
|
||||
int close_p;
|
||||
};
|
||||
|
||||
static struct gdb_file *
|
||||
stdio_file_new (file, close_p)
|
||||
FILE *file;
|
||||
int close_p;
|
||||
{
|
||||
struct gdb_file *gdb_file = gdb_file_new ();
|
||||
struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
|
||||
stdio->magic = &stdio_file_magic;
|
||||
stdio->file = file;
|
||||
stdio->close_p = close_p;
|
||||
set_gdb_file_data (gdb_file, stdio, stdio_file_delete);
|
||||
set_gdb_file_flush (gdb_file, stdio_file_flush);
|
||||
set_gdb_file_write (gdb_file, stdio_file_write);
|
||||
set_gdb_file_fputs (gdb_file, stdio_file_fputs);
|
||||
set_gdb_file_isatty (gdb_file, stdio_file_isatty);
|
||||
return gdb_file;
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_delete: bad magic number");
|
||||
if (stdio->close_p)
|
||||
{
|
||||
fclose (stdio->file);
|
||||
}
|
||||
free (stdio);
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_flush (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_flush: bad magic number");
|
||||
fflush (stdio->file);
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_write (struct gdb_file *file, const char *buf, long length_buf)
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_write: bad magic number");
|
||||
fwrite (buf, length_buf, 1, stdio->file);
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_file_fputs (linebuffer, file)
|
||||
const char *linebuffer;
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_fputs: bad magic number");
|
||||
fputs (linebuffer, stdio->file);
|
||||
}
|
||||
|
||||
static int
|
||||
stdio_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct stdio_file *stdio = gdb_file_data (file);
|
||||
if (stdio->magic != &stdio_file_magic)
|
||||
internal_error ("stdio_file_isatty: bad magic number");
|
||||
return (isatty (fileno (stdio->file)));
|
||||
}
|
||||
|
||||
/* Like fdopen(). Create a gdb_file from a previously opened FILE. */
|
||||
|
||||
struct gdb_file *
|
||||
stdio_fileopen (file)
|
||||
FILE *file;
|
||||
{
|
||||
return stdio_file_new (file, 0);
|
||||
}
|
||||
|
||||
|
||||
/* A pure memory based ``struct gdb_file'' that can be used an output
|
||||
buffer. The buffers accumulated contents are available via
|
||||
gdb_file_put(). */
|
||||
|
||||
struct mem_file
|
||||
{
|
||||
int *magic;
|
||||
char *buffer;
|
||||
int sizeof_buffer;
|
||||
int length_buffer;
|
||||
};
|
||||
|
||||
static gdb_file_rewind_ftype mem_file_rewind;
|
||||
static gdb_file_put_ftype mem_file_put;
|
||||
static gdb_file_write_ftype mem_file_write;
|
||||
static gdb_file_delete_ftype mem_file_delete;
|
||||
static struct gdb_file *mem_file_new PARAMS ((void));
|
||||
static int mem_file_magic;
|
||||
|
||||
static struct gdb_file *
|
||||
mem_file_new (void)
|
||||
{
|
||||
struct mem_file *stream = XMALLOC (struct mem_file);
|
||||
struct gdb_file *file = gdb_file_new ();
|
||||
set_gdb_file_data (file, stream, mem_file_delete);
|
||||
set_gdb_file_rewind (file, mem_file_rewind);
|
||||
set_gdb_file_put (file, mem_file_put);
|
||||
set_gdb_file_write (file, mem_file_write);
|
||||
stream->magic = &mem_file_magic;
|
||||
stream->buffer = NULL;
|
||||
stream->sizeof_buffer = 0;
|
||||
stream->length_buffer = 0;
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
mem_file_delete (struct gdb_file *file)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_delete: bad magic number");
|
||||
if (stream->buffer != NULL)
|
||||
free (stream->buffer);
|
||||
free (stream);
|
||||
}
|
||||
|
||||
struct gdb_file *
|
||||
mem_fileopen (void)
|
||||
{
|
||||
return mem_file_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
mem_file_rewind (struct gdb_file *file)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_rewind: bad magic number");
|
||||
stream->length_buffer = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mem_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_put: bad magic number");
|
||||
if (stream->length_buffer > 0)
|
||||
write (dest, stream->buffer, stream->length_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
mem_file_write (struct gdb_file *file,
|
||||
const char *buffer,
|
||||
long length_buffer)
|
||||
{
|
||||
struct mem_file *stream = gdb_file_data (file);
|
||||
if (stream->magic != &mem_file_magic)
|
||||
internal_error ("mem_file_write: bad magic number");
|
||||
if (stream->buffer == NULL)
|
||||
{
|
||||
stream->length_buffer = length_buffer;
|
||||
stream->sizeof_buffer = length_buffer;
|
||||
stream->buffer = xmalloc (stream->sizeof_buffer);
|
||||
memcpy (stream->buffer, buffer, length_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
int new_length = stream->length_buffer + length_buffer;
|
||||
if (new_length >= stream->sizeof_buffer)
|
||||
{
|
||||
stream->sizeof_buffer = new_length;
|
||||
stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
|
||||
}
|
||||
memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
|
||||
stream->length_buffer = new_length;
|
||||
}
|
||||
}
|
||||
|
||||
/* A ``struct gdb_file'' that is compatible with all the legacy
|
||||
code. */
|
||||
|
||||
/* new */
|
||||
enum streamtype
|
||||
{
|
||||
afile,
|
||||
astring
|
||||
};
|
||||
|
||||
/* new */
|
||||
struct tui_stream
|
||||
{
|
||||
int *ts_magic;
|
||||
enum streamtype ts_streamtype;
|
||||
FILE *ts_filestream;
|
||||
char *ts_strbuf;
|
||||
int ts_buflen;
|
||||
};
|
||||
|
||||
static gdb_file_flush_ftype tui_file_flush;
|
||||
extern gdb_file_fputs_ftype tui_file_fputs;
|
||||
static gdb_file_isatty_ftype tui_file_isatty;
|
||||
static gdb_file_rewind_ftype tui_file_rewind;
|
||||
static gdb_file_put_ftype tui_file_put;
|
||||
static gdb_file_delete_ftype tui_file_delete;
|
||||
static struct gdb_file *tui_file_new PARAMS ((void));
|
||||
static int tui_file_magic;
|
||||
|
||||
static struct gdb_file *
|
||||
tui_file_new ()
|
||||
{
|
||||
struct tui_stream *tui = xmalloc (sizeof (struct tui_stream));
|
||||
struct gdb_file *file = gdb_file_new ();
|
||||
set_gdb_file_data (file, tui, tui_file_delete);
|
||||
set_gdb_file_flush (file, tui_file_flush);
|
||||
set_gdb_file_fputs (file, tui_file_fputs);
|
||||
set_gdb_file_isatty (file, tui_file_isatty);
|
||||
set_gdb_file_rewind (file, tui_file_rewind);
|
||||
set_gdb_file_put (file, tui_file_put);
|
||||
tui->ts_magic = &tui_file_magic;
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct tui_stream *tmpstream = gdb_file_data (file);
|
||||
if (tmpstream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_delete: bad magic number");
|
||||
if ((tmpstream->ts_streamtype == astring) &&
|
||||
(tmpstream->ts_strbuf != NULL))
|
||||
{
|
||||
free (tmpstream->ts_strbuf);
|
||||
}
|
||||
free (tmpstream);
|
||||
}
|
||||
|
||||
struct gdb_file *
|
||||
tui_fileopen (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
struct gdb_file *file = tui_file_new ();
|
||||
struct tui_stream *tmpstream = gdb_file_data (file);
|
||||
tmpstream->ts_streamtype = afile;
|
||||
tmpstream->ts_filestream = stream;
|
||||
tmpstream->ts_strbuf = NULL;
|
||||
tmpstream->ts_buflen = 0;
|
||||
return file;
|
||||
}
|
||||
|
||||
struct gdb_file *
|
||||
tui_sfileopen (n)
|
||||
int n;
|
||||
{
|
||||
struct gdb_file *file = tui_file_new ();
|
||||
struct tui_stream *tmpstream = gdb_file_data (file);
|
||||
tmpstream->ts_streamtype = astring;
|
||||
tmpstream->ts_filestream = NULL;
|
||||
if (n > 0)
|
||||
{
|
||||
tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
|
||||
tmpstream->ts_strbuf[0] = '\0';
|
||||
}
|
||||
else
|
||||
/* Do not allocate the buffer now. The first time something is printed
|
||||
one will be allocated by tui_file_adjust_strbuf() */
|
||||
tmpstream->ts_strbuf = NULL;
|
||||
tmpstream->ts_buflen = n;
|
||||
return file;
|
||||
}
|
||||
|
||||
static int
|
||||
tui_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_isatty: bad magic number");
|
||||
if (stream->ts_streamtype == afile)
|
||||
return (isatty (fileno (stream->ts_filestream)));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_rewind (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_rewind: bad magic number");
|
||||
stream->ts_strbuf[0] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_put: bad magic number");
|
||||
if (stream->ts_streamtype == astring)
|
||||
write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
|
||||
}
|
||||
|
||||
/* All TUI I/O sent to the *_filtered and *_unfiltered functions
|
||||
eventually ends up here. The fputs_unfiltered_hook is primarily
|
||||
used by GUIs to collect all output and send it to the GUI, instead
|
||||
of the controlling terminal. Only output to gdb_stdout and
|
||||
gdb_stderr are sent to the hook. Everything else is sent on to
|
||||
fputs to allow file I/O to be handled appropriately. */
|
||||
|
||||
/* FIXME: Should be broken up and moved to a TUI specific file. */
|
||||
|
||||
void
|
||||
tui_file_fputs (linebuffer, file)
|
||||
const char *linebuffer;
|
||||
GDB_FILE *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
#if defined(TUI)
|
||||
extern int tui_owns_terminal;
|
||||
#endif
|
||||
/* NOTE: cagney/1999-10-13: The use of fputs_unfiltered_hook is
|
||||
seriously discouraged. Those wanting to hook output should
|
||||
instead implement their own gdb_file object and install that. See
|
||||
also tui_file_flush(). */
|
||||
if (fputs_unfiltered_hook
|
||||
&& (file == gdb_stdout
|
||||
|| file == gdb_stderr))
|
||||
fputs_unfiltered_hook (linebuffer, file);
|
||||
else
|
||||
{
|
||||
#if defined(TUI)
|
||||
if (tui_version && tui_owns_terminal)
|
||||
{
|
||||
/* If we get here somehow while updating the TUI (from
|
||||
* within a tuiDo(), then we need to temporarily
|
||||
* set up the terminal for GDB output. This probably just
|
||||
* happens on error output.
|
||||
*/
|
||||
|
||||
if (stream->ts_streamtype == astring)
|
||||
{
|
||||
tui_file_adjust_strbuf (strlen (linebuffer), stream);
|
||||
strcat (stream->ts_strbuf, linebuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
tuiTermUnsetup (0, (tui_version) ? cmdWin->detail.commandInfo.curch : 0);
|
||||
fputs (linebuffer, stream->ts_filestream);
|
||||
tuiTermSetup (0);
|
||||
if (linebuffer[strlen (linebuffer) - 1] == '\n')
|
||||
tuiClearCommandCharCount ();
|
||||
else
|
||||
tuiIncrCommandCharCountBy (strlen (linebuffer));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The normal case - just do a fputs() */
|
||||
if (stream->ts_streamtype == astring)
|
||||
{
|
||||
tui_file_adjust_strbuf (strlen (linebuffer), stream);
|
||||
strcat (stream->ts_strbuf, linebuffer);
|
||||
}
|
||||
else
|
||||
fputs (linebuffer, stream->ts_filestream);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
if (stream->ts_streamtype == astring)
|
||||
{
|
||||
tui_file_adjust_strbuf (strlen (linebuffer), file);
|
||||
strcat (stream->ts_strbuf, linebuffer);
|
||||
}
|
||||
else
|
||||
fputs (linebuffer, stream->ts_filestream);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
tui_file_get_strbuf (struct gdb_file *file)
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_get_strbuf: bad magic number");
|
||||
return (stream->ts_strbuf);
|
||||
}
|
||||
|
||||
/* adjust the length of the buffer by the amount necessary
|
||||
to accomodate appending a string of length N to the buffer contents */
|
||||
void
|
||||
tui_file_adjust_strbuf (int n, struct gdb_file *file)
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
int non_null_chars;
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_adjust_strbuf: bad magic number");
|
||||
|
||||
if (stream->ts_streamtype != astring)
|
||||
return;
|
||||
|
||||
if (stream->ts_strbuf)
|
||||
{
|
||||
/* There is already a buffer allocated */
|
||||
non_null_chars = strlen (stream->ts_strbuf);
|
||||
|
||||
if (n > (stream->ts_buflen - non_null_chars - 1))
|
||||
{
|
||||
stream->ts_buflen = n + non_null_chars + 1;
|
||||
stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* No buffer yet, so allocate one of the desired size */
|
||||
stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
|
||||
}
|
||||
|
||||
GDB_FILE *
|
||||
gdb_fopen (name, mode)
|
||||
char *name;
|
||||
char *mode;
|
||||
{
|
||||
FILE *f = fopen (name, mode);
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
return stdio_file_new (f, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
tui_file_flush (file)
|
||||
GDB_FILE *file;
|
||||
{
|
||||
struct tui_stream *stream = gdb_file_data (file);
|
||||
if (stream->ts_magic != &tui_file_magic)
|
||||
internal_error ("tui_file_flush: bad magic number");
|
||||
|
||||
/* NOTE: cagney/1999-10-12: If we've been linked with code that uses
|
||||
fputs_unfiltered_hook then we assume that it doesn't need to know
|
||||
about flushes. Code that does need to know about flushes can
|
||||
implement a proper gdb_file object. */
|
||||
if (fputs_unfiltered_hook)
|
||||
return;
|
||||
|
||||
switch (stream->ts_streamtype)
|
||||
{
|
||||
case astring:
|
||||
break;
|
||||
case afile:
|
||||
fflush (stream->ts_filestream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement the ``struct gdb_file'' object. */
|
||||
|
||||
static gdb_file_isatty_ftype null_file_isatty;
|
||||
static gdb_file_write_ftype null_file_write;
|
||||
static gdb_file_fputs_ftype null_file_fputs;
|
||||
static gdb_file_flush_ftype null_file_flush;
|
||||
static gdb_file_delete_ftype null_file_delete;
|
||||
static gdb_file_rewind_ftype null_file_rewind;
|
||||
static gdb_file_put_ftype null_file_put;
|
||||
|
||||
struct gdb_file
|
||||
{
|
||||
int *magic;
|
||||
gdb_file_flush_ftype *to_flush;
|
||||
gdb_file_write_ftype *to_write;
|
||||
gdb_file_fputs_ftype *to_fputs;
|
||||
gdb_file_delete_ftype *to_delete;
|
||||
gdb_file_isatty_ftype *to_isatty;
|
||||
gdb_file_rewind_ftype *to_rewind;
|
||||
gdb_file_put_ftype *to_put;
|
||||
void *to_data;
|
||||
};
|
||||
int gdb_file_magic;
|
||||
|
||||
struct gdb_file *
|
||||
gdb_file_new ()
|
||||
{
|
||||
struct gdb_file *file = xmalloc (sizeof (struct gdb_file));
|
||||
file->magic = &gdb_file_magic;
|
||||
set_gdb_file_data (file, NULL, null_file_delete);
|
||||
set_gdb_file_flush (file, null_file_flush);
|
||||
set_gdb_file_write (file, null_file_write);
|
||||
set_gdb_file_fputs (file, null_file_fputs);
|
||||
set_gdb_file_isatty (file, null_file_isatty);
|
||||
set_gdb_file_rewind (file, null_file_rewind);
|
||||
set_gdb_file_put (file, null_file_put);
|
||||
return file;
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_delete (file);
|
||||
free (file);
|
||||
}
|
||||
|
||||
static int
|
||||
null_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_rewind (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_flush (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_write (struct gdb_file *file,
|
||||
const char *buf,
|
||||
long sizeof_buf)
|
||||
{
|
||||
if (file->to_fputs == null_file_fputs)
|
||||
/* Both the write and fputs methods are null. Discard the
|
||||
request. */
|
||||
return;
|
||||
else
|
||||
{
|
||||
/* The fputs method isn't null, slowly pass the write request
|
||||
onto that. FYI, this isn't as bad as it may look - the
|
||||
current (as of 1999-11-07) printf_* function calls fputc and
|
||||
fputc does exactly the below. By having a write function it
|
||||
is possible to clean up that code. */
|
||||
int i;
|
||||
char b[2];
|
||||
b[1] = '\0';
|
||||
for (i = 0; i < sizeof_buf; i++)
|
||||
{
|
||||
b[0] = buf[i];
|
||||
file->to_fputs (b, file);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_fputs (buf, file)
|
||||
const char *buf;
|
||||
struct gdb_file *file;
|
||||
{
|
||||
if (file->to_write == null_file_write)
|
||||
/* Both the write and fputs methods are null. Discard the
|
||||
request. */
|
||||
return;
|
||||
else
|
||||
{
|
||||
/* The write method was implemented, use that. */
|
||||
file->to_write (file, buf, strlen (buf));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
null_file_delete (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
gdb_file_data (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
if (file->magic != &gdb_file_magic)
|
||||
internal_error ("gdb_file_data: bad magic number");
|
||||
return file->to_data;
|
||||
}
|
||||
|
||||
void
|
||||
gdb_flush (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_flush (file);
|
||||
}
|
||||
|
||||
int
|
||||
gdb_file_isatty (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
return file->to_isatty (file);
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_rewind (file)
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_rewind (file);
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_put (struct gdb_file *file,
|
||||
gdb_file_put_method_ftype *write,
|
||||
void *dest)
|
||||
{
|
||||
file->to_put (file, write, dest);
|
||||
}
|
||||
|
||||
void
|
||||
gdb_file_write (struct gdb_file *file,
|
||||
const char *buf,
|
||||
long length_buf)
|
||||
{
|
||||
file->to_write (file, buf, length_buf);
|
||||
}
|
||||
|
||||
void
|
||||
fputs_unfiltered (buf, file)
|
||||
const char *buf;
|
||||
struct gdb_file *file;
|
||||
{
|
||||
file->to_fputs (buf, file);
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_flush (file, flush)
|
||||
struct gdb_file *file;
|
||||
gdb_file_flush_ftype *flush;
|
||||
{
|
||||
file->to_flush = flush;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_isatty (file, isatty)
|
||||
struct gdb_file *file;
|
||||
gdb_file_isatty_ftype *isatty;
|
||||
{
|
||||
file->to_isatty = isatty;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_rewind (file, rewind)
|
||||
struct gdb_file *file;
|
||||
gdb_file_rewind_ftype *rewind;
|
||||
{
|
||||
file->to_rewind = rewind;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_put (file, put)
|
||||
struct gdb_file *file;
|
||||
gdb_file_put_ftype *put;
|
||||
{
|
||||
file->to_put = put;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_write (struct gdb_file *file,
|
||||
gdb_file_write_ftype *write)
|
||||
{
|
||||
file->to_write = write;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_fputs (file, fputs)
|
||||
struct gdb_file *file;
|
||||
gdb_file_fputs_ftype *fputs;
|
||||
{
|
||||
file->to_fputs = fputs;
|
||||
}
|
||||
|
||||
void
|
||||
set_gdb_file_data (file, data, delete)
|
||||
struct gdb_file *file;
|
||||
void *data;
|
||||
gdb_file_delete_ftype *delete;
|
||||
{
|
||||
file->to_data = data;
|
||||
file->to_delete = delete;
|
||||
}
|
||||
|
||||
/* gdb_file utility function for converting a ``struct gdb_file'' into
|
||||
a memory buffer''. */
|
||||
|
||||
struct accumulated_gdb_file
|
||||
{
|
||||
char *buffer;
|
||||
long length;
|
||||
};
|
||||
|
||||
static void
|
||||
do_gdb_file_xstrdup (void *context, const char *buffer, long length)
|
||||
{
|
||||
struct accumulated_gdb_file *acc = context;
|
||||
if (acc->buffer == NULL)
|
||||
acc->buffer = xmalloc (length + 1);
|
||||
else
|
||||
acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
|
||||
memcpy (acc->buffer + acc->length, buffer, length);
|
||||
acc->length += length;
|
||||
acc->buffer[acc->length] = '\0';
|
||||
}
|
||||
|
||||
char *
|
||||
gdb_file_xstrdup (struct gdb_file *file,
|
||||
long *length)
|
||||
{
|
||||
struct accumulated_gdb_file acc;
|
||||
acc.buffer = NULL;
|
||||
acc.length = 0;
|
||||
gdb_file_put (file, do_gdb_file_xstrdup, &acc);
|
||||
if (acc.buffer == NULL)
|
||||
acc.buffer = xstrdup ("");
|
||||
*length = acc.length;
|
||||
return acc.buffer;
|
||||
}
|
||||
|
||||
|
||||
/* Like fputs but if FILTER is true, pause after every screenful.
|
||||
|
||||
Regardless of FILTER can wrap at points other than the final
|
||||
|
25
gdb/valops.c
25
gdb/valops.c
@ -1292,6 +1292,7 @@ hand_function_call (function, nargs, args)
|
||||
{
|
||||
register CORE_ADDR sp;
|
||||
register int i;
|
||||
int rc;
|
||||
CORE_ADDR start_sp;
|
||||
/* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word
|
||||
is in host byte order. Before calling FIX_CALL_DUMMY, we byteswap it
|
||||
@ -1687,9 +1688,28 @@ You must use a pointer to function type variable. Command ignored.", arg_name);
|
||||
/* 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))
|
||||
rc = run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf);
|
||||
|
||||
if (rc == 1)
|
||||
{
|
||||
/* We stopped somewhere besides the call dummy. */
|
||||
/* We stopped inside the FUNCTION because of a random signal.
|
||||
Further execution of the FUNCTION is not allowed. */
|
||||
|
||||
/* In this case, we must do the cleanups because we don't
|
||||
want the dummy anymore (the dummy frame has been poped already. */
|
||||
do_cleanups (old_chain);
|
||||
|
||||
/* 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\
|
||||
Evaluation of the expression containing the function (%s) will be abandoned.",
|
||||
name);
|
||||
}
|
||||
|
||||
if (rc == 2)
|
||||
{
|
||||
/* We hit a breakpoint inside the FUNCTION. */
|
||||
|
||||
/* If we did the cleanups, we would print a spurious error
|
||||
message (Unable to restore previously selected frame),
|
||||
@ -1714,6 +1734,7 @@ stop (instead of continuing to evaluate the expression containing\n\
|
||||
the function call).", name);
|
||||
}
|
||||
|
||||
/* If we get here the called FUNCTION run to completion. */
|
||||
do_cleanups (old_chain);
|
||||
|
||||
/* Figure out the value returned by the function. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user