diff options
author | Peter Schauer <Peter.Schauer@mytum.de> | 1993-10-05 19:44:57 +0000 |
---|---|---|
committer | Peter Schauer <Peter.Schauer@mytum.de> | 1993-10-05 19:44:57 +0000 |
commit | cef4c2e7a5f2d3426a8255f74b6c7f4e795fd9a4 (patch) | |
tree | 89bc0058548c4a5ef634989a13e0a9ce0f51e3a0 /gdb | |
parent | a72e9833652c3a2e3c616b75522f7dfb462533e6 (diff) | |
download | gdb-cef4c2e7a5f2d3426a8255f74b6c7f4e795fd9a4.zip gdb-cef4c2e7a5f2d3426a8255f74b6c7f4e795fd9a4.tar.gz gdb-cef4c2e7a5f2d3426a8255f74b6c7f4e795fd9a4.tar.bz2 |
Changes to support alpha OSF/1 in native mode.
* alpha-nat.c, alpha-tdep.c, config/alpha/alpha-osf1.mt,
config/alpha/nm-alpha.h, config/alpha/tm-alpha.h, osfsolib.c:
New files.
* Makefile.in: Add new files and dependencies.
* configure.in: Add alpha target.
* config/alpha/alpha-osf1.mh (NATDEPFILES): Add osfsolib.o
* config/alpha/alpha-osf1.mh (MH_CFLAGS): Remove, we can handle
shared libraries now.
* config/alpha/xm-alpha.h: Cleanup, get MAKEVA_* defines right.
* defs.h (CORE_ADDR): Make its type overridable via CORE_ADDR_TYPE,
provide `unsigned int' default.
* breakpoint.c (breakpoint_auto_delete): Delete only if we really
stopped for the breakpoint.
* stabsread.c, stabsread.h (define_symbol): Change valu parameter
to a CORE_ADDR.
* stabsread.c (read_range_type): Handle the case where the lower
bound overflows and the upper doesn't and the range is legal.
* infrun.c (resume): Do not step a breakpoint instruction if
CANNOT_STEP_BREAKPOINT is defined.
* inferior.h (CALL_DUMMY_LOCATION): New variant AT_ENTRY_POINT.
Now that we have the bp_call_dummy breakpoint the call dummy code
is no longer needed. PUSH_DUMMY_FRAME, PUSH_ARGUMENTS and
FIX_CALL_DUMMY can be used to set up everything for the dummy.
The breakpoint for the dummy is set at the entry point and thats it.
* blockframe.c (inside_entry_file, inside_entry_func): Do not stop
backtraces if pc is in the call dummy at the entry point.
* infcmd.c (run_stack_dummy): Handle AT_ENTRY_POINT case. Use
the expected breakpoint pc when setting up the frame for
set_momentary_breakpoint.
* symfile.c (entry_point_address): New function for AT_ENTRY_POINT
support.
* valops.c (call_function_by_hand): Handle AT_ENTRY_POINT case.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/.Sanitize | 3 | ||||
-rw-r--r-- | gdb/ChangeLog | 40 | ||||
-rw-r--r-- | gdb/Makefile.in | 22 | ||||
-rw-r--r-- | gdb/alpha-nat.c | 144 | ||||
-rw-r--r-- | gdb/alpha-tdep.c | 987 | ||||
-rw-r--r-- | gdb/blockframe.c | 47 | ||||
-rw-r--r-- | gdb/breakpoint.c | 23 | ||||
-rw-r--r-- | gdb/configure.in | 3 | ||||
-rw-r--r-- | gdb/infrun.c | 10 | ||||
-rw-r--r-- | gdb/osfsolib.c | 786 | ||||
-rw-r--r-- | gdb/stabsread.c | 10 | ||||
-rw-r--r-- | gdb/stabsread.h | 2 | ||||
-rw-r--r-- | gdb/valops.c | 21 |
13 files changed, 2055 insertions, 43 deletions
diff --git a/gdb/.Sanitize b/gdb/.Sanitize index 8cfe5ad..7fe9807 100644 --- a/gdb/.Sanitize +++ b/gdb/.Sanitize @@ -42,6 +42,8 @@ TODO a29k-pinsn.c a29k-tdep.c a68v-nat.c +alpha-nat.c +alpha-tdep.c altos-xdep.c arm-convert.s arm-pinsn.c @@ -174,6 +176,7 @@ ns32k-opcode.h ns32k-pinsn.c objfiles.c objfiles.h +osfsolib.c paread.c parse.c parser-defs.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7c98ee2..0058de2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,43 @@ +Tue Oct 5 12:17:40 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + Jim Kingdon (kingdon@cygnus.com) + Stu Grossman (grossman@cygnus.com) + + Changes to support alpha OSF/1 in native mode. + * alpha-nat.c, alpha-tdep.c, config/alpha/alpha-osf1.mt, + config/alpha/nm-alpha.h, config/alpha/tm-alpha.h, osfsolib.c: + New files. + * Makefile.in: Add new files and dependencies. + * configure.in: Add alpha target. + * config/alpha/alpha-osf1.mh (NATDEPFILES): Add osfsolib.o + * config/alpha/alpha-osf1.mh (MH_CFLAGS): Remove, we can handle + shared libraries now. + * config/alpha/xm-alpha.h: Cleanup, get MAKEVA_* defines right. + + * defs.h (CORE_ADDR): Make its type overridable via CORE_ADDR_TYPE, + provide `unsigned int' default. + * breakpoint.c (breakpoint_auto_delete): Delete only if we really + stopped for the breakpoint. + * stabsread.c, stabsread.h (define_symbol): Change valu parameter + to a CORE_ADDR. + * stabsread.c (read_range_type): Handle the case where the lower + bound overflows and the upper doesn't and the range is legal. + * infrun.c (resume): Do not step a breakpoint instruction if + CANNOT_STEP_BREAKPOINT is defined. + + * inferior.h (CALL_DUMMY_LOCATION): New variant AT_ENTRY_POINT. + Now that we have the bp_call_dummy breakpoint the call dummy code + is no longer needed. PUSH_DUMMY_FRAME, PUSH_ARGUMENTS and + FIX_CALL_DUMMY can be used to set up everything for the dummy. + The breakpoint for the dummy is set at the entry point and thats it. + * blockframe.c (inside_entry_file, inside_entry_func): Do not stop + backtraces if pc is in the call dummy at the entry point. + * infcmd.c (run_stack_dummy): Handle AT_ENTRY_POINT case. Use + the expected breakpoint pc when setting up the frame for + set_momentary_breakpoint. + * symfile.c (entry_point_address): New function for AT_ENTRY_POINT + support. + * valops.c (call_function_by_hand): Handle AT_ENTRY_POINT case. + Tue Oct 5 11:37:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) * configure.in: Recognize hppa*-*-hiux* (currently synonym for hpux). diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 1ef2aae..20f1c6d 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -802,7 +802,8 @@ unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET : # why they are separate from the lists of files above. ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \ - a29k-pinsn.c a29k-tdep.c a68v-nat.c altos-xdep.c arm-convert.s \ + a29k-pinsn.c a29k-tdep.c a68v-nat.c alpha-nat.c alpha-tdep.c \ + altos-xdep.c arm-convert.s \ arm-pinsn.c arm-tdep.c arm-xdep.c coff-solib.c convex-pinsn.c \ convex-tdep.c \ convex-xdep.c core-svr4.c coredep.c corelow.c dcache.c delta68-nat.c \ @@ -810,13 +811,14 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \ go32-xdep.c gould-pinsn.c gould-xdep.c h8300-tdep.c h8500-tdep.c \ hp300ux-nat.c hppa-pinsn.c hppa-tdep.c hppab-nat.c hppah-nat.c \ i386-pinsn.c i386-tdep.c i386b-nat.c i386mach-nat.c i386v-nat.c \ - i386aix-nat.c i386v4-nat.c i386lynx-nat.c i386lynx-tdep.c i387-tdep.c \ + i386aix-nat.c i386v4-nat.c i386lynx-nat.c i386ly-tdep.c i387-tdep.c \ i960-pinsn.c i960-tdep.c \ infptrace.c inftarg.c irix4-nat.c isi-xdep.c m68k-pinsn.c m68k-tdep.c \ m88k-nat.c m88k-pinsn.c m88k-tdep.c mips-nat.c mips-pinsn.c \ mips-tdep.c news-xdep.c nindy-share/Onindy.c nindy-share/nindy.c \ nindy-share/ttyflush.c nindy-tdep.c \ - ns32k-pinsn.c paread.c procfs.c pyr-pinsn.c pyr-tdep.c pyr-xdep.c \ + ns32k-pinsn.c osfsolib.c \ + paread.c procfs.c pyr-pinsn.c pyr-tdep.c pyr-xdep.c \ remote-adapt.c remote-bug.c remote-eb.c remote-es.c remote-hms.c remote-mips.c \ remote-mm.c remote-mon.c remote-nindy.c remote-sim.c \ remote-st.c remote-utils.c dcache.c \ @@ -829,6 +831,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \ ALLPARAM = config/a29k/nm-ultra3.h config/a29k/tm-a29k.h \ config/a29k/tm-ultra3.h config/a29k/xm-ultra3.h \ + config/alpha/nm-alpha.h config/alpha/tm-alpha.h \ config/alpha/xm-alpha.h config/arm/tm-arm.h \ config/arm/xm-arm.h config/convex/tm-convex.h \ config/convex/xm-convex.h config/gould/tm-np1.h config/gould/tm-pn.h \ @@ -897,7 +900,7 @@ ALLPARAM = config/a29k/nm-ultra3.h config/a29k/tm-a29k.h \ ALLCONFIG = config/a29k/a29k-kern.mt config/a29k/a29k-udi.mt \ config/a29k/a29k.mt config/a29k/ultra3.mh config/a29k/ultra3.mt \ - config/alpha/alpha-osf1.mh \ + config/alpha/alpha-osf1.mh config/alpha/alpha-osf1.mt \ config/arm/arm.mh config/arm/arm.mt config/convex/convex.mh \ config/convex/convex.mt config/gould/np1.mh config/gould/np1.mt \ config/gould/pn.mh config/gould/pn.mt config/h8300/h8300hms.mt \ @@ -956,6 +959,12 @@ udr.o: 29k-share/udi/udr.c $(udiheaders) a29k-pinsn.o: a29k-pinsn.c $(bfd_h) $(dis-asm_h) a29k-tdep.o: a29k-tdep.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) a68v-nat.o: a68v-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +alpha-nat.o: alpha-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h + +alpha-tdep.o: alpha-tdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) $(symtab_h) $(dis-asm.h) + altos-xdep.o: altos-xdep.c $(defs_h) $(gdbcore_h) $(inferior_h) arm-pinsn.o: arm-pinsn.c $(OP_INCLUDE)/arm.h $(defs_h) $(symtab_h) @@ -1086,7 +1095,7 @@ i386-pinsn.o: i386-pinsn.c $(bfd_h) $(dis-asm_h) $(defs_h) i386-tdep.o: i386-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h i386b-nat.o: i386b-nat.c $(defs_h) i386lynx-nat.o: i386lynx-nat.c $(defs_h) $(frame_h) $(inferior_h) target.h -i386lynx-tdep.o: i386lynx-tdep.c $(defs_h) $(inferior_h) target.h +i386ly-tdep.o: i386ly-tdep.c $(defs_h) $(inferior_h) target.h i386mach-nat.o: i386mach-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) i386v-nat.o: i386v-nat.c $(ieee-float_h) $(defs_h) $(gdbcore_h) \ @@ -1184,6 +1193,9 @@ ns32k-pinsn.o: ns32k-pinsn.c $(defs_h) $(gdbcore_h) ns32k-opcode.h \ objfiles.o: objfiles.c $(bfd_h) $(defs_h) objfiles.h symfile.h \ $(symtab_h) +osfsolib.o: osfsolib.c $(command_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ + objfiles.h regex.h symfile.h target.h language.h + paread.o: paread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ gdb-stabs.h objfiles.h symfile.h $(symtab_h) diff --git a/gdb/alpha-nat.c b/gdb/alpha-nat.c new file mode 100644 index 0000000..a0c5399 --- /dev/null +++ b/gdb/alpha-nat.c @@ -0,0 +1,144 @@ +/* Low level Alpha interface, for GDB when running native. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" +#include <sys/ptrace.h> +#include <machine/reg.h> + +/* Size of elements in jmpbuf */ + +#define JB_ELEMENT_SIZE 8 + +/* The definition for JB_PC in machine/reg.h is wrong. + And we can't get at the correct definition in setjmp.h as it is + not always available (eg. if _POSIX_SOURCE is defined which is the + default). As the defintion is unlikely to change (see comment + in <setjmp.h>, define the correct value here. */ + +#undef JB_PC +#define JB_PC 2 + +/* Figure out where the longjmp will land. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target (pc) + CORE_ADDR *pc; +{ + CORE_ADDR jb_addr; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + + jb_addr = read_register(A0_REGNUM); + + if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, raw_buffer, + sizeof(CORE_ADDR))) + return 0; + + *pc = extract_address (raw_buffer, sizeof(CORE_ADDR)); + return 1; +} + +/* Extract the register values out of the core file and store + them where `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into memory. + CORE_REG_SIZE is the size of that area. + WHICH says which set of registers we are handling (0 = int, 2 = float + on machines where they are discontiguous). + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to + locate the registers in a large upage-plus-stack ".reg" section. + Original upage address X is at location core_reg_sect+x+reg_addr. + */ + +void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned reg_addr; +{ + register int regno; + register int addr; + int bad_reg = -1; + + /* Table to map a gdb regnum to an index in the core register section. + The floating point register values are garbage in OSF/1.2 core files. */ + static int core_reg_mapping[NUM_REGS] = + { +#define EFL (EF_SIZE / 8) + EF_V0, EF_T0, EF_T1, EF_T2, EF_T3, EF_T4, EF_T5, EF_T6, + EF_T7, EF_S0, EF_S1, EF_S2, EF_S3, EF_S4, EF_S5, EF_S6, + EF_A0, EF_A1, EF_A2, EF_A3, EF_A4, EF_A5, EF_T8, EF_T9, + EF_T10, EF_T11, EF_RA, EF_T12, EF_AT, EF_GP, EF_SP, -1, + EFL+0, EFL+1, EFL+2, EFL+3, EFL+4, EFL+5, EFL+6, EFL+7, + EFL+8, EFL+9, EFL+10, EFL+11, EFL+12, EFL+13, EFL+14, EFL+15, + EFL+16, EFL+17, EFL+18, EFL+19, EFL+20, EFL+21, EFL+22, EFL+23, + EFL+24, EFL+25, EFL+26, EFL+27, EFL+28, EFL+29, EFL+30, EFL+31, + EF_PC, -1 + }; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + for (regno = 0; regno < NUM_REGS; regno++) + { + if (CANNOT_FETCH_REGISTER (regno)) + { + supply_register (regno, zerobuf); + continue; + } + addr = 8 * core_reg_mapping[regno]; + if (addr < 0 || addr >= core_reg_size) + { + if (bad_reg < 0) + bad_reg = regno; + } + else + { + supply_register (regno, core_reg_sect + addr); + } + } + if (bad_reg >= 0) + { + error ("Register %s not found in core file.", reg_names[bad_reg]); + } +} + +/* Map gdb internal register number to a ptrace ``address''. + These ``addresses'' are defined in <sys/ptrace.h> */ + +#define REGISTER_PTRACE_ADDR(regno) \ + (regno < FP0_REGNUM ? GPR_BASE + (regno) \ + : regno == PC_REGNUM ? PC \ + : regno >= FP0_REGNUM ? FPR_BASE + ((regno) - FP0_REGNUM) \ + : 0) + +/* Return the ptrace ``address'' of register REGNO. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + return REGISTER_PTRACE_ADDR (regno); +} diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c new file mode 100644 index 0000000..57e098f --- /dev/null +++ b/gdb/alpha-tdep.c @@ -0,0 +1,987 @@ +/* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "dis-asm.h" + +/* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */ + +#define VM_MIN_ADDRESS (CORE_ADDR)0x120000000 + + +/* Forward declarations. */ + +static CORE_ADDR +read_next_frame_reg PARAMS ((FRAME, int)); + +static CORE_ADDR +heuristic_proc_start PARAMS ((CORE_ADDR)); + +static alpha_extra_func_info_t +heuristic_proc_desc PARAMS ((CORE_ADDR, CORE_ADDR, FRAME)); + +static alpha_extra_func_info_t +find_proc_desc PARAMS ((CORE_ADDR, FRAME)); + +static int +alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR)); + +static void +reinit_frame_cache_sfunc PARAMS ((char *, int, struct cmd_list_element *)); + +void +_initialize_alpha_tdep PARAMS ((void)); + +/* Heuristic_proc_start may hunt through the text section for a long + time across a 2400 baud serial line. Allows the user to limit this + search. */ +static unsigned int heuristic_fence_post = 0; + +/* Layout of a stack frame on the alpha: + + | | + pdr members: | 7th ... nth arg, | + | `pushed' by caller. | + | | +----------------|-------------------------------|<-- old_sp == vfp + ^ ^ ^ ^ | | + | | | | | | + | |localoff | Copies of 1st .. 6th | + | | | | | argument if necessary. | + | | | v | | + | | | --- |-------------------------------|<-- FRAME_ARGS_ADDRESS, + | | | | | FRAME_LOCALS_ADDRESS + | | | | Locals and temporaries. | + | | | | | + | | | |-------------------------------| + | | | | | + |-fregoffset | Saved float registers. | + | | | | F9 | + | | | | . | + | | | | . | + | | | | F2 | + | | v | | + | | -------|-------------------------------| + | | | | + | | | Saved registers. | + | | | S6 | + |-regoffset | . | + | | | . | + | | | S0 | + | | | pdr.pcreg | + | v | | + | ----------|-------------------------------| + | | | + frameoffset | Argument build area, gets | + | | 7th ... nth arg for any | + | | called procedure. | + v | | + -------------|-------------------------------|<-- sp + | | +*/ + +#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */ +#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */ +#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.iopt) /* frame for CALL_DUMMY */ +#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) +#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg) +#define PROC_REG_MASK(proc) ((proc)->pdr.regmask) +#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask) +#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset) +#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset) +#define PROC_PC_REG(proc) ((proc)->pdr.pcreg) +#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff) +#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym) +#define _PROC_MAGIC_ 0x0F0F0F0F +#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_) +#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym = _PROC_MAGIC_) + +struct linked_proc_info +{ + struct alpha_extra_func_info info; + struct linked_proc_info *next; +} *linked_proc_desc_table = NULL; + + +#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno) + +static CORE_ADDR +read_next_frame_reg(fi, regno) + FRAME fi; + int regno; +{ + /* If it is the frame for sigtramp we have a pointer to the sigcontext + on the stack. + If the stack layout for __sigtramp changes or if sigcontext offsets + change we might have to update this code. */ +#ifndef SIGFRAME_PC_OFF +#define SIGFRAME_PC_OFF (2 * 8) +#define SIGFRAME_REGSAVE_OFF (4 * 8) +#endif + for (; fi; fi = fi->next) + { + if (fi->signal_handler_caller) + { + int offset; + CORE_ADDR sigcontext_addr = read_memory_integer(fi->frame, 8); + + if (regno == PC_REGNUM) + offset = SIGFRAME_PC_OFF; + else if (regno < 32) + offset = SIGFRAME_REGSAVE_OFF + regno * 8; + else + return 0; + return read_memory_integer(sigcontext_addr + offset, 8); + } + else if (regno == SP_REGNUM) + return fi->frame; + else if (fi->saved_regs->regs[regno]) + return read_memory_integer(fi->saved_regs->regs[regno], 8); + } + return read_register(regno); +} + +CORE_ADDR +alpha_frame_saved_pc(frame) + FRAME frame; +{ + alpha_extra_func_info_t proc_desc = frame->proc_desc; + int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM; + + if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) + return read_memory_integer(frame->frame - 8, 8); + + return read_next_frame_reg(frame, pcreg); +} + +CORE_ADDR +alpha_saved_pc_after_call (frame) + FRAME frame; +{ + alpha_extra_func_info_t proc_desc = find_proc_desc (frame->pc, frame->next); + int pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM; + + return read_register (pcreg); +} + + +static struct alpha_extra_func_info temp_proc_desc; +static struct frame_saved_regs temp_saved_regs; + +/* This fencepost looks highly suspicious to me. Removing it also + seems suspicious as it could affect remote debugging across serial + lines. */ + +static CORE_ADDR +heuristic_proc_start(pc) + CORE_ADDR pc; +{ + CORE_ADDR start_pc = pc; + CORE_ADDR fence = start_pc - heuristic_fence_post; + + if (start_pc == 0) return 0; + + if (heuristic_fence_post == UINT_MAX + || fence < VM_MIN_ADDRESS) + fence = VM_MIN_ADDRESS; + + /* search back for previous return */ + for (start_pc -= 4; ; start_pc -= 4) + if (start_pc < fence) + { + /* It's not clear to me why we reach this point when + stop_soon_quietly, but with this test, at least we + don't print out warnings for every child forked (eg, on + decstation). 22apr93 rich@cygnus.com. */ + if (!stop_soon_quietly) + { + static int blurb_printed = 0; + + if (fence == VM_MIN_ADDRESS) + warning("Hit beginning of text section without finding"); + else + warning("Hit heuristic-fence-post without finding"); + + warning("enclosing function for address 0x%lx", pc); + if (!blurb_printed) + { + printf_filtered ("\ +This warning occurs if you are debugging a function without any symbols\n\ +(for example, in a stripped executable). In that case, you may wish to\n\ +increase the size of the search with the `set heuristic-fence-post' command.\n\ +\n\ +Otherwise, you told GDB there was a function where there isn't one, or\n\ +(more likely) you have encountered a bug in GDB.\n"); + blurb_printed = 1; + } + } + + return 0; + } + else if (ABOUT_TO_RETURN(start_pc)) + break; + + start_pc += 4; /* skip return */ + return start_pc; +} + +static alpha_extra_func_info_t +heuristic_proc_desc(start_pc, limit_pc, next_frame) + CORE_ADDR start_pc, limit_pc; + FRAME next_frame; +{ + CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM); + CORE_ADDR cur_pc; + int frame_size; + int has_frame_reg = 0; + unsigned long reg_mask = 0; + + if (start_pc == 0) + return NULL; + memset(&temp_proc_desc, '\0', sizeof(temp_proc_desc)); + memset(&temp_saved_regs, '\0', sizeof(struct frame_saved_regs)); + PROC_LOW_ADDR(&temp_proc_desc) = start_pc; + + if (start_pc + 200 < limit_pc) + limit_pc = start_pc + 200; + frame_size = 0; + for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) + { + char buf[4]; + unsigned long word; + int status; + + status = read_memory_nobpt (cur_pc, buf, 4); + if (status) + memory_error (status, cur_pc); + word = extract_unsigned_integer (buf, 4); + + if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ + frame_size += (-word) & 0xffff; + else if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ + && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ + { + int reg = (word & 0x03e00000) >> 21; + reg_mask |= 1 << reg; + temp_saved_regs.regs[reg] = sp + (short)word; + } + else if (word == 0x47de040f) /* bis sp,sp fp */ + has_frame_reg = 1; + } + if (has_frame_reg) + PROC_FRAME_REG(&temp_proc_desc) = GCC_FP_REGNUM; + else + PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM; + PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size; + PROC_REG_MASK(&temp_proc_desc) = reg_mask; + PROC_PC_REG(&temp_proc_desc) = RA_REGNUM; + return &temp_proc_desc; +} + +static alpha_extra_func_info_t +find_proc_desc(pc, next_frame) + CORE_ADDR pc; + FRAME next_frame; +{ + alpha_extra_func_info_t proc_desc; + struct block *b; + struct symbol *sym; + CORE_ADDR startaddr; + + /* Try to get the proc_desc from the linked call dummy proc_descs + if the pc is in the call dummy. + This is hairy. In the case of nested dummy calls we have to find the + right proc_desc, but we might not yet know the frame for the dummy + as it will be contained in the proc_desc we are searching for. + So we have to find the proc_desc whose frame is closest to the current + stack pointer. */ + if (PC_IN_CALL_DUMMY (pc, 0, 0)) + { + struct linked_proc_info *link; + CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM); + alpha_extra_func_info_t found_proc_desc = NULL; + long min_distance = LONG_MAX; + + for (link = linked_proc_desc_table; link; link = link->next) + { + long distance = (CORE_ADDR) PROC_DUMMY_FRAME (&link->info) - sp; + if (distance > 0 && distance < min_distance) + { + min_distance = distance; + found_proc_desc = &link->info; + } + } + if (found_proc_desc != NULL) + return found_proc_desc; + } + + b = block_for_pc(pc); + find_pc_partial_function (pc, NULL, &startaddr, NULL); + if (b == NULL) + sym = NULL; + else + { + if (startaddr > BLOCK_START (b)) + /* This is the "pathological" case referred to in a comment in + print_frame_info. It might be better to move this check into + symbol reading. */ + sym = NULL; + else + sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, + 0, NULL); + } + + if (sym) + { + /* IF (this is the topmost frame OR a frame interrupted by a signal) + * AND (this proc does not have debugging information OR + * the PC is in the procedure prologue) + * THEN create a "heuristic" proc_desc (by analyzing + * the actual code) to replace the "official" proc_desc. + */ + proc_desc = (alpha_extra_func_info_t)SYMBOL_VALUE(sym); + if (next_frame == NULL || next_frame->signal_handler_caller) { + struct symtab_and_line val; + struct symbol *proc_symbol = + PROC_DESC_IS_DUMMY(proc_desc) ? 0 : PROC_SYMBOL(proc_desc); + + if (proc_symbol) { + val = find_pc_line (BLOCK_START + (SYMBOL_BLOCK_VALUE(proc_symbol)), + 0); + val.pc = val.end ? val.end : pc; + } + if (!proc_symbol || pc < val.pc) { + alpha_extra_func_info_t found_heuristic = + heuristic_proc_desc(PROC_LOW_ADDR(proc_desc), + pc, next_frame); + if (found_heuristic) + { + /* The call to heuristic_proc_desc determines + which registers have been saved so far and if the + frame is already set up. + The heuristic algorithm doesn't work well for other + information in the procedure descriptor, so copy + it from the found procedure descriptor. */ + PROC_LOCALOFF(found_heuristic) = PROC_LOCALOFF(proc_desc); + PROC_PC_REG(found_heuristic) = PROC_PC_REG(proc_desc); + proc_desc = found_heuristic; + } + } + } + } + else + { + if (startaddr == 0) + startaddr = heuristic_proc_start (pc); + + proc_desc = + heuristic_proc_desc (startaddr, pc, next_frame); + } + return proc_desc; +} + +alpha_extra_func_info_t cached_proc_desc; + +FRAME_ADDR +alpha_frame_chain(frame) + FRAME frame; +{ + alpha_extra_func_info_t proc_desc; + CORE_ADDR saved_pc = FRAME_SAVED_PC(frame); + + if (saved_pc == 0 || inside_entry_file (saved_pc)) + return 0; + + proc_desc = find_proc_desc(saved_pc, frame); + if (!proc_desc) + return 0; + + cached_proc_desc = proc_desc; + + /* Fetch the frame pointer for a dummy frame from the procedure + descriptor. */ + if (PROC_DESC_IS_DUMMY(proc_desc)) + return (FRAME_ADDR) PROC_DUMMY_FRAME(proc_desc); + + /* If no frame pointer and frame size is zero, we must be at end + of stack (or otherwise hosed). If we don't check frame size, + we loop forever if we see a zero size frame. */ + if (PROC_FRAME_REG (proc_desc) == SP_REGNUM + && PROC_FRAME_OFFSET (proc_desc) == 0 + /* The alpha __sigtramp routine is frameless and has a frame size + of zero. Luckily it is the only procedure which has PC_REGNUM + as PROC_PC_REG. */ + && PROC_PC_REG (proc_desc) != PC_REGNUM + /* The previous frame from a sigtramp frame might be frameless + and have frame size zero. */ + && !frame->signal_handler_caller) + return 0; + else + return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc)) + + PROC_FRAME_OFFSET(proc_desc); +} + +void +init_extra_frame_info(fci) + struct frame_info *fci; +{ + extern struct obstack frame_cache_obstack; + /* Use proc_desc calculated in frame_chain */ + alpha_extra_func_info_t proc_desc = + fci->next ? cached_proc_desc : find_proc_desc(fci->pc, fci->next); + + fci->saved_regs = (struct frame_saved_regs*) + obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs)); + memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs)); + fci->proc_desc = + proc_desc == &temp_proc_desc ? 0 : proc_desc; + if (proc_desc) + { + int ireg; + CORE_ADDR reg_position; + unsigned long mask; + int returnreg; + + /* Get the locals offset from the procedure descriptor, it is valid + even if we are in the middle of the prologue. */ + fci->localoff = PROC_LOCALOFF(proc_desc); + + /* FIXME: This is a kludge for gcc-2.4.5. + gcc-2.4.5 builds frames for the alpha in a peculiar way. + It uses $fp as a frame register (which seems to be identical to $sp + in all procedures that do not use alloca). + It has the arguments and the locals above the frame register, if + there are few arguments then the locals are above the arguments, + otherwise the arguments are above the local. + Frame offsets for arguments and locals are relative to $fp and always + positive. + If we want to stay compatible with the native cc compiler we have + to set localoff to frameoffset so that FRAME_ARGS_ADDRESS and + FRAME_LOCALS_ADDRESS point to the right place in the frame. + Please note that the setting of localoff in the compiler won't work + as localoff is only 8 bits wide (which is enough for cc as it needs + at most number_of_arg_regs * 8 == 48). */ + if (PROC_FRAME_REG(proc_desc) == GCC_FP_REGNUM) + fci->localoff = PROC_FRAME_OFFSET(proc_desc); + + /* Fixup frame-pointer - only needed for top frame */ + /* Fetch the frame pointer for a dummy frame from the procedure + descriptor. */ + if (PROC_DESC_IS_DUMMY(proc_desc)) + fci->frame = (FRAME_ADDR) PROC_DUMMY_FRAME(proc_desc); + /* This may not be quite right, if proc has a real frame register. + Get the value of the frame relative sp, procedure might have been + interrupted by a signal at it's very start. */ + else if (fci->pc == PROC_LOW_ADDR(proc_desc)) + fci->frame = READ_FRAME_REG(fci, SP_REGNUM); + else + fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc)) + + PROC_FRAME_OFFSET(proc_desc); + + /* If this is the innermost frame, and we are still in the + prologue (loosely defined), then the registers may not have + been saved yet. */ + if (fci->next == NULL + && !PROC_DESC_IS_DUMMY(proc_desc) + && alpha_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc)) + { + /* Can't just say that the registers are not saved, because they + might get clobbered halfway through the prologue. + heuristic_proc_desc already has the right code to figure out + exactly what has been saved, so use it. As far as I know we + could be doing this (as we do on the 68k, for example) + regardless of whether we are in the prologue; I'm leaving in + the check for being in the prologue only out of conservatism + (I'm not sure whether heuristic_proc_desc handles all cases, + for example). + + This stuff is ugly (and getting uglier by the minute). Probably + the best way to clean it up is to ignore the proc_desc's from + the symbols altogher, and get all the information we need by + examining the prologue (provided we can make the prologue + examining code good enough to get all the cases...). */ + proc_desc = + heuristic_proc_desc (PROC_LOW_ADDR (proc_desc), + fci->pc, + fci->next); + } + + if (proc_desc == &temp_proc_desc) + *fci->saved_regs = temp_saved_regs; + else + { + /* Find which general-purpose registers were saved. + The return address register is the first saved register, + the other registers follow in ascending order. */ + reg_position = fci->frame + PROC_REG_OFFSET(proc_desc); + mask = PROC_REG_MASK(proc_desc) & 0xffffffffL; + returnreg = PROC_PC_REG(proc_desc); + if (mask & (1 << returnreg)) + { + fci->saved_regs->regs[returnreg] = reg_position; + reg_position += 8; + } + for (ireg = 0; mask; ireg++, mask >>= 1) + if (mask & 1) + { + if (ireg == returnreg) + continue; + fci->saved_regs->regs[ireg] = reg_position; + reg_position += 8; + } + /* find which floating-point registers were saved */ + reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc); + mask = PROC_FREG_MASK(proc_desc) & 0xffffffffL; + for (ireg = 0; mask; ireg++, mask >>= 1) + if (mask & 1) + { + fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position; + reg_position += 8; + } + } + + fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[PROC_PC_REG(proc_desc)]; + } +} + +/* ALPHA stack frames are almost impenetrable. When execution stops, + we basically have to look at symbol information for the function + that we stopped in, which tells us *which* register (if any) is + the base of the frame pointer, and what offset from that register + the frame itself is at. + + This presents a problem when trying to examine a stack in memory + (that isn't executing at the moment), using the "frame" command. We + don't have a PC, nor do we have any registers except SP. + + This routine takes two arguments, SP and PC, and tries to make the + cached frames look as if these two arguments defined a frame on the + cache. This allows the rest of info frame to extract the important + arguments without difficulty. */ + +FRAME +setup_arbitrary_frame (argc, argv) + int argc; + FRAME_ADDR *argv; +{ + if (argc != 2) + error ("ALPHA frame specifications require two arguments: sp and pc"); + + return create_new_frame (argv[0], argv[1]); +} + +/* The alpha passes the first six arguments in the registers, the rest on + the stack. The register arguments are eventually transferred to the + argument transfer area immediately below the stack by the called function + anyway. So we `push' at least six arguments on the stack, `reload' the + argument registers and then adjust the stack pointer to point past the + sixth argument. This algorithm simplifies the passing of a large struct + which extends from the registers to the stack. + If the called function is returning a structure, the address of the + structure to be returned is passed as a hidden first argument. */ + +#define NUM_ARG_REGS 6 + +CORE_ADDR +alpha_push_arguments (nargs, args, sp, struct_return, struct_addr) + int nargs; + value *args; + CORE_ADDR sp; + int struct_return; + CORE_ADDR struct_addr; +{ + register i; + int accumulate_size = struct_return ? 8 : 0; + int arg_regs_size = NUM_ARG_REGS * 8; + struct alpha_arg { char *contents; int len; int offset; }; + struct alpha_arg *alpha_args = + (struct alpha_arg*)alloca (nargs * sizeof (struct alpha_arg)); + register struct alpha_arg *m_arg; + char raw_buffer[sizeof (CORE_ADDR)]; + int required_arg_regs; + + for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++) + { + value arg = value_arg_coerce (args[i]); + /* Cast argument to long if necessary as the compiler does it too. */ + if (TYPE_LENGTH (VALUE_TYPE (arg)) < TYPE_LENGTH (builtin_type_long)) + arg = value_cast (builtin_type_long, arg); + m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg)); + m_arg->offset = accumulate_size; + accumulate_size = (accumulate_size + m_arg->len + 7) & ~7; + m_arg->contents = VALUE_CONTENTS(arg); + } + + /* Determine required argument register loads, loading an argument register + is expensive as it uses three ptrace calls. */ + required_arg_regs = accumulate_size / 8; + if (required_arg_regs > NUM_ARG_REGS) + required_arg_regs = NUM_ARG_REGS; + + /* Make room for the arguments on the stack. */ + if (accumulate_size < arg_regs_size) + accumulate_size = arg_regs_size; + sp -= accumulate_size; + + /* Keep sp aligned to a multiple of 16 as the compiler does it too. */ + sp &= ~15; + + /* `Push' arguments on the stack. */ + for (i = nargs; m_arg--, --i >= 0; ) + write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len); + if (struct_return) + { + store_address (raw_buffer, sizeof (CORE_ADDR), struct_addr); + write_memory (sp, raw_buffer, sizeof (CORE_ADDR)); + } + + /* Load the argument registers. */ + for (i = 0; i < required_arg_regs; i++) + { + LONGEST val; + + val = read_memory_integer (sp + i * 8, 8); + write_register (A0_REGNUM + i, val); + write_register (FPA0_REGNUM + i, val); + } + + return sp + arg_regs_size; +} + +void +alpha_push_dummy_frame() +{ + int ireg; + struct linked_proc_info *link = (struct linked_proc_info*) + xmalloc(sizeof (struct linked_proc_info)); + alpha_extra_func_info_t proc_desc = &link->info; + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR save_address; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + unsigned long mask; + + link->next = linked_proc_desc_table; + linked_proc_desc_table = link; + + /* + * The registers we must save are all those not preserved across + * procedure calls. + * In addition, we must save the PC and RA. + * + * Dummy frame layout: + * (high memory) + * Saved PC + * Saved F30 + * ... + * Saved F0 + * Saved R29 + * ... + * Saved R0 + * Saved R26 (RA) + * Parameter build area + * (low memory) + */ + +/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */ +#define MASK(i,j) (((1L << ((j)+1)) - 1) ^ ((1L << (i)) - 1)) +#define GEN_REG_SAVE_MASK (MASK(0,8) | MASK(16,29)) +#define GEN_REG_SAVE_COUNT 24 +#define FLOAT_REG_SAVE_MASK (MASK(0,1) | MASK(10,30)) +#define FLOAT_REG_SAVE_COUNT 23 + /* The special register is the PC as we have no bit for it in the save masks. + alpha_frame_saved_pc knows where the pc is saved in a dummy frame. */ +#define SPECIAL_REG_SAVE_COUNT 1 + + PROC_REG_MASK(proc_desc) = GEN_REG_SAVE_MASK; + PROC_FREG_MASK(proc_desc) = FLOAT_REG_SAVE_MASK; + /* PROC_REG_OFFSET is the offset from the dummy frame to the saved RA, + but keep SP aligned to a multiple of 16. */ + PROC_REG_OFFSET(proc_desc) = + - ((8 * (SPECIAL_REG_SAVE_COUNT + + GEN_REG_SAVE_COUNT + + FLOAT_REG_SAVE_COUNT) + + 15) & ~15); + PROC_FREG_OFFSET(proc_desc) = + PROC_REG_OFFSET(proc_desc) + 8 * GEN_REG_SAVE_COUNT; + + /* Save general registers. + The return address register is the first saved register, all other + registers follow in ascending order. + The PC is saved immediately below the SP. */ + save_address = sp + PROC_REG_OFFSET(proc_desc); + store_address (raw_buffer, 8, read_register (RA_REGNUM)); + write_memory (save_address, raw_buffer, 8); + save_address += 8; + mask = PROC_REG_MASK(proc_desc) & 0xffffffffL; + for (ireg = 0; mask; ireg++, mask >>= 1) + if (mask & 1) + { + if (ireg == RA_REGNUM) + continue; + store_address (raw_buffer, 8, read_register (ireg)); + write_memory (save_address, raw_buffer, 8); + save_address += 8; + } + + store_address (raw_buffer, 8, read_register (PC_REGNUM)); + write_memory (sp - 8, raw_buffer, 8); + + /* Save floating point registers. */ + save_address = sp + PROC_FREG_OFFSET(proc_desc); + mask = PROC_FREG_MASK(proc_desc) & 0xffffffffL; + for (ireg = 0; mask; ireg++, mask >>= 1) + if (mask & 1) + { + store_address (raw_buffer, 8, read_register (ireg + FP0_REGNUM)); + write_memory (save_address, raw_buffer, 8); + save_address += 8; + } + + /* Set and save the frame address for the dummy. + This is tricky. The only registers that are suitable for a frame save + are those that are preserved across procedure calls (s0-s6). But if + a read system call is interrupted and then a dummy call is made + (see testsuite/gdb.t17/interrupt.exp) the dummy call hangs till the read + is satisfied. Then it returns with the s0-s6 registers set to the values + on entry to the read system call and our dummy frame pointer would be + destroyed. So we save the dummy frame in the proc_desc and handle the + retrieval of the frame pointer of a dummy specifically. The frame register + is set to the virtual frame (pseudo) register, it's value will always + be read as zero and will help us to catch any errors in the dummy frame + retrieval code. */ + PROC_DUMMY_FRAME(proc_desc) = sp; + PROC_FRAME_REG(proc_desc) = FP_REGNUM; + PROC_FRAME_OFFSET(proc_desc) = 0; + sp += PROC_REG_OFFSET(proc_desc); + write_register (SP_REGNUM, sp); + + PROC_LOW_ADDR(proc_desc) = entry_point_address (); + PROC_HIGH_ADDR(proc_desc) = PROC_LOW_ADDR(proc_desc) + 4; + + SET_PROC_DESC_IS_DUMMY(proc_desc); + PROC_PC_REG(proc_desc) = RA_REGNUM; +} + +void +alpha_pop_frame() +{ + register int regnum; + FRAME frame = get_current_frame (); + CORE_ADDR new_sp = frame->frame; + + alpha_extra_func_info_t proc_desc = frame->proc_desc; + + write_register (PC_REGNUM, FRAME_SAVED_PC(frame)); + if (proc_desc) + { + for (regnum = 32; --regnum >= 0; ) + if (PROC_REG_MASK(proc_desc) & (1 << regnum)) + write_register (regnum, + read_memory_integer (frame->saved_regs->regs[regnum], + 8)); + for (regnum = 32; --regnum >= 0; ) + if (PROC_FREG_MASK(proc_desc) & (1 << regnum)) + write_register (regnum + FP0_REGNUM, + read_memory_integer (frame->saved_regs->regs[regnum + FP0_REGNUM], 8)); + } + write_register (SP_REGNUM, new_sp); + flush_cached_frames (); + /* We let init_extra_frame_info figure out the frame pointer */ + set_current_frame (create_new_frame (0, read_pc ())); + + if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) + { + struct linked_proc_info *pi_ptr, *prev_ptr; + + for (pi_ptr = linked_proc_desc_table, prev_ptr = NULL; + pi_ptr != NULL; + prev_ptr = pi_ptr, pi_ptr = pi_ptr->next) + { + if (&pi_ptr->info == proc_desc) + break; + } + + if (pi_ptr == NULL) + error ("Can't locate dummy extra frame info\n"); + + if (prev_ptr != NULL) + prev_ptr->next = pi_ptr->next; + else + linked_proc_desc_table = pi_ptr->next; + + free (pi_ptr); + } +} + +/* To skip prologues, I use this predicate. Returns either PC itself + if the code at PC does not look like a function prologue; otherwise + returns an address that (if we're lucky) follows the prologue. If + LENIENT, then we must skip everything which is involved in setting + up the frame (it's OK to skip more, just so long as we don't skip + anything which might clobber the registers which are being saved. + Currently we must not skip more on the alpha, but we might the lenient + stuff some day. */ + +CORE_ADDR +alpha_skip_prologue (pc, lenient) + CORE_ADDR pc; + int lenient; +{ + unsigned long inst; + int offset; + + /* Skip the typical prologue instructions. These are the stack adjustment + instruction and the instructions that save registers on the stack + or in the gcc frame. */ + for (offset = 0; offset < 100; offset += 4) + { + char buf[4]; + int status; + + status = read_memory_nobpt (pc + offset, buf, 4); + if (status) + memory_error (status, pc + offset); + inst = extract_unsigned_integer (buf, 4); + + /* The alpha has no delay slots. But let's keep the lenient stuff, + we might need it for something else in the future. */ + if (lenient && 0) + continue; + + if ((inst & 0xffff0000) == 0x27bb0000) /* ldah $gp,n($t12) */ + continue; + if ((inst & 0xffff0000) == 0x23bd0000) /* lda $gp,n($gp) */ + continue; + if ((inst & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ + continue; + else if ((inst & 0xfc1f0000) == 0xb41e0000 + && (inst & 0xffff0000) != 0xb7fe0000) + continue; /* stq reg,n($sp) */ + /* reg != $zero */ + else if ((inst & 0xfc1f0000) == 0x9c1e0000 + && (inst & 0xffff0000) != 0x9ffe0000) + continue; /* stt reg,n($sp) */ + /* reg != $zero */ + else if (inst == 0x47de040f) /* bis sp,sp,fp */ + continue; + else + break; + } + return pc + offset; +} + +/* Is address PC in the prologue (loosely defined) for function at + STARTADDR? */ + +static int +alpha_in_lenient_prologue (startaddr, pc) + CORE_ADDR startaddr; + CORE_ADDR pc; +{ + CORE_ADDR end_prologue = alpha_skip_prologue (startaddr, 1); + return pc >= startaddr && pc < end_prologue; +} + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ +void +alpha_extract_return_value (valtype, regbuf, valbuf) + struct type *valtype; + char regbuf[REGISTER_BYTES]; + char *valbuf; +{ + int regnum; + + regnum = TYPE_CODE (valtype) == TYPE_CODE_FLT ? FP0_REGNUM : V0_REGNUM; + + memcpy (valbuf, regbuf + REGISTER_BYTE (regnum), TYPE_LENGTH (valtype)); +} + +/* Given a return value in `regbuf' with a type `valtype', + write it's value into the appropriate register. */ +void +alpha_store_return_value (valtype, valbuf) + struct type *valtype; + char *valbuf; +{ + int regnum; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + + regnum = TYPE_CODE (valtype) == TYPE_CODE_FLT ? FP0_REGNUM : V0_REGNUM; + memcpy(raw_buffer, valbuf, TYPE_LENGTH (valtype)); + + write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype)); +} + +/* Print the instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + disassemble_info info; + + GDB_INIT_DISASSEMBLE_INFO(info, stream); + + return print_insn_alpha (memaddr, &info); +} + +/* Just like reinit_frame_cache, but with the right arguments to be + callable as an sfunc. */ +static void +reinit_frame_cache_sfunc (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + reinit_frame_cache (); +} + +void +_initialize_alpha_tdep () +{ + struct cmd_list_element *c; + + /* Let the user set the fence post for heuristic_proc_start. */ + + /* We really would like to have both "0" and "unlimited" work, but + command.c doesn't deal with that. So make it a var_zinteger + because the user can always use "999999" or some such for unlimited. */ + c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger, + (char *) &heuristic_fence_post, + "\ +Set the distance searched for the start of a function.\n\ +If you are debugging a stripped executable, GDB needs to search through the\n\ +program for the start of a function. This command sets the distance of the\n\ +search. The only need to set it is when debugging a stripped executable.", + &setlist); + /* We need to throw away the frame cache when we set this, since it + might change our ability to get backtraces. */ + c->function.sfunc = reinit_frame_cache_sfunc; + add_show_from_set (c, &showlist); +} diff --git a/gdb/blockframe.c b/gdb/blockframe.c index a61face..7acbf6a 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -45,6 +45,12 @@ inside_entry_file (addr) return 1; if (symfile_objfile == 0) return 0; +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + /* Do not stop backtracing if the pc is in the call dummy + at the entry point. */ + if (PC_IN_CALL_DUMMY (addr, 0, 0)) + return 0; +#endif return (addr >= symfile_objfile -> ei.entry_file_lowpc && addr < symfile_objfile -> ei.entry_file_highpc); } @@ -85,6 +91,12 @@ CORE_ADDR pc; return 1; if (symfile_objfile == 0) return 0; +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + /* Do not stop backtracing if the pc is in the call dummy + at the entry point. */ + if (PC_IN_CALL_DUMMY (pc, 0, 0)) + return 0; +#endif return (symfile_objfile -> ei.entry_func_lowpc <= pc && symfile_objfile -> ei.entry_func_highpc > pc); } @@ -653,23 +665,26 @@ find_pc_partial_function (pc, name, address, endaddr) goto return_cached_value; } } - - /* Now that static symbols go in the minimal symbol table, perhaps - we could just ignore the partial symbols. But at least for now - we use the partial or minimal symbol, whichever is larger. */ - psb = find_pc_psymbol (pst, pc); - - if (psb - && (msymbol == NULL || - (SYMBOL_VALUE_ADDRESS (psb) >= SYMBOL_VALUE_ADDRESS (msymbol)))) + else { - /* This case isn't being cached currently. */ - if (address) - *address = SYMBOL_VALUE_ADDRESS (psb); - if (name) - *name = SYMBOL_NAME (psb); - /* endaddr non-NULL can't happen here. */ - return 1; + /* Now that static symbols go in the minimal symbol table, perhaps + we could just ignore the partial symbols. But at least for now + we use the partial or minimal symbol, whichever is larger. */ + psb = find_pc_psymbol (pst, pc); + + if (psb + && (msymbol == NULL || + (SYMBOL_VALUE_ADDRESS (psb) + >= SYMBOL_VALUE_ADDRESS (msymbol)))) + { + /* This case isn't being cached currently. */ + if (address) + *address = SYMBOL_VALUE_ADDRESS (psb); + if (name) + *name = SYMBOL_NAME (psb); + /* endaddr non-NULL can't happen here. */ + return 1; + } } } diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index faa3da4..b425ac1 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -494,11 +494,11 @@ remove_breakpoints () b->inserted = 0; #ifdef BREAKPOINT_DEBUG printf ("Removed breakpoint at %s", - local_hex_string(b->address)); + local_hex_string((unsigned long) b->address)); printf (", shadow %s", - local_hex_string(b->shadow_contents[0])); + local_hex_string((unsigned long) b->shadow_contents[0])); printf (", %s.\n", - local_hex_string(b->shadow_contents[1])); + local_hex_string((unsigned long) b->shadow_contents[1])); #endif /* BREAKPOINT_DEBUG */ } @@ -945,8 +945,8 @@ watchpoint_check (p) { /* We use value_{,free_to_}mark because it could be a *long* time before we return to the command level and - call free_all_values. */ - /* But couldn't we just call free_all_values instead? */ + call free_all_values. We can't call free_all_values because + we might be in the middle of evaluating a function call. */ value mark = value_mark (); value new_val = evaluate_expression (bs->breakpoint_at->exp); @@ -1252,6 +1252,8 @@ bpstat_what (bs) enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING; struct bpstat_what retval; + retval.call_dummy = 0; + retval.step_resume = 0; for (; bs != NULL; bs = bs->next) { enum class bs_class = no_effect; @@ -1396,7 +1398,7 @@ breakpoint_1 (bnum, allflag) case bp_step_resume: case bp_call_dummy: if (addressprint) - printf_filtered ("%s ", local_hex_string_custom(b->address, "08")); + printf_filtered ("%s ", local_hex_string_custom ((unsigned long) b->address, "08l")); last_addr = b->address; if (b->source_file) @@ -1421,7 +1423,7 @@ breakpoint_1 (bnum, allflag) if (b->frame) printf_filtered ("\tstop only in stack frame at %s\n", - local_hex_string(b->frame)); + local_hex_string((unsigned long) b->frame)); if (b->cond) { printf_filtered ("\tstop only if "); @@ -1510,7 +1512,7 @@ describe_other_breakpoints (pc) (b->enable == disabled) ? " (disabled)" : "", (others > 1) ? "," : ((others == 1) ? " and" : "")); } - printf ("also set at pc %s.\n", local_hex_string(pc)); + printf ("also set at pc %s.\n", local_hex_string((unsigned long) pc)); } } @@ -1744,7 +1746,7 @@ mention (b) break; case bp_breakpoint: printf_filtered ("Breakpoint %d at %s", b->number, - local_hex_string(b->address)); + local_hex_string((unsigned long) b->address)); if (b->source_file) printf_filtered (": file %s, line %d.", b->source_file, b->line_number); @@ -2503,7 +2505,8 @@ breakpoint_auto_delete (bs) bpstat bs; { for (; bs; bs = bs->next) - if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete) + if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete + && bs->stop) delete_breakpoint (bs->breakpoint_at); } diff --git a/gdb/configure.in b/gdb/configure.in index 1d2d2a2..f2d0241 100644 --- a/gdb/configure.in +++ b/gdb/configure.in @@ -130,6 +130,7 @@ hostfile=`awk '$1 == "XM_FILE=" { print $2 }' <${srcdir}/config/${gdb_host_cpu}/ case "${target_cpu}" in +alpha) gdb_target_cpu=alpha ;; c[12]) gdb_target_cpu=convex ;; hppa*) gdb_target_cpu=pa ;; i[34]86) gdb_target_cpu=i386 ;; @@ -159,6 +160,8 @@ a29k-*-none) gdb_target=a29k ;; a29k-*-sym1) gdb_target=ultra3 ;; a29k-*-udi) gdb_target=a29k-udi ;; +alpha-*-osf*) gdb_target=alpha-osf1 ;; + arm-*-*) gdb_target=arm ;; c1-*-*) gdb_target=convex ;; diff --git a/gdb/infrun.c b/gdb/infrun.c index e7d2c42..409a768 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -283,6 +283,14 @@ resume (step, sig) struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); QUIT; +#ifdef CANNOT_STEP_BREAKPOINT + /* Most targets can step a breakpoint instruction, thus executing it + normally. But if this one cannot, just continue and we will hit + it anyway. */ + if (step && breakpoints_inserted && breakpoint_here_p (read_pc ())) + step = 0; +#endif + #ifdef NO_SINGLE_STEP if (step) { single_step(sig); /* Do it the hard way, w/temp breakpoints */ @@ -1255,6 +1263,8 @@ step_into_function: /* I'm not sure when this following segment applies. I do know, now, that we shouldn't rewrite the regs when we were stopped by a random signal from the inferior process. */ + /* FIXME: Shouldn't this be based on the valid bit of the SXIP? + (this is only used on the 88k). */ if (!bpstat_explains_signal (stop_bpstat) && (stop_signal != SIGCLD) diff --git a/gdb/osfsolib.c b/gdb/osfsolib.c new file mode 100644 index 0000000..a27243d --- /dev/null +++ b/gdb/osfsolib.c @@ -0,0 +1,786 @@ +/* Handle OSF/1 shared libraries for GDB, the GNU Debugger. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* FIXME: Most of this code could be merged with solib.c by using + next_link_map_member and xfer_link_map_member in solib.c. */ + +#include "defs.h" + +#include <sys/types.h> +#include <signal.h> +#include <string.h> +#include <fcntl.h> + +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" +#include "command.h" +#include "target.h" +#include "frame.h" +#include "regex.h" +#include "inferior.h" +#include "language.h" + +#define MAX_PATH_SIZE 256 /* FIXME: Should be dynamic */ + +/* FIXME: This is a terrible hack for shared library support under OSF/1. + The main problem is that the needed definitions are not contained in + the system header files. + The ldr_* routines described in loader(3) would be the way to go here. + But they do not work for arbitrary target processes (as documented). */ + +#ifndef USE_LDR_ROUTINES +#define RLD_CONTEXT_ADDRESS 0x3ffc0000000 + +typedef struct +{ + CORE_ADDR next; + CORE_ADDR previous; + CORE_ADDR unknown; + char *module_name; + CORE_ADDR modinfo_addr; +} ldr_module_info_t; + +typedef struct +{ + CORE_ADDR unknown1; + CORE_ADDR unknown2; + CORE_ADDR head; + CORE_ADDR tail; +} ldr_context_t; + +static ldr_context_t ldr_context; +#else +#include <loader.h> +#endif + +/* Define our own link_map structure. + This will help to share code with solib.c. */ + +struct link_map { + CORE_ADDR l_addr; /* address at which object mapped */ + char *l_name; /* full name of loaded object */ + ldr_module_info_t module_info; /* corresponding module info */ +}; + +#define LM_ADDR(so) ((so) -> lm.l_addr) +#define LM_NAME(so) ((so) -> lm.l_name) + +struct so_list { + struct so_list *next; /* next structure in linked list */ + struct link_map lm; /* copy of link map from inferior */ + struct link_map *lmaddr; /* addr in inferior lm was read from */ + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; + struct section_table *textsection; + bfd *bfd; +}; + +static struct so_list *so_list_head; /* List of known shared objects */ + +extern int +fdmatch PARAMS ((int, int)); /* In libiberty */ + +/* Local function prototypes */ + +static void +sharedlibrary_command PARAMS ((char *, int)); + +static void +info_sharedlibrary_command PARAMS ((char *, int)); + +static int +symbol_add_stub PARAMS ((char *)); + +static struct so_list * +find_solib PARAMS ((struct so_list *)); + +static struct link_map * +first_link_map_member PARAMS ((void)); + +static struct link_map * +next_link_map_member PARAMS ((struct so_list *)); + +static void +xfer_link_map_member PARAMS ((struct so_list *, struct link_map *)); + +static void +solib_map_sections PARAMS ((struct so_list *)); + +void +_initialize_solib PARAMS ((void)); + +/* + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + +static void +solib_map_sections (so) + struct so_list *so; +{ + char *filename; + char *scratch_pathname; + int scratch_chan; + struct section_table *p; + struct cleanup *old_chain; + bfd *abfd; + + filename = tilde_expand (so -> so_name); + old_chain = make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &scratch_pathname); + if (scratch_chan < 0) + { + scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, + O_RDONLY, 0, &scratch_pathname); + } + if (scratch_chan < 0) + { + perror_with_name (filename); + } + /* Leave scratch_pathname allocated. bfd->name will point to it. */ + + abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!abfd) + { + close (scratch_chan); + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_error)); + } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ + so -> bfd = abfd; + abfd -> cacheable = true; + + if (!bfd_check_format (abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_error)); + } + if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + bfd_get_filename (exec_bfd), bfd_errmsg (bfd_error)); + } + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the base address to which the object was actually + mapped. */ + p -> addr += (CORE_ADDR) LM_ADDR (so); + p -> endaddr += (CORE_ADDR) LM_ADDR (so); + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + if (STREQ (p -> sec_ptr -> name, ".text")) + { + so -> textsection = p; + } + } + + /* Free the file names, close the file now. */ + do_cleanups (old_chain); +} + +/* + +LOCAL FUNCTION + + first_link_map_member -- locate first member in dynamic linker's map + +SYNOPSIS + + static struct link_map *first_link_map_member (void) + +DESCRIPTION + + Read in a copy of the first member in the inferior's dynamic + link map from the inferior's dynamic linker structures, and return + a pointer to the copy in our address space. +*/ + +static struct link_map * +first_link_map_member () +{ + struct link_map *lm = NULL; + static struct link_map first_lm; + +#ifdef USE_LDR_ROUTINES + ldr_module_t mod_id = LDR_NULL_MODULE; + size_t retsize; + + if (ldr_next_module(inferior_pid, &mod_id) != 0 + || mod_id == LDR_NULL_MODULE + || ldr_inq_module(inferior_pid, mod_id, + &first_lm.module_info, sizeof(ldr_module_info_t), + &retsize) != 0) + return lm; +#else + CORE_ADDR ldr_context_addr; + + if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS, + (char *) &ldr_context_addr, + sizeof (CORE_ADDR)) != 0 + || target_read_memory (ldr_context_addr, + (char *) &ldr_context, + sizeof (ldr_context_t)) != 0 + || target_read_memory ((CORE_ADDR) ldr_context.head, + (char *) &first_lm.module_info, + sizeof (ldr_module_info_t)) != 0) + return lm; +#endif + + lm = &first_lm; + + /* The first entry is for the main program and should be skipped. */ + lm->l_name = NULL; + + return lm; +} + +static struct link_map * +next_link_map_member (so_list_ptr) + struct so_list *so_list_ptr; +{ + struct link_map *lm = NULL; + static struct link_map next_lm; +#ifdef USE_LDR_ROUTINES + ldr_module_t mod_id = lm->module_info.lmi_modid; + size_t retsize; + + if (ldr_next_module(inferior_pid, &mod_id) != 0 + || mod_id == LDR_NULL_MODULE + || ldr_inq_module(inferior_pid, mod_id, + &next_lm.module_info, sizeof(ldr_module_info_t), + &retsize) != 0) + return lm; + + lm = &next_lm; + lm->l_name = lm->module_info.lmi_name; +#else + CORE_ADDR ldr_context_addr; + + /* Reread context in case ldr_context.tail was updated. */ + + if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS, + (char *) &ldr_context_addr, + sizeof (CORE_ADDR)) != 0 + || target_read_memory (ldr_context_addr, + (char *) &ldr_context, + sizeof (ldr_context_t)) != 0 + || so_list_ptr->lm.module_info.modinfo_addr == ldr_context.tail + || target_read_memory (so_list_ptr->lm.module_info.next, + (char *) &next_lm.module_info, + sizeof (ldr_module_info_t)) != 0) + return lm; + + lm = &next_lm; + lm->l_name = lm->module_info.module_name; +#endif + return lm; +} + +static void +xfer_link_map_member (so_list_ptr, lm) + struct so_list *so_list_ptr; + struct link_map *lm; +{ + so_list_ptr->lm = *lm; + + /* OSF/1 has absolute addresses in shared libraries. */ + LM_ADDR (so_list_ptr) = 0; + + /* There is one entry that has no name (for the inferior executable) + since it is not a shared object. */ + if (LM_NAME (so_list_ptr) != 0) + { + +#ifdef USE_LDR_ROUTINES + int len = strlen (LM_NAME (so_list_ptr) + 1); + + if (len > MAX_PATH_SIZE) + len = MAX_PATH_SIZE; + strncpy (so_list_ptr->so_name, LM_NAME (so_list_ptr), MAX_PATH_SIZE); +#else + if (!target_read_string((CORE_ADDR) LM_NAME (so_list_ptr), + so_list_ptr->so_name, MAX_PATH_SIZE - 1)) + error ("xfer_link_map_member: Can't read pathname for load map\n"); +#endif + so_list_ptr->so_name[MAX_PATH_SIZE - 1] = 0; + + solib_map_sections (so_list_ptr); + } +} + +/* + +LOCAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. + + The arg and return value are "struct link_map" pointers, as defined + in <link.h>. + */ + +static struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; + struct link_map *lm = NULL; + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* Find the first link map list member. */ + lm = first_link_map_member (); + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + lm = next_link_map_member (so_list_ptr); + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *) new, 0, sizeof (struct so_list)); + new -> lmaddr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + xfer_link_map_member (new, lm); + } + return (so_list_next); +} + +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ + +static int +symbol_add_stub (arg) + char *arg; +{ + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + so -> objfile = symbol_file_add (so -> so_name, so -> from_tty, + so -> textsection -> addr, + 0, 0, 0); + return (1); +} + +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + register struct so_list *so = NULL; /* link map state variable */ + + /* Last shared library that we read. */ + struct so_list *so_last = NULL; + + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + + /* Add the shared library sections to the section table of the + specified target, if any. We have to do this before reading the + symbol files as symbol_file_add calls reinit_frame_cache and + creating a new frame might access memory in the shared library. */ + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + /* Reallocate the target's section table including the new size. */ + if (target -> to_sections) + { + old = target -> to_sections_end - target -> to_sections; + target -> to_sections = (struct section_table *) + xrealloc ((char *)target -> to_sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * count); + } + target -> to_sections_end = target -> to_sections + (count + old); + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count = so -> sections_end - so -> sections; + memcpy ((char *) (target -> to_sections + old), + so -> sections, + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } + + /* Now add the symbol files. */ + so = NULL; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && re_exec (so -> so_name)) + { + so -> from_tty = from_tty; + if (so -> symbols_loaded) + { + if (from_tty) + { + printf ("Symbols already loaded for %s\n", so -> so_name); + } + } + else if (catch_errors + (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + so_last = so; + so -> symbols_loaded = 1; + } + } + } +} + +/* + +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION + + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + unsigned long txt_start = 0; + unsigned long txt_end = 0; + + if (!header_done) + { + printf("%-20s%-20s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + if (so -> textsection) + { + txt_start = (unsigned long) so -> textsection -> addr; + txt_end = (unsigned long) so -> textsection -> endaddr; + } + printf ("%-20s", local_hex_string_custom (txt_start, "08l")); + printf ("%-20s", local_hex_string_custom (txt_end, "08l")); + printf ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf ("%s\n", so -> so_name); + } + } + if (so_list_head == NULL) + { + printf ("No shared libraries loaded at this time.\n"); + } +} + +/* + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + int solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + +int +solib_address (address) + CORE_ADDR address; +{ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && so -> textsection) + { + if ((address >= (CORE_ADDR) so -> textsection -> addr) && + (address < (CORE_ADDR) so -> textsection -> endaddr)) + { + return (1); + } + } + } + return (0); +} + +/* Called by free_all_symtabs */ + +void +clear_solib() +{ + struct so_list *next; + char *bfd_filename; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free ((PTR)so_list_head -> sections); + } + if (so_list_head -> bfd) + { + bfd_filename = bfd_get_filename (so_list_head -> bfd); + bfd_close (so_list_head -> bfd); + } + else + /* This happens for the executable on SVR4. */ + bfd_filename = NULL; + + next = so_list_head -> next; + if (bfd_filename) + free ((PTR)bfd_filename); + free ((PTR)so_list_head); + so_list_head = next; + } +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + For a statically bound executable, this first instruction is the + one at "_start", or a similar text label. No further processing is + needed in that case. + For a dynamically bound executable, this first instruction is somewhere + in the rld, and the actual user executable is not yet mapped in. + We continue the inferior again, rld then maps in the actual user + executable and any needed shared libraries and then sends + itself a SIGTRAP. + At that point we discover the names of all shared libraries and + read their symbols in. + +FIXME + + This code does not properly handle hitting breakpoints which the + user might have set in the rld itself. Proper handling would have + to check if the SIGTRAP happened due to a kill call. + + Also, what if child has exit()ed? Must exit loop somehow. + */ + +void +solib_create_inferior_hook() +{ + + /* Nothing to do for statically bound executables. */ + + if (symfile_objfile == 0 || symfile_objfile->ei.entry_file_lowpc == stop_pc) + return; + + /* Now run the target. It will eventually get a SIGTRAP, at + which point all of the libraries will have been mapped in and we + can go groveling around in the rld structures to find + out what we need to know about them. */ + + clear_proceed_status (); + stop_soon_quietly = 1; + stop_signal = 0; + do + { + target_resume (inferior_pid, 0, stop_signal); + wait_for_inferior (); + } + while (stop_signal != SIGTRAP); + stop_soon_quietly = 0; + + solib_add ((char *) 0, 0, (struct target_ops *) 0); +} + + +/* + +LOCAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + static void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +sharedlibrary_command (args, from_tty) +char *args; +int from_tty; +{ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); +} + +void +_initialize_solib() +{ + + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); +} diff --git a/gdb/stabsread.c b/gdb/stabsread.c index f631313..f63409f 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -467,7 +467,7 @@ static char *type_synonym_name; /* ARGSUSED */ struct symbol * define_symbol (valu, string, desc, type, objfile) - unsigned int valu; + CORE_ADDR valu; char *string; int desc; int type; @@ -3228,8 +3228,12 @@ read_range_type (pp, typenums, objfile) nbits = n3bits; } /* Range from <large number> to <large number>-1 is a large signed - integral type. */ - else if (n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1) + integral type. Take care of the case where <large number> doesn't + fit in a long but <large number>-1 does. */ + else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1) + || (n2bits != 0 && n3bits == 0 + && (n2bits == sizeof (long) * HOST_CHAR_BIT) + && n3 == LONG_MAX)) { got_signed = 1; nbits = n2bits; diff --git a/gdb/stabsread.h b/gdb/stabsread.h index 8d18ac8..67cefc2 100644 --- a/gdb/stabsread.h +++ b/gdb/stabsread.h @@ -152,7 +152,7 @@ extern void add_undefined_type PARAMS ((struct type *)); extern struct symbol * -define_symbol PARAMS ((unsigned int, char *, int, int, struct objfile *)); +define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *)); extern void stabsread_init PARAMS ((void)); diff --git a/gdb/valops.c b/gdb/valops.c index c8bd496..82d0f58 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -896,8 +896,8 @@ call_function_by_hand (function, nargs, args) #if CALL_DUMMY_LOCATION == ON_STACK write_memory (start_sp, (char *)dummy1, sizeof dummy); +#endif /* On stack. */ -#else /* Not on stack. */ #if CALL_DUMMY_LOCATION == BEFORE_TEXT_END /* Convex Unix prohibits executing in the stack segment. */ /* Hope there is empty room at the top of the text segment. */ @@ -913,7 +913,9 @@ call_function_by_hand (function, nargs, args) real_pc = text_end - sizeof dummy; write_memory (real_pc, (char *)dummy1, sizeof dummy); } -#else /* After text_end. */ +#endif /* Before text_end. */ + +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END { extern CORE_ADDR text_end; int errcode; @@ -924,7 +926,10 @@ call_function_by_hand (function, nargs, args) error ("Cannot write text segment -- call_function failed"); } #endif /* After text_end. */ -#endif /* Not on stack. */ + +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + real_pc = funaddr; +#endif /* At entry point. */ #ifdef lint sp = old_sp; /* It really is used, for some ifdef's... */ @@ -1056,7 +1061,7 @@ call_function_by_hand (function, nargs, args) char format[80]; sprintf (format, "at %s", local_hex_format ()); name = alloca (80); - sprintf (name, format, funaddr); + sprintf (name, format, (unsigned long) funaddr); } /* Execute the stack dummy routine, calling FUNCTION. @@ -1349,7 +1354,7 @@ search_struct_field (name, arg1, offset, type, looking_for_baseclass) /* Helper function used by value_struct_elt to recurse through baseclasses. Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, and search in it assuming it has (class) type TYPE. - If found, return value, else if name matched and args not return -1, + If found, return value, else if name matched and args not return (value)-1, else return NULL. */ static value @@ -1409,7 +1414,7 @@ search_struct_method (name, arg1p, args, offset, static_memfuncp, type) } v = search_struct_method (name, arg1p, args, base_offset + offset, static_memfuncp, TYPE_BASECLASS (type, i)); - if (v == -1) + if (v == (value) -1) { name_matched = 1; } @@ -1420,7 +1425,7 @@ search_struct_method (name, arg1p, args, offset, static_memfuncp, type) return v; } } - if (name_matched) return -1; + if (name_matched) return (value) -1; else return NULL; } @@ -1519,7 +1524,7 @@ value_struct_elt (argp, args, name, static_memfuncp, err) else v = search_struct_method (name, argp, args, 0, static_memfuncp, t); - if (v == -1) + if (v == (value) -1) { error("Argument list of %s mismatch with component in the structure.", name); } |