diff options
Diffstat (limited to 'contrib')
25 files changed, 23531 insertions, 17753 deletions
diff --git a/contrib/gdb/gdb/alpha-tdep.c b/contrib/gdb/gdb/alpha-tdep.c index 744a7cf..4ca6bcc 100644 --- a/contrib/gdb/gdb/alpha-tdep.c +++ b/contrib/gdb/gdb/alpha-tdep.c @@ -1,27 +1,24 @@ /* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger. - Copyright 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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. */ -#ifdef __FreeBSD__ -#include <sys/param.h> -#include <machine/alpha_cpu.h> -#include <machine/vmparam.h> -#endif #include "defs.h" #include "frame.h" #include "inferior.h" @@ -33,42 +30,57 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "symfile.h" #include "objfiles.h" #include "gdb_string.h" +#include "linespec.h" +#include "regcache.h" +#include "doublest.h" + +struct frame_extra_info + { + alpha_extra_func_info_t proc_desc; + int localoff; + int pc_reg; + }; /* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */ /* Prototypes for local functions. */ -static alpha_extra_func_info_t push_sigtramp_desc PARAMS ((CORE_ADDR low_addr)); +static void alpha_find_saved_regs (struct frame_info *); + +static alpha_extra_func_info_t push_sigtramp_desc (CORE_ADDR low_addr); -static CORE_ADDR read_next_frame_reg PARAMS ((struct frame_info *, int)); +static CORE_ADDR read_next_frame_reg (struct frame_info *, int); -static CORE_ADDR heuristic_proc_start PARAMS ((CORE_ADDR)); +static CORE_ADDR heuristic_proc_start (CORE_ADDR); -static alpha_extra_func_info_t heuristic_proc_desc PARAMS ((CORE_ADDR, - CORE_ADDR, - struct frame_info *)); +static alpha_extra_func_info_t heuristic_proc_desc (CORE_ADDR, + CORE_ADDR, + struct frame_info *); -static alpha_extra_func_info_t find_proc_desc PARAMS ((CORE_ADDR, - struct frame_info *)); +static alpha_extra_func_info_t find_proc_desc (CORE_ADDR, + struct frame_info *); #if 0 -static int alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR)); +static int alpha_in_lenient_prologue (CORE_ADDR, CORE_ADDR); #endif -static void reinit_frame_cache_sfunc PARAMS ((char *, int, - struct cmd_list_element *)); +static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *); -static CORE_ADDR after_prologue PARAMS ((CORE_ADDR pc, - alpha_extra_func_info_t proc_desc)); +static CORE_ADDR after_prologue (CORE_ADDR pc, + alpha_extra_func_info_t proc_desc); -static int alpha_in_prologue PARAMS ((CORE_ADDR pc, - alpha_extra_func_info_t proc_desc)); +static int alpha_in_prologue (CORE_ADDR pc, + alpha_extra_func_info_t proc_desc); + +static int alpha_about_to_return (CORE_ADDR pc); + +void _initialize_alpha_tdep (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; - +/* *INDENT-OFF* */ /* Layout of a stack frame on the alpha: | | @@ -111,10 +123,16 @@ static unsigned int heuristic_fence_post = 0; -------------|-------------------------------|<-- sp | | */ +/* *INDENT-ON* */ -#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_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */ +/* These next two fields are kind of being hijacked. I wonder if + iline is too small for the values it needs to hold, if GDB is + running on a 32-bit host. */ +#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */ +#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.cbLineOffset) /*CALL_DUMMY frame */ #define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) #define PROC_FRAME_REG(proc) ((proc)->pdr.framereg) #define PROC_REG_MASK(proc) ((proc)->pdr.regmask) @@ -129,21 +147,27 @@ static unsigned int heuristic_fence_post = 0; #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; + +int +alpha_osf_in_sigtramp (CORE_ADDR pc, char *func_name) { - struct alpha_extra_func_info info; - struct linked_proc_info *next; -} *linked_proc_desc_table = NULL; + return (func_name != NULL && STREQ ("__sigtramp", func_name)); +} - /* Under GNU/Linux, signal handler invocations can be identified by the designated code sequence that is used to return from a signal handler. In particular, the return address of a signal handler points to the following sequence (the first instruction is quadword aligned): - bis $30,$30,$16 - addq $31,0x67,$0 - call_pal callsys + bis $30,$30,$16 + addq $31,0x67,$0 + call_pal callsys Each instruction has a unique encoding, so we simply attempt to match the instruction the pc is pointing to with any of the above @@ -157,24 +181,36 @@ struct linked_proc_info middle of the designated sequence, in which case there is no guarantee that we are in the middle of a sigreturn syscall. Don't think this will be a problem in praxis, though. -*/ + */ +#ifndef TM_LINUXALPHA_H +/* HACK: Provide a prototype when compiling this file for non + linuxalpha targets. */ +long alpha_linux_sigtramp_offset (CORE_ADDR pc); +#endif long alpha_linux_sigtramp_offset (CORE_ADDR pc) { unsigned int i[3], w; long off; - if (read_memory_nobpt(pc, (char *) &w, 4) != 0) + if (read_memory_nobpt (pc, (char *) &w, 4) != 0) return -1; off = -1; switch (w) { - case 0x47de0410: off = 0; break; /* bis $30,$30,$16 */ - case 0x43ecf400: off = 4; break; /* addq $31,0x67,$0 */ - case 0x00000083: off = 8; break; /* call_pal callsys */ - default: return -1; + case 0x47de0410: + off = 0; + break; /* bis $30,$30,$16 */ + case 0x43ecf400: + off = 4; + break; /* addq $31,0x67,$0 */ + case 0x00000083: + off = 8; + break; /* call_pal callsys */ + default: + return -1; } pc -= off; if (pc & 0x7) @@ -183,7 +219,7 @@ alpha_linux_sigtramp_offset (CORE_ADDR pc) return -1; } - if (read_memory_nobpt(pc, (char *) i, sizeof(i)) != 0) + if (read_memory_nobpt (pc, (char *) i, sizeof (i)) != 0) return -1; if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083) @@ -191,31 +227,28 @@ alpha_linux_sigtramp_offset (CORE_ADDR pc) return -1; } - + /* Under OSF/1, the __sigtramp routine is frameless and has a frame size of zero, but we are able to backtrace through it. */ CORE_ADDR -alpha_osf_skip_sigtramp_frame (frame, pc) - struct frame_info *frame; - CORE_ADDR pc; +alpha_osf_skip_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc) { char *name; - find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL, (CORE_ADDR *)NULL); + find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL); if (IN_SIGTRAMP (pc, name)) return frame->frame; else return 0; } - + /* Dynamically create a signal-handler caller procedure descriptor for the signal-handler return code starting at address LOW_ADDR. The descriptor is added to the linked_proc_desc_table. */ static alpha_extra_func_info_t -push_sigtramp_desc (low_addr) - CORE_ADDR low_addr; +push_sigtramp_desc (CORE_ADDR low_addr) { struct linked_proc_info *link; alpha_extra_func_info_t proc_desc; @@ -228,26 +261,92 @@ push_sigtramp_desc (low_addr) proc_desc = &link->info; proc_desc->numargs = 0; - PROC_LOW_ADDR (proc_desc) = low_addr; - PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4; - PROC_DUMMY_FRAME (proc_desc) = 0; - PROC_FRAME_OFFSET (proc_desc) = 0x298; /* sizeof(struct sigcontext_struct) */ - PROC_FRAME_REG (proc_desc) = SP_REGNUM; - PROC_REG_MASK (proc_desc) = 0xffff; - PROC_FREG_MASK (proc_desc) = 0xffff; - PROC_PC_REG (proc_desc) = 26; - PROC_LOCALOFF (proc_desc) = 0; + PROC_LOW_ADDR (proc_desc) = low_addr; + PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4; + PROC_DUMMY_FRAME (proc_desc) = 0; + PROC_FRAME_OFFSET (proc_desc) = 0x298; /* sizeof(struct sigcontext_struct) */ + PROC_FRAME_REG (proc_desc) = SP_REGNUM; + PROC_REG_MASK (proc_desc) = 0xffff; + PROC_FREG_MASK (proc_desc) = 0xffff; + PROC_PC_REG (proc_desc) = 26; + PROC_LOCALOFF (proc_desc) = 0; SET_PROC_DESC_IS_DYN_SIGTRAMP (proc_desc); return (proc_desc); } + + +char * +alpha_register_name (int regno) +{ + static char *register_names[] = + { + "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", + "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", + "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", + "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "fpcr", + "pc", "vfp", + }; + + if (regno < 0) + return (NULL); + if (regno >= (sizeof(register_names) / sizeof(*register_names))) + return (NULL); + return (register_names[regno]); +} + +int +alpha_cannot_fetch_register (int regno) +{ + return (regno == FP_REGNUM || regno == ZERO_REGNUM); +} + +int +alpha_cannot_store_register (int regno) +{ + return (regno == FP_REGNUM || regno == ZERO_REGNUM); +} + +int +alpha_register_convertible (int regno) +{ + return (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31); +} + +struct type * +alpha_register_virtual_type (int regno) +{ + return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31)) + ? builtin_type_double : builtin_type_long); +} + +int +alpha_register_byte (int regno) +{ + return (regno * 8); +} +int +alpha_register_raw_size (int regno) +{ + return 8; +} + +int +alpha_register_virtual_size (int regno) +{ + return 8; +} + /* Guaranteed to set frame->saved_regs to some values (it never leaves it NULL). */ -void -alpha_find_saved_regs (frame) - struct frame_info *frame; +static void +alpha_find_saved_regs (struct frame_info *frame) { int ireg; CORE_ADDR reg_position; @@ -274,19 +373,19 @@ alpha_find_saved_regs (frame) sigcontext_addr = SIGCONTEXT_ADDR (frame); for (ireg = 0; ireg < 32; ireg++) { - reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8; - frame->saved_regs[ireg] = reg_position; + reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8; + frame->saved_regs[ireg] = reg_position; } for (ireg = 0; ireg < 32; ireg++) { - reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8; - frame->saved_regs[FP0_REGNUM + ireg] = reg_position; + reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8; + frame->saved_regs[FP0_REGNUM + ireg] = reg_position; } frame->saved_regs[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF; return; } - proc_desc = frame->proc_desc; + proc_desc = frame->extra_info->proc_desc; if (proc_desc == NULL) /* I'm not sure how/whether this can happen. Normally when we can't find a proc_desc, we "synthesize" one using heuristic_proc_desc @@ -307,11 +406,11 @@ alpha_find_saved_regs (frame) { frame->saved_regs[returnreg] = reg_position; reg_position += 8; - mask &= ~(1 << returnreg); /* Clear bit for RA so we - don't save again later. */ + mask &= ~(1 << returnreg); /* Clear bit for RA so we + don't save again later. */ } - for (ireg = 0; ireg <= 31 ; ++ireg) + for (ireg = 0; ireg <= 31; ++ireg) if (mask & (1 << ireg)) { frame->saved_regs[ireg] = reg_position; @@ -324,25 +423,38 @@ alpha_find_saved_regs (frame) reg_position = frame->frame + PROC_FREG_OFFSET (proc_desc); mask = PROC_FREG_MASK (proc_desc); - for (ireg = 0; ireg <= 31 ; ++ireg) + for (ireg = 0; ireg <= 31; ++ireg) if (mask & (1 << ireg)) { - frame->saved_regs[FP0_REGNUM+ireg] = reg_position; + frame->saved_regs[FP0_REGNUM + ireg] = reg_position; reg_position += 8; } frame->saved_regs[PC_REGNUM] = frame->saved_regs[returnreg]; } +void +alpha_frame_init_saved_regs (struct frame_info *fi) +{ + if (fi->saved_regs == NULL) + alpha_find_saved_regs (fi); + fi->saved_regs[SP_REGNUM] = fi->frame; +} + +void +alpha_init_frame_pc_first (int fromleaf, struct frame_info *prev) +{ + prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : + prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ()); +} + static CORE_ADDR -read_next_frame_reg(fi, regno) - struct frame_info *fi; - int regno; +read_next_frame_reg (struct frame_info *fi, int regno) { for (; fi; fi = fi->next) { /* We have to get the saved sp from the sigcontext - if it is a signal handler frame. */ + if it is a signal handler frame. */ if (regno == SP_REGNUM && !fi->signal_handler_caller) return fi->frame; else @@ -350,30 +462,29 @@ read_next_frame_reg(fi, regno) if (fi->saved_regs == NULL) alpha_find_saved_regs (fi); if (fi->saved_regs[regno]) - return read_memory_integer(fi->saved_regs[regno], 8); + return read_memory_integer (fi->saved_regs[regno], 8); } } - return read_register(regno); + return read_register (regno); } CORE_ADDR -alpha_frame_saved_pc(frame) - struct frame_info *frame; +alpha_frame_saved_pc (struct frame_info *frame) { - alpha_extra_func_info_t proc_desc = frame->proc_desc; + alpha_extra_func_info_t proc_desc = frame->extra_info->proc_desc; /* We have to get the saved pc from the sigcontext if it is a signal handler frame. */ - int pcreg = frame->signal_handler_caller ? PC_REGNUM : frame->pc_reg; + int pcreg = frame->signal_handler_caller ? PC_REGNUM + : frame->extra_info->pc_reg; - if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) - return read_memory_integer(frame->frame - 8, 8); + if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc)) + return read_memory_integer (frame->frame - 8, 8); - return read_next_frame_reg(frame, pcreg); + return read_next_frame_reg (frame, pcreg); } CORE_ADDR -alpha_saved_pc_after_call (frame) - struct frame_info *frame; +alpha_saved_pc_after_call (struct frame_info *frame) { CORE_ADDR pc = frame->pc; CORE_ADDR tmp; @@ -396,14 +507,13 @@ alpha_saved_pc_after_call (frame) static struct alpha_extra_func_info temp_proc_desc; -static struct frame_saved_regs temp_saved_regs; +static CORE_ADDR temp_saved_regs[NUM_REGS]; /* Nonzero if instruction at PC is a return instruction. "ret $zero,($ra),1" on alpha. */ static int -alpha_about_to_return (pc) - CORE_ADDR pc; +alpha_about_to_return (CORE_ADDR pc) { return read_memory_integer (pc, 4) == 0x6bfa8001; } @@ -415,186 +525,183 @@ alpha_about_to_return (pc) lines. */ static CORE_ADDR -heuristic_proc_start(pc) - CORE_ADDR pc; +heuristic_proc_start (CORE_ADDR pc) { - CORE_ADDR start_pc = pc; - CORE_ADDR fence = start_pc - heuristic_fence_post; + CORE_ADDR start_pc = pc; + CORE_ADDR fence = start_pc - heuristic_fence_post; - if (start_pc == 0) return 0; + if (start_pc == 0) + return 0; - if (heuristic_fence_post == UINT_MAX - || fence < VM_MIN_ADDRESS) - fence = VM_MIN_ADDRESS; + 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) + /* 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) { - /* 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%s", paddr_nz (pc)); + if (!blurb_printed) { - 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 ("\ + 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; - } + blurb_printed = 1; } - - return 0; } - else if (alpha_about_to_return (start_pc)) - break; - start_pc += 4; /* skip return */ - return start_pc; + return 0; + } + else if (alpha_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; - struct frame_info *next_frame; +heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc, + struct frame_info *next_frame) { - CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM); - CORE_ADDR cur_pc; - int frame_size; - int has_frame_reg = 0; - unsigned long reg_mask = 0; - int pcreg = -1; - - 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; + CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM); + CORE_ADDR cur_pc; + int frame_size; + int has_frame_reg = 0; + unsigned long reg_mask = 0; + int pcreg = -1; + + if (start_pc == 0) + return NULL; + memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc)); + memset (&temp_saved_regs, '\0', SIZEOF_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); + 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) */ - { - if (word & 0x8000) - frame_size += (-word) & 0xffff; - else - /* Exit loop if a positive stack adjustment is found, which - usually means that the stack cleanup code in the function - epilogue is reached. */ - break; - } - 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; - - /* Starting with OSF/1-3.2C, the system libraries are shipped - without local symbols, but they still contain procedure - descriptors without a symbol reference. GDB is currently - unable to find these procedure descriptors and uses - heuristic_proc_desc instead. - As some low level compiler support routines (__div*, __add*) - use a non-standard return address register, we have to - add some heuristics to determine the return address register, - or stepping over these routines will fail. - Usually the return address register is the first register - saved on the stack, but assembler optimization might - rearrange the register saves. - So we recognize only a few registers (t7, t9, ra) within - the procedure prologue as valid return address registers. - If we encounter a return instruction, we extract the - the return address register from it. - - FIXME: Rewriting GDB to access the procedure descriptors, - e.g. via the minimal symbol table, might obviate this hack. */ - if (pcreg == -1 - && cur_pc < (start_pc + 80) - && (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM)) - pcreg = reg; - } - else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ - pcreg = (word >> 16) & 0x1f; - else if (word == 0x47de040f) /* bis sp,sp fp */ - has_frame_reg = 1; - } - if (pcreg == -1) - { - /* If we haven't found a valid return address register yet, - keep searching in the procedure prologue. */ - while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80)) - { - char buf[4]; - unsigned long word; + if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ + { + if (word & 0x8000) + frame_size += (-word) & 0xffff; + else + /* Exit loop if a positive stack adjustment is found, which + usually means that the stack cleanup code in the function + epilogue is reached. */ + break; + } + 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[reg] = sp + (short) word; + + /* Starting with OSF/1-3.2C, the system libraries are shipped + without local symbols, but they still contain procedure + descriptors without a symbol reference. GDB is currently + unable to find these procedure descriptors and uses + heuristic_proc_desc instead. + As some low level compiler support routines (__div*, __add*) + use a non-standard return address register, we have to + add some heuristics to determine the return address register, + or stepping over these routines will fail. + Usually the return address register is the first register + saved on the stack, but assembler optimization might + rearrange the register saves. + So we recognize only a few registers (t7, t9, ra) within + the procedure prologue as valid return address registers. + If we encounter a return instruction, we extract the + the return address register from it. + + FIXME: Rewriting GDB to access the procedure descriptors, + e.g. via the minimal symbol table, might obviate this hack. */ + if (pcreg == -1 + && cur_pc < (start_pc + 80) + && (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM)) + pcreg = reg; + } + else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ + pcreg = (word >> 16) & 0x1f; + else if (word == 0x47de040f) /* bis sp,sp fp */ + has_frame_reg = 1; + } + if (pcreg == -1) + { + /* If we haven't found a valid return address register yet, + keep searching in the procedure prologue. */ + while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80)) + { + char buf[4]; + unsigned long word; - if (read_memory_nobpt (cur_pc, buf, 4)) - break; - cur_pc += 4; - word = extract_unsigned_integer (buf, 4); + if (read_memory_nobpt (cur_pc, buf, 4)) + break; + cur_pc += 4; + word = extract_unsigned_integer (buf, 4); - if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ - && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ - { - int reg = (word & 0x03e00000) >> 21; - if (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM) - { - pcreg = reg; - break; - } - } - else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ - { - pcreg = (word >> 16) & 0x1f; - break; - } - } - } + if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ + && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ + { + int reg = (word & 0x03e00000) >> 21; + if (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM) + { + pcreg = reg; + break; + } + } + else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ + { + pcreg = (word >> 16) & 0x1f; + break; + } + } + } - 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) = (pcreg == -1) ? RA_REGNUM : pcreg; - PROC_LOCALOFF(&temp_proc_desc) = 0; /* XXX - bogus */ - return &temp_proc_desc; + 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) = (pcreg == -1) ? RA_REGNUM : pcreg; + PROC_LOCALOFF (&temp_proc_desc) = 0; /* XXX - bogus */ + return &temp_proc_desc; } /* This returns the PC of the first inst after the prologue. If we can't find the prologue, then return 0. */ static CORE_ADDR -after_prologue (pc, proc_desc) - CORE_ADDR pc; - alpha_extra_func_info_t proc_desc; +after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) { struct symtab_and_line sal; CORE_ADDR func_addr, func_end; @@ -608,7 +715,7 @@ after_prologue (pc, proc_desc) return PROC_LOW_ADDR (proc_desc); /* "prologue" is in kernel */ /* If function is frameless, then we need to do it the hard way. I - strongly suspect that frameless always means prologueless... */ + strongly suspect that frameless always means prologueless... */ if (PROC_FRAME_REG (proc_desc) == SP_REGNUM && PROC_FRAME_OFFSET (proc_desc) == 0) return 0; @@ -632,9 +739,7 @@ after_prologue (pc, proc_desc) are definitively *not* in a function prologue. */ static int -alpha_in_prologue (pc, proc_desc) - CORE_ADDR pc; - alpha_extra_func_info_t proc_desc; +alpha_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) { CORE_ADDR after_prologue_pc; @@ -648,9 +753,7 @@ alpha_in_prologue (pc, proc_desc) } static alpha_extra_func_info_t -find_proc_desc (pc, next_frame) - CORE_ADDR pc; - struct frame_info *next_frame; +find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame) { alpha_extra_func_info_t proc_desc; struct block *b; @@ -685,7 +788,7 @@ find_proc_desc (pc, next_frame) return found_proc_desc; } - b = block_for_pc(pc); + b = block_for_pc (pc); find_pc_partial_function (pc, NULL, &startaddr, NULL); if (b == NULL) @@ -709,57 +812,57 @@ find_proc_desc (pc, next_frame) if (sym) { - /* IF this is the topmost frame 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) - { - if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc)) - { - alpha_extra_func_info_t found_heuristic = - heuristic_proc_desc (PROC_LOW_ADDR (proc_desc), - pc, next_frame); - if (found_heuristic) - { - PROC_LOCALOFF (found_heuristic) = - PROC_LOCALOFF (proc_desc); - PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc); - proc_desc = found_heuristic; - } - } - } + /* IF this is the topmost frame 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) + { + if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc)) + { + alpha_extra_func_info_t found_heuristic = + heuristic_proc_desc (PROC_LOW_ADDR (proc_desc), + pc, next_frame); + if (found_heuristic) + { + PROC_LOCALOFF (found_heuristic) = + PROC_LOCALOFF (proc_desc); + PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc); + proc_desc = found_heuristic; + } + } + } } else { long offset; /* Is linked_proc_desc_table really necessary? It only seems to be used - by procedure call dummys. However, the procedures being called ought - to have their own proc_descs, and even if they don't, - heuristic_proc_desc knows how to create them! */ + by procedure call dummys. However, the procedures being called ought + to have their own proc_descs, and even if they don't, + heuristic_proc_desc knows how to create them! */ register struct linked_proc_info *link; for (link = linked_proc_desc_table; link; link = link->next) - if (PROC_LOW_ADDR(&link->info) <= pc - && PROC_HIGH_ADDR(&link->info) > pc) - return &link->info; + if (PROC_LOW_ADDR (&link->info) <= pc + && PROC_HIGH_ADDR (&link->info) > pc) + return &link->info; /* If PC is inside a dynamically generated sigtramp handler, - create and push a procedure descriptor for that code: */ + create and push a procedure descriptor for that code: */ offset = DYNAMIC_SIGTRAMP_OFFSET (pc); if (offset >= 0) return push_sigtramp_desc (pc - offset); /* If heuristic_fence_post is non-zero, determine the procedure - start address by examining the instructions. - This allows us to find the start address of static functions which - have no symbolic information, as startaddr would have been set to - the preceding global function start address by the - find_pc_partial_function call above. */ + start address by examining the instructions. + This allows us to find the start address of static functions which + have no symbolic information, as startaddr would have been set to + the preceding global function start address by the + find_pc_partial_function call above. */ if (startaddr == 0 || heuristic_fence_post != 0) startaddr = heuristic_proc_start (pc); @@ -772,70 +875,83 @@ find_proc_desc (pc, next_frame) alpha_extra_func_info_t cached_proc_desc; CORE_ADDR -alpha_frame_chain(frame) - struct frame_info *frame; +alpha_frame_chain (struct frame_info *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 (CORE_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 previous frame from a sigtramp frame might be frameless - and have frame size zero. */ - && !frame->signal_handler_caller) - return FRAME_PAST_SIGTRAMP_FRAME (frame, saved_pc); - else - return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc)) - + PROC_FRAME_OFFSET(proc_desc); + 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 (CORE_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 previous frame from a sigtramp frame might be frameless + and have frame size zero. */ + && !frame->signal_handler_caller) + return FRAME_PAST_SIGTRAMP_FRAME (frame, saved_pc); + else + return read_next_frame_reg (frame, PROC_FRAME_REG (proc_desc)) + + PROC_FRAME_OFFSET (proc_desc); } void -init_extra_frame_info (frame) - struct frame_info *frame; +alpha_print_extra_frame_info (struct frame_info *fi) +{ + if (fi + && fi->extra_info + && fi->extra_info->proc_desc + && fi->extra_info->proc_desc->pdr.framereg < NUM_REGS) + printf_filtered (" frame pointer is at %s+%s\n", + REGISTER_NAME (fi->extra_info->proc_desc->pdr.framereg), + paddr_d (fi->extra_info->proc_desc->pdr.frameoffset)); +} + +void +alpha_init_extra_frame_info (int fromleaf, struct frame_info *frame) { /* Use proc_desc calculated in frame_chain */ alpha_extra_func_info_t proc_desc = - frame->next ? cached_proc_desc : find_proc_desc(frame->pc, frame->next); + frame->next ? cached_proc_desc : find_proc_desc (frame->pc, frame->next); + + frame->extra_info = (struct frame_extra_info *) + frame_obstack_alloc (sizeof (struct frame_extra_info)); frame->saved_regs = NULL; - frame->localoff = 0; - frame->pc_reg = RA_REGNUM; - frame->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc; + frame->extra_info->localoff = 0; + frame->extra_info->pc_reg = RA_REGNUM; + frame->extra_info->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc; if (proc_desc) { /* Get the locals offset and the saved pc register from the - procedure descriptor, they are valid even if we are in the - middle of the prologue. */ - frame->localoff = PROC_LOCALOFF(proc_desc); - frame->pc_reg = PROC_PC_REG(proc_desc); + procedure descriptor, they are valid even if we are in the + middle of the prologue. */ + frame->extra_info->localoff = PROC_LOCALOFF (proc_desc); + frame->extra_info->pc_reg = PROC_PC_REG (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)) - frame->frame = (CORE_ADDR) PROC_DUMMY_FRAME(proc_desc); + descriptor. */ + if (PROC_DESC_IS_DUMMY (proc_desc)) + frame->frame = (CORE_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. */ + Get the value of the frame relative sp, procedure might have been + interrupted by a signal at it's very start. */ else if (frame->pc == PROC_LOW_ADDR (proc_desc) && !PROC_DESC_IS_DYN_SIGTRAMP (proc_desc)) frame->frame = read_next_frame_reg (frame->next, SP_REGNUM); @@ -851,12 +967,13 @@ init_extra_frame_info (frame) alpha_find_saved_registers will do that for us. We can't use frame->signal_handler_caller, it is not yet set. */ find_pc_partial_function (frame->pc, &name, - (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + (CORE_ADDR *) NULL, (CORE_ADDR *) NULL); if (!IN_SIGTRAMP (frame->pc, name)) { - frame->saved_regs = (CORE_ADDR*) + frame->saved_regs = (CORE_ADDR *) frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS); - memcpy (frame->saved_regs, temp_saved_regs.regs, SIZEOF_FRAME_SAVED_REGS); + memcpy (frame->saved_regs, temp_saved_regs, + SIZEOF_FRAME_SAVED_REGS); frame->saved_regs[PC_REGNUM] = frame->saved_regs[RA_REGNUM]; } @@ -864,6 +981,18 @@ init_extra_frame_info (frame) } } +CORE_ADDR +alpha_frame_locals_address (struct frame_info *fi) +{ + return (fi->frame - fi->extra_info->localoff); +} + +CORE_ADDR +alpha_frame_args_address (struct frame_info *fi) +{ + return (fi->frame - (ALPHA_NUM_ARG_REGS * 8)); +} + /* 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 @@ -880,9 +1009,7 @@ init_extra_frame_info (frame) arguments without difficulty. */ struct frame_info * -setup_arbitrary_frame (argc, argv) - int argc; - CORE_ADDR *argv; +setup_arbitrary_frame (int argc, CORE_ADDR *argv) { if (argc != 2) error ("ALPHA frame specifications require two arguments: sp and pc"); @@ -901,26 +1028,27 @@ setup_arbitrary_frame (argc, argv) structure to be returned is passed as a hidden first argument. */ CORE_ADDR -alpha_push_arguments (nargs, args, sp, struct_return, struct_addr) - int nargs; - value_ptr *args; - CORE_ADDR sp; - int struct_return; - CORE_ADDR struct_addr; +alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) { - register i; + int i; int accumulate_size = struct_return ? 8 : 0; int arg_regs_size = ALPHA_NUM_ARG_REGS * 8; - struct alpha_arg { char *contents; int len; int offset; }; + struct alpha_arg + { + char *contents; + int len; + int offset; + }; struct alpha_arg *alpha_args = - (struct alpha_arg*)alloca (nargs * sizeof (struct alpha_arg)); + (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_ptr arg = args[i]; + struct value *arg = args[i]; struct type *arg_type = check_typedef (VALUE_TYPE (arg)); /* Cast argument to long if necessary as the compiler does it too. */ switch (TYPE_CODE (arg_type)) @@ -942,7 +1070,7 @@ alpha_push_arguments (nargs, args, sp, struct_return, struct_addr) m_arg->len = TYPE_LENGTH (arg_type); m_arg->offset = accumulate_size; accumulate_size = (accumulate_size + m_arg->len + 7) & ~7; - m_arg->contents = VALUE_CONTENTS(arg); + m_arg->contents = VALUE_CONTENTS (arg); } /* Determine required argument register loads, loading an argument register @@ -953,15 +1081,15 @@ alpha_push_arguments (nargs, args, sp, struct_return, struct_addr) /* Make room for the arguments on the stack. */ if (accumulate_size < arg_regs_size) - 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); + 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); @@ -982,7 +1110,7 @@ alpha_push_arguments (nargs, args, sp, struct_return, struct_addr) } void -alpha_push_dummy_frame() +alpha_push_dummy_frame (void) { int ireg; struct linked_proc_info *link; @@ -992,10 +1120,10 @@ alpha_push_dummy_frame() char raw_buffer[MAX_REGISTER_RAW_SIZE]; unsigned long mask; - link = (struct linked_proc_info *) xmalloc(sizeof (struct linked_proc_info)); + link = (struct linked_proc_info *) xmalloc (sizeof (struct linked_proc_info)); link->next = linked_proc_desc_table; linked_proc_desc_table = link; - + proc_desc = &link->info; /* @@ -1005,15 +1133,15 @@ alpha_push_dummy_frame() * * Dummy frame layout: * (high memory) - * Saved PC + * Saved PC * Saved F30 * ... * Saved F0 - * Saved R29 - * ... - * Saved R0 - * Saved R26 (RA) - * Parameter build area + * Saved R29 + * ... + * Saved R0 + * Saved R26 (RA) + * Parameter build area * (low memory) */ @@ -1027,27 +1155,27 @@ alpha_push_dummy_frame() 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_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 + 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; + + 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); + 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; + mask = PROC_REG_MASK (proc_desc) & 0xffffffffL; for (ireg = 0; mask; ireg++, mask >>= 1) if (mask & 1) { @@ -1062,8 +1190,8 @@ alpha_push_dummy_frame() 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; + 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) { @@ -1084,47 +1212,56 @@ alpha_push_dummy_frame() 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); + 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) = CALL_DUMMY_ADDRESS (); - PROC_HIGH_ADDR(proc_desc) = PROC_LOW_ADDR(proc_desc) + 4; + PROC_LOW_ADDR (proc_desc) = CALL_DUMMY_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; + SET_PROC_DESC_IS_DUMMY (proc_desc); + PROC_PC_REG (proc_desc) = RA_REGNUM; } void -alpha_pop_frame() +alpha_pop_frame (void) { register int regnum; struct frame_info *frame = get_current_frame (); CORE_ADDR new_sp = frame->frame; - alpha_extra_func_info_t proc_desc = frame->proc_desc; + alpha_extra_func_info_t proc_desc = frame->extra_info->proc_desc; + + /* we need proc_desc to know how to restore the registers; + if it is NULL, construct (a temporary) one */ + if (proc_desc == NULL) + proc_desc = find_proc_desc (frame->pc, frame->next); + + /* Question: should we copy this proc_desc and save it in + frame->proc_desc? If we do, who will free it? + For now, we don't save a copy... */ - write_register (PC_REGNUM, FRAME_SAVED_PC(frame)); + write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); if (frame->saved_regs == NULL) alpha_find_saved_regs (frame); if (proc_desc) { - for (regnum = 32; --regnum >= 0; ) - if (PROC_REG_MASK(proc_desc) & (1 << regnum)) + for (regnum = 32; --regnum >= 0;) + if (PROC_REG_MASK (proc_desc) & (1 << regnum)) write_register (regnum, read_memory_integer (frame->saved_regs[regnum], 8)); - for (regnum = 32; --regnum >= 0; ) - if (PROC_FREG_MASK(proc_desc) & (1 << regnum)) + for (regnum = 32; --regnum >= 0;) + if (PROC_FREG_MASK (proc_desc) & (1 << regnum)) write_register (regnum + FP0_REGNUM, - read_memory_integer (frame->saved_regs[regnum + FP0_REGNUM], 8)); + read_memory_integer (frame->saved_regs[regnum + FP0_REGNUM], 8)); } write_register (SP_REGNUM, new_sp); flush_cached_frames (); - if (proc_desc && (PROC_DESC_IS_DUMMY(proc_desc) + if (proc_desc && (PROC_DESC_IS_DUMMY (proc_desc) || PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))) { struct linked_proc_info *pi_ptr, *prev_ptr; @@ -1145,7 +1282,7 @@ alpha_pop_frame() else linked_proc_desc_table = pi_ptr->next; - free (pi_ptr); + xfree (pi_ptr); } } @@ -1155,79 +1292,86 @@ alpha_pop_frame() 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. */ + Currently we must not skip more on the alpha, but we might need the + lenient stuff some day. */ -CORE_ADDR -alpha_skip_prologue (pc, lenient) - CORE_ADDR pc; - int lenient; +static CORE_ADDR +alpha_skip_prologue_internal (CORE_ADDR pc, int lenient) { - unsigned long inst; - int offset; - CORE_ADDR post_prologue_pc; - char buf[4]; + unsigned long inst; + int offset; + CORE_ADDR post_prologue_pc; + char buf[4]; #ifdef GDB_TARGET_HAS_SHARED_LIBS - /* Silently return the unaltered pc upon memory errors. - This could happen on OSF/1 if decode_line_1 tries to skip the - prologue for quickstarted shared library functions when the - shared library is not yet mapped in. - Reading target memory is slow over serial lines, so we perform - this check only if the target has shared libraries. */ - if (target_read_memory (pc, buf, 4)) - return pc; + /* Silently return the unaltered pc upon memory errors. + This could happen on OSF/1 if decode_line_1 tries to skip the + prologue for quickstarted shared library functions when the + shared library is not yet mapped in. + Reading target memory is slow over serial lines, so we perform + this check only if the target has shared libraries. */ + if (target_read_memory (pc, buf, 4)) + return pc; #endif - /* See if we can determine the end of the prologue via the symbol table. - If so, then return either PC, or the PC after the prologue, whichever - is greater. */ - - post_prologue_pc = after_prologue (pc, NULL); + /* See if we can determine the end of the prologue via the symbol table. + If so, then return either PC, or the PC after the prologue, whichever + is greater. */ - if (post_prologue_pc != 0) - return max (pc, post_prologue_pc); - - /* Can't determine prologue from the symbol table, need to examine - instructions. */ - - /* 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) - { - int status; + post_prologue_pc = after_prologue (pc, NULL); - status = read_memory_nobpt (pc + offset, buf, 4); - if (status) - memory_error (status, pc + offset); - inst = extract_unsigned_integer (buf, 4); + if (post_prologue_pc != 0) + return max (pc, post_prologue_pc); - /* 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; + /* Can't determine prologue from the symbol table, need to examine + instructions. */ - 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; + /* 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) + { + 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; + if ((inst & 0xffe01fff) == 0x43c0153e) /* subq $sp,n,$sp */ + continue; + + if ((inst & 0xfc1f0000) == 0xb41e0000 + && (inst & 0xffff0000) != 0xb7fe0000) + continue; /* stq reg,n($sp) */ + /* reg != $zero */ + if ((inst & 0xfc1f0000) == 0x9c1e0000 + && (inst & 0xffff0000) != 0x9ffe0000) + continue; /* stt reg,n($sp) */ + /* reg != $zero */ + if (inst == 0x47de040f) /* bis sp,sp,fp */ + continue; + + break; } - return pc + offset; + return pc + offset; +} + +CORE_ADDR +alpha_skip_prologue (CORE_ADDR addr) +{ + return (alpha_skip_prologue_internal (addr, 0)); } #if 0 @@ -1235,27 +1379,22 @@ alpha_skip_prologue (pc, lenient) STARTADDR? */ static int -alpha_in_lenient_prologue (startaddr, pc) - CORE_ADDR startaddr; - CORE_ADDR pc; +alpha_in_lenient_prologue (CORE_ADDR startaddr, CORE_ADDR pc) { - CORE_ADDR end_prologue = alpha_skip_prologue (startaddr, 1); + CORE_ADDR end_prologue = alpha_skip_prologue_internal (startaddr, 1); return pc >= startaddr && pc < end_prologue; } #endif /* The alpha needs a conversion between register and memory format if the register is a floating point register and - memory format is float, as the register format must be double + memory format is float, as the register format must be double or - memory format is an integer with 4 bytes or less, as the representation - of integers in floating point registers is different. */ + memory format is an integer with 4 bytes or less, as the representation + of integers in floating point registers is different. */ void -alpha_register_convert_to_virtual (regnum, valtype, raw_buffer, virtual_buffer) - int regnum; - struct type *valtype; - char *raw_buffer; - char *virtual_buffer; +alpha_register_convert_to_virtual (int regnum, struct type *valtype, + char *raw_buffer, char *virtual_buffer) { if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) { @@ -1280,11 +1419,8 @@ alpha_register_convert_to_virtual (regnum, valtype, raw_buffer, virtual_buffer) } void -alpha_register_convert_to_raw (valtype, regnum, virtual_buffer, raw_buffer) - struct type *valtype; - int regnum; - char *virtual_buffer; - char *raw_buffer; +alpha_register_convert_to_raw (struct type *valtype, int regnum, + char *virtual_buffer, char *raw_buffer) { if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) { @@ -1315,10 +1451,8 @@ alpha_register_convert_to_raw (valtype, regnum, virtual_buffer, raw_buffer) extract and copy its value into `valbuf'. */ void -alpha_extract_return_value (valtype, regbuf, valbuf) - struct type *valtype; - char regbuf[REGISTER_BYTES]; - char *valbuf; +alpha_extract_return_value (struct type *valtype, + char regbuf[REGISTER_BYTES], char *valbuf) { if (TYPE_CODE (valtype) == TYPE_CODE_FLT) alpha_register_convert_to_virtual (FP0_REGNUM, valtype, @@ -1332,14 +1466,12 @@ alpha_extract_return_value (valtype, regbuf, valbuf) write its value into the appropriate register. */ void -alpha_store_return_value (valtype, valbuf) - struct type *valtype; - char *valbuf; +alpha_store_return_value (struct type *valtype, char *valbuf) { char raw_buffer[MAX_REGISTER_RAW_SIZE]; int regnum = V0_REGNUM; int length = TYPE_LENGTH (valtype); - + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) { regnum = FP0_REGNUM; @@ -1356,10 +1488,7 @@ alpha_store_return_value (valtype, valbuf) 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_sfunc (char *args, int from_tty, struct cmd_list_element *c) { reinit_frame_cache (); } @@ -1370,7 +1499,7 @@ reinit_frame_cache_sfunc (args, from_tty, c) */ CORE_ADDR -alpha_call_dummy_address () +alpha_call_dummy_address (void) { CORE_ADDR entry; struct minimal_symbol *sym; @@ -1389,7 +1518,154 @@ alpha_call_dummy_address () } void -_initialize_alpha_tdep () +alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, + struct value **args, struct type *type, int gcc_p) +{ + CORE_ADDR bp_address = CALL_DUMMY_ADDRESS (); + + if (bp_address == 0) + error ("no place to put call"); + write_register (RA_REGNUM, bp_address); + write_register (T12_REGNUM, fun); +} + +/* On the Alpha, the call dummy code is nevery copied to user space + (see alpha_fix_call_dummy() above). The contents of this do not + matter. */ +LONGEST alpha_call_dummy_words[] = { 0 }; + +int +alpha_use_struct_convention (int gcc_p, struct type *type) +{ + /* Structures are returned by ref in extra arg0. */ + return 1; +} + +void +alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +{ + /* Store the address of the place in which to copy the structure the + subroutine will return. Handled by alpha_push_arguments. */ +} + +CORE_ADDR +alpha_extract_struct_value_address (char *regbuf) +{ + return (extract_address (regbuf + REGISTER_BYTE (V0_REGNUM), + REGISTER_RAW_SIZE (V0_REGNUM))); +} + +/* alpha_software_single_step() is called just before we want to resume + the inferior, if we want to single-step it but there is no hardware + or kernel single-step support (NetBSD on Alpha, for example). We find + the target of the coming instruction and breakpoint it. + + single_step is also called just after the inferior stops. If we had + set up a simulated single-step, we undo our damage. */ + +static CORE_ADDR +alpha_next_pc (CORE_ADDR pc) +{ + unsigned int insn; + unsigned int op; + int offset; + LONGEST rav; + + insn = read_memory_unsigned_integer (pc, sizeof (insn)); + + /* Opcode is top 6 bits. */ + op = (insn >> 26) & 0x3f; + + if (op == 0x1a) + { + /* Jump format: target PC is: + RB & ~3 */ + return (read_register ((insn >> 16) & 0x1f) & ~3); + } + + if ((op & 0x30) == 0x30) + { + /* Branch format: target PC is: + (new PC) + (4 * sext(displacement)) */ + if (op == 0x30 || /* BR */ + op == 0x34) /* BSR */ + { + branch_taken: + offset = (insn & 0x001fffff); + if (offset & 0x00100000) + offset |= 0xffe00000; + offset *= 4; + return (pc + 4 + offset); + } + + /* Need to determine if branch is taken; read RA. */ + rav = (LONGEST) read_register ((insn >> 21) & 0x1f); + switch (op) + { + case 0x38: /* BLBC */ + if ((rav & 1) == 0) + goto branch_taken; + break; + case 0x3c: /* BLBS */ + if (rav & 1) + goto branch_taken; + break; + case 0x39: /* BEQ */ + if (rav == 0) + goto branch_taken; + break; + case 0x3d: /* BNE */ + if (rav != 0) + goto branch_taken; + break; + case 0x3a: /* BLT */ + if (rav < 0) + goto branch_taken; + break; + case 0x3b: /* BLE */ + if (rav <= 0) + goto branch_taken; + break; + case 0x3f: /* BGT */ + if (rav > 0) + goto branch_taken; + break; + case 0x3e: /* BGE */ + if (rav >= 0) + goto branch_taken; + break; + } + } + + /* Not a branch or branch not taken; target PC is: + pc + 4 */ + return (pc + 4); +} + +void +alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p) +{ + static CORE_ADDR next_pc; + typedef char binsn_quantum[BREAKPOINT_MAX]; + static binsn_quantum break_mem; + CORE_ADDR pc; + + if (insert_breakpoints_p) + { + pc = read_pc (); + next_pc = alpha_next_pc (pc); + + target_insert_breakpoint (next_pc, break_mem); + } + else + { + target_remove_breakpoint (next_pc, break_mem); + write_pc (next_pc); + } +} + +void +_initialize_alpha_tdep (void) { struct cmd_list_element *c; @@ -1410,6 +1686,6 @@ 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; + set_cmd_sfunc (c, reinit_frame_cache_sfunc); add_show_from_set (c, &showlist); } diff --git a/contrib/gdb/gdb/coffread.c b/contrib/gdb/gdb/coffread.c index 60a524f..84b3761 100644 --- a/contrib/gdb/gdb/coffread.c +++ b/contrib/gdb/gdb/coffread.c @@ -1,23 +1,25 @@ /* Read coff symbol tables and convert to internal format, for GDB. - Copyright 1987, 88, 89, 90, 91, 92, 93, 94, 96, 97, 1998 - Free Software Foundation, Inc. + Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. Contributed by David D. Johnson, Brown University (ddj@cs.brown.edu). -This file is part of GDB. + 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 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. + 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. */ + 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 "symtab.h" @@ -41,17 +43,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stabsread.h" #include "complaints.h" #include "target.h" +#include "gdb_assert.h" -struct coff_symfile_info { - file_ptr min_lineno_offset; /* Where in file lowest line#s are */ - file_ptr max_lineno_offset; /* 1+last byte of line#s in file */ +extern void _initialize_coffread (void); - CORE_ADDR textaddr; /* Addr of .text section. */ - unsigned int textsize; /* Size of .text section. */ - struct stab_section_list *stabsects; /* .stab sections. */ - asection *stabstrsect; /* Section pointer for .stab section */ - char *stabstrdata; -}; +struct coff_symfile_info + { + file_ptr min_lineno_offset; /* Where in file lowest line#s are */ + file_ptr max_lineno_offset; /* 1+last byte of line#s in file */ + + CORE_ADDR textaddr; /* Addr of .text section. */ + unsigned int textsize; /* Size of .text section. */ + struct stab_section_list *stabsects; /* .stab sections. */ + asection *stabstrsect; /* Section pointer for .stab section */ + char *stabstrdata; + }; /* Translate an external name string into a user-visible name. */ #define EXTERNAL_NAME(string, abfd) \ @@ -64,14 +70,6 @@ struct coff_symfile_info { #define SDB_TYPE(type) (BTYPE(type) | (type & N_TMASK)) -/* Convert from an sdb register number to an internal gdb register number. - This should be defined in tm.h, if REGISTER_NAMES is not set up - to map one to one onto the sdb register numbers. */ - -#ifndef SDB_REG_TO_REGNUM -# define SDB_REG_TO_REGNUM(value) (value) -#endif - /* Core address of start and end of text of current source file. This comes from a ".text" symbol where x_nlinno > 0. */ @@ -84,21 +82,6 @@ static CORE_ADDR current_source_end_addr; static bfd *nlist_bfd_global; static int nlist_nsyms_global; -/* Vector of line number information. */ - -static struct linetable *line_vector; - -/* Index of next entry to go in line_vector_index. */ - -static int line_vector_index; - -/* Last line number recorded in the line vector. */ - -static int prev_line_number; - -/* Number of elements allocated for line_vector currently. */ - -static int line_vector_length; /* Pointers to scratch storage, used for reading raw symbols and auxents. */ @@ -111,24 +94,24 @@ static char *temp_aux; internally to the BTYPE, ISPTR, ISFCN, ISARY, ISTAG, and DECREF macros from include/coff/internal.h . */ -static unsigned local_n_btmask; -static unsigned local_n_btshft; -static unsigned local_n_tmask; -static unsigned local_n_tshift; +static unsigned local_n_btmask; +static unsigned local_n_btshft; +static unsigned local_n_tmask; +static unsigned local_n_tshift; #define N_BTMASK local_n_btmask #define N_BTSHFT local_n_btshft #define N_TMASK local_n_tmask #define N_TSHIFT local_n_tshift - + /* Local variables that hold the sizes in the file of various COFF structures. (We only need to know this to read them from the file -- BFD will then translate the data in them, into `internal_xxx' structs in the right byte order, alignment, etc.) */ -static unsigned local_linesz; -static unsigned local_symesz; -static unsigned local_auxesz; +static unsigned local_linesz; +static unsigned local_symesz; +static unsigned local_auxesz; /* This is set if this is a PE format file. */ @@ -141,124 +124,96 @@ static struct symbol *opaque_type_chain[HASHSIZE]; /* Complaints about various problems in the file being read */ -struct complaint ef_complaint = - {"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0}; +struct complaint ef_complaint = +{"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0}; -struct complaint ef_stack_complaint = - {"`.ef' symbol without matching `.bf' symbol ignored starting at symnum %d", 0, 0}; +struct complaint ef_stack_complaint = +{"`.ef' symbol without matching `.bf' symbol ignored starting at symnum %d", 0, 0}; -struct complaint eb_stack_complaint = - {"`.eb' symbol without matching `.bb' symbol ignored starting at symnum %d", 0, 0}; +struct complaint eb_stack_complaint = +{"`.eb' symbol without matching `.bb' symbol ignored starting at symnum %d", 0, 0}; struct complaint bf_no_aux_complaint = - {"`.bf' symbol %d has no aux entry", 0, 0}; +{"`.bf' symbol %d has no aux entry", 0, 0}; struct complaint ef_no_aux_complaint = - {"`.ef' symbol %d has no aux entry", 0, 0}; +{"`.ef' symbol %d has no aux entry", 0, 0}; struct complaint lineno_complaint = - {"Line number pointer %d lower than start of line numbers", 0, 0}; +{"Line number pointer %d lower than start of line numbers", 0, 0}; struct complaint unexpected_type_complaint = - {"Unexpected type for symbol %s", 0, 0}; +{"Unexpected type for symbol %s", 0, 0}; struct complaint bad_sclass_complaint = - {"Bad n_sclass for symbol %s", 0, 0}; +{"Bad n_sclass for symbol %s", 0, 0}; struct complaint misordered_blocks_complaint = - {"Blocks out of order at address %x", 0, 0}; +{"Blocks out of order at address %x", 0, 0}; struct complaint tagndx_bad_complaint = - {"Symbol table entry for %s has bad tagndx value", 0, 0}; +{"Symbol table entry for %s has bad tagndx value", 0, 0}; -struct complaint eb_complaint = - {"Mismatched .eb symbol ignored starting at symnum %d", 0, 0}; +struct complaint eb_complaint = +{"Mismatched .eb symbol ignored starting at symnum %d", 0, 0}; /* Simplified internal version of coff symbol table information */ -struct coff_symbol { - char *c_name; - int c_symnum; /* symbol number of this entry */ - int c_naux; /* 0 if syment only, 1 if syment + auxent, etc */ - long c_value; - int c_sclass; - int c_secnum; - unsigned int c_type; -}; - -static struct type *coff_read_struct_type PARAMS ((int, int, int)); - -static struct type *decode_base_type PARAMS ((struct coff_symbol *, - unsigned int, - union internal_auxent *)); - -static struct type *decode_type PARAMS ((struct coff_symbol *, unsigned int, - union internal_auxent *)); - -static struct type *decode_function_type PARAMS ((struct coff_symbol *, - unsigned int, - union internal_auxent *)); - -static struct type *coff_read_enum_type PARAMS ((int, int, int)); - -static struct symbol *process_coff_symbol PARAMS ((struct coff_symbol *, - union internal_auxent *, - struct section_offsets *, - struct objfile *)); - -static void patch_opaque_types PARAMS ((struct symtab *)); - -static void patch_type PARAMS ((struct type *, struct type *)); - -static void enter_linenos PARAMS ((long, int, int, struct section_offsets *)); - -static void free_linetab PARAMS ((void)); - -static int init_lineno PARAMS ((bfd *, long, int)); +struct coff_symbol + { + char *c_name; + int c_symnum; /* symbol number of this entry */ + int c_naux; /* 0 if syment only, 1 if syment + auxent, etc */ + long c_value; + int c_sclass; + int c_secnum; + unsigned int c_type; + }; -static char *getsymname PARAMS ((struct internal_syment *)); +extern void stabsread_clear_cache (void); -static char *coff_getfilename PARAMS ((union internal_auxent *)); +static struct type *coff_read_struct_type (int, int, int); -static void free_stringtab PARAMS ((void)); +static struct type *decode_base_type (struct coff_symbol *, + unsigned int, union internal_auxent *); -static int init_stringtab PARAMS ((bfd *, long)); +static struct type *decode_type (struct coff_symbol *, unsigned int, + union internal_auxent *); -static void read_one_sym PARAMS ((struct coff_symbol *, - struct internal_syment *, - union internal_auxent *)); +static struct type *decode_function_type (struct coff_symbol *, + unsigned int, + union internal_auxent *); -static void coff_symtab_read PARAMS ((long, int, struct section_offsets *, - struct objfile *)); +static struct type *coff_read_enum_type (int, int, int); -static void find_linenos PARAMS ((bfd *, sec_ptr, PTR)); +static struct symbol *process_coff_symbol (struct coff_symbol *, + union internal_auxent *, + struct objfile *); -static void coff_symfile_init PARAMS ((struct objfile *)); +static void patch_opaque_types (struct symtab *); -static void coff_new_init PARAMS ((struct objfile *)); +static void enter_linenos (long, int, int, struct objfile *); -static void coff_symfile_read PARAMS ((struct objfile *, - struct section_offsets *, int)); +static void free_linetab (void); -static void coff_symfile_finish PARAMS ((struct objfile *)); +static void free_linetab_cleanup (void *ignore); -static void record_minimal_symbol PARAMS ((char *, CORE_ADDR, - enum minimal_symbol_type, - struct objfile *)); +static int init_lineno (bfd *, long, int); -static void coff_end_symtab PARAMS ((struct objfile *)); +static char *getsymname (struct internal_syment *); -static void complete_symtab PARAMS ((char *, CORE_ADDR, unsigned int)); +static char *coff_getfilename (union internal_auxent *); -static void coff_start_symtab PARAMS ((char *)); +static void free_stringtab (void); -static void coff_record_line PARAMS ((int, CORE_ADDR)); +static void free_stringtab_cleanup (void *ignore); -static struct type *coff_alloc_type PARAMS ((int)); +static int init_stringtab (bfd *, long); -static struct type **coff_lookup_type PARAMS ((int)); +static void read_one_sym (struct coff_symbol *, + struct internal_syment *, union internal_auxent *); -static void coff_locate_sections PARAMS ((bfd *, asection *, PTR)); +static void coff_symtab_read (long, unsigned int, struct objfile *); /* We are called once per section from coff_symfile_read. We need to examine each section we are passed, check to see @@ -271,10 +226,7 @@ static void coff_locate_sections PARAMS ((bfd *, asection *, PTR)); -kingdon). */ static void -coff_locate_sections (abfd, sectp, csip) - bfd *abfd; - asection *sectp; - PTR csip; +coff_locate_sections (bfd *abfd, asection *sectp, void *csip) { register struct coff_symfile_info *csi; const char *name; @@ -301,7 +253,7 @@ coff_locate_sections (abfd, sectp, csip) /* We can have multiple .stab sections if linked with --split-by-reloc. */ for (s = name + sizeof ".stab" - 1; *s != '\0'; s++) - if (! isdigit (*s)) + if (!isdigit (*s)) break; if (*s == '\0') { @@ -316,42 +268,37 @@ coff_locate_sections (abfd, sectp, csip) *pn = n; /* This will be run after coffstab_build_psymtabs is called - in coff_symfile_read, at which point we no longer need - the information. */ - make_cleanup (free, n); + in coff_symfile_read, at which point we no longer need + the information. */ + make_cleanup (xfree, n); } } } /* Return the section_offsets* that CS points to. */ -static int cs_to_section PARAMS ((struct coff_symbol *, struct objfile *)); - -struct find_targ_sec_arg { - int targ_index; - asection **resultp; -}; +static int cs_to_section (struct coff_symbol *, struct objfile *); -static void find_targ_sec PARAMS ((bfd *, asection *, void *)); +struct find_targ_sec_arg + { + int targ_index; + asection **resultp; + }; -static void find_targ_sec (abfd, sect, obj) - bfd *abfd; - asection *sect; - PTR obj; +static void +find_targ_sec (bfd *abfd, asection *sect, void *obj) { - struct find_targ_sec_arg *args = (struct find_targ_sec_arg *)obj; + struct find_targ_sec_arg *args = (struct find_targ_sec_arg *) obj; if (sect->target_index == args->targ_index) *args->resultp = sect; } /* Return the section number (SECT_OFF_*) that CS points to. */ static int -cs_to_section (cs, objfile) - struct coff_symbol *cs; - struct objfile *objfile; +cs_to_section (struct coff_symbol *cs, struct objfile *objfile) { asection *sect = NULL; struct find_targ_sec_arg args; - int off = SECT_OFF_TEXT; + int off = SECT_OFF_TEXT (objfile); args.targ_index = cs->c_secnum; args.resultp = § @@ -360,23 +307,22 @@ cs_to_section (cs, objfile) { /* This is the section. Figure out what SECT_OFF_* code it is. */ if (bfd_get_section_flags (abfd, sect) & SEC_CODE) - off = SECT_OFF_TEXT; + off = SECT_OFF_TEXT (objfile); else if (bfd_get_section_flags (abfd, sect) & SEC_LOAD) - off = SECT_OFF_DATA; + off = SECT_OFF_DATA (objfile); else - off = SECT_OFF_BSS; + /* Just return the bfd section index. */ + off = sect->index; } return off; } /* Return the address of the section of a COFF symbol. */ -static CORE_ADDR cs_section_address PARAMS ((struct coff_symbol *, bfd *)); +static CORE_ADDR cs_section_address (struct coff_symbol *, bfd *); static CORE_ADDR -cs_section_address (cs, abfd) - struct coff_symbol *cs; - bfd *abfd; +cs_section_address (struct coff_symbol *cs, bfd *abfd) { asection *sect = NULL; struct find_targ_sec_arg args; @@ -398,22 +344,21 @@ cs_section_address (cs, abfd) or for associating a new type with the index. */ static struct type ** -coff_lookup_type (index) - register int index; +coff_lookup_type (register int index) { if (index >= type_vector_length) { int old_vector_length = type_vector_length; type_vector_length *= 2; - if (index /* is still */ >= type_vector_length) + if (index /* is still */ >= type_vector_length) type_vector_length = index * 2; type_vector = (struct type **) xrealloc ((char *) type_vector, type_vector_length * sizeof (struct type *)); memset (&type_vector[old_vector_length], 0, - (type_vector_length - old_vector_length) * sizeof(struct type *)); + (type_vector_length - old_vector_length) * sizeof (struct type *)); } return &type_vector[index]; } @@ -423,8 +368,7 @@ coff_lookup_type (index) This can create an empty (zeroed) type object. */ static struct type * -coff_alloc_type (index) - int index; +coff_alloc_type (int index) { register struct type **type_addr = coff_lookup_type (index); register struct type *type = *type_addr; @@ -440,61 +384,25 @@ coff_alloc_type (index) return type; } -/* Record a line number entry for line LINE at address PC. - FIXME: Use record_line instead. */ - -static void -coff_record_line (line, pc) - int line; - CORE_ADDR pc; -{ - struct linetable_entry *e; - /* Make sure line vector is big enough. */ - - if (line_vector_index + 2 >= line_vector_length) - { - line_vector_length *= 2; - line_vector = (struct linetable *) - xrealloc ((char *) line_vector, sizeof (struct linetable) - + (line_vector_length - * sizeof (struct linetable_entry))); - } - - e = line_vector->item + line_vector_index++; - e->line = line; e->pc = pc; -} - /* Start a new symtab for a new source file. This is called when a COFF ".file" symbol is seen; it indicates the start of data for one original source file. */ static void -coff_start_symtab (name) - char *name; +coff_start_symtab (char *name) { start_symtab ( - /* We fill in the filename later. start_symtab puts - this pointer into last_source_file and we put it in - subfiles->name, which end_symtab frees; that's why - it must be malloc'd. */ - savestring (name, strlen(name)), - /* We never know the directory name for COFF. */ - NULL, - /* The start address is irrelevant, since we set - last_source_start_addr in coff_end_symtab. */ - 0); + /* We fill in the filename later. start_symtab puts + this pointer into last_source_file and we put it in + subfiles->name, which end_symtab frees; that's why + it must be malloc'd. */ + savestring (name, strlen (name)), + /* We never know the directory name for COFF. */ + NULL, + /* The start address is irrelevant, since we set + last_source_start_addr in coff_end_symtab. */ + 0); record_debugformat ("COFF"); - - /* Initialize the source file line number information for this file. */ - - if (line_vector) /* Unlikely, but maybe possible? */ - free ((PTR)line_vector); - line_vector_index = 0; - line_vector_length = 1000; - prev_line_number = -2; /* Force first line number to be explicit */ - line_vector = (struct linetable *) - xmalloc (sizeof (struct linetable) - + line_vector_length * sizeof (struct linetable_entry)); } /* Save the vital information from when starting to read a file, @@ -503,22 +411,19 @@ coff_start_symtab (name) text address for the file, and SIZE is the number of bytes of text. */ static void -complete_symtab (name, start_addr, size) - char *name; - CORE_ADDR start_addr; - unsigned int size; +complete_symtab (char *name, CORE_ADDR start_addr, unsigned int size) { if (last_source_file != NULL) - free (last_source_file); + xfree (last_source_file); last_source_file = savestring (name, strlen (name)); current_source_start_addr = start_addr; current_source_end_addr = start_addr + size; - if (current_objfile -> ei.entry_point >= current_source_start_addr && - current_objfile -> ei.entry_point < current_source_end_addr) + if (current_objfile->ei.entry_point >= current_source_start_addr && + current_objfile->ei.entry_point < current_source_end_addr) { - current_objfile -> ei.entry_file_lowpc = current_source_start_addr; - current_objfile -> ei.entry_file_highpc = current_source_end_addr; + current_objfile->ei.entry_file_lowpc = current_source_start_addr; + current_objfile->ei.entry_file_highpc = current_source_end_addr; } } @@ -528,45 +433,28 @@ complete_symtab (name, start_addr, size) struct symtab for that file and put it in the list of all such. */ static void -coff_end_symtab (objfile) - struct objfile *objfile; +coff_end_symtab (struct objfile *objfile) { struct symtab *symtab; last_source_start_addr = current_source_start_addr; - /* For no good reason, this file stores the number of entries in a - separate variable instead of in line_vector->nitems. Fix it. */ - if (line_vector) - line_vector->nitems = line_vector_index; - - /* For COFF, we only have one subfile, so we can just look at - subfiles and not worry about there being other elements in the - chain. We fill in various fields now because we didn't know them - before (or because doing it now is simply an artifact of how this - file used to be written). */ - subfiles->line_vector = line_vector; - - symtab = end_symtab (current_source_end_addr, objfile, 0); + symtab = end_symtab (current_source_end_addr, objfile, SECT_OFF_TEXT (objfile)); if (symtab != NULL) free_named_symtabs (symtab->filename); /* Reinitialize for beginning of new file. */ - line_vector = 0; - line_vector_length = -1; last_source_file = NULL; } static void -record_minimal_symbol (name, address, type, objfile) - char *name; - CORE_ADDR address; - enum minimal_symbol_type type; - struct objfile *objfile; +record_minimal_symbol (char *name, CORE_ADDR address, + enum minimal_symbol_type type, struct objfile *objfile) { /* We don't want TDESC entry points in the minimal symbol table */ - if (name[0] == '@') return; + if (name[0] == '@') + return; prim_record_minimal_symbol (name, address, type, objfile); } @@ -585,14 +473,14 @@ record_minimal_symbol (name, address, type, objfile) The ultimate result is a new symtab (or, FIXME, eventually a psymtab). */ static void -coff_symfile_init (objfile) - struct objfile *objfile; +coff_symfile_init (struct objfile *objfile) { /* Allocate struct to keep track of stab reading. */ objfile->sym_stab_info = (struct dbx_symfile_info *) xmmalloc (objfile->md, sizeof (struct dbx_symfile_info)); - memset ((PTR) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info)); + memset (objfile->sym_stab_info, 0, + sizeof (struct dbx_symfile_info)); /* Allocate struct to keep track of the symfile */ objfile->sym_private = xmmalloc (objfile->md, @@ -614,10 +502,7 @@ coff_symfile_init (objfile) /* ARGSUSED */ static void -find_linenos (abfd, asect, vpinfo) - bfd *abfd; - sec_ptr asect; - PTR vpinfo; +find_linenos (bfd *abfd, sec_ptr asect, void *vpinfo) { struct coff_symfile_info *info; int size, count; @@ -631,7 +516,7 @@ find_linenos (abfd, asect, vpinfo) return; size = count * local_linesz; - info = (struct coff_symfile_info *)vpinfo; + info = (struct coff_symfile_info *) vpinfo; /* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ offset = asect->line_filepos; /* End of warning */ @@ -654,10 +539,7 @@ static bfd *symfile_bfd; /* ARGSUSED */ static void -coff_symfile_read (objfile, section_offsets, mainline) - struct objfile *objfile; - struct section_offsets *section_offsets; - int mainline; +coff_symfile_read (struct objfile *objfile, int mainline) { struct coff_symfile_info *info; struct dbx_symfile_info *dbxinfo; @@ -665,82 +547,84 @@ coff_symfile_read (objfile, section_offsets, mainline) coff_data_type *cdata = coff_data (abfd); char *name = bfd_get_filename (abfd); register int val; - int num_symbols; + unsigned int num_symbols; int symtab_offset; int stringtab_offset; struct cleanup *back_to; int stabstrsize; - - info = (struct coff_symfile_info *) objfile -> sym_private; + int len; + char * target; + + info = (struct coff_symfile_info *) objfile->sym_private; dbxinfo = objfile->sym_stab_info; - symfile_bfd = abfd; /* Kludge for swap routines */ + symfile_bfd = abfd; /* Kludge for swap routines */ /* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ - num_symbols = bfd_get_symcount (abfd); /* How many syms */ - symtab_offset = cdata->sym_filepos; /* Symbol table file offset */ - stringtab_offset = symtab_offset + /* String table file offset */ - num_symbols * cdata->local_symesz; + num_symbols = bfd_get_symcount (abfd); /* How many syms */ + symtab_offset = cdata->sym_filepos; /* Symbol table file offset */ + stringtab_offset = symtab_offset + /* String table file offset */ + num_symbols * cdata->local_symesz; /* Set a few file-statics that give us specific information about the particular COFF file format we're reading. */ - local_linesz = cdata->local_linesz; local_n_btmask = cdata->local_n_btmask; local_n_btshft = cdata->local_n_btshft; - local_n_tmask = cdata->local_n_tmask; + local_n_tmask = cdata->local_n_tmask; local_n_tshift = cdata->local_n_tshift; - local_linesz = cdata->local_linesz; - local_symesz = cdata->local_symesz; - local_auxesz = cdata->local_auxesz; + local_linesz = cdata->local_linesz; + local_symesz = cdata->local_symesz; + local_auxesz = cdata->local_auxesz; /* Allocate space for raw symbol and aux entries, based on their space requirements as reported by BFD. */ temp_sym = (char *) xmalloc - (cdata->local_symesz + cdata->local_auxesz); + (cdata->local_symesz + cdata->local_auxesz); temp_aux = temp_sym + cdata->local_symesz; - back_to = make_cleanup ((make_cleanup_func) free_current_contents, &temp_sym); + back_to = make_cleanup (free_current_contents, &temp_sym); /* We need to know whether this is a PE file, because in PE files, unlike standard COFF files, symbol values are stored as offsets from the section address, rather than as absolute addresses. FIXME: We should use BFD to read the symbol table, and thus avoid this problem. */ - pe_file = strncmp (bfd_get_target (objfile->obfd), "pe", 2) == 0; + pe_file = + strncmp (bfd_get_target (objfile->obfd), "pe", 2) == 0 + || strncmp (bfd_get_target (objfile->obfd), "epoc-pe", 7) == 0; /* End of warning */ /* Read the line number table, all at once. */ info->min_lineno_offset = 0; info->max_lineno_offset = 0; - bfd_map_over_sections (abfd, find_linenos, (PTR) info); + bfd_map_over_sections (abfd, find_linenos, (void *) info); - make_cleanup ((make_cleanup_func) free_linetab, 0); - val = init_lineno (abfd, info->min_lineno_offset, + make_cleanup (free_linetab_cleanup, 0 /*ignore*/); + val = init_lineno (abfd, info->min_lineno_offset, info->max_lineno_offset - info->min_lineno_offset); if (val < 0) error ("\"%s\": error reading line numbers\n", name); /* Now read the string table, all at once. */ - make_cleanup ((make_cleanup_func) free_stringtab, 0); + make_cleanup (free_stringtab_cleanup, 0 /*ignore*/); val = init_stringtab (abfd, stringtab_offset); if (val < 0) error ("\"%s\": can't get string table", name); init_minimal_symbol_collection (); - make_cleanup ((make_cleanup_func) discard_minimal_symbols, 0); + make_cleanup_discard_minimal_symbols (); /* Now that the executable file is positioned at symbol table, process it and define symbols accordingly. */ - coff_symtab_read ((long) symtab_offset, num_symbols, section_offsets, - objfile); + coff_symtab_read ((long) symtab_offset, num_symbols, objfile); /* Sort symbols alphabetically within each block. */ { struct symtab *s; - for (s = objfile -> symtabs; s != NULL; s = s -> next) + for (s = objfile->symtabs; s != NULL; s = s->next) sort_symtab_syms (s); } @@ -749,30 +633,41 @@ coff_symfile_read (objfile, section_offsets, mainline) install_minimal_symbols (objfile); - bfd_map_over_sections (abfd, coff_locate_sections, (PTR) info); + bfd_map_over_sections (abfd, coff_locate_sections, (void *) info); if (info->stabsects) { + if (!info->stabstrsect) + { + error (("The debugging information in `%s' is corrupted.\n" + "The file has a `.stabs' section, but no `.stabstr' " + "section."), + name); + } + /* FIXME: dubious. Why can't we use something normal like - bfd_get_section_contents? */ + bfd_get_section_contents? */ bfd_seek (abfd, abfd->where, 0); stabstrsize = bfd_section_size (abfd, info->stabstrsect); coffstab_build_psymtabs (objfile, - section_offsets, mainline, info->textaddr, info->textsize, info->stabsects, info->stabstrsect->filepos, stabstrsize); } + if (dwarf2_has_info (abfd)) + { + /* DWARF2 sections. */ + dwarf2_build_psymtabs (objfile, mainline); + } do_cleanups (back_to); } static void -coff_new_init (ignore) - struct objfile *ignore; +coff_new_init (struct objfile *ignore) { } @@ -782,27 +677,26 @@ coff_new_init (ignore) objfile struct from the global list of known objfiles. */ static void -coff_symfile_finish (objfile) - struct objfile *objfile; +coff_symfile_finish (struct objfile *objfile) { - if (objfile -> sym_private != NULL) + if (objfile->sym_private != NULL) { - mfree (objfile -> md, objfile -> sym_private); + xmfree (objfile->md, objfile->sym_private); } -} + /* Let stabs reader clean up */ + stabsread_clear_cache (); +} + /* Given pointers to a symbol table in coff style exec file, analyze them and create struct symtab's describing the symbols. NSYMS is the number of symbols in the symbol table. We read them one at a time using read_one_sym (). */ static void -coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) - long symtab_offset; - int nsyms; - struct section_offsets *section_offsets; - struct objfile *objfile; +coff_symtab_read (long symtab_offset, unsigned int nsyms, + struct objfile *objfile) { register struct context_stack *new; struct coff_symbol coff_symbol; @@ -820,6 +714,7 @@ coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) char *filestring = ""; int depth = 0; int fcn_first_line = 0; + CORE_ADDR fcn_first_line_addr = 0; int fcn_last_line = 0; int fcn_start_addr = 0; long fcn_line_ptr = 0; @@ -853,8 +748,8 @@ coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) last_source_file = NULL; memset (opaque_type_chain, 0, sizeof opaque_type_chain); - if (type_vector) /* Get rid of previous one */ - free ((PTR) type_vector); + if (type_vector) /* Get rid of previous one */ + xfree (type_vector); type_vector_length = 160; type_vector = (struct type **) xmalloc (type_vector_length * sizeof (struct type *)); @@ -888,7 +783,7 @@ coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF) { /* Record all functions -- external and static -- in minsyms. */ - tmpaddr = cs->c_value + ANOFFSET (section_offsets, SECT_OFF_TEXT); + tmpaddr = cs->c_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); record_minimal_symbol (cs->c_name, tmpaddr, mst_text, objfile); fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; @@ -901,50 +796,51 @@ coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) switch (cs->c_sclass) { - case C_EFCN: - case C_EXTDEF: - case C_ULABEL: - case C_USTATIC: - case C_LINE: - case C_ALIAS: - case C_HIDDEN: - complain (&bad_sclass_complaint, cs->c_name); - break; - - case C_FILE: - /* c_value field contains symnum of next .file entry in table - or symnum of first global after last .file. */ - next_file_symnum = cs->c_value; - if (cs->c_naux > 0) - filestring = coff_getfilename (&main_aux); - else - filestring = ""; + case C_EFCN: + case C_EXTDEF: + case C_ULABEL: + case C_USTATIC: + case C_LINE: + case C_ALIAS: + case C_HIDDEN: + complain (&bad_sclass_complaint, cs->c_name); + break; - /* Complete symbol table for last object file - containing debugging information. */ - if (last_source_file) - { - coff_end_symtab (objfile); - coff_start_symtab (filestring); - } - in_source_file = 1; - break; + case C_FILE: + /* c_value field contains symnum of next .file entry in table + or symnum of first global after last .file. */ + next_file_symnum = cs->c_value; + if (cs->c_naux > 0) + filestring = coff_getfilename (&main_aux); + else + filestring = ""; + + /* Complete symbol table for last object file + containing debugging information. */ + if (last_source_file) + { + coff_end_symtab (objfile); + coff_start_symtab (filestring); + } + in_source_file = 1; + break; /* C_LABEL is used for labels and static functions. Including it here allows gdb to see static functions when no debug info is available. */ - case C_LABEL: - /* However, labels within a function can make weird backtraces, - so filter them out (from phdm@macqel.be). */ - if (within_function) - break; - case C_STAT: - case C_THUMBLABEL: - case C_THUMBSTAT: - case C_THUMBSTATFUNC: - if (cs->c_name[0] == '.') - { - if (STREQ (cs->c_name, ".text")) { + case C_LABEL: + /* However, labels within a function can make weird backtraces, + so filter them out (from phdm@macqel.be). */ + if (within_function) + break; + case C_STAT: + case C_THUMBLABEL: + case C_THUMBSTAT: + case C_THUMBSTATFUNC: + if (cs->c_name[0] == '.') + { + if (STREQ (cs->c_name, ".text")) + { /* FIXME: don't wire in ".text" as section name or symbol name! */ /* Check for in_source_file deals with case of @@ -952,236 +848,247 @@ coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) followed by a later file with no symbols. */ if (in_source_file) complete_symtab (filestring, - cs->c_value + ANOFFSET (section_offsets, SECT_OFF_TEXT), + cs->c_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)), main_aux.x_scn.x_scnlen); in_source_file = 0; } - /* flush rest of '.' symbols */ - break; - } - else if (!SDB_TYPE (cs->c_type) - && cs->c_name[0] == 'L' - && (strncmp (cs->c_name, "LI%", 3) == 0 - || strncmp (cs->c_name, "LF%", 3) == 0 - || strncmp (cs->c_name,"LC%",3) == 0 - || strncmp (cs->c_name,"LP%",3) == 0 - || strncmp (cs->c_name,"LPB%",4) == 0 - || strncmp (cs->c_name,"LBB%",4) == 0 - || strncmp (cs->c_name,"LBE%",4) == 0 - || strncmp (cs->c_name,"LPBX%",5) == 0)) - /* At least on a 3b1, gcc generates swbeg and string labels - that look like this. Ignore them. */ + /* flush rest of '.' symbols */ break; - /* fall in for static symbols that don't start with '.' */ - case C_THUMBEXT: - case C_THUMBEXTFUNC: - case C_EXT: - { - /* Record it in the minimal symbols regardless of - SDB_TYPE. This parallels what we do for other debug - formats, and probably is needed to make - print_address_symbolic work right without the (now - gone) "set fast-symbolic-addr off" kludge. */ - - /* FIXME: should use mst_abs, and not relocate, if absolute. */ - enum minimal_symbol_type ms_type; - int sec; - - if (cs->c_secnum == N_UNDEF) - { - /* This is a common symbol. See if the target - environment knows where it has been relocated to. */ - CORE_ADDR reladdr; - if (target_lookup_symbol (cs->c_name, &reladdr)) - { - /* Error in lookup; ignore symbol. */ - break; - } - tmpaddr = reladdr; - /* The address has already been relocated; make sure that - objfile_relocate doesn't relocate it again. */ - sec = -2; - ms_type = cs->c_sclass == C_EXT - || cs->c_sclass == C_THUMBEXT ? - mst_bss : mst_file_bss; - } - else - { - sec = cs_to_section (cs, objfile); - tmpaddr = cs->c_value; - if (cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC - || cs->c_sclass == C_THUMBEXT) - tmpaddr += ANOFFSET (section_offsets, sec); - - switch (sec) - { - case SECT_OFF_TEXT: - case SECT_OFF_RODATA: - ms_type = - cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC - || cs->c_sclass == C_THUMBEXT ? - mst_text : mst_file_text; -#ifdef SMASH_TEXT_ADDRESS - if (tmpaddr & 1) /* FIXME: delete this line */ - SMASH_TEXT_ADDRESS (tmpaddr); -#endif - break; - case SECT_OFF_DATA: - ms_type = - cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT ? - mst_data : mst_file_data; - break; - case SECT_OFF_BSS: - ms_type = - cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT ? - mst_data : mst_file_data; - break; - default: - ms_type = mst_unknown; - break; - } - } - - if (cs->c_name[0] != '@' /* Skip tdesc symbols */) - { - struct minimal_symbol *msym; - - msym = prim_record_minimal_symbol_and_info - (cs->c_name, tmpaddr, ms_type, (char *)(long)cs->c_sclass, sec, - NULL, objfile); -#ifdef COFF_MAKE_MSYMBOL_SPECIAL - if(msym) - COFF_MAKE_MSYMBOL_SPECIAL(cs->c_sclass, msym); -#endif - } - if (SDB_TYPE (cs->c_type)) - { - struct symbol *sym; - sym = process_coff_symbol - (cs, &main_aux, section_offsets, objfile); - SYMBOL_VALUE (sym) = tmpaddr; - SYMBOL_SECTION (sym) = sec; - } } + else if (!SDB_TYPE (cs->c_type) + && cs->c_name[0] == 'L' + && (strncmp (cs->c_name, "LI%", 3) == 0 + || strncmp (cs->c_name, "LF%", 3) == 0 + || strncmp (cs->c_name, "LC%", 3) == 0 + || strncmp (cs->c_name, "LP%", 3) == 0 + || strncmp (cs->c_name, "LPB%", 4) == 0 + || strncmp (cs->c_name, "LBB%", 4) == 0 + || strncmp (cs->c_name, "LBE%", 4) == 0 + || strncmp (cs->c_name, "LPBX%", 5) == 0)) + /* At least on a 3b1, gcc generates swbeg and string labels + that look like this. Ignore them. */ break; + /* fall in for static symbols that don't start with '.' */ + case C_THUMBEXT: + case C_THUMBEXTFUNC: + case C_EXT: + { + /* Record it in the minimal symbols regardless of + SDB_TYPE. This parallels what we do for other debug + formats, and probably is needed to make + print_address_symbolic work right without the (now + gone) "set fast-symbolic-addr off" kludge. */ - case C_FCN: - if (STREQ (cs->c_name, ".bf")) - { - within_function = 1; - - /* value contains address of first non-init type code */ - /* main_aux.x_sym.x_misc.x_lnsz.x_lnno - contains line number of '{' } */ - if (cs->c_naux != 1) - complain (&bf_no_aux_complaint, cs->c_symnum); - fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; - - /* Might want to check that locals are 0 and - context_stack_depth is zero, and complain if not. */ - - depth = 0; - new = push_context (depth, fcn_start_addr); - fcn_cs_saved.c_name = getsymname (&fcn_sym_saved); - new->name = - process_coff_symbol (&fcn_cs_saved, &fcn_aux_saved, - section_offsets, objfile); - } - else if (STREQ (cs->c_name, ".ef")) + /* FIXME: should use mst_abs, and not relocate, if absolute. */ + enum minimal_symbol_type ms_type; + int sec; + + if (cs->c_secnum == N_UNDEF) { - /* the value of .ef is the address of epilogue code; - not useful for gdb. */ - /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno - contains number of lines to '}' */ - - if (context_stack_depth <= 0) - { /* We attempted to pop an empty context stack */ - complain (&ef_stack_complaint, cs->c_symnum); - within_function = 0; + /* This is a common symbol. See if the target + environment knows where it has been relocated to. */ + CORE_ADDR reladdr; + if (target_lookup_symbol (cs->c_name, &reladdr)) + { + /* Error in lookup; ignore symbol. */ break; } + tmpaddr = reladdr; + /* The address has already been relocated; make sure that + objfile_relocate doesn't relocate it again. */ + sec = -2; + ms_type = cs->c_sclass == C_EXT + || cs->c_sclass == C_THUMBEXT ? + mst_bss : mst_file_bss; + } + else + { + sec = cs_to_section (cs, objfile); + tmpaddr = cs->c_value; + if (cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC + || cs->c_sclass == C_THUMBEXT) + tmpaddr += ANOFFSET (objfile->section_offsets, sec); - new = pop_context (); - /* Stack must be empty now. */ - if (context_stack_depth > 0 || new == NULL) + if (sec == SECT_OFF_TEXT (objfile)) { - complain (&ef_complaint, cs->c_symnum); - within_function = 0; - break; + ms_type = + cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC + || cs->c_sclass == C_THUMBEXT ? + mst_text : mst_file_text; + tmpaddr = SMASH_TEXT_ADDRESS (tmpaddr); } - if (cs->c_naux != 1) + else if (sec == SECT_OFF_DATA (objfile)) { - complain (&ef_no_aux_complaint, cs->c_symnum); - fcn_last_line = 0x7FFFFFFF; + ms_type = + cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT ? + mst_data : mst_file_data; } - else + else if (sec == SECT_OFF_BSS (objfile)) { - fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + ms_type = + cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXT ? + mst_data : mst_file_data; } + else + ms_type = mst_unknown; + } + + if (cs->c_name[0] != '@' /* Skip tdesc symbols */ ) + { + struct minimal_symbol *msym; + + /* FIXME: cagney/2001-02-01: The nasty (int) -> (long) + -> (void*) cast is to ensure that that the value of + cs->c_sclass can be correctly stored in a void + pointer in MSYMBOL_INFO. Better solutions + welcome. */ + gdb_assert (sizeof (void *) >= sizeof (cs->c_sclass)); + msym = prim_record_minimal_symbol_and_info + (cs->c_name, tmpaddr, ms_type, (void *) (long) cs->c_sclass, + sec, NULL, objfile); + if (msym) + COFF_MAKE_MSYMBOL_SPECIAL (cs->c_sclass, msym); + } + if (SDB_TYPE (cs->c_type)) + { + struct symbol *sym; + sym = process_coff_symbol + (cs, &main_aux, objfile); + SYMBOL_VALUE (sym) = tmpaddr; + SYMBOL_SECTION (sym) = sec; + } + } + break; + + case C_FCN: + if (STREQ (cs->c_name, ".bf")) + { + within_function = 1; + + /* value contains address of first non-init type code */ + /* main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains line number of '{' } */ + if (cs->c_naux != 1) + complain (&bf_no_aux_complaint, cs->c_symnum); + fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + fcn_first_line_addr = cs->c_value; + + /* Might want to check that locals are 0 and + context_stack_depth is zero, and complain if not. */ + + depth = 0; + new = push_context (depth, fcn_start_addr); + fcn_cs_saved.c_name = getsymname (&fcn_sym_saved); + new->name = + process_coff_symbol (&fcn_cs_saved, &fcn_aux_saved, objfile); + } + else if (STREQ (cs->c_name, ".ef")) + { + if (!within_function) + error ("Bad coff function information\n"); + /* the value of .ef is the address of epilogue code; + not useful for gdb. */ + /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains number of lines to '}' */ + + if (context_stack_depth <= 0) + { /* We attempted to pop an empty context stack */ + complain (&ef_stack_complaint, cs->c_symnum); + within_function = 0; + break; + } + + new = pop_context (); + /* Stack must be empty now. */ + if (context_stack_depth > 0 || new == NULL) + { + complain (&ef_complaint, cs->c_symnum); + within_function = 0; + break; + } + if (cs->c_naux != 1) + { + complain (&ef_no_aux_complaint, cs->c_symnum); + fcn_last_line = 0x7FFFFFFF; + } + else + { + fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + } + /* fcn_first_line is the line number of the opening '{'. + Do not record it - because it would affect gdb's idea + of the line number of the first statement of the function - + except for one-line functions, for which it is also the line + number of all the statements and of the closing '}', and + for which we do not have any other statement-line-number. */ + if (fcn_last_line == 1) + record_line (current_subfile, fcn_first_line, + fcn_first_line_addr); + else enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line, - section_offsets); + objfile); - finish_block (new->name, &local_symbols, new->old_blocks, - new->start_addr, + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, #if defined (FUNCTION_EPILOGUE_SIZE) - /* This macro should be defined only on - machines where the - fcn_aux_saved.x_sym.x_misc.x_fsize - field is always zero. - So use the .bf record information that - points to the epilogue and add the size - of the epilogue. */ - cs->c_value - + FUNCTION_EPILOGUE_SIZE - + ANOFFSET (section_offsets, SECT_OFF_TEXT), + /* This macro should be defined only on + machines where the + fcn_aux_saved.x_sym.x_misc.x_fsize + field is always zero. + So use the .bf record information that + points to the epilogue and add the size + of the epilogue. */ + cs->c_value + + FUNCTION_EPILOGUE_SIZE + + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)), #else - fcn_cs_saved.c_value - + fcn_aux_saved.x_sym.x_misc.x_fsize - + ANOFFSET (section_offsets, SECT_OFF_TEXT), + fcn_cs_saved.c_value + + fcn_aux_saved.x_sym.x_misc.x_fsize + + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)), #endif - objfile - ); - within_function = 0; - } - break; + objfile + ); + within_function = 0; + } + break; - case C_BLOCK: - if (STREQ (cs->c_name, ".bb")) - { - tmpaddr = cs->c_value; - tmpaddr += ANOFFSET (section_offsets, SECT_OFF_TEXT); - push_context (++depth, tmpaddr); - } - else if (STREQ (cs->c_name, ".eb")) - { - if (context_stack_depth <= 0) - { /* We attempted to pop an empty context stack */ - complain (&eb_stack_complaint, cs->c_symnum); - break; - } + case C_BLOCK: + if (STREQ (cs->c_name, ".bb")) + { + tmpaddr = cs->c_value; + tmpaddr += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + push_context (++depth, tmpaddr); + } + else if (STREQ (cs->c_name, ".eb")) + { + if (context_stack_depth <= 0) + { /* We attempted to pop an empty context stack */ + complain (&eb_stack_complaint, cs->c_symnum); + break; + } - new = pop_context (); - if (depth-- != new->depth) - { - complain (&eb_complaint, symnum); - break; - } - if (local_symbols && context_stack_depth > 0) - { - tmpaddr = - cs->c_value + ANOFFSET (section_offsets, SECT_OFF_TEXT); - /* Make a block for the local symbols within. */ - finish_block (0, &local_symbols, new->old_blocks, - new->start_addr, tmpaddr, objfile); - } - /* Now pop locals of block just finished. */ - local_symbols = new->locals; - } - break; + new = pop_context (); + if (depth-- != new->depth) + { + complain (&eb_complaint, symnum); + break; + } + if (local_symbols && context_stack_depth > 0) + { + tmpaddr = + cs->c_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, tmpaddr, objfile); + } + /* Now pop locals of block just finished. */ + local_symbols = new->locals; + } + break; - default: - process_coff_symbol (cs, &main_aux, section_offsets, objfile); - break; + default: + process_coff_symbol (cs, &main_aux, objfile); + break; } } @@ -1203,26 +1110,25 @@ coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) in internal_auxent form, and skip any other auxents. */ static void -read_one_sym (cs, sym, aux) - register struct coff_symbol *cs; - register struct internal_syment *sym; - register union internal_auxent *aux; +read_one_sym (register struct coff_symbol *cs, + register struct internal_syment *sym, + register union internal_auxent *aux) { int i; cs->c_symnum = symnum; - bfd_read (temp_sym, local_symesz, 1, nlist_bfd_global); - bfd_coff_swap_sym_in (symfile_bfd, temp_sym, (char *)sym); + bfd_bread (temp_sym, local_symesz, nlist_bfd_global); + bfd_coff_swap_sym_in (symfile_bfd, temp_sym, (char *) sym); cs->c_naux = sym->n_numaux & 0xff; if (cs->c_naux >= 1) { - bfd_read (temp_aux, local_auxesz, 1, nlist_bfd_global); - bfd_coff_swap_aux_in (symfile_bfd, temp_aux, sym->n_type, sym->n_sclass, - 0, cs->c_naux, (char *)aux); - /* If more than one aux entry, read past it (only the first aux - is important). */ - for (i = 1; i < cs->c_naux; i++) - bfd_read (temp_aux, local_auxesz, 1, nlist_bfd_global); + bfd_bread (temp_aux, local_auxesz, nlist_bfd_global); + bfd_coff_swap_aux_in (symfile_bfd, temp_aux, sym->n_type, sym->n_sclass, + 0, cs->c_naux, (char *) aux); + /* If more than one aux entry, read past it (only the first aux + is important). */ + for (i = 1; i < cs->c_naux; i++) + bfd_bread (temp_aux, local_auxesz, nlist_bfd_global); } cs->c_name = getsymname (sym); cs->c_value = sym->n_value; @@ -1234,7 +1140,7 @@ read_one_sym (cs, sym, aux) #if 0 if (cs->c_sclass & 128) - printf("thumb symbol %s, class 0x%x\n", cs->c_name, cs->c_sclass); + printf ("thumb symbol %s, class 0x%x\n", cs->c_name, cs->c_sclass); #endif symnum += 1 + cs->c_naux; @@ -1273,9 +1179,7 @@ read_one_sym (cs, sym, aux) static char *stringtab = NULL; static int -init_stringtab (abfd, offset) - bfd *abfd; - long offset; +init_stringtab (bfd *abfd, long offset) { long length; int val; @@ -1291,9 +1195,9 @@ init_stringtab (abfd, offset) if (bfd_seek (abfd, offset, 0) < 0) return -1; - val = bfd_read ((char *)lengthbuf, sizeof lengthbuf, 1, abfd); + val = bfd_bread ((char *) lengthbuf, sizeof lengthbuf, abfd); length = bfd_h_get_32 (symfile_bfd, lengthbuf); - + /* If no string table is needed, then the file may end immediately after the symbols. Just return with `stringtab' set to null. */ if (val != sizeof lengthbuf || length < sizeof lengthbuf) @@ -1303,10 +1207,11 @@ init_stringtab (abfd, offset) /* This is in target format (probably not very useful, and not currently used), not host format. */ memcpy (stringtab, lengthbuf, sizeof lengthbuf); - if (length == sizeof length) /* Empty table -- just the count */ + if (length == sizeof length) /* Empty table -- just the count */ return 0; - val = bfd_read (stringtab + sizeof lengthbuf, length - sizeof lengthbuf, 1, abfd); + val = bfd_bread (stringtab + sizeof lengthbuf, length - sizeof lengthbuf, + abfd); if (val != length - sizeof lengthbuf || stringtab[length - 1] != '\0') return -1; @@ -1314,24 +1219,29 @@ init_stringtab (abfd, offset) } static void -free_stringtab () +free_stringtab (void) { if (stringtab) - free (stringtab); + xfree (stringtab); stringtab = NULL; } +static void +free_stringtab_cleanup (void *ignore) +{ + free_stringtab (); +} + static char * -getsymname (symbol_entry) - struct internal_syment *symbol_entry; +getsymname (struct internal_syment *symbol_entry) { - static char buffer[SYMNMLEN+1]; + static char buffer[SYMNMLEN + 1]; char *result; if (symbol_entry->_n._n_n._n_zeroes == 0) { /* FIXME: Probably should be detecting corrupt symbol files by - seeing whether offset points to within the stringtab. */ + seeing whether offset points to within the stringtab. */ result = stringtab + symbol_entry->_n._n_n._n_offset; } else @@ -1348,8 +1258,7 @@ getsymname (symbol_entry) is only good for temporary use. */ static char * -coff_getfilename (aux_entry) - union internal_auxent *aux_entry; +coff_getfilename (union internal_auxent *aux_entry) { static char buffer[BUFSIZ]; register char *temp; @@ -1381,30 +1290,27 @@ static unsigned long linetab_size; /* Read in all the line numbers for fast lookups later. Leave them in external (unswapped) format in memory; we'll swap them as we enter them into GDB's data structures. */ - + static int -init_lineno (abfd, offset, size) - bfd *abfd; - long offset; - int size; +init_lineno (bfd *abfd, long offset, int size) { int val; linetab_offset = offset; linetab_size = size; - free_linetab(); + free_linetab (); if (size == 0) return 0; if (bfd_seek (abfd, offset, 0) < 0) return -1; - + /* Allocate the desired table, plus a sentinel */ linetab = (char *) xmalloc (size + local_linesz); - val = bfd_read (linetab, size, 1, abfd); + val = bfd_bread (linetab, size, abfd); if (val != size) return -1; @@ -1415,37 +1321,40 @@ init_lineno (abfd, offset, size) } static void -free_linetab () +free_linetab (void) { if (linetab) - free (linetab); + xfree (linetab); linetab = NULL; } +static void +free_linetab_cleanup (void *ignore) +{ + free_linetab (); +} + #if !defined (L_LNNO32) #define L_LNNO32(lp) ((lp)->l_lnno) #endif static void -enter_linenos (file_offset, first_line, last_line, section_offsets) - long file_offset; - register int first_line; - register int last_line; - struct section_offsets *section_offsets; +enter_linenos (long file_offset, register int first_line, + register int last_line, struct objfile *objfile) { register char *rawptr; struct internal_lineno lptr; if (!linetab) - return ; + return; if (file_offset < linetab_offset) { complain (&lineno_complaint, file_offset); if (file_offset > linetab_size) /* Too big to be an offset? */ return; - file_offset += linetab_offset; /* Try reading at that linetab offset */ + file_offset += linetab_offset; /* Try reading at that linetab offset */ } - + rawptr = &linetab[file_offset - linetab_offset]; /* skip first line entry for each function */ @@ -1453,23 +1362,22 @@ enter_linenos (file_offset, first_line, last_line, section_offsets) /* line numbers start at one for the first line of the function */ first_line--; - for (;;) { - bfd_coff_swap_lineno_in (symfile_bfd, rawptr, &lptr); - rawptr += local_linesz; - /* The next function, or the sentinel, will have L_LNNO32 zero; we exit. */ - if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line) - coff_record_line (first_line + L_LNNO32 (&lptr), - lptr.l_addr.l_paddr - + ANOFFSET (section_offsets, SECT_OFF_TEXT)); - else - break; - } + for (;;) + { + bfd_coff_swap_lineno_in (symfile_bfd, rawptr, &lptr); + rawptr += local_linesz; + /* The next function, or the sentinel, will have L_LNNO32 zero; we exit. */ + if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line) + record_line (current_subfile, first_line + L_LNNO32 (&lptr), + lptr.l_addr.l_paddr + + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile))); + else + break; + } } static void -patch_type (type, real_type) - struct type *type; - struct type *real_type; +patch_type (struct type *type, struct type *real_type) { register struct type *target = TYPE_TARGET_TYPE (type); register struct type *real_target = TYPE_TARGET_TYPE (real_type); @@ -1484,7 +1392,7 @@ patch_type (type, real_type) if (TYPE_NAME (real_target)) { if (TYPE_NAME (target)) - free (TYPE_NAME (target)); + xfree (TYPE_NAME (target)); TYPE_NAME (target) = concat (TYPE_NAME (real_target), NULL); } } @@ -1493,21 +1401,20 @@ patch_type (type, real_type) so that they can be used to print out opaque data structures properly. */ static void -patch_opaque_types (s) - struct symtab *s; +patch_opaque_types (struct symtab *s) { register struct block *b; register int i; register struct symbol *real_sym; - + /* Go through the per-file symbols only */ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) { /* Find completed typedefs to use to fix opaque ones. - Remove syms from the chain when their types are stored, - but search the whole chain, as there may be several syms - from different files with the same name. */ + Remove syms from the chain when their types are stored, + but search the whole chain, as there may be several syms + from different files with the same name. */ real_sym = BLOCK_SYM (b, i); if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF && SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE && @@ -1517,7 +1424,7 @@ patch_opaque_types (s) register char *name = SYMBOL_NAME (real_sym); register int hash = hashname (name); register struct symbol *sym, *prev; - + prev = 0; for (sym = opaque_type_chain[hash]; sym;) { @@ -1532,9 +1439,9 @@ patch_opaque_types (s) { opaque_type_chain[hash] = SYMBOL_VALUE_CHAIN (sym); } - + patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym)); - + if (prev) { sym = SYMBOL_VALUE_CHAIN (prev); @@ -1555,15 +1462,13 @@ patch_opaque_types (s) } static struct symbol * -process_coff_symbol (cs, aux, section_offsets, objfile) - register struct coff_symbol *cs; - register union internal_auxent *aux; - struct section_offsets *section_offsets; - struct objfile *objfile; +process_coff_symbol (register struct coff_symbol *cs, + register union internal_auxent *aux, + struct objfile *objfile) { register struct symbol *sym - = (struct symbol *) obstack_alloc (&objfile->symbol_obstack, - sizeof (struct symbol)); + = (struct symbol *) obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); char *name; memset (sym, 0, sizeof (struct symbol)); @@ -1581,9 +1486,9 @@ process_coff_symbol (cs, aux, section_offsets, objfile) if (ISFCN (cs->c_type)) { - SYMBOL_VALUE (sym) += ANOFFSET (section_offsets, SECT_OFF_TEXT); - SYMBOL_TYPE(sym) = - lookup_function_type (decode_function_type (cs, cs->c_type, aux)); + SYMBOL_VALUE (sym) += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + SYMBOL_TYPE (sym) = + lookup_function_type (decode_function_type (cs, cs->c_type, aux)); SYMBOL_CLASS (sym) = LOC_BLOCK; if (cs->c_sclass == C_STAT || cs->c_sclass == C_THUMBSTAT @@ -1598,181 +1503,183 @@ process_coff_symbol (cs, aux, section_offsets, objfile) SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux); switch (cs->c_sclass) { - case C_NULL: - break; + case C_NULL: + break; - case C_AUTO: - SYMBOL_CLASS (sym) = LOC_LOCAL; - add_symbol_to_list (sym, &local_symbols); - break; + case C_AUTO: + SYMBOL_CLASS (sym) = LOC_LOCAL; + add_symbol_to_list (sym, &local_symbols); + break; - case C_THUMBEXT: - case C_THUMBEXTFUNC: - case C_EXT: - SYMBOL_CLASS (sym) = LOC_STATIC; - SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; - SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (section_offsets, SECT_OFF_TEXT); - add_symbol_to_list (sym, &global_symbols); - break; + case C_THUMBEXT: + case C_THUMBEXTFUNC: + case C_EXT: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; + SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + add_symbol_to_list (sym, &global_symbols); + break; - case C_THUMBSTAT: - case C_THUMBSTATFUNC: - case C_STAT: - SYMBOL_CLASS (sym) = LOC_STATIC; - SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; - SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (section_offsets, SECT_OFF_TEXT); - if (within_function) { + case C_THUMBSTAT: + case C_THUMBSTATFUNC: + case C_STAT: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; + SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + if (within_function) + { /* Static symbol of local scope */ add_symbol_to_list (sym, &local_symbols); } - else { + else + { /* Static symbol at top level of file */ add_symbol_to_list (sym, &file_symbols); } - break; + break; #ifdef C_GLBLREG /* AMD coff */ - case C_GLBLREG: + case C_GLBLREG: #endif - case C_REG: - SYMBOL_CLASS (sym) = LOC_REGISTER; - SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value); - add_symbol_to_list (sym, &local_symbols); - break; + case C_REG: + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM (cs->c_value); + add_symbol_to_list (sym, &local_symbols); + break; - case C_THUMBLABEL: - case C_LABEL: - break; + case C_THUMBLABEL: + case C_LABEL: + break; - case C_ARG: - SYMBOL_CLASS (sym) = LOC_ARG; - add_symbol_to_list (sym, &local_symbols); + case C_ARG: + SYMBOL_CLASS (sym) = LOC_ARG; + add_symbol_to_list (sym, &local_symbols); #if !defined (BELIEVE_PCC_PROMOTION) - if (TARGET_BYTE_ORDER == BIG_ENDIAN) - { - /* If PCC says a parameter is a short or a char, - aligned on an int boundary, realign it to the - "little end" of the int. */ - struct type *temptype; - temptype = lookup_fundamental_type (current_objfile, - FT_INTEGER); - if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) - && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT - && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (temptype)) - { - SYMBOL_VALUE (sym) += - TYPE_LENGTH (temptype) - - TYPE_LENGTH (SYMBOL_TYPE (sym)); - } - } + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + /* If PCC says a parameter is a short or a char, + aligned on an int boundary, realign it to the + "little end" of the int. */ + struct type *temptype; + temptype = lookup_fundamental_type (current_objfile, + FT_INTEGER); + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT + && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (temptype)) + { + SYMBOL_VALUE (sym) += + TYPE_LENGTH (temptype) + - TYPE_LENGTH (SYMBOL_TYPE (sym)); + } + } #endif - break; + break; - case C_REGPARM: - SYMBOL_CLASS (sym) = LOC_REGPARM; - SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value); - add_symbol_to_list (sym, &local_symbols); + case C_REGPARM: + SYMBOL_CLASS (sym) = LOC_REGPARM; + SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM (cs->c_value); + add_symbol_to_list (sym, &local_symbols); #if !defined (BELIEVE_PCC_PROMOTION) - /* FIXME: This should retain the current type, since it's just - a register value. gnu@adobe, 26Feb93 */ + /* FIXME: This should retain the current type, since it's just + a register value. gnu@adobe, 26Feb93 */ + { + /* If PCC says a parameter is a short or a char, + it is really an int. */ + struct type *temptype; + temptype = + lookup_fundamental_type (current_objfile, FT_INTEGER); + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT) { - /* If PCC says a parameter is a short or a char, - it is really an int. */ - struct type *temptype; - temptype = - lookup_fundamental_type (current_objfile, FT_INTEGER); - if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) - && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT) - { - SYMBOL_TYPE (sym) = - (TYPE_UNSIGNED (SYMBOL_TYPE (sym)) - ? lookup_fundamental_type (current_objfile, - FT_UNSIGNED_INTEGER) - : temptype); - } + SYMBOL_TYPE (sym) = + (TYPE_UNSIGNED (SYMBOL_TYPE (sym)) + ? lookup_fundamental_type (current_objfile, + FT_UNSIGNED_INTEGER) + : temptype); } + } #endif - break; - - case C_TPDEF: - SYMBOL_CLASS (sym) = LOC_TYPEDEF; - SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + break; - /* If type has no name, give it one */ - if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) - { - if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR - || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC) - { - /* If we are giving a name to a type such as "pointer to - foo" or "function returning foo", we better not set - the TYPE_NAME. If the program contains "typedef char - *caddr_t;", we don't want all variables of type char - * to print as caddr_t. This is not just a - consequence of GDB's type management; CC and GCC (at - least through version 2.4) both output variables of - either type char * or caddr_t with the type - refering to the C_TPDEF symbol for caddr_t. If a future - compiler cleans this up it GDB is not ready for it - yet, but if it becomes ready we somehow need to - disable this check (without breaking the PCC/GCC2.4 - case). - - Sigh. - - Fortunately, this check seems not to be necessary - for anything except pointers or functions. */ - ; - } - else - TYPE_NAME (SYMBOL_TYPE (sym)) = - concat (SYMBOL_NAME (sym), NULL); - } + case C_TPDEF: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + /* If type has no name, give it one */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) + { + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; CC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type + refering to the C_TPDEF symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + ; + } + else + TYPE_NAME (SYMBOL_TYPE (sym)) = + concat (SYMBOL_NAME (sym), NULL); + } #ifdef CXUX_TARGET - /* Ignore vendor section for Harris CX/UX targets. */ - else if (cs->c_name[0] == '$') - break; + /* Ignore vendor section for Harris CX/UX targets. */ + else if (cs->c_name[0] == '$') + break; #endif /* CXUX_TARGET */ - /* Keep track of any type which points to empty structured type, - so it can be filled from a definition from another file. A - simple forward reference (TYPE_CODE_UNDEF) is not an - empty structured type, though; the forward references - work themselves out via the magic of coff_lookup_type. */ - if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR && - TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0 && - TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) != - TYPE_CODE_UNDEF) - { - register int i = hashname (SYMBOL_NAME (sym)); - - SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i]; - opaque_type_chain[i] = sym; - } - add_symbol_to_list (sym, &file_symbols); - break; + /* Keep track of any type which points to empty structured type, + so it can be filled from a definition from another file. A + simple forward reference (TYPE_CODE_UNDEF) is not an + empty structured type, though; the forward references + work themselves out via the magic of coff_lookup_type. */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0 && + TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) != + TYPE_CODE_UNDEF) + { + register int i = hashname (SYMBOL_NAME (sym)); - case C_STRTAG: - case C_UNTAG: - case C_ENTAG: - SYMBOL_CLASS (sym) = LOC_TYPEDEF; - SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; - - /* Some compilers try to be helpful by inventing "fake" - names for anonymous enums, structures, and unions, like - "~0fake" or ".0fake". Thanks, but no thanks... */ - if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0) - if (SYMBOL_NAME(sym) != NULL - && *SYMBOL_NAME(sym) != '~' - && *SYMBOL_NAME(sym) != '.') - TYPE_TAG_NAME (SYMBOL_TYPE (sym)) = - concat (SYMBOL_NAME (sym), NULL); + SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i]; + opaque_type_chain[i] = sym; + } + add_symbol_to_list (sym, &file_symbols); + break; - add_symbol_to_list (sym, &file_symbols); - break; + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + + /* Some compilers try to be helpful by inventing "fake" + names for anonymous enums, structures, and unions, like + "~0fake" or ".0fake". Thanks, but no thanks... */ + if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0) + if (SYMBOL_NAME (sym) != NULL + && *SYMBOL_NAME (sym) != '~' + && *SYMBOL_NAME (sym) != '.') + TYPE_TAG_NAME (SYMBOL_TYPE (sym)) = + concat (SYMBOL_NAME (sym), NULL); + + add_symbol_to_list (sym, &file_symbols); + break; - default: - break; + default: + break; } } return sym; @@ -1781,10 +1688,8 @@ process_coff_symbol (cs, aux, section_offsets, objfile) /* Decode a coff type specifier; return the type that is meant. */ static struct type * -decode_type (cs, c_type, aux) - register struct coff_symbol *cs; - unsigned int c_type; - register union internal_auxent *aux; +decode_type (register struct coff_symbol *cs, unsigned int c_type, + register union internal_auxent *aux) { register struct type *type = 0; unsigned int new_c_type; @@ -1862,13 +1767,11 @@ decode_type (cs, c_type, aux) return the type that the function returns. */ static struct type * -decode_function_type (cs, c_type, aux) - register struct coff_symbol *cs; - unsigned int c_type; - register union internal_auxent *aux; +decode_function_type (register struct coff_symbol *cs, unsigned int c_type, + register union internal_auxent *aux) { if (aux->x_sym.x_tagndx.l == 0) - cs->c_naux = 0; /* auxent refers to function, not base type */ + cs->c_naux = 0; /* auxent refers to function, not base type */ return decode_type (cs, DECREF (c_type), aux); } @@ -1876,149 +1779,147 @@ decode_function_type (cs, c_type, aux) /* basic C types */ static struct type * -decode_base_type (cs, c_type, aux) - register struct coff_symbol *cs; - unsigned int c_type; - register union internal_auxent *aux; +decode_base_type (register struct coff_symbol *cs, unsigned int c_type, + register union internal_auxent *aux) { struct type *type; switch (c_type) { - case T_NULL: - /* shows up with "void (*foo)();" structure members */ - return lookup_fundamental_type (current_objfile, FT_VOID); + case T_NULL: + /* shows up with "void (*foo)();" structure members */ + return lookup_fundamental_type (current_objfile, FT_VOID); #if 0 /* DGUX actually defines both T_ARG and T_VOID to the same value. */ #ifdef T_ARG - case T_ARG: - /* Shows up in DGUX, I think. Not sure where. */ - return lookup_fundamental_type (current_objfile, FT_VOID); /* shouldn't show up here */ + case T_ARG: + /* Shows up in DGUX, I think. Not sure where. */ + return lookup_fundamental_type (current_objfile, FT_VOID); /* shouldn't show up here */ #endif #endif /* 0 */ #ifdef T_VOID - case T_VOID: - /* Intel 960 COFF has this symbol and meaning. */ - return lookup_fundamental_type (current_objfile, FT_VOID); + case T_VOID: + /* Intel 960 COFF has this symbol and meaning. */ + return lookup_fundamental_type (current_objfile, FT_VOID); #endif - case T_CHAR: - return lookup_fundamental_type (current_objfile, FT_CHAR); - - case T_SHORT: - return lookup_fundamental_type (current_objfile, FT_SHORT); + case T_CHAR: + return lookup_fundamental_type (current_objfile, FT_CHAR); - case T_INT: - return lookup_fundamental_type (current_objfile, FT_INTEGER); + case T_SHORT: + return lookup_fundamental_type (current_objfile, FT_SHORT); - case T_LONG: - if (cs->c_sclass == C_FIELD - && aux->x_sym.x_misc.x_lnsz.x_size > TARGET_LONG_BIT) - return lookup_fundamental_type (current_objfile, FT_LONG_LONG); - else - return lookup_fundamental_type (current_objfile, FT_LONG); + case T_INT: + return lookup_fundamental_type (current_objfile, FT_INTEGER); - case T_FLOAT: - return lookup_fundamental_type (current_objfile, FT_FLOAT); + case T_LONG: + if (cs->c_sclass == C_FIELD + && aux->x_sym.x_misc.x_lnsz.x_size > TARGET_LONG_BIT) + return lookup_fundamental_type (current_objfile, FT_LONG_LONG); + else + return lookup_fundamental_type (current_objfile, FT_LONG); - case T_DOUBLE: - return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT); + case T_FLOAT: + return lookup_fundamental_type (current_objfile, FT_FLOAT); - case T_LNGDBL: - return lookup_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT); + case T_DOUBLE: + return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT); - case T_STRUCT: - if (cs->c_naux != 1) - { - /* anonymous structure type */ - type = coff_alloc_type (cs->c_symnum); - TYPE_CODE (type) = TYPE_CODE_STRUCT; - TYPE_NAME (type) = NULL; - /* This used to set the tag to "<opaque>". But I think setting it - to NULL is right, and the printing code can print it as - "struct {...}". */ - TYPE_TAG_NAME (type) = NULL; - INIT_CPLUS_SPECIFIC(type); - TYPE_LENGTH (type) = 0; - TYPE_FIELDS (type) = 0; - TYPE_NFIELDS (type) = 0; - } - else - { - type = coff_read_struct_type (cs->c_symnum, - aux->x_sym.x_misc.x_lnsz.x_size, - aux->x_sym.x_fcnary.x_fcn.x_endndx.l); - } - return type; + case T_LNGDBL: + return lookup_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT); - case T_UNION: - if (cs->c_naux != 1) - { - /* anonymous union type */ - type = coff_alloc_type (cs->c_symnum); - TYPE_NAME (type) = NULL; - /* This used to set the tag to "<opaque>". But I think setting it - to NULL is right, and the printing code can print it as - "union {...}". */ - TYPE_TAG_NAME (type) = NULL; - INIT_CPLUS_SPECIFIC(type); - TYPE_LENGTH (type) = 0; - TYPE_FIELDS (type) = 0; - TYPE_NFIELDS (type) = 0; - } - else - { - type = coff_read_struct_type (cs->c_symnum, - aux->x_sym.x_misc.x_lnsz.x_size, - aux->x_sym.x_fcnary.x_fcn.x_endndx.l); - } - TYPE_CODE (type) = TYPE_CODE_UNION; - return type; + case T_STRUCT: + if (cs->c_naux != 1) + { + /* anonymous structure type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NAME (type) = NULL; + /* This used to set the tag to "<opaque>". But I think setting it + to NULL is right, and the printing code can print it as + "struct {...}". */ + TYPE_TAG_NAME (type) = NULL; + INIT_CPLUS_SPECIFIC (type); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + return type; - case T_ENUM: - if (cs->c_naux != 1) - { - /* anonymous enum type */ - type = coff_alloc_type (cs->c_symnum); - TYPE_CODE (type) = TYPE_CODE_ENUM; - TYPE_NAME (type) = NULL; - /* This used to set the tag to "<opaque>". But I think setting it - to NULL is right, and the printing code can print it as - "enum {...}". */ - TYPE_TAG_NAME (type) = NULL; - TYPE_LENGTH (type) = 0; - TYPE_FIELDS (type) = 0; - TYPE_NFIELDS(type) = 0; - } - else - { - type = coff_read_enum_type (cs->c_symnum, + case T_UNION: + if (cs->c_naux != 1) + { + /* anonymous union type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_NAME (type) = NULL; + /* This used to set the tag to "<opaque>". But I think setting it + to NULL is right, and the printing code can print it as + "union {...}". */ + TYPE_TAG_NAME (type) = NULL; + INIT_CPLUS_SPECIFIC (type); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_struct_type (cs->c_symnum, aux->x_sym.x_misc.x_lnsz.x_size, - aux->x_sym.x_fcnary.x_fcn.x_endndx.l); - } - return type; + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + TYPE_CODE (type) = TYPE_CODE_UNION; + return type; - case T_MOE: - /* shouldn't show up here */ - break; + case T_ENUM: + if (cs->c_naux != 1) + { + /* anonymous enum type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NAME (type) = NULL; + /* This used to set the tag to "<opaque>". But I think setting it + to NULL is right, and the printing code can print it as + "enum {...}". */ + TYPE_TAG_NAME (type) = NULL; + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_enum_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + return type; - case T_UCHAR: - return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR); + case T_MOE: + /* shouldn't show up here */ + break; + + case T_UCHAR: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR); - case T_USHORT: - return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT); + case T_USHORT: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT); - case T_UINT: - return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER); + case T_UINT: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER); - case T_ULONG: - if (cs->c_sclass == C_FIELD - && aux->x_sym.x_misc.x_lnsz.x_size > TARGET_LONG_BIT) - return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG); - else - return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG); + case T_ULONG: + if (cs->c_sclass == C_FIELD + && aux->x_sym.x_misc.x_lnsz.x_size > TARGET_LONG_BIT) + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG); + else + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG); } complain (&unexpected_type_complaint, cs->c_name); return lookup_fundamental_type (current_objfile, FT_VOID); @@ -2030,10 +1931,7 @@ decode_base_type (cs, c_type, aux) object describing the type. */ static struct type * -coff_read_struct_type (index, length, lastsym) - int index; - int length; - int lastsym; +coff_read_struct_type (int index, int length, int lastsym) { struct nextfield { @@ -2055,7 +1953,7 @@ coff_read_struct_type (index, length, lastsym) type = coff_alloc_type (index); TYPE_CODE (type) = TYPE_CODE_STRUCT; - INIT_CPLUS_SPECIFIC(type); + INIT_CPLUS_SPECIFIC (type); TYPE_LENGTH (type) = length; while (!done && symnum < lastsym && symnum < nlist_nsyms_global) @@ -2066,46 +1964,46 @@ coff_read_struct_type (index, length, lastsym) switch (ms->c_sclass) { - case C_MOS: - case C_MOU: - - /* Get space to record the next field's data. */ - new = (struct nextfield *) alloca (sizeof (struct nextfield)); - new->next = list; - list = new; - - /* Save the data. */ - list->field.name = - obsavestring (name, - strlen (name), - ¤t_objfile->symbol_obstack); - FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux); - FIELD_BITPOS (list->field) = 8 * ms->c_value; - FIELD_BITSIZE (list->field) = 0; - nfields++; - break; + case C_MOS: + case C_MOU: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = + obsavestring (name, + strlen (name), + ¤t_objfile->symbol_obstack); + FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux); + FIELD_BITPOS (list->field) = 8 * ms->c_value; + FIELD_BITSIZE (list->field) = 0; + nfields++; + break; - case C_FIELD: - - /* Get space to record the next field's data. */ - new = (struct nextfield *) alloca (sizeof (struct nextfield)); - new->next = list; - list = new; - - /* Save the data. */ - list->field.name = - obsavestring (name, - strlen (name), - ¤t_objfile->symbol_obstack); - FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux); - FIELD_BITPOS (list->field) = ms->c_value; - FIELD_BITSIZE (list->field) = sub_aux.x_sym.x_misc.x_lnsz.x_size; - nfields++; - break; + case C_FIELD: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = + obsavestring (name, + strlen (name), + ¤t_objfile->symbol_obstack); + FIELD_TYPE (list->field) = decode_type (ms, ms->c_type, &sub_aux); + FIELD_BITPOS (list->field) = ms->c_value; + FIELD_BITSIZE (list->field) = sub_aux.x_sym.x_misc.x_lnsz.x_size; + nfields++; + break; - case C_EOS: - done = 1; - break; + case C_EOS: + done = 1; + break; } } /* Now create the vector of fields, and record how big it is. */ @@ -2128,10 +2026,7 @@ coff_read_struct_type (index, length, lastsym) /* ARGSUSED */ static struct type * -coff_read_enum_type (index, length, lastsym) - int index; - int length; - int lastsym; +coff_read_enum_type (int index, int length, int lastsym) { register struct symbol *sym; register struct type *type; @@ -2164,28 +2059,28 @@ coff_read_enum_type (index, length, lastsym) switch (ms->c_sclass) { - case C_MOE: - sym = (struct symbol *) obstack_alloc - (¤t_objfile->symbol_obstack, - sizeof (struct symbol)); - memset (sym, 0, sizeof (struct symbol)); - - SYMBOL_NAME (sym) = - obsavestring (name, strlen (name), - ¤t_objfile->symbol_obstack); - SYMBOL_CLASS (sym) = LOC_CONST; - SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; - SYMBOL_VALUE (sym) = ms->c_value; - add_symbol_to_list (sym, symlist); - nsyms++; - break; + case C_MOE: + sym = (struct symbol *) obstack_alloc + (¤t_objfile->symbol_obstack, + sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + + SYMBOL_NAME (sym) = + obsavestring (name, strlen (name), + ¤t_objfile->symbol_obstack); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = ms->c_value; + add_symbol_to_list (sym, symlist); + nsyms++; + break; - case C_EOS: - /* Sometimes the linker (on 386/ix 2.0.2 at least) screws - up the count of how many symbols to read. So stop - on .eos. */ - done = 1; - break; + case C_EOS: + /* Sometimes the linker (on 386/ix 2.0.2 at least) screws + up the count of how many symbols to read. So stop + on .eos. */ + done = 1; + break; } } @@ -2194,7 +2089,7 @@ coff_read_enum_type (index, length, lastsym) if (length > 0) TYPE_LENGTH (type) = length; else - TYPE_LENGTH (type) = TARGET_INT_BIT / TARGET_CHAR_BIT; /* Assume ints */ + TYPE_LENGTH (type) = TARGET_INT_BIT / TARGET_CHAR_BIT; /* Assume ints */ TYPE_CODE (type) = TYPE_CODE_ENUM; TYPE_NFIELDS (type) = nsyms; TYPE_FIELDS (type) = (struct field *) @@ -2214,7 +2109,7 @@ coff_read_enum_type (index, length, lastsym) if (syms == osyms) j = o_nsyms; - for (; j < syms->nsyms; j++,n++) + for (; j < syms->nsyms; j++, n++) { struct symbol *xsym = syms->symbol[j]; SYMBOL_TYPE (xsym) = type; @@ -2239,17 +2134,16 @@ coff_read_enum_type (index, length, lastsym) static struct sym_fns coff_sym_fns = { bfd_target_coff_flavour, - coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ - coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ - coff_symfile_read, /* sym_read: read a symbol file into symtab */ - coff_symfile_finish, /* sym_finish: finished with file, cleanup */ - default_symfile_offsets, - /* sym_offsets: xlate external to internal form */ - NULL /* next: pointer to next struct sym_fns */ + coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + coff_symfile_read, /* sym_read: read a symbol file into symtab */ + coff_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: xlate external to internal form */ + NULL /* next: pointer to next struct sym_fns */ }; void -_initialize_coffread () +_initialize_coffread (void) { add_symtab_fns (&coff_sym_fns); } diff --git a/contrib/gdb/gdb/config/alpha/tm-alpha.h b/contrib/gdb/gdb/config/alpha/tm-alpha.h index cfe97cf..58412d0 100644 --- a/contrib/gdb/gdb/config/alpha/tm-alpha.h +++ b/contrib/gdb/gdb/config/alpha/tm-alpha.h @@ -1,40 +1,38 @@ /* Definitions to make GDB run on an Alpha box under OSF1. This is - also used by the Alpha/Netware and Alpha/Linux targets. - Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + also used by the Alpha/Netware and Alpha GNU/Linux targets. -This file is part of GDB. + Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002 Free + Software Foundation, Inc. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This file is part of GDB. -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. + 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. -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. */ + 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 TM_ALPHA_H #define TM_ALPHA_H +#include "regcache.h" #include "bfd.h" #include "coff/sym.h" /* Needed for PDR below. */ #include "coff/symconst.h" -#ifdef __STDC__ struct frame_info; struct type; struct value; struct symbol; -#endif - -#if !defined (TARGET_BYTE_ORDER) -#define TARGET_BYTE_ORDER LITTLE_ENDIAN -#endif /* Redefine some target bit sizes from the default. */ @@ -42,9 +40,6 @@ struct symbol; #define TARGET_LONG_LONG_BIT 64 #define TARGET_PTR_BIT 64 -/* Floating point is IEEE compliant */ -#define IEEE_FLOAT - /* Number of traps that happen between exec'ing the shell * to run an inferior, and when we finally get to * the inferior code. This is 2 on most implementations. @@ -59,27 +54,27 @@ struct symbol; /* Advance PC across any function entry prologue instructions to reach some "real" code. */ -#define SKIP_PROLOGUE(pc) pc = alpha_skip_prologue(pc, 0) -extern CORE_ADDR alpha_skip_prologue PARAMS ((CORE_ADDR addr, int lenient)); +#define SKIP_PROLOGUE(pc) alpha_skip_prologue((pc)) +extern CORE_ADDR alpha_skip_prologue (CORE_ADDR addr); /* Immediately after a function call, return the saved pc. Can't always go through the frames for this because on some machines the new frame is not set up until the new function executes some instructions. */ -#define SAVED_PC_AFTER_CALL(frame) alpha_saved_pc_after_call(frame) -extern CORE_ADDR -alpha_saved_pc_after_call PARAMS ((struct frame_info *)); +#define SAVED_PC_AFTER_CALL(frame) alpha_saved_pc_after_call(frame) +extern CORE_ADDR alpha_saved_pc_after_call (struct frame_info *); /* Are we currently handling a signal ? */ -#define IN_SIGTRAMP(pc, name) ((name) && STREQ ("__sigtramp", (name))) +#define IN_SIGTRAMP(pc, name) alpha_osf_in_sigtramp ((pc), (name)) +extern int alpha_osf_in_sigtramp (CORE_ADDR, char *); /* Stack grows downward. */ -#define INNER_THAN(lhs,rhs) ((lhs) < (rhs)) +#define INNER_THAN(lhs,rhs) core_addr_lessthan ((lhs), (rhs)) -#define BREAKPOINT {0x80, 0, 0, 0} /* call_pal bpt */ +#define BREAKPOINT {0x80, 0, 0, 0} /* call_pal bpt */ /* Amount PC must be decremented by after a breakpoint. This is often the number of bytes in BREAKPOINT @@ -99,20 +94,12 @@ alpha_saved_pc_after_call PARAMS ((struct frame_info *)); #define NUM_REGS 66 -/* Initializer for an array of names of registers. - There should be NUM_REGS strings in this initializer. */ - -#define REGISTER_NAMES \ - { "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", \ - "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", \ - "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", \ - "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\ - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\ - "pc", "vfp", \ - } + +/* Return the name of register REGNO. */ + +#define REGISTER_NAME(regno) alpha_register_name ((regno)) +extern char *alpha_register_name (int); + /* Register numbers of various important registers. Note that most of these values are "real" register numbers, @@ -130,15 +117,19 @@ alpha_saved_pc_after_call PARAMS ((struct frame_info *)); #define SP_REGNUM 30 /* Contains address of top of stack */ #define RA_REGNUM 26 /* Contains return address value */ #define ZERO_REGNUM 31 /* Read-only register, always 0 */ -#define FP0_REGNUM 32 /* Floating point register 0 */ -#define FPA0_REGNUM 48 /* First float arg during a subr call */ +#define FP0_REGNUM 32 /* Floating point register 0 */ +#define FPA0_REGNUM 48 /* First float arg during a subr call */ +#define FPCR_REGNUM 63 /* Floating point control register */ #define PC_REGNUM 64 /* Contains program counter */ #define FP_REGNUM 65 /* Virtual frame pointer */ #define CANNOT_FETCH_REGISTER(regno) \ - ((regno) == FP_REGNUM || (regno) == ZERO_REGNUM) + alpha_cannot_fetch_register ((regno)) +extern int alpha_cannot_fetch_register (int); + #define CANNOT_STORE_REGISTER(regno) \ - ((regno) == FP_REGNUM || (regno) == ZERO_REGNUM) + alpha_cannot_store_register ((regno)) +extern int alpha_cannot_store_register (int); /* Total amount of space needed to store our copies of the machine's register state, the array `registers'. */ @@ -147,17 +138,20 @@ alpha_saved_pc_after_call PARAMS ((struct frame_info *)); /* Index within `registers' of the first byte of the space for register N. */ -#define REGISTER_BYTE(N) ((N) * 8) +#define REGISTER_BYTE(N) alpha_register_byte ((N)) +extern int alpha_register_byte (int); /* Number of bytes of storage in the actual machine representation for register N. On Alphas, all regs are 8 bytes. */ -#define REGISTER_RAW_SIZE(N) 8 +#define REGISTER_RAW_SIZE(N) alpha_register_raw_size ((N)) +extern int alpha_register_raw_size (int); /* Number of bytes of storage in the program's representation for register N. On Alphas, all regs are 8 bytes. */ -#define REGISTER_VIRTUAL_SIZE(N) 8 +#define REGISTER_VIRTUAL_SIZE(N) alpha_register_virtual_size ((N)) +extern int alpha_register_virtual_size (int); /* Largest value REGISTER_RAW_SIZE can have. */ @@ -171,12 +165,13 @@ alpha_saved_pc_after_call PARAMS ((struct frame_info *)); from raw format to virtual format. The alpha needs a conversion between register and memory format if the register is a floating point register and - memory format is float, as the register format must be double + memory format is float, as the register format must be double or - memory format is an integer with 4 bytes or less, as the representation - of integers in floating point registers is different. */ + memory format is an integer with 4 bytes or less, as the representation + of integers in floating point registers is different. */ -#define REGISTER_CONVERTIBLE(N) ((N) >= FP0_REGNUM && (N) < FP0_REGNUM + 32) +#define REGISTER_CONVERTIBLE(N) alpha_register_convertible ((N)) +extern int alpha_register_convertible (int); /* Convert data from raw format for register REGNUM in buffer FROM to virtual format with type TYPE in buffer TO. */ @@ -184,7 +179,7 @@ alpha_saved_pc_after_call PARAMS ((struct frame_info *)); #define REGISTER_CONVERT_TO_VIRTUAL(REGNUM, TYPE, FROM, TO) \ alpha_register_convert_to_virtual (REGNUM, TYPE, FROM, TO) extern void -alpha_register_convert_to_virtual PARAMS ((int, struct type *, char *, char *)); +alpha_register_convert_to_virtual (int, struct type *, char *, char *); /* Convert data from virtual format with type TYPE in buffer FROM to raw format for register REGNUM in buffer TO. */ @@ -192,19 +187,21 @@ alpha_register_convert_to_virtual PARAMS ((int, struct type *, char *, char *)); #define REGISTER_CONVERT_TO_RAW(TYPE, REGNUM, FROM, TO) \ alpha_register_convert_to_raw (TYPE, REGNUM, FROM, TO) extern void -alpha_register_convert_to_raw PARAMS ((struct type *, int, char *, char *)); +alpha_register_convert_to_raw (struct type *, int, char *, char *); /* Return the GDB type object for the "standard" data type of data in register N. */ -#define REGISTER_VIRTUAL_TYPE(N) \ - (((N) >= FP0_REGNUM && (N) < FP0_REGNUM+32) \ - ? builtin_type_double : builtin_type_long) \ +#define REGISTER_VIRTUAL_TYPE(N) alpha_register_virtual_type ((N)) +extern struct type * alpha_register_virtual_type (int); /* Store the address of the place in which to copy the structure the subroutine will return. Handled by alpha_push_arguments. */ -#define STORE_STRUCT_RETURN(addr, sp) /**/ +#define STORE_STRUCT_RETURN(addr, sp) \ + alpha_store_struct_return ((addr), (sp)) +extern void alpha_store_struct_return (CORE_ADDR, CORE_ADDR); +/**/ /* Extract from an array REGBUF containing the (raw) register state a function return value of type TYPE, and copy that, in virtual format, @@ -212,16 +209,14 @@ alpha_register_convert_to_raw PARAMS ((struct type *, int, char *, char *)); #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ alpha_extract_return_value(TYPE, REGBUF, VALBUF) -extern void -alpha_extract_return_value PARAMS ((struct type *, char *, char *)); +extern void alpha_extract_return_value (struct type *, char *, char *); /* Write into appropriate registers a function return value of type TYPE, given in virtual format. */ #define STORE_RETURN_VALUE(TYPE,VALBUF) \ alpha_store_return_value(TYPE, VALBUF) -extern void -alpha_store_return_value PARAMS ((struct type *, char *)); +extern void alpha_store_return_value (struct type *, char *); /* Extract from an array REGBUF containing the (raw) register state the address in which a function should return its structure value, @@ -232,37 +227,38 @@ alpha_store_return_value PARAMS ((struct type *, char *)); on it. */ #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ - (extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \ - REGISTER_RAW_SIZE (V0_REGNUM))) + alpha_extract_struct_value_address (REGBUF) +extern CORE_ADDR alpha_extract_struct_value_address (char *); /* Structures are returned by ref in extra arg0 */ -#define USE_STRUCT_CONVENTION(gcc_p, type) 1 - +#define USE_STRUCT_CONVENTION(gcc_p, type) \ + alpha_use_struct_convention ((gcc_p), (type)) +extern int alpha_use_struct_convention (int, struct type *); + /* Describe the pointer in each stack frame to the previous stack frame (its caller). */ /* FRAME_CHAIN takes a frame's nominal address and produces the frame's chain-pointer. */ -#define FRAME_CHAIN(thisframe) (CORE_ADDR) alpha_frame_chain (thisframe) -extern CORE_ADDR alpha_frame_chain PARAMS ((struct frame_info *)); +#define FRAME_CHAIN(thisframe) alpha_frame_chain (thisframe) +extern CORE_ADDR alpha_frame_chain (struct frame_info *); /* Define other aspects of the stack frame. */ -/* A macro that tells us whether the function invocation represented - by FI does not have a frame on the stack associated with it. If it - does not, FRAMELESS is set to 1, else 0. */ +/* An expression that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. */ /* We handle this differently for alpha, and maybe we should not */ -#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) {(FRAMELESS) = 0;} +#define FRAMELESS_FUNCTION_INVOCATION(FI) \ + generic_frameless_function_invocation_not ((FI)) /* Saved Pc. */ -#define FRAME_SAVED_PC(FRAME) (alpha_frame_saved_pc(FRAME)) -extern CORE_ADDR -alpha_frame_saved_pc PARAMS ((struct frame_info *)); +#define FRAME_SAVED_PC(FRAME) alpha_frame_saved_pc(FRAME) +extern CORE_ADDR alpha_frame_saved_pc (struct frame_info *); /* The alpha has two different virtual pointers for arguments and locals. @@ -279,14 +275,16 @@ alpha_frame_saved_pc PARAMS ((struct frame_info *)); #define ALPHA_NUM_ARG_REGS 6 -#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame - (ALPHA_NUM_ARG_REGS * 8)) +#define FRAME_ARGS_ADDRESS(fi) alpha_frame_args_address ((fi)) +extern CORE_ADDR alpha_frame_args_address (struct frame_info *); -#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame - (fi)->localoff) +#define FRAME_LOCALS_ADDRESS(fi) alpha_frame_locals_address ((fi)) +extern CORE_ADDR alpha_frame_locals_address (struct frame_info *); /* Return number of args passed to a frame. Can return -1, meaning no way to tell. */ -#define FRAME_NUM_ARGS(num, fi) ((num) = -1) +#define FRAME_NUM_ARGS(fi) frame_num_args_unknown ((fi)) /* Return number of bytes at start of arglist that are not really args. */ @@ -298,34 +296,27 @@ alpha_frame_saved_pc PARAMS ((struct frame_info *)); ways in the stack frame. sp is even more special: the address we return for it IS the sp for the next frame. */ -extern void alpha_find_saved_regs PARAMS ((struct frame_info *)); - #define FRAME_INIT_SAVED_REGS(frame_info) \ - do { \ - if ((frame_info)->saved_regs == NULL) \ - alpha_find_saved_regs (frame_info); \ - (frame_info)->saved_regs[SP_REGNUM] = (frame_info)->frame; \ - } while (0) - + alpha_frame_init_saved_regs (frame_info) +extern void alpha_frame_init_saved_regs (struct frame_info *); + /* Things needed for making the inferior call functions. */ #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ - sp = alpha_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr)) + (alpha_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr))) extern CORE_ADDR -alpha_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR)); +alpha_push_arguments (int, struct value **, CORE_ADDR, int, CORE_ADDR); /* Push an empty stack frame, to record the current PC, etc. */ -#define PUSH_DUMMY_FRAME alpha_push_dummy_frame() -extern void -alpha_push_dummy_frame PARAMS ((void)); +#define PUSH_DUMMY_FRAME alpha_push_dummy_frame() +extern void alpha_push_dummy_frame (void); /* Discard from the stack the innermost frame, restoring all registers. */ -#define POP_FRAME alpha_pop_frame() -extern void -alpha_pop_frame PARAMS ((void)); +#define POP_FRAME alpha_pop_frame() +extern void alpha_pop_frame (void); /* Alpha OSF/1 inhibits execution of code on the stack. But there is no need for a dummy on the alpha. PUSH_ARGUMENTS @@ -340,52 +331,56 @@ alpha_pop_frame PARAMS ((void)); call_function_by_hand and to avoid zero length array warnings in valops.c */ -#define CALL_DUMMY { 0 } /* Content doesn't matter. */ +#define CALL_DUMMY_P (1) + +#define CALL_DUMMY_WORDS alpha_call_dummy_words +extern LONGEST alpha_call_dummy_words[]; + +#define SIZEOF_CALL_DUMMY_WORDS 0 #define CALL_DUMMY_START_OFFSET (0) #define CALL_DUMMY_BREAKPOINT_OFFSET (0) -extern CORE_ADDR alpha_call_dummy_address PARAMS ((void)); #define CALL_DUMMY_ADDRESS() alpha_call_dummy_address() +extern CORE_ADDR alpha_call_dummy_address (void); /* Insert the specified number of args and function address into a call sequence of the above form stored at DUMMYNAME. We only have to set RA_REGNUM to the dummy breakpoint address and T12_REGNUM (the `procedure value register') to the function address. */ -#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ -{ \ - CORE_ADDR bp_address = CALL_DUMMY_ADDRESS (); \ - if (bp_address == 0) \ - error ("no place to put call"); \ - write_register (RA_REGNUM, bp_address); \ - write_register (T12_REGNUM, fun); \ -} +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ + alpha_fix_call_dummy ((dummyname), (pc), (fun), (nargs), (args), \ + (type), (gcc_p)) +extern void alpha_fix_call_dummy (char *, CORE_ADDR, CORE_ADDR, int, + struct value **, struct type *, int); /* There's a mess in stack frame creation. See comments in blockframe.c near reference to INIT_FRAME_PC_FIRST. */ -#define INIT_FRAME_PC(fromleaf, prev) /* nada */ +#define INIT_FRAME_PC(fromleaf, prev) init_frame_pc_noop ((fromleaf), (prev)) #define INIT_FRAME_PC_FIRST(fromleaf, prev) \ - (prev)->pc = ((fromleaf) ? SAVED_PC_AFTER_CALL ((prev)->next) : \ - (prev)->next ? FRAME_SAVED_PC ((prev)->next) : read_pc ()); + alpha_init_frame_pc_first ((fromleaf), (prev)) +extern void alpha_init_frame_pc_first (int, struct frame_info *); /* Special symbol found in blocks associated with routines. We can hang alpha_extra_func_info_t's off of this. */ #define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__" -extern void ecoff_relocate_efi PARAMS ((struct symbol *, CORE_ADDR)); +extern void ecoff_relocate_efi (struct symbol *, CORE_ADDR); /* Specific information about a procedure. This overlays the ALPHA's PDR records, alpharead.c (ab)uses this to save memory */ -typedef struct alpha_extra_func_info { - long numargs; /* number of args to procedure (was iopt) */ - PDR pdr; /* Procedure descriptor record */ -} *alpha_extra_func_info_t; +typedef struct alpha_extra_func_info + { + long numargs; /* number of args to procedure (was iopt) */ + PDR pdr; /* Procedure descriptor record */ + } + *alpha_extra_func_info_t; /* Define the extra_func_info that mipsread.c needs. FIXME: We should define our own PDR interface, perhaps in a separate @@ -394,22 +389,14 @@ typedef struct alpha_extra_func_info { #define mips_extra_func_info alpha_extra_func_info #define mips_extra_func_info_t alpha_extra_func_info_t -#define EXTRA_FRAME_INFO \ - int localoff; \ - int pc_reg; \ - alpha_extra_func_info_t proc_desc; -#define INIT_EXTRA_FRAME_INFO(fromleaf, fci) init_extra_frame_info(fci) -extern void -init_extra_frame_info PARAMS ((struct frame_info *)); - -#define PRINT_EXTRA_FRAME_INFO(fi) \ - { \ - if (fi && fi->proc_desc && fi->proc_desc->pdr.framereg < NUM_REGS) \ - printf_filtered (" frame pointer is at %s+%d\n", \ - REGISTER_NAME (fi->proc_desc->pdr.framereg), \ - fi->proc_desc->pdr.frameoffset); \ - } +#define INIT_EXTRA_FRAME_INFO(fromleaf, fci) \ + alpha_init_extra_frame_info(fromleaf, fci) +extern void alpha_init_extra_frame_info (int, struct frame_info *); + +#define PRINT_EXTRA_FRAME_INFO(fi) alpha_print_extra_frame_info ((fi)) +extern void alpha_print_extra_frame_info (struct frame_info *); + /* It takes two values to specify a frame on the ALPHA. Sigh. @@ -422,14 +409,12 @@ init_extra_frame_info PARAMS ((struct frame_info *)); multiple functions with the same SP that are at different stack levels. */ #define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv) -extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *)); +extern struct frame_info *setup_arbitrary_frame (int, CORE_ADDR *); /* This is used by heuristic_proc_start. It should be shot it the head. */ -#ifndef __FreeBSD__ #ifndef VM_MIN_ADDRESS #define VM_MIN_ADDRESS (CORE_ADDR)0x120000000 #endif -#endif /* If PC is in a shared library trampoline code, return the PC where the function itself actually starts. If not, return 0. */ @@ -445,7 +430,8 @@ extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *)); values are always passed in as doubles. Thus by setting this to 1, both types of calls will work. */ -#define COERCE_FLOAT_TO_DOUBLE 1 +#define COERCE_FLOAT_TO_DOUBLE(formal, actual) \ + standard_coerce_float_to_double ((formal), (actual)) /* Return TRUE if procedure descriptor PROC is a procedure descriptor that refers to a dynamically generated sigtramp function. @@ -476,6 +462,10 @@ extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *)); #define FRAME_PAST_SIGTRAMP_FRAME(frame, pc) \ (alpha_osf_skip_sigtramp_frame (frame, pc)) -extern CORE_ADDR alpha_osf_skip_sigtramp_frame PARAMS ((struct frame_info *, CORE_ADDR)); +extern CORE_ADDR alpha_osf_skip_sigtramp_frame (struct frame_info *, + CORE_ADDR); + +/* Single step based on where the current instruction will take us. */ +extern void alpha_software_single_step (enum target_signal, int); #endif /* TM_ALPHA_H */ diff --git a/contrib/gdb/gdb/core-aout.c b/contrib/gdb/gdb/core-aout.c index 08cca22..0329302 100644 --- a/contrib/gdb/gdb/core-aout.c +++ b/contrib/gdb/gdb/core-aout.c @@ -1,21 +1,23 @@ /* Extract registers from a "standard" core file, for GDB. - Copyright (C) 1988-1998 Free Software Foundation, Inc. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000, 2001 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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. */ /* Typically used on systems that have a.out format executables. corefile.c is supposed to contain the more machine-independent @@ -25,21 +27,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #ifdef HAVE_PTRACE_H -# include <ptrace.h> +#include <ptrace.h> #else -# ifdef HAVE_SYS_PTRACE_H -# include <sys/ptrace.h> -# endif +#ifdef HAVE_SYS_PTRACE_H +#include <sys/ptrace.h> +#endif #endif #include <sys/types.h> #include <sys/param.h> #include "gdbcore.h" -#include "value.h" /* For supply_register. */ -#include "inferior.h" /* For ARCH_NUM_REGS. */ +#include "value.h" /* For supply_register. */ +#include "regcache.h" /* These are needed on various systems to expand REGISTER_U_ADDR. */ #ifndef USG +#include "gdb_dirent.h" #include <sys/file.h> #include "gdb_stat.h" #include <sys/user.h> @@ -53,9 +56,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <sys/core.h> #endif -static void fetch_core_registers PARAMS ((char *, unsigned, int, CORE_ADDR)); +static void fetch_core_registers (char *, unsigned, int, CORE_ADDR); -void _initialize_core_aout PARAMS ((void)); +void _initialize_core_aout (void); /* Extract the register values out of the core file and store them where `read_register' will find them. @@ -63,25 +66,22 @@ void _initialize_core_aout PARAMS ((void)); 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). + 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. + 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. */ static void -fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) - char *core_reg_sect; - unsigned core_reg_size; - int which; - CORE_ADDR reg_addr; +fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, + CORE_ADDR reg_addr) { int regno; CORE_ADDR addr; int bad_reg = -1; - CORE_ADDR reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ - int numregs = ARCH_NUM_REGS; + CORE_ADDR reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ + int numregs = NUM_REGS; /* If u.u_ar0 was an absolute address in the core file, relativize it now, so we can use it as an offset into core_reg_sect. When we're done, @@ -98,8 +98,8 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) if (addr >= core_reg_size && bad_reg < 0) bad_reg = regno; - else - supply_register (regno, core_reg_sect + addr); + else + supply_register (regno, core_reg_sect + addr); } if (bad_reg >= 0) @@ -113,13 +113,11 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) BLOCKEND is the address of the end of the user structure. */ CORE_ADDR -register_addr (regno, blockend) - int regno; - CORE_ADDR blockend; +register_addr (int regno, CORE_ADDR blockend) { CORE_ADDR addr; - if (regno < 0 || regno >= ARCH_NUM_REGS) + if (regno < 0 || regno >= NUM_REGS) error ("Invalid register number %d.", regno); REGISTER_U_ADDR (addr, blockend, regno); @@ -128,19 +126,21 @@ register_addr (regno, blockend) } #endif /* REGISTER_U_ADDR */ - + /* Register that we are able to handle aout (trad-core) file formats. */ static struct core_fns aout_core_fns = { - bfd_target_unknown_flavour, - fetch_core_registers, - NULL + bfd_target_unknown_flavour, /* core_flavour */ + default_check_format, /* check_format */ + default_core_sniffer, /* core_sniffer */ + fetch_core_registers, /* core_read_registers */ + NULL /* next */ }; void -_initialize_core_aout () +_initialize_core_aout (void) { add_core_fns (&aout_core_fns); } diff --git a/contrib/gdb/gdb/core-regset.c b/contrib/gdb/gdb/core-regset.c index d925abe..16cfde5 100644 --- a/contrib/gdb/gdb/core-regset.c +++ b/contrib/gdb/gdb/core-regset.c @@ -1,34 +1,36 @@ /* Machine independent GDB support for core files on systems using "regsets". - Copyright 1993-1998 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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. */ -/* N O T E S +/* N O T E S -This file is used by most systems that implement /proc. For these systems, -the general registers are laid out the same way in both the core file and -the gregset_p structure. The current exception to this is Irix-4.*, where -the gregset_p structure is split up into two pieces in the core file. + This file is used by most systems that implement /proc. For these systems, + the general registers are laid out the same way in both the core file and + the gregset_p structure. The current exception to this is Irix-4.*, where + the gregset_p structure is split up into two pieces in the core file. -The general register and floating point register sets are manipulated by -separate ioctl's. This file makes the assumption that if FP0_REGNUM is -defined, then support for the floating point register set is desired, -regardless of whether or not the actual target has floating point hardware. + The general register and floating point register sets are manipulated by + separate ioctl's. This file makes the assumption that if FP0_REGNUM is + defined, then support for the floating point register set is desired, + regardless of whether or not the actual target has floating point hardware. */ @@ -47,45 +49,43 @@ regardless of whether or not the actual target has floating point hardware. #include "command.h" #include "gdbcore.h" -static void fetch_core_registers PARAMS ((char *, unsigned, int, CORE_ADDR)); +/* Prototypes for supply_gregset etc. */ +#include "gregset.h" -void _initialize_core_regset PARAMS ((void)); +static void fetch_core_registers (char *, unsigned, int, CORE_ADDR); -/* +void _initialize_core_regset (void); -GLOBAL FUNCTION +/* - fetch_core_registers -- fetch current registers from core file + GLOBAL FUNCTION -SYNOPSIS + fetch_core_registers -- fetch current registers from core file - void fetch_core_registers (char *core_reg_sect, - unsigned core_reg_size, - int which, CORE_ADDR reg_addr) + SYNOPSIS -DESCRIPTION + void fetch_core_registers (char *core_reg_sect, + unsigned core_reg_size, + int which, CORE_ADDR reg_addr) - Read the values of either the general register set (WHICH equals 0) - or the floating point register set (WHICH equals 2) from the core - file data (pointed to by CORE_REG_SECT), and update gdb's idea of - their current values. The CORE_REG_SIZE parameter is ignored. + DESCRIPTION -NOTES + Read the values of either the general register set (WHICH equals 0) + or the floating point register set (WHICH equals 2) from the core + file data (pointed to by CORE_REG_SECT), and update gdb's idea of + their current values. The CORE_REG_SIZE parameter is compared to + the size of the gregset or fpgregset structures (as appropriate) to + validate the size of the structure from the core file. The + REG_ADDR parameter is ignored. - Use the indicated sizes to validate the gregset and fpregset - structures. -*/ + */ static void -fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) - char *core_reg_sect; - unsigned core_reg_size; - int which; - CORE_ADDR reg_addr; /* Unused in this version */ +fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, + CORE_ADDR reg_addr) { -#if defined (HAVE_GREGSET_T) && defined (HAVE_FPREGSET_T) - gregset_t gregset; - fpregset_t fpregset; + gdb_gregset_t gregset; + gdb_fpregset_t fpregset; if (which == 0) { @@ -108,27 +108,27 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) else { memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset)); -#if defined (FP0_REGNUM) - supply_fpregset (&fpregset); -#endif + if (FP0_REGNUM >= 0) + supply_fpregset (&fpregset); } } -#endif /* defined(HAVE_GREGSET_T) && defined (HAVE_FPREGSET_T) */ } - + /* Register that we are able to handle ELF file formats using standard procfs "regset" structures. */ static struct core_fns regset_core_fns = { - bfd_target_elf_flavour, - fetch_core_registers, - NULL + bfd_target_elf_flavour, /* core_flavour */ + default_check_format, /* check_format */ + default_core_sniffer, /* core_sniffer */ + fetch_core_registers, /* core_read_registers */ + NULL /* next */ }; void -_initialize_core_regset () +_initialize_core_regset (void) { add_core_fns (®set_core_fns); } diff --git a/contrib/gdb/gdb/dbxread.c b/contrib/gdb/gdb/dbxread.c index 2f99398..16d0043 100644 --- a/contrib/gdb/gdb/dbxread.c +++ b/contrib/gdb/gdb/dbxread.c @@ -1,22 +1,24 @@ /* Read dbx symbol tables and convert to internal format, for GDB. - Copyright 1986, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 1998 + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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. */ /* This module provides three functions: dbx_symfile_init, which initializes to read a symbol file; dbx_new_init, which @@ -42,26 +44,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "obstack.h" #include "gdb_stat.h" -#include <ctype.h> #include "symtab.h" #include "breakpoint.h" -#include "command.h" #include "target.h" #include "gdbcore.h" /* for bfd stuff */ -#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */ +#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */ #include "symfile.h" #include "objfiles.h" #include "buildsym.h" #include "stabsread.h" #include "gdb-stabs.h" #include "demangle.h" -#include "language.h" /* Needed inside partial-stab.h */ +#include "language.h" /* Needed for local_hex_string */ #include "complaints.h" +#include "cp-abi.h" #include "aout/aout64.h" #include "aout/stab_gnu.h" /* We always use GNU stabs, not native, now */ - + /* This macro returns the size field of a minimal symbol, which is normally stored in the "info" field. The macro can be overridden for specific targets (e.g. MIPS16) that use the info field for other purposes. */ @@ -73,50 +74,56 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* We put a pointer to this structure in the read_symtab_private field of the psymtab. */ -struct symloc { +struct symloc + { + /* The start (inclusive) and end (exclusive) addresses for this + partial symtab's text. STABS doesn't reliably give us nice + start and end addresses for each function. Instead, we are + told the addresses of various boundary points, and we have to + gather those together to build ranges. These are our running + best guess as to the range of text addresses for this psymtab. */ + CORE_ADDR textlow, texthigh; - /* Offset within the file symbol table of first local symbol for this - file. */ + /* Offset within the file symbol table of first local symbol for this + file. */ - int ldsymoff; + int ldsymoff; - /* Length (in bytes) of the section of the symbol table devoted to - this file's symbols (actually, the section bracketed may contain - more than just this file's symbols). If ldsymlen is 0, the only - reason for this thing's existence is the dependency list. Nothing - else will happen when it is read in. */ + /* Length (in bytes) of the section of the symbol table devoted to + this file's symbols (actually, the section bracketed may contain + more than just this file's symbols). If ldsymlen is 0, the only + reason for this thing's existence is the dependency list. Nothing + else will happen when it is read in. */ - int ldsymlen; + int ldsymlen; - /* The size of each symbol in the symbol file (in external form). */ + /* The size of each symbol in the symbol file (in external form). */ - int symbol_size; + int symbol_size; - /* Further information needed to locate the symbols if they are in - an ELF file. */ + /* Further information needed to locate the symbols if they are in + an ELF file. */ - int symbol_offset; - int string_offset; - int file_string_offset; -}; + int symbol_offset; + int string_offset; + int file_string_offset; + }; #define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff) #define LDSYMLEN(p) (((struct symloc *)((p)->read_symtab_private))->ldsymlen) #define SYMLOC(p) ((struct symloc *)((p)->read_symtab_private)) +#define TEXTLOW(p) (SYMLOC(p)->textlow) +#define TEXTHIGH(p) (SYMLOC(p)->texthigh) #define SYMBOL_SIZE(p) (SYMLOC(p)->symbol_size) #define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset) #define STRING_OFFSET(p) (SYMLOC(p)->string_offset) #define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset) - + /* Remember what we deduced to be the source language of this psymtab. */ static enum language psymtab_language = language_unknown; -/* Nonzero means give verbose info on gdb action. From main.c. */ - -extern int info_verbose; - /* The BFD for this file -- implicit parameter to next_symbol_text. */ static bfd *symfile_bfd; @@ -170,33 +177,81 @@ static int has_line_numbers; /* Complaints about the symbols we have encountered. */ -struct complaint lbrac_complaint = - {"bad block start address patched", 0, 0}; +struct complaint lbrac_complaint = +{"bad block start address patched", 0, 0}; struct complaint string_table_offset_complaint = - {"bad string table offset in symbol %d", 0, 0}; +{"bad string table offset in symbol %d", 0, 0}; struct complaint unknown_symtype_complaint = - {"unknown symbol type %s", 0, 0}; +{"unknown symbol type %s", 0, 0}; struct complaint unknown_symchar_complaint = - {"unknown symbol descriptor `%c'", 0, 0}; +{"unknown symbol descriptor `%c'", 0, 0}; struct complaint lbrac_rbrac_complaint = - {"block start larger than block end", 0, 0}; +{"block start larger than block end", 0, 0}; struct complaint lbrac_unmatched_complaint = - {"unmatched N_LBRAC before symtab pos %d", 0, 0}; +{"unmatched N_LBRAC before symtab pos %d", 0, 0}; struct complaint lbrac_mismatch_complaint = - {"N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", 0, 0}; +{"N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", 0, 0}; struct complaint repeated_header_complaint = - {"\"repeated\" header file %s not previously seen, at symtab pos %d", 0, 0}; +{"\"repeated\" header file %s not previously seen, at symtab pos %d", 0, 0}; struct complaint unclaimed_bincl_complaint = - {"N_BINCL %s not in entries for any file, at symtab pos %d", 0, 0}; +{"N_BINCL %s not in entries for any file, at symtab pos %d", 0, 0}; + +/* find_text_range --- find start and end of loadable code sections + + The find_text_range function finds the shortest address range that + encloses all sections containing executable code, and stores it in + objfile's text_addr and text_size members. + + dbx_symfile_read will use this to finish off the partial symbol + table, in some cases. */ + +static void +find_text_range (bfd * sym_bfd, struct objfile *objfile) +{ + asection *sec; + int found_any = 0; + CORE_ADDR start = 0; + CORE_ADDR end = 0; + + for (sec = sym_bfd->sections; sec; sec = sec->next) + if (bfd_get_section_flags (sym_bfd, sec) & SEC_CODE) + { + CORE_ADDR sec_start = bfd_section_vma (sym_bfd, sec); + CORE_ADDR sec_end = sec_start + bfd_section_size (sym_bfd, sec); + + if (found_any) + { + if (sec_start < start) + start = sec_start; + if (sec_end > end) + end = sec_end; + } + else + { + start = sec_start; + end = sec_end; + } + + found_any = 1; + } + + if (!found_any) + error ("Can't find any code sections in symbol file"); + + DBX_TEXT_ADDR (objfile) = start; + DBX_TEXT_SIZE (objfile) = end - start; +} + + /* During initial symbol readin, we need to have a structure to keep track of which psymtabs have which bincls in them. This structure is used during readin to setup the list of dependencies within each @@ -216,82 +271,61 @@ static int bincls_allocated; /* Local function prototypes */ -static void -process_now PARAMS ((struct objfile *)); +extern void _initialize_dbxread (void); -static void -free_header_files PARAMS ((void)); +static void process_now (struct objfile *); -static void -init_header_files PARAMS ((void)); +static void read_ofile_symtab (struct partial_symtab *); -static void -read_ofile_symtab PARAMS ((struct partial_symtab *)); +static void dbx_psymtab_to_symtab (struct partial_symtab *); -static void -dbx_psymtab_to_symtab PARAMS ((struct partial_symtab *)); +static void dbx_psymtab_to_symtab_1 (struct partial_symtab *); -static void -dbx_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); +static void read_dbx_dynamic_symtab (struct objfile *objfile); -static void -read_dbx_dynamic_symtab PARAMS ((struct section_offsets *, - struct objfile *objfile)); +static void read_dbx_symtab (struct objfile *); -static void -read_dbx_symtab PARAMS ((struct section_offsets *, struct objfile *, - CORE_ADDR, int)); +static void free_bincl_list (struct objfile *); -static void -free_bincl_list PARAMS ((struct objfile *)); +static struct partial_symtab *find_corresponding_bincl_psymtab (char *, int); -static struct partial_symtab * -find_corresponding_bincl_psymtab PARAMS ((char *, int)); +static void add_bincl_to_list (struct partial_symtab *, char *, int); -static void -add_bincl_to_list PARAMS ((struct partial_symtab *, char *, int)); +static void init_bincl_list (int, struct objfile *); -static void -init_bincl_list PARAMS ((int, struct objfile *)); +static char *dbx_next_symbol_text (struct objfile *); -static char * -dbx_next_symbol_text PARAMS ((struct objfile *)); +static void fill_symbuf (bfd *); -static void -fill_symbuf PARAMS ((bfd *)); +static void dbx_symfile_init (struct objfile *); -static void -dbx_symfile_init PARAMS ((struct objfile *)); +static void dbx_new_init (struct objfile *); -static void -dbx_new_init PARAMS ((struct objfile *)); +static void dbx_symfile_read (struct objfile *, int); -static void -dbx_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); +static void dbx_symfile_finish (struct objfile *); -static void -dbx_symfile_finish PARAMS ((struct objfile *)); +static void record_minimal_symbol (char *, CORE_ADDR, int, struct objfile *); -static void -record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *)); +static void add_new_header_file (char *, int); -static void -add_new_header_file PARAMS ((char *, int)); +static void add_old_header_file (char *, int); -static void -add_old_header_file PARAMS ((char *, int)); +static void add_this_object_header_file (int); -static void -add_this_object_header_file PARAMS ((int)); +static struct partial_symtab *start_psymtab (struct objfile *, char *, + CORE_ADDR, int, + struct partial_symbol **, + struct partial_symbol **); /* Free up old header file tables */ -static void -free_header_files () +void +free_header_files (void) { if (this_object_header_files) { - free ((PTR)this_object_header_files); + xfree (this_object_header_files); this_object_header_files = NULL; } n_allocated_this_object_header_files = 0; @@ -299,8 +333,8 @@ free_header_files () /* Allocate new header file tables */ -static void -init_header_files () +void +init_header_files (void) { n_allocated_this_object_header_files = 10; this_object_header_files = (int *) xmalloc (10 * sizeof (int)); @@ -310,15 +344,14 @@ init_header_files () at the next successive FILENUM. */ static void -add_this_object_header_file (i) - int i; +add_this_object_header_file (int i) { if (n_this_object_header_files == n_allocated_this_object_header_files) { n_allocated_this_object_header_files *= 2; this_object_header_files = (int *) xrealloc ((char *) this_object_header_files, - n_allocated_this_object_header_files * sizeof (int)); + n_allocated_this_object_header_files * sizeof (int)); } this_object_header_files[n_this_object_header_files++] = i; @@ -330,9 +363,7 @@ add_this_object_header_file (i) symbol tables for the same header file. */ static void -add_old_header_file (name, instance) - char *name; - int instance; +add_old_header_file (char *name, int instance) { register struct header_file *p = HEADER_FILES (current_objfile); register int i; @@ -358,9 +389,7 @@ add_old_header_file (name, instance) so we record the file when its "begin" is seen and ignore the "end". */ static void -add_new_header_file (name, instance) - char *name; - int instance; +add_new_header_file (char *name, int instance) { register int i; register struct header_file *hfile; @@ -391,7 +420,7 @@ add_new_header_file (name, instance) i = N_HEADER_FILES (current_objfile)++; hfile = HEADER_FILES (current_objfile) + i; - hfile->name = savestring (name, strlen(name)); + hfile->name = savestring (name, strlen (name)); hfile->instance = instance; hfile->length = 10; hfile->vector @@ -403,8 +432,7 @@ add_new_header_file (name, instance) #if 0 static struct type ** -explicit_lookup_type (real_filenum, index) - int real_filenum, index; +explicit_lookup_type (int real_filenum, int index) { register struct header_file *f = &HEADER_FILES (current_objfile)[real_filenum]; @@ -414,18 +442,15 @@ explicit_lookup_type (real_filenum, index) f->vector = (struct type **) xrealloc (f->vector, f->length * sizeof (struct type *)); memset (&f->vector[f->length / 2], - '\0', f->length * sizeof (struct type *) / 2); + '\0', f->length * sizeof (struct type *) / 2); } return &f->vector[index]; } #endif static void -record_minimal_symbol (name, address, type, objfile) - char *name; - CORE_ADDR address; - int type; - struct objfile *objfile; +record_minimal_symbol (char *name, CORE_ADDR address, int type, + struct objfile *objfile) { enum minimal_symbol_type ms_type; int section; @@ -435,17 +460,17 @@ record_minimal_symbol (name, address, type, objfile) { case N_TEXT | N_EXT: ms_type = mst_text; - section = SECT_OFF_TEXT; + section = SECT_OFF_TEXT (objfile); bfd_section = DBX_TEXT_SECTION (objfile); break; case N_DATA | N_EXT: ms_type = mst_data; - section = SECT_OFF_DATA; + section = SECT_OFF_DATA (objfile); bfd_section = DBX_DATA_SECTION (objfile); break; case N_BSS | N_EXT: ms_type = mst_bss; - section = SECT_OFF_BSS; + section = SECT_OFF_BSS (objfile); bfd_section = DBX_BSS_SECTION (objfile); break; case N_ABS | N_EXT: @@ -456,15 +481,15 @@ record_minimal_symbol (name, address, type, objfile) #ifdef N_SETV case N_SETV | N_EXT: ms_type = mst_data; - section = SECT_OFF_DATA; + section = SECT_OFF_DATA (objfile); bfd_section = DBX_DATA_SECTION (objfile); break; case N_SETV: /* I don't think this type actually exists; since a N_SETV is the result - of going over many .o files, it doesn't make sense to have one - file local. */ + of going over many .o files, it doesn't make sense to have one + file local. */ ms_type = mst_file_data; - section = SECT_OFF_DATA; + section = SECT_OFF_DATA (objfile); bfd_section = DBX_DATA_SECTION (objfile); break; #endif @@ -473,16 +498,16 @@ record_minimal_symbol (name, address, type, objfile) case N_FN: case N_FN_SEQ: ms_type = mst_file_text; - section = SECT_OFF_TEXT; + section = SECT_OFF_TEXT (objfile); bfd_section = DBX_TEXT_SECTION (objfile); break; case N_DATA: ms_type = mst_file_data; /* Check for __DYNAMIC, which is used by Sun shared libraries. - Record it as global even if it's local, not global, so - lookup_minimal_symbol can find it. We don't check symbol_leading_char - because for SunOS4 it always is '_'. */ + Record it as global even if it's local, not global, so + lookup_minimal_symbol can find it. We don't check symbol_leading_char + because for SunOS4 it always is '_'. */ if (name[8] == 'C' && STREQ ("__DYNAMIC", name)) ms_type = mst_data; @@ -491,15 +516,15 @@ record_minimal_symbol (name, address, type, objfile) char *tempstring = name; if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd)) ++tempstring; - if (VTBL_PREFIX_P ((tempstring))) + if (is_vtable_name (tempstring)) ms_type = mst_data; } - section = SECT_OFF_DATA; + section = SECT_OFF_DATA (objfile); bfd_section = DBX_DATA_SECTION (objfile); break; case N_BSS: ms_type = mst_file_bss; - section = SECT_OFF_BSS; + section = SECT_OFF_BSS (objfile); bfd_section = DBX_BSS_SECTION (objfile); break; default: @@ -507,7 +532,7 @@ record_minimal_symbol (name, address, type, objfile) section = -1; bfd_section = NULL; break; - } + } if ((ms_type == mst_file_text || ms_type == mst_text) && address < lowest_text_address) @@ -522,23 +547,16 @@ record_minimal_symbol (name, address, type, objfile) put all the relevant info into a "struct dbx_symfile_info", hung off the objfile structure. - SECTION_OFFSETS contains offsets relative to which the symbols in the - various sections are (depending where the sections were actually loaded). MAINLINE is true if we are reading the main symbol table (as opposed to a shared lib or dynamically loaded file). */ static void -dbx_symfile_read (objfile, section_offsets, mainline) - struct objfile *objfile; - struct section_offsets *section_offsets; - int mainline; /* FIXME comments above */ +dbx_symfile_read (struct objfile *objfile, int mainline) { bfd *sym_bfd; int val; struct cleanup *back_to; - val = strlen (objfile->name); - sym_bfd = objfile->obfd; /* .o and .nlm files are relocatables with text, data and bss segs based at @@ -556,6 +574,7 @@ dbx_symfile_read (objfile, section_offsets, mainline) || (0 == strncmp (bfd_get_target (sym_bfd), "som", 3)) || (0 == strncmp (bfd_get_target (sym_bfd), "coff", 4)) || (0 == strncmp (bfd_get_target (sym_bfd), "pe", 2)) + || (0 == strncmp (bfd_get_target (sym_bfd), "epoc-pe", 7)) || (0 == strncmp (bfd_get_target (sym_bfd), "nlm", 3))); val = bfd_seek (sym_bfd, DBX_SYMTAB_OFFSET (objfile), SEEK_SET); @@ -564,29 +583,39 @@ dbx_symfile_read (objfile, section_offsets, mainline) /* If we are reinitializing, or if we have never loaded syms yet, init */ if (mainline - || objfile->global_psymbols.size == 0 - || objfile->static_psymbols.size == 0) + || (objfile->global_psymbols.size == 0 + && objfile->static_psymbols.size == 0)) init_psymbol_list (objfile, DBX_SYMCOUNT (objfile)); symbol_size = DBX_SYMBOL_SIZE (objfile); symbol_table_offset = DBX_SYMTAB_OFFSET (objfile); free_pending_blocks (); - back_to = make_cleanup ((make_cleanup_func) really_free_pendings, 0); + back_to = make_cleanup (really_free_pendings, 0); init_minimal_symbol_collection (); - make_cleanup ((make_cleanup_func) discard_minimal_symbols, 0); + make_cleanup_discard_minimal_symbols (); - /* Now that the symbol table data of the executable file are all in core, - process them and define symbols accordingly. */ + /* Read stabs data from executable file and define symbols. */ - read_dbx_symtab (section_offsets, objfile, - DBX_TEXT_ADDR (objfile), - DBX_TEXT_SIZE (objfile)); + read_dbx_symtab (objfile); /* Add the dynamic symbols. */ - read_dbx_dynamic_symtab (section_offsets, objfile); + read_dbx_dynamic_symtab (objfile); + + /* Take the text ranges the STABS partial symbol scanner computed + for each of the psymtabs and convert it into the canonical form + for psymtabs. */ + { + struct partial_symtab *p; + + ALL_OBJFILE_PSYMTABS (objfile, p) + { + p->textlow = TEXTLOW (p); + p->texthigh = TEXTHIGH (p); + } + } /* Install any minimal symbols that have been collected as the current minimal symbols for this objfile. */ @@ -601,8 +630,7 @@ dbx_symfile_read (objfile, section_offsets, mainline) file, e.g. a shared library). */ static void -dbx_new_init (ignore) - struct objfile *ignore; +dbx_new_init (struct objfile *ignore) { stabsread_new_init (); buildsym_new_init (); @@ -623,11 +651,10 @@ dbx_new_init (ignore) be called unless this is an a.out (or very similar) file. FIXME, there should be a cleaner peephole into the BFD environment here. */ -#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */ +#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */ static void -dbx_symfile_init (objfile) - struct objfile *objfile; +dbx_symfile_init (struct objfile *objfile) { int val; bfd *sym_bfd = objfile->obfd; @@ -637,7 +664,7 @@ dbx_symfile_init (objfile) /* Allocate struct to keep track of the symfile */ objfile->sym_stab_info = (struct dbx_symfile_info *) - xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + xmmalloc (objfile->md, sizeof (struct dbx_symfile_info)); memset ((PTR) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info)); DBX_TEXT_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); @@ -651,7 +678,7 @@ dbx_symfile_init (objfile) /* FIXME POKING INSIDE BFD DATA STRUCTURES */ DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL; - + text_sect = bfd_get_section_by_name (sym_bfd, ".text"); if (!text_sect) error ("Can't find .text section in symbol file"); @@ -679,8 +706,8 @@ dbx_symfile_init (objfile) if (STRING_TABLE_OFFSET == 0) { /* It appears that with the existing bfd code, STRING_TABLE_OFFSET - will never be zero, even when there is no string table. This - would appear to be a bug in bfd. */ + will never be zero, even when there is no string table. This + would appear to be a bug in bfd. */ DBX_STRINGTAB_SIZE (objfile) = 0; DBX_STRINGTAB (objfile) = NULL; } @@ -689,9 +716,9 @@ dbx_symfile_init (objfile) val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET); if (val < 0) perror_with_name (name); - + memset ((PTR) size_temp, 0, sizeof (size_temp)); - val = bfd_read ((PTR) size_temp, sizeof (size_temp), 1, sym_bfd); + val = bfd_bread ((PTR) size_temp, sizeof (size_temp), sym_bfd); if (val < 0) { perror_with_name (name); @@ -714,24 +741,25 @@ dbx_symfile_init (objfile) bfd can't tell us there is no string table, the sanity checks may or may not catch this. */ DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp); - + if (DBX_STRINGTAB_SIZE (objfile) < sizeof (size_temp) || DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd)) error ("ridiculous string table size (%d bytes).", DBX_STRINGTAB_SIZE (objfile)); - + DBX_STRINGTAB (objfile) = - (char *) obstack_alloc (&objfile -> psymbol_obstack, + (char *) obstack_alloc (&objfile->psymbol_obstack, DBX_STRINGTAB_SIZE (objfile)); OBJSTAT (objfile, sz_strtab += DBX_STRINGTAB_SIZE (objfile)); - + /* Now read in the string table in one big gulp. */ - + val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET); if (val < 0) perror_with_name (name); - val = bfd_read (DBX_STRINGTAB (objfile), DBX_STRINGTAB_SIZE (objfile), 1, - sym_bfd); + val = bfd_bread (DBX_STRINGTAB (objfile), + DBX_STRINGTAB_SIZE (objfile), + sym_bfd); if (val != DBX_STRINGTAB_SIZE (objfile)) perror_with_name (name); } @@ -744,8 +772,7 @@ dbx_symfile_init (objfile) objfile struct from the global list of known objfiles. */ static void -dbx_symfile_finish (objfile) - struct objfile *objfile; +dbx_symfile_finish (struct objfile *objfile) { if (objfile->sym_stab_info != NULL) { @@ -756,17 +783,17 @@ dbx_symfile_finish (objfile) while (--i >= 0) { - free (hfiles [i].name); - free (hfiles [i].vector); + xfree (hfiles[i].name); + xfree (hfiles[i].vector); } - free ((PTR) hfiles); + xfree (hfiles); } - mfree (objfile -> md, objfile->sym_stab_info); + xmfree (objfile->md, objfile->sym_stab_info); } free_header_files (); } - + /* Buffer for reading the symbol table entries. */ static struct external_nlist symbuf[4096]; static int symbuf_idx; @@ -775,23 +802,23 @@ static int symbuf_end; /* cont_elem is used for continuing information in cfront. It saves information about which types need to be fixed up and completed after all the stabs are read. */ -struct cont_elem +struct cont_elem { - /* sym and stabsstring for continuing information in cfront */ - struct symbol * sym; - char * stabs; - /* state dependancies (statics that must be preserved) */ + /* sym and stabstring for continuing information in cfront */ + struct symbol *sym; + char *stabs; + /* state dependencies (statics that must be preserved) */ int sym_idx; int sym_end; int symnum; - int (*func) PARAMS ((struct objfile *, struct symbol *, char *)); - /* other state dependancies include: + int (*func) (struct objfile *, struct symbol *, char *); + /* other state dependencies include: (assumption is that these will not change since process_now FIXME!!) - stringtab_global - n_stabs - objfile - symfile_bfd */ -}; + stringtab_global + n_stabs + objfile + symfile_bfd */ + }; static struct cont_elem *cont_list = 0; static int cont_limit = 0; @@ -799,24 +826,22 @@ static int cont_count = 0; /* Arrange for function F to be called with arguments SYM and P later in the stabs reading process. */ -void -process_later (sym, p, f) - struct symbol *sym; - char *p; - int (*f) PARAMS ((struct objfile *, struct symbol *, char *)); +void +process_later (struct symbol *sym, char *p, + int (*f) (struct objfile *, struct symbol *, char *)) { /* Allocate more space for the deferred list. */ if (cont_count >= cont_limit - 1) { - cont_limit += 32; /* chunk size */ + cont_limit += 32; /* chunk size */ cont_list - = (struct cont_elem *) xrealloc (cont_list, - (cont_limit - * sizeof (struct cont_elem))); + = (struct cont_elem *) xrealloc (cont_list, + (cont_limit + * sizeof (struct cont_elem))); if (!cont_list) - error ("Virtual memory exhausted\n"); + error ("Virtual memory exhausted\n"); } /* Save state variables so we can process these stabs later. */ @@ -831,9 +856,8 @@ process_later (sym, p, f) /* Call deferred funtions in CONT_LIST. */ -static void -process_now (objfile) - struct objfile *objfile; +static void +process_now (struct objfile *objfile) { int i; int save_symbuf_idx; @@ -842,7 +866,7 @@ process_now (objfile) struct symbol *sym; char *stabs; int err; - int (*func) PARAMS ((struct objfile *, struct symbol *, char *)); + int (*func) (struct objfile *, struct symbol *, char *); /* Save the state of our caller, we'll want to restore it before returning. */ @@ -855,8 +879,8 @@ process_now (objfile) { /* Restore the state for this deferred stab. */ symbuf_idx = cont_list[i].sym_idx; - symbuf_end = cont_list[i].sym_end; - symnum = cont_list[i].symnum; + symbuf_end = cont_list[i].sym_end; + symnum = cont_list[i].symnum; sym = cont_list[i].sym; stabs = cont_list[i].stabs; func = cont_list[i].func; @@ -902,8 +926,7 @@ static unsigned int symbuf_read; (into the string table) but this does no harm. */ static void -fill_symbuf (sym_bfd) - bfd *sym_bfd; +fill_symbuf (bfd *sym_bfd) { unsigned int count; int nbytes; @@ -927,7 +950,7 @@ fill_symbuf (sym_bfd) count = sizeof (symbuf); } - nbytes = bfd_read ((PTR)symbuf, count, 1, sym_bfd); + nbytes = bfd_bread ((PTR) symbuf, count, sym_bfd); if (nbytes < 0) perror_with_name (bfd_get_filename (sym_bfd)); else if (nbytes == 0) @@ -938,22 +961,15 @@ fill_symbuf (sym_bfd) symbuf_read += nbytes; } -#define SWAP_SYMBOL(symp, abfd) \ - { \ - (symp)->n_strx = bfd_h_get_32(abfd, \ - (unsigned char *)&(symp)->n_strx); \ - (symp)->n_desc = bfd_h_get_16 (abfd, \ - (unsigned char *)&(symp)->n_desc); \ - (symp)->n_value = bfd_h_get_32 (abfd, \ - (unsigned char *)&(symp)->n_value); \ - } - #define INTERNALIZE_SYMBOL(intern, extern, abfd) \ { \ (intern).n_type = bfd_h_get_8 (abfd, (extern)->e_type); \ (intern).n_strx = bfd_h_get_32 (abfd, (extern)->e_strx); \ (intern).n_desc = bfd_h_get_16 (abfd, (extern)->e_desc); \ - (intern).n_value = bfd_h_get_32 (abfd, (extern)->e_value); \ + if (bfd_get_sign_extend_vma (abfd)) \ + (intern).n_value = bfd_h_get_signed_32 (abfd, (extern)->e_value); \ + else \ + (intern).n_value = bfd_h_get_32 (abfd, (extern)->e_value); \ } /* Invariant: The symbol pointed to by symbuf_idx is the first one @@ -966,8 +982,7 @@ fill_symbuf (sym_bfd) call this function to get the continuation. */ static char * -dbx_next_symbol_text (objfile) - struct objfile *objfile; +dbx_next_symbol_text (struct objfile *objfile) { struct internal_nlist nlist; @@ -975,7 +990,7 @@ dbx_next_symbol_text (objfile) fill_symbuf (symfile_bfd); symnum++; - INTERNALIZE_SYMBOL(nlist, &symbuf[symbuf_idx], symfile_bfd); + INTERNALIZE_SYMBOL (nlist, &symbuf[symbuf_idx], symfile_bfd); OBJSTAT (objfile, n_stabs++); symbuf_idx++; @@ -987,30 +1002,25 @@ dbx_next_symbol_text (objfile) allocated. */ static void -init_bincl_list (number, objfile) - int number; - struct objfile *objfile; +init_bincl_list (int number, struct objfile *objfile) { bincls_allocated = number; next_bincl = bincl_list = (struct header_file_location *) - xmmalloc (objfile -> md, bincls_allocated * sizeof(struct header_file_location)); + xmmalloc (objfile->md, bincls_allocated * sizeof (struct header_file_location)); } /* Add a bincl to the list. */ static void -add_bincl_to_list (pst, name, instance) - struct partial_symtab *pst; - char *name; - int instance; +add_bincl_to_list (struct partial_symtab *pst, char *name, int instance) { if (next_bincl >= bincl_list + bincls_allocated) { int offset = next_bincl - bincl_list; bincls_allocated *= 2; bincl_list = (struct header_file_location *) - xmrealloc (pst->objfile->md, (char *)bincl_list, - bincls_allocated * sizeof (struct header_file_location)); + xmrealloc (pst->objfile->md, (char *) bincl_list, + bincls_allocated * sizeof (struct header_file_location)); next_bincl = bincl_list + offset; } next_bincl->pst = pst; @@ -1023,9 +1033,7 @@ add_bincl_to_list (pst, name, instance) with that header_file_location. */ static struct partial_symtab * -find_corresponding_bincl_psymtab (name, instance) - char *name; - int instance; +find_corresponding_bincl_psymtab (char *name, int instance) { struct header_file_location *bincl; @@ -1041,20 +1049,50 @@ find_corresponding_bincl_psymtab (name, instance) /* Free the storage allocated for the bincl list. */ static void -free_bincl_list (objfile) - struct objfile *objfile; +free_bincl_list (struct objfile *objfile) { - mfree (objfile -> md, (PTR)bincl_list); + xmfree (objfile->md, (PTR) bincl_list); bincls_allocated = 0; } +static void +do_free_bincl_list_cleanup (void *objfile) +{ + free_bincl_list (objfile); +} + +static struct cleanup * +make_cleanup_free_bincl_list (struct objfile *objfile) +{ + return make_cleanup (do_free_bincl_list_cleanup, objfile); +} + +/* Set namestring based on nlist. If the string table index is invalid, + give a fake name, and print a single error message per symbol file read, + rather than abort the symbol reading or flood the user with messages. */ + +static char * +set_namestring (struct objfile *objfile, struct internal_nlist nlist) +{ + char *namestring; + + if (((unsigned) nlist.n_strx + file_string_table_offset) >= + DBX_STRINGTAB_SIZE (objfile)) + { + complain (&string_table_offset_complaint, symnum); + namestring = "<bad string table offset>"; + } + else + namestring = nlist.n_strx + file_string_table_offset + + DBX_STRINGTAB (objfile); + return namestring; +} + /* Scan a SunOs dynamic symbol table for symbols of interest and add them to the minimal symbol table. */ static void -read_dbx_dynamic_symtab (section_offsets, objfile) - struct section_offsets *section_offsets; - struct objfile *objfile; +read_dbx_dynamic_symtab (struct objfile *objfile) { bfd *abfd = objfile->obfd; struct cleanup *back_to; @@ -1085,7 +1123,7 @@ read_dbx_dynamic_symtab (section_offsets, objfile) return; dynsyms = (asymbol **) xmalloc (dynsym_size); - back_to = make_cleanup (free, dynsyms); + back_to = make_cleanup (xfree, dynsyms); dynsym_count = bfd_canonicalize_dynamic_symtab (abfd, dynsyms); if (dynsym_count < 0) @@ -1112,17 +1150,17 @@ read_dbx_dynamic_symtab (section_offsets, objfile) if (bfd_get_section_flags (abfd, sec) & SEC_CODE) { - sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + sym_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); type = N_TEXT; } else if (bfd_get_section_flags (abfd, sec) & SEC_DATA) { - sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA); + sym_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); type = N_DATA; } else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) { - sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS); + sym_value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile)); type = N_BSS; } else @@ -1146,9 +1184,9 @@ read_dbx_dynamic_symtab (section_offsets, objfile) do_cleanups (back_to); return; } - + dynrels = (arelent **) xmalloc (dynrel_size); - make_cleanup (free, dynrels); + make_cleanup (xfree, dynrels); dynrel_count = bfd_canonicalize_dynamic_reloc (abfd, dynrels, dynsyms); if (dynrel_count < 0) @@ -1163,7 +1201,7 @@ read_dbx_dynamic_symtab (section_offsets, objfile) { arelent *rel = *relptr; CORE_ADDR address = - rel->address + ANOFFSET (section_offsets, SECT_OFF_DATA); + rel->address + ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); switch (bfd_get_arch (abfd)) { @@ -1192,22 +1230,16 @@ read_dbx_dynamic_symtab (section_offsets, objfile) do_cleanups (back_to); } -/* Given pointers to an a.out symbol table in core containing dbx - style data, setup partial_symtab's describing each source file for - which debugging information is available. - SYMFILE_NAME is the name of the file we are reading from - and SECTION_OFFSETS is the set of offsets for the various sections - of the file (a set of zeros if the mainline program). */ +/* Setup partial_symtab's describing each source file for which + debugging information is available. */ static void -read_dbx_symtab (section_offsets, objfile, text_addr, text_size) - struct section_offsets *section_offsets; - struct objfile *objfile; - CORE_ADDR text_addr; - int text_size; +read_dbx_symtab (struct objfile *objfile) { register struct external_nlist *bufp = 0; /* =0 avoids gcc -Wall glitch */ struct internal_nlist nlist; + CORE_ADDR text_addr; + int text_size; register char *namestring; int nsl; @@ -1230,13 +1262,16 @@ read_dbx_symtab (section_offsets, objfile, text_addr, text_size) struct partial_symtab **dependency_list; int dependencies_used, dependencies_allocated; + text_addr = DBX_TEXT_ADDR (objfile); + text_size = DBX_TEXT_SIZE (objfile); + /* FIXME. We probably want to change stringtab_global rather than add this while processing every symbol entry. FIXME. */ file_string_table_offset = 0; next_file_string_table_offset = 0; stringtab_global = DBX_STRINGTAB (objfile); - + pst = (struct partial_symtab *) 0; includes_allocated = 30; @@ -1252,11 +1287,11 @@ read_dbx_symtab (section_offsets, objfile, text_addr, text_size) /* Init bincl list */ init_bincl_list (20, objfile); - back_to = make_cleanup ((make_cleanup_func) free_bincl_list, objfile); + back_to = make_cleanup_free_bincl_list (objfile); last_source_file = NULL; - lowest_text_address = (CORE_ADDR)-1; + lowest_text_address = (CORE_ADDR) -1; symfile_bfd = objfile->obfd; /* For next_text_symbol */ abfd = objfile->obfd; @@ -1268,7 +1303,7 @@ read_dbx_symtab (section_offsets, objfile, text_addr, text_size) for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++) { /* Get the symbol for this run and pull out some info */ - QUIT; /* allow this to be interruptable */ + QUIT; /* allow this to be interruptable */ if (symbuf_idx == symbuf_end) fill_symbuf (abfd); bufp = &symbuf[symbuf_idx++]; @@ -1290,62 +1325,845 @@ read_dbx_symtab (section_offsets, objfile, text_addr, text_size) like duplicating code, I will do my penance here, and describe the code which is duplicated: - *) The assignment to namestring. - *) The call to strchr. - *) The addition of a partial symbol the the two partial - symbol lists. This last is a large section of code, so - I've imbedded it in the following macro. - */ - -/* Set namestring based on nlist. If the string table index is invalid, - give a fake name, and print a single error message per symbol file read, - rather than abort the symbol reading or flood the user with messages. */ + *) The assignment to namestring. + *) The call to strchr. + *) The addition of a partial symbol the the two partial + symbol lists. This last is a large section of code, so + I've imbedded it in the following macro. + */ + + switch (nlist.n_type) + { + static struct complaint function_outside_compilation_unit = { + "function `%s' appears to be defined outside of all compilation units", 0, 0 + }; + char *p; + /* + * Standard, external, non-debugger, symbols + */ + + case N_TEXT | N_EXT: + case N_NBTEXT | N_EXT: + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + goto record_it; + + case N_DATA | N_EXT: + case N_NBDATA | N_EXT: + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); + goto record_it; + + case N_BSS: + case N_BSS | N_EXT: + case N_NBBSS | N_EXT: + case N_SETV | N_EXT: /* FIXME, is this in BSS? */ + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_BSS (objfile)); + goto record_it; + + case N_ABS | N_EXT: + record_it: + namestring = set_namestring (objfile, nlist); + + bss_ext_symbol: + record_minimal_symbol (namestring, nlist.n_value, + nlist.n_type, objfile); /* Always */ + continue; + + /* Standard, local, non-debugger, symbols */ + + case N_NBTEXT: + + /* We need to be able to deal with both N_FN or N_TEXT, + because we have no way of knowing whether the sys-supplied ld + or GNU ld was used to make the executable. Sequents throw + in another wrinkle -- they renumbered N_FN. */ + + case N_FN: + case N_FN_SEQ: + case N_TEXT: + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + namestring = set_namestring (objfile, nlist); + + if ((namestring[0] == '-' && namestring[1] == 'l') + || (namestring[(nsl = strlen (namestring)) - 1] == 'o' + && namestring[nsl - 2] == '.')) + { + if (objfile->ei.entry_point < nlist.n_value && + objfile->ei.entry_point >= last_o_file_start) + { + objfile->ei.entry_file_lowpc = last_o_file_start; + objfile->ei.entry_file_highpc = nlist.n_value; + } + if (past_first_source_file && pst + /* The gould NP1 uses low values for .o and -l symbols + which are not the address. */ + && nlist.n_value >= TEXTLOW (pst)) + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + nlist.n_value > TEXTHIGH (pst) + ? nlist.n_value : TEXTHIGH (pst), + dependency_list, dependencies_used, textlow_not_set); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + else + past_first_source_file = 1; + last_o_file_start = nlist.n_value; + } + else + goto record_it; + continue; + + case N_DATA: + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); + goto record_it; + + case N_UNDF | N_EXT: + if (nlist.n_value != 0) + { + /* This is a "Fortran COMMON" symbol. See if the target + environment knows where it has been relocated to. */ + + CORE_ADDR reladdr; + + namestring = set_namestring (objfile, nlist); + if (target_lookup_symbol (namestring, &reladdr)) + { + continue; /* Error in lookup; ignore symbol for now. */ + } + nlist.n_type ^= (N_BSS ^ N_UNDF); /* Define it as a bss-symbol */ + nlist.n_value = reladdr; + goto bss_ext_symbol; + } + continue; /* Just undefined, not COMMON */ + + case N_UNDF: + if (processing_acc_compilation && nlist.n_strx == 1) + { + /* Deal with relative offsets in the string table + used in ELF+STAB under Solaris. If we want to use the + n_strx field, which contains the name of the file, + we must adjust file_string_table_offset *before* calling + set_namestring(). */ + past_first_source_file = 1; + file_string_table_offset = next_file_string_table_offset; + next_file_string_table_offset = + file_string_table_offset + nlist.n_value; + if (next_file_string_table_offset < file_string_table_offset) + error ("string table offset backs up at %d", symnum); + /* FIXME -- replace error() with complaint. */ + continue; + } + continue; + + /* Lots of symbol types we can just ignore. */ + + case N_ABS: + case N_NBDATA: + case N_NBBSS: + continue; + + /* Keep going . . . */ + + /* + * Special symbol types for GNU + */ + case N_INDR: + case N_INDR | N_EXT: + case N_SETA: + case N_SETA | N_EXT: + case N_SETT: + case N_SETT | N_EXT: + case N_SETD: + case N_SETD | N_EXT: + case N_SETB: + case N_SETB | N_EXT: + case N_SETV: + continue; + + /* + * Debugger symbols + */ + + case N_SO: + { + CORE_ADDR valu; + static int prev_so_symnum = -10; + static int first_so_symnum; + char *p; + int prev_textlow_not_set; + + valu = nlist.n_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + prev_textlow_not_set = textlow_not_set; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* A zero value is probably an indication for the SunPRO 3.0 + compiler. end_psymtab explicitly tests for zero, so + don't relocate it. */ + + if (nlist.n_value == 0) + { + textlow_not_set = 1; + valu = 0; + } + else + textlow_not_set = 0; +#else + textlow_not_set = 0; +#endif + past_first_source_file = 1; + + if (prev_so_symnum != symnum - 1) + { /* Here if prev stab wasn't N_SO */ + first_so_symnum = symnum; + + if (pst) + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + valu > TEXTHIGH (pst) ? valu : TEXTHIGH (pst), + dependency_list, dependencies_used, + prev_textlow_not_set); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + } + + prev_so_symnum = symnum; + + /* End the current partial symtab and start a new one */ + + namestring = set_namestring (objfile, nlist); + + /* Null name means end of .o file. Don't start a new one. */ + if (*namestring == '\000') + continue; + + /* Some compilers (including gcc) emit a pair of initial N_SOs. + The first one is a directory name; the second the file name. + If pst exists, is empty, and has a filename ending in '/', + we assume the previous N_SO was a directory name. */ + + p = strrchr (namestring, '/'); + if (p && *(p + 1) == '\000') + continue; /* Simply ignore directory name SOs */ + + /* Some other compilers (C++ ones in particular) emit useless + SOs for non-existant .c files. We ignore all subsequent SOs that + immediately follow the first. */ + + if (!pst) + pst = start_psymtab (objfile, + namestring, valu, + first_so_symnum * symbol_size, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + continue; + } + + case N_BINCL: + { + enum language tmp_language; + /* Add this bincl to the bincl_list for future EXCLs. No + need to save the string; it'll be around until + read_dbx_symtab function returns */ + + namestring = set_namestring (objfile, nlist); + tmp_language = deduce_language_from_filename (namestring); + + /* Only change the psymtab's language if we've learned + something useful (eg. tmp_language is not language_unknown). + In addition, to match what start_subfile does, never change + from C++ to C. */ + if (tmp_language != language_unknown + && (tmp_language != language_c + || psymtab_language != language_cplus)) + psymtab_language = tmp_language; + + if (pst == NULL) + { + /* FIXME: we should not get here without a PST to work on. + Attempt to recover. */ + complain (&unclaimed_bincl_complaint, namestring, symnum); + continue; + } + add_bincl_to_list (pst, namestring, nlist.n_value); + + /* Mark down an include file in the current psymtab */ + + goto record_include_file; + } + + case N_SOL: + { + enum language tmp_language; + /* Mark down an include file in the current psymtab */ + + namestring = set_namestring (objfile, nlist); + tmp_language = deduce_language_from_filename (namestring); + + /* Only change the psymtab's language if we've learned + something useful (eg. tmp_language is not language_unknown). + In addition, to match what start_subfile does, never change + from C++ to C. */ + if (tmp_language != language_unknown + && (tmp_language != language_c + || psymtab_language != language_cplus)) + psymtab_language = tmp_language; + + /* In C++, one may expect the same filename to come round many + times, when code is coming alternately from the main file + and from inline functions in other files. So I check to see + if this is a file we've seen before -- either the main + source file, or a previously included file. + + This seems to be a lot of time to be spending on N_SOL, but + things like "break c-exp.y:435" need to work (I + suppose the psymtab_include_list could be hashed or put + in a binary tree, if profiling shows this is a major hog). */ + if (pst && STREQ (namestring, pst->filename)) + continue; + { + register int i; + for (i = 0; i < includes_used; i++) + if (STREQ (namestring, psymtab_include_list[i])) + { + i = -1; + break; + } + if (i == -1) + continue; + } + + record_include_file: + + psymtab_include_list[includes_used++] = namestring; + if (includes_used >= includes_allocated) + { + char **orig = psymtab_include_list; + + psymtab_include_list = (char **) + alloca ((includes_allocated *= 2) * + sizeof (char *)); + memcpy ((PTR) psymtab_include_list, (PTR) orig, + includes_used * sizeof (char *)); + } + continue; + } + case N_LSYM: /* Typedef or automatic variable. */ + case N_STSYM: /* Data seg var -- static */ + case N_LCSYM: /* BSS " */ + case N_ROSYM: /* Read-only data seg var -- static. */ + case N_NBSTS: /* Gould nobase. */ + case N_NBLCS: /* symbols. */ + case N_FUN: + case N_GSYM: /* Global (extern) variable; can be + data or bss (sigh FIXME). */ + + /* Following may probably be ignored; I'll leave them here + for now (until I do Pascal and Modula 2 extensions). */ + + case N_PC: /* I may or may not need this; I + suspect not. */ + case N_M2C: /* I suspect that I can ignore this here. */ + case N_SCOPE: /* Same. */ + + namestring = set_namestring (objfile, nlist); + + /* See if this is an end of function stab. */ + if (pst && nlist.n_type == N_FUN && *namestring == '\000') + { + CORE_ADDR valu; + + /* It's value is the size (in bytes) of the function for + function relative stabs, or the address of the function's + end for old style stabs. */ + valu = nlist.n_value + last_function_start; + if (TEXTHIGH (pst) == 0 || valu > TEXTHIGH (pst)) + TEXTHIGH (pst) = valu; + break; + } + + p = (char *) strchr (namestring, ':'); + if (!p) + continue; /* Not a debugging symbol. */ + + + + /* Main processing section for debugging symbols which + the initial read through the symbol tables needs to worry + about. If we reach this point, the symbol which we are + considering is definitely one we are interested in. + p must also contain the (valid) index into the namestring + which indicates the debugging type symbol. */ + + switch (p[1]) + { + case 'S': + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); +#ifdef STATIC_TRANSFORM_NAME + namestring = STATIC_TRANSFORM_NAME (namestring); +#endif + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + &objfile->static_psymbols, + 0, nlist.n_value, + psymtab_language, objfile); + continue; + case 'G': + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); + /* The addresses in these entries are reported to be + wrong. See the code that reads 'G's for symtabs. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + &objfile->global_psymbols, + 0, nlist.n_value, + psymtab_language, objfile); + continue; + + case 'T': + /* When a 'T' entry is defining an anonymous enum, it + may have a name which is the empty string, or a + single space. Since they're not really defining a + symbol, those shouldn't go in the partial symbol + table. We do pick up the elements of such enums at + 'check_enum:', below. */ + if (p >= namestring + 2 + || (p == namestring + 1 + && namestring[0] != ' ')) + { + add_psymbol_to_list (namestring, p - namestring, + STRUCT_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, + psymtab_language, objfile); + if (p[2] == 't') + { + /* Also a typedef with the same name. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, + psymtab_language, objfile); + p += 1; + } + /* The semantics of C++ state that "struct foo { ... }" + also defines a typedef for "foo". Unfortuantely, cfront + never makes the typedef when translating from C++ to C. + We make the typedef here so that "ptype foo" works as + expected for cfront translated code. */ + else if (psymtab_language == language_cplus) + { + /* Also a typedef with the same name. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, + psymtab_language, objfile); + } + } + goto check_enum; + case 't': + if (p != namestring) /* a name is there, not just :T... */ + { + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + nlist.n_value, 0, + psymtab_language, objfile); + } + check_enum: + /* If this is an enumerated type, we need to + add all the enum constants to the partial symbol + table. This does not cover enums without names, e.g. + "enum {a, b} c;" in C, but fortunately those are + rare. There is no way for GDB to find those from the + enum type without spending too much time on it. Thus + to solve this problem, the compiler needs to put out the + enum in a nameless type. GCC2 does this. */ + + /* We are looking for something of the form + <name> ":" ("t" | "T") [<number> "="] "e" + {<constant> ":" <value> ","} ";". */ + + /* Skip over the colon and the 't' or 'T'. */ + p += 2; + /* This type may be given a number. Also, numbers can come + in pairs like (0,26). Skip over it. */ + while ((*p >= '0' && *p <= '9') + || *p == '(' || *p == ',' || *p == ')' + || *p == '=') + p++; + + if (*p++ == 'e') + { + /* The aix4 compiler emits extra crud before the members. */ + if (*p == '-') + { + /* Skip over the type (?). */ + while (*p != ':') + p++; + + /* Skip over the colon. */ + p++; + } + + /* We have found an enumerated type. */ + /* According to comments in read_enum_type + a comma could end it instead of a semicolon. + I don't know where that happens. + Accept either. */ + while (*p && *p != ';' && *p != ',') + { + char *q; + + /* Check for and handle cretinous dbx symbol name + continuation! */ + if (*p == '\\' || (*p == '?' && p[1] == '\0')) + p = next_symbol_text (objfile); + + /* Point to the character after the name + of the enum constant. */ + for (q = p; *q && *q != ':'; q++) + ; + /* Note that the value doesn't matter for + enum constants in psymtabs, just in symtabs. */ + add_psymbol_to_list (p, q - p, + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, 0, + 0, psymtab_language, objfile); + /* Point past the name. */ + p = q; + /* Skip over the value. */ + while (*p && *p != ',') + p++; + /* Advance past the comma. */ + if (*p) + p++; + } + } + continue; + case 'c': + /* Constant, e.g. from "const" in Pascal. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, nlist.n_value, + 0, psymtab_language, objfile); + continue; + + case 'f': + if (! pst) + { + int name_len = p - namestring; + char *name = xmalloc (name_len + 1); + memcpy (name, namestring, name_len); + name[name_len] = '\0'; + complain (&function_outside_compilation_unit, name); + xfree (name); + } + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + /* Kludges for ELF/STABS with Sun ACC */ + last_function_name = namestring; +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Do not fix textlow==0 for .o or NLM files, as 0 is a legit + value for the bottom of the text seg in those cases. */ + if (nlist.n_value == ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile))) + { + CORE_ADDR minsym_valu = + find_stab_function_addr (namestring, pst->filename, objfile); + /* find_stab_function_addr will return 0 if the minimal + symbol wasn't found. (Unfortunately, this might also + be a valid address.) Anyway, if it *does* return 0, + it is likely that the value was set correctly to begin + with... */ + if (minsym_valu != 0) + nlist.n_value = minsym_valu; + } + if (pst && textlow_not_set) + { + TEXTLOW (pst) = nlist.n_value; + textlow_not_set = 0; + } +#endif + /* End kludge. */ + + /* Keep track of the start of the last function so we + can handle end of function symbols. */ + last_function_start = nlist.n_value; + + /* In reordered executables this function may lie outside + the bounds created by N_SO symbols. If that's the case + use the address of this function as the low bound for + the partial symbol table. */ + if (pst + && (textlow_not_set + || (nlist.n_value < TEXTLOW (pst) + && (nlist.n_value + != ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile)))))) + { + TEXTLOW (pst) = nlist.n_value; + textlow_not_set = 0; + } + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + &objfile->static_psymbols, + 0, nlist.n_value, + psymtab_language, objfile); + continue; + + /* Global functions were ignored here, but now they + are put into the global psymtab like one would expect. + They're also in the minimal symbol table. */ + case 'F': + if (! pst) + { + int name_len = p - namestring; + char *name = xmalloc (name_len + 1); + memcpy (name, namestring, name_len); + name[name_len] = '\0'; + complain (&function_outside_compilation_unit, name); + xfree (name); + } + nlist.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + /* Kludges for ELF/STABS with Sun ACC */ + last_function_name = namestring; +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Do not fix textlow==0 for .o or NLM files, as 0 is a legit + value for the bottom of the text seg in those cases. */ + if (nlist.n_value == ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile))) + { + CORE_ADDR minsym_valu = + find_stab_function_addr (namestring, pst->filename, objfile); + /* find_stab_function_addr will return 0 if the minimal + symbol wasn't found. (Unfortunately, this might also + be a valid address.) Anyway, if it *does* return 0, + it is likely that the value was set correctly to begin + with... */ + if (minsym_valu != 0) + nlist.n_value = minsym_valu; + } + if (pst && textlow_not_set) + { + TEXTLOW (pst) = nlist.n_value; + textlow_not_set = 0; + } +#endif + /* End kludge. */ + + /* Keep track of the start of the last function so we + can handle end of function symbols. */ + last_function_start = nlist.n_value; + + /* In reordered executables this function may lie outside + the bounds created by N_SO symbols. If that's the case + use the address of this function as the low bound for + the partial symbol table. */ + if (pst + && (textlow_not_set + || (nlist.n_value < TEXTLOW (pst) + && (nlist.n_value + != ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile)))))) + { + TEXTLOW (pst) = nlist.n_value; + textlow_not_set = 0; + } + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + &objfile->global_psymbols, + 0, nlist.n_value, + psymtab_language, objfile); + continue; + + /* Two things show up here (hopefully); static symbols of + local scope (static used inside braces) or extensions + of structure symbols. We can ignore both. */ + case 'V': + case '(': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + case '#': /* for symbol identification (used in live ranges) */ + /* added to support cfront stabs strings */ + case 'Z': /* for definition continuations */ + case 'P': /* for prototypes */ + continue; + + case ':': + /* It is a C++ nested symbol. We don't need to record it + (I don't think); if we try to look up foo::bar::baz, + then symbols for the symtab containing foo should get + read in, I think. */ + /* Someone says sun cc puts out symbols like + /foo/baz/maclib::/usr/local/bin/maclib, + which would get here with a symbol type of ':'. */ + continue; + + default: + /* Unexpected symbol descriptor. The second and subsequent stabs + of a continued stab can show up here. The question is + whether they ever can mimic a normal stab--it would be + nice if not, since we certainly don't want to spend the + time searching to the end of every string looking for + a backslash. */ + + complain (&unknown_symchar_complaint, p[1]); + + /* Ignore it; perhaps it is an extension that we don't + know about. */ + continue; + } + + case N_EXCL: + + namestring = set_namestring (objfile, nlist); + + /* Find the corresponding bincl and mark that psymtab on the + psymtab dependency list */ + { + struct partial_symtab *needed_pst = + find_corresponding_bincl_psymtab (namestring, nlist.n_value); + + /* If this include file was defined earlier in this file, + leave it alone. */ + if (needed_pst == pst) + continue; + + if (needed_pst) + { + int i; + int found = 0; + + for (i = 0; i < dependencies_used; i++) + if (dependency_list[i] == needed_pst) + { + found = 1; + break; + } + + /* If it's already in the list, skip the rest. */ + if (found) + continue; + + dependency_list[dependencies_used++] = needed_pst; + if (dependencies_used >= dependencies_allocated) + { + struct partial_symtab **orig = dependency_list; + dependency_list = + (struct partial_symtab **) + alloca ((dependencies_allocated *= 2) + * sizeof (struct partial_symtab *)); + memcpy ((PTR) dependency_list, (PTR) orig, + (dependencies_used + * sizeof (struct partial_symtab *))); +#ifdef DEBUG_INFO + fprintf_unfiltered (gdb_stderr, "Had to reallocate dependency list.\n"); + fprintf_unfiltered (gdb_stderr, "New dependencies allocated: %d\n", + dependencies_allocated); +#endif + } + } + } + continue; + + case N_ENDM: +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Solaris 2 end of module, finish current partial symbol table. + end_psymtab will set TEXTHIGH (pst) to the proper value, which + is necessary if a module compiled without debugging info + follows this module. */ + if (pst) + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + (CORE_ADDR) 0, + dependency_list, dependencies_used, textlow_not_set); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } +#endif + continue; + + case N_RBRAC: +#ifdef HANDLE_RBRAC + HANDLE_RBRAC (nlist.n_value); + continue; +#endif + case N_EINCL: + case N_DSLINE: + case N_BSLINE: + case N_SSYM: /* Claim: Structure or union element. + Hopefully, I can ignore this. */ + case N_ENTRY: /* Alternate entry point; can ignore. */ + case N_MAIN: /* Can definitely ignore this. */ + case N_CATCH: /* These are GNU C++ extensions */ + case N_EHDECL: /* that can safely be ignored here. */ + case N_LENG: + case N_BCOMM: + case N_ECOMM: + case N_ECOML: + case N_FNAME: + case N_SLINE: + case N_RSYM: + case N_PSYM: + case N_LBRAC: + case N_NSYMS: /* Ultrix 4.0: symbol count */ + case N_DEFD: /* GNU Modula-2 */ + case N_ALIAS: /* SunPro F77: alias name, ignore for now. */ + + case N_OBJ: /* useless types from Solaris */ + case N_OPT: + /* These symbols aren't interesting; don't worry about them */ + + continue; -/*FIXME: Too many adds and indirections in here for the inner loop. */ -#define SET_NAMESTRING()\ - if (((unsigned)CUR_SYMBOL_STRX + file_string_table_offset) >= \ - DBX_STRINGTAB_SIZE (objfile)) { \ - complain (&string_table_offset_complaint, symnum); \ - namestring = "<bad string table offset>"; \ - } else \ - namestring = CUR_SYMBOL_STRX + file_string_table_offset + \ - DBX_STRINGTAB (objfile) - -#define CUR_SYMBOL_TYPE nlist.n_type -#define CUR_SYMBOL_VALUE nlist.n_value -#define CUR_SYMBOL_STRX nlist.n_strx -#define DBXREAD_ONLY -#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\ - start_psymtab(ofile, secoff, fname, low, symoff, global_syms, static_syms) -#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps,textlow_not_set)\ - end_psymtab(pst,ilist,ninc,c_off,c_text,dep_list,n_deps,textlow_not_set) - -#include "partial-stab.h" + default: + /* If we haven't found it yet, ignore it. It's probably some + new type we don't know about yet. */ + complain (&unknown_symtype_complaint, + local_hex_string (nlist.n_type)); + continue; + } } /* If there's stuff to be cleaned up, clean it up. */ - if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */ -/*FIXME, does this have a bug at start address 0? */ + if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */ + /*FIXME, does this have a bug at start address 0? */ && last_o_file_start - && objfile -> ei.entry_point < nlist.n_value - && objfile -> ei.entry_point >= last_o_file_start) + && objfile->ei.entry_point < nlist.n_value + && objfile->ei.entry_point >= last_o_file_start) { - objfile -> ei.entry_file_lowpc = last_o_file_start; - objfile -> ei.entry_file_highpc = nlist.n_value; + objfile->ei.entry_file_lowpc = last_o_file_start; + objfile->ei.entry_file_highpc = nlist.n_value; } if (pst) { /* Don't set pst->texthigh lower than it already is. */ CORE_ADDR text_end = - (lowest_text_address == (CORE_ADDR)-1 - ? (text_addr + section_offsets->offsets[SECT_OFF_TEXT]) + (lowest_text_address == (CORE_ADDR) -1 + ? (text_addr + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile))) : lowest_text_address) + text_size; end_psymtab (pst, psymtab_include_list, includes_used, symnum * symbol_size, - text_end > pst->texthigh ? text_end : pst->texthigh, + text_end > TEXTHIGH (pst) ? text_end : TEXTHIGH (pst), dependency_list, dependencies_used, textlow_not_set); } @@ -1360,29 +2178,25 @@ read_dbx_symtab (section_offsets, objfile, text_addr, text_size) (normal). */ -struct partial_symtab * -start_psymtab (objfile, section_offsets, - filename, textlow, ldsymoff, global_syms, static_syms) - struct objfile *objfile; - struct section_offsets *section_offsets; - char *filename; - CORE_ADDR textlow; - int ldsymoff; - struct partial_symbol **global_syms; - struct partial_symbol **static_syms; +static struct partial_symtab * +start_psymtab (struct objfile *objfile, char *filename, CORE_ADDR textlow, + int ldsymoff, struct partial_symbol **global_syms, + struct partial_symbol **static_syms) { struct partial_symtab *result = - start_psymtab_common(objfile, section_offsets, - filename, textlow, global_syms, static_syms); + start_psymtab_common (objfile, objfile->section_offsets, + filename, textlow, global_syms, static_syms); result->read_symtab_private = (char *) - obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc)); - LDSYMOFF(result) = ldsymoff; + obstack_alloc (&objfile->psymbol_obstack, sizeof (struct symloc)); + TEXTLOW (result) = result->textlow; + TEXTHIGH (result) = result->texthigh; + LDSYMOFF (result) = ldsymoff; result->read_symtab = dbx_psymtab_to_symtab; - SYMBOL_SIZE(result) = symbol_size; - SYMBOL_OFFSET(result) = symbol_table_offset; - STRING_OFFSET(result) = string_table_offset; - FILE_STRING_OFFSET(result) = file_string_table_offset; + SYMBOL_SIZE (result) = symbol_size; + SYMBOL_OFFSET (result) = symbol_table_offset; + STRING_OFFSET (result) = string_table_offset; + FILE_STRING_OFFSET (result) = file_string_table_offset; /* If we're handling an ELF file, drag some section-relocation info for this source file out of the ELF symbol table, to compensate for @@ -1402,41 +2216,35 @@ start_psymtab (objfile, section_offsets, FIXME: List variables and peculiarities of same. */ struct partial_symtab * -end_psymtab (pst, include_list, num_includes, capping_symbol_offset, - capping_text, dependency_list, number_dependencies, textlow_not_set) - struct partial_symtab *pst; - char **include_list; - int num_includes; - int capping_symbol_offset; - CORE_ADDR capping_text; - struct partial_symtab **dependency_list; - int number_dependencies; - int textlow_not_set; +end_psymtab (struct partial_symtab *pst, char **include_list, int num_includes, + int capping_symbol_offset, CORE_ADDR capping_text, + struct partial_symtab **dependency_list, int number_dependencies, + int textlow_not_set) { int i; - struct objfile *objfile = pst -> objfile; + struct objfile *objfile = pst->objfile; if (capping_symbol_offset != -1) - LDSYMLEN(pst) = capping_symbol_offset - LDSYMOFF(pst); - pst->texthigh = capping_text; + LDSYMLEN (pst) = capping_symbol_offset - LDSYMOFF (pst); + TEXTHIGH (pst) = capping_text; #ifdef SOFUN_ADDRESS_MAYBE_MISSING /* Under Solaris, the N_SO symbols always have a value of 0, instead of the usual address of the .o file. Therefore, we have to do some tricks to fill in texthigh and textlow. - The first trick is in partial-stab.h: if we see a static + The first trick is: if we see a static or global function, and the textlow for the current pst is not set (ie: textlow_not_set), then we use that function's address for the textlow of the pst. */ /* Now, to fill in texthigh, we remember the last function seen - in the .o file (also in partial-stab.h). Also, there's a hack in + in the .o file. Also, there's a hack in bfd/elf.c and gdb/elfread.c to pass the ELF st_size field to here via the misc_info field. Therefore, we can fill in a reliable texthigh by taking the address plus size of the last function in the file. */ - if (pst->texthigh == 0 && last_function_name) + if (TEXTHIGH (pst) == 0 && last_function_name) { char *p; int n; @@ -1449,7 +2257,7 @@ end_psymtab (pst, include_list, num_includes, capping_symbol_offset, p = alloca (n + 2); strncpy (p, last_function_name, n); p[n] = 0; - + minsym = lookup_minimal_symbol (p, pst->filename, objfile); if (minsym == NULL) { @@ -1462,34 +2270,34 @@ end_psymtab (pst, include_list, num_includes, capping_symbol_offset, } if (minsym) - pst->texthigh = SYMBOL_VALUE_ADDRESS (minsym) + MSYMBOL_SIZE (minsym); + TEXTHIGH (pst) = SYMBOL_VALUE_ADDRESS (minsym) + MSYMBOL_SIZE (minsym); last_function_name = NULL; } /* this test will be true if the last .o file is only data */ if (textlow_not_set) - pst->textlow = pst->texthigh; + TEXTLOW (pst) = TEXTHIGH (pst); else { struct partial_symtab *p1; /* If we know our own starting text address, then walk through all other - psymtabs for this objfile, and if any didn't know their ending text - address, set it to our starting address. Take care to not set our - own ending address to our starting address, nor to set addresses on - `dependency' files that have both textlow and texthigh zero. */ + psymtabs for this objfile, and if any didn't know their ending text + address, set it to our starting address. Take care to not set our + own ending address to our starting address, nor to set addresses on + `dependency' files that have both textlow and texthigh zero. */ ALL_OBJFILE_PSYMTABS (objfile, p1) - { - if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) - { - p1->texthigh = pst->textlow; - /* if this file has only data, then make textlow match texthigh */ - if (p1->textlow == 0) - p1->textlow = p1->texthigh; - } - } + { + if (TEXTHIGH (p1) == 0 && TEXTLOW (p1) != 0 && p1 != pst) + { + TEXTHIGH (p1) = TEXTLOW (pst); + /* if this file has only data, then make textlow match texthigh */ + if (TEXTLOW (p1) == 0) + TEXTLOW (p1) = TEXTHIGH (p1); + } + } } /* End of kludge for patching Solaris textlow and texthigh. */ @@ -1505,9 +2313,9 @@ end_psymtab (pst, include_list, num_includes, capping_symbol_offset, { pst->dependencies = (struct partial_symtab **) obstack_alloc (&objfile->psymbol_obstack, - number_dependencies * sizeof (struct partial_symtab *)); + number_dependencies * sizeof (struct partial_symtab *)); memcpy (pst->dependencies, dependency_list, - number_dependencies * sizeof (struct partial_symtab *)); + number_dependencies * sizeof (struct partial_symtab *)); } else pst->dependencies = 0; @@ -1515,19 +2323,20 @@ end_psymtab (pst, include_list, num_includes, capping_symbol_offset, for (i = 0; i < num_includes; i++) { struct partial_symtab *subpst = - allocate_psymtab (include_list[i], objfile); + allocate_psymtab (include_list[i], objfile); + /* Copy the sesction_offsets array from the main psymtab. */ subpst->section_offsets = pst->section_offsets; subpst->read_symtab_private = - (char *) obstack_alloc (&objfile->psymbol_obstack, - sizeof (struct symloc)); - LDSYMOFF(subpst) = - LDSYMLEN(subpst) = - subpst->textlow = - subpst->texthigh = 0; + (char *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc)); + LDSYMOFF (subpst) = + LDSYMLEN (subpst) = + TEXTLOW (subpst) = + TEXTHIGH (subpst) = 0; /* We could save slight bits of space by only making one of these, - shared by the entire set of include files. FIXME-someday. */ + shared by the entire set of include files. FIXME-someday. */ subpst->dependencies = (struct partial_symtab **) obstack_alloc (&objfile->psymbol_obstack, sizeof (struct partial_symtab *)); @@ -1536,8 +2345,8 @@ end_psymtab (pst, include_list, num_includes, capping_symbol_offset, subpst->globals_offset = subpst->n_global_syms = - subpst->statics_offset = - subpst->n_static_syms = 0; + subpst->statics_offset = + subpst->n_static_syms = 0; subpst->readin = 0; subpst->symtab = 0; @@ -1558,35 +2367,34 @@ end_psymtab (pst, include_list, num_includes, capping_symbol_offset, && has_line_numbers == 0) { /* Throw away this psymtab, it's empty. We can't deallocate it, since - it is on the obstack, but we can forget to chain it on the list. */ + it is on the obstack, but we can forget to chain it on the list. */ /* Empty psymtabs happen as a result of header files which don't have - any symbols in them. There can be a lot of them. But this check - is wrong, in that a psymtab with N_SLINE entries but nothing else - is not empty, but we don't realize that. Fixing that without slowing - things down might be tricky. */ + any symbols in them. There can be a lot of them. But this check + is wrong, in that a psymtab with N_SLINE entries but nothing else + is not empty, but we don't realize that. Fixing that without slowing + things down might be tricky. */ discard_psymtab (pst); /* Indicate that psymtab was thrown away. */ - pst = (struct partial_symtab *)NULL; + pst = (struct partial_symtab *) NULL; } return pst; } static void -dbx_psymtab_to_symtab_1 (pst) - struct partial_symtab *pst; +dbx_psymtab_to_symtab_1 (struct partial_symtab *pst) { struct cleanup *old_chain; int i; - + if (!pst) return; if (pst->readin) { fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", - pst->filename); + pst->filename); return; } @@ -1602,18 +2410,18 @@ dbx_psymtab_to_symtab_1 (pst) fputs_filtered ("and ", gdb_stdout); wrap_here (""); printf_filtered ("%s...", pst->dependencies[i]->filename); - wrap_here (""); /* Flush output */ + wrap_here (""); /* Flush output */ gdb_flush (gdb_stdout); } dbx_psymtab_to_symtab_1 (pst->dependencies[i]); } - if (LDSYMLEN(pst)) /* Otherwise it's a dummy */ + if (LDSYMLEN (pst)) /* Otherwise it's a dummy */ { /* Init stuff necessary for reading in symbols */ stabsread_init (); buildsym_init (); - old_chain = make_cleanup ((make_cleanup_func) really_free_pendings, 0); + old_chain = make_cleanup (really_free_pendings, 0); file_string_table_offset = FILE_STRING_OFFSET (pst); symbol_size = SYMBOL_SIZE (pst); @@ -1632,8 +2440,7 @@ dbx_psymtab_to_symtab_1 (pst) Be verbose about it if the user wants that. */ static void -dbx_psymtab_to_symtab (pst) - struct partial_symtab *pst; +dbx_psymtab_to_symtab (struct partial_symtab *pst) { bfd *sym_bfd; @@ -1643,14 +2450,14 @@ dbx_psymtab_to_symtab (pst) if (pst->readin) { fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", - pst->filename); + pst->filename); return; } - if (LDSYMLEN(pst) || pst->number_of_dependencies) + if (LDSYMLEN (pst) || pst->number_of_dependencies) { /* Print the message now, before reading the string table, - to avoid disconcerting pauses. */ + to avoid disconcerting pauses. */ if (info_verbose) { printf_filtered ("Reading in symbols for %s...", pst->filename); @@ -1674,10 +2481,9 @@ dbx_psymtab_to_symtab (pst) } /* Read in a defined section of a specific object file's symbols. */ - + static void -read_ofile_symtab (pst) - struct partial_symtab *pst; +read_ofile_symtab (struct partial_symtab *pst) { register char *namestring; register struct external_nlist *bufp; @@ -1693,10 +2499,14 @@ read_ofile_symtab (pst) struct section_offsets *section_offsets; objfile = pst->objfile; - sym_offset = LDSYMOFF(pst); - sym_size = LDSYMLEN(pst); - text_offset = pst->textlow; - text_size = pst->texthigh - pst->textlow; + sym_offset = LDSYMOFF (pst); + sym_size = LDSYMLEN (pst); + text_offset = TEXTLOW (pst); + text_size = TEXTHIGH (pst) - TEXTLOW (pst); + /* This cannot be simply objfile->section_offsets because of + elfstab_offset_sections() which initializes the psymtab section + offsets information in a special way, and that is different from + objfile->section_offsets. */ section_offsets = pst->section_offsets; current_objfile = objfile; @@ -1715,7 +2525,7 @@ read_ofile_symtab (pst) Detecting this in read_dbx_symtab would slow down initial readin, so we look for it here instead. */ - if (!processing_acc_compilation && sym_offset >= (int)symbol_size) + if (!processing_acc_compilation && sym_offset >= (int) symbol_size) { bfd_seek (symfile_bfd, sym_offset - symbol_size, SEEK_CUR); fill_symbuf (abfd); @@ -1723,7 +2533,7 @@ read_ofile_symtab (pst) INTERNALIZE_SYMBOL (nlist, bufp, abfd); OBJSTAT (objfile, n_stabs++); - SET_NAMESTRING (); + namestring = set_namestring (objfile, nlist); processing_gcc_compilation = 0; if (nlist.n_type == N_TEXT) @@ -1741,8 +2551,11 @@ read_ofile_symtab (pst) } /* Try to select a C++ demangling based on the compilation unit - producer. */ + producer. */ +#if 0 + /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't + know whether it will use the old style or v3 mangling. */ if (processing_gcc_compilation) { if (AUTO_DEMANGLING) @@ -1750,12 +2563,13 @@ read_ofile_symtab (pst) set_demangling_style (GNU_DEMANGLING_STYLE_STRING); } } +#endif } else { /* The N_SO starting this symtab is the first symbol, so we - better not check the symbol before it. I'm not this can - happen, but it doesn't hurt to check for it. */ + better not check the symbol before it. I'm not this can + happen, but it doesn't hurt to check for it. */ bfd_seek (symfile_bfd, sym_offset, SEEK_CUR); processing_gcc_compilation = 0; } @@ -1764,7 +2578,7 @@ read_ofile_symtab (pst) fill_symbuf (abfd); bufp = &symbuf[symbuf_idx]; if (bfd_h_get_8 (abfd, bufp->e_type) != N_SO) - error("First symbol in segment of executable not a source symbol"); + error ("First symbol in segment of executable not a source symbol"); max_symnum = sym_size / symbol_size; @@ -1774,19 +2588,20 @@ read_ofile_symtab (pst) { QUIT; /* Allow this to be interruptable */ if (symbuf_idx == symbuf_end) - fill_symbuf(abfd); + fill_symbuf (abfd); bufp = &symbuf[symbuf_idx++]; INTERNALIZE_SYMBOL (nlist, bufp, abfd); OBJSTAT (objfile, n_stabs++); type = bfd_h_get_8 (abfd, bufp->e_type); - SET_NAMESTRING (); + namestring = set_namestring (objfile, nlist); - if (type & N_STAB) { + if (type & N_STAB) + { process_one_symbol (type, nlist.n_desc, nlist.n_value, namestring, section_offsets, objfile); - } + } /* We skip checking for a new .o or -l file; that should never happen in this routine. */ else if (type == N_TEXT) @@ -1802,14 +2617,19 @@ read_ofile_symtab (pst) else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) processing_gcc_compilation = 2; +#if 0 + /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't + know whether it will use the old style or v3 mangling. */ if (AUTO_DEMANGLING) { set_demangling_style (GNU_DEMANGLING_STYLE_STRING); } +#endif } - else if (type & N_EXT || type == (unsigned char)N_TEXT - || type == (unsigned char)N_NBTEXT - ) { + else if (type & N_EXT || type == (unsigned char) N_TEXT + || type == (unsigned char) N_NBTEXT + ) + { /* Global symbol: see if we came across a dbx defintion for a corresponding symbol. If so, store the value. Remove syms from the chain when their values are stored, but @@ -1820,33 +2640,33 @@ read_ofile_symtab (pst) be satisfied in each file as it appears. So we skip this section. */ ; - } + } } current_objfile = NULL; /* In a Solaris elf file, this variable, which comes from the value of the N_SO symbol, will still be 0. Luckily, text_offset, - which comes from pst->textlow is correct. */ + which comes from TEXTLOW (pst) is correct. */ if (last_source_start_addr == 0) last_source_start_addr = text_offset; /* In reordered executables last_source_start_addr may not be the lower bound for this symtab, instead use text_offset which comes - from pst->textlow which is correct. */ + from TEXTLOW (pst) which is correct. */ if (last_source_start_addr > text_offset) last_source_start_addr = text_offset; - pst->symtab = end_symtab (text_offset + text_size, objfile, SECT_OFF_TEXT); + pst->symtab = end_symtab (text_offset + text_size, objfile, SECT_OFF_TEXT (objfile)); - /* Process items which we had to "process_later" due to dependancies + /* Process items which we had to "process_later" due to dependencies on other stabs. */ - process_now (objfile); + process_now (objfile); end_stabs (); } - + /* This handles a single symbol from the symbol-file, building symbols into a GDB symtab. It takes these arguments and an implicit argument. @@ -1855,19 +2675,18 @@ read_ofile_symtab (pst) VALU is the value field of the ".stab" entry. NAME is the symbol name, in our address space. SECTION_OFFSETS is a set of amounts by which the sections of this object - file were relocated when it was loaded into memory. - All symbols that refer - to memory locations need to be offset by these amounts. + file were relocated when it was loaded into memory. + Note that these section_offsets are not the + objfile->section_offsets but the pst->section_offsets. + All symbols that refer + to memory locations need to be offset by these amounts. OBJFILE is the object file from which we are reading symbols. - It is used in end_symtab. */ + It is used in end_symtab. */ void -process_one_symbol (type, desc, valu, name, section_offsets, objfile) - int type, desc; - CORE_ADDR valu; - char *name; - struct section_offsets *section_offsets; - struct objfile *objfile; +process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, + struct section_offsets *section_offsets, + struct objfile *objfile) { #ifdef SUN_FIXED_LBRAC_BUG /* If SUN_FIXED_LBRAC_BUG is defined, then it tells us whether we need @@ -1888,6 +2707,15 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) used to relocate these symbol types rather than SECTION_OFFSETS. */ static CORE_ADDR function_start_offset; + /* This holds the address of the start of a function, without the system + peculiarities of function_start_offset. */ + static CORE_ADDR last_function_start; + + /* If this is nonzero, we've seen an N_SLINE since the start of the current + function. Initialized to nonzero to assure that last_function_start + is never used uninitialized. */ + static int sline_found_in_function = 1; + /* If this is nonzero, we've seen a non-gcc N_OPT symbol for this source file. Used to detect the SunPRO solaris compiler. */ static int n_opt_found; @@ -1899,17 +2727,17 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) if (!block_address_function_relative) /* N_LBRAC, N_RBRAC and N_SLINE entries are not relative to the function start address, so just use the text offset. */ - function_start_offset = ANOFFSET (section_offsets, SECT_OFF_TEXT); + function_start_offset = ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); /* Something is wrong if we see real data before seeing a source file name. */ - if (last_source_file == NULL && type != (unsigned char)N_SO) + if (last_source_file == NULL && type != (unsigned char) N_SO) { /* Ignore any symbols which appear before an N_SO symbol. - Currently no one puts symbols there, but we should deal - gracefully with the case. A complain()t might be in order, - but this should not be an error (). */ + Currently no one puts symbols there, but we should deal + gracefully with the case. A complain()t might be in order, + but this should not be an error (). */ return; } @@ -1922,6 +2750,7 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) { /* This N_FUN marks the end of a function. This closes off the current block. */ + record_line (current_subfile, 0, function_start_offset + valu); within_function = 0; new = pop_context (); @@ -1938,16 +2767,18 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) break; } + sline_found_in_function = 0; + /* Relocate for dynamic loading */ - valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); -#ifdef SMASH_TEXT_ADDRESS - SMASH_TEXT_ADDRESS (valu); -#endif + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); + valu = SMASH_TEXT_ADDRESS (valu); + last_function_start = valu; + goto define_a_symbol; case N_LBRAC: /* This "symbol" just indicates the start of an inner lexical - context within a function. */ + context within a function. */ /* Ignore extra outermost context from SunPRO cc and acc. */ if (n_opt_found && desc == 1) @@ -1962,18 +2793,19 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) valu += last_source_start_addr; #ifdef SUN_FIXED_LBRAC_BUG - if (!SUN_FIXED_LBRAC_BUG && valu < last_pc_address) { - /* Patch current LBRAC pc value to match last handy pc value */ - complain (&lbrac_complaint); - valu = last_pc_address; - } + if (!SUN_FIXED_LBRAC_BUG && valu < last_pc_address) + { + /* Patch current LBRAC pc value to match last handy pc value */ + complain (&lbrac_complaint); + valu = last_pc_address; + } #endif new = push_context (desc, valu); break; case N_RBRAC: /* This "symbol" just indicates the end of an inner lexical - context that was started with N_LBRAC. */ + context that was started with N_LBRAC. */ /* Ignore extra outermost context from SunPRO cc and acc. */ if (n_opt_found && desc == 1) @@ -1987,26 +2819,26 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) N_SO, the linker did not relocate them (sigh). */ valu += last_source_start_addr; - new = pop_context(); + new = pop_context (); if (desc != new->depth) complain (&lbrac_mismatch_complaint, symnum); /* Some compilers put the variable decls inside of an LBRAC/RBRAC block. This macro should be nonzero if this - is true. DESC is N_DESC from the N_RBRAC symbol. - GCC_P is true if we've detected the GCC_COMPILED_SYMBOL - or the GCC2_COMPILED_SYMBOL. */ + is true. DESC is N_DESC from the N_RBRAC symbol. + GCC_P is true if we've detected the GCC_COMPILED_SYMBOL + or the GCC2_COMPILED_SYMBOL. */ #if !defined (VARIABLES_INSIDE_BLOCK) #define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 0 #endif /* Can only use new->locals as local symbols here if we're in gcc or on a machine that puts them before the lbrack. */ - if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + if (!VARIABLES_INSIDE_BLOCK (desc, processing_gcc_compilation)) local_symbols = new->locals; if (context_stack_depth - > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + > !VARIABLES_INSIDE_BLOCK (desc, processing_gcc_compilation)) { /* This is not the outermost LBRAC...RBRAC pair in the function, its local symbols preceded it, and are the ones just recovered @@ -2017,7 +2849,7 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) if (local_symbols != NULL) { /* Muzzle a compiler bug that makes end < start. (which - compilers? Is this ever harmful?). */ + compilers? Is this ever harmful?). */ if (new->start_addr > valu) { complain (&lbrac_rbrac_complaint); @@ -2037,7 +2869,7 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) within_function = 0; } - if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + if (VARIABLES_INSIDE_BLOCK (desc, processing_gcc_compilation)) /* Now pop locals of block just finished. */ local_symbols = new->locals; break; @@ -2046,16 +2878,16 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) case N_FN_SEQ: /* This kind of symbol indicates the start of an object file. */ /* Relocate for dynamic loading */ - valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); break; case N_SO: /* This type of symbol indicates the start of data - for one source file. - Finish the symbol table of the previous source file - (if any) and start accumulating a new symbol table. */ + for one source file. + Finish the symbol table of the previous source file + (if any) and start accumulating a new symbol table. */ /* Relocate for dynamic loading */ - valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); n_opt_found = 0; @@ -2076,23 +2908,23 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) /* Check if previous symbol was also an N_SO (with some sanity checks). If so, that one was actually the directory name, and the current one is the real file name. - Patch things up. */ + Patch things up. */ if (previous_stab_code == (unsigned char) N_SO) { patch_subfile_names (current_subfile, name); break; /* Ignore repeated SOs */ } - end_symtab (valu, objfile, SECT_OFF_TEXT); + end_symtab (valu, objfile, SECT_OFF_TEXT (objfile)); end_stabs (); } /* Null name means this just marks the end of text for this .o file. - Don't start a new symtab in this case. */ + Don't start a new symtab in this case. */ if (*name == '\000') break; if (block_address_function_relative) - function_start_offset = 0; + function_start_offset = 0; start_stabs (); start_symtab (name, NULL, valu); @@ -2101,11 +2933,11 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) case N_SOL: /* This type of symbol indicates the start of data for - a sub-source-file, one whose contents were copied or - included in the compilation of the main source file - (whose name was given in the N_SO symbol.) */ + a sub-source-file, one whose contents were copied or + included in the compilation of the main source file + (whose name was given in the N_SO symbol.) */ /* Relocate for dynamic loading */ - valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); start_subfile (name, current_subfile->dirname); break; @@ -2125,8 +2957,8 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) case N_SLINE: /* This type of "symbol" really just records - one line-number -- core-address correspondence. - Enter it in the line list for this symbol table. */ + one line-number -- core-address correspondence. + Enter it in the line list for this symbol table. */ /* Relocate for dynamic loading and for ELF acc fn-relative syms. */ valu += function_start_offset; @@ -2134,7 +2966,15 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) #ifdef SUN_FIXED_LBRAC_BUG last_pc_address = valu; /* Save for SunOS bug circumcision */ #endif - record_line (current_subfile, desc, valu); + /* If this is the first SLINE note in the function, record it at + the start of the function instead of at the listed location. */ + if (within_function && sline_found_in_function == 0) + { + record_line (current_subfile, desc, last_function_start); + sline_found_in_function = 1; + } + else + record_line (current_subfile, desc, valu); break; case N_BCOMM: @@ -2145,21 +2985,21 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) common_block_end (objfile); break; - /* The following symbol types need to have the appropriate offset added - to their value; then we process symbol definitions in the name. */ + /* The following symbol types need to have the appropriate offset added + to their value; then we process symbol definitions in the name. */ case N_STSYM: /* Static symbol in data seg */ case N_LCSYM: /* Static symbol in BSS seg */ case N_ROSYM: /* Static symbol in Read-only data seg */ - /* HORRID HACK DEPT. However, it's Sun's furgin' fault. - Solaris2's stabs-in-elf makes *most* symbols relative - but leaves a few absolute (at least for Solaris 2.1 and version - 2.0.1 of the SunPRO compiler). N_STSYM and friends sit on the fence. - .stab "foo:S...",N_STSYM is absolute (ld relocates it) - .stab "foo:V...",N_STSYM is relative (section base subtracted). - This leaves us no choice but to search for the 'S' or 'V'... - (or pass the whole section_offsets stuff down ONE MORE function - call level, which we really don't want to do). */ + /* HORRID HACK DEPT. However, it's Sun's furgin' fault. + Solaris2's stabs-in-elf makes *most* symbols relative + but leaves a few absolute (at least for Solaris 2.1 and version + 2.0.1 of the SunPRO compiler). N_STSYM and friends sit on the fence. + .stab "foo:S...",N_STSYM is absolute (ld relocates it) + .stab "foo:V...",N_STSYM is relative (section base subtracted). + This leaves us no choice but to search for the 'S' or 'V'... + (or pass the whole section_offsets stuff down ONE MORE function + call level, which we really don't want to do). */ { char *p; @@ -2183,47 +3023,52 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) elfstab_offset_sections ever starts dealing with the text offset, and we still need to do this, we need to invent a SECT_OFF_ADDR_KLUDGE or something. */ - valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); goto define_a_symbol; } } /* Since it's not the kludge case, re-dispatch to the right handler. */ - switch (type) { - case N_STSYM: goto case_N_STSYM; - case N_LCSYM: goto case_N_LCSYM; - case N_ROSYM: goto case_N_ROSYM; - default: abort(); - } + switch (type) + { + case N_STSYM: + goto case_N_STSYM; + case N_LCSYM: + goto case_N_LCSYM; + case N_ROSYM: + goto case_N_ROSYM; + default: + internal_error (__FILE__, __LINE__, "failed internal consistency check"); + } } case_N_STSYM: /* Static symbol in data seg */ case N_DSLINE: /* Source line number, data seg */ - valu += ANOFFSET (section_offsets, SECT_OFF_DATA); + valu += ANOFFSET (section_offsets, SECT_OFF_DATA (objfile)); goto define_a_symbol; case_N_LCSYM: /* Static symbol in BSS seg */ case N_BSLINE: /* Source line number, bss seg */ - /* N_BROWS: overlaps with N_BSLINE */ - valu += ANOFFSET (section_offsets, SECT_OFF_BSS); + /* N_BROWS: overlaps with N_BSLINE */ + valu += ANOFFSET (section_offsets, SECT_OFF_BSS (objfile)); goto define_a_symbol; case_N_ROSYM: /* Static symbol in Read-only data seg */ - valu += ANOFFSET (section_offsets, SECT_OFF_RODATA); + valu += ANOFFSET (section_offsets, SECT_OFF_RODATA (objfile)); goto define_a_symbol; case N_ENTRY: /* Alternate entry point */ /* Relocate for dynamic loading */ - valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)); goto define_a_symbol; - /* The following symbol types we don't know how to process. Handle - them in a "default" way, but complain to people who care. */ + /* The following symbol types we don't know how to process. Handle + them in a "default" way, but complain to people who care. */ default: case N_CATCH: /* Exception handler catcher */ case N_EHDECL: /* Exception handler name */ case N_PC: /* Global symbol in Pascal */ - case N_M2C: /* Modula-2 compilation unit */ - /* N_MOD2: overlaps with N_EHDECL */ + case N_M2C: /* Modula-2 compilation unit */ + /* N_MOD2: overlaps with N_EHDECL */ case N_SCOPE: /* Modula-2 scope information */ case N_ECOML: /* End common (local name) */ case N_NBTEXT: /* Gould Non-Base-Register symbols??? */ @@ -2234,8 +3079,8 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) complain (&unknown_symtype_complaint, local_hex_string (type)); /* FALLTHROUGH */ - /* The following symbol types don't need the address field relocated, - since it is either unused, or is absolute. */ + /* The following symbol types don't need the address field relocated, + since it is either unused, or is absolute. */ define_a_symbol: case N_GSYM: /* Global variable */ case N_NSYMS: /* Number of symbols (ultrix) */ @@ -2263,63 +3108,47 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) #ifdef SOFUN_ADDRESS_MAYBE_MISSING /* Deal with the SunPRO 3.0 compiler which omits the address - from N_FUN symbols. */ + from N_FUN symbols. */ if (type == N_FUN - && valu == ANOFFSET (section_offsets, SECT_OFF_TEXT)) + && valu == ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile))) { - struct minimal_symbol *msym; - char *p; - int n; - - p = strchr (name, ':'); - if (p == NULL) - p = name; - n = p - name; - p = alloca (n + 2); - strncpy (p, name, n); - p[n] = 0; - - msym = lookup_minimal_symbol (p, last_source_file, - objfile); - if (msym == NULL) - { - /* Sun Fortran appends an underscore to the minimal - symbol name, try again with an appended underscore - if the minimal symbol was not found. */ - p[n] = '_'; - p[n + 1] = 0; - msym = lookup_minimal_symbol (p, last_source_file, - objfile); - } - if (msym) - valu = SYMBOL_VALUE_ADDRESS (msym); + CORE_ADDR minsym_valu = + find_stab_function_addr (name, last_source_file, objfile); + + /* find_stab_function_addr will return 0 if the minimal + symbol wasn't found. (Unfortunately, this might also + be a valid address.) Anyway, if it *does* return 0, + it is likely that the value was set correctly to begin + with... */ + if (minsym_valu != 0) + valu = minsym_valu; } #endif #ifdef SUN_FIXED_LBRAC_BUG /* The Sun acc compiler, under SunOS4, puts out - functions with N_GSYM or N_STSYM. The problem is - that the address of the symbol is no good (for N_GSYM - it doesn't even attept an address; for N_STSYM it - puts out an address but then it gets relocated - relative to the data segment, not the text segment). - Currently we can't fix this up later as we do for - some types of symbol in scan_file_globals. - Fortunately we do have a way of finding the address - - we know that the value in last_pc_address is either - the one we want (if we're dealing with the first - function in an object file), or somewhere in the - previous function. This means that we can use the - minimal symbol table to get the address. */ + functions with N_GSYM or N_STSYM. The problem is + that the address of the symbol is no good (for N_GSYM + it doesn't even attept an address; for N_STSYM it + puts out an address but then it gets relocated + relative to the data segment, not the text segment). + Currently we can't fix this up later as we do for + some types of symbol in scan_file_globals. + Fortunately we do have a way of finding the address - + we know that the value in last_pc_address is either + the one we want (if we're dealing with the first + function in an object file), or somewhere in the + previous function. This means that we can use the + minimal symbol table to get the address. */ /* Starting with release 3.0, the Sun acc compiler, - under SunOS4, puts out functions with N_FUN and a value - of zero. This gets relocated to the start of the text - segment of the module, which is no good either. - Under SunOS4 we can deal with this as N_SLINE and N_SO - entries contain valid absolute addresses. - Release 3.0 acc also puts out N_OPT entries, which makes - it possible to discern acc from cc or gcc. */ + under SunOS4, puts out functions with N_FUN and a value + of zero. This gets relocated to the start of the text + segment of the module, which is no good either. + Under SunOS4 we can deal with this as N_SLINE and N_SO + entries contain valid absolute addresses. + Release 3.0 acc also puts out N_OPT entries, which makes + it possible to discern acc from cc or gcc. */ if (type == N_GSYM || type == N_STSYM || (type == N_FUN @@ -2330,14 +3159,14 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) m = lookup_minimal_symbol_by_pc (last_pc_address); if (m && STREQN (SYMBOL_NAME (m), name, l) - && SYMBOL_NAME (m) [l] == '\0') + && SYMBOL_NAME (m)[l] == '\0') /* last_pc_address was in this function */ valu = SYMBOL_VALUE (m); - else if (m && SYMBOL_NAME (m+1) - && STREQN (SYMBOL_NAME (m+1), name, l) - && SYMBOL_NAME (m+1) [l] == '\0') + else if (m && SYMBOL_NAME (m + 1) + && STREQN (SYMBOL_NAME (m + 1), name, l) + && SYMBOL_NAME (m + 1)[l] == '\0') /* last_pc_address was in last function */ - valu = SYMBOL_VALUE (m+1); + valu = SYMBOL_VALUE (m + 1); else /* Not found - use last_pc_address (for finish_block) */ valu = last_pc_address; @@ -2353,9 +3182,16 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) Solaris 2.0, these addresses are just absolute, or relative to the N_SO, depending on BLOCK_ADDRESS_ABSOLUTE. */ - function_start_offset = valu; + function_start_offset = valu; within_function = 1; + + if (context_stack_depth > 1) + { + complain (&lbrac_unmatched_complaint, symnum); + break; + } + if (context_stack_depth > 0) { new = pop_context (); @@ -2363,9 +3199,6 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) finish_block (new->name, &local_symbols, new->old_blocks, new->start_addr, valu, objfile); } - /* Stack must be empty now. */ - if (context_stack_depth != 0) - complain (&lbrac_unmatched_complaint, symnum); new = push_context (0, valu); new->name = define_symbol (valu, name, desc, type, objfile); @@ -2378,16 +3211,18 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) } break; - /* We use N_OPT to carry the gcc2_compiled flag. Sun uses it - for a bunch of other flags, too. Someday we may parse their - flags; for now we ignore theirs and hope they'll ignore ours. */ - case N_OPT: /* Solaris 2: Compiler options */ + /* We use N_OPT to carry the gcc2_compiled flag. Sun uses it + for a bunch of other flags, too. Someday we may parse their + flags; for now we ignore theirs and hope they'll ignore ours. */ + case N_OPT: /* Solaris 2: Compiler options */ if (name) { if (STREQ (name, GCC2_COMPILED_FLAG_SYMBOL)) { processing_gcc_compilation = 2; -#if 1 /* Works, but is experimental. -fnf */ +#if 0 /* Works, but is experimental. -fnf */ + /* For now, stay with AUTO_DEMANGLING for g++ output, as we don't + know whether it will use the old style or v3 mangling. */ if (AUTO_DEMANGLING) { set_demangling_style (GNU_DEMANGLING_STYLE_STRING); @@ -2399,16 +3234,26 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) } break; - /* The following symbol types can be ignored. */ - case N_OBJ: /* Solaris 2: Object file dir and name */ - /* N_UNDF: Solaris 2: file separator mark */ - /* N_UNDF: -- we will never encounter it, since we only process one - file's symbols at once. */ - case N_ENDM: /* Solaris 2: End of module */ case N_MAIN: /* Name of main routine. */ -#if 0 /* XXX remove when binutils 2.9.2 is imported */ + /* FIXME: If one has a symbol file with N_MAIN and then replaces + it with a symbol file with "main" and without N_MAIN. I'm + not sure exactly what rule to follow but probably something + like: N_MAIN takes precedence over "main" no matter what + objfile it is in; If there is more than one N_MAIN, choose + the one in the symfile_objfile; If there is more than one + N_MAIN within a given objfile, complain() and choose + arbitrarily. (kingdon) */ + if (name != NULL) + set_main_name (name); + break; + + /* The following symbol types can be ignored. */ + case N_OBJ: /* Solaris 2: Object file dir and name */ + /* N_UNDF: Solaris 2: file separator mark */ + /* N_UNDF: -- we will never encounter it, since we only process one + file's symbols at once. */ + case N_ENDM: /* Solaris 2: End of module */ case N_ALIAS: /* SunPro F77: alias name, ignore for now. */ -#endif break; } @@ -2416,7 +3261,7 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) related symbol. Generally this is used so that an alias can refer to its main - symbol. */ + symbol. */ if (name[0] == '#') { /* Initialize symbol reference names and determine if this is @@ -2427,10 +3272,10 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) int refnum; /* If this stab defines a new reference ID that is not on the - reference list, then put it on the reference list. + reference list, then put it on the reference list. - We go ahead and advance NAME past the reference, even though - it is not strictly necessary at this time. */ + We go ahead and advance NAME past the reference, even though + it is not strictly necessary at this time. */ refnum = symbol_reference_defined (&s); if (refnum >= 0) if (!ref_search (refnum)) @@ -2468,17 +3313,10 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) adjusted for coff details. */ void -coffstab_build_psymtabs (objfile, section_offsets, mainline, - textaddr, textsize, stabsects, - stabstroffset, stabstrsize) - struct objfile *objfile; - struct section_offsets *section_offsets; - int mainline; - CORE_ADDR textaddr; - unsigned int textsize; - struct stab_section_list *stabsects; - file_ptr stabstroffset; - unsigned int stabstrsize; +coffstab_build_psymtabs (struct objfile *objfile, int mainline, + CORE_ADDR textaddr, unsigned int textsize, + struct stab_section_list *stabsects, + file_ptr stabstroffset, unsigned int stabstrsize) { int val; bfd *sym_bfd = objfile->obfd; @@ -2494,21 +3332,21 @@ coffstab_build_psymtabs (objfile, section_offsets, mainline, DBX_TEXT_SIZE (objfile) = textsize; #define COFF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */ - DBX_SYMBOL_SIZE (objfile) = COFF_STABS_SYMBOL_SIZE; + DBX_SYMBOL_SIZE (objfile) = COFF_STABS_SYMBOL_SIZE; DBX_STRINGTAB_SIZE (objfile) = stabstrsize; - + if (stabstrsize > bfd_get_size (sym_bfd)) error ("ridiculous string table size: %d bytes", stabstrsize); DBX_STRINGTAB (objfile) = (char *) - obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1); - OBJSTAT (objfile, sz_strtab += stabstrsize+1); + obstack_alloc (&objfile->psymbol_obstack, stabstrsize + 1); + OBJSTAT (objfile, sz_strtab += stabstrsize + 1); /* Now read in the string table in one big gulp. */ val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET); if (val < 0) perror_with_name (name); - val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd); + val = bfd_bread (DBX_STRINGTAB (objfile), stabstrsize, sym_bfd); if (val != stabstrsize) perror_with_name (name); @@ -2546,7 +3384,7 @@ coffstab_build_psymtabs (objfile, section_offsets, mainline, symbuf_read = 0; } - dbx_symfile_read (objfile, section_offsets, 0); + dbx_symfile_read (objfile, 0); } /* Scan and build partial symbols for an ELF symbol file. @@ -2570,51 +3408,41 @@ coffstab_build_psymtabs (objfile, section_offsets, mainline, adjusted for elf details. */ void -elfstab_build_psymtabs (objfile, section_offsets, mainline, - staboffset, stabsize, - stabstroffset, stabstrsize) - struct objfile *objfile; - struct section_offsets *section_offsets; - int mainline; - file_ptr staboffset; - unsigned int stabsize; - file_ptr stabstroffset; - unsigned int stabstrsize; +elfstab_build_psymtabs (struct objfile *objfile, int mainline, + file_ptr staboffset, unsigned int stabsize, + file_ptr stabstroffset, unsigned int stabstrsize) { int val; bfd *sym_bfd = objfile->obfd; char *name = bfd_get_filename (sym_bfd); struct dbx_symfile_info *info; - asection *text_sect; /* There is already a dbx_symfile_info allocated by our caller. It might even contain some info from the ELF symtab to help us. */ info = objfile->sym_stab_info; - text_sect = bfd_get_section_by_name (sym_bfd, ".text"); - if (!text_sect) - error ("Can't find .text section in symbol file"); - DBX_TEXT_ADDR (objfile) = bfd_section_vma (sym_bfd, text_sect); - DBX_TEXT_SIZE (objfile) = bfd_section_size (sym_bfd, text_sect); + /* Find the first and last text address. dbx_symfile_read seems to + want this. */ + find_text_range (sym_bfd, objfile); #define ELF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */ - DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE; - DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile); + DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE; + DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile); DBX_STRINGTAB_SIZE (objfile) = stabstrsize; - DBX_SYMTAB_OFFSET (objfile) = staboffset; - + DBX_SYMTAB_OFFSET (objfile) = staboffset; + if (stabstrsize > bfd_get_size (sym_bfd)) error ("ridiculous string table size: %d bytes", stabstrsize); DBX_STRINGTAB (objfile) = (char *) - obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1); - OBJSTAT (objfile, sz_strtab += stabstrsize+1); + obstack_alloc (&objfile->psymbol_obstack, stabstrsize + 1); + OBJSTAT (objfile, sz_strtab += stabstrsize + 1); /* Now read in the string table in one big gulp. */ val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET); if (val < 0) perror_with_name (name); - val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd); + val = bfd_bread (DBX_STRINGTAB (objfile), stabstrsize, sym_bfd); if (val != stabstrsize) perror_with_name (name); @@ -2629,7 +3457,7 @@ elfstab_build_psymtabs (objfile, section_offsets, mainline, /* In an elf file, we've already installed the minimal symbols that came from the elf (non-stab) symbol table, so always act like an incremental load here. */ - dbx_symfile_read (objfile, section_offsets, 0); + dbx_symfile_read (objfile, 0); } /* Scan and build partial symbols for a file with special sections for stabs @@ -2641,23 +3469,17 @@ elfstab_build_psymtabs (objfile, section_offsets, mainline, OBJFILE is the object file we are reading symbols from. ADDR is the address relative to which the symbols are (e.g. the base address - of the text segment). + of the text segment). MAINLINE is true if we are reading the main symbol table (as opposed to a - shared lib or dynamically loaded file). + shared lib or dynamically loaded file). STAB_NAME is the name of the section that contains the stabs. STABSTR_NAME is the name of the section that contains the stab strings. This routine is mostly copied from dbx_symfile_init and dbx_symfile_read. */ void -stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, - stabstr_name, text_name) - struct objfile *objfile; - struct section_offsets *section_offsets; - int mainline; - char *stab_name; - char *stabstr_name; - char *text_name; +stabsect_build_psymtabs (struct objfile *objfile, int mainline, char *stab_name, + char *stabstr_name, char *text_name) { int val; bfd *sym_bfd = objfile->obfd; @@ -2686,12 +3508,12 @@ stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, DBX_TEXT_ADDR (objfile) = bfd_section_vma (sym_bfd, text_sect); DBX_TEXT_SIZE (objfile) = bfd_section_size (sym_bfd, text_sect); - DBX_SYMBOL_SIZE (objfile) = sizeof (struct external_nlist); - DBX_SYMCOUNT (objfile) = bfd_section_size (sym_bfd, stabsect) + DBX_SYMBOL_SIZE (objfile) = sizeof (struct external_nlist); + DBX_SYMCOUNT (objfile) = bfd_section_size (sym_bfd, stabsect) / DBX_SYMBOL_SIZE (objfile); DBX_STRINGTAB_SIZE (objfile) = bfd_section_size (sym_bfd, stabstrsect); - DBX_SYMTAB_OFFSET (objfile) = stabsect->filepos; /* XXX - FIXME: POKING INSIDE BFD DATA STRUCTURES */ - + DBX_SYMTAB_OFFSET (objfile) = stabsect->filepos; /* XXX - FIXME: POKING INSIDE BFD DATA STRUCTURES */ + if (DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd)) error ("ridiculous string table size: %d bytes", DBX_STRINGTAB_SIZE (objfile)); DBX_STRINGTAB (objfile) = (char *) @@ -2700,11 +3522,11 @@ stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, /* Now read in the string table in one big gulp. */ - val = bfd_get_section_contents (sym_bfd, /* bfd */ - stabstrsect, /* bfd section */ - DBX_STRINGTAB (objfile), /* input buffer */ - 0, /* offset into section */ - DBX_STRINGTAB_SIZE (objfile)); /* amount to read */ + val = bfd_get_section_contents (sym_bfd, /* bfd */ + stabstrsect, /* bfd section */ + DBX_STRINGTAB (objfile), /* input buffer */ + 0, /* offset into section */ + DBX_STRINGTAB_SIZE (objfile)); /* amount to read */ if (!val) perror_with_name (name); @@ -2718,23 +3540,22 @@ stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, /* Now, do an incremental load */ processing_acc_compilation = 1; - dbx_symfile_read (objfile, section_offsets, 0); + dbx_symfile_read (objfile, 0); } static struct sym_fns aout_sym_fns = { bfd_target_aout_flavour, - dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ - dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ - dbx_symfile_read, /* sym_read: read a symbol file into symtab */ - dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ - default_symfile_offsets, - /* sym_offsets: parse user's offsets to internal form */ - NULL /* next: pointer to next struct sym_fns */ + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */ + NULL /* next: pointer to next struct sym_fns */ }; void -_initialize_dbxread () +_initialize_dbxread (void) { - add_symtab_fns(&aout_sym_fns); + add_symtab_fns (&aout_sym_fns); } diff --git a/contrib/gdb/gdb/defs.h b/contrib/gdb/gdb/defs.h index b487657..b6e7953 100644 --- a/contrib/gdb/gdb/defs.h +++ b/contrib/gdb/gdb/defs.h @@ -1,24 +1,25 @@ +/* *INDENT-OFF* */ /* ATTR_FORMAT confuses indent, avoid running it for now */ /* Basic, host-specific, and target-specific definitions for GDB. - Copyright (C) 1986, 89, 91, 92, 93, 94, 95, 96, 98, 1999 + Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ - -/* $FreeBSD$ */ + 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 DEFS_H #define DEFS_H @@ -27,13 +28,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> #include <errno.h> /* System call error return status */ #include <limits.h> -#include <stdlib.h> -#include <string.h> #ifdef HAVE_STDDEF_H -# include <stddef.h> +#include <stddef.h> #else -# include <sys/types.h> /* for size_t */ +#include <sys/types.h> /* for size_t */ +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> #endif /* Just in case they're not defined in stdio.h. */ @@ -50,26 +53,38 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ansidecl.h" -#ifdef ANSI_PROTOTYPES -#include <stdarg.h> -#else -#include <varargs.h> -#endif +#include <stdarg.h> /* for va_list */ #include "libiberty.h" -/* libiberty.h can't declare this one, but evidently we can. */ -extern char *strsignal PARAMS ((int)); - #include "progress.h" -#ifdef USE_MMALLOC -#include "mmalloc.h" -#endif - /* For BFD64 and bfd_vma. */ #include "bfd.h" + +/* The target is partially multi-arched. Both "tm.h" and the + multi-arch vector provide definitions. "tm.h" normally overrides + the multi-arch vector (but there are a few exceptions). */ + +#define GDB_MULTI_ARCH_PARTIAL 1 + +/* The target is partially multi-arched. Both the multi-arch vector + and "tm.h" provide definitions. "tm.h" cannot override a definition + provided by the multi-arch vector. It is detected as a compilation + error. + + This setting is only useful during a multi-arch conversion. */ + +#define GDB_MULTI_ARCH_TM 2 + +/* The target is pure multi-arch. The MULTI-ARCH vector provides all + definitions. "tm.h" is linked to an empty file. */ + +#define GDB_MULTI_ARCH_PURE 3 + + + /* An address in the program being debugged. Host byte order. Rather than duplicate all the logic in BFD which figures out what type this is (long, long long, etc.) and whether it needs to be 64 @@ -78,6 +93,36 @@ extern char *strsignal PARAMS ((int)); typedef bfd_vma CORE_ADDR; +/* This is to make sure that LONGEST is at least as big as CORE_ADDR. */ + +#ifndef LONGEST + +#ifdef BFD64 + +#define LONGEST BFD_HOST_64_BIT +#define ULONGEST BFD_HOST_U_64_BIT + +#else /* No BFD64 */ + +#ifdef CC_HAS_LONG_LONG +#define LONGEST long long +#define ULONGEST unsigned long long +#else +#ifdef BFD_HOST_64_BIT +/* BFD_HOST_64_BIT is defined for some hosts that don't have long long + (e.g. i386-windows) so try it. */ +#define LONGEST BFD_HOST_64_BIT +#define ULONGEST BFD_HOST_U_64_BIT +#else +#define LONGEST long +#define ULONGEST unsigned long +#endif +#endif + +#endif /* No BFD64 */ + +#endif /* ! LONGEST */ + #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif @@ -85,10 +130,24 @@ typedef bfd_vma CORE_ADDR; #define max(a, b) ((a) > (b) ? (a) : (b)) #endif -/* Gdb does *lots* of string compares. Use macros to speed them up by - avoiding function calls if the first characters are not the same. */ +/* Macros to do string compares. + + NOTE: cagney/2000-03-14: + + While old code can continue to refer to these macros, new code is + probably better off using strcmp() directly vis: ``strcmp() == 0'' + and ``strcmp() != 0''. + + This is because modern compilers can directly inline strcmp() + making the original justification for these macros - avoid function + call overhead by pre-testing the first characters + (``*X==*Y?...:0'') - redundant. + + ``Even if [...] testing the first character does have a modest + performance improvement, I'd rather that whenever a performance + issue is found that we spend the effort on algorithmic + optimizations than micro-optimizing.'' J.T. */ -#define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b)) #define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0) #define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0) @@ -97,18 +156,11 @@ typedef bfd_vma CORE_ADDR; #define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */ /* Check if a character is one of the commonly used C++ marker characters. */ -extern int is_cplus_marker PARAMS ((int)); +extern int is_cplus_marker (int); /* use tui interface if non-zero */ extern int tui_version; -#if defined(TUI) -/* all invocations of TUIDO should have two sets of parens */ -#define TUIDO(x) tuiDo x -#else -#define TUIDO(x) -#endif - /* enable xdb commands if set */ extern int xdb_commands; @@ -119,7 +171,14 @@ extern int quit_flag; extern int immediate_quit; extern int sevenbit_strings; -extern void quit PARAMS ((void)); +extern void quit (void); + +/* FIXME: cagney/2000-03-13: It has been suggested that the peformance + benefits of having a ``QUIT'' macro rather than a function are + marginal. If the overhead of a QUIT function call is proving + significant then its calling frequency should probably be reduced + [kingdon]. A profile analyzing the current situtation is + needed. */ #ifdef QUIT /* do twice to force compiler warning */ @@ -133,49 +192,240 @@ extern void quit PARAMS ((void)); } #endif -/* Command classes are top-level categories into which commands are broken - down for "help" purposes. - Notes on classes: class_alias is for alias commands which are not - abbreviations of the original command. class-pseudo is for commands - which are not really commands nor help topics ("stop"). */ - -enum command_class -{ - /* Special args to help_list */ - all_classes = -2, all_commands = -1, - /* Classes of commands */ - no_class = -1, class_run = 0, class_vars, class_stack, - class_files, class_support, class_info, class_breakpoint, class_trace, - class_alias, class_obscure, class_user, class_maintenance, - class_pseudo, class_tui, class_xdb -}; - /* Languages represented in the symbol table and elsewhere. This should probably be in language.h, but since enum's can't be forward declared to satisfy opaque references before their actual definition, needs to be here. */ -enum language -{ - language_unknown, /* Language not known */ - language_auto, /* Placeholder for automatic setting */ - language_c, /* C */ - language_cplus, /* C++ */ - language_java, /* Java */ - language_chill, /* Chill */ - language_fortran, /* Fortran */ - language_m2, /* Modula-2 */ - language_asm, /* Assembly language */ - language_scm /* Scheme / Guile */ -}; +enum language + { + language_unknown, /* Language not known */ + language_auto, /* Placeholder for automatic setting */ + language_c, /* C */ + language_cplus, /* C++ */ + language_java, /* Java */ + language_chill, /* Chill */ + language_fortran, /* Fortran */ + language_m2, /* Modula-2 */ + language_asm, /* Assembly language */ + language_scm, /* Scheme / Guile */ + language_pascal /* Pascal */ + }; enum precision_type -{ - single_precision, - double_precision, - unspecified_precision -}; - + { + single_precision, + double_precision, + unspecified_precision + }; + +/* The numbering of these signals is chosen to match traditional unix + signals (insofar as various unices use the same numbers, anyway). + It is also the numbering of the GDB remote protocol. Other remote + protocols, if they use a different numbering, should make sure to + translate appropriately. + + Since these numbers have actually made it out into other software + (stubs, etc.), you mustn't disturb the assigned numbering. If you + need to add new signals here, add them to the end of the explicitly + numbered signals. + + This is based strongly on Unix/POSIX signals for several reasons: + (1) This set of signals represents a widely-accepted attempt to + represent events of this sort in a portable fashion, (2) we want a + signal to make it from wait to child_wait to the user intact, (3) many + remote protocols use a similar encoding. However, it is + recognized that this set of signals has limitations (such as not + distinguishing between various kinds of SIGSEGV, or not + distinguishing hitting a breakpoint from finishing a single step). + So in the future we may get around this either by adding additional + signals for breakpoint, single-step, etc., or by adding signal + codes; the latter seems more in the spirit of what BSD, System V, + etc. are doing to address these issues. */ + +/* For an explanation of what each signal means, see + target_signal_to_string. */ + +enum target_signal + { + /* Used some places (e.g. stop_signal) to record the concept that + there is no signal. */ + TARGET_SIGNAL_0 = 0, + TARGET_SIGNAL_FIRST = 0, + TARGET_SIGNAL_HUP = 1, + TARGET_SIGNAL_INT = 2, + TARGET_SIGNAL_QUIT = 3, + TARGET_SIGNAL_ILL = 4, + TARGET_SIGNAL_TRAP = 5, + TARGET_SIGNAL_ABRT = 6, + TARGET_SIGNAL_EMT = 7, + TARGET_SIGNAL_FPE = 8, + TARGET_SIGNAL_KILL = 9, + TARGET_SIGNAL_BUS = 10, + TARGET_SIGNAL_SEGV = 11, + TARGET_SIGNAL_SYS = 12, + TARGET_SIGNAL_PIPE = 13, + TARGET_SIGNAL_ALRM = 14, + TARGET_SIGNAL_TERM = 15, + TARGET_SIGNAL_URG = 16, + TARGET_SIGNAL_STOP = 17, + TARGET_SIGNAL_TSTP = 18, + TARGET_SIGNAL_CONT = 19, + TARGET_SIGNAL_CHLD = 20, + TARGET_SIGNAL_TTIN = 21, + TARGET_SIGNAL_TTOU = 22, + TARGET_SIGNAL_IO = 23, + TARGET_SIGNAL_XCPU = 24, + TARGET_SIGNAL_XFSZ = 25, + TARGET_SIGNAL_VTALRM = 26, + TARGET_SIGNAL_PROF = 27, + TARGET_SIGNAL_WINCH = 28, + TARGET_SIGNAL_LOST = 29, + TARGET_SIGNAL_USR1 = 30, + TARGET_SIGNAL_USR2 = 31, + TARGET_SIGNAL_PWR = 32, + /* Similar to SIGIO. Perhaps they should have the same number. */ + TARGET_SIGNAL_POLL = 33, + TARGET_SIGNAL_WIND = 34, + TARGET_SIGNAL_PHONE = 35, + TARGET_SIGNAL_WAITING = 36, + TARGET_SIGNAL_LWP = 37, + TARGET_SIGNAL_DANGER = 38, + TARGET_SIGNAL_GRANT = 39, + TARGET_SIGNAL_RETRACT = 40, + TARGET_SIGNAL_MSG = 41, + TARGET_SIGNAL_SOUND = 42, + TARGET_SIGNAL_SAK = 43, + TARGET_SIGNAL_PRIO = 44, + TARGET_SIGNAL_REALTIME_33 = 45, + TARGET_SIGNAL_REALTIME_34 = 46, + TARGET_SIGNAL_REALTIME_35 = 47, + TARGET_SIGNAL_REALTIME_36 = 48, + TARGET_SIGNAL_REALTIME_37 = 49, + TARGET_SIGNAL_REALTIME_38 = 50, + TARGET_SIGNAL_REALTIME_39 = 51, + TARGET_SIGNAL_REALTIME_40 = 52, + TARGET_SIGNAL_REALTIME_41 = 53, + TARGET_SIGNAL_REALTIME_42 = 54, + TARGET_SIGNAL_REALTIME_43 = 55, + TARGET_SIGNAL_REALTIME_44 = 56, + TARGET_SIGNAL_REALTIME_45 = 57, + TARGET_SIGNAL_REALTIME_46 = 58, + TARGET_SIGNAL_REALTIME_47 = 59, + TARGET_SIGNAL_REALTIME_48 = 60, + TARGET_SIGNAL_REALTIME_49 = 61, + TARGET_SIGNAL_REALTIME_50 = 62, + TARGET_SIGNAL_REALTIME_51 = 63, + TARGET_SIGNAL_REALTIME_52 = 64, + TARGET_SIGNAL_REALTIME_53 = 65, + TARGET_SIGNAL_REALTIME_54 = 66, + TARGET_SIGNAL_REALTIME_55 = 67, + TARGET_SIGNAL_REALTIME_56 = 68, + TARGET_SIGNAL_REALTIME_57 = 69, + TARGET_SIGNAL_REALTIME_58 = 70, + TARGET_SIGNAL_REALTIME_59 = 71, + TARGET_SIGNAL_REALTIME_60 = 72, + TARGET_SIGNAL_REALTIME_61 = 73, + TARGET_SIGNAL_REALTIME_62 = 74, + TARGET_SIGNAL_REALTIME_63 = 75, + + /* Used internally by Solaris threads. See signal(5) on Solaris. */ + TARGET_SIGNAL_CANCEL = 76, + + /* Yes, this pains me, too. But LynxOS didn't have SIG32, and now + GNU/Linux does, and we can't disturb the numbering, since it's + part of the remote protocol. Note that in some GDB's + TARGET_SIGNAL_REALTIME_32 is number 76. */ + TARGET_SIGNAL_REALTIME_32, + /* Yet another pain, IRIX 6 has SIG64. */ + TARGET_SIGNAL_REALTIME_64, + /* Yet another pain, GNU/Linux MIPS might go up to 128. */ + TARGET_SIGNAL_REALTIME_65, + TARGET_SIGNAL_REALTIME_66, + TARGET_SIGNAL_REALTIME_67, + TARGET_SIGNAL_REALTIME_68, + TARGET_SIGNAL_REALTIME_69, + TARGET_SIGNAL_REALTIME_70, + TARGET_SIGNAL_REALTIME_71, + TARGET_SIGNAL_REALTIME_72, + TARGET_SIGNAL_REALTIME_73, + TARGET_SIGNAL_REALTIME_74, + TARGET_SIGNAL_REALTIME_75, + TARGET_SIGNAL_REALTIME_76, + TARGET_SIGNAL_REALTIME_77, + TARGET_SIGNAL_REALTIME_78, + TARGET_SIGNAL_REALTIME_79, + TARGET_SIGNAL_REALTIME_80, + TARGET_SIGNAL_REALTIME_81, + TARGET_SIGNAL_REALTIME_82, + TARGET_SIGNAL_REALTIME_83, + TARGET_SIGNAL_REALTIME_84, + TARGET_SIGNAL_REALTIME_85, + TARGET_SIGNAL_REALTIME_86, + TARGET_SIGNAL_REALTIME_87, + TARGET_SIGNAL_REALTIME_88, + TARGET_SIGNAL_REALTIME_89, + TARGET_SIGNAL_REALTIME_90, + TARGET_SIGNAL_REALTIME_91, + TARGET_SIGNAL_REALTIME_92, + TARGET_SIGNAL_REALTIME_93, + TARGET_SIGNAL_REALTIME_94, + TARGET_SIGNAL_REALTIME_95, + TARGET_SIGNAL_REALTIME_96, + TARGET_SIGNAL_REALTIME_97, + TARGET_SIGNAL_REALTIME_98, + TARGET_SIGNAL_REALTIME_99, + TARGET_SIGNAL_REALTIME_100, + TARGET_SIGNAL_REALTIME_101, + TARGET_SIGNAL_REALTIME_102, + TARGET_SIGNAL_REALTIME_103, + TARGET_SIGNAL_REALTIME_104, + TARGET_SIGNAL_REALTIME_105, + TARGET_SIGNAL_REALTIME_106, + TARGET_SIGNAL_REALTIME_107, + TARGET_SIGNAL_REALTIME_108, + TARGET_SIGNAL_REALTIME_109, + TARGET_SIGNAL_REALTIME_110, + TARGET_SIGNAL_REALTIME_111, + TARGET_SIGNAL_REALTIME_112, + TARGET_SIGNAL_REALTIME_113, + TARGET_SIGNAL_REALTIME_114, + TARGET_SIGNAL_REALTIME_115, + TARGET_SIGNAL_REALTIME_116, + TARGET_SIGNAL_REALTIME_117, + TARGET_SIGNAL_REALTIME_118, + TARGET_SIGNAL_REALTIME_119, + TARGET_SIGNAL_REALTIME_120, + TARGET_SIGNAL_REALTIME_121, + TARGET_SIGNAL_REALTIME_122, + TARGET_SIGNAL_REALTIME_123, + TARGET_SIGNAL_REALTIME_124, + TARGET_SIGNAL_REALTIME_125, + TARGET_SIGNAL_REALTIME_126, + TARGET_SIGNAL_REALTIME_127, + +#if defined(MACH) || defined(__MACH__) + /* Mach exceptions */ + TARGET_EXC_BAD_ACCESS, + TARGET_EXC_BAD_INSTRUCTION, + TARGET_EXC_ARITHMETIC, + TARGET_EXC_EMULATION, + TARGET_EXC_SOFTWARE, + TARGET_EXC_BREAKPOINT, +#endif + TARGET_SIGNAL_INFO, + + /* Some signal we don't know about. */ + TARGET_SIGNAL_UNKNOWN, + + /* Use whatever signal we use when one is not specifically specified + (for passing to proceed and so on). */ + TARGET_SIGNAL_DEFAULT, + + /* Last and unused enum value, for sizing arrays, etc. */ + TARGET_SIGNAL_LAST + }; + /* the cleanup list records things that have to be undone if an error happens (descriptors to be closed, memory to be freed, etc.) Each link in the chain records a function to call and an @@ -187,11 +437,11 @@ enum precision_type from the chain back to a given point, not doing them. */ struct cleanup -{ - struct cleanup *next; - void (*function) PARAMS ((PTR)); - PTR arg; -}; + { + struct cleanup *next; + void (*function) (PTR); + PTR arg; + }; /* The ability to declare that a function never returns is useful, but @@ -202,12 +452,12 @@ struct cleanup "volatile" to indicate that it does not return. */ #ifndef NORETURN -# if defined(__GNUC__) \ +#if defined(__GNUC__) \ && (__GNUC__ == 1 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)) -# define NORETURN volatile -# else -# define NORETURN /* nothing */ -# endif +#define NORETURN volatile +#else +#define NORETURN /* nothing */ +#endif #endif /* GCC 2.5 and later versions define a function attribute "noreturn", @@ -216,332 +466,428 @@ struct cleanup works everywhere we use it. */ #ifndef ATTR_NORETURN -# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 7 -# define ATTR_NORETURN __attribute__ ((noreturn)) -# else -# define ATTR_NORETURN /* nothing */ -# endif +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) +#define ATTR_NORETURN __attribute__ ((noreturn)) +#else +#define ATTR_NORETURN /* nothing */ +#endif #endif #ifndef ATTR_FORMAT -# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 4 && defined (__ANSI_PROTOTYPES) -# define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y))) -# else -# define ATTR_FORMAT(type, x, y) /* nothing */ -# endif +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4)) +#define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y))) +#else +#define ATTR_FORMAT(type, x, y) /* nothing */ +#endif #endif /* Needed for various prototypes */ -#ifdef __STDC__ struct symtab; struct breakpoint; -#endif /* From blockframe.c */ -extern int inside_entry_func PARAMS ((CORE_ADDR)); +extern int inside_entry_func (CORE_ADDR); -extern int inside_entry_file PARAMS ((CORE_ADDR addr)); +extern int inside_entry_file (CORE_ADDR addr); -extern int inside_main_func PARAMS ((CORE_ADDR pc)); +extern int inside_main_func (CORE_ADDR pc); /* From ch-lang.c, for the moment. (FIXME) */ -extern char *chill_demangle PARAMS ((const char *)); +extern char *chill_demangle (const char *); /* From utils.c */ -extern void notice_quit PARAMS ((void)); +extern void initialize_utils (void); -extern int strcmp_iw PARAMS ((const char *, const char *)); +extern void notice_quit (void); -extern char *safe_strerror PARAMS ((int)); +extern int strcmp_iw (const char *, const char *); -extern char *safe_strsignal PARAMS ((int)); +extern int subset_compare (char *, char *); -extern void init_malloc PARAMS ((void *)); +extern char *safe_strerror (int); -extern void request_quit PARAMS ((int)); +extern void init_malloc (void *); -extern void do_cleanups PARAMS ((struct cleanup *)); -extern void do_final_cleanups PARAMS ((struct cleanup *)); -extern void do_my_cleanups PARAMS ((struct cleanup **, struct cleanup *)); -extern void do_run_cleanups PARAMS ((struct cleanup *)); +extern void request_quit (int); -extern void discard_cleanups PARAMS ((struct cleanup *)); -extern void discard_final_cleanups PARAMS ((struct cleanup *)); -extern void discard_my_cleanups PARAMS ((struct cleanup **, struct cleanup *)); +extern void do_cleanups (struct cleanup *); +extern void do_final_cleanups (struct cleanup *); +extern void do_my_cleanups (struct cleanup **, struct cleanup *); +extern void do_run_cleanups (struct cleanup *); +extern void do_exec_cleanups (struct cleanup *); +extern void do_exec_error_cleanups (struct cleanup *); -typedef void (*make_cleanup_func) PARAMS ((void *)); +extern void discard_cleanups (struct cleanup *); +extern void discard_final_cleanups (struct cleanup *); +extern void discard_exec_error_cleanups (struct cleanup *); +extern void discard_my_cleanups (struct cleanup **, struct cleanup *); -extern struct cleanup *make_cleanup PARAMS ((make_cleanup_func, void *)); +/* NOTE: cagney/2000-03-04: This typedef is strictly for the + make_cleanup function declarations below. Do not use this typedef + as a cast when passing functions into the make_cleanup() code. + Instead either use a bounce function or add a wrapper function. + Calling a f(char*) function with f(void*) is non-portable. */ +typedef void (make_cleanup_ftype) (void *); -extern struct cleanup *make_final_cleanup PARAMS ((make_cleanup_func, void *)); +extern struct cleanup *make_cleanup (make_cleanup_ftype *, void *); -extern struct cleanup *make_my_cleanup PARAMS ((struct cleanup **, - make_cleanup_func, void *)); +extern struct cleanup *make_cleanup_freeargv (char **); -extern struct cleanup *make_run_cleanup PARAMS ((make_cleanup_func, void *)); +struct ui_file; +extern struct cleanup *make_cleanup_ui_file_delete (struct ui_file *); -extern struct cleanup *save_cleanups PARAMS ((void)); -extern struct cleanup *save_final_cleanups PARAMS ((void)); -extern struct cleanup *save_my_cleanups PARAMS ((struct cleanup **)); +extern struct cleanup *make_cleanup_close (int fd); -extern void restore_cleanups PARAMS ((struct cleanup *)); -extern void restore_final_cleanups PARAMS ((struct cleanup *)); -extern void restore_my_cleanups PARAMS ((struct cleanup **, struct cleanup *)); +extern struct cleanup *make_cleanup_bfd_close (bfd *abfd); -extern void free_current_contents PARAMS ((char **)); +extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); -extern void null_cleanup PARAMS ((PTR)); +extern struct cleanup *make_my_cleanup (struct cleanup **, + make_cleanup_ftype *, void *); -extern int myread PARAMS ((int, char *, int)); +extern struct cleanup *make_run_cleanup (make_cleanup_ftype *, void *); -extern int query PARAMS((char *, ...)) - ATTR_FORMAT(printf, 1, 2); +extern struct cleanup *make_exec_cleanup (make_cleanup_ftype *, void *); +extern struct cleanup *make_exec_error_cleanup (make_cleanup_ftype *, void *); -#if !defined (USE_MMALLOC) -extern PTR mmalloc PARAMS ((PTR, size_t)); -extern PTR mrealloc PARAMS ((PTR, PTR, size_t)); -extern void mfree PARAMS ((PTR, PTR)); -#endif +extern struct cleanup *save_cleanups (void); +extern struct cleanup *save_final_cleanups (void); +extern struct cleanup *save_my_cleanups (struct cleanup **); + +extern void restore_cleanups (struct cleanup *); +extern void restore_final_cleanups (struct cleanup *); +extern void restore_my_cleanups (struct cleanup **, struct cleanup *); + +extern void free_current_contents (void *); + +extern void null_cleanup (void *); + +extern int myread (int, char *, int); + +extern int query (const char *, ...) ATTR_FORMAT (printf, 1, 2); + +extern void init_page_info (void); + +extern CORE_ADDR host_pointer_to_address (void *ptr); +extern void *address_to_host_pointer (CORE_ADDR addr); + +extern char *gdb_realpath (const char *); /* From demangle.c */ -extern void set_demangling_style PARAMS ((char *)); +extern void set_demangling_style (char *); /* From tm.h */ struct type; -typedef int (use_struct_convention_fn) PARAMS ((int gcc_p, struct type *value_type)); +typedef int (use_struct_convention_fn) (int gcc_p, struct type * value_type); extern use_struct_convention_fn generic_use_struct_convention; -typedef unsigned char *(breakpoint_from_pc_fn) PARAMS ((CORE_ADDR *pcptr, int *lenptr)); - - +typedef unsigned char *(breakpoint_from_pc_fn) (CORE_ADDR * pcptr, int *lenptr); /* Annotation stuff. */ -extern int annotation_level; /* in stack.c */ +extern int annotation_level; /* in stack.c */ -extern void begin_line PARAMS ((void)); - -extern void wrap_here PARAMS ((char *)); - -extern void reinitialize_more_filter PARAMS ((void)); - -/* new */ -enum streamtype -{ - afile, - astring -}; - -/* new */ -typedef struct tui_stream -{ - enum streamtype ts_streamtype; - FILE *ts_filestream; - char *ts_strbuf; - int ts_buflen; -} GDB_FILE; - -extern GDB_FILE *gdb_stdout; -extern GDB_FILE *gdb_stderr; - -#if 0 -typedef FILE GDB_FILE; -#define gdb_stdout stdout -#define gdb_stderr stderr -#endif +extern void begin_line (void); + +extern void wrap_here (char *); + +extern void reinitialize_more_filter (void); + +/* Normal results */ +extern struct ui_file *gdb_stdout; +/* Serious error notifications */ +extern struct ui_file *gdb_stderr; +/* Log/debug/trace messages that should bypass normal stdout/stderr + filtering. For momement, always call this stream using + *_unfiltered. In the very near future that restriction shall be + removed - either call shall be unfiltered. (cagney 1999-06-13). */ +extern struct ui_file *gdb_stdlog; +/* Target output that should bypass normal stdout/stderr filtering. + For momement, always call this stream using *_unfiltered. In the + very near future that restriction shall be removed - either call + shall be unfiltered. (cagney 1999-07-02). */ +extern struct ui_file *gdb_stdtarg; #if defined(TUI) #include "tui.h" -#include "tuiCommand.h" -#include "tuiData.h" -#include "tuiIO.h" -#include "tuiLayout.h" -#include "tuiWin.h" #endif -extern void gdb_fclose PARAMS ((GDB_FILE **)); - -extern void gdb_flush PARAMS ((GDB_FILE *)); +#include "ui-file.h" -extern GDB_FILE *gdb_fopen PARAMS ((char * name, char * mode)); +/* More generic printf like operations. Filtered versions may return + non-locally on error. */ -extern void fputs_filtered PARAMS ((const char *, GDB_FILE *)); +extern void fputs_filtered (const char *, struct ui_file *); -extern void fputs_unfiltered PARAMS ((const char *, GDB_FILE *)); +extern void fputs_unfiltered (const char *, struct ui_file *); -extern int fputc_filtered PARAMS ((int c, GDB_FILE *)); +extern int fputc_filtered (int c, struct ui_file *); -extern int fputc_unfiltered PARAMS ((int c, GDB_FILE *)); +extern int fputc_unfiltered (int c, struct ui_file *); -extern int putchar_unfiltered PARAMS ((int c)); +extern int putchar_filtered (int c); -extern void puts_filtered PARAMS ((const char *)); +extern int putchar_unfiltered (int c); -extern void puts_unfiltered PARAMS ((const char *)); +extern void puts_filtered (const char *); -extern void puts_debug PARAMS ((char *prefix, char *string, char *suffix)); +extern void puts_unfiltered (const char *); -extern void vprintf_filtered PARAMS ((const char *, va_list)) - ATTR_FORMAT(printf, 1, 0); +extern void puts_debug (char *prefix, char *string, char *suffix); -extern void vfprintf_filtered PARAMS ((GDB_FILE *, const char *, va_list)) - ATTR_FORMAT(printf, 2, 0); +extern void vprintf_filtered (const char *, va_list) ATTR_FORMAT (printf, 1, 0); -extern void fprintf_filtered PARAMS ((GDB_FILE *, const char *, ...)) - ATTR_FORMAT(printf, 2, 3); +extern void vfprintf_filtered (struct ui_file *, const char *, va_list) ATTR_FORMAT (printf, 2, 0); -extern void fprintfi_filtered PARAMS ((int, GDB_FILE *, const char *, ...)) - ATTR_FORMAT(printf, 3, 4); +extern void fprintf_filtered (struct ui_file *, const char *, ...) ATTR_FORMAT (printf, 2, 3); -extern void printf_filtered PARAMS ((const char *, ...)) - ATTR_FORMAT(printf, 1, 2); +extern void fprintfi_filtered (int, struct ui_file *, const char *, ...) ATTR_FORMAT (printf, 3, 4); -extern void printfi_filtered PARAMS ((int, const char *, ...)) - ATTR_FORMAT(printf, 2, 3); +extern void printf_filtered (const char *, ...) ATTR_FORMAT (printf, 1, 2); -extern void vprintf_unfiltered PARAMS ((const char *, va_list)) - ATTR_FORMAT(printf, 1, 0); +extern void printfi_filtered (int, const char *, ...) ATTR_FORMAT (printf, 2, 3); -extern void vfprintf_unfiltered PARAMS ((GDB_FILE *, const char *, va_list)) - ATTR_FORMAT(printf, 2, 0); +extern void vprintf_unfiltered (const char *, va_list) ATTR_FORMAT (printf, 1, 0); -extern void fprintf_unfiltered PARAMS ((GDB_FILE *, const char *, ...)) - ATTR_FORMAT(printf, 2, 3); +extern void vfprintf_unfiltered (struct ui_file *, const char *, va_list) ATTR_FORMAT (printf, 2, 0); -extern void printf_unfiltered PARAMS ((const char *, ...)) - ATTR_FORMAT(printf, 1, 2); +extern void fprintf_unfiltered (struct ui_file *, const char *, ...) ATTR_FORMAT (printf, 2, 3); -extern int gdb_file_isatty PARAMS ((GDB_FILE *)); +extern void printf_unfiltered (const char *, ...) ATTR_FORMAT (printf, 1, 2); -extern GDB_FILE *gdb_file_init_astring PARAMS ((int)); +extern void print_spaces (int, struct ui_file *); -extern void gdb_file_deallocate PARAMS ((GDB_FILE **)); +extern void print_spaces_filtered (int, struct ui_file *); -extern char *gdb_file_get_strbuf PARAMS ((GDB_FILE *)); +extern char *n_spaces (int); -extern void gdb_file_adjust_strbuf PARAMS ((int, GDB_FILE *)); +extern void fputstr_filtered (const char *str, int quotr, struct ui_file * stream); -extern void print_spaces PARAMS ((int, GDB_FILE *)); +extern void fputstr_unfiltered (const char *str, int quotr, struct ui_file * stream); -extern void print_spaces_filtered PARAMS ((int, GDB_FILE *)); +extern void fputstrn_unfiltered (const char *str, int n, int quotr, struct ui_file * stream); -extern char *n_spaces PARAMS ((int)); +/* Display the host ADDR on STREAM formatted as ``0x%x''. */ +extern void gdb_print_host_address (void *addr, struct ui_file *stream); -extern void gdb_printchar PARAMS ((int, GDB_FILE *, int)); +/* Convert a CORE_ADDR into a HEX string. paddr() is like %08lx. + paddr_nz() is like %lx. paddr_u() is like %lu. paddr_width() is + for ``%*''. */ +extern int strlen_paddr (void); +extern char *paddr (CORE_ADDR addr); +extern char *paddr_nz (CORE_ADDR addr); +extern char *paddr_u (CORE_ADDR addr); +extern char *paddr_d (LONGEST addr); -extern void gdb_print_address PARAMS ((void *, GDB_FILE *)); +extern char *phex (ULONGEST l, int sizeof_l); +extern char *phex_nz (ULONGEST l, int sizeof_l); -typedef bfd_vma t_addr; -typedef bfd_vma t_reg; -extern char* paddr PARAMS ((t_addr addr)); +/* Like paddr() only print/scan raw CORE_ADDR. The output from + core_addr_to_string() can be passed direct to + string_to_core_addr(). */ +extern const char *core_addr_to_string (const CORE_ADDR addr); +extern const char *core_addr_to_string_nz (const CORE_ADDR addr); +extern CORE_ADDR string_to_core_addr (const char *my_string); -extern char* preg PARAMS ((t_reg reg)); +extern void fprintf_symbol_filtered (struct ui_file *, char *, + enum language, int); -extern char* paddr_nz PARAMS ((t_addr addr)); +extern NORETURN void perror_with_name (const char *) ATTR_NORETURN; -extern char* preg_nz PARAMS ((t_reg reg)); - -extern void fprintf_symbol_filtered PARAMS ((GDB_FILE *, char *, - enum language, int)); - -extern NORETURN void perror_with_name PARAMS ((char *)) ATTR_NORETURN; - -extern void print_sys_errmsg PARAMS ((char *, int)); +extern void print_sys_errmsg (const char *, int); /* From regex.c or libc. BSD 4.4 declares this with the argument type as "const char *" in unistd.h, so we can't declare the argument as "char *". */ -extern char *re_comp PARAMS ((const char *)); +extern char *re_comp (const char *); /* From symfile.c */ -extern void symbol_file_command PARAMS ((char *, int)); +extern void symbol_file_command (char *, int); + +/* Remote targets may wish to use this as their load function. */ +extern void generic_load (char *name, int from_tty); + +/* Summarise a download */ +extern void print_transfer_performance (struct ui_file *stream, + unsigned long data_count, + unsigned long write_count, + unsigned long time_count); /* From top.c */ -extern char *skip_quoted PARAMS ((char *)); +typedef void initialize_file_ftype (void); + +extern char *skip_quoted (char *); -extern char *gdb_readline PARAMS ((char *)); +extern char *gdb_readline (char *); -extern char *command_line_input PARAMS ((char *, int, char *)); +extern char *command_line_input (char *, int, char *); -extern void print_prompt PARAMS ((void)); +extern void print_prompt (void); -extern int input_from_terminal_p PARAMS ((void)); +extern int input_from_terminal_p (void); extern int info_verbose; /* From printcmd.c */ -extern void set_next_address PARAMS ((CORE_ADDR)); +extern void set_next_address (CORE_ADDR); -extern void print_address_symbolic PARAMS ((CORE_ADDR, GDB_FILE *, int, - char *)); +extern void print_address_symbolic (CORE_ADDR, struct ui_file *, int, + char *); -extern void print_address_numeric PARAMS ((CORE_ADDR, int, GDB_FILE *)); +extern int build_address_symbolic (CORE_ADDR addr, + int do_demangle, + char **name, + int *offset, + char **filename, + int *line, + int *unmapped); -extern void print_address PARAMS ((CORE_ADDR, GDB_FILE *)); +extern void print_address_numeric (CORE_ADDR, int, struct ui_file *); + +extern void print_address (CORE_ADDR, struct ui_file *); /* From source.c */ -extern int openp PARAMS ((char *, int, char *, int, int, char **)); +extern int openp (const char *, int, const char *, int, int, char **); + +extern int source_full_path_of (char *, char **); + +extern void mod_path (char *, char **); + +extern void directory_command (char *, int); -extern int source_full_path_of PARAMS ((char *, char **)); +extern void init_source_path (void); -extern void mod_path PARAMS ((char *, char **)); +extern char *symtab_to_filename (struct symtab *); -extern void directory_command PARAMS ((char *, int)); +/* From exec.c */ -extern void init_source_path PARAMS ((void)); +extern void exec_set_section_offsets (bfd_signed_vma text_off, + bfd_signed_vma data_off, + bfd_signed_vma bss_off); -extern char *symtab_to_filename PARAMS ((struct symtab *)); +/* Take over the 'find_mapped_memory' vector from exec.c. */ +extern void exec_set_find_memory_regions (int (*) (int (*) (CORE_ADDR, + unsigned long, + int, int, int, + void *), + void *)); /* From findvar.c */ -extern int read_relative_register_raw_bytes PARAMS ((int, char *)); +extern int read_relative_register_raw_bytes (int, char *); + +/* Possible lvalue types. Like enum language, this should be in + value.h, but needs to be here for the same reason. */ + +enum lval_type + { + /* Not an lval. */ + not_lval, + /* In memory. Could be a saved register. */ + lval_memory, + /* In a register. */ + lval_register, + /* In a gdb internal variable. */ + lval_internalvar, + /* Part of a gdb internal variable (structure field). */ + lval_internalvar_component, + /* In a register series in a frame not the current one, which may have been + partially saved or saved in different places (otherwise would be + lval_register or lval_memory). */ + lval_reg_frame_relative + }; + +struct frame_info; + +/* From readline (but not in any readline .h files). */ + +extern char *tilde_expand (char *); /* Control types for commands */ enum misc_command_type -{ - ok_command, - end_command, - else_command, - nop_command -}; + { + ok_command, + end_command, + else_command, + nop_command + }; enum command_control_type -{ - simple_control, - break_control, - continue_control, - while_control, - if_control, - invalid_control -}; + { + simple_control, + break_control, + continue_control, + while_control, + if_control, + invalid_control + }; /* Structure for saved commands lines (for breakpoints, defined commands, etc). */ struct command_line -{ - struct command_line *next; - char *line; - enum command_control_type control_type; - int body_count; - struct command_line **body_list; -}; + { + struct command_line *next; + char *line; + enum command_control_type control_type; + int body_count; + struct command_line **body_list; + }; + +extern struct command_line *read_command_lines (char *, int); + +extern void free_command_lines (struct command_line **); + +/* To continue the execution commands when running gdb asynchronously. + A continuation structure contains a pointer to a function to be called + to finish the command, once the target has stopped. Such mechanism is + used bt the finish and until commands, and in the remote protocol + when opening an extended-remote connection. */ + +struct continuation_arg + { + struct continuation_arg *next; + union continuation_data { + void *pointer; + int integer; + long longint; + } data; + }; + +struct continuation + { + void (*continuation_hook) (struct continuation_arg *); + struct continuation_arg *arg_list; + struct continuation *next; + }; + +/* In infrun.c. */ +extern struct continuation *cmd_continuation; +/* Used only by the step_1 function. */ +extern struct continuation *intermediate_continuation; -extern struct command_line *read_command_lines PARAMS ((char *, int)); +/* From utils.c */ +extern void add_continuation (void (*)(struct continuation_arg *), + struct continuation_arg *); +extern void do_all_continuations (void); +extern void discard_all_continuations (void); -extern void free_command_lines PARAMS ((struct command_line **)); +extern void add_intermediate_continuation (void (*)(struct continuation_arg *), + struct continuation_arg *); +extern void do_all_intermediate_continuations (void); +extern void discard_all_intermediate_continuations (void); /* String containing the current directory (what getwd would return). */ @@ -558,28 +904,81 @@ extern unsigned output_radix; value.h. */ enum val_prettyprint -{ - Val_no_prettyprint = 0, - Val_prettyprint, - /* Use the default setting which the user has specified. */ - Val_pretty_default -}; + { + Val_no_prettyprint = 0, + Val_prettyprint, + /* Use the default setting which the user has specified. */ + Val_pretty_default + }; + +/* The ptid struct is a collection of the various "ids" necessary + for identifying the inferior. This consists of the process id + (pid), thread id (tid), and other fields necessary for uniquely + identifying the inferior process/thread being debugged. When + manipulating ptids, the constructors, accessors, and predicate + declared in inferior.h should be used. These are as follows: + + ptid_build - Make a new ptid from a pid, lwp, and tid. + pid_to_ptid - Make a new ptid from just a pid. + ptid_get_pid - Fetch the pid component of a ptid. + ptid_get_lwp - Fetch the lwp component of a ptid. + ptid_get_tid - Fetch the tid component of a ptid. + ptid_equal - Test to see if two ptids are equal. + + Please do NOT access the struct ptid members directly (except, of + course, in the implementation of the above ptid manipulation + functions). */ + +struct ptid + { + /* Process id */ + int pid; + + /* Lightweight process id */ + long lwp; + + /* Thread id */ + long tid; + }; + +typedef struct ptid ptid_t; -/* Host machine definition. This will be a symlink to one of the - xm-*.h files, built by the `configure' script. */ +/* Optional host machine definition. Pure autoconf targets will not + need a "xm.h" file. This will be a symlink to one of the xm-*.h + files, built by the `configure' script. */ + +#ifdef GDB_XM_FILE #include "xm.h" +#endif -/* Native machine support. This will be a symlink to one of the - nm-*.h files, built by the `configure' script. */ +/* Optional native machine support. Non-native (and possibly pure + multi-arch) targets do not need a "nm.h" file. This will be a + symlink to one of the nm-*.h files, built by the `configure' + script. */ +#ifdef GDB_NM_FILE #include "nm.h" +#endif -/* Target machine definition. This will be a symlink to one of the +/* Optional target machine definition. Pure multi-arch configurations + do not need a "tm.h" file. This will be a symlink to one of the tm-*.h files, built by the `configure' script. */ +#ifdef GDB_TM_FILE #include "tm.h" +#endif + +/* GDB_MULTI_ARCH is normally set by configure.in using information + from configure.tgt or the config/%/%.mt Makefile fragment. Since + some targets have defined it in their "tm.h" file, delay providing + a default definition until after "tm.h" has been included.. */ + +#ifndef GDB_MULTI_ARCH +#define GDB_MULTI_ARCH 0 +#endif + /* If the xm.h file did not define the mode string used to open the files, assume that binary files are opened the same way as text @@ -588,40 +987,15 @@ enum val_prettyprint #include "fopen-same.h" #endif -/* Microsoft C can't deal with const pointers */ - -#ifdef _MSC_VER -#define CONST_PTR -#else -#define CONST_PTR const -#endif - -/* - * Allow things in gdb to be declared "volatile". If compiling ANSI, it - * just works. If compiling with gcc but non-ansi, redefine to __volatile__. - * If non-ansi, non-gcc, then eliminate "volatile" entirely, making those - * objects be read-write rather than read-only. - */ - -#ifndef volatile -#ifndef __STDC__ -# ifdef __GNUC__ -# define volatile __volatile__ -# else -# define volatile /*nothing*/ -# endif /* GNUC */ -#endif /* STDC */ -#endif /* volatile */ - /* Defaults for system-wide constants (if not defined by xm.h, we fake it). FIXME: Assumes 2's complement arithmetic */ #if !defined (UINT_MAX) -#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */ +#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */ #endif #if !defined (INT_MAX) -#define INT_MAX ((int)(UINT_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ +#define INT_MAX ((int)(UINT_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ #endif #if !defined (INT_MIN) @@ -636,70 +1010,46 @@ enum val_prettyprint #define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ #endif -#ifndef LONGEST - -#ifdef BFD64 - -/* This is to make sure that LONGEST is at least as big as CORE_ADDR. */ - -#define LONGEST BFD_HOST_64_BIT -#define ULONGEST BFD_HOST_U_64_BIT - -#else /* No BFD64 */ - -# ifdef CC_HAS_LONG_LONG -# define LONGEST long long -# define ULONGEST unsigned long long -# else -/* BFD_HOST_64_BIT is defined for some hosts that don't have long long - (e.g. i386-windows) so try it. */ -# ifdef BFD_HOST_64_BIT -# define LONGEST BFD_HOST_64_BIT -# define ULONGEST BFD_HOST_U_64_BIT -# else -# define LONGEST long -# define ULONGEST unsigned long -# endif -# endif - -#endif /* No BFD64 */ +#if !defined (ULONGEST_MAX) +#define ULONGEST_MAX (~(ULONGEST)0) /* 0xFFFFFFFFFFFFFFFF for 64-bits */ +#endif -#endif /* ! LONGEST */ +#if !defined (LONGEST_MAX) /* 0x7FFFFFFFFFFFFFFF for 64-bits */ +#define LONGEST_MAX ((LONGEST)(ULONGEST_MAX >> 1)) +#endif /* Convert a LONGEST to an int. This is used in contexts (e.g. number of arguments to a function, number in a value history, register number, etc.) where the value must not be larger than can fit in an int. */ -extern int longest_to_int PARAMS ((LONGEST)); +extern int longest_to_int (LONGEST); /* Assorted functions we can declare, now that const and volatile are defined. */ -extern char *savestring PARAMS ((const char *, int)); +extern char *savestring (const char *, size_t); -extern char *msavestring PARAMS ((void *, const char *, int)); +extern char *msavestring (void *, const char *, size_t); -extern char *strsave PARAMS ((const char *)); +extern char *mstrsave (void *, const char *); -extern char *mstrsave PARAMS ((void *, const char *)); +/* Robust versions of same. Throw an internal error when no memory, + guard against stray NULL arguments. */ +extern void *xmmalloc (void *md, size_t size); +extern void *xmrealloc (void *md, void *ptr, size_t size); +extern void *xmcalloc (void *md, size_t number, size_t size); +extern void xmfree (void *md, void *ptr); -#ifdef _MSC_VER /* FIXME; was long, but this causes compile errors in msvc if already defined */ -extern PTR xmmalloc PARAMS ((PTR, size_t)); +/* xmalloc(), xrealloc() and xcalloc() have already been declared in + "libiberty.h". */ +extern void xfree (void *); -extern PTR xmrealloc PARAMS ((PTR, PTR, size_t)); -#else -extern PTR xmmalloc PARAMS ((PTR, long)); - -extern PTR xmrealloc PARAMS ((PTR, PTR, long)); -#endif +/* Like asprintf/vasprintf but get an internal_error if the call + fails. */ +extern void xasprintf (char **ret, const char *format, ...) ATTR_FORMAT (printf, 2, 3); +extern void xvasprintf (char **ret, const char *format, va_list ap); -extern int parse_escape PARAMS ((char **)); - -/* compat - handle old targets that just define REGISTER_NAMES */ -#ifndef REGISTER_NAME -extern char *gdb_register_names[]; -#define REGISTER_NAME(i) gdb_register_names[i] -#endif +extern int parse_escape (char **); /* Message to be printed before the error message, when an error occurs. */ @@ -713,45 +1063,113 @@ extern char *quit_pre_print; extern char *warning_pre_print; -extern NORETURN void error PARAMS((const char *, ...)) ATTR_NORETURN; +extern NORETURN void verror (const char *fmt, va_list ap) ATTR_NORETURN; + +extern NORETURN void error (const char *fmt, ...) ATTR_NORETURN; + +extern NORETURN void error_stream (struct ui_file *) ATTR_NORETURN; -extern void error_begin PARAMS ((void)); +/* Returns a freshly allocate buffer containing the last error + message. */ +extern char *error_last_message (void); -extern NORETURN void fatal PARAMS((char *, ...)) ATTR_NORETURN; +extern NORETURN void internal_verror (const char *file, int line, + const char *, va_list ap) ATTR_NORETURN; -extern NORETURN void nomem PARAMS ((long)) ATTR_NORETURN; +extern NORETURN void internal_error (const char *file, int line, + const char *, ...) ATTR_NORETURN ATTR_FORMAT (printf, 3, 4); -/* Reasons for calling return_to_top_level. */ -enum return_reason { - /* User interrupt. */ - RETURN_QUIT, +extern NORETURN void nomem (long) ATTR_NORETURN; - /* Any other error. */ - RETURN_ERROR -}; +/* Reasons for calling throw_exception(). NOTE: all reason values + must be less than zero. enum value 0 is reserved for internal use + as the return value from an initial setjmp(). The function + catch_exceptions() reserves values >= 0 as legal results from its + wrapped function. */ -#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT) -#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR) -#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR) +enum return_reason + { + /* User interrupt. */ + RETURN_QUIT = -2, + /* Any other error. */ + RETURN_ERROR + }; + +#define ALL_CLEANUPS ((struct cleanup *)0) + +#define RETURN_MASK(reason) (1 << (int)(-reason)) +#define RETURN_MASK_QUIT RETURN_MASK (RETURN_QUIT) +#define RETURN_MASK_ERROR RETURN_MASK (RETURN_ERROR) +#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR) typedef int return_mask; -extern NORETURN void -return_to_top_level PARAMS ((enum return_reason)) ATTR_NORETURN; +/* Throw an exception of type RETURN_REASON. Will execute a LONG JUMP + to the inner most containing exception handler established using + catch_exceptions() (or the legacy catch_errors()). + + Code normally throws an exception using error() et.al. For various + reaons, GDB also contains code that throws an exception directly. + For instance, the remote*.c targets contain CNTRL-C signal handlers + that propogate the QUIT event up the exception chain. ``This could + be a good thing or a dangerous thing.'' -- the Existential Wombat. */ + +extern NORETURN void throw_exception (enum return_reason) ATTR_NORETURN; + +/* Call FUNC(UIOUT, FUNC_ARGS) but wrapped within an exception + handler. If an exception (enum return_reason) is thrown using + throw_exception() than all cleanups installed since + catch_exceptions() was entered are invoked, the (-ve) exception + value is then returned by catch_exceptions. If FUNC() returns + normally (with a postive or zero return value) then that value is + returned by catch_exceptions(). It is an internal_error() for + FUNC() to return a negative value. + + For the period of the FUNC() call: UIOUT is installed as the output + builder; ERRSTRING is installed as the error/quit message; and a + new cleanup_chain is established. The old values are restored + before catch_exceptions() returns. -typedef int (catch_errors_ftype) PARAMS ((PTR)); -extern int catch_errors PARAMS ((catch_errors_ftype *, PTR, char *, return_mask)); + FIXME; cagney/2001-08-13: The need to override the global UIOUT + builder variable should just go away. -extern void warning_begin PARAMS ((void)); + This function superseeds catch_errors(). -extern void warning PARAMS ((const char *, ...)) - ATTR_FORMAT(printf, 1, 2); + This function uses SETJMP() and LONGJUMP(). */ + +struct ui_out; +typedef int (catch_exceptions_ftype) (struct ui_out *ui_out, void *args); +extern int catch_exceptions (struct ui_out *uiout, + catch_exceptions_ftype *func, void *func_args, + char *errstring, return_mask mask); + +/* If CATCH_ERRORS_FTYPE throws an error, catch_errors() returns zero + otherwize the result from CATCH_ERRORS_FTYPE is returned. It is + probably useful for CATCH_ERRORS_FTYPE to always return a non-zero + value. It's unfortunate that, catch_errors() does not return an + indication of the exact exception that it caught - quit_flag might + help. + + This function is superseeded by catch_exceptions(). */ + +typedef int (catch_errors_ftype) (PTR); +extern int catch_errors (catch_errors_ftype *, void *, char *, return_mask); + +/* Template to catch_errors() that wraps calls to command + functions. */ + +typedef void (catch_command_errors_ftype) (char *, int); +extern int catch_command_errors (catch_command_errors_ftype *func, char *command, int from_tty, return_mask); + +extern void warning (const char *, ...) ATTR_FORMAT (printf, 1, 2); + +extern void vwarning (const char *, va_list args); /* Global functions from other, non-gdb GNU thingies. Libiberty thingies are no longer declared here. We include libiberty.h above, instead. */ #ifndef GETENV_PROVIDED -extern char *getenv PARAMS ((const char *)); +extern char *getenv (const char *); #endif /* From other system libraries */ @@ -761,11 +1179,6 @@ extern char *getenv PARAMS ((const char *)); #endif #ifdef HAVE_STDLIB_H -#if defined(_MSC_VER) && !defined(__cplusplus) -/* msvc defines these in stdlib.h for c code */ -#undef min -#undef max -#endif #include <stdlib.h> #endif #ifndef min @@ -782,70 +1195,42 @@ extern char *getenv PARAMS ((const char *)); somewhere. */ #ifndef FCLOSE_PROVIDED -extern int fclose PARAMS ((FILE *)); +extern int fclose (FILE *); #endif #ifndef atof -extern double atof PARAMS ((const char *)); /* X3.159-1989 4.10.1.1 */ -#endif - -#ifndef MALLOC_INCOMPATIBLE - -#ifdef NEED_DECLARATION_MALLOC -extern PTR malloc (); -#endif - -#ifdef NEED_DECLARATION_REALLOC -extern PTR realloc (); +extern double atof (const char *); /* X3.159-1989 4.10.1.1 */ #endif -#ifdef NEED_DECLARATION_FREE -extern void free (); -#endif - -#endif /* MALLOC_INCOMPATIBLE */ - /* Various possibilities for alloca. */ #ifndef alloca -# ifdef __GNUC__ -# define alloca __builtin_alloca -# else /* Not GNU C */ -# ifdef HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifdef _AIX - #pragma alloca -# else +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* Not GNU C */ +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#else +#ifdef _AIX +#pragma alloca +#else /* We need to be careful not to declare this in a way which conflicts with bison. Bison never declares it as char *, but under various circumstances (like __hpux) we need to use void *. */ -# if defined (__STDC__) || defined (__hpux) - extern void *alloca (); -# else /* Don't use void *. */ - extern char *alloca (); -# endif /* Don't use void *. */ -# endif /* Not _AIX */ -# endif /* Not HAVE_ALLOCA_H */ -# endif /* Not GNU C */ +extern void *alloca (); +#endif /* Not _AIX */ +#endif /* Not HAVE_ALLOCA_H */ +#endif /* Not GNU C */ #endif /* alloca not defined */ -/* HOST_BYTE_ORDER must be defined to one of these. */ - -#ifdef HAVE_ENDIAN_H -#include <endian.h> -#endif - -#if !defined (BIG_ENDIAN) -#define BIG_ENDIAN 4321 -#endif - -#if !defined (LITTLE_ENDIAN) -#define LITTLE_ENDIAN 1234 -#endif - /* Dynamic target-system-dependent parameters for GDB. */ #include "gdbarch.h" +#if (GDB_MULTI_ARCH == 0) +/* Multi-arch targets _should_ be including "arch-utils.h" directly + into their *-tdep.c file. This is a prop to help old non- + multi-arch targets to continue to compile. */ +#include "arch-utils.h" +#endif /* Static target-system-dependent parameters for GDB. */ @@ -855,46 +1240,6 @@ extern void free (); #define TARGET_CHAR_BIT 8 #endif -/* Number of bits in a short or unsigned short for the target machine. */ -#if !defined (TARGET_SHORT_BIT) -#define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT) -#endif - -/* Number of bits in an int or unsigned int for the target machine. */ -#if !defined (TARGET_INT_BIT) -#define TARGET_INT_BIT (4 * TARGET_CHAR_BIT) -#endif - -/* Number of bits in a long or unsigned long for the target machine. */ -#if !defined (TARGET_LONG_BIT) -#define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT) -#endif - -/* Number of bits in a long long or unsigned long long for the target machine. */ -#if !defined (TARGET_LONG_LONG_BIT) -#define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT) -#endif - -/* Number of bits in a float for the target machine. */ -#if !defined (TARGET_FLOAT_BIT) -#define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT) -#endif - -/* Number of bits in a double for the target machine. */ -#if !defined (TARGET_DOUBLE_BIT) -#define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT) -#endif - -/* Number of bits in a long double for the target machine. */ -#if !defined (TARGET_LONG_DOUBLE_BIT) -#define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT) -#endif - -/* Number of bits in a pointer for the target machine */ -#if !defined (TARGET_PTR_BIT) -#define TARGET_PTR_BIT TARGET_INT_BIT -#endif - /* If we picked up a copy of CHAR_BIT from a configuration file (which may get it by including <limits.h>) then use it to set the number of bits in a host char. If not, use the same size @@ -911,172 +1256,95 @@ extern void free (); from byte/word byte order. */ #if !defined (BITS_BIG_ENDIAN) -#define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BIG_ENDIAN) +#define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) #endif /* In findvar.c. */ -extern LONGEST extract_signed_integer PARAMS ((void *, int)); - -extern ULONGEST extract_unsigned_integer PARAMS ((void *, int)); - -extern int extract_long_unsigned_integer PARAMS ((void *, int, LONGEST *)); +extern LONGEST extract_signed_integer (void *, int); -extern CORE_ADDR extract_address PARAMS ((void *, int)); +extern ULONGEST extract_unsigned_integer (void *, int); -extern void store_signed_integer PARAMS ((PTR, int, LONGEST)); +extern int extract_long_unsigned_integer (void *, int, LONGEST *); -extern void store_unsigned_integer PARAMS ((PTR, int, ULONGEST)); +extern CORE_ADDR extract_address (void *, int); -extern void store_address PARAMS ((PTR, int, LONGEST)); +extern CORE_ADDR extract_typed_address (void *buf, struct type *type); -/* Setup definitions for host and target floating point formats. We need to - consider the format for `float', `double', and `long double' for both target - and host. We need to do this so that we know what kind of conversions need - to be done when converting target numbers to and from the hosts DOUBLEST - data type. */ +extern void store_signed_integer (void *, int, LONGEST); -/* This is used to indicate that we don't know the format of the floating point - number. Typically, this is useful for native ports, where the actual format - is irrelevant, since no conversions will be taking place. */ - -extern const struct floatformat floatformat_unknown; - -#if HOST_BYTE_ORDER == BIG_ENDIAN -# ifndef HOST_FLOAT_FORMAT -# define HOST_FLOAT_FORMAT &floatformat_ieee_single_big -# endif -# ifndef HOST_DOUBLE_FORMAT -# define HOST_DOUBLE_FORMAT &floatformat_ieee_double_big -# endif -#else /* LITTLE_ENDIAN */ -# ifndef HOST_FLOAT_FORMAT -# define HOST_FLOAT_FORMAT &floatformat_ieee_single_little -# endif -# ifndef HOST_DOUBLE_FORMAT -# define HOST_DOUBLE_FORMAT &floatformat_ieee_double_little -# endif -#endif +extern void store_unsigned_integer (void *, int, ULONGEST); -#ifndef HOST_LONG_DOUBLE_FORMAT -#define HOST_LONG_DOUBLE_FORMAT &floatformat_unknown -#endif - -#ifndef TARGET_FLOAT_FORMAT -#define TARGET_FLOAT_FORMAT (TARGET_BYTE_ORDER == BIG_ENDIAN \ - ? &floatformat_ieee_single_big \ - : &floatformat_ieee_single_little) -#endif -#ifndef TARGET_DOUBLE_FORMAT -#define TARGET_DOUBLE_FORMAT (TARGET_BYTE_ORDER == BIG_ENDIAN \ - ? &floatformat_ieee_double_big \ - : &floatformat_ieee_double_little) -#endif - -#ifndef TARGET_LONG_DOUBLE_FORMAT -# define TARGET_LONG_DOUBLE_FORMAT &floatformat_unknown -#endif +extern void store_address (void *, int, LONGEST); -/* Use `long double' if the host compiler supports it. (Note that this is not - necessarily any longer than `double'. On SunOS/gcc, it's the same as - double.) This is necessary because GDB internally converts all floating - point values to the widest type supported by the host. +extern void store_typed_address (void *buf, struct type *type, CORE_ADDR addr); - There are problems however, when the target `long double' is longer than the - host's `long double'. In general, we'll probably reduce the precision of - any such values and print a warning. */ - -#ifdef HAVE_LONG_DOUBLE -typedef long double DOUBLEST; -#else -typedef double DOUBLEST; -#endif - -extern void floatformat_to_doublest PARAMS ((const struct floatformat *, - char *, DOUBLEST *)); -extern void floatformat_from_doublest PARAMS ((const struct floatformat *, - DOUBLEST *, char *)); -extern DOUBLEST extract_floating PARAMS ((void *, int)); - -extern void store_floating PARAMS ((void *, int, DOUBLEST)); -/* On some machines there are bits in addresses which are not really - part of the address, but are used by the kernel, the hardware, etc. - for special purposes. ADDR_BITS_REMOVE takes out any such bits - so we get a "real" address such as one would find in a symbol - table. This is used only for addresses of instructions, and even then - I'm not sure it's used in all contexts. It exists to deal with there - being a few stray bits in the PC which would mislead us, not as some sort - of generic thing to handle alignment or segmentation (it's possible it - should be in TARGET_READ_PC instead). */ -#if !defined (ADDR_BITS_REMOVE) -#define ADDR_BITS_REMOVE(addr) (addr) -#endif /* No ADDR_BITS_REMOVE. */ - /* From valops.c */ -extern CORE_ADDR push_bytes PARAMS ((CORE_ADDR, char *, int)); - -extern CORE_ADDR push_word PARAMS ((CORE_ADDR, ULONGEST)); +extern CORE_ADDR push_bytes (CORE_ADDR, char *, int); -/* Some parts of gdb might be considered optional, in the sense that they - are not essential for being able to build a working, usable debugger - for a specific environment. For example, the maintenance commands - are there for the benefit of gdb maintainers. As another example, - some environments really don't need gdb's that are able to read N - different object file formats. In order to make it possible (but - not necessarily recommended) to build "stripped down" versions of - gdb, the following defines control selective compilation of those - parts of gdb which can be safely left out when necessary. Note that - the default is to include everything. */ +extern CORE_ADDR push_word (CORE_ADDR, ULONGEST); -#ifndef MAINTENANCE_CMDS -#define MAINTENANCE_CMDS 1 -#endif - -#ifdef MAINTENANCE_CMDS extern int watchdog; -#endif /* Hooks for alternate command interfaces. */ -#ifdef __STDC__ +/* The name of the interpreter if specified on the command line. */ +extern char *interpreter_p; + +/* If a given interpreter matches INTERPRETER_P then it should update + command_loop_hook and init_ui_hook with the per-interpreter + implementation. */ +/* FIXME: command_loop_hook and init_ui_hook should be moved here. */ + struct target_waitstatus; struct cmd_list_element; -#endif -extern void (*init_ui_hook) PARAMS ((char *argv0)); -extern void (*command_loop_hook) PARAMS ((void)); -extern void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, - GDB_FILE *stream)); -extern void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, - int line, int stopline, - int noerror)); -extern struct frame_info *parse_frame_specification PARAMS ((char *frame_exp)); -extern int (*query_hook) PARAMS ((const char *, va_list)); -extern void (*warning_hook) PARAMS ((const char *, va_list)); -extern void (*flush_hook) PARAMS ((GDB_FILE *stream)); -extern void (*create_breakpoint_hook) PARAMS ((struct breakpoint *b)); -extern void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); -extern void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); -extern void (*target_output_hook) PARAMS ((char *)); -extern void (*interactive_hook) PARAMS ((void)); -extern void (*registers_changed_hook) PARAMS ((void)); -extern void (*readline_begin_hook) PARAMS ((char *, ...)); -extern char * (*readline_hook) PARAMS ((char *)); -extern void (*readline_end_hook) PARAMS ((void)); -extern void (*register_changed_hook) PARAMS ((int regno)); -extern void (*memory_changed_hook) PARAMS ((CORE_ADDR addr, int len)); -extern void (*context_hook) PARAMS ((int)); -extern int (*target_wait_hook) PARAMS ((int pid, - struct target_waitstatus *status)); - -extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c, - char *cmd, int from_tty)); - -extern NORETURN void (*error_hook) PARAMS ((void)) ATTR_NORETURN; - -extern void (*error_begin_hook) PARAMS ((void)); +/* Should the asynchronous variant of the interpreter (using the + event-loop) be enabled? */ +extern int event_loop_p; + +extern void (*init_ui_hook) (char *argv0); +extern void (*command_loop_hook) (void); +extern void (*show_load_progress) (const char *section, + unsigned long section_sent, + unsigned long section_size, + unsigned long total_sent, + unsigned long total_size); +extern void (*print_frame_info_listing_hook) (struct symtab * s, + int line, int stopline, + int noerror); +extern struct frame_info *parse_frame_specification (char *frame_exp); +extern int (*query_hook) (const char *, va_list); +extern void (*warning_hook) (const char *, va_list); +extern void (*flush_hook) (struct ui_file * stream); +extern void (*create_breakpoint_hook) (struct breakpoint * b); +extern void (*delete_breakpoint_hook) (struct breakpoint * bpt); +extern void (*modify_breakpoint_hook) (struct breakpoint * bpt); +extern void (*interactive_hook) (void); +extern void (*registers_changed_hook) (void); +extern void (*readline_begin_hook) (char *,...); +extern char *(*readline_hook) (char *); +extern void (*readline_end_hook) (void); +extern void (*register_changed_hook) (int regno); +extern void (*memory_changed_hook) (CORE_ADDR addr, int len); +extern void (*context_hook) (int); +extern ptid_t (*target_wait_hook) (ptid_t ptid, + struct target_waitstatus * status); + +extern void (*attach_hook) (void); +extern void (*detach_hook) (void); +extern void (*call_command_hook) (struct cmd_list_element * c, + char *cmd, int from_tty); + +extern void (*set_hook) (struct cmd_list_element * c); + +extern NORETURN void (*error_hook) (void) ATTR_NORETURN; + +extern void (*error_begin_hook) (void); + +extern int (*ui_load_progress_hook) (const char *section, unsigned long num); /* Inhibit window interface if non-zero. */ @@ -1091,49 +1359,42 @@ extern int use_windows; #define DIRNAME_SEPARATOR ':' #endif -#ifndef SLASH_P -#if defined(__GO32__)||defined(_WIN32) -#define SLASH_P(X) ((X)=='\\') -#else -#define SLASH_P(X) ((X)=='/') -#endif -#endif - -#ifndef SLASH_CHAR -#if defined(__GO32__)||defined(_WIN32) -#define SLASH_CHAR '\\' -#else -#define SLASH_CHAR '/' -#endif -#endif - #ifndef SLASH_STRING -#if defined(__GO32__)||defined(_WIN32) -#define SLASH_STRING "\\" -#else #define SLASH_STRING "/" #endif -#endif -#ifndef ROOTED_P -#define ROOTED_P(X) (SLASH_P((X)[0])) +#ifdef __MSDOS__ +# define CANT_FORK +# define GLOBAL_CURDIR #endif -/* On some systems, PIDGET is defined to extract the inferior pid from - an internal pid that has the thread id and pid in seperate bit - fields. If not defined, then just use the entire internal pid as - the actual pid. */ +/* Provide default definitions of PIDGET, TIDGET, and MERGEPID. + The name ``TIDGET'' is a historical accident. Many uses of TIDGET + in the code actually refer to a lightweight process id, i.e, + something that can be considered a process id in its own right for + certain purposes. */ #ifndef PIDGET -#define PIDGET(pid) (pid) +#define PIDGET(PTID) (ptid_get_pid (PTID)) +#define TIDGET(PTID) (ptid_get_lwp (PTID)) +#define MERGEPID(PID, TID) ptid_build (PID, TID, 0) #endif -/* If under Cygwin, provide backwards compatibility with older - Cygwin compilers that don't define the current cpp define. */ -#ifdef __CYGWIN32__ -#ifndef __CYGWIN__ -#define __CYGWIN__ +/* Define well known filenos if the system does not define them. */ +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 #endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) #endif #endif /* #ifndef DEFS_H */ diff --git a/contrib/gdb/gdb/demangle.c b/contrib/gdb/gdb/demangle.c index 6b1555f..1fd69be 100644 --- a/contrib/gdb/gdb/demangle.c +++ b/contrib/gdb/gdb/demangle.c @@ -1,5 +1,6 @@ /* Basic C++ demangling support for GDB. - Copyright 1991, 1992, 1996, 1999 Free Software Foundation, Inc. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. Written by Fred Fish at Cygnus Support. This file is part of GDB. @@ -16,7 +17,8 @@ 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. */ + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ /* This file contains support code for C++ demangling that is common @@ -40,68 +42,20 @@ #define DEFAULT_DEMANGLING_STYLE AUTO_DEMANGLING_STYLE_STRING #endif +extern void _initialize_demangler (void); + /* String name for the current demangling style. Set by the "set demangle-style" command, printed as part of the output by the "show demangle-style" command. */ static char *current_demangling_style_string; -/* List of supported demangling styles. Contains the name of the style as - seen by the user, and the enum value that corresponds to that style. */ +/* The array of names of the known demanglyng styles. Generated by + _initialize_demangler from libiberty_demanglers[] array. */ -static const struct demangler - { - char *demangling_style_name; - enum demangling_styles demangling_style; - char *demangling_style_doc; - } -demanglers[] = -{ - { - AUTO_DEMANGLING_STYLE_STRING, - auto_demangling, - "Automatic selection based on executable" - } - , - { - GNU_DEMANGLING_STYLE_STRING, - gnu_demangling, - "GNU (g++) style demangling" - } - , - { - LUCID_DEMANGLING_STYLE_STRING, - lucid_demangling, - "Lucid (lcc) style demangling" - } - , - { - ARM_DEMANGLING_STYLE_STRING, - arm_demangling, - "ARM style demangling" - } - , -#if 0 /* XXX remove when binutils 2.9.2 is imported */ - { - HP_DEMANGLING_STYLE_STRING, - hp_demangling, - "HP (aCC) style demangling" - } - , - { - EDG_DEMANGLING_STYLE_STRING, - edg_demangling, - "EDG style demangling" - } - , -#endif - { - NULL, unknown_demangling, NULL - } -}; +static const char **demangling_style_names; -static void -set_demangling_command PARAMS ((char *, int, struct cmd_list_element *)); +static void set_demangling_command (char *, int, struct cmd_list_element *); /* Set current demangling style. Called by the "set demangle-style" command after it has updated the current_demangling_style_string to @@ -120,19 +74,18 @@ set_demangling_command PARAMS ((char *, int, struct cmd_list_element *)); a malloc'd string, even if it is a null-string. */ static void -set_demangling_command (ignore, from_tty, c) - char *ignore; - int from_tty; - struct cmd_list_element *c; +set_demangling_command (char *ignore, int from_tty, struct cmd_list_element *c) { - const struct demangler *dem; + const struct demangler_engine *dem; /* First just try to match whatever style name the user supplied with one of the known ones. Don't bother special casing for an empty name, we just treat it as any other style name that doesn't match. If we match, update the current demangling style enum. */ - for (dem = demanglers; dem->demangling_style_name != NULL; dem++) + for (dem = libiberty_demanglers; + dem->demangling_style != unknown_demangling; + dem++) { if (STREQ (current_demangling_style_string, dem->demangling_style_name)) @@ -146,7 +99,7 @@ set_demangling_command (ignore, from_tty, c) style name and supply a list of valid ones. FIXME: This should probably be done with some sort of completion and with help. */ - if (dem->demangling_style_name == NULL) + if (dem->demangling_style == unknown_demangling) { if (*current_demangling_style_string != '\0') { @@ -154,13 +107,15 @@ set_demangling_command (ignore, from_tty, c) current_demangling_style_string); } printf_unfiltered ("The currently understood settings are:\n\n"); - for (dem = demanglers; dem->demangling_style_name != NULL; dem++) + for (dem = libiberty_demanglers; + dem->demangling_style != unknown_demangling; + dem++) { printf_unfiltered ("%-10s %s\n", dem->demangling_style_name, dem->demangling_style_doc); if (dem->demangling_style == current_demangling_style) { - free (current_demangling_style_string); + xfree (current_demangling_style_string); current_demangling_style_string = savestring (dem->demangling_style_name, strlen (dem->demangling_style_name)); @@ -171,10 +126,11 @@ set_demangling_command (ignore, from_tty, c) /* This can happen during initialization if gdb is compiled with a DEMANGLING_STYLE value that is unknown, so pick the first one as the default. */ - current_demangling_style = demanglers[0].demangling_style; + current_demangling_style = libiberty_demanglers[0].demangling_style; current_demangling_style_string = - savestring (demanglers[0].demangling_style_name, - strlen (demanglers[0].demangling_style_name)); + savestring ( + libiberty_demanglers[0].demangling_style_name, + strlen (libiberty_demanglers[0].demangling_style_name)); warning ("`%s' style demangling chosen as the default.\n", current_demangling_style_string); } @@ -184,12 +140,11 @@ set_demangling_command (ignore, from_tty, c) /* Fake a "set demangle-style" command. */ void -set_demangling_style (style) - char *style; +set_demangling_style (char *style) { if (current_demangling_style_string != NULL) { - free (current_demangling_style_string); + xfree (current_demangling_style_string); } current_demangling_style_string = savestring (style, strlen (style)); set_demangling_command ((char *) NULL, 0, (struct cmd_list_element *) NULL); @@ -211,27 +166,41 @@ set_demangling_style (style) ensuring that it is the character that terminates the gcc<n>_compiled marker symbol (FIXME). */ -static char cplus_markers[] = {CPLUS_MARKER, '.', '$', '\0'}; +static char cplus_markers[] = +{CPLUS_MARKER, '.', '$', '\0'}; int -is_cplus_marker (c) - int c; +is_cplus_marker (int c) { return c && strchr (cplus_markers, c) != NULL; } void -_initialize_demangler () +_initialize_demangler (void) { struct cmd_list_element *set, *show; - - set = add_set_cmd ("demangle-style", class_support, var_string_noescape, - (char *) ¤t_demangling_style_string, - "Set the current C++ demangling style.\n\ + int i, ndems; + + /* Fill the demangling_style_names[] array. */ + for (ndems = 0; + libiberty_demanglers[ndems].demangling_style != unknown_demangling; + ndems++) + ; + demangling_style_names = xcalloc (ndems + 1, sizeof (char *)); + for (i = 0; + libiberty_demanglers[i].demangling_style != unknown_demangling; + i++) + demangling_style_names[i] = + xstrdup (libiberty_demanglers[i].demangling_style_name); + + set = add_set_enum_cmd ("demangle-style", class_support, + demangling_style_names, + (const char **) ¤t_demangling_style_string, + "Set the current C++ demangling style.\n\ Use `set demangle-style' without arguments for a list of demangling styles.", - &setlist); + &setlist); show = add_show_from_set (set, &showlist); - set->function.sfunc = set_demangling_command; + set_cmd_sfunc (set, set_demangling_command); /* Set the default demangling style chosen at compilation time. */ set_demangling_style (DEFAULT_DEMANGLING_STYLE); diff --git a/contrib/gdb/gdb/doc/gdb.texinfo b/contrib/gdb/gdb/doc/gdb.texinfo index 127da78..04a0624 100644 --- a/contrib/gdb/gdb/doc/gdb.texinfo +++ b/contrib/gdb/gdb/doc/gdb.texinfo @@ -1,20 +1,16 @@ \input texinfo @c -*-texinfo-*- -@c Copyright 1988-1999 +@c Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, +@c 1999, 2000, 2001, 2002 @c Free Software Foundation, Inc. @c -@c %**start of header +@c %**start of header @c makeinfo ignores cmds prev to setfilename, so its arg cannot make use @c of @set vars. However, you can override filename with makeinfo -o. @setfilename gdb.info @c @include gdb-cfg.texi @c -@ifset GENERIC @settitle Debugging with @value{GDBN} -@end ifset -@ifclear GENERIC -@settitle Debugging with @value{GDBN} (@value{TARGET}) -@end ifclear @setchapternewpage odd @c %**end of header @@ -26,134 +22,104 @@ @finalout @syncodeindex ky cp -@c readline appendices use @vindex +@c readline appendices use @vindex, @findex and @ftable, +@c annotate.texi and gdbmi use @findex. @syncodeindex vr cp +@syncodeindex fn cp @c !!set GDB manual's edition---not the same as GDB version! -@set EDITION Seventh +@set EDITION Ninth @c !!set GDB manual's revision date -@set DATE February 1999 +@set DATE December 2001 -@c THIS MANUAL REQUIRES TEXINFO-2 macros and info-makers to format properly. +@c THIS MANUAL REQUIRES TEXINFO 4.0 OR LATER. -@ifinfo @c This is a dir.info fragment to support semi-automated addition of -@c manuals to an info tree. zoo@cygnus.com is developing this facility. -@format -START-INFO-DIR-ENTRY -* Gdb: (gdb). The @sc{gnu} debugger. -END-INFO-DIR-ENTRY -@end format -@end ifinfo -@c -@c +@c manuals to an info tree. +@dircategory Programming & development tools. +@direntry +* Gdb: (gdb). The @sc{gnu} debugger. +@end direntry + @ifinfo This file documents the @sc{gnu} debugger @value{GDBN}. -This is the @value{EDITION} Edition, @value{DATE}, +This is the @value{EDITION} Edition, @value{DATE}, of @cite{Debugging with @value{GDBN}: the @sc{gnu} Source-Level Debugger} for @value{GDBN} Version @value{GDBVN}. -Copyright (C) 1988-1999 Free Software Foundation, Inc. - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -@ignore -Permission is granted to process this file through TeX and print the -results, provided the printed document carries copying permission -notice identical to this one except for the removal of this paragraph -(this paragraph not being relevant to the printed manual). +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,@* + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. -@end ignore -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``Free Software'' and ``Free Software Needs +Free Documentation'', with the Front-Cover Texts being ``A GNU Manual,'' +and with the Back-Cover Texts as in (a) below. -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions. +(a) The Free Software Foundation's Back-Cover Text is: ``You have +freedom to copy and modify this GNU Manual, like GNU software. Copies +published by the Free Software Foundation raise funds for GNU +development.'' @end ifinfo @titlepage @title Debugging with @value{GDBN} @subtitle The @sc{gnu} Source-Level Debugger -@ifclear GENERIC -@subtitle (@value{TARGET}) -@end ifclear @sp 1 -@ifclear HPPA @subtitle @value{EDITION} Edition, for @value{GDBN} version @value{GDBVN} @subtitle @value{DATE} -@author Richard M. Stallman and Roland H. Pesch -@end ifclear -@ifset HPPA -@subtitle Edition @value{EDITION}, for @value{HPVER} (based on @value{GDBN} @value{GDBVN}) -@subtitle @value{DATE} -@author Richard M. Stallman and Roland H. Pesch (modified by HP) -@end ifset +@author Richard Stallman, Roland Pesch, Stan Shebs, et al. @page -@ifclear HPPA -@tex -{\parskip=0pt -\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@prep.ai.mit.edu.)\par -\hfill {\it Debugging with @value{GDBN}}\par -\hfill \TeX{}info \texinfoversion\par -} -@end tex -@end ifclear -@ifset HPPA @tex {\parskip=0pt +\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@gnu.org.)\par \hfill {\it Debugging with @value{GDBN}}\par \hfill \TeX{}info \texinfoversion\par } @end tex -@end ifset @vskip 0pt plus 1filll -Copyright @copyright{} 1988-1999 Free Software Foundation, Inc. +Copyright @copyright{} 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, +1996, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. @sp 2 -@ifclear HPPA Published by the Free Software Foundation @* 59 Temple Place - Suite 330, @* Boston, MA 02111-1307 USA @* -Printed copies are available for $20 each. @* -ISBN 1-882114-11-6 @* -@end ifclear - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions. +ISBN 1-882114-77-9 @* + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``Free Software'' and ``Free Software Needs +Free Documentation'', with the Front-Cover Texts being ``A GNU Manual,'' +and with the Back-Cover Texts as in (a) below. + +(a) The Free Software Foundation's Back-Cover Text is: ``You have +freedom to copy and modify this GNU Manual, like GNU software. Copies +published by the Free Software Foundation raise funds for GNU +development.'' @end titlepage @page -@ifinfo +@ifnottex @node Top, Summary, (dir), (dir) + @top Debugging with @value{GDBN} This file describes @value{GDBN}, the @sc{gnu} symbolic debugger. -This is the @value{EDITION} Edition, @value{DATE}, for @value{GDBN} Version +This is the @value{EDITION} Edition, @value{DATE}, for @value{GDBN} Version @value{GDBVN}. -Copyright (C) 1988-1999 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. + @menu * Summary:: Summary of @value{GDBN} -@ifclear BARETARGET * Sample Session:: A sample @value{GDBN} session -@end ifclear * Invocation:: Getting in and out of @value{GDBN} * Commands:: @value{GDBN} commands @@ -162,288 +128,43 @@ Copyright (C) 1988-1999 Free Software Foundation, Inc. * Stack:: Examining the stack * Source:: Examining source files * Data:: Examining data -@ifclear CONLY -* Languages:: Using @value{GDBN} with different languages -@end ifclear +* Tracepoints:: Debugging remote targets non-intrusively +* Overlays:: Debugging programs that use overlays -@ifset CONLY -* C:: C language support -@end ifset +* Languages:: Using @value{GDBN} with different languages * Symbols:: Examining the symbol table * Altering:: Altering execution * GDB Files:: @value{GDBN} files * Targets:: Specifying a debugging target +* Remote Debugging:: Debugging remote programs +* Configurations:: Configuration-specific information * Controlling GDB:: Controlling @value{GDBN} * Sequences:: Canned sequences of commands -@ifclear DOSHOST +* TUI:: @value{GDBN} Text User Interface * Emacs:: Using @value{GDBN} under @sc{gnu} Emacs -@end ifclear +* Annotations:: @value{GDBN}'s annotation interface. +* GDB/MI:: @value{GDBN}'s Machine Interface. * GDB Bugs:: Reporting bugs in @value{GDBN} - -@ifclear PRECONFIGURED -@ifclear HPPA * Formatting Documentation:: How to format and print @value{GDBN} documentation -@end ifclear - -@end ifclear * Command Line Editing:: Command Line Editing * Using History Interactively:: Using History Interactively * Installing GDB:: Installing GDB +* Maintenance Commands:: Maintenance Commands +* Remote Protocol:: GDB Remote Serial Protocol +* Copying:: GNU General Public License says + how you can copy and share GDB +* GNU Free Documentation License:: The license for this documentation * Index:: Index - - --- The Detailed Node Listing --- - -Summary of @value{GDBN} - -* Free Software:: Freely redistributable software -* Contributors:: Contributors to GDB - -Getting In and Out of @value{GDBN} - -* Invoking GDB:: How to start @value{GDBN} -* Quitting GDB:: How to quit @value{GDBN} -* Shell Commands:: How to use shell commands inside @value{GDBN} - -Invoking @value{GDBN} - -* File Options:: Choosing files -* Mode Options:: Choosing modes - -@value{GDBN} Commands - -* Command Syntax:: How to give commands to @value{GDBN} -* Completion:: Command completion -* Help:: How to ask @value{GDBN} for help - -Running Programs Under @value{GDBN} - -* Compilation:: Compiling for debugging -* Starting:: Starting your program -@ifclear BARETARGET -* Arguments:: Your program's arguments -* Environment:: Your program's environment -@end ifclear - -* Working Directory:: Your program's working directory -* Input/Output:: Your program's input and output -* Attach:: Debugging an already-running process -* Kill Process:: Killing the child process -@ifclear HPPA -* Process Information:: Additional process information -@end ifclear - -* Threads:: Debugging programs with multiple threads -* Processes:: Debugging programs with multiple processes - -Stopping and Continuing - -* Breakpoints:: Breakpoints, watchpoints, and catchpoints -* Continuing and Stepping:: Resuming execution -@ifset POSIX -* Signals:: Signals -@end ifset -@ifclear BARETARGET -* Thread Stops:: Stopping and starting multi-thread programs -@end ifclear - -Breakpoints and watchpoints - -* Set Breaks:: Setting breakpoints -* Set Watchpoints:: Setting watchpoints -* Set Catchpoints:: Setting catchpoints -* Delete Breaks:: Deleting breakpoints -* Disabling:: Disabling breakpoints -* Conditions:: Break conditions -* Break Commands:: Breakpoint command lists -@ifclear CONLY -* Breakpoint Menus:: Breakpoint menus -@end ifclear - -Examining the Stack - -* Frames:: Stack frames -* Backtrace:: Backtraces -* Selection:: Selecting a frame -* Frame Info:: Information on a frame -* Alpha/MIPS Stack:: Alpha and MIPS machines and the function stack - -Examining Source Files - -* List:: Printing source lines -@ifclear DOSHOST -* Search:: Searching source files -@end ifclear -* Source Path:: Specifying source directories -* Machine Code:: Source and machine code - -Examining Data - -* Expressions:: Expressions -* Variables:: Program variables -* Arrays:: Artificial arrays -* Output Formats:: Output formats -* Memory:: Examining memory -* Auto Display:: Automatic display -* Print Settings:: Print settings -* Value History:: Value history -* Convenience Vars:: Convenience variables -* Registers:: Registers -@ifclear HAVE-FLOAT -* Floating Point Hardware:: Floating point hardware -@end ifclear - -Using @value{GDBN} with Different Languages - -* Setting:: Switching between source languages -* Show:: Displaying the language -@ifset MOD2 -* Checks:: Type and range checks -@end ifset - -* Support:: Supported languages - -Switching between source languages - -* Filenames:: Filename extensions and languages. -* Manually:: Setting the working language manually -* Automatically:: Having @value{GDBN} infer the source language - -@ifset MOD2 -Type and range checking - -* Type Checking:: An overview of type checking -* Range Checking:: An overview of range checking -@end ifset - -Supported languages - -@ifset MOD2 -* C:: C and C++ - -C Language Support - -* C Operators:: C operators - -C Language Support -@end ifset - -* C Operators:: C and C++ operators -* C Constants:: C and C++ constants -* Cplus expressions:: C++ expressions -* C Defaults:: Default settings for C and C++ -@ifset MOD2 -* C Checks:: C and C++ type and range checks -@end ifset -* Debugging C:: @value{GDBN} and C -* Debugging C plus plus:: @value{GDBN} features for C++ - -@ifset MOD2 -Modula-2 - -* M2 Operators:: Built-in operators -* Built-In Func/Proc:: Built-in functions and procedures -* M2 Constants:: Modula-2 constants -* M2 Defaults:: Default settings for Modula-2 -* Deviations:: Deviations from standard Modula-2 -* M2 Checks:: Modula-2 type and range checks -* M2 Scope:: The scope operators @code{::} and @code{.} -* GDB/M2:: @value{GDBN} and Modula-2 -@end ifset - -Altering Execution - -* Assignment:: Assignment to variables -* Jumping:: Continuing at a different address -@ifclear BARETARGET -* Signaling:: Giving your program a signal -@end ifclear -* Returning:: Returning from a function -* Calling:: Calling your program's functions -* Patching:: Patching your program - -@value{GDBN} Files - -* Files:: Commands to specify files -* Symbol Errors:: Errors reading symbol files - -Specifying a Debugging Target - -* Active Targets:: Active targets -* Target Commands:: Commands for managing targets -@ifclear HPPA -* Byte Order:: Choosing target byte order -* Remote:: Remote debugging - -Remote debugging -@end ifclear - -@ifset REMOTESTUB -* Remote Serial:: @value{GDBN} remote serial protocol -@end ifset - -@ifset I960 -* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) -@end ifset - -@ifset AMD29K -* UDI29K Remote:: The UDI protocol for AMD29K -* EB29K Remote:: The EBMON protocol for AMD29K -@end ifset - -@ifset VXWORKS -* VxWorks Remote:: @value{GDBN} and VxWorks -@end ifset - -@ifset ST2000 -* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 -@end ifset - -@ifset H8 -* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors -@end ifset - -@ifset MIPS -* MIPS Remote:: @value{GDBN} and MIPS boards -@end ifset - -@ifset SIMS -* Simulator:: Simulated CPU target -@end ifset - -Controlling @value{GDBN} - -* Prompt:: Prompt -* Editing:: Command editing -* History:: Command history -* Screen Size:: Screen size -* Numbers:: Numbers -* Messages/Warnings:: Optional warnings and messages - -Canned Sequences of Commands - -* Define:: User-defined commands -* Hooks:: User-defined command hooks -* Command Files:: Command files -* Output:: Commands for controlled output - -Reporting Bugs in @value{GDBN} - -* Bug Criteria:: Have you found a bug? -* Bug Reporting:: How to report bugs - -Installing @value{GDBN} - -* Separate Objdir:: Compiling @value{GDBN} in another directory -* Config Names:: Specifying names for hosts and targets -* Configure Options:: Summary of options for configure @end menu -@end ifinfo +@end ifnottex + +@contents -@node Summary, Sample Session, Top, Top +@node Summary @unnumbered Summary of @value{GDBN} The purpose of a debugger such as @value{GDBN} is to allow you to see what is @@ -468,51 +189,35 @@ Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another. @end itemize -@ifclear CONLY -You can use @value{GDBN} to debug programs written in C or C++. -@c "MOD2" used as a "miscellaneous languages" flag here. -@c This is acceptable while there is no real doc for Chill and Pascal. -@ifclear MOD2 +You can use @value{GDBN} to debug programs written in C and C++. For more information, see @ref{Support,,Supported languages}. -@end ifclear -@ifset MOD2 For more information, see @ref{C,,C and C++}. +@cindex Chill +@cindex Modula-2 Support for Modula-2 and Chill is partial. For information on Modula-2, -see @ref{Modula-2,,Modula-2}. There is no further documentation on Chill yet. +see @ref{Modula-2,,Modula-2}. For information on Chill, see @ref{Chill}. -Debugging Pascal programs which use sets, subranges, file variables, or nested -functions does not currently work. @value{GDBN} does not support -entering expressions, printing values, or similar features using Pascal syntax. -@end ifset +@cindex Pascal +Debugging Pascal programs which use sets, subranges, file variables, or +nested functions does not currently work. @value{GDBN} does not support +entering expressions, printing values, or similar features using Pascal +syntax. -@ifset FORTRAN @cindex Fortran @value{GDBN} can be used to debug programs written in Fortran, although -it does not yet support entering expressions, printing values, or -similar features using Fortran syntax. It may be necessary to refer to -some variables with a trailing underscore. -@end ifset -@end ifclear - -@ifset HPPA -This version of the manual documents HP Wildebeest (WDB) Version 0.75, -implemented on HP 9000 systems running Release 10.20, 10.30, or 11.0 of -the HP-UX operating system. HP WDB 0.75 can be used to debug code -generated by the HP ANSI C and HP ANSI C++ compilers as well as the -@sc{gnu} C and C++ compilers. It does not support the debugging of -Fortran, Modula-2, or Chill programs. -@end ifset +it may be necessary to refer to some variables with a trailing +underscore. @menu * Free Software:: Freely redistributable software * Contributors:: Contributors to GDB @end menu -@node Free Software, Contributors, Summary, Summary +@node Free Software @unnumberedsec Free software -@value{GDBN} is @dfn{free software}, protected by the @sc{gnu} +@value{GDBN} is @dfn{free software}, protected by the @sc{gnu} General Public License (GPL). The GPL gives you the freedom to copy or adapt a licensed program---but every person getting a copy also gets with it the @@ -525,15 +230,105 @@ Fundamentally, the General Public License is a license which says that you have these freedoms and that you cannot take these freedoms away from anyone else. -@node Contributors, , Free Software, Summary -@unnumberedsec Contributors to GDB - -Richard Stallman was the original author of GDB, and of many other -@sc{gnu} programs. Many others have contributed to its development. -This section attempts to credit major contributors. One of the virtues -of free software is that everyone is free to contribute to it; with -regret, we cannot actually acknowledge everyone here. The file -@file{ChangeLog} in the @value{GDBN} distribution approximates a +@unnumberedsec Free Software Needs Free Documentation + +The biggest deficiency in the free software community today is not in +the software---it is the lack of good free documentation that we can +include with the free software. Many of our most important +programs do not come with free reference manuals and free introductory +texts. Documentation is an essential part of any software package; +when an important free software package does not come with a free +manual and a free tutorial, that is a major gap. We have many such +gaps today. + +Consider Perl, for instance. The tutorial manuals that people +normally use are non-free. How did this come about? Because the +authors of those manuals published them with restrictive terms---no +copying, no modification, source files not available---which exclude +them from the free software world. + +That wasn't the first time this sort of thing happened, and it was far +from the last. Many times we have heard a GNU user eagerly describe a +manual that he is writing, his intended contribution to the community, +only to learn that he had ruined everything by signing a publication +contract to make it non-free. + +Free documentation, like free software, is a matter of freedom, not +price. The problem with the non-free manual is not that publishers +charge a price for printed copies---that in itself is fine. (The Free +Software Foundation sells printed copies of manuals, too.) The +problem is the restrictions on the use of the manual. Free manuals +are available in source code form, and give you permission to copy and +modify. Non-free manuals do not allow this. + +The criteria of freedom for a free manual are roughly the same as for +free software. Redistribution (including the normal kinds of +commercial redistribution) must be permitted, so that the manual can +accompany every copy of the program, both on-line and on paper. + +Permission for modification of the technical content is crucial too. +When people modify the software, adding or changing features, if they +are conscientious they will change the manual too---so they can +provide accurate and clear documentation for the modified program. A +manual that leaves you no choice but to write a new manual to document +a changed version of the program is not really available to our +community. + +Some kinds of limits on the way modification is handled are +acceptable. For example, requirements to preserve the original +author's copyright notice, the distribution terms, or the list of +authors, are ok. It is also no problem to require modified versions +to include notice that they were modified. Even entire sections that +may not be deleted or changed are acceptable, as long as they deal +with nontechnical topics (like this one). These kinds of restrictions +are acceptable because they don't obstruct the community's normal use +of the manual. + +However, it must be possible to modify all the @emph{technical} +content of the manual, and then distribute the result in all the usual +media, through all the usual channels. Otherwise, the restrictions +obstruct the use of the manual, it is not free, and we need another +manual to replace it. + +Please spread the word about this issue. Our community continues to +lose manuals to proprietary publishing. If we spread the word that +free software needs free reference manuals and free tutorials, perhaps +the next person who wants to contribute by writing documentation will +realize, before it is too late, that only free manuals contribute to +the free software community. + +If you are writing documentation, please insist on publishing it under +the GNU Free Documentation License or another free documentation +license. Remember that this decision requires your approval---you +don't have to let the publisher decide. Some commercial publishers +will use a free license if you insist, but they will not propose the +option; it is up to you to raise the issue and say firmly that this is +what you want. If the publisher you are dealing with refuses, please +try other publishers. If you're not sure whether a proposed license +is free, write to @email{licensing@@gnu.org}. + +You can encourage commercial publishers to sell more free, copylefted +manuals and tutorials by buying them, and particularly by buying +copies from the publishers that paid for their writing or for major +improvements. Meanwhile, try to avoid buying non-free documentation +at all. Check the distribution terms of a manual before you buy it, +and insist that whoever seeks your business must respect your freedom. +Check the history of the book, and try to reward the publishers that +have paid or pay the authors to work on it. + +The Free Software Foundation maintains a list of free documentation +published by other publishers, at +@url{http://www.fsf.org/doc/other-free-books.html}. + +@node Contributors +@unnumberedsec Contributors to @value{GDBN} + +Richard Stallman was the original author of @value{GDBN}, and of many +other @sc{gnu} programs. Many others have contributed to its +development. This section attempts to credit major contributors. One +of the virtues of free software is that everyone is free to contribute +to it; with regret, we cannot actually acknowledge everyone here. The +file @file{ChangeLog} in the @value{GDBN} distribution approximates a blow-by-blow account. Changes much prior to version 2.0 are lost in the mists of time. @@ -547,6 +342,7 @@ omitted from this list, we would like to add your names! So that they may not regard their many labors as thankless, we particularly thank those who shepherded @value{GDBN} through major releases: +Andrew Cagney (releases 5.0 and 5.1); Jim Blandy (release 4.18); Jason Molenda (release 4.17); Stan Shebs (release 4.14); @@ -559,21 +355,20 @@ and Randy Smith (releases 3.2, 3.1, and 3.0). Richard Stallman, assisted at various times by Peter TerMaat, Chris Hanson, and Richard Mlynarik, handled releases through 2.8. -@ifclear CONLY -Michael Tiemann is the author of most of the @sc{gnu} C++ support in GDB, -with significant additional contributions from Per Bothner. James -Clark wrote the @sc{gnu} C++ demangler. Early work on C++ was by Peter -TerMaat (who also did much general update work leading to release 3.0). -@end ifclear +Michael Tiemann is the author of most of the @sc{gnu} C@t{++} support +in @value{GDBN}, with significant additional contributions from Per +Bothner and Daniel Berlin. James Clark wrote the @sc{gnu} C@t{++} +demangler. Early work on C@t{++} was by Peter TerMaat (who also did +much general update work leading to release 3.0). -@value{GDBN} 4 uses the BFD subroutine library to examine multiple +@value{GDBN} uses the BFD subroutine library to examine multiple object-file formats; BFD was a joint project of David V. Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore. David Johnson wrote the original COFF support; Pace Willison did the original support for encapsulated COFF. -Brent Benson of Harris Computer Systems contributed DWARF 2 support. +Brent Benson of Harris Computer Systems contributed DWARF2 support. Adam de Boor and Bradley Davis contributed the ISI Optimum V support. Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS @@ -610,17 +405,12 @@ and RDI targets, respectively. Brian Fox is the author of the readline libraries providing command-line editing and command history. -Andrew Beers of SUNY Buffalo wrote the language-switching code, -@ifset MOD2 -the Modula-2 support, -@end ifset -and contributed the Languages chapter of this manual. +Andrew Beers of SUNY Buffalo wrote the language-switching code, the +Modula-2 support, and contributed the Languages chapter of this manual. -Fred Fish wrote most of the support for Unix System Vr4. -@ifclear CONLY -He also enhanced the command-completion support to cover C++ overloaded +Fred Fish wrote most of the support for Unix System Vr4. +He also enhanced the command-completion support to cover C@t{++} overloaded symbols. -@end ifclear Hitachi America, Ltd. sponsored the support for H8/300, H8/500, and Super-H processors. @@ -633,7 +423,7 @@ Toshiba sponsored the support for the TX39 Mips processor. Matsushita sponsored the support for the MN10200 and MN10300 processors. -Fujitsu sponsored the support for SPARClite and FR30 processors +Fujitsu sponsored the support for SPARClite and FR30 processors. Kung Hsu, Jeff Law, and Rick Sladkey added support for hardware watchpoints. @@ -643,35 +433,37 @@ Michael Snyder added support for tracepoints. Stu Grossman wrote gdbserver. Jim Kingdon, Peter Schauer, Ian Taylor, and Stu Grossman made -nearly innumerable bug fixes and cleanups throughout GDB. +nearly innumerable bug fixes and cleanups throughout @value{GDBN}. The following people at the Hewlett-Packard Company contributed support for the PA-RISC 2.0 architecture, HP-UX 10.20, 10.30, and 11.0 -(narrow mode), HP's implementation of kernel threads, HP's aC++ +(narrow mode), HP's implementation of kernel threads, HP's aC@t{++} compiler, and the terminal user interface: Ben Krepp, Richard Title, John Bishop, Susan Macchia, Kathy Mann, Satish Pai, India Paul, Steve Rehrauer, and Elena Zannoni. Kim Haase provided HP-specific information in this manual. -Cygnus Solutions has sponsored GDB maintenance and much of its -development since 1991. Cygnus engineers who have worked on GDB -fulltime include Mark Alexander, Jim Blandy, Per Bothner, Edith Epstein, -Chris Faylor, Fred Fish, Martin Hunt, Jim Ingham, John Gilmore, Stu -Grossman, Kung Hsu, Jim Kingdon, John Metzler, Fernando Nasser, Geoffrey -Noer, Dawn Perchik, Rich Pixley, Zdenek Radouch, Keith Seitz, Stan -Shebs, David Taylor, and Elena Zannoni. In addition, Dave Brolley, Ian -Carmichael, Steve Chamberlain, Nick Clifton, JT Conklin, Stan Cox, DJ -Delorie, Ulrich Drepper, Frank Eigler, Doug Evans, Sean Fagan, David -Henkel-Wallace, Richard Henderson, Jeff Holcomb, Jeff Law, Jim Lemke, -Tom Lord, Bob Manson, Michael Meissner, Jason Merrill, Catherine Moore, -Drew Moseley, Ken Raeburn, Gavin Romig-Koch, Rob Savoye, Jamie Smith, -Mike Stump, Ian Taylor, Angela Thomas, Michael Tiemann, Tom Tromey, Ron -Unrau, Jim Wilson, and David Zuhn have made contributions both large -and small. - - -@ifclear BARETARGET -@node Sample Session, Invocation, Summary, Top +DJ Delorie ported @value{GDBN} to MS-DOS, for the DJGPP project. +Robert Hoehne made significant contributions to the DJGPP port. + +Cygnus Solutions has sponsored @value{GDBN} maintenance and much of its +development since 1991. Cygnus engineers who have worked on @value{GDBN} +fulltime include Mark Alexander, Jim Blandy, Per Bothner, Kevin +Buettner, Edith Epstein, Chris Faylor, Fred Fish, Martin Hunt, Jim +Ingham, John Gilmore, Stu Grossman, Kung Hsu, Jim Kingdon, John Metzler, +Fernando Nasser, Geoffrey Noer, Dawn Perchik, Rich Pixley, Zdenek +Radouch, Keith Seitz, Stan Shebs, David Taylor, and Elena Zannoni. In +addition, Dave Brolley, Ian Carmichael, Steve Chamberlain, Nick Clifton, +JT Conklin, Stan Cox, DJ Delorie, Ulrich Drepper, Frank Eigler, Doug +Evans, Sean Fagan, David Henkel-Wallace, Richard Henderson, Jeff +Holcomb, Jeff Law, Jim Lemke, Tom Lord, Bob Manson, Michael Meissner, +Jason Merrill, Catherine Moore, Drew Moseley, Ken Raeburn, Gavin +Romig-Koch, Rob Savoye, Jamie Smith, Mike Stump, Ian Taylor, Angela +Thomas, Michael Tiemann, Tom Tromey, Ron Unrau, Jim Wilson, and David +Zuhn have made contributions both large and small. + + +@node Sample Session @chapter A Sample @value{GDBN} Session You can use this manual at your leisure to read all about @value{GDBN}. @@ -718,35 +510,19 @@ m4: End of input: 0: fatal error: EOF in string @noindent Let us use @value{GDBN} to try to see what is going on. -@ifclear HPPA @smallexample $ @b{@value{GDBP} m4} @c FIXME: this falsifies the exact text played out, to permit smallbook @c FIXME... format to come out better. @value{GDBN} is free software and you are welcome to distribute copies - of it under certain conditions; type "show copying" to see + of it under certain conditions; type "show copying" to see the conditions. -There is absolutely no warranty for @value{GDBN}; type "show warranty" +There is absolutely no warranty for @value{GDBN}; type "show warranty" for details. @value{GDBN} @value{GDBVN}, Copyright 1999 Free Software Foundation, Inc... (@value{GDBP}) @end smallexample -@end ifclear -@ifset HPPA -@smallexample -$ @b{@value{GDBP} m4} -Wildebeest is free software and you are welcome to distribute copies of -it under certain conditions; type "show copying" to see the conditions. -There is absolutely no warranty for Wildebeest; type "show warranty" -for details. - -Hewlett-Packard Wildebeest 0.75 (based on GDB 4.16) -(built for PA-RISC 1.1 or 2.0, HP-UX 10.20) -Copyright 1996, 1997 Free Software Foundation, Inc. -(@value{GDBP}) -@end smallexample -@end ifset @noindent @value{GDBN} reads only enough symbol data to know where to find the @@ -791,7 +567,7 @@ context where it stops. @smallexample @b{changequote(<QUOTE>,<UNQUOTE>)} -Breakpoint 1, m4_changequote (argc=3, argv=0x33c70) +Breakpoint 1, m4_changequote (argc=3, argv=0x33c70) at builtin.c:879 879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3)) @end smallexample @@ -831,7 +607,7 @@ stack frame for each active subroutine. (@value{GDBP}) @b{bt} #0 set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>") at input.c:530 -#1 0x6344 in m4_changequote (argc=3, argv=0x33c70) +#1 0x6344 in m4_changequote (argc=3, argv=0x33c70) at builtin.c:882 #2 0x8174 in expand_macro (sym=0x33320) at macro.c:242 #3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30) @@ -956,17 +732,16 @@ session with the @value{GDBN} @code{quit} command. @smallexample (@value{GDBP}) @b{quit} @end smallexample -@end ifclear -@node Invocation, Commands, Sample Session, Top +@node Invocation @chapter Getting In and Out of @value{GDBN} This chapter discusses how to start @value{GDBN}, and how to get out of it. -The essentials are: +The essentials are: @itemize @bullet -@item -type @samp{@value{GDBP}} to start GDB. -@item +@item +type @samp{@value{GDBP}} to start @value{GDBN}. +@item type @kbd{quit} or @kbd{C-d} to exit. @end itemize @@ -976,26 +751,18 @@ type @kbd{quit} or @kbd{C-d} to exit. * Shell Commands:: How to use shell commands inside @value{GDBN} @end menu -@node Invoking GDB, Quitting GDB, Invocation, Invocation +@node Invoking GDB @section Invoking @value{GDBN} -@ifset H8EXCLUSIVE -For details on starting up @value{GDBP} as a -remote debugger attached to a Hitachi microprocessor, see @ref{Hitachi -Remote,,@value{GDBN} and Hitachi Microprocessors}. -@end ifset - Invoke @value{GDBN} by running the program @code{@value{GDBP}}. Once started, @value{GDBN} reads commands from the terminal until you tell it to exit. You can also run @code{@value{GDBP}} with a variety of arguments and options, to specify more of your debugging environment at the outset. -@ifset GENERIC The command-line options described here are designed to cover a variety of situations; in some environments, some of these -options may effectively be unavailable. -@end ifset +options may effectively be unavailable. The most usual way to start @value{GDBN} is with one argument, specifying an executable program: @@ -1004,7 +771,6 @@ specifying an executable program: @value{GDBP} @var{program} @end example -@ifclear BARETARGET @noindent You can also start with both an executable program and a core file specified: @@ -1024,15 +790,22 @@ to debug a running process: would attach @value{GDBN} to process @code{1234} (unless you also have a file named @file{1234}; @value{GDBN} does check for a core file first). -@ifclear HPPA Taking advantage of the second command-line argument requires a fairly -complete operating system; when you use @value{GDBN} as a remote debugger -attached to a bare board, there may not be any notion of ``process'', -and there is often no way to get a core dump. -@end ifclear -@end ifclear +complete operating system; when you use @value{GDBN} as a remote +debugger attached to a bare board, there may not be any notion of +``process'', and there is often no way to get a core dump. @value{GDBN} +will warn you if it is unable to attach or to read core dumps. + +You can optionally have @code{@value{GDBP}} pass any arguments after the +executable file to the inferior using @code{--args}. This option stops +option processing. +@example +gdb --args gcc -O2 -c foo.c +@end example +This will cause @code{@value{GDBP}} to debug @code{gcc}, and to set +@code{gcc}'s command-line arguments (@pxref{Arguments}) to @samp{-O2 -c foo.c}. -You can run @code{gdb} without printing the front material, which describes +You can run @code{@value{GDBP}} without printing the front material, which describes @value{GDBN}'s non-warranty, by specifying @code{-silent}: @smallexample @@ -1060,66 +833,30 @@ in sequential order. The order makes a difference when the @menu -@ifclear GENERIC -@ifset REMOTESTUB -* Remote Serial:: @value{GDBN} remote serial protocol -@end ifset -@ifset I960 -* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) -@end ifset -@ifset AMD29K -* UDI29K Remote:: The UDI protocol for AMD29K -* EB29K Remote:: The EBMON protocol for AMD29K -@end ifset -@ifset VXWORKS -* VxWorks Remote:: @value{GDBN} and VxWorks -@end ifset -@ifset ST2000 -* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 -@end ifset -@ifset H8 -* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors -@end ifset -@ifset MIPS -* MIPS Remote:: @value{GDBN} and MIPS boards -@end ifset -@ifset SPARCLET -* Sparclet Remote:: @value{GDBN} and Sparclet boards -@end ifset -@ifset SIMS -* Simulator:: Simulated CPU target -@end ifset -@end ifclear -@c remnant makeinfo bug requires this blank line after *two* end-ifblahs: - * File Options:: Choosing files * Mode Options:: Choosing modes @end menu -@ifclear GENERIC -@ifclear HPPA -@include remote.texi -@end ifclear -@end ifclear - @node File Options @subsection Choosing files -@ifclear BARETARGET When @value{GDBN} starts, it reads any arguments other than options as specifying an executable file and core file (or process ID). This is the same as if the arguments were specified by the @samp{-se} and -@samp{-c} options respectively. (@value{GDBN} reads the first argument -that does not have an associated option flag as equivalent to the -@samp{-se} option followed by that argument; and the second argument -that does not have an associated option flag, if any, as equivalent to -the @samp{-c} option followed by that argument.) -@end ifclear -@ifset BARETARGET -When @value{GDBN} starts, it reads any argument other than options as -specifying an executable file. This is the same as if the argument was -specified by the @samp{-se} option. -@end ifset +@samp{-c} (or @samp{-p} options respectively. (@value{GDBN} reads the +first argument that does not have an associated option flag as +equivalent to the @samp{-se} option followed by that argument; and the +second argument that does not have an associated option flag, if any, as +equivalent to the @samp{-c}/@samp{-p} option followed by that argument.) +If the second argument begins with a decimal digit, @value{GDBN} will +first attempt to attach to it as a process, and if that fails, attempt +to open it as a corefile. If you have a corefile whose name begins with +a digit, you can prevent @value{GDBN} from treating it as a pid by +prefixing it with @file{./}, eg. @file{./12345}. + +If @value{GDBN} has not been configured to included core file support, +such as for most embedded targets, then it will complain about a second +argument and ignore it. Many options have both long and short forms; both are shown in the following list. @value{GDBN} also recognizes the long forms if you truncate @@ -1127,57 +864,68 @@ them, so long as enough of the option is present to be unambiguous. (If you prefer, you can flag option arguments with @samp{--} rather than @samp{-}, though we illustrate the more usual convention.) +@c NOTE: the @cindex entries here use double dashes ON PURPOSE. This +@c way, both those who look for -foo and --foo in the index, will find +@c it. + @table @code @item -symbols @var{file} @itemx -s @var{file} +@cindex @code{--symbols} +@cindex @code{-s} Read symbol table from file @var{file}. @item -exec @var{file} @itemx -e @var{file} -Use file @var{file} as the executable file to execute when -@ifset BARETARGET -appropriate. -@end ifset -@ifclear BARETARGET -appropriate, and for examining pure data in conjunction with a core -dump. -@end ifclear +@cindex @code{--exec} +@cindex @code{-e} +Use file @var{file} as the executable file to execute when appropriate, +and for examining pure data in conjunction with a core dump. @item -se @var{file} +@cindex @code{--se} Read symbol table from file @var{file} and use it as the executable file. -@ifclear BARETARGET @item -core @var{file} @itemx -c @var{file} -Use file @var{file} as a core dump to examine. +@cindex @code{--core} +@cindex @code{-c} +Use file @var{file} as a core dump to examine. @item -c @var{number} -Connect to process ID @var{number}, as with the @code{attach} command -(unless there is a file in core-dump format named @var{number}, in which -case @samp{-c} specifies that file as a core dump to read). -@end ifclear +@item -pid @var{number} +@itemx -p @var{number} +@cindex @code{--pid} +@cindex @code{-p} +Connect to process ID @var{number}, as with the @code{attach} command. +If there is no such process, @value{GDBN} will attempt to open a core +file named @var{number}. @item -command @var{file} @itemx -x @var{file} +@cindex @code{--command} +@cindex @code{-x} Execute @value{GDBN} commands from file @var{file}. @xref{Command Files,, Command files}. @item -directory @var{directory} @itemx -d @var{directory} +@cindex @code{--directory} +@cindex @code{-d} Add @var{directory} to the path to search for source files. -@ifclear BARETARGET -@ifclear HPPA @item -m @itemx -mapped +@cindex @code{--mapped} +@cindex @code{-m} @emph{Warning: this option depends on operating system facilities that are not supported on all systems.}@* If memory-mapped files are available on your system through the @code{mmap} -system call, you can use this option +system call, you can use this option to have @value{GDBN} write the symbols from your program into a reusable file in the current directory. If the program you are debugging is -called @file{/tmp/fred}, the mapped symbol file is @file{./fred.syms}. +called @file{/tmp/fred}, the mapped symbol file is @file{/tmp/fred.syms}. Future @value{GDBN} debugging sessions notice the presence of this file, and can quickly map in symbol information from it, rather than reading the symbol table from the executable program. @@ -1185,33 +933,28 @@ the symbol table from the executable program. The @file{.syms} file is specific to the host machine where @value{GDBN} is run. It holds an exact image of the internal @value{GDBN} symbol table. It cannot be shared across multiple host platforms. -@end ifclear -@end ifclear -@ifclear HPPA @item -r @itemx -readnow +@cindex @code{--readnow} +@cindex @code{-r} Read each symbol file's entire symbol table immediately, rather than the default, which is to read it incrementally as it is needed. This makes startup slower, but makes future operations faster. -@end ifclear + @end table -@ifclear BARETARGET -@ifclear HPPA -The @code{-mapped} and @code{-readnow} options are typically combined in +You typically combine the @code{-mapped} and @code{-readnow} options in order to build a @file{.syms} file that contains complete symbol -information. (@xref{Files,,Commands to specify files}, for -information on @file{.syms} files.) A simple GDB invocation to do -nothing but build a @file{.syms} file for future use is: +information. (@xref{Files,,Commands to specify files}, for information +on @file{.syms} files.) A simple @value{GDBN} invocation to do nothing +but build a @file{.syms} file for future use is: @example - gdb -batch -nx -mapped -readnow programname +gdb -batch -nx -mapped -readnow programname @end example -@end ifclear -@end ifclear -@node Mode Options, , File Options, Invoking GDB +@node Mode Options @subsection Choosing modes You can run @value{GDBN} in various alternative modes---for example, in @@ -1220,93 +963,200 @@ batch mode or quiet mode. @table @code @item -nx @itemx -n -Do not execute commands from any initialization files (normally called -@file{.gdbinit}, or @file{gdb.ini} on PCs). Normally, the commands in -these files are executed after all the command options and arguments -have been processed. @xref{Command Files,,Command files}. +@cindex @code{--nx} +@cindex @code{-n} +Do not execute commands found in any initialization files. Normally, +@value{GDBN} executes the commands in these files after all the command +options and arguments have been processed. @xref{Command Files,,Command +files}. @item -quiet +@itemx -silent @itemx -q +@cindex @code{--quiet} +@cindex @code{--silent} +@cindex @code{-q} ``Quiet''. Do not print the introductory and copyright messages. These messages are also suppressed in batch mode. @item -batch +@cindex @code{--batch} Run in batch mode. Exit with status @code{0} after processing all the command files specified with @samp{-x} (and all commands from initialization files, if not inhibited with @samp{-n}). Exit with nonzero status if an error occurs in executing the @value{GDBN} commands in the command files. -Batch mode may be useful for running @value{GDBN} as a filter, for example to -download and run a program on another computer; in order to make this -more useful, the message +Batch mode may be useful for running @value{GDBN} as a filter, for +example to download and run a program on another computer; in order to +make this more useful, the message @example Program exited normally. @end example @noindent -(which is ordinarily issued whenever a program running under @value{GDBN} control -terminates) is not issued when running in batch mode. +(which is ordinarily issued whenever a program running under +@value{GDBN} control terminates) is not issued when running in batch +mode. + +@item -nowindows +@itemx -nw +@cindex @code{--nowindows} +@cindex @code{-nw} +``No windows''. If @value{GDBN} comes with a graphical user interface +(GUI) built in, then this option tells @value{GDBN} to only use the command-line +interface. If no GUI is available, this option has no effect. + +@item -windows +@itemx -w +@cindex @code{--windows} +@cindex @code{-w} +If @value{GDBN} includes a GUI, then this option requires it to be +used if possible. @item -cd @var{directory} +@cindex @code{--cd} Run @value{GDBN} using @var{directory} as its working directory, instead of the current directory. -@ifclear DOSHOST @item -fullname @itemx -f -@sc{gnu} Emacs sets this option when it runs @value{GDBN} as a subprocess. It tells @value{GDBN} -to output the full file name and line number in a standard, -recognizable fashion each time a stack frame is displayed (which -includes each time your program stops). This recognizable format looks -like two @samp{\032} characters, followed by the file name, line number -and character position separated by colons, and a newline. The -Emacs-to-@value{GDBN} interface program uses the two @samp{\032} characters as -a signal to display the source code for the frame. -@end ifclear - -@ifset SERIAL -@ifclear HPPA -@item -b @var{bps} +@cindex @code{--fullname} +@cindex @code{-f} +@sc{gnu} Emacs sets this option when it runs @value{GDBN} as a +subprocess. It tells @value{GDBN} to output the full file name and line +number in a standard, recognizable fashion each time a stack frame is +displayed (which includes each time your program stops). This +recognizable format looks like two @samp{\032} characters, followed by +the file name, line number and character position separated by colons, +and a newline. The Emacs-to-@value{GDBN} interface program uses the two +@samp{\032} characters as a signal to display the source code for the +frame. + +@item -epoch +@cindex @code{--epoch} +The Epoch Emacs-@value{GDBN} interface sets this option when it runs +@value{GDBN} as a subprocess. It tells @value{GDBN} to modify its print +routines so as to allow Epoch to display values of expressions in a +separate window. + +@item -annotate @var{level} +@cindex @code{--annotate} +This option sets the @dfn{annotation level} inside @value{GDBN}. Its +effect is identical to using @samp{set annotate @var{level}} +(@pxref{Annotations}). +Annotation level controls how much information does @value{GDBN} print +together with its prompt, values of expressions, source lines, and other +types of output. Level 0 is the normal, level 1 is for use when +@value{GDBN} is run as a subprocess of @sc{gnu} Emacs, level 2 is the +maximum annotation suitable for programs that control @value{GDBN}. + +@item -async +@cindex @code{--async} +Use the asynchronous event loop for the command-line interface. +@value{GDBN} processes all events, such as user keyboard input, via a +special event loop. This allows @value{GDBN} to accept and process user +commands in parallel with the debugged process being +run@footnote{@value{GDBN} built with @sc{djgpp} tools for +MS-DOS/MS-Windows supports this mode of operation, but the event loop is +suspended when the debuggee runs.}, so you don't need to wait for +control to return to @value{GDBN} before you type the next command. +(@emph{Note:} as of version 5.1, the target side of the asynchronous +operation is not yet in place, so @samp{-async} does not work fully +yet.) +@c FIXME: when the target side of the event loop is done, the above NOTE +@c should be removed. + +When the standard input is connected to a terminal device, @value{GDBN} +uses the asynchronous event loop by default, unless disabled by the +@samp{-noasync} option. + +@item -noasync +@cindex @code{--noasync} +Disable the asynchronous event loop for the command-line interface. + +@item --args +@cindex @code{--args} +Change interpretation of command line so that arguments following the +executable file are passed as command line arguments to the inferior. +This option stops option processing. + +@item -baud @var{bps} +@itemx -b @var{bps} +@cindex @code{--baud} +@cindex @code{-b} Set the line speed (baud rate or bits per second) of any serial interface used by @value{GDBN} for remote debugging. -@end ifclear @item -tty @var{device} +@itemx -t @var{device} +@cindex @code{--tty} +@cindex @code{-t} Run using @var{device} for your program's standard input and output. @c FIXME: kingdon thinks there is more to -tty. Investigate. -@end ifset -@ifset HPPA +@c resolve the situation of these eventually @item -tui -Use a Terminal User Interface. For information, use your Web browser to -read the file @file{TUI.html}, which is usually installed in the -directory @code{/opt/langtools/wdb/doc} on HP-UX systems. Do not use -this option if you run @value{GDBN} from Emacs (see @pxref{Emacs, ,Using -@value{GDBN} under @sc{gnu} Emacs}). - -@item -xdb -Run in XDB compatibility mode, allowing the use of certain XDB commands. -For information, see the file @file{xdb_trans.html}, which is usually -installed in the directory @code{/opt/langtools/wdb/doc} on HP-UX -systems. -@end ifset +@cindex @code{--tui} +Activate the Terminal User Interface when starting. +The Terminal User Interface manages several text windows on the terminal, +showing source, assembly, registers and @value{GDBN} command outputs +(@pxref{TUI, ,@value{GDBN} Text User Interface}). +Do not use this option if you run @value{GDBN} from Emacs +(@pxref{Emacs, ,Using @value{GDBN} under @sc{gnu} Emacs}). + +@c @item -xdb +@c @cindex @code{--xdb} +@c Run in XDB compatibility mode, allowing the use of certain XDB commands. +@c For information, see the file @file{xdb_trans.html}, which is usually +@c installed in the directory @code{/opt/langtools/wdb/doc} on HP-UX +@c systems. + +@item -interpreter @var{interp} +@cindex @code{--interpreter} +Use the interpreter @var{interp} for interface with the controlling +program or device. This option is meant to be set by programs which +communicate with @value{GDBN} using it as a back end. + +@samp{--interpreter=mi} (or @samp{--interpreter=mi1}) causes +@value{GDBN} to use the @dfn{gdb/mi interface} (@pxref{GDB/MI, , The +@sc{gdb/mi} Interface}). The older @sc{gdb/mi} interface, included in +@value{GDBN} version 5.0 can be selected with @samp{--interpreter=mi0}. + +@item -write +@cindex @code{--write} +Open the executable and core files for both reading and writing. This +is equivalent to the @samp{set write on} command inside @value{GDBN} +(@pxref{Patching}). + +@item -statistics +@cindex @code{--statistics} +This option causes @value{GDBN} to print statistics about time and +memory usage after it completes each command and returns to the prompt. + +@item -version +@cindex @code{--version} +This option causes @value{GDBN} to print its version number and +no-warranty blurb, and exit. + @end table -@node Quitting GDB, Shell Commands, Invoking GDB, Invocation +@node Quitting GDB @section Quitting @value{GDBN} @cindex exiting @value{GDBN} @cindex leaving @value{GDBN} @table @code @kindex quit @r{[}@var{expression}@r{]} -@kindex q -@item quit -To exit @value{GDBN}, use the @code{quit} command (abbreviated @code{q}), or -type an end-of-file character (usually @kbd{C-d}). If you do not supply -@var{expression}, @value{GDBN} will terminate normally; otherwise it will -terminate using the result of @var{expression} as the error code. +@kindex q @r{(@code{quit})} +@item quit @r{[}@var{expression}@r{]} +@itemx q +To exit @value{GDBN}, use the @code{quit} command (abbreviated +@code{q}), or type an end-of-file character (usually @kbd{C-d}). If you +do not supply @var{expression}, @value{GDBN} will terminate normally; +otherwise it will terminate using the result of @var{expression} as the +error code. @end table @cindex interrupt @@ -1316,13 +1166,11 @@ returns to @value{GDBN} command level. It is safe to type the interrupt character at any time because @value{GDBN} does not allow it to take effect until a time when it is safe. -@ifclear BARETARGET If you have been using @value{GDBN} to control an attached process or device, you can release it with the @code{detach} command (@pxref{Attach, ,Debugging an already-running process}). -@end ifclear -@node Shell Commands, , Quitting GDB, Invocation +@node Shell Commands @section Shell commands If you need to execute occasional shell commands during your @@ -1334,10 +1182,9 @@ just use the @code{shell} command. @cindex shell escape @item shell @var{command string} Invoke a standard shell to execute @var{command string}. -@ifclear DOSHOST If it exists, the environment variable @code{SHELL} determines which -shell to run. Otherwise @value{GDBN} uses @code{/bin/sh}. -@end ifclear +shell to run. Otherwise @value{GDBN} uses the default shell +(@file{/bin/sh} on Unix systems, @file{COMMAND.COM} on MS-DOS, etc.). @end table The utility @code{make} is often needed in development environments. @@ -1352,7 +1199,7 @@ Execute the @code{make} program with the specified arguments. This is equivalent to @samp{shell make @var{make-args}}. @end table -@node Commands, Running, Invocation, Top +@node Commands @chapter @value{GDBN} Commands You can abbreviate a @value{GDBN} command to the first few letters of the command @@ -1367,7 +1214,7 @@ show you the alternatives available, if there is more than one possibility). * Help:: How to ask @value{GDBN} for help @end menu -@node Command Syntax, Completion, Commands, Commands +@node Command Syntax @section Command syntax A @value{GDBN} command is a single line of input. There is no limit on @@ -1375,7 +1222,7 @@ how long it can be. It starts with a command name, which is followed by arguments whose meaning depends on the command name. For example, the command @code{step} accepts an argument which is the number of times to step, as in @samp{step 5}. You can also use the @code{step} command -with no arguments. Some command names do not allow any arguments. +with no arguments. Some commands do not allow any arguments. @cindex abbreviation @value{GDBN} command names may always be truncated if that abbreviation is @@ -1387,9 +1234,9 @@ names start with @code{s}. You can test abbreviations by using them as arguments to the @code{help} command. @cindex repeating commands -@kindex RET +@kindex RET @r{(repeat last command)} A blank line as input to @value{GDBN} (typing just @key{RET}) means to -repeat the previous command. Certain commands (for example, @code{run}) +repeat the previous command. Certain commands (for example, @code{run}) will not repeat this way; these are commands whose unintentional repetition might cause trouble and which you are unlikely to want to repeat. @@ -1404,13 +1251,20 @@ output, in a way similar to the common utility @code{more} @key{RET} too many in this situation, @value{GDBN} disables command repetition after any command that generates this sort of display. -@kindex # +@kindex # @r{(a comment)} @cindex comment Any text from a @kbd{#} to the end of the line is a comment; it does nothing. This is useful mainly in command files (@pxref{Command Files,,Command files}). -@node Completion, Help, Command Syntax, Commands +@cindex repeating command sequences +@kindex C-o @r{(operate-and-get-next)} +The @kbd{C-o} binding is useful for repeating a complex sequence of +commands. This command accepts the current line, like @kbd{RET}, and +then fetches the next line relative to the current line from the history +for editing. + +@node Completion @section Command completion @cindex completion @@ -1462,10 +1316,10 @@ example: @example (@value{GDBP}) b make_ @key{TAB} @exdent @value{GDBN} sounds bell; press @key{TAB} again, to see: -make_a_section_from_file make_environ -make_abs_section make_function_type -make_blockvector make_pointer_type -make_cleanup make_reference_type +make_a_section_from_file make_environ +make_abs_section make_function_type +make_blockvector make_pointer_type +make_cleanup make_reference_type make_command make_symbol_completion_list (@value{GDBP}) b make_ @end example @@ -1476,37 +1330,33 @@ partial input (@samp{b make_} in the example) so you can finish the command. If you just want to see the list of alternatives in the first place, you -can press @kbd{M-?} rather than pressing @key{TAB} twice. @kbd{M-?} -means @kbd{@key{META} ?}. You can type this -@ifclear DOSHOST -either by holding down a +can press @kbd{M-?} rather than pressing @key{TAB} twice. @kbd{M-?} +means @kbd{@key{META} ?}. You can type this either by holding down a key designated as the @key{META} shift on your keyboard (if there is -one) while typing @kbd{?}, or -@end ifclear -as @key{ESC} followed by @kbd{?}. +one) while typing @kbd{?}, or as @key{ESC} followed by @kbd{?}. @cindex quotes in commands @cindex completion of quoted strings Sometimes the string you need, while logically a ``word'', may contain -parentheses or other characters that @value{GDBN} normally excludes from its -notion of a word. To permit word completion to work in this situation, -you may enclose words in @code{'} (single quote marks) in @value{GDBN} commands. +parentheses or other characters that @value{GDBN} normally excludes from +its notion of a word. To permit word completion to work in this +situation, you may enclose words in @code{'} (single quote marks) in +@value{GDBN} commands. -@ifclear CONLY The most likely situation where you might need this is in typing the -name of a C++ function. This is because C++ allows function overloading -(multiple definitions of the same function, distinguished by argument -type). For example, when you want to set a breakpoint you may need to -distinguish whether you mean the version of @code{name} that takes an -@code{int} parameter, @code{name(int)}, or the version that takes a -@code{float} parameter, @code{name(float)}. To use the word-completion -facilities in this situation, type a single quote @code{'} at the -beginning of the function name. This alerts @value{GDBN} that it may need to -consider more information than usual when you press @key{TAB} or -@kbd{M-?} to request word completion: +name of a C@t{++} function. This is because C@t{++} allows function +overloading (multiple definitions of the same function, distinguished +by argument type). For example, when you want to set a breakpoint you +may need to distinguish whether you mean the version of @code{name} +that takes an @code{int} parameter, @code{name(int)}, or the version +that takes a @code{float} parameter, @code{name(float)}. To use the +word-completion facilities in this situation, type a single quote +@code{'} at the beginning of the function name. This alerts +@value{GDBN} that it may need to consider more information than usual +when you press @key{TAB} or @kbd{M-?} to request word completion: @example -(@value{GDBP}) b 'bubble( @key{M-?} +(@value{GDBP}) b 'bubble( @kbd{M-?} bubble(double,double) bubble(int,int) (@value{GDBP}) b 'bubble( @end example @@ -1527,23 +1377,22 @@ In general, @value{GDBN} can tell that a quote is needed (and inserts it) if you have not yet started typing the argument list when you ask for completion on an overloaded symbol. -For more information about overloaded functions, @pxref{Cplus -expressions, ,C++ expressions}. You can use the command @code{set +For more information about overloaded functions, see @ref{C plus plus +expressions, ,C@t{++} expressions}. You can use the command @code{set overload-resolution off} to disable overload resolution; -@pxref{Debugging C plus plus, ,@value{GDBN} features for C++}. -@end ifclear +see @ref{Debugging C plus plus, ,@value{GDBN} features for C@t{++}}. -@node Help, , Completion, Commands +@node Help @section Getting help @cindex online documentation @kindex help -You can always ask @value{GDBN} itself for information on its commands, +You can always ask @value{GDBN} itself for information on its commands, using the command @code{help}. @table @code -@kindex h +@kindex h @r{(@code{help})} @item help @itemx h You can use @code{help} (abbreviated @code{h}) with no arguments to @@ -1553,24 +1402,28 @@ display a short list of named classes of commands: (@value{GDBP}) help List of classes of commands: -running -- Running the program -stack -- Examining the stack -data -- Examining data +aliases -- Aliases of other commands breakpoints -- Making program stop at certain points +data -- Examining data files -- Specifying and examining files +internals -- Maintenance commands +obscure -- Obscure features +running -- Running the program +stack -- Examining the stack status -- Status inquiries support -- Support facilities +tracepoints -- Tracing of program execution without@* + stopping the program user-defined -- User-defined commands -aliases -- Aliases of other commands -obscure -- Obscure features -Type "help" followed by a class name for a list of +Type "help" followed by a class name for a list of commands in that class. -Type "help" followed by command name for full +Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (@value{GDBP}) @end smallexample +@c the above line break eliminates huge line overfull... @item help @var{class} Using one of the general help classes as an argument, you can get a @@ -1585,11 +1438,12 @@ List of commands: @c Line break in "show" line falsifies real output, but needed @c to fit in smallbook page size. -show -- Generic command for showing things set - with "set" -info -- Generic command for printing status +info -- Generic command for showing things + about the program being debugged +show -- Generic command for showing things + about the debugger -Type "help" followed by command name for full +Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (@value{GDBP}) @@ -1599,6 +1453,28 @@ Command name abbreviations are allowed if unambiguous. With a command name as @code{help} argument, @value{GDBN} displays a short paragraph on how to use that command. +@kindex apropos +@item apropos @var{args} +The @code{apropos @var{args}} command searches through all of the @value{GDBN} +commands, and their documentation, for the regular expression specified in +@var{args}. It prints out all matches found. For example: + +@smallexample +apropos reload +@end smallexample + +@noindent +results in: + +@smallexample +@c @group +set symbol-reloading -- Set dynamic symbol table reloading + multiple times in one run +show symbol-reloading -- Show dynamic symbol table reloading + multiple times in one run +@c @end group +@end smallexample + @kindex complete @item complete @var{args} The @code{complete @var{args}} command lists all the possible completions @@ -1613,9 +1489,10 @@ complete i @smallexample @group +if +ignore info inspect -ignore @end group @end smallexample @@ -1632,7 +1509,7 @@ all the sub-commands. @xref{Index}. @c @group @table @code @kindex info -@kindex i +@kindex i @r{(@code{info})} @item info This command (abbreviated @code{i}) is for describing the state of your program. For example, you can list the arguments given to your program @@ -1643,13 +1520,13 @@ You can get a complete list of the @code{info} sub-commands with @kindex set @item set -You can assign the result of an expression to an environment variable with +You can assign the result of an expression to an environment variable with @code{set}. For example, you can set the @value{GDBN} prompt to a $-sign with @code{set prompt $}. @kindex show @item show -In contrast to @code{info}, @code{show} is for describing the state of +In contrast to @code{info}, @code{show} is for describing the state of @value{GDBN} itself. You can change most of the things you can @code{show}, by using the related command @code{set}; for example, you can control what number @@ -1674,11 +1551,14 @@ exceptional in lacking corresponding @code{set} commands: @cindex version number @item show version Show what version of @value{GDBN} is running. You should include this -information in @value{GDBN} bug-reports. If multiple versions of @value{GDBN} are in -use at your site, you may occasionally want to determine which version -of @value{GDBN} you are running; as @value{GDBN} evolves, new commands are introduced, -and old ones may wither away. The version number is also announced -when you start @value{GDBN}. +information in @value{GDBN} bug-reports. If multiple versions of +@value{GDBN} are in use at your site, you may need to determine which +version of @value{GDBN} you are running; as @value{GDBN} evolves, new +commands are introduced, and old ones may wither away. Also, many +system vendors ship variant versions of @value{GDBN}, and there are +variant versions of @value{GDBN} in @sc{gnu}/Linux distributions as well. +The version number is the same as the one announced when you start +@value{GDBN}. @kindex show copying @item show copying @@ -1686,41 +1566,38 @@ Display information about permission for copying @value{GDBN}. @kindex show warranty @item show warranty -Display the @sc{gnu} ``NO WARRANTY'' statement. +Display the @sc{gnu} ``NO WARRANTY'' statement, or a warranty, +if your version of @value{GDBN} comes with one. + @end table -@node Running, Stopping, Commands, Top +@node Running @chapter Running Programs Under @value{GDBN} When you run a program under @value{GDBN}, you must first generate debugging information when you compile it. -@ifclear BARETARGET -You may start @value{GDBN} with its arguments, if any, in an environment -of your choice. You may redirect your program's input and output, debug an -already running process, or kill a child process. -@end ifclear + +You may start @value{GDBN} with its arguments, if any, in an environment +of your choice. If you are doing native debugging, you may redirect +your program's input and output, debug an already running process, or +kill a child process. @menu * Compilation:: Compiling for debugging * Starting:: Starting your program -@ifclear BARETARGET * Arguments:: Your program's arguments * Environment:: Your program's environment -@end ifclear * Working Directory:: Your program's working directory * Input/Output:: Your program's input and output * Attach:: Debugging an already-running process * Kill Process:: Killing the child process -@ifclear HPPA -* Process Information:: Additional process information -@end ifclear * Threads:: Debugging programs with multiple threads * Processes:: Debugging programs with multiple processes @end menu -@node Compilation, Starting, Running, Running +@node Compilation @section Compiling for debugging In order to debug a program effectively, you need to generate @@ -1736,17 +1613,11 @@ Many C compilers are unable to handle the @samp{-g} and @samp{-O} options together. Using those compilers, you cannot generate optimized executables containing debugging information. -@ifclear HPPA -@value{NGCC}, the @sc{gnu} C compiler, supports @samp{-g} with or without -@end ifclear -@ifset HPPA -The HP ANSI C and C++ compilers, as well as @value{NGCC}, the @sc{gnu} C -compiler, support @samp{-g} with or without -@end ifset -@samp{-O}, making it possible to debug optimized code. We recommend -that you @emph{always} use @samp{-g} whenever you compile a program. -You may think your program is correct, but there is no sense in pushing -your luck. +@value{NGCC}, the @sc{gnu} C compiler, supports @samp{-g} with or +without @samp{-O}, making it possible to debug optimized code. We +recommend that you @emph{always} use @samp{-g} whenever you compile a +program. You may think your program is correct, but there is no sense +in pushing your luck. @cindex optimized code, debugging @cindex debugging optimized code @@ -1767,27 +1638,24 @@ Older versions of the @sc{gnu} C compiler permitted a variant option format; if your @sc{gnu} C compiler has this option, do not use it. @need 2000 -@node Starting, Arguments, Compilation, Running +@node Starting @section Starting your program @cindex starting @cindex running @table @code @kindex run +@kindex r @r{(@code{run})} @item run @itemx r -Use the @code{run} command to start your program under @value{GDBN}. You must -first specify the program name -@ifset VXWORKS -(except on VxWorks) -@end ifset -with an argument to @value{GDBN} (@pxref{Invocation, ,Getting In and -Out of @value{GDBN}}), or by using the @code{file} or @code{exec-file} -command (@pxref{Files, ,Commands to specify files}). +Use the @code{run} command to start your program under @value{GDBN}. +You must first specify the program name (except on VxWorks) with an +argument to @value{GDBN} (@pxref{Invocation, ,Getting In and Out of +@value{GDBN}}), or by using the @code{file} or @code{exec-file} command +(@pxref{Files, ,Commands to specify files}). @end table -@ifclear BARETARGET If you are running your program in an execution environment that supports processes, @code{run} creates an inferior process and makes that process run your program. (In environments without processes, @@ -1835,7 +1703,6 @@ pipes to pass the output of the program you are debugging to another program; if you attempt this, @value{GDBN} is likely to wind up debugging the wrong program. @end table -@end ifclear When you issue the @code{run} command, your program begins to execute immediately. @xref{Stopping, ,Stopping and continuing}, for discussion @@ -1848,24 +1715,28 @@ time @value{GDBN} read its symbols, @value{GDBN} discards its symbol table, and reads it again. When it does this, @value{GDBN} tries to retain your current breakpoints. -@ifclear BARETARGET -@node Arguments, Environment, Starting, Running +@node Arguments @section Your program's arguments @cindex arguments (to your program) The arguments to your program can be specified by the arguments of the -@code{run} command. +@code{run} command. They are passed to a shell, which expands wildcard characters and performs redirection of I/O, and thence to your program. Your @code{SHELL} environment variable (if it exists) specifies what shell @value{GDBN} uses. If you do not define @code{SHELL}, @value{GDBN} uses -@code{/bin/sh}. +the default shell (@file{/bin/sh} on Unix). + +On non-Unix systems, the program is usually invoked directly by +@value{GDBN}, which emulates I/O redirection via the appropriate system +calls, and the wildcard characters are expanded by the startup code of +the program, not by the shell. @code{run} with no arguments uses the same arguments used by the previous @code{run}, or those set by the @code{set args} command. -@kindex set args @table @code +@kindex set args @item set args Specify the arguments to be used the next time your program is run. If @code{set args} has no arguments, @code{run} executes your program @@ -1878,7 +1749,7 @@ it again without arguments. Show the arguments to give your program when it is started. @end table -@node Environment, Working Directory, Arguments, Running +@node Environment @section Your program's environment @cindex environment (of your program) @@ -1894,10 +1765,12 @@ environment without having to start @value{GDBN} over again. @kindex path @item path @var{directory} Add @var{directory} to the front of the @code{PATH} environment variable -(the search path for executables), for both @value{GDBN} and your program. -You may specify several directory names, separated by @samp{:} or -whitespace. If @var{directory} is already in the path, it is moved to -the front, so it is searched sooner. +(the search path for executables) that will be passed to your program. +The value of @code{PATH} used by @value{GDBN} does not change. +You may specify several directory names, separated by whitespace or by a +system-dependent separator character (@samp{:} on Unix, @samp{;} on +MS-DOS and MS-Windows). If @var{directory} is already in the path, it +is moved to the front, so it is searched sooner. You can use the string @samp{$cwd} to refer to whatever is the current working directory at the time @value{GDBN} searches the path. If you @@ -1921,7 +1794,7 @@ print the names and values of all environment variables to be given to your program. You can abbreviate @code{environment} as @code{env}. @kindex set environment -@item set environment @var{varname} @r{[}=@r{]} @var{value} +@item set environment @var{varname} @r{[}=@var{value}@r{]} Set environment variable @var{varname} to @var{value}. The value changes for your program only, not for @value{GDBN} itself. @var{value} may be any string; the values of environment variables are just strings, and @@ -1938,7 +1811,7 @@ set env USER = foo @end example @noindent -tells a Unix program, when subsequently run, that its user is named +tells the debugged program, when subsequently run, that its user is named @samp{foo}. (The spaces around @samp{=} are used for clarity here; they are not actually required.) @@ -1950,7 +1823,8 @@ program. This is different from @samp{set env @var{varname} =}; rather than assigning it an empty value. @end table -@emph{Warning:} @value{GDBN} runs your program using the shell indicated +@emph{Warning:} On Unix systems, @value{GDBN} runs your program using +the shell indicated by your @code{SHELL} environment variable if it exists (or @code{/bin/sh} if not). If your @code{SHELL} variable names a shell that runs an initialization file---such as @file{.cshrc} for C-shell, or @@ -1959,7 +1833,7 @@ your program. You may wish to move setting of environment variables to files that are only run when you sign on, such as @file{.login} or @file{.profile}. -@node Working Directory, Input/Output, Environment, Running +@node Working Directory @section Your program's working directory @cindex working directory (of your program) @@ -1983,14 +1857,14 @@ Set the @value{GDBN} working directory to @var{directory}. Print the @value{GDBN} working directory. @end table -@node Input/Output, Attach, Working Directory, Running +@node Input/Output @section Your program's input and output @cindex redirection @cindex i/o @cindex terminal By default, the program you run under @value{GDBN} does input and output to -the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal +the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal to its own terminal modes to interact with you, but it records the terminal modes your program was using and switches back to them when you continue running your program. @@ -2037,7 +1911,7 @@ When you use the @code{tty} command or redirect input in the @code{run} command, only the input @emph{for your program} is affected. The input for @value{GDBN} still comes from your terminal. -@node Attach, Kill Process, Input/Output, Running +@node Attach @section Debugging an already-running process @kindex attach @cindex attach @@ -2068,16 +1942,10 @@ Specify Files}. The first thing @value{GDBN} does after arranging to debug the specified process is to stop it. You can examine and modify an attached process -with all the @value{GDBN} commands that are ordinarily available when you start -@ifclear HPPA -processes with @code{run}. You can insert breakpoints; you can step and -@end ifclear -@ifset HPPA -processes with @code{run}. You can insert breakpoints (except in shared -libraries); you can step and -@end ifset -continue; you can modify storage. If you would rather the process -continue running, you may use the @code{continue} command after +with all the @value{GDBN} commands that are ordinarily available when +you start processes with @code{run}. You can insert breakpoints; you +can step and continue; you can modify storage. If you would rather the +process continue running, you may use the @code{continue} command after attaching @value{GDBN} to the process. @table @code @@ -2099,14 +1967,8 @@ control whether or not you need to confirm by using the @code{set confirm} command (@pxref{Messages/Warnings, ,Optional warnings and messages}). -@ifset HPPA -@node Kill Process, Threads, Attach, Running +@node Kill Process @section Killing the child process -@end ifset -@ifclear HPPA -@node Kill Process, Process Information, Attach, Running -@section Killing the child process -@end ifclear @table @code @kindex kill @@ -2130,58 +1992,8 @@ next type @code{run}, @value{GDBN} notices that the file has changed, and reads the symbol table again (while trying to preserve your current breakpoint settings). -@ifclear HPPA -@node Process Information, Threads, Kill Process, Running -@section Additional process information - -@kindex /proc -@cindex process image -Some operating systems provide a facility called @samp{/proc} that can -be used to examine the image of a running process using file-system -subroutines. If @value{GDBN} is configured for an operating system with this -facility, the command @code{info proc} is available to report on several -kinds of information about the process running your program. -@code{info proc} works only on SVR4 systems that support @code{procfs}. - -@table @code -@kindex info proc -@item info proc -Summarize available information about the process. - -@kindex info proc mappings -@item info proc mappings -Report on the address ranges accessible in the program, with information -on whether your program may read, write, or execute each range. - -@kindex info proc times -@item info proc times -Starting time, user CPU time, and system CPU time for your program and -its children. - -@kindex info proc id -@item info proc id -Report on the process IDs related to your program: its own process ID, -the ID of its parent, the process group ID, and the session ID. - -@kindex info proc status -@item info proc status -General information on the state of the process. If the process is -stopped, this report includes the reason for stopping, and any signal -received. - -@item info proc all -Show all the above information about the process. -@end table -@end ifclear - -@ifset HPPA -@node Threads, Processes, Kill Process, Running +@node Threads @section Debugging programs with multiple threads -@end ifset -@ifclear HPPA -@node Threads, Processes, Process Information, Running -@section Debugging programs with multiple threads -@end ifclear @cindex threads of execution @cindex multiple threads @@ -2201,12 +2013,11 @@ programs: @item automatic notification of new threads @item @samp{thread @var{threadno}}, a command to switch among threads @item @samp{info threads}, a command to inquire about existing threads -@item @samp{thread apply [@var{threadno}] [@var{all}] @var{args}}, +@item @samp{thread apply [@var{threadno}] [@var{all}] @var{args}}, a command to apply a command to a list of threads @item thread-specific breakpoints @end itemize -@ifclear HPPA @quotation @emph{Warning:} These facilities are not yet available on every @value{GDBN} configuration where the operating system supports threads. @@ -2224,7 +2035,6 @@ see the IDs of currently known threads. @c FIXME to implementors: how hard would it be to say "sorry, this GDB @c doesn't support threads"? @end quotation -@end ifclear @cindex focus of debugging @cindex current thread @@ -2234,8 +2044,7 @@ control, one thread in particular is always the focus of debugging. This thread is called the @dfn{current thread}. Debugging commands show program information from the perspective of the current thread. -@ifclear HPPA -@kindex New @var{systag} +@cindex @code{New} @var{systag} message @cindex thread identifier (system) @c FIXME-implementors!! It would be more helpful if the [New...] message @c included GDB's numeric thread handle, so you could just go to that @@ -2257,11 +2066,11 @@ further qualifier. @c FIXME!! (1) Does the [New...] message appear even for the very first @c thread of a program, or does it only appear for the -@c second---i.e., when it becomes obvious we have a multithread +@c second---i.e.@: when it becomes obvious we have a multithread @c program? @c (2) *Is* there necessarily a first thread always? Or do some @c multithread systems permit starting a program with multiple -@c threads ab initio? +@c threads ab initio? @cindex thread number @cindex thread identifier (GDB) @@ -2286,7 +2095,7 @@ program. @value{GDBN} displays for each thread (in this order): An asterisk @samp{*} to the left of the @value{GDBN} thread number indicates the current thread. -For example, +For example, @end table @c end table here to get a little more width for example @@ -2297,8 +2106,8 @@ For example, * 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8) at threadtest.c:68 @end smallexample -@end ifclear -@ifset HPPA + +On HP-UX systems: @cindex thread number @cindex thread identifier (GDB) @@ -2306,8 +2115,8 @@ For debugging purposes, @value{GDBN} associates its own thread number---a small integer assigned in thread-creation order---with each thread in your program. -@kindex New @var{systag} -@cindex thread identifier (system) +@cindex @code{New} @var{systag} message, on HP-UX +@cindex thread identifier (system), on HP-UX @c FIXME-implementors!! It would be more helpful if the [New...] message @c included GDB's numeric thread handle, so you could just go to that @c thread without first checking `info threads'. @@ -2322,7 +2131,7 @@ HP-UX, you see @end example @noindent -when @value{GDBN} notices a new thread. +when @value{GDBN} notices a new thread. @table @code @kindex info threads @@ -2342,17 +2151,19 @@ program. @value{GDBN} displays for each thread (in this order): An asterisk @samp{*} to the left of the @value{GDBN} thread number indicates the current thread. -For example, +For example, @end table @c end table here to get a little more width for example @example (@value{GDBP}) info threads - * 3 system thread 26607 worker (wptr=0x7b09c318 "@@") at quicksort.c:137 - 2 system thread 26606 0x7b0030d8 in __ksleep () from /usr/lib/libc.2 - 1 system thread 27905 0x7b003498 in _brk () from /usr/lib/libc.2 + * 3 system thread 26607 worker (wptr=0x7b09c318 "@@") \@* + at quicksort.c:137 + 2 system thread 26606 0x7b0030d8 in __ksleep () \@* + from /usr/lib/libc.2 + 1 system thread 27905 0x7b003498 in _brk () \@* + from /usr/lib/libc.2 @end example -@end ifset @table @code @kindex thread @var{threadno} @@ -2366,19 +2177,14 @@ you selected, and its current stack frame summary: @smallexample @c FIXME!! This example made up; find a @value{GDBN} w/threads and get real one (@value{GDBP}) thread 2 -@ifclear HPPA [Switching to process 35 thread 23] -@end ifclear -@ifset HPPA -[Switching to thread 2 (system thread 26594)] -@end ifset 0x34e5 in sigpause () @end smallexample @noindent As with the @samp{[New @dots{}]} message, the form of the text after @samp{Switching to} depends on your system's conventions for identifying -threads. +threads. @kindex thread apply @item thread apply [@var{threadno}] [@var{all}] @var{args} @@ -2386,8 +2192,8 @@ The @code{thread apply} command allows you to apply a command to one or more threads. Specify the numbers of the threads that you want affected with the command argument @var{threadno}. @var{threadno} is the internal @value{GDBN} thread number, as shown in the first field of the @samp{info -threads} display. To apply a command to all threads, use -@code{thread apply all} @var{args}. +threads} display. To apply a command to all threads, use +@code{thread apply all} @var{args}. @end table @cindex automatic thread selection @@ -2405,21 +2211,20 @@ programs with multiple threads. @xref{Set Watchpoints,,Setting watchpoints}, for information about watchpoints in programs with multiple threads. -@end ifclear -@ifclear HPPA -@node Processes, , Threads, Running +@node Processes @section Debugging programs with multiple processes @cindex fork, debugging programs which call @cindex multiple processes @cindex processes, multiple -@value{GDBN} has no special support for debugging programs which create -additional processes using the @code{fork} function. When a program -forks, @value{GDBN} will continue to debug the parent process and the -child process will run unimpeded. If you have set a breakpoint in any -code which the child then executes, the child will get a @code{SIGTRAP} -signal which (unless it catches the signal) will cause it to terminate. +On most systems, @value{GDBN} has no special support for debugging +programs which create additional processes using the @code{fork} +function. When a program forks, @value{GDBN} will continue to debug the +parent process and the child process will run unimpeded. If you have +set a breakpoint in any code which the child then executes, the child +will get a @code{SIGTRAP} signal which (unless it catches the signal) +will cause it to terminate. However, if you want to debug the child process there is a workaround which isn't too painful. Put a call to @code{sleep} in the code which @@ -2429,19 +2234,12 @@ so that the delay need not occur when you don't want to run @value{GDBN} on the child. While the child is sleeping, use the @code{ps} program to get its process ID. Then tell @value{GDBN} (a new invocation of @value{GDBN} if you are also debugging the parent process) to attach to -the child process (see @ref{Attach}). From that point on you can debug +the child process (@pxref{Attach}). From that point on you can debug the child process just like any other process which you attached to. -@end ifclear -@ifset HPPA -@node Processes, , Threads, Running -@section Debugging programs with multiple processes -@cindex fork, debugging programs which call -@cindex multiple processes -@cindex processes, multiple - -@value{GDBN} provides support for debugging programs that create -additional processes using the @code{fork} or @code{vfork} function. +On HP-UX (11.x and later only?), @value{GDBN} provides support for +debugging programs that create additional processes using the +@code{fork} or @code{vfork} function. By default, when a program forks, @value{GDBN} will continue to debug the parent process and the child process will run unimpeded. @@ -2459,7 +2257,7 @@ process. The @var{mode} can be: @table @code @item parent The original process is debugged after a fork. The child process runs -unimpeded. +unimpeded. This is the default. @item child The new process is debugged after a fork. The parent process runs @@ -2470,7 +2268,7 @@ The debugger will ask for one of the above choices. @end table @item show follow-fork-mode -Display the current debugger response to a fork or vfork call. +Display the current debugger response to a @code{fork} or @code{vfork} call. @end table If you ask to debug a child process and a @code{vfork} is followed by an @@ -2490,52 +2288,37 @@ argument. You can use the @code{catch} command to make @value{GDBN} stop whenever a @code{fork}, @code{vfork}, or @code{exec} call is made. @xref{Set Catchpoints, ,Setting catchpoints}. -@end ifset -@node Stopping, Stack, Running, Top +@node Stopping @chapter Stopping and Continuing The principal purposes of using a debugger are so that you can stop your program before it terminates; or so that, if your program runs into trouble, you can investigate and find out why. -Inside @value{GDBN}, your program may stop for any of several reasons, such -as -@ifclear BARETARGET -a signal, -@end ifclear -a breakpoint, or reaching a new line after a @value{GDBN} -command such as @code{step}. You may then examine and change -variables, set new breakpoints or remove old ones, and then continue -execution. Usually, the messages shown by @value{GDBN} provide ample -explanation of the status of your program---but you can also explicitly -request this information at any time. +Inside @value{GDBN}, your program may stop for any of several reasons, +such as a signal, a breakpoint, or reaching a new line after a +@value{GDBN} command such as @code{step}. You may then examine and +change variables, set new breakpoints or remove old ones, and then +continue execution. Usually, the messages shown by @value{GDBN} provide +ample explanation of the status of your program---but you can also +explicitly request this information at any time. @table @code @kindex info program @item info program Display information about the status of your program: whether it is -running or not, -@ifclear BARETARGET -what process it is, -@end ifclear -and why it stopped. +running or not, what process it is, and why it stopped. @end table @menu * Breakpoints:: Breakpoints, watchpoints, and catchpoints * Continuing and Stepping:: Resuming execution -@ifset POSIX * Signals:: Signals -@end ifset - -@ifclear BARETARGET * Thread Stops:: Stopping and starting multi-thread programs -@end ifclear - @end menu -@node Breakpoints, Continuing and Stepping, Stopping, Stopping +@node Breakpoints @section Breakpoints, watchpoints, and catchpoints @cindex breakpoints @@ -2572,12 +2355,12 @@ Automatic display}. @cindex catchpoints @cindex breakpoint on events A @dfn{catchpoint} is another special breakpoint that stops your program -when a certain kind of event occurs, such as the throwing of a C++ +when a certain kind of event occurs, such as the throwing of a C@t{++} exception or the loading of a library. As with watchpoints, you use a different command to set a catchpoint (@pxref{Set Catchpoints, ,Setting catchpoints}), but aside from that, you can manage a catchpoint like any other breakpoint. (To stop when your program receives a signal, use the -@code{handle} command; @pxref{Signals, ,Signals}.) +@code{handle} command; see @ref{Signals, ,Signals}.) @cindex breakpoint numbers @cindex numbers for breakpoints @@ -2589,6 +2372,14 @@ breakpoint you want to change. Each breakpoint may be @dfn{enabled} or @dfn{disabled}; if disabled, it has no effect on your program until you enable it again. +@cindex breakpoint ranges +@cindex ranges of breakpoints +Some @value{GDBN} commands accept a range of breakpoints on which to +operate. A breakpoint range is either a single breakpoint number, like +@samp{5}, or two such numbers, in increasing order, separated by a +hyphen, like @samp{5-7}. When a breakpoint range is given to a command, +all breakpoint in that range are operated on. + @menu * Set Breaks:: Setting breakpoints * Set Watchpoints:: Setting watchpoints @@ -2597,30 +2388,25 @@ enable it again. * Disabling:: Disabling breakpoints * Conditions:: Break conditions * Break Commands:: Breakpoint command lists -@ifclear CONLY * Breakpoint Menus:: Breakpoint menus -@end ifclear - -@c @ifclear BARETARGET -@c * Error in Breakpoints:: ``Cannot insert breakpoints'' -@c @end ifclear +* Error in Breakpoints:: ``Cannot insert breakpoints'' @end menu -@node Set Breaks, Set Watchpoints, Breakpoints, Breakpoints +@node Set Breaks @subsection Setting breakpoints -@c FIXME LMB what does GDB do if no code on line of breakpt? +@c FIXME LMB what does GDB do if no code on line of breakpt? @c consider in particular declaration with/without initialization. @c @c FIXME 2 is there stuff on this already? break at fun start, already init? @kindex break -@kindex b -@kindex $bpnum +@kindex b @r{(@code{break})} +@vindex $bpnum@r{, convenience variable} @cindex latest breakpoint Breakpoints are set with the @code{break} command (abbreviated -@code{b}). The debugger convenience variable @samp{$bpnum} records the -number of the breakpoints you've set most recently; see @ref{Convenience +@code{b}). The debugger convenience variable @samp{$bpnum} records the +number of the breakpoint you've set most recently; see @ref{Convenience Vars,, Convenience variables}, for a discussion of what you can do with convenience variables. @@ -2628,22 +2414,21 @@ You have several ways to say where the breakpoint should go. @table @code @item break @var{function} -Set a breakpoint at entry to function @var{function}. -@ifclear CONLY +Set a breakpoint at entry to function @var{function}. When using source languages that permit overloading of symbols, such as -C++, @var{function} may refer to more than one possible place to break. +C@t{++}, @var{function} may refer to more than one possible place to break. @xref{Breakpoint Menus,,Breakpoint menus}, for a discussion of that situation. -@end ifclear @item break +@var{offset} @itemx break -@var{offset} Set a breakpoint some number of lines forward or back from the position -at which execution stopped in the currently selected frame. +at which execution stopped in the currently selected @dfn{stack frame}. +(@xref{Frames, ,Frames}, for a description of stack frames.) @item break @var{linenum} Set a breakpoint at line @var{linenum} in the current source file. -That file is the last file whose source text was printed. This -breakpoint stops your program just before it executes any of the +The current source file is the last file whose source text was printed. +The breakpoint will stop your program just before it executes any of the code on that line. @item break @var{filename}:@var{linenum} @@ -2693,51 +2478,54 @@ same as for the @code{break} command, and the breakpoint is set in the same way, but the breakpoint is automatically deleted after the first time your program stops there. @xref{Disabling, ,Disabling breakpoints}. -@ifclear HPPA @kindex hbreak @item hbreak @var{args} -Set a hardware-assisted breakpoint. @var{args} are the same as for the -@code{break} command and the breakpoint is set in the same way, but the +Set a hardware-assisted breakpoint. @var{args} are the same as for the +@code{break} command and the breakpoint is set in the same way, but the breakpoint requires hardware support and some target hardware may not have this support. The main purpose of this is EPROM/ROM code -debugging, so you can set a breakpoint at an instruction without -changing the instruction. This can be used with the new trap-generation -provided by SPARClite DSU. DSU will generate traps when a program accesses -some data or instruction address that is assigned to the debug registers. -However the hardware breakpoint registers can only take two data breakpoints, -and @value{GDBN} will reject this command if more than two are used. -Delete or disable unused hardware breakpoints before setting -new ones. @xref{Conditions, ,Break conditions}. +debugging, so you can set a breakpoint at an instruction without +changing the instruction. This can be used with the new trap-generation +provided by SPARClite DSU and some x86-based targets. These targets +will generate traps when a program accesses some data or instruction +address that is assigned to the debug registers. However the hardware +breakpoint registers can take a limited number of breakpoints. For +example, on the DSU, only two data breakpoints can be set at a time, and +@value{GDBN} will reject this command if more than two are used. Delete +or disable unused hardware breakpoints before setting new ones +(@pxref{Disabling, ,Disabling}). @xref{Conditions, ,Break conditions}. @kindex thbreak @item thbreak @var{args} Set a hardware-assisted breakpoint enabled only for one stop. @var{args} are the same as for the @code{hbreak} command and the breakpoint is set in -the same way. However, like the @code{tbreak} command, +the same way. However, like the @code{tbreak} command, the breakpoint is automatically deleted after the first time your program stops there. Also, like the @code{hbreak} -command, the breakpoint requires hardware support and some target hardware -may not have this support. @xref{Disabling, ,Disabling breakpoints}. -Also @xref{Conditions, ,Break conditions}. -@end ifclear +command, the breakpoint requires hardware support and some target hardware +may not have this support. @xref{Disabling, ,Disabling breakpoints}. +See also @ref{Conditions, ,Break conditions}. @kindex rbreak @cindex regular expression @item rbreak @var{regex} -@c FIXME what kind of regexp? Set breakpoints on all functions matching the regular expression -@var{regex}. This command -sets an unconditional breakpoint on all matches, printing a list of all -breakpoints it set. Once these breakpoints are set, they are treated -just like the breakpoints set with the @code{break} command. You can -delete them, disable them, or make them conditional the same way as any -other breakpoint. - -@ifclear CONLY -When debugging C++ programs, @code{rbreak} is useful for setting +@var{regex}. This command sets an unconditional breakpoint on all +matches, printing a list of all breakpoints it set. Once these +breakpoints are set, they are treated just like the breakpoints set with +the @code{break} command. You can delete them, disable them, or make +them conditional the same way as any other breakpoint. + +The syntax of the regular expression is the standard one used with tools +like @file{grep}. Note that this is different from the syntax used by +shells, so for instance @code{foo*} matches all functions that include +an @code{fo} followed by zero or more @code{o}s. There is an implicit +@code{.*} leading and trailing the regular expression you supply, so to +match only functions that begin with @code{foo}, use @code{^foo}. + +When debugging C@t{++} programs, @code{rbreak} is useful for setting breakpoints on overloaded functions that are not members of any special classes. -@end ifclear @kindex info breakpoints @cindex @code{$_} and @code{info breakpoints} @@ -2757,7 +2545,7 @@ Whether the breakpoint is marked to be disabled or deleted when hit. Enabled breakpoints are marked with @samp{y}. @samp{n} marks breakpoints that are not enabled. @item Address -Where the breakpoint is in your program, as a memory address +Where the breakpoint is in your program, as a memory address. @item What Where the breakpoint is in the source for your program, as a file and line number. @@ -2773,7 +2561,7 @@ are listed after that. number @var{n} as argument lists only that breakpoint. The convenience variable @code{$_} and the default examining-address for the @code{x} command are set to the address of the last breakpoint -listed (@pxref{Memory, ,Examining memory}). +listed (@pxref{Memory, ,Examining memory}). @noindent @code{info break} displays a count of the number of times the breakpoint @@ -2791,52 +2579,15 @@ the breakpoints are conditional, this is even useful @cindex negative breakpoint numbers @cindex internal @value{GDBN} breakpoints -@value{GDBN} itself sometimes sets breakpoints in your program for special -purposes, such as proper handling of @code{longjmp} (in C programs). -These internal breakpoints are assigned negative numbers, starting with -@code{-1}; @samp{info breakpoints} does not display them. - +@value{GDBN} itself sometimes sets breakpoints in your program for +special purposes, such as proper handling of @code{longjmp} (in C +programs). These internal breakpoints are assigned negative numbers, +starting with @code{-1}; @samp{info breakpoints} does not display them. You can see these breakpoints with the @value{GDBN} maintenance command -@samp{maint info breakpoints}. - -@table @code -@kindex maint info breakpoints -@item maint info breakpoints -Using the same format as @samp{info breakpoints}, display both the -breakpoints you've set explicitly, and those @value{GDBN} is using for -internal purposes. Internal breakpoints are shown with negative -breakpoint numbers. The type column identifies what kind of breakpoint -is shown: - -@table @code -@item breakpoint -Normal, explicitly set breakpoint. - -@item watchpoint -Normal, explicitly set watchpoint. - -@item longjmp -Internal breakpoint, used to handle correctly stepping through -@code{longjmp} calls. - -@item longjmp resume -Internal breakpoint at the target of a @code{longjmp}. - -@item until -Temporary internal breakpoint used by the @value{GDBN} @code{until} command. - -@item finish -Temporary internal breakpoint used by the @value{GDBN} @code{finish} command. +@samp{maint info breakpoints} (@pxref{maint info breakpoints}). -@ifset HPPA -@item shlib events -Shared library events. -@end ifset -@end table -@end table - -@node Set Watchpoints, Set Catchpoints, Set Breaks, Breakpoints +@node Set Watchpoints @subsection Setting watchpoints @cindex setting watchpoints @@ -2847,13 +2598,14 @@ expression changes, without having to predict a particular place where this may happen. Depending on your system, watchpoints may be implemented in software or -hardware. GDB does software watchpointing by single-stepping your +hardware. @value{GDBN} does software watchpointing by single-stepping your program and testing the variable's value each time, which is hundreds of times slower than normal execution. (But this may still be worth it, to catch errors where you have no clue what part of your program is the culprit.) -On some systems, such as HP-UX and Linux, GDB includes support for +On some systems, such as HP-UX, Linux and some other x86-based targets, +@value{GDBN} includes support for hardware watchpoints, which do not slow down the running of your program. @@ -2866,14 +2618,11 @@ is written into by the program and its value changes. @kindex rwatch @item rwatch @var{expr} Set a watchpoint that will break when watch @var{expr} is read by the program. -If you use both watchpoints, both must be set with the @code{rwatch} -command. @kindex awatch @item awatch @var{expr} -Set a watchpoint that will break when @var{args} is read and written into -by the program. If you use both watchpoints, both must be set with the -@code{awatch} command. +Set a watchpoint that will break when @var{expr} is either read or written into +by the program. @kindex info watchpoints @item info watchpoints @@ -2897,26 +2646,69 @@ Hardware watchpoint @var{num}: @var{expr} @noindent if it was able to set a hardware watchpoint. -The SPARClite DSU will generate traps when a program accesses -some data or instruction address that is assigned to the debug registers. -For the data addresses, DSU facilitates the @code{watch} command. -However the hardware breakpoint registers can only take two data watchpoints, -and both watchpoints must be the same kind. For example, you can set two -watchpoints with @code{watch} commands, two with @code{rwatch} -commands, @strong{or} two with @code{awatch} commands, but you cannot set one -watchpoint with one command and the other with a different command. +Currently, the @code{awatch} and @code{rwatch} commands can only set +hardware watchpoints, because accesses to data that don't change the +value of the watched expression cannot be detected without examining +every instruction as it is being executed, and @value{GDBN} does not do +that currently. If @value{GDBN} finds that it is unable to set a +hardware breakpoint with the @code{awatch} or @code{rwatch} command, it +will print a message like this: + +@smallexample +Expression cannot be implemented with read/access watchpoint. +@end smallexample + +Sometimes, @value{GDBN} cannot set a hardware watchpoint because the +data type of the watched expression is wider than what a hardware +watchpoint on the target machine can handle. For example, some systems +can only watch regions that are up to 4 bytes wide; on such systems you +cannot set hardware watchpoints for an expression that yields a +double-precision floating-point number (which is typically 8 bytes +wide). As a work-around, it might be possible to break the large region +into a series of smaller ones and watch them with separate watchpoints. + +If you set too many hardware watchpoints, @value{GDBN} might be unable +to insert all of them when you resume the execution of your program. +Since the precise number of active watchpoints is unknown until such +time as the program is about to be resumed, @value{GDBN} might not be +able to warn you about this when you set the watchpoints, and the +warning will be printed only when the program is resumed: + +@smallexample +Hardware watchpoint @var{num}: Could not insert watchpoint +@end smallexample + +@noindent +If this happens, delete or disable some of the watchpoints. + +The SPARClite DSU will generate traps when a program accesses some data +or instruction address that is assigned to the debug registers. For the +data addresses, DSU facilitates the @code{watch} command. However the +hardware breakpoint registers can only take two data watchpoints, and +both watchpoints must be the same kind. For example, you can set two +watchpoints with @code{watch} commands, two with @code{rwatch} commands, +@strong{or} two with @code{awatch} commands, but you cannot set one +watchpoint with one command and the other with a different command. @value{GDBN} will reject the command if you try to mix watchpoints. Delete or disable unused watchpoint commands before setting new ones. If you call a function interactively using @code{print} or @code{call}, -any watchpoints you have set will be inactive until GDB reaches another +any watchpoints you have set will be inactive until @value{GDBN} reaches another kind of breakpoint or the call completes. -@ifclear BARETARGET +@value{GDBN} automatically deletes watchpoints that watch local +(automatic) variables, or expressions that involve such variables, when +they go out of scope, that is, when the execution leaves the block in +which these variables were defined. In particular, when the program +being debugged terminates, @emph{all} local variables go out of scope, +and so only watchpoints that watch global variables remain set. If you +rerun the program, you will need to set all such watchpoints again. One +way of doing that would be to set a code breakpoint at the entry to the +@code{main} function and when it breaks, set all the watchpoints. + @quotation @cindex watchpoints and threads @cindex threads and watchpoints -@ifclear HPPA @emph{Warning:} In multi-thread programs, watchpoints have only limited usefulness. With the current watchpoint implementation, @value{GDBN} can only watch the value of an expression @emph{in a single thread}. If @@ -2925,29 +2717,27 @@ thread's activity (and if you are also confident that no other thread can become current), then you can use watchpoints as usual. However, @value{GDBN} may not notice when a non-current thread's activity changes the expression. -@end ifclear -@ifset HPPA -@emph{Warning:} In multi-thread programs, software watchpoints have only -limited usefulness. If @value{GDBN} creates a software watchpoint, it -can only watch the value of an expression @emph{in a single thread}. If -you are confident that the expression can only change due to the current -thread's activity (and if you are also confident that no other thread -can become current), then you can use software watchpoints as usual. -However, @value{GDBN} may not notice when a non-current thread's -activity changes the expression. (Hardware watchpoints, in contrast, -watch an expression in all threads.) -@end ifset + +@c FIXME: this is almost identical to the previous paragraph. +@emph{HP-UX Warning:} In multi-thread programs, software watchpoints +have only limited usefulness. If @value{GDBN} creates a software +watchpoint, it can only watch the value of an expression @emph{in a +single thread}. If you are confident that the expression can only +change due to the current thread's activity (and if you are also +confident that no other thread can become current), then you can use +software watchpoints as usual. However, @value{GDBN} may not notice +when a non-current thread's activity changes the expression. (Hardware +watchpoints, in contrast, watch an expression in all threads.) @end quotation -@end ifclear -@node Set Catchpoints, Delete Breaks, Set Watchpoints, Breakpoints +@node Set Catchpoints @subsection Setting catchpoints -@cindex catchpoints +@cindex catchpoints, setting @cindex exception handlers @cindex event handling You can use @dfn{catchpoints} to cause the debugger to stop for certain -kinds of program events, such as C++ exceptions or the loading of a +kinds of program events, such as C@t{++} exceptions or the loading of a shared library. Use the @code{catch} command to set a catchpoint. @table @code @@ -2957,11 +2747,11 @@ Stop when @var{event} occurs. @var{event} can be any of the following: @table @code @item throw @kindex catch throw -The throwing of a C++ exception. +The throwing of a C@t{++} exception. @item catch @kindex catch catch -The catching of a C++ exception. +The catching of a C@t{++} exception. @item exec @kindex catch exec @@ -2996,7 +2786,7 @@ automatically deleted after the first time the event is caught. Use the @code{info break} command to list the current catchpoints. -There are currently some limitations to C++ exception handling +There are currently some limitations to C@t{++} exception handling (@code{catch throw} and @code{catch catch}) in @value{GDBN}: @itemize @bullet @@ -3026,14 +2816,14 @@ breakpoint in an exception handler instead, it may not be easy to find out where the exception was raised. To stop just before an exception handler is called, you need some -knowledge of the implementation. In the case of @sc{gnu} C++, exceptions are +knowledge of the implementation. In the case of @sc{gnu} C@t{++}, exceptions are raised by calling a library function named @code{__raise_exception} which has the following ANSI C interface: @example /* @var{addr} is where the exception identifier is stored. - ID is the exception identifier. */ - void __raise_exception (void **@var{addr}, void *@var{id}); + @var{id} is the exception identifier. */ + void __raise_exception (void **addr, void *id); @end example @noindent @@ -3048,7 +2838,7 @@ breakpoints to stop your program when any of a number of exceptions are raised. -@node Delete Breaks, Disabling, Set Catchpoints, Breakpoints +@node Delete Breaks @subsection Deleting breakpoints @cindex clearing breakpoints, watchpoints, catchpoints @@ -3085,15 +2875,15 @@ Delete any breakpoints set at or within the code of the specified line. @cindex delete breakpoints @kindex delete -@kindex d -@item delete @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} -Delete the breakpoints, watchpoints, or catchpoints of the numbers -specified as arguments. If no argument is specified, delete all +@kindex d @r{(@code{delete})} +@item delete @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]} +Delete the breakpoints, watchpoints, or catchpoints of the breakpoint +ranges specified as arguments. If no argument is specified, delete all breakpoints (@value{GDBN} asks confirmation, unless you have @code{set confirm off}). You can abbreviate this command as @code{d}. @end table -@node Disabling, Conditions, Delete Breaks, Breakpoints +@node Disabling @subsection Disabling breakpoints @kindex disable breakpoints @@ -3120,11 +2910,11 @@ with the @code{break} command starts out in this state. Disabled. The breakpoint has no effect on your program. @item Enabled once. The breakpoint stops your program, but then becomes -disabled. A breakpoint set with the @code{tbreak} command starts out in -this state. +disabled. @item Enabled for deletion. The breakpoint stops your program, but -immediately after it does so it is deleted permanently. +immediately after it does so it is deleted permanently. A breakpoint +set with the @code{tbreak} command starts out in this state. @end itemize You can use the following commands to enable or disable breakpoints, @@ -3133,8 +2923,8 @@ watchpoints, and catchpoints: @table @code @kindex disable breakpoints @kindex disable -@kindex dis -@item disable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@kindex dis @r{(@code{disable})} +@item disable @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]} Disable the specified breakpoints---or all breakpoints, if none are listed. A disabled breakpoint has no effect but is not forgotten. All options such as ignore-counts, conditions and commands are remembered in @@ -3143,19 +2933,21 @@ case the breakpoint is enabled again later. You may abbreviate @kindex enable breakpoints @kindex enable -@item enable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@item enable @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]} Enable the specified breakpoints (or all defined breakpoints). They become effective once again in stopping your program. -@item enable @r{[}breakpoints@r{]} once @var{bnums}@dots{} +@item enable @r{[}breakpoints@r{]} once @var{range}@dots{} Enable the specified breakpoints temporarily. @value{GDBN} disables any of these breakpoints immediately after stopping your program. -@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{} +@item enable @r{[}breakpoints@r{]} delete @var{range}@dots{} Enable the specified breakpoints to work once, then die. @value{GDBN} deletes any of these breakpoints as soon as your program stops there. @end table +@c FIXME: I think the following ``Except for [...] @code{tbreak}'' is +@c confusing: tbreak is also initially enabled. Except for a breakpoint set with @code{tbreak} (@pxref{Set Breaks, ,Setting breakpoints}), breakpoints that you set are initially enabled; subsequently, they become disabled or enabled only when you use one of @@ -3164,13 +2956,13 @@ breakpoint of its own, but it does not change the state of your other breakpoints; see @ref{Continuing and Stepping, ,Continuing and stepping}.) -@node Conditions, Break Commands, Disabling, Breakpoints +@node Conditions @subsection Break conditions @cindex conditional breakpoints @cindex breakpoint conditions @c FIXME what is scope of break condition expr? Context where wanted? -@c in particular for a watchpoint? +@c in particular for a watchpoint? The simplest sort of breakpoint breaks every time your program reaches a specified place. You can also specify a @dfn{condition} for a breakpoint. A condition is just a Boolean expression in your @@ -3197,7 +2989,8 @@ format special data structures. The effects are completely predictable unless there is another enabled breakpoint at the same address. (In that case, @value{GDBN} might see the other breakpoint first and stop your program without checking the condition of this one.) Note that -breakpoint commands are usually more convenient and flexible for the +breakpoint commands are usually more convenient and flexible than break +conditions for the purpose of performing side effects when a breakpoint is reached (@pxref{Break Commands, ,Breakpoint command lists}). @@ -3205,19 +2998,11 @@ Break conditions can be specified when a breakpoint is set, by using @samp{if} in the arguments to the @code{break} command. @xref{Set Breaks, ,Setting breakpoints}. They can also be changed at any time with the @code{condition} command. -@ifclear HPPA -@c The watch command now seems to recognize the if keyword. -@c catch doesn't, though. -The @code{watch} command does not recognize the @code{if} keyword; -@code{condition} is the only way to impose a further condition on a -watchpoint. -@end ifclear -@ifset HPPA + You can also use the @code{if} keyword with the @code{watch} command. The @code{catch} command does not recognize the @code{if} keyword; @code{condition} is the only way to impose a further condition on a catchpoint. -@end ifset @table @code @kindex condition @@ -3228,12 +3013,19 @@ breakpoint @var{bnum} stops your program only if the value of @var{expression} is true (nonzero, in C). When you use @code{condition}, @value{GDBN} checks @var{expression} immediately for syntactic correctness, and to determine whether symbols in it have -referents in the context of your breakpoint. -@c FIXME so what does GDB do if there is no referent? Moreover, what -@c about watchpoints? +referents in the context of your breakpoint. If @var{expression} uses +symbols not referenced in the context of the breakpoint, @value{GDBN} +prints an error message: + +@example +No symbol "foo" in current context. +@end example + +@noindent @value{GDBN} does not actually evaluate @var{expression} at the time the @code{condition} -command is given, however. @xref{Expressions, ,Expressions}. +command (or a command that sets a breakpoint with a condition, like +@code{break if @dots{}}) is given, however. @xref{Expressions, ,Expressions}. @item condition @var{bnum} Remove the condition from breakpoint number @var{bnum}. It becomes @@ -3281,7 +3073,7 @@ variables}. Ignore counts apply to breakpoints, watchpoints, and catchpoints. -@node Break Commands, Breakpoint Menus, Conditions, Breakpoints +@node Break Commands @subsection Breakpoint command lists @cindex breakpoint commands @@ -3362,13 +3154,12 @@ cont end @end example -@ifclear CONLY -@node Breakpoint Menus, , Break Commands, Breakpoints +@node Breakpoint Menus @subsection Breakpoint menus @cindex overloading @cindex symbol overloading -Some programming languages (notably C++) permit a single function name +Some programming languages (notably C@t{++}) permit a single function name to be defined several times, for application in different contexts. This is called @dfn{overloading}. When a function name is overloaded, @samp{break @var{function}} is not enough to tell @value{GDBN} where you want @@ -3408,39 +3199,62 @@ Use the "delete" command to delete unwanted (@value{GDBP}) @end group @end smallexample -@end ifclear @c @ifclear BARETARGET -@c @node Error in Breakpoints -@c @subsection ``Cannot insert breakpoints'' +@node Error in Breakpoints +@subsection ``Cannot insert breakpoints'' @c @c FIXME!! 14/6/95 Is there a real example of this? Let's use it. @c -@c Under some operating systems, breakpoints cannot be used in a program if -@c any other process is running that program. In this situation, -@c attempting to run or continue a program with a breakpoint causes -@c @value{GDBN} to stop the other process. -@c -@c When this happens, you have three ways to proceed: -@c -@c @enumerate -@c @item -@c Remove or disable the breakpoints, then continue. -@c -@c @item -@c Suspend @value{GDBN}, and copy the file containing your program to a new -@c name. Resume @value{GDBN} and use the @code{exec-file} command to specify -@c that @value{GDBN} should run your program under that name. -@c Then start your program again. -@c -@c @item -@c Relink your program so that the text segment is nonsharable, using the -@c linker option @samp{-N}. The operating system limitation may not apply -@c to nonsharable executables. -@c @end enumerate +Under some operating systems, breakpoints cannot be used in a program if +any other process is running that program. In this situation, +attempting to run or continue a program with a breakpoint causes +@value{GDBN} to print an error message: + +@example +Cannot insert breakpoints. +The same program may be running in another process. +@end example + +When this happens, you have three ways to proceed: + +@enumerate +@item +Remove or disable the breakpoints, then continue. + +@item +Suspend @value{GDBN}, and copy the file containing your program to a new +name. Resume @value{GDBN} and use the @code{exec-file} command to specify +that @value{GDBN} should run your program under that name. +Then start your program again. + +@item +Relink your program so that the text segment is nonsharable, using the +linker option @samp{-N}. The operating system limitation may not apply +to nonsharable executables. +@end enumerate @c @end ifclear -@node Continuing and Stepping, Signals, Breakpoints, Stopping +A similar message can be printed if you request too many active +hardware-assisted breakpoints and watchpoints: + +@c FIXME: the precise wording of this message may change; the relevant +@c source change is not committed yet (Sep 3, 1999). +@smallexample +Stopped; cannot insert breakpoints. +You may have requested too many hardware breakpoints and watchpoints. +@end smallexample + +@noindent +This message is printed when you attempt to resume the program, since +only then @value{GDBN} knows exactly how many hardware breakpoints and +watchpoints it needs to insert. + +When this message is printed, you need to disable or remove some of the +hardware-assisted breakpoints and watchpoints, and then continue. + + +@node Continuing and Stepping @section Continuing and stepping @cindex stepping @@ -3450,21 +3264,15 @@ Use the "delete" command to delete unwanted completes normally. In contrast, @dfn{stepping} means executing just one more ``step'' of your program, where ``step'' may mean either one line of source code, or one machine instruction (depending on what -particular command you use). Either when continuing -or when stepping, your program may stop even sooner, due to -@ifset BARETARGET -a breakpoint. -@end ifset -@ifclear BARETARGET -a breakpoint or a signal. (If due to a signal, you may want to use -@code{handle}, or use @samp{signal 0} to resume execution. -@xref{Signals, ,Signals}.) -@end ifclear +particular command you use). Either when continuing or when stepping, +your program may stop even sooner, due to a breakpoint or a signal. (If +it stops due to a signal, you may want to use @code{handle}, or use +@samp{signal 0} to resume execution. @xref{Signals, ,Signals}.) @table @code @kindex continue -@kindex c -@kindex fg +@kindex c @r{(@code{continue})} +@kindex fg @r{(resume foreground execution)} @item continue @r{[}@var{ignore-count}@r{]} @itemx c @r{[}@var{ignore-count}@r{]} @itemx fg @r{[}@var{ignore-count}@r{]} @@ -3478,8 +3286,10 @@ The argument @var{ignore-count} is meaningful only when your program stopped due to a breakpoint. At other times, the argument to @code{continue} is ignored. -The synonyms @code{c} and @code{fg} are provided purely for convenience, -and have exactly the same behavior as @code{continue}. +The synonyms @code{c} and @code{fg} (for @dfn{foreground}, as the +debugged program is deemed to be the foreground program) are provided +purely for convenience, and have exactly the same behavior as +@code{continue}. @end table To resume execution at a different place, you can use @code{return} @@ -3496,7 +3306,7 @@ interesting, until you see the problem happen. @table @code @kindex step -@kindex s +@kindex s @r{(@code{step})} @item step Continue running your program until control reaches a different source line, then stop it and return control to @value{GDBN}. This command is @@ -3516,34 +3326,33 @@ without debugging information, use the @code{stepi} command, described below. @end quotation -The @code{step} command now only stops at the first instruction of a -source line. This prevents the multiple stops that used to occur in -switch statements, for loops, etc. @code{step} continues to stop if a -function that has debugging information is called within the line. +The @code{step} command only stops at the first instruction of a source +line. This prevents the multiple stops that could otherwise occur in +@code{switch} statements, @code{for} loops, etc. @code{step} continues +to stop if a function that has debugging information is called within +the line. In other words, @code{step} @emph{steps inside} any functions +called within the line. -Also, the @code{step} command now only enters a subroutine if there is line -number information for the subroutine. Otherwise it acts like the -@code{next} command. This avoids problems when using @code{cc -gl} +Also, the @code{step} command only enters a function if there is line +number information for the function. Otherwise it acts like the +@code{next} command. This avoids problems when using @code{cc -gl} on MIPS machines. Previously, @code{step} entered subroutines if there -was any debugging information about the routine. +was any debugging information about the routine. @item step @var{count} Continue running as in @code{step}, but do so @var{count} times. If a -breakpoint is reached, -@ifclear BARETARGET -or a signal not related to stepping occurs before @var{count} steps, -@end ifclear -stepping stops right away. +breakpoint is reached, or a signal not related to stepping occurs before +@var{count} steps, stepping stops right away. @kindex next -@kindex n +@kindex n @r{(@code{next})} @item next @r{[}@var{count}@r{]} Continue to the next source line in the current (innermost) stack frame. -This is similar to @code{step}, but function calls that appear within the line -of code are executed without stopping. Execution stops when control -reaches a different line of code at the original stack level that was -executing when you gave the @code{next} command. This command is abbreviated -@code{n}. +This is similar to @code{step}, but function calls that appear within +the line of code are executed without stopping. Execution stops when +control reaches a different line of code at the original stack level +that was executing when you gave the @code{next} command. This command +is abbreviated @code{n}. An argument @var{count} is a repeat count, as for @code{step}. @@ -3555,9 +3364,26 @@ An argument @var{count} is a repeat count, as for @code{step}. @c @code{step}, but any function calls appearing within the code of the @c function are executed without stopping. -The @code{next} command now only stops at the first instruction of a -source line. This prevents the multiple stops that used to occur in -switch statements, for loops, etc. +The @code{next} command only stops at the first instruction of a +source line. This prevents multiple stops that could otherwise occur in +@code{switch} statements, @code{for} loops, etc. + +@kindex set step-mode +@item set step-mode +@cindex functions without line info, and stepping +@cindex stepping into functions with no line info +@itemx set step-mode on +The @code{set step-mode on} command causes the @code{step} command to +stop at the first instruction of a function which contains no debug line +information rather than stepping over it. + +This is useful in cases where you may be interested in inspecting the +machine instructions of a function which has no symbolic info and do not +want @value{GDBN} to automatically skip over this function. + +@item set step-mode off +Causes the @code{step} command to step over any functions which contains no +debug information. This is the default. @kindex finish @item finish @@ -3568,7 +3394,7 @@ Contrast this with the @code{return} command (@pxref{Returning, ,Returning from a function}). @kindex until -@kindex u +@kindex u @r{(@code{until})} @item until @itemx u Continue running until a source line past the current line, in the @@ -3622,8 +3448,9 @@ the forms of argument acceptable to @code{break} (@pxref{Set Breaks, and hence is quicker than @code{until} without an argument. @kindex stepi -@kindex si +@kindex si @r{(@code{stepi})} @item stepi +@itemx stepi @var{arg} @itemx si Execute one machine instruction, then stop and return to the debugger. @@ -3636,8 +3463,9 @@ An argument is a repeat count, as in @code{step}. @need 750 @kindex nexti -@kindex ni +@kindex ni @r{(@code{nexti})} @item nexti +@itemx nexti @var{arg} @itemx ni Execute one machine instruction, but if it is a function call, proceed until the function returns. @@ -3645,15 +3473,14 @@ proceed until the function returns. An argument is a repeat count, as in @code{next}. @end table -@ifset POSIX -@node Signals, Thread Stops, Continuing and Stepping, Stopping +@node Signals @section Signals @cindex signals A signal is an asynchronous event that can happen in a program. The operating system defines the possible kinds of signals, and gives each kind a name and a number. For example, in Unix @code{SIGINT} is the -signal a program gets when you type an interrupt (often @kbd{C-c}); +signal a program gets when you type an interrupt character (often @kbd{C-c}); @code{SIGSEGV} is the signal a program gets from referencing a place in memory far away from all the areas in use; @code{SIGALRM} occurs when the alarm clock timer goes off (which happens only if your program has @@ -3662,7 +3489,7 @@ requested an alarm). @cindex fatal signals Some signals, including @code{SIGALRM}, are a normal part of the functioning of your program. Others, such as @code{SIGSEGV}, indicate -errors; these signals are @dfn{fatal} (kill your program immediately) if the +errors; these signals are @dfn{fatal} (they kill your program immediately) if the program has not specified in advance some other way to handle the signal. @code{SIGINT} does not indicate an error in your program, but it is normally fatal so it can carry out the purpose of the interrupt: to kill the program. @@ -3672,25 +3499,29 @@ program. You can tell @value{GDBN} in advance what to do for each kind of signal. @cindex handling signals -Normally, @value{GDBN} is set up to ignore non-erroneous signals like @code{SIGALRM} -(so as not to interfere with their role in the functioning of your program) +Normally, @value{GDBN} is set up to let the non-erroneous signals like +@code{SIGALRM} be silently passed to your program +(so as not to interfere with their role in the program's functioning) but to stop your program immediately whenever an error signal happens. You can change these settings with the @code{handle} command. @table @code @kindex info signals @item info signals +@itemx info handle Print a table of all the kinds of signals and how @value{GDBN} has been told to handle each one. You can use this to see the signal numbers of all the defined types of signals. -@code{info handle} is the new alias for @code{info signals}. +@code{info handle} is an alias for @code{info signals}. @kindex handle @item handle @var{signal} @var{keywords}@dots{} -Change the way @value{GDBN} handles signal @var{signal}. @var{signal} can -be the number of a signal or its name (with or without the @samp{SIG} at the -beginning). The @var{keywords} say what change to make. +Change the way @value{GDBN} handles signal @var{signal}. @var{signal} +can be the number of a signal or its name (with or without the +@samp{SIG} at the beginning); a list of signal numbers of the form +@samp{@var{low}-@var{high}}; or the word @samp{all}, meaning all the +known signals. The @var{keywords} say what change to make. @end table @c @group @@ -3714,22 +3545,31 @@ the @code{print} keyword as well. implies the @code{nostop} keyword as well. @item pass +@itemx noignore @value{GDBN} should allow your program to see this signal; your program can handle the signal, or else it may terminate if the signal is fatal -and not handled. +and not handled. @code{pass} and @code{noignore} are synonyms. @item nopass +@itemx ignore @value{GDBN} should not allow your program to see this signal. +@code{nopass} and @code{ignore} are synonyms. @end table @c @end group -When a signal stops your program, the signal is not visible until you +When a signal stops your program, the signal is not visible to the +program until you continue. Your program sees the signal then, if @code{pass} is in effect for the signal in question @emph{at that time}. In other words, after @value{GDBN} reports a signal, you can use the @code{handle} command with @code{pass} or @code{nopass} to control whether your program sees that signal when you continue. +The default is set to @code{nostop}, @code{noprint}, @code{pass} for +non-erroneous signals such as @code{SIGALRM}, @code{SIGWINCH} and +@code{SIGCHLD}, and to @code{stop}, @code{print}, @code{pass} for the +erroneous signals. + You can also use the @code{signal} command to prevent your program from seeing a signal, or cause it to see a signal it normally would not see, or to give it any signal at any time. For example, if your program stopped @@ -3738,11 +3578,9 @@ values into the erroneous variables and continue, hoping to see more execution; but your program would probably terminate immediately as a result of the fatal signal once it saw the signal. To prevent this, you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your -program a signal}. -@end ifset +program a signal}. -@ifclear BARETARGET -@node Thread Stops, , Signals, Stopping +@node Thread Stops @section Stopping and starting multi-thread programs When your program has multiple threads (@pxref{Threads,, Debugging @@ -3773,7 +3611,7 @@ well; in this case, place @samp{thread @var{threadno}} before the breakpoint condition, like this: @smallexample -(gdb) break frik.c:13 thread 28 if bartab > lim +(@value{GDBP}) break frik.c:13 thread 28 if bartab > lim @end smallexample @end table @@ -3790,7 +3628,7 @@ underfoot. @cindex threads, continuing Conversely, whenever you restart the program, @emph{all} threads start executing. @emph{This is true even when single-stepping} with commands -like @code{step} or @code{next}. +like @code{step} or @code{next}. In particular, @value{GDBN} cannot single-step all threads in lockstep. Since thread scheduling is up to your debugging target's operating @@ -3816,32 +3654,30 @@ current thread may run when the inferior is resumed. The @code{step} mode optimizes for single-stepping. It stops other threads from ``seizing the prompt'' by preempting the current thread while you are stepping. Other threads will only rarely (or never) get a chance to run -when you step. They are more likely to run when you ``next'' over a +when you step. They are more likely to run when you @samp{next} over a function call, and they are completely free to run when you use commands -like ``continue'', ``until'', or ``finish''. However, unless another +like @samp{continue}, @samp{until}, or @samp{finish}. However, unless another thread hits a breakpoint during its timeslice, they will never steal the -GDB prompt away from the thread that you are debugging. +@value{GDBN} prompt away from the thread that you are debugging. @item show scheduler-locking Display the current scheduler locking mode. @end table -@end ifclear - -@node Stack, Source, Stopping, Top +@node Stack @chapter Examining the Stack When your program has stopped, the first thing you need to know is where it stopped and how it got there. @cindex call stack -Each time your program performs a function call, information about the call -is generated. -That information includes the location of the call in your program, -the arguments of the call, +Each time your program performs a function call, information about the call +is generated. +That information includes the location of the call in your program, +the arguments of the call, and the local variables of the function being called. -The information is saved in a block of data called a @dfn{stack frame}. +The information is saved in a block of data called a @dfn{stack frame}. The stack frames are allocated in a region of memory called the @dfn{call stack}. @@ -3857,7 +3693,7 @@ special @value{GDBN} commands to select whichever frame you are interested in. @xref{Selection, ,Selecting a frame}. When your program stops, @value{GDBN} automatically selects the -currently executing frame and describes it briefly, similar to the +currently executing frame and describes it briefly, similar to the @code{frame} command (@pxref{Frame Info, ,Information about a frame}). @menu @@ -3865,14 +3701,13 @@ currently executing frame and describes it briefly, similar to the * Backtrace:: Backtraces * Selection:: Selecting a frame * Frame Info:: Information on a frame -* Alpha/MIPS Stack:: Alpha and MIPS machines and the function stack @end menu -@node Frames, Backtrace, Stack, Stack +@node Frames @section Stack frames -@cindex frame +@cindex frame, definition @cindex stack frame The call stack is divided up into contiguous pieces called @dfn{stack frames}, or @dfn{frames} for short; each frame is the data associated @@ -3907,11 +3742,15 @@ and so on upward. These numbers do not really exist in your program; they are assigned by @value{GDBN} to give you a way of designating stack frames in @value{GDBN} commands. -@c below produces an acceptable overful hbox. --mew 13aug1993 +@c The -fomit-frame-pointer below perennially causes hbox overflow +@c underflow problems. @cindex frameless execution Some compilers provide a way to compile functions so that they operate -without stack frames. (For example, the @code{@value{GCC}} option -@samp{-fomit-frame-pointer} generates functions without a frame.) +without stack frames. (For example, the @value{GCC} option +@example +@samp{-fomit-frame-pointer} +@end example +generates functions without a frame.) This is occasionally done with heavily used library functions to save the frame setup time. @value{GDBN} has limited facilities for dealing with these function invocations. If the innermost function invocation @@ -3921,21 +3760,23 @@ correct tracing of the function call chain. However, @value{GDBN} has no provision for frameless functions elsewhere in the stack. @table @code -@kindex frame +@kindex frame@r{, command} +@cindex current stack frame @item frame @var{args} -The @code{frame} command allows you to move from one stack frame to another, +The @code{frame} command allows you to move from one stack frame to another, and to print the stack frame you select. @var{args} may be either the -address of the frame or the stack frame number. Without an argument, -@code{frame} prints the current stack frame. +address of the frame or the stack frame number. Without an argument, +@code{frame} prints the current stack frame. @kindex select-frame +@cindex selecting frame silently @item select-frame The @code{select-frame} command allows you to move from one stack frame to another without printing the frame. This is the silent version of @code{frame}. @end table -@node Backtrace, Selection, Frames, Stack +@node Backtrace @section Backtraces @cindex backtraces @@ -3948,7 +3789,7 @@ stack. @table @code @kindex backtrace -@kindex bt +@kindex bt @r{(@code{backtrace})} @item backtrace @itemx bt Print a backtrace of the entire stack: one line per frame for all @@ -3968,7 +3809,7 @@ Similar, but print only the outermost @var{n} frames. @kindex where @kindex info stack -@kindex info s +@kindex info s @r{(@code{info stack})} The names @code{where} and @code{info stack} (abbreviated @code{info s}) are additional aliases for @code{backtrace}. @@ -3984,7 +3825,7 @@ Here is an example of a backtrace. It was made with the command @smallexample @group -#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) +#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) at builtin.c:993 #1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242 #2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08) @@ -3998,7 +3839,7 @@ The display for frame zero does not begin with a program counter value, indicating that your program has stopped at the beginning of the code for line @code{993} of @code{builtin.c}. -@node Selection, Frame Info, Backtrace, Stack +@node Selection @section Selecting a frame Most commands for examining the stack and other data in your program work on @@ -4007,8 +3848,8 @@ selecting a stack frame; all of them finish by printing a brief description of the stack frame just selected. @table @code -@kindex frame -@kindex f +@kindex frame@r{, selecting} +@kindex f @r{(@code{frame})} @item frame @var{n} @itemx f @var{n} Select frame number @var{n}. Recall that frame zero is the innermost @@ -4024,8 +3865,6 @@ impossible for @value{GDBN} to assign numbers properly to all frames. In addition, this can be useful when your program has multiple stacks and switches between them. -@ifclear H8EXCLUSIVE -@ifclear HPPA On the SPARC architecture, @code{frame} needs two addresses to select an arbitrary frame: a frame pointer and a stack pointer. @@ -4037,8 +3876,6 @@ pointer, a program counter, and a memory stack pointer. @c note to future updaters: this is conditioned on a flag @c SETUP_ARBITRARY_FRAME in the tm-*.h files. The above is up to date @c as of 27 Jan 1994. -@end ifclear -@end ifclear @kindex up @item up @var{n} @@ -4047,7 +3884,7 @@ advances toward the outermost frame, to higher frame numbers, to frames that have existed longer. @var{n} defaults to one. @kindex down -@kindex do +@kindex do @r{(@code{down})} @item down @var{n} Move @var{n} frames down the stack. For positive numbers @var{n}, this advances toward the innermost frame, to lower frame numbers, to frames @@ -4058,7 +3895,7 @@ abbreviate @code{down} as @code{do}. All of these commands end by printing two lines of output describing the frame. The first line shows the frame number, the function name, the arguments, and the source file and line number of execution in that -frame. The second line shows the text of that source line. +frame. The second line shows the text of that source line. @need 1000 For example: @@ -4088,7 +3925,7 @@ in @value{GDBN} command scripts, where the output might be unnecessary and distracting. @end table -@node Frame Info, Alpha/MIPS Stack, Selection, Stack +@node Frame Info @section Information about a frame There are several other commands to print information about the selected @@ -4104,15 +3941,15 @@ argument, this command is used to select a stack frame. @xref{Selection, ,Selecting a frame}. @kindex info frame -@kindex info f +@kindex info f @r{(@code{info frame})} @item info frame @itemx info f This command prints a verbose description of the selected stack frame, including: @itemize @bullet -@item -the address of the frame +@item +the address of the frame @item the address of the next frame down (called by this frame) @item @@ -4122,6 +3959,8 @@ the language in which the source code corresponding to this frame is written @item the address of the frame's arguments @item +the address of the frame's local variables +@item the program counter saved in it (the address of execution in the caller frame) @item which registers were saved in the frame @@ -4149,57 +3988,20 @@ Print the local variables of the selected frame, each on a separate line. These are all variables (declared either static or automatic) accessible at the point of execution of the selected frame. -@ifclear CONLY -@ifclear HPPA @kindex info catch -@cindex catch exceptions -@cindex exception handlers +@cindex catch exceptions, list active handlers +@cindex exception handlers, how to list @item info catch Print a list of all the exception handlers that are active in the current stack frame at the current point of execution. To see other exception handlers, visit the associated frame (using the @code{up}, @code{down}, or @code{frame} commands); then type @code{info catch}. @xref{Set Catchpoints, , Setting catchpoints}. -@end ifclear -@end ifclear -@end table -@node Alpha/MIPS Stack, , Frame Info, Stack -@section MIPS/Alpha machines and the function stack - -@cindex stack on Alpha -@cindex stack on MIPS -@cindex Alpha stack -@cindex MIPS stack -Alpha- and MIPS-based computers use an unusual stack frame, which -sometimes requires @value{GDBN} to search backward in the object code to -find the beginning of a function. - -@cindex response time, MIPS debugging -To improve response time (especially for embedded applications, where -@value{GDBN} may be restricted to a slow serial line for this search) -you may want to limit the size of this search, using one of these -commands: - -@table @code -@cindex @code{heuristic-fence-post} (Alpha,MIPS) -@item set heuristic-fence-post @var{limit} -Restrict @value{GDBN} to examining at most @var{limit} bytes in its search -for the beginning of a function. A value of @var{0} (the default) -means there is no limit. However, except for @var{0}, the larger the -limit the more bytes @code{heuristic-fence-post} must search and -therefore the longer it takes to run. - -@item show heuristic-fence-post -Display the current limit. @end table -@noindent -These commands are available @emph{only} when @value{GDBN} is configured -for debugging programs on Alpha or MIPS processors. - -@node Source, Data, Stack, Top +@node Source @chapter Examining Source Files @value{GDBN} can print parts of your program's source, since the debugging @@ -4210,29 +4012,24 @@ the line where it stopped. Likewise, when you select a stack frame execution in that frame has stopped. You can print other portions of source files by explicit command. -@ifclear DOSHOST -If you use @value{GDBN} through its @sc{gnu} Emacs interface, you may prefer -to use -Emacs facilities to view source; @pxref{Emacs, ,Using @value{GDBN} under @sc{gnu} Emacs}. -@end ifclear +If you use @value{GDBN} through its @sc{gnu} Emacs interface, you may +prefer to use Emacs facilities to view source; see @ref{Emacs, ,Using +@value{GDBN} under @sc{gnu} Emacs}. @menu * List:: Printing source lines -@ifclear DOSHOST * Search:: Searching source files -@end ifclear - * Source Path:: Specifying source directories * Machine Code:: Source and machine code @end menu -@node List, Search, Source, Source +@node List @section Printing source lines @kindex list -@kindex l +@kindex l @r{(@code{list})} To print lines from a source file, use the @code{list} command -(abbreviated @code{l}). By default, ten lines are printed. +(abbreviated @code{l}). By default, ten lines are printed. There are several ways to specify what part of the file you want to print. Here are the forms of the @code{list} command most commonly used: @@ -4280,7 +4077,7 @@ each repetition moves up in the source file. @cindex linespec In general, the @code{list} command expects you to supply zero, one or two @dfn{linespecs}. Linespecs specify source lines; there are several ways -of writing them but the effect is always to specify some source line. +of writing them, but the effect is always to specify some source line. Here is a complete description of the possible arguments for @code{list}: @table @code @@ -4343,8 +4140,7 @@ Specifies the line containing the program address @var{address}. @var{address} may be any expression. @end table -@ifclear DOSHOST -@node Search, Source Path, List, Source +@node Search @section Searching source files @cindex searching @kindex reverse-search @@ -4359,7 +4155,7 @@ regular expression. @itemx search @var{regexp} The command @samp{forward-search @var{regexp}} checks each line, starting with the one following the last line listed, for a match for -@var{regexp}. It lists the line that is found. You can use the +@var{regexp}. It lists the line that is found. You can use the synonym @samp{search @var{regexp}} or abbreviate the command name as @code{fo}. @@ -4369,9 +4165,8 @@ with the one before the last line listed and going backward, for a match for @var{regexp}. It lists the line that is found. You can abbreviate this command as @code{rev}. @end table -@end ifclear -@node Source Path, Machine Code, Search, Source +@node Source Path @section Specifying source directories @cindex source path @@ -4399,21 +4194,24 @@ each line is in the file. @kindex directory @kindex dir -When you start @value{GDBN}, its source path is empty. +When you start @value{GDBN}, its source path includes only @samp{cdir} +and @samp{cwd}, in that order. To add other directories, use the @code{directory} command. @table @code @item directory @var{dirname} @dots{} @item dir @var{dirname} @dots{} Add directory @var{dirname} to the front of the source path. Several -directory names may be given to this command, separated by @samp{:} or +directory names may be given to this command, separated by @samp{:} +(@samp{;} on MS-DOS and MS-Windows, where @samp{:} usually appears as +part of absolute file names) or whitespace. You may specify a directory that is already in the source path; this moves it forward, so @value{GDBN} searches it sooner. @kindex cdir @kindex cwd -@kindex $cdir -@kindex $cwd +@vindex $cdir@r{, convenience variable} +@vindex $cwdr@r{, convenience variable} @cindex compilation directory @cindex current directory @cindex working directory @@ -4451,14 +4249,14 @@ directories you want in the source path. You can add all the directories in one command. @end enumerate -@node Machine Code, , Source Path, Source +@node Machine Code @section Source and machine code You can use the command @code{info line} to map source lines to program addresses (and vice versa), and the command @code{disassemble} to display a range of addresses as machine instructions. When run under @sc{gnu} Emacs -mode, the @code{info line} command now causes the arrow to point to the -line specified. Also, @code{info line} prints addresses in symbolic form as +mode, the @code{info line} command causes the arrow to point to the +line specified. Also, @code{info line} prints addresses in symbolic form as well as hex. @table @code @@ -4474,8 +4272,10 @@ For example, we can use @code{info line} to discover the location of the object code for the first line of function @code{m4_changequote}: +@c FIXME: I think this example should also show the addresses in +@c symbolic form, as they usually would be displayed. @smallexample -(@value{GDBP}) info line m4_changecom +(@value{GDBP}) info line m4_changequote Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350. @end smallexample @@ -4488,6 +4288,7 @@ Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404. @end smallexample @cindex @code{$_} and @code{info line} +@kindex x@r{(examine), and} info line After @code{info line}, the default address for the @code{x} command is changed to the starting address of the line, so that @samp{x/i} is sufficient to begin examining the machine code (@pxref{Memory, @@ -4510,7 +4311,6 @@ surrounding this value. Two arguments specify a range of addresses (first inclusive, second exclusive) to dump. @end table -@ifclear H8EXCLUSIVE The following example shows the disassembly of a range of addresses of HP PA-RISC 2.0 code: @@ -4527,49 +4327,30 @@ Dump of assembler code from 0x32c4 to 0x32e4: 0x32e0 <main+232>: ldil 0x3000,r31 End of assembler dump. @end smallexample -@end ifclear - -@ifset H8EXCLUSIVE -For example, here is the beginning of the output for the -disassembly of a function @code{fact}: - - -@smallexample -(@value{GDBP}) disas fact -Dump of assembler code for function fact: -to 0x808c: -0x802c <fact>: 6d f2 mov.w r2,@@-r7 -0x802e <fact+2>: 6d f3 mov.w r3,@@-r7 -0x8030 <fact+4>: 6d f6 mov.w r6,@@-r7 -0x8032 <fact+6>: 0d 76 mov.w r7,r6 -0x8034 <fact+8>: 6f 70 00 08 mov.w @@(0x8,r7),r0 -0x8038 <fact+12> 19 11 sub.w r1,r1 - . - . - . -@end smallexample -@end ifset Some architectures have more than one commonly-used set of instruction mnemonics or other syntax. @table @code -@kindex set assembly-language +@kindex set disassembly-flavor @cindex assembly instructions @cindex instructions, assembly @cindex machine instructions @cindex listing machine instructions -@item set assembly-language @var{instruction-set} +@cindex Intel disassembly flavor +@cindex AT&T disassembly flavor +@item set disassembly-flavor @var{instruction-set} Select the instruction set to use when disassembling the program via the @code{disassemble} or @code{x/i} commands. Currently this command is only defined for the Intel x86 family. You -can set @var{instruction-set} to either @code{i386} or @code{i8086}. -The default is @code{i386}. +can set @var{instruction-set} to either @code{intel} or @code{att}. +The default is @code{att}, the AT&T flavor used by default by Unix +assemblers for x86-based targets. @end table -@node Data, Languages, Source, Top +@node Data @chapter Examining Data @cindex printing data @@ -4580,25 +4361,23 @@ The default is @code{i386}. @c document because it is nonstandard... Under Epoch it displays in a @c different window or something like that. The usual way to examine data in your program is with the @code{print} -command (abbreviated @code{p}), or its synonym @code{inspect}. -@ifclear CONLY -It evaluates and prints the value of an expression of the language your -program is written in (@pxref{Languages, ,Using @value{GDBN} with Different -Languages}). -@end ifclear - -@table @code -@item print @var{exp} -@itemx print /@var{f} @var{exp} -@var{exp} is an expression (in the source language). By default the -value of @var{exp} is printed in a format appropriate to its data type; +command (abbreviated @code{p}), or its synonym @code{inspect}. It +evaluates and prints the value of an expression of the language your +program is written in (@pxref{Languages, ,Using @value{GDBN} with +Different Languages}). + +@table @code +@item print @var{expr} +@itemx print /@var{f} @var{expr} +@var{expr} is an expression (in the source language). By default the +value of @var{expr} is printed in a format appropriate to its data type; you can choose a different format by specifying @samp{/@var{f}}, where -@var{f} is a letter specifying the format; @pxref{Output Formats,,Output +@var{f} is a letter specifying the format; see @ref{Output Formats,,Output formats}. @item print @itemx print /@var{f} -If you omit @var{exp}, @value{GDBN} displays the last value again (from the +If you omit @var{expr}, @value{GDBN} displays the last value again (from the @dfn{value history}; @pxref{Value History, ,Value history}). This allows you to conveniently inspect the same value in an alternative format. @end table @@ -4607,13 +4386,10 @@ A more low-level way of examining data is with the @code{x} command. It examines data in memory at a specified address and prints it in a specified format. @xref{Memory, ,Examining memory}. -If you are interested in information about types, or about how the fields -of a struct -@ifclear CONLY -or class -@end ifclear -are declared, use the @code{ptype @var{exp}} -command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}. +If you are interested in information about types, or about how the +fields of a struct or a class are declared, use the @code{ptype @var{exp}} +command rather than @code{print}. @xref{Symbols, ,Examining the Symbol +Table}. @menu * Expressions:: Expressions @@ -4626,13 +4402,11 @@ command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}. * Value History:: Value history * Convenience Vars:: Convenience variables * Registers:: Registers -@ifclear HAVE-FLOAT * Floating Point Hardware:: Floating point hardware -@end ifclear - +* Memory Region Attributes:: Memory region attributes @end menu -@node Expressions, Variables, Data, Data +@node Expressions @section Expressions @cindex expressions @@ -4643,12 +4417,11 @@ by the programming language you are using is valid in an expression in and string constants. It unfortunately does not include symbols defined by preprocessor @code{#define} commands. -@value{GDBN} now supports array constants in expressions input by -the user. The syntax is @var{@{element, element@dots{}@}}. For example, -you can now use the command @code{print @{1, 2, 3@}} to build up an array in -memory that is malloc'd in the target program. +@value{GDBN} supports array constants in expressions input by +the user. The syntax is @{@var{element}, @var{element}@dots{}@}. For example, +you can use the command @code{print @{1, 2, 3@}} to build up an array in +memory that is @code{malloc}ed in the target program. -@ifclear CONLY Because C is so widespread, most of the expressions shown in examples in this manual are in C. @xref{Languages, , Using @value{GDBN} with Different Languages}, for information on how to use expressions in other @@ -4661,7 +4434,6 @@ Casts are supported in all languages, not just in C, because it is so useful to cast a number into a pointer in order to examine a structure at that address in memory. @c FIXME: casts supported---Mod2 true? -@end ifclear @value{GDBN} supports these operators, in addition to those common to programming languages: @@ -4687,7 +4459,7 @@ a cast). This construct is allowed regardless of what kind of data is normally supposed to reside at @var{addr}. @end table -@node Variables, Arrays, Expressions, Data +@node Variables @section Program variables The most common kind of expression to use is the name of a variable @@ -4701,13 +4473,13 @@ Variables in expressions are understood in the selected stack frame global (or file-static) @end itemize -@noindent or +@noindent or @itemize @bullet @item visible according to the scope rules of the programming language from the point of execution in that frame -@end itemize +@end itemize @noindent This means that in the function @@ -4738,10 +4510,10 @@ happens, referring to that name has unpredictable effects. If you wish, you can specify a static variable in a particular function or file, using the colon-colon notation: -@cindex colon-colon +@cindex colon-colon, context for variables/functions @iftex @c info cannot cope with a :: index entry, but why deprive hard copy readers? -@kindex :: +@cindex @code{::}, context for variables/functions @end iftex @example @var{file}::@var{variable} @@ -4758,14 +4530,12 @@ to print a global value of @code{x} defined in @file{f2.c}: (@value{GDBP}) p 'f2.c'::x @end example -@ifclear CONLY -@cindex C++ scope resolution +@cindex C@t{++} scope resolution This use of @samp{::} is very rarely in conflict with the very similar -use of the same notation in C++. @value{GDBN} also supports use of the C++ +use of the same notation in C@t{++}. @value{GDBN} also supports use of the C@t{++} scope resolution operator in @value{GDBN} expressions. @c FIXME: Um, so what happens in one of those rare cases where it's in @c conflict?? --mew -@end ifclear @cindex wrong values @cindex variable values, wrong @@ -4787,11 +4557,34 @@ This may also happen when the compiler does significant optimizations. To be sure of always seeing accurate values, turn off all optimization when compiling. -@node Arrays, Output Formats, Variables, Data +@cindex ``No symbol "foo" in current context'' +Another possible effect of compiler optimizations is to optimize +unused variables out of existence, or assign variables to registers (as +opposed to memory addresses). Depending on the support for such cases +offered by the debug info format used by the compiler, @value{GDBN} +might not be able to display values for such local variables. If that +happens, @value{GDBN} will print a message like this: + +@example +No symbol "foo" in current context. +@end example + +To solve such problems, either recompile without optimizations, or use a +different debug info format, if the compiler supports several such +formats. For example, @value{NGCC}, the @sc{gnu} C/C@t{++} compiler usually +supports the @samp{-gstabs} option. @samp{-gstabs} produces debug info +in a format that is superior to formats such as COFF. You may be able +to use DWARF2 (@samp{-gdwarf-2}), which is also an effective form for +debug info. See @ref{Debugging Options,,Options for Debugging Your +Program or @sc{gnu} CC, gcc.info, Using @sc{gnu} CC}, for more +information. + + +@node Arrays @section Artificial arrays @cindex artificial array -@kindex @@ +@kindex @@@r{, referencing memory as an array} It is often useful to print out several successive objects of the same type in memory; a section of an array, or an array of dynamically determined size for which only a pointer exists in the @@ -4833,7 +4626,7 @@ $1 = @{0x1234, 0x5678@} @end example As a convenience, if you leave the array length out (as in -@samp{(@var{type})[])@var{value}}) gdb calculates the size to fill +@samp{(@var{type}[])@var{value}}) @value{GDBN} calculates the size to fill the value (as @samp{sizeof(@var{value})/sizeof(@var{type})}: @example (@value{GDBP}) p/x (short[])0x12345678 @@ -4859,7 +4652,7 @@ p dtab[$i++]->fv @dots{} @end example -@node Output Formats, Memory, Arrays, Data +@node Output Formats @section Output formats @cindex formatted output @@ -4893,10 +4686,11 @@ Print as integer in octal. Print as integer in binary. The letter @samp{t} stands for ``two''. @footnote{@samp{b} cannot be used because these format letters are also used with the @code{x} command, where @samp{b} stands for ``byte''; -@pxref{Memory,,Examining memory}.} +see @ref{Memory,,Examining memory}.} @item a @cindex unknown address, locating +@cindex locate address Print as an address, both absolute in hexadecimal and as an offset from the nearest preceding symbol. You can use this format used to discover where (in what function) an unknown address is located: @@ -4906,6 +4700,10 @@ where (in what function) an unknown address is located: $3 = 0x54320 <_initialize_vx+396> @end example +@noindent +The command @code{info symbol 0x54320} yields similar results. +@xref{Symbols, info symbol}. + @item c Regard as an integer and print it as a character constant. @@ -4928,7 +4726,7 @@ To reprint the last value in the value history with a different format, you can use the @code{print} command with just a format and no expression. For example, @samp{p/x} reprints the last value in hex. -@node Memory, Auto Display, Output Formats, Data +@node Memory @section Examining memory You can use the command @code{x} (for ``examine'') to examine memory in @@ -4936,7 +4734,7 @@ any of several formats, independently of your program's data types. @cindex examining memory @table @code -@kindex x +@kindex x @r{(examine memory)} @item x/@var{nfu} @var{addr} @itemx x @var{addr} @itemx x @@ -4996,7 +4794,7 @@ For example, @samp{x/3uh 0x54320} is a request to display three halfwords (@code{h}) of memory, formatted as unsigned decimal integers (@samp{u}), starting at address @code{0x54320}. @samp{x/4xw $sp} prints the four words (@samp{w}) of memory above the stack pointer (here, @samp{$sp}; -@pxref{Registers}) in hexadecimal (@samp{x}). +@pxref{Registers, ,Registers}) in hexadecimal (@samp{x}). Since the letters indicating unit sizes are all distinct from the letters specifying output formats, you do not have to remember whether @@ -5008,7 +4806,7 @@ Even though the unit size @var{u} is ignored for the formats @samp{s} and @samp{i}, you might still want to use a count @var{n}; for example, @samp{3i} specifies that you want to see three machine instructions, including any operands. The command @code{disassemble} gives an -alternative way of inspecting machine instructions; @pxref{Machine +alternative way of inspecting machine instructions; see @ref{Machine Code,,Source and machine code}. All the defaults for the arguments to @code{x} are designed to make it @@ -5033,7 +4831,7 @@ If the @code{x} command has a repeat count, the address and contents saved are from the last memory unit printed; this is not the same as the last address printed if several units were printed on the last line of output. -@node Auto Display, Print Settings, Memory, Data +@node Auto Display @section Automatic display @cindex automatic display @cindex display of expressions @@ -5061,15 +4859,15 @@ supported by @code{x}; otherwise it uses @code{print}. @table @code @kindex display -@item display @var{exp} -Add the expression @var{exp} to the list of expressions to display +@item display @var{expr} +Add the expression @var{expr} to the list of expressions to display each time your program stops. @xref{Expressions, ,Expressions}. @code{display} does not repeat if you press @key{RET} again after using it. -@item display/@var{fmt} @var{exp} +@item display/@var{fmt} @var{expr} For @var{fmt} specifying only a display format and not a size or -count, add the expression @var{exp} to the auto-display list but +count, add the expression @var{expr} to the auto-display list but arrange to display it each time in the specified format @var{fmt}. @xref{Output Formats,,Output formats}. @@ -5082,7 +4880,7 @@ doing @samp{x/@var{fmt} @var{addr}}. @xref{Memory, ,Examining memory}. For example, @samp{display/i $pc} can be helpful, to see the machine instruction about to be executed each time execution stops (@samp{$pc} -is a common name for the program counter; @pxref{Registers}). +is a common name for the program counter; @pxref{Registers, ,Registers}). @table @code @kindex delete display @@ -5129,7 +4927,7 @@ there is no variable @code{last_char}---the display is disabled automatically. The next time your program stops where @code{last_char} is meaningful, you can enable the display expression once again. -@node Print Settings, Value History, Auto Display, Data +@node Print Settings @section Print settings @cindex format options @@ -5218,7 +5016,7 @@ printed is reasonably close to the closest earlier symbol: @item set print max-symbolic-offset @var{max-offset} Tell @value{GDBN} to only display the symbolic form of an address if the offset between the closest earlier symbol and the address is less than -@var{max-offset}. The default is 0, which tells @value{GDBN} +@var{max-offset}. The default is 0, which tells @value{GDBN} to always print the symbolic form of an address if any symbol precedes it. @kindex show print max-symbolic-offset @@ -5271,6 +5069,7 @@ Set a limit on how many elements of an array @value{GDBN} will print. If @value{GDBN} is printing a large array, it stops printing after it has printed the number of elements set by the @code{set print elements} command. This limit also applies to the display of strings. +When @value{GDBN} starts, this limit is set to 200. Setting @var{number-of-elements} to zero means that the printing is unlimited. @kindex show print elements @@ -5281,12 +5080,13 @@ If the number is 0, then the printing is unlimited. @kindex set print null-stop @item set print null-stop Cause @value{GDBN} to stop printing the characters of an array when the first -@sc{NULL} is encountered. This is useful when large arrays actually +@sc{null} is encountered. This is useful when large arrays actually contain only short strings. +The default is off. @kindex set print pretty @item set print pretty on -Cause @value{GDBN} to print structures in an indented format with one member +Cause @value{GDBN} to print structures in an indented format with one member per line, like this: @smallexample @@ -5337,7 +5137,7 @@ Show whether or not @value{GDBN} is printing only seven-bit characters. @kindex set print union @item set print union on -Tell @value{GDBN} to print unions which are contained in structures. This +Tell @value{GDBN} to print unions which are contained in structures. This is the default setting. @item set print union off @@ -5353,7 +5153,7 @@ For example, given the declarations @smallexample typedef enum @{Tree, Bug@} Species; typedef enum @{Big_tree, Acorn, Seedling@} Tree_forms; -typedef enum @{Caterpillar, Cocoon, Butterfly@} +typedef enum @{Caterpillar, Cocoon, Butterfly@} Bug_forms; struct thing @{ @@ -5382,61 +5182,58 @@ $1 = @{it = Tree, form = @{...@}@} @end smallexample @end table -@ifclear CONLY @need 1000 @noindent -These settings are of interest when debugging C++ programs: +These settings are of interest when debugging C@t{++} programs: @table @code @cindex demangling @kindex set print demangle @item set print demangle @itemx set print demangle on -Print C++ names in their source form rather than in the encoded +Print C@t{++} names in their source form rather than in the encoded (``mangled'') form passed to the assembler and linker for type-safe -linkage. The default is @samp{on}. +linkage. The default is on. @kindex show print demangle @item show print demangle -Show whether C++ names are printed in mangled or demangled form. +Show whether C@t{++} names are printed in mangled or demangled form. @kindex set print asm-demangle @item set print asm-demangle @itemx set print asm-demangle on -Print C++ names in their source form rather than their mangled form, even +Print C@t{++} names in their source form rather than their mangled form, even in assembler code printouts such as instruction disassemblies. The default is off. @kindex show print asm-demangle @item show print asm-demangle -Show whether C++ names in assembly listings are printed in mangled +Show whether C@t{++} names in assembly listings are printed in mangled or demangled form. @kindex set demangle-style -@cindex C++ symbol decoding style -@cindex symbol decoding style, C++ +@cindex C@t{++} symbol decoding style +@cindex symbol decoding style, C@t{++} @item set demangle-style @var{style} Choose among several encoding schemes used by different compilers to -represent C++ names. The choices for @var{style} are currently: +represent C@t{++} names. The choices for @var{style} are currently: @table @code @item auto Allow @value{GDBN} to choose a decoding style by inspecting your program. @item gnu -Decode based on the @sc{gnu} C++ compiler (@code{g++}) encoding algorithm. -@ifclear HPPA +Decode based on the @sc{gnu} C@t{++} compiler (@code{g++}) encoding algorithm. This is the default. -@end ifclear @item hp -Decode based on the HP ANSI C++ (@code{aCC}) encoding algorithm. +Decode based on the HP ANSI C@t{++} (@code{aCC}) encoding algorithm. @item lucid -Decode based on the Lucid C++ compiler (@code{lcc}) encoding algorithm. +Decode based on the Lucid C@t{++} compiler (@code{lcc}) encoding algorithm. @item arm -Decode using the algorithm in the @cite{C++ Annotated Reference Manual}. +Decode using the algorithm in the @cite{C@t{++} Annotated Reference Manual}. @strong{Warning:} this setting alone is not sufficient to allow debugging @code{cfront}-generated executables. @value{GDBN} would require further enhancement to permit that. @@ -5446,7 +5243,7 @@ If you omit @var{style}, you will see a list of possible formats. @kindex show demangle-style @item show demangle-style -Display the encoding style currently in use for decoding C++ symbols. +Display the encoding style currently in use for decoding C@t{++} symbols. @kindex set print object @item set print object @@ -5466,44 +5263,41 @@ Show whether actual, or declared, object types are displayed. @kindex set print static-members @item set print static-members @itemx set print static-members on -Print static members when displaying a C++ object. The default is on. +Print static members when displaying a C@t{++} object. The default is on. @item set print static-members off -Do not print static members when displaying a C++ object. +Do not print static members when displaying a C@t{++} object. @kindex show print static-members @item show print static-members -Show whether C++ static members are printed, or not. +Show whether C@t{++} static members are printed, or not. @c These don't work with HP ANSI C++ yet. @kindex set print vtbl @item set print vtbl @itemx set print vtbl on -Pretty print C++ virtual function tables. The default is off. -@ifset HPPA +Pretty print C@t{++} virtual function tables. The default is off. (The @code{vtbl} commands do not work on programs compiled with the HP -ANSI C++ compiler (@code{aCC}).) -@end ifset +ANSI C@t{++} compiler (@code{aCC}).) @item set print vtbl off -Do not pretty print C++ virtual function tables. +Do not pretty print C@t{++} virtual function tables. @kindex show print vtbl @item show print vtbl -Show whether C++ virtual function tables are pretty printed, or not. +Show whether C@t{++} virtual function tables are pretty printed, or not. @end table -@end ifclear -@node Value History, Convenience Vars, Print Settings, Data +@node Value History @section Value history @cindex value history -Values printed by the @code{print} command are saved in the @value{GDBN} -@dfn{value history}. This allows you to refer to them in other expressions. -Values are kept until the symbol table is re-read or discarded -(for example with the @code{file} or @code{symbol-file} commands). -When the symbol table changes, the value history is discarded, -since the values may contain pointers back to the types defined in the +Values printed by the @code{print} command are saved in the @value{GDBN} +@dfn{value history}. This allows you to refer to them in other expressions. +Values are kept until the symbol table is re-read or discarded +(for example with the @code{file} or @code{symbol-file} commands). +When the symbol table changes, the value history is discarded, +since the values may contain pointers back to the types defined in the symbol table. @cindex @code{$} @@ -5571,7 +5365,7 @@ values are available, @code{show values +} produces no display. Pressing @key{RET} to repeat @code{show values @var{n}} has exactly the same effect as @samp{show values +}. -@node Convenience Vars, Registers, Value History, Data +@node Convenience Vars @section Convenience variables @cindex convenience variables @@ -5583,7 +5377,7 @@ of your program. That is why you can use them freely. Convenience variables are prefixed with @samp{$}. Any name preceded by @samp{$} can be used for a convenience variable, unless it is one of -the predefined machine-specific register names (@pxref{Registers}). +the predefined machine-specific register names (@pxref{Registers, ,Registers}). (Value history references, in contrast, are @emph{numbers} preceded by @samp{$}. @xref{Value History, ,Value history}.) @@ -5612,7 +5406,7 @@ variable, when used as an expression, has the type of its current value. @kindex show convenience @item show convenience Print a list of convenience variables used so far, and their values. -Abbreviated @code{show con}. +Abbreviated @code{show conv}. @end table One of the ways to use a convenience variable is as a counter to be @@ -5624,13 +5418,14 @@ set $i = 0 print bar[$i++]->contents @end example -@noindent Repeat that command by typing @key{RET}. +@noindent +Repeat that command by typing @key{RET}. Some convenience variables are created automatically by @value{GDBN} and given values likely to be useful. @table @code -@kindex $_ +@vindex $_@r{, convenience variable} @item $_ The variable @code{$_} is automatically set by the @code{x} command to the last address examined (@pxref{Memory, ,Examining memory}). Other @@ -5640,25 +5435,23 @@ and @code{info breakpoint}. The type of @code{$_} is @code{void *} except when set by the @code{x} command, in which case it is a pointer to the type of @code{$__}. -@kindex $__ +@vindex $__@r{, convenience variable} @item $__ The variable @code{$__} is automatically set by the @code{x} command to the value found in the last address examined. Its type is chosen to match the format in which the data was printed. @item $_exitcode -@kindex $_exitcode +@vindex $_exitcode@r{, convenience variable} The variable @code{$_exitcode} is automatically set to the exit code when the program being debugged terminates. @end table -@ifset HPPA -If you refer to a function or variable name that begins with a dollar -sign, @value{GDBN} searches for a user or system name first, before it -searches for a convenience variable. -@end ifset +On HP-UX systems, if you refer to a function or variable name that +begins with a dollar sign, @value{GDBN} searches for a user or system +name first, before it searches for a convenience variable. -@node Registers, Floating Point Hardware, Convenience Vars, Data +@node Registers @section Registers @cindex registers @@ -5681,8 +5474,8 @@ registers. @item info registers @var{regname} @dots{} Print the @dfn{relativized} value of each specified register @var{regname}. -As discussed in detail below, register values are normally relative to -the selected stack frame. @var{regname} may be any register name valid on +As discussed in detail below, register values are normally relative to +the selected stack frame. @var{regname} may be any register name valid on the machine you are using, with or without the initial @samp{$}. @end table @@ -5713,7 +5506,7 @@ memory (most machines, nowadays). This assumes that the innermost stack frame is selected; setting @code{$sp} is not allowed when other stack frames are selected. To pop entire frames off the stack, regardless of machine architecture, use @code{return}; -@pxref{Returning, ,Returning from a function}.} with +see @ref{Returning, ,Returning from a function}.} with @example set $sp += 4 @@ -5724,7 +5517,8 @@ your machine even though the machine has different canonical mnemonics, so long as there is no conflict. The @code{info registers} command shows the canonical names. For example, on the SPARC, @code{info registers} displays the processor status register as @code{$psr} but you -can also refer to it as @code{$ps}. +can also refer to it as @code{$ps}; and on x86-based machines @code{$ps} +is an alias for the @sc{eflags} register. @value{GDBN} always considers the contents of an ordinary register as an integer when the register is examined in this way. Some machines have @@ -5740,7 +5534,7 @@ the operating system is not the same one that your program normally sees. For example, the registers of the 68881 floating point coprocessor are always saved in ``extended'' (raw) format, but all C programs expect to work with ``double'' (virtual) format. In such -cases, @value{GDBN} normally works with the virtual format only (the format +cases, @value{GDBN} normally works with the virtual format only (the format that makes sense for your program), but the @code{info registers} command prints the data in both formats. @@ -5756,31 +5550,7 @@ code generated by your compiler. If some registers are not saved, or if @value{GDBN} is unable to locate the saved registers, the selected stack frame makes no difference. -@ifset AMD29K -@table @code -@kindex set rstack_high_address -@cindex AMD 29K register stack -@cindex register stack, AMD29K -@item set rstack_high_address @var{address} -On AMD 29000 family processors, registers are saved in a separate -``register stack''. There is no way for @value{GDBN} to determine the extent -of this stack. Normally, @value{GDBN} just assumes that the stack is ``large -enough''. This may result in @value{GDBN} referencing memory locations that -do not exist. If necessary, you can get around this problem by -specifying the ending address of the register stack with the @code{set -rstack_high_address} command. The argument should be an address, which -you probably want to precede with @samp{0x} to specify in -hexadecimal. - -@kindex show rstack_high_address -@item show rstack_high_address -Display the current limit of the register stack, on AMD 29000 family -processors. -@end table -@end ifset - -@ifclear HAVE-FLOAT -@node Floating Point Hardware, , Registers, Data +@node Floating Point Hardware @section Floating point hardware @cindex floating point @@ -5795,21 +5565,1165 @@ point unit. The exact contents and layout vary depending on the floating point chip. Currently, @samp{info float} is supported on the ARM and x86 machines. @end table -@end ifclear -@ifclear CONLY -@node Languages, Symbols, Data, Top +@node Memory Region Attributes +@section Memory Region Attributes +@cindex memory region attributes + +@dfn{Memory region attributes} allow you to describe special handling +required by regions of your target's memory. @value{GDBN} uses attributes +to determine whether to allow certain types of memory accesses; whether to +use specific width accesses; and whether to cache target memory. + +Defined memory regions can be individually enabled and disabled. When a +memory region is disabled, @value{GDBN} uses the default attributes when +accessing memory in that region. Similarly, if no memory regions have +been defined, @value{GDBN} uses the default attributes when accessing +all memory. + +When a memory region is defined, it is given a number to identify it; +to enable, disable, or remove a memory region, you specify that number. + +@table @code +@kindex mem +@item mem @var{address1} @var{address2} @var{attributes}@dots{} +Define memory region bounded by @var{address1} and @var{address2} +with attributes @var{attributes}@dots{}. + +@kindex delete mem +@item delete mem @var{nums}@dots{} +Remove memory regions @var{nums}@dots{}. + +@kindex disable mem +@item disable mem @var{nums}@dots{} +Disable memory regions @var{nums}@dots{}. +A disabled memory region is not forgotten. +It may be enabled again later. + +@kindex enable mem +@item enable mem @var{nums}@dots{} +Enable memory regions @var{nums}@dots{}. + +@kindex info mem +@item info mem +Print a table of all defined memory regions, with the following columns +for each region. + +@table @emph +@item Memory Region Number +@item Enabled or Disabled. +Enabled memory regions are marked with @samp{y}. +Disabled memory regions are marked with @samp{n}. + +@item Lo Address +The address defining the inclusive lower bound of the memory region. + +@item Hi Address +The address defining the exclusive upper bound of the memory region. + +@item Attributes +The list of attributes set for this memory region. +@end table +@end table + + +@subsection Attributes + +@subsubsection Memory Access Mode +The access mode attributes set whether @value{GDBN} may make read or +write accesses to a memory region. + +While these attributes prevent @value{GDBN} from performing invalid +memory accesses, they do nothing to prevent the target system, I/O DMA, +etc. from accessing memory. + +@table @code +@item ro +Memory is read only. +@item wo +Memory is write only. +@item rw +Memory is read/write. This is the default. +@end table + +@subsubsection Memory Access Size +The acccess size attributes tells @value{GDBN} to use specific sized +accesses in the memory region. Often memory mapped device registers +require specific sized accesses. If no access size attribute is +specified, @value{GDBN} may use accesses of any size. + +@table @code +@item 8 +Use 8 bit memory accesses. +@item 16 +Use 16 bit memory accesses. +@item 32 +Use 32 bit memory accesses. +@item 64 +Use 64 bit memory accesses. +@end table + +@c @subsubsection Hardware/Software Breakpoints +@c The hardware/software breakpoint attributes set whether @value{GDBN} +@c will use hardware or software breakpoints for the internal breakpoints +@c used by the step, next, finish, until, etc. commands. +@c +@c @table @code +@c @item hwbreak +@c Always use hardware breakpoints +@c @item swbreak (default) +@c @end table + +@subsubsection Data Cache +The data cache attributes set whether @value{GDBN} will cache target +memory. While this generally improves performance by reducing debug +protocol overhead, it can lead to incorrect results because @value{GDBN} +does not know about volatile variables or memory mapped device +registers. + +@table @code +@item cache +Enable @value{GDBN} to cache target memory. +@item nocache +Disable @value{GDBN} from caching target memory. This is the default. +@end table + +@c @subsubsection Memory Write Verification +@c The memory write verification attributes set whether @value{GDBN} +@c will re-reads data after each write to verify the write was successful. +@c +@c @table @code +@c @item verify +@c @item noverify (default) +@c @end table + +@node Tracepoints +@chapter Tracepoints +@c This chapter is based on the documentation written by Michael +@c Snyder, David Taylor, Jim Blandy, and Elena Zannoni. + +@cindex tracepoints +In some applications, it is not feasible for the debugger to interrupt +the program's execution long enough for the developer to learn +anything helpful about its behavior. If the program's correctness +depends on its real-time behavior, delays introduced by a debugger +might cause the program to change its behavior drastically, or perhaps +fail, even when the code itself is correct. It is useful to be able +to observe the program's behavior without interrupting it. + +Using @value{GDBN}'s @code{trace} and @code{collect} commands, you can +specify locations in the program, called @dfn{tracepoints}, and +arbitrary expressions to evaluate when those tracepoints are reached. +Later, using the @code{tfind} command, you can examine the values +those expressions had when the program hit the tracepoints. The +expressions may also denote objects in memory---structures or arrays, +for example---whose values @value{GDBN} should record; while visiting +a particular tracepoint, you may inspect those objects as if they were +in memory at that moment. However, because @value{GDBN} records these +values without interacting with you, it can do so quickly and +unobtrusively, hopefully not disturbing the program's behavior. + +The tracepoint facility is currently available only for remote +targets. @xref{Targets}. In addition, your remote target must know how +to collect trace data. This functionality is implemented in the remote +stub; however, none of the stubs distributed with @value{GDBN} support +tracepoints as of this writing. + +This chapter describes the tracepoint commands and features. + +@menu +* Set Tracepoints:: +* Analyze Collected Data:: +* Tracepoint Variables:: +@end menu + +@node Set Tracepoints +@section Commands to Set Tracepoints + +Before running such a @dfn{trace experiment}, an arbitrary number of +tracepoints can be set. Like a breakpoint (@pxref{Set Breaks}), a +tracepoint has a number assigned to it by @value{GDBN}. Like with +breakpoints, tracepoint numbers are successive integers starting from +one. Many of the commands associated with tracepoints take the +tracepoint number as their argument, to identify which tracepoint to +work on. + +For each tracepoint, you can specify, in advance, some arbitrary set +of data that you want the target to collect in the trace buffer when +it hits that tracepoint. The collected data can include registers, +local variables, or global data. Later, you can use @value{GDBN} +commands to examine the values these data had at the time the +tracepoint was hit. + +This section describes commands to set tracepoints and associated +conditions and actions. + +@menu +* Create and Delete Tracepoints:: +* Enable and Disable Tracepoints:: +* Tracepoint Passcounts:: +* Tracepoint Actions:: +* Listing Tracepoints:: +* Starting and Stopping Trace Experiment:: +@end menu + +@node Create and Delete Tracepoints +@subsection Create and Delete Tracepoints + +@table @code +@cindex set tracepoint +@kindex trace +@item trace +The @code{trace} command is very similar to the @code{break} command. +Its argument can be a source line, a function name, or an address in +the target program. @xref{Set Breaks}. The @code{trace} command +defines a tracepoint, which is a point in the target program where the +debugger will briefly stop, collect some data, and then allow the +program to continue. Setting a tracepoint or changing its commands +doesn't take effect until the next @code{tstart} command; thus, you +cannot change the tracepoint attributes once a trace experiment is +running. + +Here are some examples of using the @code{trace} command: + +@smallexample +(@value{GDBP}) @b{trace foo.c:121} // a source file and line number + +(@value{GDBP}) @b{trace +2} // 2 lines forward + +(@value{GDBP}) @b{trace my_function} // first source line of function + +(@value{GDBP}) @b{trace *my_function} // EXACT start address of function + +(@value{GDBP}) @b{trace *0x2117c4} // an address +@end smallexample + +@noindent +You can abbreviate @code{trace} as @code{tr}. + +@vindex $tpnum +@cindex last tracepoint number +@cindex recent tracepoint number +@cindex tracepoint number +The convenience variable @code{$tpnum} records the tracepoint number +of the most recently set tracepoint. + +@kindex delete tracepoint +@cindex tracepoint deletion +@item delete tracepoint @r{[}@var{num}@r{]} +Permanently delete one or more tracepoints. With no argument, the +default is to delete all tracepoints. + +Examples: + +@smallexample +(@value{GDBP}) @b{delete trace 1 2 3} // remove three tracepoints + +(@value{GDBP}) @b{delete trace} // remove all tracepoints +@end smallexample + +@noindent +You can abbreviate this command as @code{del tr}. +@end table + +@node Enable and Disable Tracepoints +@subsection Enable and Disable Tracepoints + +@table @code +@kindex disable tracepoint +@item disable tracepoint @r{[}@var{num}@r{]} +Disable tracepoint @var{num}, or all tracepoints if no argument +@var{num} is given. A disabled tracepoint will have no effect during +the next trace experiment, but it is not forgotten. You can re-enable +a disabled tracepoint using the @code{enable tracepoint} command. + +@kindex enable tracepoint +@item enable tracepoint @r{[}@var{num}@r{]} +Enable tracepoint @var{num}, or all tracepoints. The enabled +tracepoints will become effective the next time a trace experiment is +run. +@end table + +@node Tracepoint Passcounts +@subsection Tracepoint Passcounts + +@table @code +@kindex passcount +@cindex tracepoint pass count +@item passcount @r{[}@var{n} @r{[}@var{num}@r{]]} +Set the @dfn{passcount} of a tracepoint. The passcount is a way to +automatically stop a trace experiment. If a tracepoint's passcount is +@var{n}, then the trace experiment will be automatically stopped on +the @var{n}'th time that tracepoint is hit. If the tracepoint number +@var{num} is not specified, the @code{passcount} command sets the +passcount of the most recently defined tracepoint. If no passcount is +given, the trace experiment will run until stopped explicitly by the +user. + +Examples: + +@smallexample +(@value{GDBP}) @b{passcount 5 2} // Stop on the 5th execution of +@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// tracepoint 2} + +(@value{GDBP}) @b{passcount 12} // Stop on the 12th execution of the +@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// most recently defined tracepoint.} +(@value{GDBP}) @b{trace foo} +(@value{GDBP}) @b{pass 3} +(@value{GDBP}) @b{trace bar} +(@value{GDBP}) @b{pass 2} +(@value{GDBP}) @b{trace baz} +(@value{GDBP}) @b{pass 1} // Stop tracing when foo has been +@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// executed 3 times OR when bar has} +@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// been executed 2 times} +@exdent @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @code{// OR when baz has been executed 1 time.} +@end smallexample +@end table + +@node Tracepoint Actions +@subsection Tracepoint Action Lists + +@table @code +@kindex actions +@cindex tracepoint actions +@item actions @r{[}@var{num}@r{]} +This command will prompt for a list of actions to be taken when the +tracepoint is hit. If the tracepoint number @var{num} is not +specified, this command sets the actions for the one that was most +recently defined (so that you can define a tracepoint and then say +@code{actions} without bothering about its number). You specify the +actions themselves on the following lines, one action at a time, and +terminate the actions list with a line containing just @code{end}. So +far, the only defined actions are @code{collect} and +@code{while-stepping}. + +@cindex remove actions from a tracepoint +To remove all actions from a tracepoint, type @samp{actions @var{num}} +and follow it immediately with @samp{end}. + +@smallexample +(@value{GDBP}) @b{collect @var{data}} // collect some data + +(@value{GDBP}) @b{while-stepping 5} // single-step 5 times, collect data + +(@value{GDBP}) @b{end} // signals the end of actions. +@end smallexample + +In the following example, the action list begins with @code{collect} +commands indicating the things to be collected when the tracepoint is +hit. Then, in order to single-step and collect additional data +following the tracepoint, a @code{while-stepping} command is used, +followed by the list of things to be collected while stepping. The +@code{while-stepping} command is terminated by its own separate +@code{end} command. Lastly, the action list is terminated by an +@code{end} command. + +@smallexample +(@value{GDBP}) @b{trace foo} +(@value{GDBP}) @b{actions} +Enter actions for tracepoint 1, one per line: +> collect bar,baz +> collect $regs +> while-stepping 12 + > collect $fp, $sp + > end +end +@end smallexample + +@kindex collect @r{(tracepoints)} +@item collect @var{expr1}, @var{expr2}, @dots{} +Collect values of the given expressions when the tracepoint is hit. +This command accepts a comma-separated list of any valid expressions. +In addition to global, static, or local variables, the following +special arguments are supported: + +@table @code +@item $regs +collect all registers + +@item $args +collect all function arguments + +@item $locals +collect all local variables. +@end table + +You can give several consecutive @code{collect} commands, each one +with a single argument, or one @code{collect} command with several +arguments separated by commas: the effect is the same. + +The command @code{info scope} (@pxref{Symbols, info scope}) is +particularly useful for figuring out what data to collect. + +@kindex while-stepping @r{(tracepoints)} +@item while-stepping @var{n} +Perform @var{n} single-step traces after the tracepoint, collecting +new data at each step. The @code{while-stepping} command is +followed by the list of what to collect while stepping (followed by +its own @code{end} command): + +@smallexample +> while-stepping 12 + > collect $regs, myglobal + > end +> +@end smallexample + +@noindent +You may abbreviate @code{while-stepping} as @code{ws} or +@code{stepping}. +@end table + +@node Listing Tracepoints +@subsection Listing Tracepoints + +@table @code +@kindex info tracepoints +@cindex information about tracepoints +@item info tracepoints @r{[}@var{num}@r{]} +Display information about the tracepoint @var{num}. If you don't specify +a tracepoint number, displays information about all the tracepoints +defined so far. For each tracepoint, the following information is +shown: + +@itemize @bullet +@item +its number +@item +whether it is enabled or disabled +@item +its address +@item +its passcount as given by the @code{passcount @var{n}} command +@item +its step count as given by the @code{while-stepping @var{n}} command +@item +where in the source files is the tracepoint set +@item +its action list as given by the @code{actions} command +@end itemize + +@smallexample +(@value{GDBP}) @b{info trace} +Num Enb Address PassC StepC What +1 y 0x002117c4 0 0 <gdb_asm> +2 y 0x0020dc64 0 0 in g_test at g_test.c:1375 +3 y 0x0020b1f4 0 0 in get_data at ../foo.c:41 +(@value{GDBP}) +@end smallexample + +@noindent +This command can be abbreviated @code{info tp}. +@end table + +@node Starting and Stopping Trace Experiment +@subsection Starting and Stopping Trace Experiment + +@table @code +@kindex tstart +@cindex start a new trace experiment +@cindex collected data discarded +@item tstart +This command takes no arguments. It starts the trace experiment, and +begins collecting data. This has the side effect of discarding all +the data collected in the trace buffer during the previous trace +experiment. + +@kindex tstop +@cindex stop a running trace experiment +@item tstop +This command takes no arguments. It ends the trace experiment, and +stops collecting data. + +@strong{Note:} a trace experiment and data collection may stop +automatically if any tracepoint's passcount is reached +(@pxref{Tracepoint Passcounts}), or if the trace buffer becomes full. + +@kindex tstatus +@cindex status of trace data collection +@cindex trace experiment, status of +@item tstatus +This command displays the status of the current trace data +collection. +@end table + +Here is an example of the commands we described so far: + +@smallexample +(@value{GDBP}) @b{trace gdb_c_test} +(@value{GDBP}) @b{actions} +Enter actions for tracepoint #1, one per line. +> collect $regs,$locals,$args +> while-stepping 11 + > collect $regs + > end +> end +(@value{GDBP}) @b{tstart} + [time passes @dots{}] +(@value{GDBP}) @b{tstop} +@end smallexample + + +@node Analyze Collected Data +@section Using the collected data + +After the tracepoint experiment ends, you use @value{GDBN} commands +for examining the trace data. The basic idea is that each tracepoint +collects a trace @dfn{snapshot} every time it is hit and another +snapshot every time it single-steps. All these snapshots are +consecutively numbered from zero and go into a buffer, and you can +examine them later. The way you examine them is to @dfn{focus} on a +specific trace snapshot. When the remote stub is focused on a trace +snapshot, it will respond to all @value{GDBN} requests for memory and +registers by reading from the buffer which belongs to that snapshot, +rather than from @emph{real} memory or registers of the program being +debugged. This means that @strong{all} @value{GDBN} commands +(@code{print}, @code{info registers}, @code{backtrace}, etc.) will +behave as if we were currently debugging the program state as it was +when the tracepoint occurred. Any requests for data that are not in +the buffer will fail. + +@menu +* tfind:: How to select a trace snapshot +* tdump:: How to display all data for a snapshot +* save-tracepoints:: How to save tracepoints for a future run +@end menu + +@node tfind +@subsection @code{tfind @var{n}} + +@kindex tfind +@cindex select trace snapshot +@cindex find trace snapshot +The basic command for selecting a trace snapshot from the buffer is +@code{tfind @var{n}}, which finds trace snapshot number @var{n}, +counting from zero. If no argument @var{n} is given, the next +snapshot is selected. + +Here are the various forms of using the @code{tfind} command. + +@table @code +@item tfind start +Find the first snapshot in the buffer. This is a synonym for +@code{tfind 0} (since 0 is the number of the first snapshot). + +@item tfind none +Stop debugging trace snapshots, resume @emph{live} debugging. + +@item tfind end +Same as @samp{tfind none}. + +@item tfind +No argument means find the next trace snapshot. + +@item tfind - +Find the previous trace snapshot before the current one. This permits +retracing earlier steps. + +@item tfind tracepoint @var{num} +Find the next snapshot associated with tracepoint @var{num}. Search +proceeds forward from the last examined trace snapshot. If no +argument @var{num} is given, it means find the next snapshot collected +for the same tracepoint as the current snapshot. + +@item tfind pc @var{addr} +Find the next snapshot associated with the value @var{addr} of the +program counter. Search proceeds forward from the last examined trace +snapshot. If no argument @var{addr} is given, it means find the next +snapshot with the same value of PC as the current snapshot. + +@item tfind outside @var{addr1}, @var{addr2} +Find the next snapshot whose PC is outside the given range of +addresses. + +@item tfind range @var{addr1}, @var{addr2} +Find the next snapshot whose PC is between @var{addr1} and +@var{addr2}. @c FIXME: Is the range inclusive or exclusive? + +@item tfind line @r{[}@var{file}:@r{]}@var{n} +Find the next snapshot associated with the source line @var{n}. If +the optional argument @var{file} is given, refer to line @var{n} in +that source file. Search proceeds forward from the last examined +trace snapshot. If no argument @var{n} is given, it means find the +next line other than the one currently being examined; thus saying +@code{tfind line} repeatedly can appear to have the same effect as +stepping from line to line in a @emph{live} debugging session. +@end table + +The default arguments for the @code{tfind} commands are specifically +designed to make it easy to scan through the trace buffer. For +instance, @code{tfind} with no argument selects the next trace +snapshot, and @code{tfind -} with no argument selects the previous +trace snapshot. So, by giving one @code{tfind} command, and then +simply hitting @key{RET} repeatedly you can examine all the trace +snapshots in order. Or, by saying @code{tfind -} and then hitting +@key{RET} repeatedly you can examine the snapshots in reverse order. +The @code{tfind line} command with no argument selects the snapshot +for the next source line executed. The @code{tfind pc} command with +no argument selects the next snapshot with the same program counter +(PC) as the current frame. The @code{tfind tracepoint} command with +no argument selects the next trace snapshot collected by the same +tracepoint as the current one. + +In addition to letting you scan through the trace buffer manually, +these commands make it easy to construct @value{GDBN} scripts that +scan through the trace buffer and print out whatever collected data +you are interested in. Thus, if we want to examine the PC, FP, and SP +registers from each trace frame in the buffer, we can say this: + +@smallexample +(@value{GDBP}) @b{tfind start} +(@value{GDBP}) @b{while ($trace_frame != -1)} +> printf "Frame %d, PC = %08X, SP = %08X, FP = %08X\n", \ + $trace_frame, $pc, $sp, $fp +> tfind +> end + +Frame 0, PC = 0020DC64, SP = 0030BF3C, FP = 0030BF44 +Frame 1, PC = 0020DC6C, SP = 0030BF38, FP = 0030BF44 +Frame 2, PC = 0020DC70, SP = 0030BF34, FP = 0030BF44 +Frame 3, PC = 0020DC74, SP = 0030BF30, FP = 0030BF44 +Frame 4, PC = 0020DC78, SP = 0030BF2C, FP = 0030BF44 +Frame 5, PC = 0020DC7C, SP = 0030BF28, FP = 0030BF44 +Frame 6, PC = 0020DC80, SP = 0030BF24, FP = 0030BF44 +Frame 7, PC = 0020DC84, SP = 0030BF20, FP = 0030BF44 +Frame 8, PC = 0020DC88, SP = 0030BF1C, FP = 0030BF44 +Frame 9, PC = 0020DC8E, SP = 0030BF18, FP = 0030BF44 +Frame 10, PC = 00203F6C, SP = 0030BE3C, FP = 0030BF14 +@end smallexample + +Or, if we want to examine the variable @code{X} at each source line in +the buffer: + +@smallexample +(@value{GDBP}) @b{tfind start} +(@value{GDBP}) @b{while ($trace_frame != -1)} +> printf "Frame %d, X == %d\n", $trace_frame, X +> tfind line +> end + +Frame 0, X = 1 +Frame 7, X = 2 +Frame 13, X = 255 +@end smallexample + +@node tdump +@subsection @code{tdump} +@kindex tdump +@cindex dump all data collected at tracepoint +@cindex tracepoint data, display + +This command takes no arguments. It prints all the data collected at +the current trace snapshot. + +@smallexample +(@value{GDBP}) @b{trace 444} +(@value{GDBP}) @b{actions} +Enter actions for tracepoint #2, one per line: +> collect $regs, $locals, $args, gdb_long_test +> end + +(@value{GDBP}) @b{tstart} + +(@value{GDBP}) @b{tfind line 444} +#0 gdb_test (p1=0x11, p2=0x22, p3=0x33, p4=0x44, p5=0x55, p6=0x66) +at gdb_test.c:444 +444 printp( "%s: arguments = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", ) + +(@value{GDBP}) @b{tdump} +Data collected at tracepoint 2, trace frame 1: +d0 0xc4aa0085 -995491707 +d1 0x18 24 +d2 0x80 128 +d3 0x33 51 +d4 0x71aea3d 119204413 +d5 0x22 34 +d6 0xe0 224 +d7 0x380035 3670069 +a0 0x19e24a 1696330 +a1 0x3000668 50333288 +a2 0x100 256 +a3 0x322000 3284992 +a4 0x3000698 50333336 +a5 0x1ad3cc 1758156 +fp 0x30bf3c 0x30bf3c +sp 0x30bf34 0x30bf34 +ps 0x0 0 +pc 0x20b2c8 0x20b2c8 +fpcontrol 0x0 0 +fpstatus 0x0 0 +fpiaddr 0x0 0 +p = 0x20e5b4 "gdb-test" +p1 = (void *) 0x11 +p2 = (void *) 0x22 +p3 = (void *) 0x33 +p4 = (void *) 0x44 +p5 = (void *) 0x55 +p6 = (void *) 0x66 +gdb_long_test = 17 '\021' + +(@value{GDBP}) +@end smallexample + +@node save-tracepoints +@subsection @code{save-tracepoints @var{filename}} +@kindex save-tracepoints +@cindex save tracepoints for future sessions + +This command saves all current tracepoint definitions together with +their actions and passcounts, into a file @file{@var{filename}} +suitable for use in a later debugging session. To read the saved +tracepoint definitions, use the @code{source} command (@pxref{Command +Files}). + +@node Tracepoint Variables +@section Convenience Variables for Tracepoints +@cindex tracepoint variables +@cindex convenience variables for tracepoints + +@table @code +@vindex $trace_frame +@item (int) $trace_frame +The current trace snapshot (a.k.a.@: @dfn{frame}) number, or -1 if no +snapshot is selected. + +@vindex $tracepoint +@item (int) $tracepoint +The tracepoint for the current trace snapshot. + +@vindex $trace_line +@item (int) $trace_line +The line number for the current trace snapshot. + +@vindex $trace_file +@item (char []) $trace_file +The source file for the current trace snapshot. + +@vindex $trace_func +@item (char []) $trace_func +The name of the function containing @code{$tracepoint}. +@end table + +Note: @code{$trace_file} is not suitable for use in @code{printf}, +use @code{output} instead. + +Here's a simple example of using these convenience variables for +stepping through all the trace snapshots and printing some of their +data. + +@smallexample +(@value{GDBP}) @b{tfind start} + +(@value{GDBP}) @b{while $trace_frame != -1} +> output $trace_file +> printf ", line %d (tracepoint #%d)\n", $trace_line, $tracepoint +> tfind +> end +@end smallexample + +@node Overlays +@chapter Debugging Programs That Use Overlays +@cindex overlays + +If your program is too large to fit completely in your target system's +memory, you can sometimes use @dfn{overlays} to work around this +problem. @value{GDBN} provides some support for debugging programs that +use overlays. + +@menu +* How Overlays Work:: A general explanation of overlays. +* Overlay Commands:: Managing overlays in @value{GDBN}. +* Automatic Overlay Debugging:: @value{GDBN} can find out which overlays are + mapped by asking the inferior. +* Overlay Sample Program:: A sample program using overlays. +@end menu + +@node How Overlays Work +@section How Overlays Work +@cindex mapped overlays +@cindex unmapped overlays +@cindex load address, overlay's +@cindex mapped address +@cindex overlay area + +Suppose you have a computer whose instruction address space is only 64 +kilobytes long, but which has much more memory which can be accessed by +other means: special instructions, segment registers, or memory +management hardware, for example. Suppose further that you want to +adapt a program which is larger than 64 kilobytes to run on this system. + +One solution is to identify modules of your program which are relatively +independent, and need not call each other directly; call these modules +@dfn{overlays}. Separate the overlays from the main program, and place +their machine code in the larger memory. Place your main program in +instruction memory, but leave at least enough space there to hold the +largest overlay as well. + +Now, to call a function located in an overlay, you must first copy that +overlay's machine code from the large memory into the space set aside +for it in the instruction memory, and then jump to its entry point +there. + +@c NB: In the below the mapped area's size is greater or equal to the +@c size of all overlays. This is intentional to remind the developer +@c that overlays don't necessarily need to be the same size. + +@example +@group + Data Instruction Larger +Address Space Address Space Address Space ++-----------+ +-----------+ +-----------+ +| | | | | | ++-----------+ +-----------+ +-----------+<-- overlay 1 +| program | | main | .----| overlay 1 | load address +| variables | | program | | +-----------+ +| and heap | | | | | | ++-----------+ | | | +-----------+<-- overlay 2 +| | +-----------+ | | | load address ++-----------+ | | | .-| overlay 2 | + | | | | | | + mapped --->+-----------+ | | +-----------+ + address | | | | | | + | overlay | <-' | | | + | area | <---' +-----------+<-- overlay 3 + | | <---. | | load address + +-----------+ `--| overlay 3 | + | | | | + +-----------+ | | + +-----------+ + | | + +-----------+ + + @anchor{A code overlay}A code overlay +@end group +@end example + +The diagram (@pxref{A code overlay}) shows a system with separate data +and instruction address spaces. To map an overlay, the program copies +its code from the larger address space to the instruction address space. +Since the overlays shown here all use the same mapped address, only one +may be mapped at a time. For a system with a single address space for +data and instructions, the diagram would be similar, except that the +program variables and heap would share an address space with the main +program and the overlay area. + +An overlay loaded into instruction memory and ready for use is called a +@dfn{mapped} overlay; its @dfn{mapped address} is its address in the +instruction memory. An overlay not present (or only partially present) +in instruction memory is called @dfn{unmapped}; its @dfn{load address} +is its address in the larger memory. The mapped address is also called +the @dfn{virtual memory address}, or @dfn{VMA}; the load address is also +called the @dfn{load memory address}, or @dfn{LMA}. + +Unfortunately, overlays are not a completely transparent way to adapt a +program to limited instruction memory. They introduce a new set of +global constraints you must keep in mind as you design your program: + +@itemize @bullet + +@item +Before calling or returning to a function in an overlay, your program +must make sure that overlay is actually mapped. Otherwise, the call or +return will transfer control to the right address, but in the wrong +overlay, and your program will probably crash. + +@item +If the process of mapping an overlay is expensive on your system, you +will need to choose your overlays carefully to minimize their effect on +your program's performance. + +@item +The executable file you load onto your system must contain each +overlay's instructions, appearing at the overlay's load address, not its +mapped address. However, each overlay's instructions must be relocated +and its symbols defined as if the overlay were at its mapped address. +You can use GNU linker scripts to specify different load and relocation +addresses for pieces of your program; see @ref{Overlay Description,,, +ld.info, Using ld: the GNU linker}. + +@item +The procedure for loading executable files onto your system must be able +to load their contents into the larger address space as well as the +instruction and data spaces. + +@end itemize + +The overlay system described above is rather simple, and could be +improved in many ways: + +@itemize @bullet + +@item +If your system has suitable bank switch registers or memory management +hardware, you could use those facilities to make an overlay's load area +contents simply appear at their mapped address in instruction space. +This would probably be faster than copying the overlay to its mapped +area in the usual way. + +@item +If your overlays are small enough, you could set aside more than one +overlay area, and have more than one overlay mapped at a time. + +@item +You can use overlays to manage data, as well as instructions. In +general, data overlays are even less transparent to your design than +code overlays: whereas code overlays only require care when you call or +return to functions, data overlays require care every time you access +the data. Also, if you change the contents of a data overlay, you +must copy its contents back out to its load address before you can copy a +different data overlay into the same mapped area. + +@end itemize + + +@node Overlay Commands +@section Overlay Commands + +To use @value{GDBN}'s overlay support, each overlay in your program must +correspond to a separate section of the executable file. The section's +virtual memory address and load memory address must be the overlay's +mapped and load addresses. Identifying overlays with sections allows +@value{GDBN} to determine the appropriate address of a function or +variable, depending on whether the overlay is mapped or not. + +@value{GDBN}'s overlay commands all start with the word @code{overlay}; +you can abbreviate this as @code{ov} or @code{ovly}. The commands are: + +@table @code +@item overlay off +@kindex overlay off +Disable @value{GDBN}'s overlay support. When overlay support is +disabled, @value{GDBN} assumes that all functions and variables are +always present at their mapped addresses. By default, @value{GDBN}'s +overlay support is disabled. + +@item overlay manual +@kindex overlay manual +@cindex manual overlay debugging +Enable @dfn{manual} overlay debugging. In this mode, @value{GDBN} +relies on you to tell it which overlays are mapped, and which are not, +using the @code{overlay map-overlay} and @code{overlay unmap-overlay} +commands described below. + +@item overlay map-overlay @var{overlay} +@itemx overlay map @var{overlay} +@kindex overlay map-overlay +@cindex map an overlay +Tell @value{GDBN} that @var{overlay} is now mapped; @var{overlay} must +be the name of the object file section containing the overlay. When an +overlay is mapped, @value{GDBN} assumes it can find the overlay's +functions and variables at their mapped addresses. @value{GDBN} assumes +that any other overlays whose mapped ranges overlap that of +@var{overlay} are now unmapped. + +@item overlay unmap-overlay @var{overlay} +@itemx overlay unmap @var{overlay} +@kindex overlay unmap-overlay +@cindex unmap an overlay +Tell @value{GDBN} that @var{overlay} is no longer mapped; @var{overlay} +must be the name of the object file section containing the overlay. +When an overlay is unmapped, @value{GDBN} assumes it can find the +overlay's functions and variables at their load addresses. + +@item overlay auto +@kindex overlay auto +Enable @dfn{automatic} overlay debugging. In this mode, @value{GDBN} +consults a data structure the overlay manager maintains in the inferior +to see which overlays are mapped. For details, see @ref{Automatic +Overlay Debugging}. + +@item overlay load-target +@itemx overlay load +@kindex overlay load-target +@cindex reloading the overlay table +Re-read the overlay table from the inferior. Normally, @value{GDBN} +re-reads the table @value{GDBN} automatically each time the inferior +stops, so this command should only be necessary if you have changed the +overlay mapping yourself using @value{GDBN}. This command is only +useful when using automatic overlay debugging. + +@item overlay list-overlays +@itemx overlay list +@cindex listing mapped overlays +Display a list of the overlays currently mapped, along with their mapped +addresses, load addresses, and sizes. + +@end table + +Normally, when @value{GDBN} prints a code address, it includes the name +of the function the address falls in: + +@example +(gdb) print main +$3 = @{int ()@} 0x11a0 <main> +@end example +@noindent +When overlay debugging is enabled, @value{GDBN} recognizes code in +unmapped overlays, and prints the names of unmapped functions with +asterisks around them. For example, if @code{foo} is a function in an +unmapped overlay, @value{GDBN} prints it this way: + +@example +(gdb) overlay list +No sections are mapped. +(gdb) print foo +$5 = @{int (int)@} 0x100000 <*foo*> +@end example +@noindent +When @code{foo}'s overlay is mapped, @value{GDBN} prints the function's +name normally: + +@example +(gdb) overlay list +Section .ov.foo.text, loaded at 0x100000 - 0x100034, + mapped at 0x1016 - 0x104a +(gdb) print foo +$6 = @{int (int)@} 0x1016 <foo> +@end example + +When overlay debugging is enabled, @value{GDBN} can find the correct +address for functions and variables in an overlay, whether or not the +overlay is mapped. This allows most @value{GDBN} commands, like +@code{break} and @code{disassemble}, to work normally, even on unmapped +code. However, @value{GDBN}'s breakpoint support has some limitations: + +@itemize @bullet +@item +@cindex breakpoints in overlays +@cindex overlays, setting breakpoints in +You can set breakpoints in functions in unmapped overlays, as long as +@value{GDBN} can write to the overlay at its load address. +@item +@value{GDBN} can not set hardware or simulator-based breakpoints in +unmapped overlays. However, if you set a breakpoint at the end of your +overlay manager (and tell @value{GDBN} which overlays are now mapped, if +you are using manual overlay management), @value{GDBN} will re-set its +breakpoints properly. +@end itemize + + +@node Automatic Overlay Debugging +@section Automatic Overlay Debugging +@cindex automatic overlay debugging + +@value{GDBN} can automatically track which overlays are mapped and which +are not, given some simple co-operation from the overlay manager in the +inferior. If you enable automatic overlay debugging with the +@code{overlay auto} command (@pxref{Overlay Commands}), @value{GDBN} +looks in the inferior's memory for certain variables describing the +current state of the overlays. + +Here are the variables your overlay manager must define to support +@value{GDBN}'s automatic overlay debugging: + +@table @asis + +@item @code{_ovly_table}: +This variable must be an array of the following structures: + +@example +struct +@{ + /* The overlay's mapped address. */ + unsigned long vma; + + /* The size of the overlay, in bytes. */ + unsigned long size; + + /* The overlay's load address. */ + unsigned long lma; + + /* Non-zero if the overlay is currently mapped; + zero otherwise. */ + unsigned long mapped; +@} +@end example + +@item @code{_novlys}: +This variable must be a four-byte signed integer, holding the total +number of elements in @code{_ovly_table}. + +@end table + +To decide whether a particular overlay is mapped or not, @value{GDBN} +looks for an entry in @w{@code{_ovly_table}} whose @code{vma} and +@code{lma} members equal the VMA and LMA of the overlay's section in the +executable file. When @value{GDBN} finds a matching entry, it consults +the entry's @code{mapped} member to determine whether the overlay is +currently mapped. + +In addition, your overlay manager may define a function called +@code{_ovly_debug_event}. If this function is defined, @value{GDBN} +will silently set a breakpoint there. If the overlay manager then +calls this function whenever it has changed the overlay table, this +will enable @value{GDBN} to accurately keep track of which overlays +are in program memory, and update any breakpoints that may be set +in overlays. This will allow breakpoints to work even if the +overlays are kept in ROM or other non-writable memory while they +are not being executed. + +@node Overlay Sample Program +@section Overlay Sample Program +@cindex overlay example program + +When linking a program which uses overlays, you must place the overlays +at their load addresses, while relocating them to run at their mapped +addresses. To do this, you must write a linker script (@pxref{Overlay +Description,,, ld.info, Using ld: the GNU linker}). Unfortunately, +since linker scripts are specific to a particular host system, target +architecture, and target memory layout, this manual cannot provide +portable sample code demonstrating @value{GDBN}'s overlay support. + +However, the @value{GDBN} source distribution does contain an overlaid +program, with linker scripts for a few systems, as part of its test +suite. The program consists of the following files from +@file{gdb/testsuite/gdb.base}: + +@table @file +@item overlays.c +The main program file. +@item ovlymgr.c +A simple overlay manager, used by @file{overlays.c}. +@item foo.c +@itemx bar.c +@itemx baz.c +@itemx grbx.c +Overlay modules, loaded and used by @file{overlays.c}. +@item d10v.ld +@itemx m32r.ld +Linker scripts for linking the test program on the @code{d10v-elf} +and @code{m32r-elf} targets. +@end table + +You can build the test program using the @code{d10v-elf} GCC +cross-compiler like this: + +@example +$ d10v-elf-gcc -g -c overlays.c +$ d10v-elf-gcc -g -c ovlymgr.c +$ d10v-elf-gcc -g -c foo.c +$ d10v-elf-gcc -g -c bar.c +$ d10v-elf-gcc -g -c baz.c +$ d10v-elf-gcc -g -c grbx.c +$ d10v-elf-gcc -g overlays.o ovlymgr.o foo.o bar.o \ + baz.o grbx.o -Wl,-Td10v.ld -o overlays +@end example + +The build process is identical for any other architecture, except that +you must substitute the appropriate compiler and linker script for the +target system for @code{d10v-elf-gcc} and @code{d10v.ld}. + + +@node Languages @chapter Using @value{GDBN} with Different Languages @cindex languages -@ifset MOD2 Although programming languages generally have common aspects, they are rarely expressed in the same manner. For instance, in ANSI C, dereferencing a pointer @code{p} is accomplished by @code{*p}, but in Modula-2, it is accomplished by @code{p^}. Values can also be -represented (and displayed) differently. Hex numbers in C appear as +represented (and displayed) differently. Hex numbers in C appear as @samp{0x1ae}, while in Modula-2 they appear as @samp{1AEH}. -@end ifset @cindex working language Language-specific information is built into @value{GDBN} for some languages, @@ -5822,14 +6736,11 @@ language}. @menu * Setting:: Switching between source languages * Show:: Displaying the language -@ifset MOD2 * Checks:: Type and range checks -@end ifset - * Support:: Supported languages @end menu -@node Setting, Show, Languages, Languages +@node Setting @section Switching between source languages There are two ways to control the working language---either have @value{GDBN} @@ -5844,12 +6755,14 @@ In addition to the working language, every source file that file formats, the compiler might indicate which language a particular source file is in. However, most of the time @value{GDBN} infers the language from the name of the file. The language of a source file -controls whether C++ names are demangled---this way @code{backtrace} can +controls whether C@t{++} names are demangled---this way @code{backtrace} can show each frame appropriately for its own language. There is no way to -set the language of a source file from within @value{GDBN}. +set the language of a source file from within @value{GDBN}, but you can +set the language associated with a filename extension. @xref{Show, , +Displaying the language}. This is most commonly a problem when you use a program, such -as @code{cfront} or @code{f2c}, that generates C but is written in +as @code{cfront} or @code{f2c}, that generates C but is written in another language. In that case, make the program use @code{#line} directives in its C output; that way @value{GDBN} will know the correct language of the source code of the original @@ -5861,7 +6774,7 @@ program, and will display that source code, not the generated C code. * Automatically:: Having @value{GDBN} infer the source language @end menu -@node Filenames, Manually, Setting, Setting +@node Filenames @subsection List of filename extensions and languages If a source file name ends in one of the following extensions, then @@ -5878,23 +6791,19 @@ C source file @itemx .cpp @itemx .cxx @itemx .c++ -C++ source file +C@t{++} source file @item .f @itemx .F Fortran source file -@ifclear HPPA @item .ch @itemx .c186 @itemx .c286 -CHILL source file. -@end ifclear +CHILL source file -@ifset MOD2 @item .mod Modula-2 source file -@end ifset @item .s @itemx .S @@ -5905,7 +6814,7 @@ Assembler source file. This actually behaves almost like C, but In addition, you may set the language associated with a filename extension. @xref{Show, , Displaying the language}. -@node Manually, Automatically, Filenames, Setting +@node Manually @subsection Setting the working language If you allow @value{GDBN} to set the language automatically, @@ -5915,23 +6824,10 @@ your program. @kindex set language If you wish, you may set the language manually. To do this, issue the command @samp{set language @var{lang}}, where @var{lang} is the name of -a language, such as -@ifclear MOD2 -@code{c}. -@end ifclear -@ifset MOD2 +a language, such as @code{c} or @code{modula-2}. -@end ifset For a list of the supported languages, type @samp{set language}. -@ifclear MOD2 -Setting the language manually prevents @value{GDBN} from updating the -working language automatically. For example, if you used the @code{c} -setting to debug a C++ program, names might not be demangled properly, -overload resolution would not work, user-defined operators might not be -interpreted correctly, and so on. -@end ifclear -@ifset MOD2 Setting the language manually prevents @value{GDBN} from updating the working language automatically. This can lead to confusion if you try to debug a program when the working language is not the same as the @@ -5949,9 +6845,8 @@ might not have the effect you intended. In C, this means to add @code{b} and @code{c} and place the result in @code{a}. The result printed would be the value of @code{a}. In Modula-2, this means to compare @code{a} to the result of @code{b+c}, yielding a @code{BOOLEAN} value. -@end ifset -@node Automatically, , Manually, Setting +@node Automatically @subsection Having @value{GDBN} infer the source language To have @value{GDBN} set the working language automatically, use @@ -5970,21 +6865,15 @@ written in one source language can be used by a main program written in a different source language. Using @samp{set language auto} in this case frees you from having to set the working language manually. -@ifset MOD2 -@node Show, Checks, Setting, Languages -@section Displaying the language -@end ifset -@ifclear MOD2 -@node Show, Support, Setting, Languages +@node Show @section Displaying the language -@end ifclear The following commands help you find out which language is the working language, and also what language source files were written in. @kindex show language -@kindex info frame -@kindex info source +@kindex info frame@r{, show the source language} +@kindex info source@r{, show the source language} @table @code @item show language Display the current working language. This is the @@ -5992,14 +6881,14 @@ language you can use with commands such as @code{print} to build and compute expressions that may involve variables in your program. @item info frame -Display the source language for this frame. This language becomes the +Display the source language for this frame. This language becomes the working language if you use an identifier from this frame. -@xref{Frame Info, ,Information about a frame}, to identify the other +@xref{Frame Info, ,Information about a frame}, to identify the other information listed here. @item info source Display the source language of this source file. -@xref{Symbols, ,Examining the Symbol Table}, to identify the other +@xref{Symbols, ,Examining the Symbol Table}, to identify the other information listed here. @end table @@ -6018,8 +6907,7 @@ the source language @var{language}. List all the filename extensions and the associated languages. @end table -@ifset MOD2 -@node Checks, Support, Show, Languages +@node Checks @section Type and range checking @quotation @@ -6052,7 +6940,7 @@ for the default settings of supported languages. @cindex type checking @cindex checks, type -@node Type Checking, Range Checking, Checks, Checks +@node Type Checking @subsection An overview of type checking Some languages, such as Modula-2, are strongly typed, meaning that the @@ -6069,19 +6957,19 @@ errors from ever causing any run-time problems. For example, The second example fails because the @code{CARDINAL} 1 is not type-compatible with the @code{REAL} 2.3. -For the expressions you use in @value{GDBN} commands, you can tell the -@value{GDBN} type checker to skip checking; -to treat any mismatches as errors and abandon the expression; -or to only issue warnings when type mismatches occur, +For the expressions you use in @value{GDBN} commands, you can tell the +@value{GDBN} type checker to skip checking; +to treat any mismatches as errors and abandon the expression; +or to only issue warnings when type mismatches occur, but evaluate the expression anyway. When you choose the last of these, @value{GDBN} evaluates expressions like the second example above, but also issues a warning. -Even if you turn type checking off, there may be other reasons -related to type that prevent @value{GDBN} from evaluating an expression. -For instance, @value{GDBN} does not know how to add an @code{int} and -a @code{struct foo}. These particular type errors have nothing to do -with the language in use, and usually arise from expressions, such as +Even if you turn type checking off, there may be other reasons +related to type that prevent @value{GDBN} from evaluating an expression. +For instance, @value{GDBN} does not know how to add an @code{int} and +a @code{struct foo}. These particular type errors have nothing to do +with the language in use, and usually arise from expressions, such as the one described above, which make little sense to evaluate anyway. Each language defines to what degree it is strict about type. For @@ -6093,7 +6981,7 @@ details on specific languages. @value{GDBN} provides some additional commands for controlling the type checker: -@kindex set check +@kindex set check@r{, type} @kindex set check type @kindex show check type @table @code @@ -6107,7 +6995,7 @@ each language. Set type checking on or off, overriding the default setting for the current working language. Issue a warning if the setting does not match the language default. If any type mismatches occur in -evaluating an expression while typechecking is on, @value{GDBN} prints a +evaluating an expression while type checking is on, @value{GDBN} prints a message and aborts evaluation of the expression. @item set check type warn @@ -6117,13 +7005,13 @@ be impossible for other reasons. For example, @value{GDBN} cannot add numbers and structures. @item show type -Show the current setting of the type checker, and whether or not @value{GDBN} +Show the current setting of the type checker, and whether or not @value{GDBN} is setting it automatically. @end table @cindex range checking @cindex checks, range -@node Range Checking, , Type Checking, Checks +@node Range Checking @subsection An overview of range checking In some languages (such as Modula-2), it is an error to exceed the @@ -6154,7 +7042,7 @@ Supported languages}, for further details on specific languages. @value{GDBN} provides some additional commands for controlling the range checker: -@kindex set check +@kindex set check@r{, range} @kindex set check range @kindex show check range @table @code @@ -6167,8 +7055,8 @@ each language. @itemx set check range off Set range checking on or off, overriding the default setting for the current working language. A warning is issued if the setting does not -match the language default. If a range error occurs, then a message -is printed and evaluation of the expression is aborted. +match the language default. If a range error occurs and range checking is on, +then a message is printed and evaluation of the expression is aborted. @item set check range warn Output messages when the @value{GDBN} range checker detects a range error, @@ -6181,23 +7069,12 @@ systems). Show the current setting of the range checker, and whether or not it is being set automatically by @value{GDBN}. @end table -@end ifset -@ifset MOD2 -@node Support, , Checks, Languages -@section Supported languages -@end ifset -@ifclear MOD2 -@node Support, , Show, Languages +@node Support @section Supported languages -@end ifclear -@ifset MOD2 -@value{GDBN} supports C, C++, Fortran, Chill, assembly, and Modula-2. -@end ifset -@ifclear MOD2 -@value{GDBN} supports C, C++, Fortran, Chill, and assembly. -@end ifclear +@value{GDBN} supports C, C@t{++}, Fortran, Java, Chill, assembly, and Modula-2. +@c This is false ... Some @value{GDBN} features may be used in expressions regardless of the language you use: the @value{GDBN} @code{@@} and @code{::} operators, and the @samp{@{type@}addr} construct (@pxref{Expressions, @@ -6212,130 +7089,74 @@ formats should look like for different languages. There are many good books written on each of these languages; please look to these for a language reference or tutorial. -@ifset MOD2 @menu -* C:: C and C++ -* Modula-2:: Modula-2 +* C:: C and C@t{++} +* Modula-2:: Modula-2 +* Chill:: Chill @end menu -@node C, Modula-2, , Support -@subsection C and C++ -@cindex C and C++ -@cindex expressions in C or C++ -@end ifset +@node C +@subsection C and C@t{++} + +@cindex C and C@t{++} +@cindex expressions in C or C@t{++} -Since C and C++ are so closely related, many features of @value{GDBN} apply +Since C and C@t{++} are so closely related, many features of @value{GDBN} apply to both languages. Whenever this is the case, we discuss those languages together. -@ifclear MOD2 -@c Cancel this below, under same condition, at end of this chapter! -@raisesections -@end ifclear - -@ifclear HPPA -@cindex C++ -@kindex g++ -@cindex @sc{gnu} C++ -The C++ debugging facilities are jointly implemented by the C++ -compiler and @value{GDBN}. Therefore, to debug your C++ code -effectively, you must compile your C++ programs with a supported -C++ compiler, such as @sc{gnu} @code{g++}, or the HP ANSI C++ +@cindex C@t{++} +@cindex @code{g++}, @sc{gnu} C@t{++} compiler +@cindex @sc{gnu} C@t{++} +The C@t{++} debugging facilities are jointly implemented by the C@t{++} +compiler and @value{GDBN}. Therefore, to debug your C@t{++} code +effectively, you must compile your C@t{++} programs with a supported +C@t{++} compiler, such as @sc{gnu} @code{g++}, or the HP ANSI C@t{++} compiler (@code{aCC}). -For best results when using @sc{gnu} C++, use the stabs debugging +For best results when using @sc{gnu} C@t{++}, use the stabs debugging format. You can select that format explicitly with the @code{g++} command-line options @samp{-gstabs} or @samp{-gstabs+}. See @ref{Debugging Options,,Options for Debugging Your Program or @sc{gnu} CC, gcc.info, Using @sc{gnu} CC}, for more information. -@end ifclear -@ifset HPPA -@cindex C++ -@kindex g++ -@cindex @sc{gnu} C++ -You can use @value{GDBN} to debug C programs compiled with either the HP -C compiler (@code{cc}) or the GNU C compiler (@code{gcc}), and to debug -programs compiled with either the HP ANSI C++ compiler (@code{aCC}) or -the @sc{gnu} C++ compiler (@code{g++}). - -If you compile with the @sc{gnu} C++ compiler, use the stabs debugging -format for best results when debugging. You can select that format -explicitly with the @code{g++} command-line options @samp{-gstabs} or -@samp{-gstabs+}. See @ref{Debugging Options,,Options for Debugging Your -Program or @sc{gnu} CC, gcc.info, Using @sc{gnu} CC}, for more -information. -@end ifset -@end ifclear - -@ifset CONLY -@node C, Symbols, Data, Top -@chapter C Language Support -@cindex C language -@cindex expressions in C - -Information specific to the C language is built into @value{GDBN} so that you -can use C expressions while debugging. This also permits @value{GDBN} to -output values in a manner consistent with C conventions. @menu -* C Operators:: C operators +* C Operators:: C and C@t{++} operators +* C Constants:: C and C@t{++} constants +* C plus plus expressions:: C@t{++} expressions +* C Defaults:: Default settings for C and C@t{++} +* C Checks:: C and C@t{++} type and range checks +* Debugging C:: @value{GDBN} and C +* Debugging C plus plus:: @value{GDBN} features for C@t{++} @end menu -@end ifset -@ifclear CONLY -@menu -* C Operators:: C and C++ operators -* C Constants:: C and C++ constants -* Cplus expressions:: C++ expressions -* C Defaults:: Default settings for C and C++ -@ifset MOD2 -* C Checks:: C and C++ type and range checks -@end ifset +@node C Operators +@subsubsection C and C@t{++} operators -* Debugging C:: @value{GDBN} and C -* Debugging C plus plus:: @value{GDBN} features for C++ -@end menu -@end ifclear - -@ifclear CONLY -@cindex C and C++ operators -@node C Operators, C Constants, , C -@subsubsection C and C++ operators -@end ifclear -@ifset CONLY -@cindex C operators -@node C Operators, C Constants, C, C -@section C operators -@end ifset +@cindex C and C@t{++} operators Operators must be defined on values of specific types. For instance, @code{+} is defined on numbers, but not on structures. Operators are -often defined on groups of types. +often defined on groups of types. -@ifclear CONLY -For the purposes of C and C++, the following definitions hold: -@end ifclear +For the purposes of C and C@t{++}, the following definitions hold: @itemize @bullet + @item -@ifclear HPPA -@emph{Integral types} include @code{int} with any of its storage-class -specifiers; @code{char}; and @code{enum}. -@end ifclear -@ifset HPPA @emph{Integral types} include @code{int} with any of its storage-class -specifiers; @code{char}; @code{enum}; and, for C++, @code{bool}. -@end ifset +specifiers; @code{char}; @code{enum}; and, for C@t{++}, @code{bool}. @item -@emph{Floating-point types} include @code{float} and @code{double}. +@emph{Floating-point types} include @code{float}, @code{double}, and +@code{long double} (if supported by the target platform). @item -@emph{Pointer types} include all types defined as @code{(@var{type} -*)}. +@emph{Pointer types} include all types defined as @code{(@var{type} *)}. @item @emph{Scalar types} include all of the above. + @end itemize @noindent @@ -6355,7 +7176,7 @@ assigned. Defined on scalar types. @item @var{op}= Used in an expression of the form @w{@code{@var{a} @var{op}= @var{b}}}, and translated to @w{@code{@var{a} = @var{a op b}}}. -@w{@code{@var{op}=}} and @code{=} have the same precendence. +@w{@code{@var{op}=}} and @code{=} have the same precedence. @var{op} is any one of the operators @code{|}, @code{^}, @code{&}, @code{<<}, @code{>>}, @code{+}, @code{-}, @code{*}, @code{/}, @code{%}. @@ -6416,13 +7237,11 @@ Pointer dereferencing. Defined on pointer types. Same precedence as @item & Address operator. Defined on variables. Same precedence as @code{++}. -@ifclear CONLY -For debugging C++, @value{GDBN} implements a use of @samp{&} beyond what is -allowed in the C++ language itself: you can use @samp{&(&@var{ref})} +For debugging C@t{++}, @value{GDBN} implements a use of @samp{&} beyond what is +allowed in the C@t{++} language itself: you can use @samp{&(&@var{ref})} (or, if you prefer, simply @samp{&&@var{ref}}) to examine the address -where a C++ reference variable (declared with @samp{&@var{ref}}) is +where a C@t{++} reference variable (declared with @samp{&@var{ref}}) is stored. -@end ifclear @item - Negative. Defined on integral and floating-point types. Same @@ -6443,10 +7262,8 @@ Structure member, and pointer-to-structure member. For convenience, pointer based on the stored type information. Defined on @code{struct} and @code{union} data. -@ifset HPPA @item .*@r{, }->* Dereferences of pointers to members. -@end ifset @item [] Array indexing. @code{@var{a}[@var{i}]} is defined as @@ -6455,62 +7272,37 @@ Array indexing. @code{@var{a}[@var{i}]} is defined as @item () Function parameter list. Same precedence as @code{->}. -@ifclear CONLY @item :: -C++ scope resolution operator. Defined on -@code{struct}, @code{union}, and @code{class} types. -@end ifclear +C@t{++} scope resolution operator. Defined on @code{struct}, @code{union}, +and @code{class} types. @item :: -Doubled colons -@ifclear CONLY -also -@end ifclear -represent the @value{GDBN} scope operator (@pxref{Expressions, -,Expressions}). -@ifclear CONLY -Same precedence as @code{::}, above. -@end ifclear -@end table - -@ifset HPPA +Doubled colons also represent the @value{GDBN} scope operator +(@pxref{Expressions, ,Expressions}). Same precedence as @code{::}, +above. +@end table + If an operator is redefined in the user code, @value{GDBN} usually attempts to invoke the redefined version instead of using the operator's predefined meaning. -@end ifset -@ifclear CONLY @menu -* C Constants:: +* C Constants:: @end menu -@ifset MOD2 -@node C Constants, Cplus expressions, C Operators, C -@subsubsection C and C++ constants -@end ifset -@ifclear MOD2 -@node C Constants, Cplus expressions, C Operators, Support -@subsubsection C and C++ constants -@end ifclear +@node C Constants +@subsubsection C and C@t{++} constants -@cindex C and C++ constants -@value{GDBN} allows you to express the constants of C and C++ in the -following ways: -@end ifclear -@ifset CONLY -@cindex C constants -@node C Constants, Debugging C, C Operators, C -@section C constants +@cindex C and C@t{++} constants -@value{GDBN} allows you to express the constants of C in the +@value{GDBN} allows you to express the constants of C and C@t{++} in the following ways: -@end ifset @itemize @bullet @item Integer constants are a sequence of digits. Octal constants are -specified by a leading @samp{0} (i.e. zero), and hexadecimal constants by -a leading @samp{0x} or @samp{0X}. Constants may also end with a letter +specified by a leading @samp{0} (i.e.@: zero), and hexadecimal constants +by a leading @samp{0x} or @samp{0X}. Constants may also end with a letter @samp{l}, specifying that the constant should be treated as a @code{long} value. @@ -6520,6 +7312,11 @@ point, followed by a sequence of digits, and optionally followed by an exponent. An exponent is of the form: @samp{@w{e@r{[[}+@r{]|}-@r{]}@var{nnn}}}, where @var{nnn} is another sequence of digits. The @samp{+} is optional for positive exponents. +A floating-point constant may also end with a letter @samp{f} or +@samp{F}, specifying that the constant should be treated as being of +the @code{float} (as opposed to the default @code{double}) type; or with +a letter @samp{l} or @samp{L}, which specifies a @code{long double} +constant. @item Enumerated constants consist of enumerated identifiers, or their @@ -6528,7 +7325,7 @@ integral equivalents. @item Character constants are a single character surrounded by single quotes (@code{'}), or a number---the ordinal value of the corresponding character -(usually its @sc{ASCII} value). Within quotes, the single character may +(usually its @sc{ascii} value). Within quotes, the single character may be represented by a letter or by @dfn{escape sequences}, which are of the form @samp{\@var{nnn}}, where @var{nnn} is the octal representation of the character's ordinal value; or of the form @samp{\@var{x}}, where @@ -6536,8 +7333,11 @@ of the character's ordinal value; or of the form @samp{\@var{x}}, where @samp{\n} for newline. @item -String constants are a sequence of character constants surrounded -by double quotes (@code{"}). +String constants are a sequence of character constants surrounded by +double quotes (@code{"}). Any valid character constant (as described +above) may appear. Double quotes within the string must be preceded by +a backslash, so for instance @samp{"a\"b'c"} is a string of five +characters. @item Pointer constants are an integral value. You can also write pointers @@ -6550,54 +7350,43 @@ integers, @samp{@{@{1,2@}, @{3,4@}, @{5,6@}@}} is a three-by-two array, and @samp{@{&"hi", &"there", &"fred"@}} is a three-element array of pointers. @end itemize -@ifclear CONLY @menu -* Cplus expressions:: -* C Defaults:: -@ifset MOD2 -* C Checks:: -@end ifset +* C plus plus expressions:: +* C Defaults:: +* C Checks:: -* Debugging C:: +* Debugging C:: @end menu -@ifset MOD2 -@node Cplus expressions, C Defaults, C Constants, C -@subsubsection C++ expressions -@end ifset -@ifclear MOD2 -@node Cplus expressions, C Defaults, C Constants, Support -@subsubsection C++ expressions -@end ifclear - -@cindex expressions in C++ -@value{GDBN} expression handling can interpret most C++ expressions. - -@ifclear HPPA -@cindex C++ support, not in @sc{coff} -@cindex @sc{coff} versus C++ -@cindex C++ and object formats -@cindex object formats and C++ -@cindex a.out and C++ -@cindex @sc{ecoff} and C++ -@cindex @sc{xcoff} and C++ -@cindex @sc{elf}/stabs and C++ -@cindex @sc{elf}/@sc{dwarf} and C++ +@node C plus plus expressions +@subsubsection C@t{++} expressions + +@cindex expressions in C@t{++} +@value{GDBN} expression handling can interpret most C@t{++} expressions. + +@cindex C@t{++} support, not in @sc{coff} +@cindex @sc{coff} versus C@t{++} +@cindex C@t{++} and object formats +@cindex object formats and C@t{++} +@cindex a.out and C@t{++} +@cindex @sc{ecoff} and C@t{++} +@cindex @sc{xcoff} and C@t{++} +@cindex @sc{elf}/stabs and C@t{++} +@cindex @sc{elf}/@sc{dwarf} and C@t{++} @c FIXME!! GDB may eventually be able to debug C++ using DWARF; check @c periodically whether this has happened... @quotation -@emph{Warning:} @value{GDBN} can only debug C++ code if you use the -proper compiler. Typically, C++ debugging depends on the use of +@emph{Warning:} @value{GDBN} can only debug C@t{++} code if you use the +proper compiler. Typically, C@t{++} debugging depends on the use of additional debugging information in the symbol table, and thus requires special support. In particular, if your compiler generates a.out, MIPS @sc{ecoff}, RS/6000 @sc{xcoff}, or @sc{elf} with stabs extensions to the symbol table, these facilities are all available. (With @sc{gnu} CC, you can use the @samp{-gstabs} option to request stabs debugging extensions explicitly.) Where the object code format is standard -@sc{coff} or @sc{dwarf} in @sc{elf}, on the other hand, most of the C++ +@sc{coff} or @sc{dwarf} in @sc{elf}, on the other hand, most of the C@t{++} support in @value{GDBN} does @emph{not} work. @end quotation -@end ifclear @enumerate @@ -6609,31 +7398,20 @@ Member function calls are allowed; you can use expressions like count = aml->GetOriginal(x, y) @end example -@kindex this -@cindex namespace in C++ +@vindex this@r{, inside C@t{++} member functions} +@cindex namespace in C@t{++} @item While a member function is active (in the selected stack frame), your expressions have the same namespace available as the member function; that is, @value{GDBN} allows implicit references to the class instance -pointer @code{this} following the same rules as C++. +pointer @code{this} following the same rules as C@t{++}. -@ifclear HPPA @cindex call overloaded functions -@cindex type conversions in C++ +@cindex overloaded functions, calling +@cindex type conversions in C@t{++} @item You can call overloaded functions; @value{GDBN} resolves the function -call to the right definition, with one restriction---you must use -arguments of the type required by the function that you want to call. -@value{GDBN} does not perform conversions requiring constructors or -user-defined type operators. -@end ifclear -@ifset HPPA -@cindex call overloaded functions -@cindex overloaded functions -@cindex type conversions in C++ -@item -You can call overloaded functions; @value{GDBN} resolves the function -call to the right definition, with some restrictions. GDB does not +call to the right definition, with some restrictions. @value{GDBN} does not perform overload resolution involving user-defined type conversions, calls to constructors, or instantiations of templates that do not exist in the program. It also cannot handle ellipsis argument lists or @@ -6647,22 +7425,21 @@ number of function arguments. Overload resolution is always performed, unless you have specified @code{set overload-resolution off}. @xref{Debugging C plus plus, -,@value{GDBN} features for C++}. +,@value{GDBN} features for C@t{++}}. -You must specify@code{set overload-resolution off} in order to use an +You must specify @code{set overload-resolution off} in order to use an explicit function signature to call an overloaded function, as in @smallexample p 'foo(char,int)'('x', 13) @end smallexample -The @value{GDBN} command-completion facility can simplify this; -@pxref{Completion, ,Command completion}. -@end ifset +The @value{GDBN} command-completion facility can simplify this; +see @ref{Completion, ,Command completion}. @cindex reference declarations @item -@value{GDBN} understands variables declared as C++ references; you can use -them in expressions just as you do in C++ source---they are automatically +@value{GDBN} understands variables declared as C@t{++} references; you can use +them in expressions just as you do in C@t{++} source---they are automatically dereferenced. In the parameter list shown when @value{GDBN} displays a frame, the values of @@ -6672,54 +7449,47 @@ The @emph{address} of a reference variable is always shown, unless you have specified @samp{set print address off}. @item -@value{GDBN} supports the C++ name resolution operator @code{::}---your +@value{GDBN} supports the C@t{++} name resolution operator @code{::}---your expressions can use it just as expressions in your program do. Since one scope may be defined in another, you can use @code{::} repeatedly if necessary, for example in an expression like @samp{@var{scope1}::@var{scope2}::@var{name}}. @value{GDBN} also allows -resolving name scope by reference to source files, in both C and C++ +resolving name scope by reference to source files, in both C and C@t{++} debugging (@pxref{Variables, ,Program variables}). @end enumerate -@ifset HPPA -In addition, @value{GDBN} supports calling virtual functions correctly, -printing out virtual bases of objects, calling functions in a base -subobject, casting objects, and invoking user-defined operators. -@end ifset +In addition, when used with HP's C@t{++} compiler, @value{GDBN} supports +calling virtual functions correctly, printing out virtual bases of +objects, calling functions in a base subobject, casting objects, and +invoking user-defined operators. -@ifset MOD2 -@node C Defaults, C Checks, Cplus expressions, C -@subsubsection C and C++ defaults -@end ifset -@ifclear MOD2 -@node C Defaults, Debugging C, Cplus expressions, Support -@subsubsection C and C++ defaults -@end ifclear -@cindex C and C++ defaults +@node C Defaults +@subsubsection C and C@t{++} defaults + +@cindex C and C@t{++} defaults -@ifclear HPPA If you allow @value{GDBN} to set type and range checking automatically, they both default to @code{off} whenever the working language changes to -C or C++. This happens regardless of whether you or @value{GDBN} +C or C@t{++}. This happens regardless of whether you or @value{GDBN} selects the working language. -@end ifclear If you allow @value{GDBN} to set the language automatically, it recognizes source files whose names end with @file{.c}, @file{.C}, or @file{.cc}, etc, and when @value{GDBN} enters code compiled from one of -these files, it sets the working language to C or C++. +these files, it sets the working language to C or C@t{++}. @xref{Automatically, ,Having @value{GDBN} infer the source language}, for further details. -@ifset MOD2 @c Type checking is (a) primarily motivated by Modula-2, and (b) @c unimplemented. If (b) changes, it might make sense to let this node @c appear even if Mod-2 does not, but meanwhile ignore it. roland 16jul93. -@node C Checks, Debugging C, C Defaults, C Constants -@subsubsection C and C++ type and range checks -@cindex C and C++ checks -By default, when @value{GDBN} parses C or C++ expressions, type checking +@node C Checks +@subsubsection C and C@t{++} type and range checks + +@cindex C and C@t{++} checks + +By default, when @value{GDBN} parses C or C@t{++} expressions, type checking is not used. However, if you turn type checking on, @value{GDBN} considers two variables type equivalent if: @@ -6745,54 +7515,30 @@ compilers.) Range checking, if turned on, is done on mathematical operations. Array indices are not checked, since they are often used to index a pointer that is not itself an array. -@end ifset -@end ifclear -@ifclear CONLY -@ifset MOD2 -@node Debugging C, Debugging C plus plus, C Checks, C -@subsubsection @value{GDBN} and C -@end ifset -@ifclear MOD2 -@node Debugging C, Debugging C plus plus, C Defaults, Support +@node Debugging C @subsubsection @value{GDBN} and C -@end ifclear -@end ifclear -@ifset CONLY -@node Debugging C, , C Constants, C -@section @value{GDBN} and C -@end ifset The @code{set print union} and @code{show print union} commands apply to the @code{union} type. When set to @samp{on}, any @code{union} that is -inside a @code{struct} -@ifclear CONLY -or @code{class} -@end ifclear -is also printed. -Otherwise, it appears as @samp{@{...@}}. +inside a @code{struct} or @code{class} is also printed. Otherwise, it +appears as @samp{@{...@}}. The @code{@@} operator aids in the debugging of dynamic arrays, formed with pointers and a memory allocation function. @xref{Expressions, ,Expressions}. -@ifclear CONLY @menu -* Debugging C plus plus:: +* Debugging C plus plus:: @end menu -@ifset MOD2 -@node Debugging C plus plus, , Debugging C, C -@subsubsection @value{GDBN} features for C++ -@end ifset -@ifclear MOD2 -@node Debugging C plus plus, , Debugging C, Support -@subsubsection @value{GDBN} features for C++ -@end ifclear +@node Debugging C plus plus +@subsubsection @value{GDBN} features for C@t{++} -@cindex commands for C++ -Some @value{GDBN} commands are particularly useful with C++, and some are -designed specifically for use with C++. Here is a summary: +@cindex commands for C@t{++} + +Some @value{GDBN} commands are particularly useful with C@t{++}, and some are +designed specifically for use with C@t{++}. Here is a summary: @table @code @cindex break in overloaded functions @@ -6801,17 +7547,17 @@ When you want a breakpoint in a function whose name is overloaded, @value{GDBN} breakpoint menus help you specify which function definition you want. @xref{Breakpoint Menus,,Breakpoint menus}. -@cindex overloading in C++ +@cindex overloading in C@t{++} @item rbreak @var{regex} Setting breakpoints using regular expressions is helpful for setting breakpoints on overloaded functions that are not members of any special classes. @xref{Set Breaks, ,Setting breakpoints}. -@cindex C++ exception handling +@cindex C@t{++} exception handling @item catch throw @itemx catch catch -Debug C++ exception handling using these commands. @xref{Set +Debug C@t{++} exception handling using these commands. @xref{Set Catchpoints, , Setting catchpoints}. @cindex inheritance @@ -6820,13 +7566,13 @@ Print inheritance relationships as well as other information for type @var{typename}. @xref{Symbols, ,Examining the Symbol Table}. -@cindex C++ symbol display +@cindex C@t{++} symbol display @item set print demangle @itemx show print demangle @itemx set print asm-demangle @itemx show print asm-demangle -Control whether C++ symbols display in their source form, both when -displaying code as C++ source and when displaying disassemblies. +Control whether C@t{++} symbols display in their source form, both when +displaying code as C@t{++} source and when displaying disassemblies. @xref{Print Settings, ,Print settings}. @item set print object @@ -6838,47 +7584,41 @@ Choose whether to print derived (actual) or declared types of objects. @itemx show print vtbl Control the format for printing virtual function tables. @xref{Print Settings, ,Print settings}. -@ifset HPPA (The @code{vtbl} commands do not work on programs compiled with the HP -ANSI C++ compiler (@code{aCC}).) +ANSI C@t{++} compiler (@code{aCC}).) @kindex set overload-resolution -@cindex overloaded functions +@cindex overloaded functions, overload resolution @item set overload-resolution on -Enable overload resolution for C++ expression evaluation. The default +Enable overload resolution for C@t{++} expression evaluation. The default is on. For overloaded functions, @value{GDBN} evaluates the arguments and searches for a function whose signature matches the argument types, -using the standard C++ conversion rules (@pxref{Cplus expressions, ,C++ -expressions} for details). If it cannot find a match, it emits a +using the standard C@t{++} conversion rules (see @ref{C plus plus expressions, ,C@t{++} +expressions}, for details). If it cannot find a match, it emits a message. @item set overload-resolution off -Disable overload resolution for C++ expression evaluation. For +Disable overload resolution for C@t{++} expression evaluation. For overloaded functions that are not class member functions, @value{GDBN} chooses the first function of the specified name that it finds in the symbol table, whether or not its arguments are of the correct type. For overloaded functions that are class member functions, @value{GDBN} searches for a function whose signature @emph{exactly} matches the argument types. -@end ifset @item @r{Overloaded symbol names} You can specify a particular definition of an overloaded symbol, using -the same notation that is used to declare such symbols in C++: type +the same notation that is used to declare such symbols in C@t{++}: type @code{@var{symbol}(@var{types})} rather than just @var{symbol}. You can also use the @value{GDBN} command-line word completion facilities to list the available choices, or to finish the type list for you. @xref{Completion,, Command completion}, for details on how to do this. @end table -@ifclear MOD2 -@c cancels "raisesections" under same conditions near bgn of chapter -@lowersections -@end ifclear -@ifset MOD2 -@node Modula-2, ,C , Support +@node Modula-2 @subsection Modula-2 -@cindex Modula-2 + +@cindex Modula-2, @value{GDBN} support The extensions made to @value{GDBN} to support Modula-2 only support output from the @sc{gnu} Modula-2 compiler (which is currently being @@ -6899,7 +7639,7 @@ table. * GDB/M2:: @value{GDBN} and Modula-2 @end menu -@node M2 Operators, Built-In Func/Proc, Modula-2, Modula-2 +@node M2 Operators @subsubsection Operators @cindex Modula-2 operators @@ -6951,7 +7691,7 @@ Less than, greater than on integral, floating-point, or enumerated types. @item <=@r{, }>= -Less than, greater than, less than or equal to, greater than or equal to +Less than or equal to, greater than or equal to on integral, floating-point and enumerated types, or set inclusion on set types. Same precedence as @code{<}. @@ -6969,7 +7709,7 @@ Same precedence as @code{<}. Boolean disjunction. Defined on boolean types. @item AND@r{, }& -Boolean conjuction. Defined on boolean types. +Boolean conjunction. Defined on boolean types. @item @@ The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}). @@ -7022,9 +7762,10 @@ treats the use of the operator @code{IN}, or the use of operators @code{<=}, and @code{>=} on sets as an error. @end quotation -@cindex Modula-2 built-ins -@node Built-In Func/Proc, M2 Constants, M2 Operators, Modula-2 + +@node Built-In Func/Proc @subsubsection Built-in functions and procedures +@cindex Modula-2 built-ins Modula-2 also makes available several built-in procedures and functions. In describing these, the following metavariables are used: @@ -7070,13 +7811,13 @@ Returns the absolute value of @var{n}. @item CAP(@var{c}) If @var{c} is a lower case letter, it returns its upper case -equivalent, otherwise it returns its argument +equivalent, otherwise it returns its argument. @item CHR(@var{i}) Returns the character whose ordinal value is @var{i}. @item DEC(@var{v}) -Decrements the value in the variable @var{v}. Returns the new value. +Decrements the value in the variable @var{v} by one. Returns the new value. @item DEC(@var{v},@var{i}) Decrements the value in the variable @var{v} by @var{i}. Returns the @@ -7093,7 +7834,7 @@ Returns the floating point equivalent of the integer @var{i}. Returns the index of the last member of @var{a}. @item INC(@var{v}) -Increments the value in the variable @var{v}. Returns the new value. +Increments the value in the variable @var{v} by one. Returns the new value. @item INC(@var{v},@var{i}) Increments the value in the variable @var{v} by @var{i}. Returns the @@ -7114,8 +7855,8 @@ Returns boolean TRUE if @var{i} is an odd number. @item ORD(@var{x}) Returns the ordinal value of its argument. For example, the ordinal -value of a character is its ASCII value (on machines supporting the -ASCII character set). @var{x} must be of an ordered type, which include +value of a character is its @sc{ascii} value (on machines supporting the +@sc{ascii} character set). @var{x} must be of an ordered type, which include integral, character and enumerated types. @item SIZE(@var{x}) @@ -7135,7 +7876,7 @@ an error. @end quotation @cindex Modula-2 constants -@node M2 Constants, M2 Defaults, Built-In Func/Proc, Modula-2 +@node M2 Constants @subsubsection Constants @value{GDBN} allows you to express the constants of Modula-2 in the following @@ -7160,14 +7901,14 @@ digits. @item Character constants consist of a single character enclosed by a pair of like quotes, either single (@code{'}) or double (@code{"}). They may -also be expressed by their ordinal value (their ASCII value, usually) +also be expressed by their ordinal value (their @sc{ascii} value, usually) followed by a @samp{C}. @item String constants consist of a sequence of characters enclosed by a pair of like quotes, either single (@code{'}) or double (@code{"}). Escape sequences in the style of C are also allowed. @xref{C -Constants, ,C and C++ constants}, for a brief explanation of escape +Constants, ,C and C@t{++} constants}, for a brief explanation of escape sequences. @item @@ -7184,21 +7925,21 @@ Pointer constants consist of integral values only. Set constants are not yet supported. @end itemize -@node M2 Defaults, Deviations, M2 Constants, Modula-2 +@node M2 Defaults @subsubsection Modula-2 defaults @cindex Modula-2 defaults If type and range checking are set automatically by @value{GDBN}, they both default to @code{on} whenever the working language changes to -Modula-2. This happens regardless of whether you, or @value{GDBN}, +Modula-2. This happens regardless of whether you or @value{GDBN} selected the working language. If you allow @value{GDBN} to set the language automatically, then entering code compiled from a file whose name ends with @file{.mod} sets the -working language to Modula-2. @xref{Automatically, ,Having @value{GDBN} set +working language to Modula-2. @xref{Automatically, ,Having @value{GDBN} set the language automatically}, for further details. -@node Deviations, M2 Checks, M2 Defaults, Modula-2 +@node Deviations @subsubsection Deviations from standard Modula-2 @cindex Modula-2, deviations from @@ -7228,7 +7969,7 @@ argument. All built-in procedures both modify @emph{and} return their argument. @end itemize -@node M2 Checks, M2 Scope, Deviations, Modula-2 +@node M2 Checks @subsubsection Modula-2 type and range checks @cindex Modula-2 checks @@ -7256,17 +7997,17 @@ whose types are not equivalent is an error. Range checking is done on all mathematical operations, assignment, array index bounds, and all built-in functions and procedures. -@node M2 Scope, GDB/M2, M2 Checks, Modula-2 +@node M2 Scope @subsubsection The scope operators @code{::} and @code{.} @cindex scope -@kindex . +@cindex @code{.}, Modula-2 scope operator @cindex colon, doubled as scope operator @ifinfo -@kindex colon-colon +@vindex colon-colon@r{, in Modula-2} @c Info cannot handle :: but TeX can. @end ifinfo @iftex -@kindex :: +@vindex ::@r{, in Modula-2} @end iftex There are a few subtle differences between the Modula-2 scope operator @@ -7296,33 +8037,530 @@ an error if the identifier @var{id} was not imported from definition module @var{module}, or if @var{id} is not an identifier in @var{module}. -@node GDB/M2, , M2 Scope, Modula-2 +@node GDB/M2 @subsubsection @value{GDBN} and Modula-2 Some @value{GDBN} commands have little use when debugging Modula-2 programs. Five subcommands of @code{set print} and @code{show print} apply -specifically to C and C++: @samp{vtbl}, @samp{demangle}, +specifically to C and C@t{++}: @samp{vtbl}, @samp{demangle}, @samp{asm-demangle}, @samp{object}, and @samp{union}. The first four -apply to C++, and the last to the C @code{union} type, which has no direct +apply to C@t{++}, and the last to the C @code{union} type, which has no direct analogue in Modula-2. The @code{@@} operator (@pxref{Expressions, ,Expressions}), while available -while using any language, is not useful with Modula-2. Its +with any language, is not useful with Modula-2. Its intent is to aid the debugging of @dfn{dynamic arrays}, which cannot be -created in Modula-2 as they can in C or C++. However, because an +created in Modula-2 as they can in C or C@t{++}. However, because an address can be specified by an integral constant, the construct -@samp{@{@var{type}@}@var{adrexp}} is still useful. (@pxref{Expressions, ,Expressions}) +@samp{@{@var{type}@}@var{adrexp}} is still useful. @cindex @code{#} in Modula-2 In @value{GDBN} scripts, the Modula-2 inequality operator @code{#} is interpreted as the beginning of a comment. Use @code{<>} instead. -@end ifset -@end ifclear -@node Symbols, Altering, Languages, Top +@node Chill +@subsection Chill + +The extensions made to @value{GDBN} to support Chill only support output +from the @sc{gnu} Chill compiler. Other Chill compilers are not currently +supported, and attempting to debug executables produced by them is most +likely to give an error as @value{GDBN} reads in the executable's symbol +table. + +@c This used to say "... following Chill related topics ...", but since +@c menus are not shown in the printed manual, it would look awkward. +This section covers the Chill related topics and the features +of @value{GDBN} which support these topics. + +@menu +* How modes are displayed:: How modes are displayed +* Locations:: Locations and their accesses +* Values and their Operations:: Values and their Operations +* Chill type and range checks:: +* Chill defaults:: +@end menu + +@node How modes are displayed +@subsubsection How modes are displayed + +The Chill Datatype- (Mode) support of @value{GDBN} is directly related +with the functionality of the @sc{gnu} Chill compiler, and therefore deviates +slightly from the standard specification of the Chill language. The +provided modes are: + +@c FIXME: this @table's contents effectively disable @code by using @r +@c on every @item. So why does it need @code? +@table @code +@item @r{@emph{Discrete modes:}} +@itemize @bullet +@item +@emph{Integer Modes} which are predefined by @code{BYTE, UBYTE, INT, +UINT, LONG, ULONG}, +@item +@emph{Boolean Mode} which is predefined by @code{BOOL}, +@item +@emph{Character Mode} which is predefined by @code{CHAR}, +@item +@emph{Set Mode} which is displayed by the keyword @code{SET}. +@smallexample +(@value{GDBP}) ptype x +type = SET (karli = 10, susi = 20, fritzi = 100) +@end smallexample +If the type is an unnumbered set the set element values are omitted. +@item +@emph{Range Mode} which is displayed by +@smallexample +@code{type = <basemode>(<lower bound> : <upper bound>)} +@end smallexample +where @code{<lower bound>, <upper bound>} can be of any discrete literal +expression (e.g. set element names). +@end itemize + +@item @r{@emph{Powerset Mode:}} +A Powerset Mode is displayed by the keyword @code{POWERSET} followed by +the member mode of the powerset. The member mode can be any discrete mode. +@smallexample +(@value{GDBP}) ptype x +type = POWERSET SET (egon, hugo, otto) +@end smallexample + +@item @r{@emph{Reference Modes:}} +@itemize @bullet +@item +@emph{Bound Reference Mode} which is displayed by the keyword @code{REF} +followed by the mode name to which the reference is bound. +@item +@emph{Free Reference Mode} which is displayed by the keyword @code{PTR}. +@end itemize + +@item @r{@emph{Procedure mode}} +The procedure mode is displayed by @code{type = PROC(<parameter list>) +<return mode> EXCEPTIONS (<exception list>)}. The @code{<parameter +list>} is a list of the parameter modes. @code{<return mode>} indicates +the mode of the result of the procedure if any. The exceptionlist lists +all possible exceptions which can be raised by the procedure. + +@ignore +@item @r{@emph{Instance mode}} +The instance mode is represented by a structure, which has a static +type, and is therefore not really of interest. +@end ignore + +@item @r{@emph{Synchronization Modes:}} +@itemize @bullet +@item +@emph{Event Mode} which is displayed by +@smallexample +@code{EVENT (<event length>)} +@end smallexample +where @code{(<event length>)} is optional. +@item +@emph{Buffer Mode} which is displayed by +@smallexample +@code{BUFFER (<buffer length>)<buffer element mode>} +@end smallexample +where @code{(<buffer length>)} is optional. +@end itemize + +@item @r{@emph{Timing Modes:}} +@itemize @bullet +@item +@emph{Duration Mode} which is predefined by @code{DURATION} +@item +@emph{Absolute Time Mode} which is predefined by @code{TIME} +@end itemize + +@item @r{@emph{Real Modes:}} +Real Modes are predefined with @code{REAL} and @code{LONG_REAL}. + +@item @r{@emph{String Modes:}} +@itemize @bullet +@item +@emph{Character String Mode} which is displayed by +@smallexample +@code{CHARS(<string length>)} +@end smallexample +followed by the keyword @code{VARYING} if the String Mode is a varying +mode +@item +@emph{Bit String Mode} which is displayed by +@smallexample +@code{BOOLS(<string +length>)} +@end smallexample +@end itemize + +@item @r{@emph{Array Mode:}} +The Array Mode is displayed by the keyword @code{ARRAY(<range>)} +followed by the element mode (which may in turn be an array mode). +@smallexample +(@value{GDBP}) ptype x +type = ARRAY (1:42) + ARRAY (1:20) + SET (karli = 10, susi = 20, fritzi = 100) +@end smallexample + +@item @r{@emph{Structure Mode}} +The Structure mode is displayed by the keyword @code{STRUCT(<field +list>)}. The @code{<field list>} consists of names and modes of fields +of the structure. Variant structures have the keyword @code{CASE <field> +OF <variant fields> ESAC} in their field list. Since the current version +of the GNU Chill compiler doesn't implement tag processing (no runtime +checks of variant fields, and therefore no debugging info), the output +always displays all variant fields. +@smallexample +(@value{GDBP}) ptype str +type = STRUCT ( + as x, + bs x, + CASE bs OF + (karli): + cs a + (ott): + ds x + ESAC +) +@end smallexample +@end table + +@node Locations +@subsubsection Locations and their accesses + +A location in Chill is an object which can contain values. + +A value of a location is generally accessed by the (declared) name of +the location. The output conforms to the specification of values in +Chill programs. How values are specified +is the topic of the next section, @ref{Values and their Operations}. + +The pseudo-location @code{RESULT} (or @code{result}) can be used to +display or change the result of a currently-active procedure: + +@smallexample +set result := EXPR +@end smallexample + +@noindent +This does the same as the Chill action @code{RESULT EXPR} (which +is not available in @value{GDBN}). + +Values of reference mode locations are printed by @code{PTR(<hex +value>)} in case of a free reference mode, and by @code{(REF <reference +mode>) (<hex-value>)} in case of a bound reference. @code{<hex value>} +represents the address where the reference points to. To access the +value of the location referenced by the pointer, use the dereference +operator @samp{->}. + +Values of procedure mode locations are displayed by +@smallexample +@code{@{ PROC +(<argument modes> ) <return mode> @} <address> <name of procedure +location>} +@end smallexample +@code{<argument modes>} is a list of modes according to the parameter +specification of the procedure and @code{<address>} shows the address of +the entry point. + +@ignore +Locations of instance modes are displayed just like a structure with two +fields specifying the @emph{process type} and the @emph{copy number} of +the investigated instance location@footnote{This comes from the current +implementation of instances. They are implemented as a structure (no +na). The output should be something like @code{[<name of the process>; +<instance number>]}.}. The field names are @code{__proc_type} and +@code{__proc_copy}. + +Locations of synchronization modes are displayed like a structure with +the field name @code{__event_data} in case of a event mode location, and +like a structure with the field @code{__buffer_data} in case of a buffer +mode location (refer to previous paragraph). + +Structure Mode locations are printed by @code{[.<field name>: <value>, +...]}. The @code{<field name>} corresponds to the structure mode +definition and the layout of @code{<value>} varies depending of the mode +of the field. If the investigated structure mode location is of variant +structure mode, the variant parts of the structure are enclosed in curled +braces (@samp{@{@}}). Fields enclosed by @samp{@{,@}} are residing +on the same memory location and represent the current values of the +memory location in their specific modes. Since no tag processing is done +all variants are displayed. A variant field is printed by +@code{(<variant name>) = .<field name>: <value>}. (who implements the +stuff ???) +@smallexample +(@value{GDBP}) print str1 $4 = [.as: 0, .bs: karli, .<TAG>: { (karli) = +[.cs: []], (susi) = [.ds: susi]}] +@end smallexample +@end ignore + +Substructures of string mode-, array mode- or structure mode-values +(e.g. array slices, fields of structure locations) are accessed using +certain operations which are described in the next section, @ref{Values +and their Operations}. + +A location value may be interpreted as having a different mode using the +location conversion. This mode conversion is written as @code{<mode +name>(<location>)}. The user has to consider that the sizes of the modes +have to be equal otherwise an error occurs. Furthermore, no range +checking of the location against the destination mode is performed, and +therefore the result can be quite confusing. + +@smallexample +(@value{GDBP}) print int (s(3 up 4)) XXX TO be filled in !! XXX +@end smallexample + +@node Values and their Operations +@subsubsection Values and their Operations + +Values are used to alter locations, to investigate complex structures in +more detail or to filter relevant information out of a large amount of +data. There are several (mode dependent) operations defined which enable +such investigations. These operations are not only applicable to +constant values but also to locations, which can become quite useful +when debugging complex structures. During parsing the command line +(e.g. evaluating an expression) @value{GDBN} treats location names as +the values behind these locations. + +This section describes how values have to be specified and which +operations are legal to be used with such values. + +@table @code +@item Literal Values +Literal values are specified in the same manner as in @sc{gnu} Chill programs. +For detailed specification refer to the @sc{gnu} Chill implementation Manual +chapter 1.5. +@c FIXME: if the Chill Manual is a Texinfo documents, the above should +@c be converted to a @ref. + +@ignore +@itemize @bullet +@item +@emph{Integer Literals} are specified in the same manner as in Chill +programs (refer to the Chill Standard z200/88 chpt 5.2.4.2) +@item +@emph{Boolean Literals} are defined by @code{TRUE} and @code{FALSE}. +@item +@emph{Character Literals} are defined by @code{'<character>'}. (e.g. +@code{'M'}) +@item +@emph{Set Literals} are defined by a name which was specified in a set +mode. The value delivered by a Set Literal is the set value. This is +comparable to an enumeration in C/C@t{++} language. +@item +@emph{Emptiness Literal} is predefined by @code{NULL}. The value of the +emptiness literal delivers either the empty reference value, the empty +procedure value or the empty instance value. + +@item +@emph{Character String Literals} are defined by a sequence of characters +enclosed in single- or double quotes. If a single- or double quote has +to be part of the string literal it has to be stuffed (specified twice). +@item +@emph{Bitstring Literals} are specified in the same manner as in Chill +programs (refer z200/88 chpt 5.2.4.8). +@item +@emph{Floating point literals} are specified in the same manner as in +(gnu-)Chill programs (refer @sc{gnu} Chill implementation Manual chapter 1.5). +@end itemize +@end ignore + +@item Tuple Values +A tuple is specified by @code{<mode name>[<tuple>]}, where @code{<mode +name>} can be omitted if the mode of the tuple is unambiguous. This +unambiguity is derived from the context of a evaluated expression. +@code{<tuple>} can be one of the following: + +@itemize @bullet +@item @emph{Powerset Tuple} +@item @emph{Array Tuple} +@item @emph{Structure Tuple} +Powerset tuples, array tuples and structure tuples are specified in the +same manner as in Chill programs refer to z200/88 chpt 5.2.5. +@end itemize + +@item String Element Value +A string element value is specified by +@smallexample +@code{<string value>(<index>)} +@end smallexample +where @code{<index>} is a integer expression. It delivers a character +value which is equivalent to the character indexed by @code{<index>} in +the string. + +@item String Slice Value +A string slice value is specified by @code{<string value>(<slice +spec>)}, where @code{<slice spec>} can be either a range of integer +expressions or specified by @code{<start expr> up <size>}. +@code{<size>} denotes the number of elements which the slice contains. +The delivered value is a string value, which is part of the specified +string. + +@item Array Element Values +An array element value is specified by @code{<array value>(<expr>)} and +delivers a array element value of the mode of the specified array. + +@item Array Slice Values +An array slice is specified by @code{<array value>(<slice spec>)}, where +@code{<slice spec>} can be either a range specified by expressions or by +@code{<start expr> up <size>}. @code{<size>} denotes the number of +arrayelements the slice contains. The delivered value is an array value +which is part of the specified array. + +@item Structure Field Values +A structure field value is derived by @code{<structure value>.<field +name>}, where @code{<field name>} indicates the name of a field specified +in the mode definition of the structure. The mode of the delivered value +corresponds to this mode definition in the structure definition. + +@item Procedure Call Value +The procedure call value is derived from the return value of the +procedure@footnote{If a procedure call is used for instance in an +expression, then this procedure is called with all its side +effects. This can lead to confusing results if used carelessly.}. + +Values of duration mode locations are represented by @code{ULONG} literals. + +Values of time mode locations appear as +@smallexample +@code{TIME(<secs>:<nsecs>)} +@end smallexample + + +@ignore +This is not implemented yet: +@item Built-in Value +@noindent +The following built in functions are provided: + +@table @code +@item @code{ADDR()} +@item @code{NUM()} +@item @code{PRED()} +@item @code{SUCC()} +@item @code{ABS()} +@item @code{CARD()} +@item @code{MAX()} +@item @code{MIN()} +@item @code{SIZE()} +@item @code{UPPER()} +@item @code{LOWER()} +@item @code{LENGTH()} +@item @code{SIN()} +@item @code{COS()} +@item @code{TAN()} +@item @code{ARCSIN()} +@item @code{ARCCOS()} +@item @code{ARCTAN()} +@item @code{EXP()} +@item @code{LN()} +@item @code{LOG()} +@item @code{SQRT()} +@end table + +For a detailed description refer to the GNU Chill implementation manual +chapter 1.6. +@end ignore + +@item Zero-adic Operator Value +The zero-adic operator value is derived from the instance value for the +current active process. + +@item Expression Values +The value delivered by an expression is the result of the evaluation of +the specified expression. If there are error conditions (mode +incompatibility, etc.) the evaluation of expressions is aborted with a +corresponding error message. Expressions may be parenthesised which +causes the evaluation of this expression before any other expression +which uses the result of the parenthesised expression. The following +operators are supported by @value{GDBN}: + +@table @code +@item @code{OR, ORIF, XOR} +@itemx @code{AND, ANDIF} +@itemx @code{NOT} +Logical operators defined over operands of boolean mode. + +@item @code{=, /=} +Equality and inequality operators defined over all modes. + +@item @code{>, >=} +@itemx @code{<, <=} +Relational operators defined over predefined modes. + +@item @code{+, -} +@itemx @code{*, /, MOD, REM} +Arithmetic operators defined over predefined modes. + +@item @code{-} +Change sign operator. + +@item @code{//} +String concatenation operator. + +@item @code{()} +String repetition operator. + +@item @code{->} +Referenced location operator which can be used either to take the +address of a location (@code{->loc}), or to dereference a reference +location (@code{loc->}). + +@item @code{OR, XOR} +@itemx @code{AND} +@itemx @code{NOT} +Powerset and bitstring operators. + +@item @code{>, >=} +@itemx @code{<, <=} +Powerset inclusion operators. + +@item @code{IN} +Membership operator. +@end table +@end table + +@node Chill type and range checks +@subsubsection Chill type and range checks + +@value{GDBN} considers two Chill variables mode equivalent if the sizes +of the two modes are equal. This rule applies recursively to more +complex datatypes which means that complex modes are treated +equivalent if all element modes (which also can be complex modes like +structures, arrays, etc.) have the same size. + +Range checking is done on all mathematical operations, assignment, array +index bounds and all built in procedures. + +Strong type checks are forced using the @value{GDBN} command @code{set +check strong}. This enforces strong type and range checks on all +operations where Chill constructs are used (expressions, built in +functions, etc.) in respect to the semantics as defined in the z.200 +language specification. + +All checks can be disabled by the @value{GDBN} command @code{set check +off}. + +@ignore +@c Deviations from the Chill Standard Z200/88 +see last paragraph ? +@end ignore + +@node Chill defaults +@subsubsection Chill defaults + +If type and range checking are set automatically by @value{GDBN}, they +both default to @code{on} whenever the working language changes to +Chill. This happens regardless of whether you or @value{GDBN} +selected the working language. + +If you allow @value{GDBN} to set the language automatically, then entering +code compiled from a file whose name ends with @file{.ch} sets the +working language to Chill. @xref{Automatically, ,Having @value{GDBN} set +the language automatically}, for further details. + +@node Symbols @chapter Examining the Symbol Table -The commands described in this section allow you to inquire about the +The commands described in this chapter allow you to inquire about the symbols (names of variables, functions and types) defined in your program. This information is inherent in the text of your program and does not change as your program executes. @value{GDBN} finds it in your @@ -7351,6 +8589,7 @@ looks up the value of @code{x} in the scope of the file @file{foo.c}. @table @code @kindex info address +@cindex address of a symbol @item info address @var{symbol} Describe where the data for @var{symbol} is stored. For a register variable, this says which register it is kept in. For a non-register @@ -7361,9 +8600,25 @@ Note the contrast with @samp{print &@var{symbol}}, which does not work at all for a register variable, and for a stack local variable prints the exact address of the current instantiation of the variable. +@kindex info symbol +@cindex symbol from address +@item info symbol @var{addr} +Print the name of a symbol which is stored at the address @var{addr}. +If no symbol is stored exactly at @var{addr}, @value{GDBN} prints the +nearest symbol and an offset from it: + +@example +(@value{GDBP}) info symbol 0x54320 +_initialize_vx + 396 in section .text +@end example + +@noindent +This is the opposite of the @code{info address} command. You can use +it to find out the name of a variable or a function given its address. + @kindex whatis -@item whatis @var{exp} -Print the data type of expression @var{exp}. @var{exp} is not +@item whatis @var{expr} +Print the data type of expression @var{expr}. @var{expr} is not actually evaluated, and any side-effecting operations (such as assignments or function calls) inside it do not take place. @xref{Expressions, ,Expressions}. @@ -7374,16 +8629,13 @@ Print the data type of @code{$}, the last value in the value history. @kindex ptype @item ptype @var{typename} Print a description of data type @var{typename}. @var{typename} may be -the name of a type, or for C code it may have the form -@ifclear CONLY -@samp{class @var{class-name}}, -@end ifclear -@samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or -@samp{enum @var{enum-tag}}. - -@item ptype @var{exp} +the name of a type, or for C code it may have the form @samp{class +@var{class-name}}, @samp{struct @var{struct-tag}}, @samp{union +@var{union-tag}} or @samp{enum @var{enum-tag}}. + +@item ptype @var{expr} @itemx ptype -Print a description of the type of expression @var{exp}. @code{ptype} +Print a description of the type of expression @var{expr}. @code{ptype} differs from @code{whatis} by printing a detailed description, instead of just the name of the type. @@ -7415,17 +8667,42 @@ the type of @code{$}, the last value in the value history. @kindex info types @item info types @var{regexp} @itemx info types -Print a brief description of all types whose name matches @var{regexp} +Print a brief description of all types whose names match @var{regexp} (or all types in your program, if you supply no argument). Each complete typename is matched as though it were a complete line; thus, @samp{i type value} gives information on all types in your program whose -name includes the string @code{value}, but @samp{i type ^value$} gives +names include the string @code{value}, but @samp{i type ^value$} gives information only on types whose complete name is @code{value}. This command differs from @code{ptype} in two ways: first, like @code{whatis}, it does not print a detailed description; second, it lists all source files where a type is defined. +@kindex info scope +@cindex local variables +@item info scope @var{addr} +List all the variables local to a particular scope. This command +accepts a location---a function name, a source line, or an address +preceded by a @samp{*}, and prints all the variables local to the +scope defined by that location. For example: + +@smallexample +(@value{GDBP}) @b{info scope command_line_handler} +Scope for command_line_handler: +Symbol rl is an argument at stack/frame offset 8, length 4. +Symbol linebuffer is in static storage at address 0x150a18, length 4. +Symbol linelength is in static storage at address 0x150a1c, length 4. +Symbol p is a local variable in register $esi, length 4. +Symbol p1 is a local variable in register $ebx, length 4. +Symbol nline is a local variable in register $edx, length 4. +Symbol repeat is a local variable at frame offset -8, length 4. +@end smallexample + +@noindent +This command is especially useful for determining what data to collect +during a @dfn{trace experiment}, see @ref{Tracepoint Actions, +collect}. + @kindex info source @item info source Show the name of the current source file---that is, the source file for @@ -7447,12 +8724,14 @@ Print the names and data types of all defined functions whose names contain a match for regular expression @var{regexp}. Thus, @samp{info fun step} finds all functions whose names include @code{step}; @samp{info fun ^step} finds those whose names -start with @code{step}. +start with @code{step}. If a function name contains characters +that conflict with the regular expression language (eg. +@samp{operator*()}), they may be quoted with a backslash. @kindex info variables @item info variables Print the names and data types of all variables that are declared -outside of functions (i.e., excluding local variables). +outside of functions (i.e.@: excluding local variables). @item info variables @var{regexp} Print the names and data types of all variables (except for local @@ -7465,24 +8744,20 @@ This was never implemented. @item info methods @itemx info methods @var{regexp} The @code{info methods} command permits the user to examine all defined -methods within C++ program, or (with the @var{regexp} argument) a -specific set of methods found in the various C++ classes. Many -C++ classes provide a large number of methods. Thus, the output +methods within C@t{++} program, or (with the @var{regexp} argument) a +specific set of methods found in the various C@t{++} classes. Many +C@t{++} classes provide a large number of methods. Thus, the output from the @code{ptype} command can be overwhelming and hard to use. The @code{info-methods} command filters the methods, printing only those which match the regular-expression @var{regexp}. @end ignore -@ifclear HPPA @cindex reloading symbols Some systems allow individual object files that make up your program to -be replaced without stopping and restarting your program. -@ifset VXWORKS -For example, in VxWorks you can simply recompile a defective object file -and keep on running. -@end ifset -If you are running on one of these systems, you can allow @value{GDBN} to -reload the symbols for automatically relinked modules: +be replaced without stopping and restarting your program. For example, +in VxWorks you can simply recompile a defective object file and keep on +running. If you are running on one of these systems, you can allow +@value{GDBN} to reload the symbols for automatically relinked modules: @table @code @kindex set symbol-reloading @@ -7491,20 +8766,19 @@ Replace symbol definitions for the corresponding source file when an object file with a particular name is seen again. @item set symbol-reloading off -Do not replace symbol definitions when re-encountering object files of -the same name. This is the default state; if you are not running on a -system that permits automatically relinking modules, you should leave -@code{symbol-reloading} off, since otherwise @value{GDBN} may discard symbols -when linking large programs, that may contain several modules (from -different directories or libraries) with the same name. +Do not replace symbol definitions when encountering object files of the +same name more than once. This is the default state; if you are not +running on a system that permits automatic relinking of modules, you +should leave @code{symbol-reloading} off, since otherwise @value{GDBN} +may discard symbols when linking large programs, that may contain +several modules (from different directories or libraries) with the same +name. @kindex show symbol-reloading @item show symbol-reloading Show the current @code{on} or @code{off} setting. @end table -@end ifclear -@ifset HPPA @kindex set opaque-type-resolution @item set opaque-type-resolution on Tell @value{GDBN} to resolve opaque types. An opaque type is a type @@ -7526,7 +8800,6 @@ is printed as follows: @kindex show opaque-type-resolution @item show opaque-type-resolution Show whether opaque types are resolved or not. -@end ifset @kindex maint print symbols @cindex symbol dump @@ -7551,7 +8824,7 @@ required for each object file from which @value{GDBN} has read some symbols. @value{GDBN} reads symbols (in the description of @code{symbol-file}). @end table -@node Altering, GDB Files, Symbols, Top +@node Altering @chapter Altering Execution Once you think you have found an error in your program, you might want to @@ -7561,28 +8834,19 @@ experiment, using the @value{GDBN} features for altering execution of the program. For example, you can store new values into variables or memory -locations, -@ifclear BARETARGET -give your program a signal, restart it -@end ifclear -@ifset BARETARGET -restart your program -@end ifset -at a different address, or even return prematurely from a function. +locations, give your program a signal, restart it at a different +address, or even return prematurely from a function. @menu * Assignment:: Assignment to variables * Jumping:: Continuing at a different address -@ifclear BARETARGET * Signaling:: Giving your program a signal -@end ifclear - * Returning:: Returning from a function * Calling:: Calling your program's functions * Patching:: Patching your program @end menu -@node Assignment, Jumping, Altering, Altering +@node Assignment @section Assignment to variables @cindex assignment @@ -7596,11 +8860,9 @@ print x=4 @noindent stores the value 4 into the variable @code{x}, and then prints the -value of the assignment expression (which is 4). -@ifclear CONLY +value of the assignment expression (which is 4). @xref{Languages, ,Using @value{GDBN} with Different Languages}, for more information on operators in supported languages. -@end ifclear @kindex set variable @cindex variables, setting @@ -7610,7 +8872,6 @@ really the same as @code{print} except that the expression's value is not printed and is not put in the value history (@pxref{Value History, ,Value history}). The expression is evaluated only for its effects. -@ifclear HPPA If the beginning of the argument string of the @code{set} command appears identical to a @code{set} subcommand, use the @code{set variable} command instead of just @code{set}. This command is identical @@ -7635,8 +8896,7 @@ order to actually set the program's variable @code{width}, use @example (@value{GDBP}) set var width=47 @end example -@end ifclear -@ifset HPPA + Because the @code{set} command has many subcommands that can conflict with the names of program variables, it is a good idea to use the @code{set variable} command instead of just @code{set}. For example, if @@ -7651,13 +8911,14 @@ type = double (@value{GDBP}) p g $1 = 1 (@value{GDBP}) set g=4 -(gdb) p g +(@value{GDBP}) p g $2 = 1 (@value{GDBP}) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/smith/cc_progs/a.out -"/home/smith/cc_progs/a.out": can't open to read symbols: Invalid bfd target. +"/home/smith/cc_progs/a.out": can't open to read symbols: + Invalid bfd target. (@value{GDBP}) show g The current BFD target is "=4". @end group @@ -7671,7 +8932,6 @@ The program variable @code{g} did not change, and you silently set the @example (@value{GDBP}) set var g=4 @end example -@end ifset @value{GDBN} allows more implicit conversions in assignments than C; you can freely store an integer value into a pointer variable or vice versa, @@ -7693,7 +8953,7 @@ set @{int@}0x83040 = 4 @noindent stores the value 4 into that memory location. -@node Jumping, Signaling, Assignment, Altering +@node Jumping @section Continuing at a different address Ordinarily, when you continue your program, you do so at the place where @@ -7724,12 +8984,12 @@ well acquainted with the machine-language code of your program. Resume execution at the instruction at address @var{address}. @end table -@ifclear HPPA @c Doesn't work on HP-UX; have to set $pcoqh and $pcoqt. -You can get much the same effect as the @code{jump} command by storing a -new value into the register @code{$pc}. The difference is that this -does not start your program running; it only changes the address of where it -@emph{will} run when you continue. For example, +On many systems, you can get much the same effect as the @code{jump} +command by storing a new value into the register @code{$pc}. The +difference is that this does not start your program running; it only +changes the address of where it @emph{will} run when you continue. For +example, @example set $pc = 0x485 @@ -7739,16 +8999,14 @@ set $pc = 0x485 makes the next @code{continue} command or stepping command execute at address @code{0x485}, rather than at the address where your program stopped. @xref{Continuing and Stepping, ,Continuing and stepping}. -@end ifclear The most common occasion to use the @code{jump} command is to back up---perhaps with more breakpoints set---over a portion of a program that has already executed, in order to examine its execution in more detail. -@ifclear BARETARGET @c @group -@node Signaling, Returning, Jumping, Altering +@node Signaling @section Giving your program a signal @table @code @@ -7776,9 +9034,8 @@ causes @value{GDBN} to decide what to do with the signal depending on the signal handling tables (@pxref{Signals}). The @code{signal} command passes the signal directly to your program. -@end ifclear -@node Returning, Calling, Signaling, Altering +@node Returning @section Returning from a function @table @code @@ -7809,7 +9066,7 @@ returned. In contrast, the @code{finish} command (@pxref{Continuing and Stepping, ,Continuing and stepping}) resumes execution until the selected stack frame returns naturally. -@node Calling, Patching, Returning, Altering +@node Calling @section Calling program functions @cindex calling functions @@ -7822,33 +9079,26 @@ returned values. You can use this variant of the @code{print} command if you want to execute a function from your program, but without cluttering the output -with @code{void} returned values. If the result is not void, it -is printed and saved in the value history. - -@ifclear HPPA -For the A29K, a user-controlled variable @code{call_scratch_address}, -specifies the location of a scratch area to be used when @value{GDBN} -calls a function in the target. This is necessary because the usual -method of putting the scratch area on the stack does not work in systems -that have separate instruction and data spaces. -@end ifclear - -@node Patching, , Calling, Altering +with @code{void} returned values. If the result is not void, it +is printed and saved in the value history. + +@c OBSOLETE For the A29K, a user-controlled variable @code{call_scratch_address}, +@c OBSOLETE specifies the location of a scratch area to be used when @value{GDBN} +@c OBSOLETE calls a function in the target. This is necessary because the usual +@c OBSOLETE method of putting the scratch area on the stack does not work in systems +@c OBSOLETE that have separate instruction and data spaces. + +@node Patching @section Patching programs + @cindex patching binaries @cindex writing into executables -@ifclear BARETARGET @cindex writing into corefiles -@end ifclear -By default, @value{GDBN} opens the file containing your program's executable -code -@ifclear BARETARGET -(or the corefile) -@end ifclear -read-only. This prevents accidental alterations -to machine code; but it also prevents you from intentionally patching -your program's binary. +By default, @value{GDBN} opens the file containing your program's +executable code (or the corefile) read-only. This prevents accidental +alterations to machine code; but it also prevents you from intentionally +patching your program's binary. If you'd like to be able to patch the binary, you can specify that explicitly with the @code{set write} command. For example, you might @@ -7859,61 +9109,43 @@ repairs. @kindex set write @item set write on @itemx set write off -If you specify @samp{set write on}, @value{GDBN} opens executable -@ifclear BARETARGET -and core -@end ifclear -files for both reading and writing; if you specify @samp{set write +If you specify @samp{set write on}, @value{GDBN} opens executable and +core files for both reading and writing; if you specify @samp{set write off} (the default), @value{GDBN} opens them read-only. If you have already loaded a file, you must load it again (using the -@code{exec-file} -@ifclear BARETARGET -or @code{core-file} -@end ifclear -command) after changing @code{set write}, for your new setting to take -effect. +@code{exec-file} or @code{core-file} command) after changing @code{set +write}, for your new setting to take effect. @item show write @kindex show write -Display whether executable files -@ifclear BARETARGET -and core files -@end ifclear -are opened for writing as well as reading. +Display whether executable files and core files are opened for writing +as well as reading. @end table -@node GDB Files, Targets, Altering, Top +@node GDB Files @chapter @value{GDBN} Files -@value{GDBN} needs to know the file name of the program to be debugged, both in -order to read its symbol table and in order to start your program. -@ifclear BARETARGET -To debug a core dump of a previous run, you must also tell @value{GDBN} -the name of the core dump file. -@end ifclear +@value{GDBN} needs to know the file name of the program to be debugged, +both in order to read its symbol table and in order to start your +program. To debug a core dump of a previous run, you must also tell +@value{GDBN} the name of the core dump file. @menu * Files:: Commands to specify files * Symbol Errors:: Errors reading symbol files @end menu -@node Files, Symbol Errors, GDB Files, GDB Files +@node Files @section Commands to specify files -@cindex symbol table -@ifclear BARETARGET +@cindex symbol table @cindex core dump file -You may want to specify executable and core dump file names. -The usual way to do this is at start-up time, using the arguments to -@value{GDBN}'s start-up commands (@pxref{Invocation, , -Getting In and Out of @value{GDBN}}). -@end ifclear -@ifset BARETARGET -The usual way to specify an executable file name is with -the command argument given when you start @value{GDBN}, (@pxref{Invocation, -,Getting In and Out of @value{GDBN}}. -@end ifset + +You may want to specify executable and core dump file names. The usual +way to do this is at start-up time, using the arguments to +@value{GDBN}'s start-up commands (@pxref{Invocation, , Getting In and +Out of @value{GDBN}}). Occasionally it is necessary to change to a different file during a @value{GDBN} session. Or you may run @value{GDBN} and forget to specify @@ -7927,22 +9159,20 @@ to specify new files are useful. Use @var{filename} as the program to be debugged. It is read for its symbols and for the contents of pure memory. It is also the program executed when you use the @code{run} command. If you do not specify a -directory and the file is not found in the @value{GDBN} working directory, -@value{GDBN} uses the environment variable @code{PATH} as a list of -directories to search, just as the shell does when looking for a program -to run. You can change the value of this variable, for both @value{GDBN} +directory and the file is not found in the @value{GDBN} working directory, +@value{GDBN} uses the environment variable @code{PATH} as a list of +directories to search, just as the shell does when looking for a program +to run. You can change the value of this variable, for both @value{GDBN} and your program, using the @code{path} command. -@ifclear HPPA -On systems with memory-mapped files, an auxiliary file +On systems with memory-mapped files, an auxiliary file named @file{@var{filename}.syms} may hold symbol table information for @var{filename}. If so, @value{GDBN} maps in the symbol table from @file{@var{filename}.syms}, starting up more quickly. See the descriptions of the file options @samp{-mapped} and @samp{-readnow} (available on the command line, and with the commands @code{file}, -@code{symbol-file}, or @code{add-symbol-file}, described below), +@code{symbol-file}, or @code{add-symbol-file}, described below), for more information. -@end ifclear @item file @code{file} with no argument makes @value{GDBN} discard any information it @@ -7964,7 +9194,7 @@ table and program to run from the same file. @code{symbol-file} with no argument clears out @value{GDBN} information on your program's symbol table. -The @code{symbol-file} command causes @value{GDBN} to forget the contents +The @code{symbol-file} command causes @value{GDBN} to forget the contents of its convenience variables, the value history, and all breakpoints and auto-display expressions. This is because they may contain pointers to the internal data recording symbols and data types, which are part of @@ -7977,11 +9207,9 @@ When @value{GDBN} is configured for a particular environment, it understands debugging information in whatever format is the standard generated for that environment; you may use either a @sc{gnu} compiler, or other compilers that adhere to the local conventions. -@ifclear HPPA Best results are usually obtained from @sc{gnu} compilers; for example, using @code{@value{GCC}} you can generate debugging information for optimized code. -@end ifclear For most kinds of object files, with the exception of old SVR3 systems using COFF, the @code{symbol-file} command does not normally read the @@ -7996,7 +9224,6 @@ file are being read. (The @code{set verbose} command can turn these pauses into messages if desired. @xref{Messages/Warnings, ,Optional warnings and messages}.) -@ifclear HPPA We have not implemented the two-stage strategy for COFF yet. When the symbol table is stored in COFF format, @code{symbol-file} reads the symbol table data in full right away. Note that ``stabs-in-COFF'' @@ -8014,11 +9241,8 @@ in stabs format. You can override the @value{GDBN} two-stage strategy for reading symbol tables by using the @samp{-readnow} option with any of the commands that load symbol table information, if you want to be sure @value{GDBN} has the -entire symbol table available. -@end ifclear +entire symbol table available. -@ifclear BARETARGET -@ifclear HPPA If memory-mapped files are available on your system through the @code{mmap} system call, you can use another option, @samp{-mapped}, to cause @value{GDBN} to write the symbols for your program into a reusable @@ -8040,7 +9264,6 @@ needed. The @file{.syms} file is specific to the host machine where you run @value{GDBN}. It holds an exact image of the internal @value{GDBN} symbol table. It cannot be shared across multiple host platforms. -@end ifclear @c FIXME: for now no mention of directories, since this seems to be in @c flux. 13mar1992 status is that in theory GDB would look either in @@ -8062,30 +9285,65 @@ executable file itself for other parts. to be used. Note that the core file is ignored when your program is actually running -under @value{GDBN}. So, if you have been running your program and you wish to -debug a core file instead, you must kill the subprocess in which the -program is running. To do this, use the @code{kill} command +under @value{GDBN}. So, if you have been running your program and you +wish to debug a core file instead, you must kill the subprocess in which +the program is running. To do this, use the @code{kill} command (@pxref{Kill Process, ,Killing the child process}). -@end ifclear -@ifclear BARETARGET -@ifclear HPPA @kindex add-symbol-file @cindex dynamic linking @item add-symbol-file @var{filename} @var{address} @itemx add-symbol-file @var{filename} @var{address} @r{[} -readnow @r{]} @r{[} -mapped @r{]} -The @code{add-symbol-file} command reads additional symbol table information -from the file @var{filename}. You would use this command when @var{filename} -has been dynamically loaded (by some other means) into the program that -is running. @var{address} should be the memory address at which the -file has been loaded; @value{GDBN} cannot figure this out for itself. -You can specify @var{address} as an expression. +@itemx add-symbol-file @var{filename} @r{-s}@var{section} @var{address} @dots{} +The @code{add-symbol-file} command reads additional symbol table +information from the file @var{filename}. You would use this command +when @var{filename} has been dynamically loaded (by some other means) +into the program that is running. @var{address} should be the memory +address at which the file has been loaded; @value{GDBN} cannot figure +this out for itself. You can additionally specify an arbitrary number +of @samp{@r{-s}@var{section} @var{address}} pairs, to give an explicit +section name and base address for that section. You can specify any +@var{address} as an expression. The symbol table of the file @var{filename} is added to the symbol table originally read with the @code{symbol-file} command. You can use the -@code{add-symbol-file} command any number of times; the new symbol data thus -read keeps adding to the old. To discard all old symbol data instead, -use the @code{symbol-file} command. +@code{add-symbol-file} command any number of times; the new symbol data +thus read keeps adding to the old. To discard all old symbol data +instead, use the @code{symbol-file} command without any arguments. + +@cindex relocatable object files, reading symbols from +@cindex object files, relocatable, reading symbols from +@cindex reading symbols from relocatable object files +@cindex symbols, reading from relocatable object files +@cindex @file{.o} files, reading symbols from +Although @var{filename} is typically a shared library file, an +executable file, or some other object file which has been fully +relocated for loading into a process, you can also load symbolic +information from relocatable @file{.o} files, as long as: + +@itemize @bullet +@item +the file's symbolic information refers only to linker symbols defined in +that file, not to symbols defined by other object files, +@item +every section the file's symbolic information refers to has actually +been loaded into the inferior, as it appears in the file, and +@item +you can determine the address at which every section was loaded, and +provide these to the @code{add-symbol-file} command. +@end itemize + +@noindent +Some embedded operating systems, like Sun Chorus and VxWorks, can load +relocatable files into an already running program; such systems +typically make the requirements above easy to meet. However, it's +important to recognize that many native systems use complex link +procedures (@code{.linkonce} section factoring and C++ constructor table +assembly, for example) that make the requirements difficult to meet. In +general, one cannot assume that using @code{add-symbol-file} to read a +relocatable object file's symbolic information will have the same effect +as linking the relocatable object file into the program in the normal +way. @code{add-symbol-file} does not repeat if you press @key{RET} after using it. @@ -8096,68 +9354,140 @@ table information for @var{filename}. @kindex add-shared-symbol-file @item add-shared-symbol-file The @code{add-shared-symbol-file} command can be used only under Harris' CXUX -operating system for the Motorola 88k. @value{GDBN} automatically looks for -shared libraries, however if @value{GDBN} does not find yours, you can run +operating system for the Motorola 88k. @value{GDBN} automatically looks for +shared libraries, however if @value{GDBN} does not find yours, you can run @code{add-shared-symbol-file}. It takes no arguments. -@end ifclear -@end ifclear -@ifclear HPPA @kindex section @item section -The @code{section} command changes the base address of section SECTION of -the exec file to ADDR. This can be used if the exec file does not contain -section addresses, (such as in the a.out format), or when the addresses -specified in the file itself are wrong. Each section must be changed -separately. The ``info files'' command lists all the sections and their -addresses. -@end ifclear +The @code{section} command changes the base address of section SECTION of +the exec file to ADDR. This can be used if the exec file does not contain +section addresses, (such as in the a.out format), or when the addresses +specified in the file itself are wrong. Each section must be changed +separately. The @code{info files} command, described below, lists all +the sections and their addresses. @kindex info files @kindex info target @item info files @itemx info target -@code{info files} and @code{info target} are synonymous; both print -the current target (@pxref{Targets, ,Specifying a Debugging Target}), -including the -@ifclear BARETARGET -names of the executable and core dump files -@end ifclear -@ifset BARETARGET -name of the executable file -@end ifset -currently in use by @value{GDBN}, and the files from which symbols were -loaded. The command @code{help target} lists all possible targets -rather than current ones. +@code{info files} and @code{info target} are synonymous; both print the +current target (@pxref{Targets, ,Specifying a Debugging Target}), +including the names of the executable and core dump files currently in +use by @value{GDBN}, and the files from which symbols were loaded. The +command @code{help target} lists all possible targets rather than +current ones. + +@kindex maint info sections +@item maint info sections +Another command that can give you extra information about program sections +is @code{maint info sections}. In addition to the section information +displayed by @code{info files}, this command displays the flags and file +offset of each section in the executable and core dump files. In addition, +@code{maint info sections} provides the following command options (which +may be arbitrarily combined): + +@table @code +@item ALLOBJ +Display sections for all loaded object files, including shared libraries. +@item @var{sections} +Display info only for named @var{sections}. +@item @var{section-flags} +Display info only for sections for which @var{section-flags} are true. +The section flags that @value{GDBN} currently knows about are: +@table @code +@item ALLOC +Section will have space allocated in the process when loaded. +Set for all sections except those containing debug information. +@item LOAD +Section will be loaded from the file into the child process memory. +Set for pre-initialized code and data, clear for @code{.bss} sections. +@item RELOC +Section needs to be relocated before loading. +@item READONLY +Section cannot be modified by the child process. +@item CODE +Section contains executable code only. +@item DATA +Section contains data only (no executable code). +@item ROM +Section will reside in ROM. +@item CONSTRUCTOR +Section contains data for constructor/destructor lists. +@item HAS_CONTENTS +Section is not empty. +@item NEVER_LOAD +An instruction to the linker to not output the section. +@item COFF_SHARED_LIBRARY +A notification to the linker that the section contains +COFF shared library information. +@item IS_COMMON +Section contains common symbols. +@end table +@end table +@kindex set trust-readonly-sections +@item set trust-readonly-sections on +Tell @value{GDBN} that readonly sections in your object file +really are read-only (i.e.@: that their contents will not change). +In that case, @value{GDBN} can fetch values from these sections +out of the object file, rather than from the target program. +For some targets (notably embedded ones), this can be a significant +enhancement to debugging performance. + +The default is off. + +@item set trust-readonly-sections off +Tell @value{GDBN} not to trust readonly sections. This means that +the contents of the section might change while the program is running, +and must therefore be fetched from the target when needed. @end table All file-specifying commands allow both absolute and relative file names as arguments. @value{GDBN} always converts the file name to an absolute file name and remembers it that way. -@ifclear BARETARGET @cindex shared libraries -@ifclear HPPA -@c added HP-UX -- Kim (HP writer) @value{GDBN} supports HP-UX, SunOS, SVr4, Irix 5, and IBM RS/6000 shared libraries. -@end ifclear -@ifset HPPA -@value{GDBN} supports HP-UX shared libraries. -@end ifset + @value{GDBN} automatically loads symbol definitions from shared libraries when you use the @code{run} command, or when you examine a core file. (Before you issue the @code{run} command, @value{GDBN} does not understand references to a function in a shared library, however---unless you are debugging a core file). -@ifset HPPA -If the program loads a library explicitly, @value{GDBN} automatically -loads the symbols at the time of the @code{shl_load} call. -@end ifset + +On HP-UX, if the program loads a library explicitly, @value{GDBN} +automatically loads the symbols at the time of the @code{shl_load} call. + @c FIXME: some @value{GDBN} release may permit some refs to undef @c FIXME...symbols---eg in a break cmd---assuming they are from a shared @c FIXME...lib; check this from time to time when updating manual +There are times, however, when you may wish to not automatically load +symbol definitions from shared libraries, such as when they are +particularly large or there are many of them. + +To control the automatic loading of shared library symbols, use the +commands: + +@table @code +@kindex set auto-solib-add +@item set auto-solib-add @var{mode} +If @var{mode} is @code{on}, symbols from all shared object libraries +will be loaded automatically when the inferior begins execution, you +attach to an independently started inferior, or when the dynamic linker +informs @value{GDBN} that a new library has been loaded. If @var{mode} +is @code{off}, symbols must be loaded manually, using the +@code{sharedlibrary} command. The default value is @code{on}. + +@kindex show auto-solib-add +@item show auto-solib-add +Display the current autoloading mode. +@end table + +To explicitly load shared library symbols, use the @code{sharedlibrary} +command: + @table @code @kindex info sharedlibrary @kindex info share @@ -8169,7 +9499,6 @@ Print the names of the shared libraries which are currently loaded. @kindex share @item sharedlibrary @var{regex} @itemx share @var{regex} - Load shared object library symbols for files matching a Unix regular expression. As with files loaded automatically, it only loads shared libraries @@ -8178,38 +9507,37 @@ required by your program for a core file or after typing @code{run}. If loaded. @end table -@ifset HPPA -@value{GDBN} detects the loading of a shared library and automatically -reads in symbols from the newly loaded library, up to a threshold that -is initially set but that you can modify if you wish. +On some systems, such as HP-UX systems, @value{GDBN} supports +autoloading shared library symbols until a limiting threshold size is +reached. This provides the benefit of allowing autoloading to remain on +by default, but avoids autoloading excessively large shared libraries, +up to a threshold that is initially set, but which you can modify if you +wish. Beyond that threshold, symbols from shared libraries must be explicitly -loaded. To load these symbols, use the command @code{sharedlibrary} -@var{filename}. The base address of the shared library is determined +loaded. To load these symbols, use the command @code{sharedlibrary +@var{filename}}. The base address of the shared library is determined automatically by @value{GDBN} and need not be specified. To display or set the threshold, use the commands: @table @code -@kindex set auto-solib-add -@item set auto-solib-add @var{threshold} -Set the autoloading size threshold, in megabytes. If @var{threshold} is -nonzero, symbols from all shared object libraries will be loaded -automatically when the inferior begins execution or when the dynamic -linker informs @value{GDBN} that a new library has been loaded, until -the symbol table of the program and libraries exceeds this threshold. +@kindex set auto-solib-limit +@item set auto-solib-limit @var{threshold} +Set the autoloading size threshold, in an integral number of megabytes. +If @var{threshold} is nonzero and shared library autoloading is enabled, +symbols from all shared object libraries will be loaded until the total +size of the loaded shared library symbols exceeds this threshold. Otherwise, symbols must be loaded manually, using the -@code{sharedlibrary} command. The default threshold is 100 megabytes. +@code{sharedlibrary} command. The default threshold is 100 (i.e.@: 100 +Mb). -@kindex show auto-solib-add -@item show auto-solib-add +@kindex show auto-solib-limit +@item show auto-solib-limit Display the current autoloading size threshold, in megabytes. @end table -@end ifset -@end ifclear - -@node Symbol Errors, , Files, GDB Files +@node Symbol Errors @section Errors reading symbol files While reading a symbol file, @value{GDBN} occasionally encounters problems, @@ -8272,106 +9600,70 @@ with this name. @item unknown symbol type @code{0x@var{nn}} -The symbol information contains new data types that @value{GDBN} does not yet -know how to read. @code{0x@var{nn}} is the symbol type of the misunderstood -information, in hexadecimal. +The symbol information contains new data types that @value{GDBN} does +not yet know how to read. @code{0x@var{nn}} is the symbol type of the +uncomprehended information, in hexadecimal. -@value{GDBN} circumvents the error by ignoring this symbol information. This -usually allows you to debug your program, though certain symbols +@value{GDBN} circumvents the error by ignoring this symbol information. +This usually allows you to debug your program, though certain symbols are not accessible. If you encounter such a problem and feel like -debugging it, you can debug @code{@value{GDBP}} with itself, breakpoint on -@code{complain}, then go up to the function @code{read_dbx_symtab} and -examine @code{*bufp} to see the symbol. +debugging it, you can debug @code{@value{GDBP}} with itself, breakpoint +on @code{complain}, then go up to the function @code{read_dbx_symtab} +and examine @code{*bufp} to see the symbol. @item stub type has NULL name -@value{GDBN} could not find the full definition for -@ifclear CONLY -a struct or class. -@end ifclear -@ifset CONLY -a struct. -@end ifset -@ifclear CONLY -@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{} +@value{GDBN} could not find the full definition for a struct or class. -The symbol information for a C++ member function is missing some -information that recent versions of the compiler should have output -for it. -@end ifclear +@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{} +The symbol information for a C@t{++} member function is missing some +information that recent versions of the compiler should have output for +it. @item info mismatch between compiler and debugger @value{GDBN} could not parse a type specification output by the compiler. + @end table -@node Targets, Controlling GDB, GDB Files, Top +@node Targets @chapter Specifying a Debugging Target + @cindex debugging target @kindex target A @dfn{target} is the execution environment occupied by your program. -@ifclear HPPA -@ifclear BARETARGET -Often, @value{GDBN} runs in the same host environment as your program; in -that case, the debugging target is specified as a side effect when you -use the @code{file} or @code{core} commands. When you need more + +Often, @value{GDBN} runs in the same host environment as your program; +in that case, the debugging target is specified as a side effect when +you use the @code{file} or @code{core} commands. When you need more flexibility---for example, running @value{GDBN} on a physically separate host, or controlling a standalone system over a serial port or a -realtime system over a TCP/IP connection---you -@end ifclear -@end ifclear -@ifset HPPA -On HP-UX systems, @value{GDBN} has been configured to support debugging -of processes running on the PA-RISC architecture. This means that the -only possible targets are: - -@itemize @bullet -@item -An executable that has been compiled and linked to run on HP-UX - -@item -A live HP-UX process, either started by @value{GDBN} (with the -@code{run} command) or started outside of @value{GDBN} and attached to -(with the @code{attach} command) - -@item -A core file generated by an HP-UX process that previously aborted -execution -@end itemize - -@value{GDBN} on HP-UX has not been configured to support remote -debugging, or to support programs running on other platforms. You -@end ifset -@ifset BARETARGET -You -@end ifset -can use the @code{target} command to specify one of the target types -configured for @value{GDBN} (@pxref{Target Commands, ,Commands for managing -targets}). +realtime system over a TCP/IP connection---you can use the @code{target} +command to specify one of the target types configured for @value{GDBN} +(@pxref{Target Commands, ,Commands for managing targets}). @menu * Active Targets:: Active targets * Target Commands:: Commands for managing targets -@ifset REMOTESTUB * Byte Order:: Choosing target byte order * Remote:: Remote debugging -@end ifset +* KOD:: Kernel Object Display @end menu -@node Active Targets, Target Commands, Targets, Targets +@node Active Targets @section Active targets + @cindex stacking targets @cindex active targets @cindex multiple targets -@ifclear BARETARGET There are three classes of targets: processes, core files, and -executable files. @value{GDBN} can work concurrently on up to three active -targets, one in each class. This allows you to (for example) start a -process and inspect its activity without abandoning your work on a core -file. +executable files. @value{GDBN} can work concurrently on up to three +active targets, one in each class. This allows you to (for example) +start a process and inspect its activity without abandoning your work on +a core file. For example, if you execute @samp{gdb a.out}, then the executable file @code{a.out} is the only active target. If you designate a core file as @@ -8382,48 +9674,32 @@ requests for memory addresses. (Typically, these two classes of target are complementary, since core files contain only a program's read-write memory---variables and so on---plus machine status, while executable files contain only the program text and initialized data.) -@end ifclear When you type @code{run}, your executable file becomes an active process -target as well. When a process target is active, all @value{GDBN} commands -requesting memory addresses refer to that target; addresses in an -@ifclear BARETARGET -active core file or -@end ifclear -executable file target are obscured while the process -target is active. - -@ifset BARETARGET -Use the @code{exec-file} command to select a -new executable target (@pxref{Files, ,Commands to specify -files}). -@end ifset -@ifclear BARETARGET -Use the @code{core-file} and @code{exec-file} commands to select a -new core file or executable target (@pxref{Files, ,Commands to specify +target as well. When a process target is active, all @value{GDBN} +commands requesting memory addresses refer to that target; addresses in +an active core file or executable file target are obscured while the +process target is active. + +Use the @code{core-file} and @code{exec-file} commands to select a new +core file or executable target (@pxref{Files, ,Commands to specify files}). To specify as a target a process that is already running, use -the @code{attach} command (@pxref{Attach, ,Debugging an -already-running process}). -@end ifclear +the @code{attach} command (@pxref{Attach, ,Debugging an already-running +process}). -@node Target Commands, Byte Order, Active Targets, Targets +@node Target Commands @section Commands for managing targets @table @code @item target @var{type} @var{parameters} -Connects the @value{GDBN} host environment to a target -@ifset BARETARGET -machine. -@end ifset -@ifclear BARETARGET -machine or process. A target is typically a protocol for talking to -debugging facilities. You use the argument @var{type} to specify the -type or protocol of the target machine. +Connects the @value{GDBN} host environment to a target machine or +process. A target is typically a protocol for talking to debugging +facilities. You use the argument @var{type} to specify the type or +protocol of the target machine. Further @var{parameters} are interpreted by the target protocol, but typically include things like device names or host names to connect with, process numbers, and baud rates. -@end ifclear The @code{target} command does not repeat if you press @key{RET} again after executing the command. @@ -8440,18 +9716,21 @@ select it. @kindex set gnutarget @item set gnutarget @var{args} -@value{GDBN} uses its own library BFD to read your files. @value{GDBN} +@value{GDBN} uses its own library BFD to read your files. @value{GDBN} knows whether it is reading an @dfn{executable}, -a @dfn{core}, or a @dfn{.o} file; however, you can specify the file format -with the @code{set gnutarget} command. Unlike most @code{target} commands, +a @dfn{core}, or a @dfn{.o} file; however, you can specify the file format +with the @code{set gnutarget} command. Unlike most @code{target} commands, with @code{gnutarget} the @code{target} refers to a program, not a machine. +@quotation @emph{Warning:} To specify a file format with @code{set gnutarget}, you must know the actual BFD name. +@end quotation -@noindent @xref{Files, , Commands to specify files}. +@noindent +@xref{Files, , Commands to specify files}. -@kindex show gnutarget +@kindex show gnutarget @item show gnutarget Use the @code{show gnutarget} command to display what file format @code{gnutarget} is set to read. If you have not set @code{gnutarget}, @@ -8459,13 +9738,8 @@ Use the @code{show gnutarget} command to display what file format and @code{show gnutarget} displays @samp{The current BDF target is "auto"}. @end table -@ifclear HPPA Here are some common targets (available, or not, depending on the GDB configuration): -@end ifclear -@ifset HPPA -These are the valid targets on HP-UX systems: -@end ifset @table @code @kindex target exec @@ -8473,204 +9747,50 @@ These are the valid targets on HP-UX systems: An executable file. @samp{target exec @var{program}} is the same as @samp{exec-file @var{program}}. -@ifclear BARETARGET @kindex target core @item target core @var{filename} A core dump file. @samp{target core @var{filename}} is the same as @samp{core-file @var{filename}}. -@end ifclear @kindex target remote @item target remote @var{dev} Remote serial target in GDB-specific protocol. The argument @var{dev} specifies what serial device to use for the connection (e.g. @file{/dev/ttya}). @xref{Remote, ,Remote debugging}. @code{target remote} -now supports the @code{load} command. This is only useful if you have +supports the @code{load} command. This is only useful if you have some other way of getting the stub to the target system, and you can put it somewhere in memory where it won't get clobbered by the download. -@ifclear HPPA @kindex target sim @item target sim -CPU simulator. @xref{Simulator,,Simulated CPU Target}. -@end ifclear +Builtin CPU simulator. @value{GDBN} includes simulators for most architectures. +In general, +@example + target sim + load + run +@end example +@noindent +works; however, you cannot assume that a specific memory map, device +drivers, or even basic I/O is available, although some simulators do +provide these. For info about any processor-specific simulator details, +see the appropriate section in @ref{Embedded Processors, ,Embedded +Processors}. + @end table -The following targets are all CPU-specific, and only available for -specific configurations. -@c should organize by CPU +Some configurations may include these targets as well: @table @code -@kindex target abug -@item target abug @var{dev} -ABug ROM monitor for M68K. - -@kindex target adapt -@item target adapt @var{dev} -Adapt monitor for A29K. - -@kindex target amd-eb -@item target amd-eb @var{dev} @var{speed} @var{PROG} -@cindex AMD EB29K -Remote PC-resident AMD EB29K board, attached over serial lines. -@var{dev} is the serial device, as for @code{target remote}; -@var{speed} allows you to specify the linespeed; and @var{PROG} is the -name of the program to be debugged, as it appears to DOS on the PC. -@xref{EB29K Remote, ,The EBMON protocol for AMD29K}. - -@kindex target array -@item target array @var{dev} -Array Tech LSI33K RAID controller board. - -@kindex target bug -@item target bug @var{dev} -BUG monitor, running on a MVME187 (m88k) board. - -@kindex target cpu32bug -@item target cpu32bug @var{dev} -CPU32BUG monitor, running on a CPU32 (M68K) board. - -@kindex target dbug -@item target dbug @var{dev} -dBUG ROM monitor for Motorola ColdFire. - -@kindex target ddb -@item target ddb @var{dev} -NEC's DDB monitor for Mips Vr4300. - -@kindex target dink32 -@item target dink32 @var{dev} -DINK32 ROM monitor for PowerPC. - -@kindex target e7000 -@item target e7000 @var{dev} -E7000 emulator for Hitachi H8 and SH. - -@kindex target es1800 -@item target es1800 @var{dev} -ES-1800 emulator for M68K. - -@kindex target est -@item target est @var{dev} -EST-300 ICE monitor, running on a CPU32 (M68K) board. - -@kindex target hms -@item target hms @var{dev} -A Hitachi SH, H8/300, or H8/500 board, attached via serial line to your host. -@ifclear H8EXCLUSIVE -Use special commands @code{device} and @code{speed} to control the serial -line and the communications speed used. -@xref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}. - -@kindex target lsi -@item target lsi @var{dev} -LSI ROM monitor for Mips. - -@kindex target m32r -@item target m32r @var{dev} -Mitsubishi M32R/D ROM monitor. - -@kindex target mips -@item target mips @var{dev} -IDT/SIM ROM monitor for Mips. - -@kindex target mon960 -@item target mon960 @var{dev} -MON960 monitor for Intel i960. - -@kindex target nindy -@item target nindy @var{devicename} -An Intel 960 board controlled by a Nindy Monitor. @var{devicename} is -the name of the serial device to use for the connection, e.g. -@file{/dev/ttya}. @xref{i960-Nindy Remote, ,@value{GDBN} with a remote i960 (Nindy)}. - @kindex target nrom @item target nrom @var{dev} NetROM ROM emulator. This target only supports downloading. -@kindex target op50n -@item target op50n @var{dev} -OP50N monitor, running on an OKI HPPA board. - -@kindex target pmon -@item target pmon @var{dev} -PMON ROM monitor for Mips. - -@kindex target ppcbug -@item target ppcbug @var{dev} -@kindex target ppcbug1 -@item target ppcbug1 @var{dev} -PPCBUG ROM monitor for PowerPC. - -@kindex target r3900 -@item target r3900 @var{dev} -Densan DVE-R3900 ROM monitor for Toshiba R3900 Mips. - -@kindex target rdi -@item target rdi @var{dev} -ARM Angel monitor, via RDI library interface. - -@kindex target rdp -@item target rdp @var{dev} -ARM Demon monitor. - -@kindex target rom68k -@item target rom68k @var{dev} -ROM 68K monitor, running on an M68K IDP board. - -@kindex target rombug -@item target rombug @var{dev} -ROMBUG ROM monitor for OS/9000. - -@kindex target sds -@item target sds @var{dev} -SDS monitor, running on a PowerPC board (such as Motorola's ADS). - -@kindex target sparclite -@item target sparclite @var{dev} -Fujitsu sparclite boards, used only for the purpose of loading. -You must use an additional command to debug the program. -For example: target remote @var{dev} using @value{GDBN} standard -remote protocol. - -@kindex target sh3 -@kindex target sh3e -@item target sh3 @var{dev} -@item target sh3e @var{dev} -Hitachi SH-3 and SH-3E target systems. - -@kindex target st2000 -@item target st2000 @var{dev} @var{speed} -A Tandem ST2000 phone switch, running Tandem's STDBUG protocol. @var{dev} -is the name of the device attached to the ST2000 serial line; -@var{speed} is the communication line speed. The arguments are not used -if @value{GDBN} is configured to connect to the ST2000 using TCP or Telnet. -@xref{ST2000 Remote,,@value{GDBN} with a Tandem ST2000}. - -@kindex target udi -@item target udi @var{keyword} -Remote AMD29K target, using the AMD UDI protocol. The @var{keyword} -argument specifies which 29K board or simulator to use. @xref{UDI29K -Remote,,The UDI protocol for AMD29K}. - -@kindex target vxworks -@item target vxworks @var{machinename} -A VxWorks system, attached via TCP/IP. The argument @var{machinename} -is the target system's machine name or IP address. -@xref{VxWorks Remote, ,@value{GDBN} and VxWorks}. - -@kindex target w89k -@item target w89k @var{dev} -W89K monitor, running on a Winbond HPPA board. - -@end ifclear @end table -@ifset GENERIC -Different targets are available on different configurations of @value{GDBN}; +Different targets are available on different configurations of @value{GDBN}; your configuration may have more or fewer targets. -@end ifset Many remote targets require you to download the executable's code once you've successfully established a connection. @@ -8679,7 +9799,6 @@ once you've successfully established a connection. @kindex load @var{filename} @item load @var{filename} -@ifset GENERIC Depending on what remote debugging facilities are configured into @value{GDBN}, the @code{load} command may be available. Where it exists, it is meant to make @var{filename} (an executable) available for debugging @@ -8690,7 +9809,6 @@ the @code{add-symbol-file} command. If your @value{GDBN} does not have a @code{load} command, attempting to execute it gets the error message ``@code{You can't do that when your target is @dots{}}'' -@end ifset The file is loaded at whatever address is specified in the executable. For some object file formats, you can specify the load address when you @@ -8698,49 +9816,21 @@ link the program; for other formats, like a.out, the object file format specifies a fixed address. @c FIXME! This would be a good place for an xref to the GNU linker doc. -@ifset VXWORKS -On VxWorks, @code{load} links @var{filename} dynamically on the -current target system as well as adding its symbols in @value{GDBN}. -@end ifset - -@ifset I960 -@cindex download to Nindy-960 -With the Nindy interface to an Intel 960 board, @code{load} -downloads @var{filename} to the 960 as well as adding its symbols in -@value{GDBN}. -@end ifset - -@ifset H8 -@cindex download to H8/300 or H8/500 -@cindex H8/300 or H8/500 download -@cindex download to Hitachi SH -@cindex Hitachi SH download -When you select remote debugging to a Hitachi SH, H8/300, or H8/500 board -(@pxref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}), -the @code{load} command downloads your program to the Hitachi board and also -opens it as the current executable target for @value{GDBN} on your host -(like the @code{file} command). -@end ifset - @code{load} does not repeat if you press @key{RET} again after using it. @end table -@ifset REMOTESTUB -@node Byte Order, Remote, Target Commands, Targets +@node Byte Order @section Choosing target byte order + @cindex choosing target byte order @cindex target byte order -@kindex set endian big -@kindex set endian little -@kindex set endian auto -@kindex show endian Some types of processors, such as the MIPS, PowerPC, and Hitachi SH, offer the ability to run either big-endian or little-endian byte orders. Usually the executable or symbol will include a bit to designate the endian-ness, and you will not need to worry about which to use. However, you may still find it useful to adjust -GDB's idea of processor endian-ness manually. +@value{GDBN}'s idea of processor endian-ness manually. @table @code @kindex set endian big @@ -8765,72 +9855,2358 @@ Note that these commands merely adjust interpretation of symbolic data on the host, and that they have absolutely no effect on the target system. -@node Remote, , Byte Order, Targets +@node Remote @section Remote debugging @cindex remote debugging If you are trying to debug a program running on a machine that cannot run -@value{GDBN} in the usual way, it is often useful to use remote debugging. -For example, you might use remote debugging on an operating system kernel, +@value{GDBN} in the usual way, it is often useful to use remote debugging. +For example, you might use remote debugging on an operating system kernel, or on a small system which does not have a general purpose operating system powerful enough to run a full-featured debugger. Some configurations of @value{GDBN} have special serial or TCP/IP interfaces to make this work with particular debugging targets. In addition, -@value{GDBN} comes with a generic serial protocol (specific to @value{GDBN}, +@value{GDBN} comes with a generic serial protocol (specific to @value{GDBN}, but not specific to any particular target system) which you can use if you write the remote stubs---the code that runs on the remote system to communicate with @value{GDBN}. Other remote targets may be available in your configuration of @value{GDBN}; use @code{help target} to list them. -@end ifset -@ifset GENERIC -@c Text on starting up GDB in various specific cases; it goes up front -@c in manuals configured for any of those particular situations, here -@c otherwise. +@node KOD +@section Kernel Object Display + +@cindex kernel object display +@cindex kernel object +@cindex KOD + +Some targets support kernel object display. Using this facility, +@value{GDBN} communicates specially with the underlying operating system +and can display information about operating system-level objects such as +mutexes and other synchronization objects. Exactly which objects can be +displayed is determined on a per-OS basis. + +Use the @code{set os} command to set the operating system. This tells +@value{GDBN} which kernel object display module to initialize: + +@example +(@value{GDBP}) set os cisco +@end example + +If @code{set os} succeeds, @value{GDBN} will display some information +about the operating system, and will create a new @code{info} command +which can be used to query the target. The @code{info} command is named +after the operating system: + +@example +(@value{GDBP}) info cisco +List of Cisco Kernel Objects +Object Description +any Any and all objects +@end example + +Further subcommands can be used to query about particular objects known +by the kernel. + +There is currently no way to determine whether a given operating system +is supported other than to try it. + + +@node Remote Debugging +@chapter Debugging remote programs + @menu -@ifset REMOTESTUB -* Remote Serial:: @value{GDBN} remote serial protocol -@end ifset -@ifset I960 -* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) -@end ifset -@ifset AMD29K -* UDI29K Remote:: The UDI protocol for AMD29K -* EB29K Remote:: The EBMON protocol for AMD29K -@end ifset -@ifset VXWORKS -* VxWorks Remote:: @value{GDBN} and VxWorks -@end ifset -@ifset ST2000 -* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 -@end ifset -@ifset H8 -* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors -@end ifset -@ifset MIPS -* MIPS Remote:: @value{GDBN} and MIPS boards -@end ifset -@ifset SPARCLET -* Sparclet Remote:: @value{GDBN} and Sparclet boards -@end ifset -@ifset SIMS -* Simulator:: Simulated CPU target -@end ifset +* Server:: Using the gdbserver program +* NetWare:: Using the gdbserve.nlm program +* remote stub:: Implementing a remote stub @end menu -@include remote.texi -@end ifset +@node Server +@section Using the @code{gdbserver} program + +@kindex gdbserver +@cindex remote connection without stubs +@code{gdbserver} is a control program for Unix-like systems, which +allows you to connect your program with a remote @value{GDBN} via +@code{target remote}---but without linking in the usual debugging stub. + +@code{gdbserver} is not a complete replacement for the debugging stubs, +because it requires essentially the same operating-system facilities +that @value{GDBN} itself does. In fact, a system that can run +@code{gdbserver} to connect to a remote @value{GDBN} could also run +@value{GDBN} locally! @code{gdbserver} is sometimes useful nevertheless, +because it is a much smaller program than @value{GDBN} itself. It is +also easier to port than all of @value{GDBN}, so you may be able to get +started more quickly on a new system by using @code{gdbserver}. +Finally, if you develop code for real-time systems, you may find that +the tradeoffs involved in real-time operation make it more convenient to +do as much development work as possible on another system, for example +by cross-compiling. You can use @code{gdbserver} to make a similar +choice for debugging. + +@value{GDBN} and @code{gdbserver} communicate via either a serial line +or a TCP connection, using the standard @value{GDBN} remote serial +protocol. + +@table @emph +@item On the target machine, +you need to have a copy of the program you want to debug. +@code{gdbserver} does not need your program's symbol table, so you can +strip the program if necessary to save space. @value{GDBN} on the host +system does all the symbol handling. + +To use the server, you must tell it how to communicate with @value{GDBN}; +the name of your program; and the arguments for your program. The usual +syntax is: + +@smallexample +target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ] +@end smallexample + +@var{comm} is either a device name (to use a serial line) or a TCP +hostname and portnumber. For example, to debug Emacs with the argument +@samp{foo.txt} and communicate with @value{GDBN} over the serial port +@file{/dev/com1}: + +@smallexample +target> gdbserver /dev/com1 emacs foo.txt +@end smallexample + +@code{gdbserver} waits passively for the host @value{GDBN} to communicate +with it. + +To use a TCP connection instead of a serial line: + +@smallexample +target> gdbserver host:2345 emacs foo.txt +@end smallexample + +The only difference from the previous example is the first argument, +specifying that you are communicating with the host @value{GDBN} via +TCP. The @samp{host:2345} argument means that @code{gdbserver} is to +expect a TCP connection from machine @samp{host} to local TCP port 2345. +(Currently, the @samp{host} part is ignored.) You can choose any number +you want for the port number as long as it does not conflict with any +TCP ports already in use on the target system (for example, @code{23} is +reserved for @code{telnet}).@footnote{If you choose a port number that +conflicts with another service, @code{gdbserver} prints an error message +and exits.} You must use the same port number with the host @value{GDBN} +@code{target remote} command. + +On some targets, @code{gdbserver} can also attach to running programs. +This is accomplished via the @code{--attach} argument. The syntax is: + +@smallexample +target> gdbserver @var{comm} --attach @var{pid} +@end smallexample + +@var{pid} is the process ID of a currently running process. It isn't necessary +to point @code{gdbserver} at a binary for the running process. + +@item On the @value{GDBN} host machine, +you need an unstripped copy of your program, since @value{GDBN} needs +symbols and debugging information. Start up @value{GDBN} as usual, +using the name of the local copy of your program as the first argument. +(You may also need the @w{@samp{--baud}} option if the serial line is +running at anything other than 9600@dmn{bps}.) After that, use @code{target +remote} to establish communications with @code{gdbserver}. Its argument +is either a device name (usually a serial device, like +@file{/dev/ttyb}), or a TCP port descriptor in the form +@code{@var{host}:@var{PORT}}. For example: + +@smallexample +(@value{GDBP}) target remote /dev/ttyb +@end smallexample + +@noindent +communicates with the server via serial line @file{/dev/ttyb}, and + +@smallexample +(@value{GDBP}) target remote the-target:2345 +@end smallexample + +@noindent +communicates via a TCP connection to port 2345 on host @w{@file{the-target}}. +For TCP connections, you must start up @code{gdbserver} prior to using +the @code{target remote} command. Otherwise you may get an error whose +text depends on the host system, but which usually looks something like +@samp{Connection refused}. +@end table + +@node NetWare +@section Using the @code{gdbserve.nlm} program + +@kindex gdbserve.nlm +@code{gdbserve.nlm} is a control program for NetWare systems, which +allows you to connect your program with a remote @value{GDBN} via +@code{target remote}. + +@value{GDBN} and @code{gdbserve.nlm} communicate via a serial line, +using the standard @value{GDBN} remote serial protocol. + +@table @emph +@item On the target machine, +you need to have a copy of the program you want to debug. +@code{gdbserve.nlm} does not need your program's symbol table, so you +can strip the program if necessary to save space. @value{GDBN} on the +host system does all the symbol handling. + +To use the server, you must tell it how to communicate with +@value{GDBN}; the name of your program; and the arguments for your +program. The syntax is: + +@smallexample +load gdbserve [ BOARD=@var{board} ] [ PORT=@var{port} ] + [ BAUD=@var{baud} ] @var{program} [ @var{args} @dots{} ] +@end smallexample + +@var{board} and @var{port} specify the serial line; @var{baud} specifies +the baud rate used by the connection. @var{port} and @var{node} default +to 0, @var{baud} defaults to 9600@dmn{bps}. + +For example, to debug Emacs with the argument @samp{foo.txt}and +communicate with @value{GDBN} over serial port number 2 or board 1 +using a 19200@dmn{bps} connection: + +@smallexample +load gdbserve BOARD=1 PORT=2 BAUD=19200 emacs foo.txt +@end smallexample + +@item On the @value{GDBN} host machine, +you need an unstripped copy of your program, since @value{GDBN} needs +symbols and debugging information. Start up @value{GDBN} as usual, +using the name of the local copy of your program as the first argument. +(You may also need the @w{@samp{--baud}} option if the serial line is +running at anything other than 9600@dmn{bps}. After that, use @code{target +remote} to establish communications with @code{gdbserve.nlm}. Its +argument is a device name (usually a serial device, like +@file{/dev/ttyb}). For example: + +@smallexample +(@value{GDBP}) target remote /dev/ttyb +@end smallexample + +@noindent +communications with the server via serial line @file{/dev/ttyb}. +@end table + +@node remote stub +@section Implementing a remote stub + +@cindex debugging stub, example +@cindex remote stub, example +@cindex stub example, remote debugging +The stub files provided with @value{GDBN} implement the target side of the +communication protocol, and the @value{GDBN} side is implemented in the +@value{GDBN} source file @file{remote.c}. Normally, you can simply allow +these subroutines to communicate, and ignore the details. (If you're +implementing your own stub file, you can still ignore the details: start +with one of the existing stub files. @file{sparc-stub.c} is the best +organized, and therefore the easiest to read.) + +@cindex remote serial debugging, overview +To debug a program running on another machine (the debugging +@dfn{target} machine), you must first arrange for all the usual +prerequisites for the program to run by itself. For example, for a C +program, you need: + +@enumerate +@item +A startup routine to set up the C runtime environment; these usually +have a name like @file{crt0}. The startup routine may be supplied by +your hardware supplier, or you may have to write your own. + +@item +A C subroutine library to support your program's +subroutine calls, notably managing input and output. + +@item +A way of getting your program to the other machine---for example, a +download program. These are often supplied by the hardware +manufacturer, but you may have to write your own from hardware +documentation. +@end enumerate + +The next step is to arrange for your program to use a serial port to +communicate with the machine where @value{GDBN} is running (the @dfn{host} +machine). In general terms, the scheme looks like this: + +@table @emph +@item On the host, +@value{GDBN} already understands how to use this protocol; when everything +else is set up, you can simply use the @samp{target remote} command +(@pxref{Targets,,Specifying a Debugging Target}). + +@item On the target, +you must link with your program a few special-purpose subroutines that +implement the @value{GDBN} remote serial protocol. The file containing these +subroutines is called a @dfn{debugging stub}. + +On certain remote targets, you can use an auxiliary program +@code{gdbserver} instead of linking a stub into your program. +@xref{Server,,Using the @code{gdbserver} program}, for details. +@end table + +The debugging stub is specific to the architecture of the remote +machine; for example, use @file{sparc-stub.c} to debug programs on +@sc{sparc} boards. + +@cindex remote serial stub list +These working remote stubs are distributed with @value{GDBN}: + +@table @code + +@item i386-stub.c +@cindex @file{i386-stub.c} +@cindex Intel +@cindex i386 +For Intel 386 and compatible architectures. + +@item m68k-stub.c +@cindex @file{m68k-stub.c} +@cindex Motorola 680x0 +@cindex m680x0 +For Motorola 680x0 architectures. + +@item sh-stub.c +@cindex @file{sh-stub.c} +@cindex Hitachi +@cindex SH +For Hitachi SH architectures. + +@item sparc-stub.c +@cindex @file{sparc-stub.c} +@cindex Sparc +For @sc{sparc} architectures. + +@item sparcl-stub.c +@cindex @file{sparcl-stub.c} +@cindex Fujitsu +@cindex SparcLite +For Fujitsu @sc{sparclite} architectures. + +@end table + +The @file{README} file in the @value{GDBN} distribution may list other +recently added stubs. + +@menu +* Stub Contents:: What the stub can do for you +* Bootstrapping:: What you must do for the stub +* Debug Session:: Putting it all together +@end menu + +@node Stub Contents +@subsection What the stub can do for you + +@cindex remote serial stub +The debugging stub for your architecture supplies these three +subroutines: + +@table @code +@item set_debug_traps +@kindex set_debug_traps +@cindex remote serial stub, initialization +This routine arranges for @code{handle_exception} to run when your +program stops. You must call this subroutine explicitly near the +beginning of your program. + +@item handle_exception +@kindex handle_exception +@cindex remote serial stub, main routine +This is the central workhorse, but your program never calls it +explicitly---the setup code arranges for @code{handle_exception} to +run when a trap is triggered. + +@code{handle_exception} takes control when your program stops during +execution (for example, on a breakpoint), and mediates communications +with @value{GDBN} on the host machine. This is where the communications +protocol is implemented; @code{handle_exception} acts as the @value{GDBN} +representative on the target machine. It begins by sending summary +information on the state of your program, then continues to execute, +retrieving and transmitting any information @value{GDBN} needs, until you +execute a @value{GDBN} command that makes your program resume; at that point, +@code{handle_exception} returns control to your own code on the target +machine. + +@item breakpoint +@cindex @code{breakpoint} subroutine, remote +Use this auxiliary subroutine to make your program contain a +breakpoint. Depending on the particular situation, this may be the only +way for @value{GDBN} to get control. For instance, if your target +machine has some sort of interrupt button, you won't need to call this; +pressing the interrupt button transfers control to +@code{handle_exception}---in effect, to @value{GDBN}. On some machines, +simply receiving characters on the serial port may also trigger a trap; +again, in that situation, you don't need to call @code{breakpoint} from +your own program---simply running @samp{target remote} from the host +@value{GDBN} session gets control. + +Call @code{breakpoint} if none of these is true, or if you simply want +to make certain your program stops at a predetermined point for the +start of your debugging session. +@end table + +@node Bootstrapping +@subsection What you must do for the stub + +@cindex remote stub, support routines +The debugging stubs that come with @value{GDBN} are set up for a particular +chip architecture, but they have no information about the rest of your +debugging target machine. + +First of all you need to tell the stub how to communicate with the +serial port. + +@table @code +@item int getDebugChar() +@kindex getDebugChar +Write this subroutine to read a single character from the serial port. +It may be identical to @code{getchar} for your target system; a +different name is used to allow you to distinguish the two if you wish. + +@item void putDebugChar(int) +@kindex putDebugChar +Write this subroutine to write a single character to the serial port. +It may be identical to @code{putchar} for your target system; a +different name is used to allow you to distinguish the two if you wish. +@end table + +@cindex control C, and remote debugging +@cindex interrupting remote targets +If you want @value{GDBN} to be able to stop your program while it is +running, you need to use an interrupt-driven serial driver, and arrange +for it to stop when it receives a @code{^C} (@samp{\003}, the control-C +character). That is the character which @value{GDBN} uses to tell the +remote system to stop. + +Getting the debugging target to return the proper status to @value{GDBN} +probably requires changes to the standard stub; one quick and dirty way +is to just execute a breakpoint instruction (the ``dirty'' part is that +@value{GDBN} reports a @code{SIGTRAP} instead of a @code{SIGINT}). + +Other routines you need to supply are: + +@table @code +@item void exceptionHandler (int @var{exception_number}, void *@var{exception_address}) +@kindex exceptionHandler +Write this function to install @var{exception_address} in the exception +handling tables. You need to do this because the stub does not have any +way of knowing what the exception handling tables on your target system +are like (for example, the processor's table might be in @sc{rom}, +containing entries which point to a table in @sc{ram}). +@var{exception_number} is the exception number which should be changed; +its meaning is architecture-dependent (for example, different numbers +might represent divide by zero, misaligned access, etc). When this +exception occurs, control should be transferred directly to +@var{exception_address}, and the processor state (stack, registers, +and so on) should be just as it is when a processor exception occurs. So if +you want to use a jump instruction to reach @var{exception_address}, it +should be a simple jump, not a jump to subroutine. + +For the 386, @var{exception_address} should be installed as an interrupt +gate so that interrupts are masked while the handler runs. The gate +should be at privilege level 0 (the most privileged level). The +@sc{sparc} and 68k stubs are able to mask interrupts themselves without +help from @code{exceptionHandler}. + +@item void flush_i_cache() +@kindex flush_i_cache +On @sc{sparc} and @sc{sparclite} only, write this subroutine to flush the +instruction cache, if any, on your target machine. If there is no +instruction cache, this subroutine may be a no-op. + +On target machines that have instruction caches, @value{GDBN} requires this +function to make certain that the state of your program is stable. +@end table + +@noindent +You must also make sure this library routine is available: + +@table @code +@item void *memset(void *, int, int) +@kindex memset +This is the standard library function @code{memset} that sets an area of +memory to a known value. If you have one of the free versions of +@code{libc.a}, @code{memset} can be found there; otherwise, you must +either obtain it from your hardware manufacturer, or write your own. +@end table + +If you do not use the GNU C compiler, you may need other standard +library subroutines as well; this varies from one stub to another, +but in general the stubs are likely to use any of the common library +subroutines which @code{@value{GCC}} generates as inline code. + + +@node Debug Session +@subsection Putting it all together + +@cindex remote serial debugging summary +In summary, when your program is ready to debug, you must follow these +steps. + +@enumerate +@item +Make sure you have defined the supporting low-level routines +(@pxref{Bootstrapping,,What you must do for the stub}): +@display +@code{getDebugChar}, @code{putDebugChar}, +@code{flush_i_cache}, @code{memset}, @code{exceptionHandler}. +@end display + +@item +Insert these lines near the top of your program: + +@example +set_debug_traps(); +breakpoint(); +@end example + +@item +For the 680x0 stub only, you need to provide a variable called +@code{exceptionHook}. Normally you just use: + +@example +void (*exceptionHook)() = 0; +@end example + +@noindent +but if before calling @code{set_debug_traps}, you set it to point to a +function in your program, that function is called when +@code{@value{GDBN}} continues after stopping on a trap (for example, bus +error). The function indicated by @code{exceptionHook} is called with +one parameter: an @code{int} which is the exception number. + +@item +Compile and link together: your program, the @value{GDBN} debugging stub for +your target architecture, and the supporting subroutines. + +@item +Make sure you have a serial connection between your target machine and +the @value{GDBN} host, and identify the serial port on the host. + +@item +@c The "remote" target now provides a `load' command, so we should +@c document that. FIXME. +Download your program to your target machine (or get it there by +whatever means the manufacturer provides), and start it. + +@item +To start remote debugging, run @value{GDBN} on the host machine, and specify +as an executable file the program that is running in the remote machine. +This tells @value{GDBN} how to find your program's symbols and the contents +of its pure text. + +@item +@cindex serial line, @code{target remote} +Establish communication using the @code{target remote} command. +Its argument specifies how to communicate with the target +machine---either via a devicename attached to a direct serial line, or a +TCP port (usually to a terminal server which in turn has a serial line +to the target). For example, to use a serial line connected to the +device named @file{/dev/ttyb}: + +@example +target remote /dev/ttyb +@end example + +@cindex TCP port, @code{target remote} +To use a TCP connection, use an argument of the form +@code{@var{host}:port}. For example, to connect to port 2828 on a +terminal server named @code{manyfarms}: + +@example +target remote manyfarms:2828 +@end example + +If your remote target is actually running on the same machine as +your debugger session (e.g.@: a simulator of your target running on +the same host), you can omit the hostname. For example, to connect +to port 1234 on your local machine: + +@example +target remote :1234 +@end example +@noindent + +Note that the colon is still required here. +@end enumerate + +Now you can use all the usual commands to examine and change data and to +step and continue the remote program. + +To resume the remote program and stop debugging it, use the @code{detach} +command. + +@cindex interrupting remote programs +@cindex remote programs, interrupting +Whenever @value{GDBN} is waiting for the remote program, if you type the +interrupt character (often @key{C-C}), @value{GDBN} attempts to stop the +program. This may or may not succeed, depending in part on the hardware +and the serial drivers the remote system uses. If you type the +interrupt character once again, @value{GDBN} displays this prompt: + +@example +Interrupted while waiting for the program. +Give up (and stop debugging it)? (y or n) +@end example + +If you type @kbd{y}, @value{GDBN} abandons the remote debugging session. +(If you decide you want to try again later, you can use @samp{target +remote} again to connect once more.) If you type @kbd{n}, @value{GDBN} +goes back to waiting. + + +@node Configurations +@chapter Configuration-Specific Information + +While nearly all @value{GDBN} commands are available for all native and +cross versions of the debugger, there are some exceptions. This chapter +describes things that are only available in certain configurations. + +There are three major categories of configurations: native +configurations, where the host and target are the same, embedded +operating system configurations, which are usually the same for several +different processor architectures, and bare embedded processors, which +are quite different from each other. + +@menu +* Native:: +* Embedded OS:: +* Embedded Processors:: +* Architectures:: +@end menu + +@node Native +@section Native + +This section describes details specific to particular native +configurations. + +@menu +* HP-UX:: HP-UX +* SVR4 Process Information:: SVR4 process information +* DJGPP Native:: Features specific to the DJGPP port +* Cygwin Native:: Features specific to the Cygwin port +@end menu + +@node HP-UX +@subsection HP-UX + +On HP-UX systems, if you refer to a function or variable name that +begins with a dollar sign, @value{GDBN} searches for a user or system +name first, before it searches for a convenience variable. + +@node SVR4 Process Information +@subsection SVR4 process information + +@kindex /proc +@cindex process image + +Many versions of SVR4 provide a facility called @samp{/proc} that can be +used to examine the image of a running process using file-system +subroutines. If @value{GDBN} is configured for an operating system with +this facility, the command @code{info proc} is available to report on +several kinds of information about the process running your program. +@code{info proc} works only on SVR4 systems that include the +@code{procfs} code. This includes OSF/1 (Digital Unix), Solaris, Irix, +and Unixware, but not HP-UX or Linux, for example. + +@table @code +@kindex info proc +@item info proc +Summarize available information about the process. + +@kindex info proc mappings +@item info proc mappings +Report on the address ranges accessible in the program, with information +on whether your program may read, write, or execute each range. +@ignore +@comment These sub-options of 'info proc' were not included when +@comment procfs.c was re-written. Keep their descriptions around +@comment against the day when someone finds the time to put them back in. +@kindex info proc times +@item info proc times +Starting time, user CPU time, and system CPU time for your program and +its children. + +@kindex info proc id +@item info proc id +Report on the process IDs related to your program: its own process ID, +the ID of its parent, the process group ID, and the session ID. + +@kindex info proc status +@item info proc status +General information on the state of the process. If the process is +stopped, this report includes the reason for stopping, and any signal +received. + +@item info proc all +Show all the above information about the process. +@end ignore +@end table + +@node DJGPP Native +@subsection Features for Debugging @sc{djgpp} Programs +@cindex @sc{djgpp} debugging +@cindex native @sc{djgpp} debugging +@cindex MS-DOS-specific commands + +@sc{djgpp} is the port of @sc{gnu} development tools to MS-DOS and +MS-Windows. @sc{djgpp} programs are 32-bit protected-mode programs +that use the @dfn{DPMI} (DOS Protected-Mode Interface) API to run on +top of real-mode DOS systems and their emulations. + +@value{GDBN} supports native debugging of @sc{djgpp} programs, and +defines a few commands specific to the @sc{djgpp} port. This +subsection describes those commands. + +@table @code +@kindex info dos +@item info dos +This is a prefix of @sc{djgpp}-specific commands which print +information about the target system and important OS structures. + +@kindex sysinfo +@cindex MS-DOS system info +@cindex free memory information (MS-DOS) +@item info dos sysinfo +This command displays assorted information about the underlying +platform: the CPU type and features, the OS version and flavor, the +DPMI version, and the available conventional and DPMI memory. + +@cindex GDT +@cindex LDT +@cindex IDT +@cindex segment descriptor tables +@cindex descriptor tables display +@item info dos gdt +@itemx info dos ldt +@itemx info dos idt +These 3 commands display entries from, respectively, Global, Local, +and Interrupt Descriptor Tables (GDT, LDT, and IDT). The descriptor +tables are data structures which store a descriptor for each segment +that is currently in use. The segment's selector is an index into a +descriptor table; the table entry for that index holds the +descriptor's base address and limit, and its attributes and access +rights. + +A typical @sc{djgpp} program uses 3 segments: a code segment, a data +segment (used for both data and the stack), and a DOS segment (which +allows access to DOS/BIOS data structures and absolute addresses in +conventional memory). However, the DPMI host will usually define +additional segments in order to support the DPMI environment. + +@cindex garbled pointers +These commands allow to display entries from the descriptor tables. +Without an argument, all entries from the specified table are +displayed. An argument, which should be an integer expression, means +display a single entry whose index is given by the argument. For +example, here's a convenient way to display information about the +debugged program's data segment: + +@smallexample +@exdent @code{(@value{GDBP}) info dos ldt $ds} +@exdent @code{0x13f: base=0x11970000 limit=0x0009ffff 32-Bit Data (Read/Write, Exp-up)} +@end smallexample + +@noindent +This comes in handy when you want to see whether a pointer is outside +the data segment's limit (i.e.@: @dfn{garbled}). + +@cindex page tables display (MS-DOS) +@item info dos pde +@itemx info dos pte +These two commands display entries from, respectively, the Page +Directory and the Page Tables. Page Directories and Page Tables are +data structures which control how virtual memory addresses are mapped +into physical addresses. A Page Table includes an entry for every +page of memory that is mapped into the program's address space; there +may be several Page Tables, each one holding up to 4096 entries. A +Page Directory has up to 4096 entries, one each for every Page Table +that is currently in use. + +Without an argument, @kbd{info dos pde} displays the entire Page +Directory, and @kbd{info dos pte} displays all the entries in all of +the Page Tables. An argument, an integer expression, given to the +@kbd{info dos pde} command means display only that entry from the Page +Directory table. An argument given to the @kbd{info dos pte} command +means display entries from a single Page Table, the one pointed to by +the specified entry in the Page Directory. + +@cindex direct memory access (DMA) on MS-DOS +These commands are useful when your program uses @dfn{DMA} (Direct +Memory Access), which needs physical addresses to program the DMA +controller. + +These commands are supported only with some DPMI servers. + +@cindex physical address from linear address +@item info dos address-pte @var{addr} +This command displays the Page Table entry for a specified linear +address. The argument linear address @var{addr} should already have the +appropriate segment's base address added to it, because this command +accepts addresses which may belong to @emph{any} segment. For +example, here's how to display the Page Table entry for the page where +the variable @code{i} is stored: + +@smallexample +@exdent @code{(@value{GDBP}) info dos address-pte __djgpp_base_address + (char *)&i} +@exdent @code{Page Table entry for address 0x11a00d30:} +@exdent @code{Base=0x02698000 Dirty Acc. Not-Cached Write-Back Usr Read-Write +0xd30} +@end smallexample + +@noindent +This says that @code{i} is stored at offset @code{0xd30} from the page +whose physical base address is @code{0x02698000}, and prints all the +attributes of that page. + +Note that you must cast the addresses of variables to a @code{char *}, +since otherwise the value of @code{__djgpp_base_address}, the base +address of all variables and functions in a @sc{djgpp} program, will +be added using the rules of C pointer arithmetics: if @code{i} is +declared an @code{int}, @value{GDBN} will add 4 times the value of +@code{__djgpp_base_address} to the address of @code{i}. + +Here's another example, it displays the Page Table entry for the +transfer buffer: + +@smallexample +@exdent @code{(@value{GDBP}) info dos address-pte *((unsigned *)&_go32_info_block + 3)} +@exdent @code{Page Table entry for address 0x29110:} +@exdent @code{Base=0x00029000 Dirty Acc. Not-Cached Write-Back Usr Read-Write +0x110} +@end smallexample + +@noindent +(The @code{+ 3} offset is because the transfer buffer's address is the +3rd member of the @code{_go32_info_block} structure.) The output of +this command clearly shows that addresses in conventional memory are +mapped 1:1, i.e.@: the physical and linear addresses are identical. + +This command is supported only with some DPMI servers. +@end table + +@node Cygwin Native +@subsection Features for Debugging MS Windows PE executables +@cindex MS Windows debugging +@cindex native Cygwin debugging +@cindex Cygwin-specific commands + +@value{GDBN} supports native debugging of MS Windows programs, and +defines a few commands specific to the Cygwin port. This +subsection describes those commands. + +@table @code +@kindex info w32 +@item info w32 +This is a prefix of MS Windows specific commands which print +information about the target system and important OS structures. + +@item info w32 selector +This command displays information returned by +the Win32 API @code{GetThreadSelectorEntry} function. +It takes an optional argument that is evaluated to +a long value to give the information about this given selector. +Without argument, this command displays information +about the the six segment registers. + +@kindex info dll +@item info dll +This is a Cygwin specific alias of info shared. + +@kindex dll-symbols +@item dll-symbols +This command loads symbols from a dll similarly to +add-sym command but without the need to specify a base address. + +@kindex set new-console +@item set new-console @var{mode} +If @var{mode} is @code{on} the debuggee will +be started in a new console on next start. +If @var{mode} is @code{off}i, the debuggee will +be started in the same console as the debugger. + +@kindex show new-console +@item show new-console +Displays whether a new console is used +when the debuggee is started. + +@kindex set new-group +@item set new-group @var{mode} +This boolean value controls whether the debuggee should +start a new group or stay in the same group as the debugger. +This affects the way the Windows OS handles +Ctrl-C. + +@kindex show new-group +@item show new-group +Displays current value of new-group boolean. + +@kindex set debugevents +@item set debugevents +This boolean value adds debug output concerning events seen by the debugger. + +@kindex set debugexec +@item set debugexec +This boolean value adds debug output concerning execute events +seen by the debugger. + +@kindex set debugexceptions +@item set debugexceptions +This boolean value adds debug ouptut concerning exception events +seen by the debugger. + +@kindex set debugmemory +@item set debugmemory +This boolean value adds debug ouptut concerning memory events +seen by the debugger. + +@kindex set shell +@item set shell +This boolean values specifies whether the debuggee is called +via a shell or directly (default value is on). + +@kindex show shell +@item show shell +Displays if the debuggee will be started with a shell. + +@end table + +@node Embedded OS +@section Embedded Operating Systems + +This section describes configurations involving the debugging of +embedded operating systems that are available for several different +architectures. + +@menu +* VxWorks:: Using @value{GDBN} with VxWorks +@end menu + +@value{GDBN} includes the ability to debug programs running on +various real-time operating systems. + +@node VxWorks +@subsection Using @value{GDBN} with VxWorks + +@cindex VxWorks + +@table @code + +@kindex target vxworks +@item target vxworks @var{machinename} +A VxWorks system, attached via TCP/IP. The argument @var{machinename} +is the target system's machine name or IP address. + +@end table + +On VxWorks, @code{load} links @var{filename} dynamically on the +current target system as well as adding its symbols in @value{GDBN}. + +@value{GDBN} enables developers to spawn and debug tasks running on networked +VxWorks targets from a Unix host. Already-running tasks spawned from +the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on +both the Unix host and on the VxWorks target. The program +@code{@value{GDBP}} is installed and executed on the Unix host. (It may be +installed with the name @code{vxgdb}, to distinguish it from a +@value{GDBN} for debugging programs on the host itself.) + +@table @code +@item VxWorks-timeout @var{args} +@kindex vxworks-timeout +All VxWorks-based targets now support the option @code{vxworks-timeout}. +This option is set by the user, and @var{args} represents the number of +seconds @value{GDBN} waits for responses to rpc's. You might use this if +your VxWorks target is a slow software simulator or is on the far side +of a thin network line. +@end table + +The following information on connecting to VxWorks was current when +this manual was produced; newer releases of VxWorks may use revised +procedures. + +@kindex INCLUDE_RDB +To use @value{GDBN} with VxWorks, you must rebuild your VxWorks kernel +to include the remote debugging interface routines in the VxWorks +library @file{rdb.a}. To do this, define @code{INCLUDE_RDB} in the +VxWorks configuration file @file{configAll.h} and rebuild your VxWorks +kernel. The resulting kernel contains @file{rdb.a}, and spawns the +source debugging task @code{tRdbTask} when VxWorks is booted. For more +information on configuring and remaking VxWorks, see the manufacturer's +manual. +@c VxWorks, see the @cite{VxWorks Programmer's Guide}. + +Once you have included @file{rdb.a} in your VxWorks system image and set +your Unix execution search path to find @value{GDBN}, you are ready to +run @value{GDBN}. From your Unix host, run @code{@value{GDBP}} (or +@code{vxgdb}, depending on your installation). + +@value{GDBN} comes up showing the prompt: + +@example +(vxgdb) +@end example + +@menu +* VxWorks Connection:: Connecting to VxWorks +* VxWorks Download:: VxWorks download +* VxWorks Attach:: Running tasks +@end menu + +@node VxWorks Connection +@subsubsection Connecting to VxWorks + +The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the +network. To connect to a target whose host name is ``@code{tt}'', type: + +@example +(vxgdb) target vxworks tt +@end example + +@need 750 +@value{GDBN} displays messages like these: + +@smallexample +Attaching remote machine across net... +Connected to tt. +@end smallexample + +@need 1000 +@value{GDBN} then attempts to read the symbol tables of any object modules +loaded into the VxWorks target since it was last booted. @value{GDBN} locates +these files by searching the directories listed in the command search +path (@pxref{Environment, ,Your program's environment}); if it fails +to find an object file, it displays a message such as: + +@example +prog.o: No such file or directory. +@end example + +When this happens, add the appropriate directory to the search path with +the @value{GDBN} command @code{path}, and execute the @code{target} +command again. + +@node VxWorks Download +@subsubsection VxWorks download + +@cindex download to VxWorks +If you have connected to the VxWorks target and you want to debug an +object that has not yet been loaded, you can use the @value{GDBN} +@code{load} command to download a file from Unix to VxWorks +incrementally. The object file given as an argument to the @code{load} +command is actually opened twice: first by the VxWorks target in order +to download the code, then by @value{GDBN} in order to read the symbol +table. This can lead to problems if the current working directories on +the two systems differ. If both systems have NFS mounted the same +filesystems, you can avoid these problems by using absolute paths. +Otherwise, it is simplest to set the working directory on both systems +to the directory in which the object file resides, and then to reference +the file by its name, without any path. For instance, a program +@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks +and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this +program, type this on VxWorks: + +@example +-> cd "@var{vxpath}/vw/demo/rdb" +@end example + +@noindent +Then, in @value{GDBN}, type: + +@example +(vxgdb) cd @var{hostpath}/vw/demo/rdb +(vxgdb) load prog.o +@end example + +@value{GDBN} displays a response similar to this: + +@smallexample +Reading symbol data from wherever/vw/demo/rdb/prog.o... done. +@end smallexample + +You can also use the @code{load} command to reload an object module +after editing and recompiling the corresponding source file. Note that +this makes @value{GDBN} delete all currently-defined breakpoints, +auto-displays, and convenience variables, and to clear the value +history. (This is necessary in order to preserve the integrity of +debugger's data structures that reference the target system's symbol +table.) + +@node VxWorks Attach +@subsubsection Running tasks + +@cindex running VxWorks tasks +You can also attach to an existing task using the @code{attach} command as +follows: + +@example +(vxgdb) attach @var{task} +@end example + +@noindent +where @var{task} is the VxWorks hexadecimal task ID. The task can be running +or suspended when you attach to it. Running tasks are suspended at +the time of attachment. + +@node Embedded Processors +@section Embedded Processors + +This section goes into details specific to particular embedded +configurations. + + +@c OBSOLETE * A29K Embedded:: AMD A29K Embedded +@menu +* ARM:: ARM +* H8/300:: Hitachi H8/300 +* H8/500:: Hitachi H8/500 +* i960:: Intel i960 +* M32R/D:: Mitsubishi M32R/D +* M68K:: Motorola M68K +* M88K:: Motorola M88K +* MIPS Embedded:: MIPS Embedded +* PA:: HP PA Embedded +* PowerPC: PowerPC +* SH:: Hitachi SH +* Sparclet:: Tsqware Sparclet +* Sparclite:: Fujitsu Sparclite +* ST2000:: Tandem ST2000 +* Z8000:: Zilog Z8000 +@end menu + +@c OBSOLETE @node A29K Embedded +@c OBSOLETE @subsection AMD A29K Embedded +@c OBSOLETE +@c OBSOLETE @menu +@c OBSOLETE * A29K UDI:: +@c OBSOLETE * A29K EB29K:: +@c OBSOLETE * Comms (EB29K):: Communications setup +@c OBSOLETE * gdb-EB29K:: EB29K cross-debugging +@c OBSOLETE * Remote Log:: Remote log +@c OBSOLETE @end menu +@c OBSOLETE +@c OBSOLETE @table @code +@c OBSOLETE +@c OBSOLETE @kindex target adapt +@c OBSOLETE @item target adapt @var{dev} +@c OBSOLETE Adapt monitor for A29K. +@c OBSOLETE +@c OBSOLETE @kindex target amd-eb +@c OBSOLETE @item target amd-eb @var{dev} @var{speed} @var{PROG} +@c OBSOLETE @cindex AMD EB29K +@c OBSOLETE Remote PC-resident AMD EB29K board, attached over serial lines. +@c OBSOLETE @var{dev} is the serial device, as for @code{target remote}; +@c OBSOLETE @var{speed} allows you to specify the linespeed; and @var{PROG} is the +@c OBSOLETE name of the program to be debugged, as it appears to DOS on the PC. +@c OBSOLETE @xref{A29K EB29K, ,EBMON protocol for AMD29K}. +@c OBSOLETE +@c OBSOLETE @end table +@c OBSOLETE +@c OBSOLETE @node A29K UDI +@c OBSOLETE @subsubsection A29K UDI +@c OBSOLETE +@c OBSOLETE @cindex UDI +@c OBSOLETE @cindex AMD29K via UDI +@c OBSOLETE +@c OBSOLETE @value{GDBN} supports AMD's UDI (``Universal Debugger Interface'') +@c OBSOLETE protocol for debugging the a29k processor family. To use this +@c OBSOLETE configuration with AMD targets running the MiniMON monitor, you need the +@c OBSOLETE program @code{MONTIP}, available from AMD at no charge. You can also +@c OBSOLETE use @value{GDBN} with the UDI-conformant a29k simulator program +@c OBSOLETE @code{ISSTIP}, also available from AMD. +@c OBSOLETE +@c OBSOLETE @table @code +@c OBSOLETE @item target udi @var{keyword} +@c OBSOLETE @kindex udi +@c OBSOLETE Select the UDI interface to a remote a29k board or simulator, where +@c OBSOLETE @var{keyword} is an entry in the AMD configuration file @file{udi_soc}. +@c OBSOLETE This file contains keyword entries which specify parameters used to +@c OBSOLETE connect to a29k targets. If the @file{udi_soc} file is not in your +@c OBSOLETE working directory, you must set the environment variable @samp{UDICONF} +@c OBSOLETE to its pathname. +@c OBSOLETE @end table +@c OBSOLETE +@c OBSOLETE @node A29K EB29K +@c OBSOLETE @subsubsection EBMON protocol for AMD29K +@c OBSOLETE +@c OBSOLETE @cindex EB29K board +@c OBSOLETE @cindex running 29K programs +@c OBSOLETE +@c OBSOLETE AMD distributes a 29K development board meant to fit in a PC, together +@c OBSOLETE with a DOS-hosted monitor program called @code{EBMON}. As a shorthand +@c OBSOLETE term, this development system is called the ``EB29K''. To use +@c OBSOLETE @value{GDBN} from a Unix system to run programs on the EB29K board, you +@c OBSOLETE must first connect a serial cable between the PC (which hosts the EB29K +@c OBSOLETE board) and a serial port on the Unix system. In the following, we +@c OBSOLETE assume you've hooked the cable between the PC's @file{COM1} port and +@c OBSOLETE @file{/dev/ttya} on the Unix system. +@c OBSOLETE +@c OBSOLETE @node Comms (EB29K) +@c OBSOLETE @subsubsection Communications setup +@c OBSOLETE +@c OBSOLETE The next step is to set up the PC's port, by doing something like this +@c OBSOLETE in DOS on the PC: +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE C:\> MODE com1:9600,n,8,1,none +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE @noindent +@c OBSOLETE This example---run on an MS DOS 4.0 system---sets the PC port to 9600 +@c OBSOLETE bps, no parity, eight data bits, one stop bit, and no ``retry'' action; +@c OBSOLETE you must match the communications parameters when establishing the Unix +@c OBSOLETE end of the connection as well. +@c OBSOLETE @c FIXME: Who knows what this "no retry action" crud from the DOS manual may +@c OBSOLETE @c mean? It's optional; leave it out? ---doc@cygnus.com, 25feb91 +@c OBSOLETE @c +@c OBSOLETE @c It's optional, but it's unwise to omit it: who knows what is the +@c OBSOLETE @c default value set when the DOS machines boots? "No retry" means that +@c OBSOLETE @c the DOS serial device driver won't retry the operation if it fails; +@c OBSOLETE @c I understand that this is needed because the GDB serial protocol +@c OBSOLETE @c handles any errors and retransmissions itself. ---Eli Zaretskii, 3sep99 +@c OBSOLETE +@c OBSOLETE To give control of the PC to the Unix side of the serial line, type +@c OBSOLETE the following at the DOS console: +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE C:\> CTTY com1 +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE @noindent +@c OBSOLETE (Later, if you wish to return control to the DOS console, you can use +@c OBSOLETE the command @code{CTTY con}---but you must send it over the device that +@c OBSOLETE had control, in our example over the @file{COM1} serial line.) +@c OBSOLETE +@c OBSOLETE From the Unix host, use a communications program such as @code{tip} or +@c OBSOLETE @code{cu} to communicate with the PC; for example, +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE cu -s 9600 -l /dev/ttya +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE @noindent +@c OBSOLETE The @code{cu} options shown specify, respectively, the linespeed and the +@c OBSOLETE serial port to use. If you use @code{tip} instead, your command line +@c OBSOLETE may look something like the following: +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE tip -9600 /dev/ttya +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE @noindent +@c OBSOLETE Your system may require a different name where we show +@c OBSOLETE @file{/dev/ttya} as the argument to @code{tip}. The communications +@c OBSOLETE parameters, including which port to use, are associated with the +@c OBSOLETE @code{tip} argument in the ``remote'' descriptions file---normally the +@c OBSOLETE system table @file{/etc/remote}. +@c OBSOLETE @c FIXME: What if anything needs doing to match the "n,8,1,none" part of +@c OBSOLETE @c the DOS side's comms setup? cu can support -o (odd +@c OBSOLETE @c parity), -e (even parity)---apparently no settings for no parity or +@c OBSOLETE @c for character size. Taken from stty maybe...? John points out tip +@c OBSOLETE @c can set these as internal variables, eg ~s parity=none; man stty +@c OBSOLETE @c suggests that it *might* work to stty these options with stdin or +@c OBSOLETE @c stdout redirected... ---doc@cygnus.com, 25feb91 +@c OBSOLETE @c +@c OBSOLETE @c There's nothing to be done for the "none" part of the DOS MODE +@c OBSOLETE @c command. The rest of the parameters should be matched by the +@c OBSOLETE @c baudrate, bits, and parity used by the Unix side. ---Eli Zaretskii, 3Sep99 +@c OBSOLETE +@c OBSOLETE @kindex EBMON +@c OBSOLETE Using the @code{tip} or @code{cu} connection, change the DOS working +@c OBSOLETE directory to the directory containing a copy of your 29K program, then +@c OBSOLETE start the PC program @code{EBMON} (an EB29K control program supplied +@c OBSOLETE with your board by AMD). You should see an initial display from +@c OBSOLETE @code{EBMON} similar to the one that follows, ending with the +@c OBSOLETE @code{EBMON} prompt @samp{#}--- +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE C:\> G: +@c OBSOLETE +@c OBSOLETE G:\> CD \usr\joe\work29k +@c OBSOLETE +@c OBSOLETE G:\USR\JOE\WORK29K> EBMON +@c OBSOLETE Am29000 PC Coprocessor Board Monitor, version 3.0-18 +@c OBSOLETE Copyright 1990 Advanced Micro Devices, Inc. +@c OBSOLETE Written by Gibbons and Associates, Inc. +@c OBSOLETE +@c OBSOLETE Enter '?' or 'H' for help +@c OBSOLETE +@c OBSOLETE PC Coprocessor Type = EB29K +@c OBSOLETE I/O Base = 0x208 +@c OBSOLETE Memory Base = 0xd0000 +@c OBSOLETE +@c OBSOLETE Data Memory Size = 2048KB +@c OBSOLETE Available I-RAM Range = 0x8000 to 0x1fffff +@c OBSOLETE Available D-RAM Range = 0x80002000 to 0x801fffff +@c OBSOLETE +@c OBSOLETE PageSize = 0x400 +@c OBSOLETE Register Stack Size = 0x800 +@c OBSOLETE Memory Stack Size = 0x1800 +@c OBSOLETE +@c OBSOLETE CPU PRL = 0x3 +@c OBSOLETE Am29027 Available = No +@c OBSOLETE Byte Write Available = Yes +@c OBSOLETE +@c OBSOLETE # ~. +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE Then exit the @code{cu} or @code{tip} program (done in the example by +@c OBSOLETE typing @code{~.} at the @code{EBMON} prompt). @code{EBMON} keeps +@c OBSOLETE running, ready for @value{GDBN} to take over. +@c OBSOLETE +@c OBSOLETE For this example, we've assumed what is probably the most convenient +@c OBSOLETE way to make sure the same 29K program is on both the PC and the Unix +@c OBSOLETE system: a PC/NFS connection that establishes ``drive @file{G:}'' on the +@c OBSOLETE PC as a file system on the Unix host. If you do not have PC/NFS or +@c OBSOLETE something similar connecting the two systems, you must arrange some +@c OBSOLETE other way---perhaps floppy-disk transfer---of getting the 29K program +@c OBSOLETE from the Unix system to the PC; @value{GDBN} does @emph{not} download it over the +@c OBSOLETE serial line. +@c OBSOLETE +@c OBSOLETE @node gdb-EB29K +@c OBSOLETE @subsubsection EB29K cross-debugging +@c OBSOLETE +@c OBSOLETE Finally, @code{cd} to the directory containing an image of your 29K +@c OBSOLETE program on the Unix system, and start @value{GDBN}---specifying as argument the +@c OBSOLETE name of your 29K program: +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE cd /usr/joe/work29k +@c OBSOLETE @value{GDBP} myfoo +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE @need 500 +@c OBSOLETE Now you can use the @code{target} command: +@c OBSOLETE +@c OBSOLETE @example +@c OBSOLETE target amd-eb /dev/ttya 9600 MYFOO +@c OBSOLETE @c FIXME: test above 'target amd-eb' as spelled, with caps! caps are meant to +@c OBSOLETE @c emphasize that this is the name as seen by DOS (since I think DOS is +@c OBSOLETE @c single-minded about case of letters). ---doc@cygnus.com, 25feb91 +@c OBSOLETE @end example +@c OBSOLETE +@c OBSOLETE @noindent +@c OBSOLETE In this example, we've assumed your program is in a file called +@c OBSOLETE @file{myfoo}. Note that the filename given as the last argument to +@c OBSOLETE @code{target amd-eb} should be the name of the program as it appears to DOS. +@c OBSOLETE In our example this is simply @code{MYFOO}, but in general it can include +@c OBSOLETE a DOS path, and depending on your transfer mechanism may not resemble +@c OBSOLETE the name on the Unix side. +@c OBSOLETE +@c OBSOLETE At this point, you can set any breakpoints you wish; when you are ready +@c OBSOLETE to see your program run on the 29K board, use the @value{GDBN} command +@c OBSOLETE @code{run}. +@c OBSOLETE +@c OBSOLETE To stop debugging the remote program, use the @value{GDBN} @code{detach} +@c OBSOLETE command. +@c OBSOLETE +@c OBSOLETE To return control of the PC to its console, use @code{tip} or @code{cu} +@c OBSOLETE once again, after your @value{GDBN} session has concluded, to attach to +@c OBSOLETE @code{EBMON}. You can then type the command @code{q} to shut down +@c OBSOLETE @code{EBMON}, returning control to the DOS command-line interpreter. +@c OBSOLETE Type @kbd{CTTY con} to return command input to the main DOS console, +@c OBSOLETE and type @kbd{~.} to leave @code{tip} or @code{cu}. +@c OBSOLETE +@c OBSOLETE @node Remote Log +@c OBSOLETE @subsubsection Remote log +@c OBSOLETE @cindex @file{eb.log}, a log file for EB29K +@c OBSOLETE @cindex log file for EB29K +@c OBSOLETE +@c OBSOLETE The @code{target amd-eb} command creates a file @file{eb.log} in the +@c OBSOLETE current working directory, to help debug problems with the connection. +@c OBSOLETE @file{eb.log} records all the output from @code{EBMON}, including echoes +@c OBSOLETE of the commands sent to it. Running @samp{tail -f} on this file in +@c OBSOLETE another window often helps to understand trouble with @code{EBMON}, or +@c OBSOLETE unexpected events on the PC side of the connection. + +@node ARM +@subsection ARM + +@table @code + +@kindex target rdi +@item target rdi @var{dev} +ARM Angel monitor, via RDI library interface to ADP protocol. You may +use this target to communicate with both boards running the Angel +monitor, or with the EmbeddedICE JTAG debug device. + +@kindex target rdp +@item target rdp @var{dev} +ARM Demon monitor. + +@end table + +@node H8/300 +@subsection Hitachi H8/300 + +@table @code + +@kindex target hms@r{, with H8/300} +@item target hms @var{dev} +A Hitachi SH, H8/300, or H8/500 board, attached via serial line to your host. +Use special commands @code{device} and @code{speed} to control the serial +line and the communications speed used. + +@kindex target e7000@r{, with H8/300} +@item target e7000 @var{dev} +E7000 emulator for Hitachi H8 and SH. + +@kindex target sh3@r{, with H8/300} +@kindex target sh3e@r{, with H8/300} +@item target sh3 @var{dev} +@itemx target sh3e @var{dev} +Hitachi SH-3 and SH-3E target systems. + +@end table + +@cindex download to H8/300 or H8/500 +@cindex H8/300 or H8/500 download +@cindex download to Hitachi SH +@cindex Hitachi SH download +When you select remote debugging to a Hitachi SH, H8/300, or H8/500 +board, the @code{load} command downloads your program to the Hitachi +board and also opens it as the current executable target for +@value{GDBN} on your host (like the @code{file} command). + +@value{GDBN} needs to know these things to talk to your +Hitachi SH, H8/300, or H8/500: + +@enumerate +@item +that you want to use @samp{target hms}, the remote debugging interface +for Hitachi microprocessors, or @samp{target e7000}, the in-circuit +emulator for the Hitachi SH and the Hitachi 300H. (@samp{target hms} is +the default when @value{GDBN} is configured specifically for the Hitachi SH, +H8/300, or H8/500.) + +@item +what serial device connects your host to your Hitachi board (the first +serial device available on your host is the default). + +@item +what speed to use over the serial device. +@end enumerate + +@menu +* Hitachi Boards:: Connecting to Hitachi boards. +* Hitachi ICE:: Using the E7000 In-Circuit Emulator. +* Hitachi Special:: Special @value{GDBN} commands for Hitachi micros. +@end menu + +@node Hitachi Boards +@subsubsection Connecting to Hitachi boards + +@c only for Unix hosts +@kindex device +@cindex serial device, Hitachi micros +Use the special @code{@value{GDBN}} command @samp{device @var{port}} if you +need to explicitly set the serial device. The default @var{port} is the +first available port on your host. This is only necessary on Unix +hosts, where it is typically something like @file{/dev/ttya}. + +@kindex speed +@cindex serial line speed, Hitachi micros +@code{@value{GDBN}} has another special command to set the communications +speed: @samp{speed @var{bps}}. This command also is only used from Unix +hosts; on DOS hosts, set the line speed as usual from outside @value{GDBN} with +the DOS @code{mode} command (for instance, +@w{@kbd{mode com2:9600,n,8,1,p}} for a 9600@dmn{bps} connection). + +The @samp{device} and @samp{speed} commands are available only when you +use a Unix host to debug your Hitachi microprocessor programs. If you +use a DOS host, +@value{GDBN} depends on an auxiliary terminate-and-stay-resident program +called @code{asynctsr} to communicate with the development board +through a PC serial port. You must also use the DOS @code{mode} command +to set up the serial port on the DOS side. + +The following sample session illustrates the steps needed to start a +program under @value{GDBN} control on an H8/300. The example uses a +sample H8/300 program called @file{t.x}. The procedure is the same for +the Hitachi SH and the H8/500. + +First hook up your development board. In this example, we use a +board attached to serial port @code{COM2}; if you use a different serial +port, substitute its name in the argument of the @code{mode} command. +When you call @code{asynctsr}, the auxiliary comms program used by the +debugger, you give it just the numeric part of the serial port's name; +for example, @samp{asyncstr 2} below runs @code{asyncstr} on +@code{COM2}. + +@example +C:\H8300\TEST> asynctsr 2 +C:\H8300\TEST> mode com2:9600,n,8,1,p + +Resident portion of MODE loaded + +COM2: 9600, n, 8, 1, p + +@end example + +@quotation +@emph{Warning:} We have noticed a bug in PC-NFS that conflicts with +@code{asynctsr}. If you also run PC-NFS on your DOS host, you may need to +disable it, or even boot without it, to use @code{asynctsr} to control +your development board. +@end quotation + +@kindex target hms@r{, and serial protocol} +Now that serial communications are set up, and the development board is +connected, you can start up @value{GDBN}. Call @code{@value{GDBP}} with +the name of your program as the argument. @code{@value{GDBN}} prompts +you, as usual, with the prompt @samp{(@value{GDBP})}. Use two special +commands to begin your debugging session: @samp{target hms} to specify +cross-debugging to the Hitachi board, and the @code{load} command to +download your program to the board. @code{load} displays the names of +the program's sections, and a @samp{*} for each 2K of data downloaded. +(If you want to refresh @value{GDBN} data on symbols or on the +executable file without downloading, use the @value{GDBN} commands +@code{file} or @code{symbol-file}. These commands, and @code{load} +itself, are described in @ref{Files,,Commands to specify files}.) + +@smallexample +(eg-C:\H8300\TEST) @value{GDBP} t.x +@value{GDBN} is free software and you are welcome to distribute copies + of it under certain conditions; type "show copying" to see + the conditions. +There is absolutely no warranty for @value{GDBN}; type "show warranty" +for details. +@value{GDBN} @value{GDBVN}, Copyright 1992 Free Software Foundation, Inc... +(@value{GDBP}) target hms +Connected to remote H8/300 HMS system. +(@value{GDBP}) load t.x +.text : 0x8000 .. 0xabde *********** +.data : 0xabde .. 0xad30 * +.stack : 0xf000 .. 0xf014 * +@end smallexample + +At this point, you're ready to run or debug your program. From here on, +you can use all the usual @value{GDBN} commands. The @code{break} command +sets breakpoints; the @code{run} command starts your program; +@code{print} or @code{x} display data; the @code{continue} command +resumes execution after stopping at a breakpoint. You can use the +@code{help} command at any time to find out more about @value{GDBN} commands. + +Remember, however, that @emph{operating system} facilities aren't +available on your development board; for example, if your program hangs, +you can't send an interrupt---but you can press the @sc{reset} switch! + +Use the @sc{reset} button on the development board +@itemize @bullet +@item +to interrupt your program (don't use @kbd{ctl-C} on the DOS host---it has +no way to pass an interrupt signal to the development board); and + +@item +to return to the @value{GDBN} command prompt after your program finishes +normally. The communications protocol provides no other way for @value{GDBN} +to detect program completion. +@end itemize + +In either case, @value{GDBN} sees the effect of a @sc{reset} on the +development board as a ``normal exit'' of your program. + +@node Hitachi ICE +@subsubsection Using the E7000 in-circuit emulator + +@kindex target e7000@r{, with Hitachi ICE} +You can use the E7000 in-circuit emulator to develop code for either the +Hitachi SH or the H8/300H. Use one of these forms of the @samp{target +e7000} command to connect @value{GDBN} to your E7000: + +@table @code +@item target e7000 @var{port} @var{speed} +Use this form if your E7000 is connected to a serial port. The +@var{port} argument identifies what serial port to use (for example, +@samp{com2}). The third argument is the line speed in bits per second +(for example, @samp{9600}). + +@item target e7000 @var{hostname} +If your E7000 is installed as a host on a TCP/IP network, you can just +specify its hostname; @value{GDBN} uses @code{telnet} to connect. +@end table + +@node Hitachi Special +@subsubsection Special @value{GDBN} commands for Hitachi micros + +Some @value{GDBN} commands are available only for the H8/300: + +@table @code + +@kindex set machine +@kindex show machine +@item set machine h8300 +@itemx set machine h8300h +Condition @value{GDBN} for one of the two variants of the H8/300 +architecture with @samp{set machine}. You can use @samp{show machine} +to check which variant is currently in effect. + +@end table + +@node H8/500 +@subsection H8/500 + +@table @code + +@kindex set memory @var{mod} +@cindex memory models, H8/500 +@item set memory @var{mod} +@itemx show memory +Specify which H8/500 memory model (@var{mod}) you are using with +@samp{set memory}; check which memory model is in effect with @samp{show +memory}. The accepted values for @var{mod} are @code{small}, +@code{big}, @code{medium}, and @code{compact}. + +@end table + +@node i960 +@subsection Intel i960 + +@table @code + +@kindex target mon960 +@item target mon960 @var{dev} +MON960 monitor for Intel i960. + +@kindex target nindy +@item target nindy @var{devicename} +An Intel 960 board controlled by a Nindy Monitor. @var{devicename} is +the name of the serial device to use for the connection, e.g. +@file{/dev/ttya}. + +@end table + +@cindex Nindy +@cindex i960 +@dfn{Nindy} is a ROM Monitor program for Intel 960 target systems. When +@value{GDBN} is configured to control a remote Intel 960 using Nindy, you can +tell @value{GDBN} how to connect to the 960 in several ways: + +@itemize @bullet +@item +Through command line options specifying serial port, version of the +Nindy protocol, and communications speed; + +@item +By responding to a prompt on startup; + +@item +By using the @code{target} command at any point during your @value{GDBN} +session. @xref{Target Commands, ,Commands for managing targets}. + +@end itemize + +@cindex download to Nindy-960 +With the Nindy interface to an Intel 960 board, @code{load} +downloads @var{filename} to the 960 as well as adding its symbols in +@value{GDBN}. + +@menu +* Nindy Startup:: Startup with Nindy +* Nindy Options:: Options for Nindy +* Nindy Reset:: Nindy reset command +@end menu + +@node Nindy Startup +@subsubsection Startup with Nindy + +If you simply start @code{@value{GDBP}} without using any command-line +options, you are prompted for what serial port to use, @emph{before} you +reach the ordinary @value{GDBN} prompt: + +@example +Attach /dev/ttyNN -- specify NN, or "quit" to quit: +@end example + +@noindent +Respond to the prompt with whatever suffix (after @samp{/dev/tty}) +identifies the serial port you want to use. You can, if you choose, +simply start up with no Nindy connection by responding to the prompt +with an empty line. If you do this and later wish to attach to Nindy, +use @code{target} (@pxref{Target Commands, ,Commands for managing targets}). + +@node Nindy Options +@subsubsection Options for Nindy + +These are the startup options for beginning your @value{GDBN} session with a +Nindy-960 board attached: + +@table @code +@item -r @var{port} +Specify the serial port name of a serial interface to be used to connect +to the target system. This option is only available when @value{GDBN} is +configured for the Intel 960 target architecture. You may specify +@var{port} as any of: a full pathname (e.g. @samp{-r /dev/ttya}), a +device name in @file{/dev} (e.g. @samp{-r ttya}), or simply the unique +suffix for a specific @code{tty} (e.g. @samp{-r a}). + +@item -O +(An uppercase letter ``O'', not a zero.) Specify that @value{GDBN} should use +the ``old'' Nindy monitor protocol to connect to the target system. +This option is only available when @value{GDBN} is configured for the Intel 960 +target architecture. + +@quotation +@emph{Warning:} if you specify @samp{-O}, but are actually trying to +connect to a target system that expects the newer protocol, the connection +fails, appearing to be a speed mismatch. @value{GDBN} repeatedly +attempts to reconnect at several different line speeds. You can abort +this process with an interrupt. +@end quotation + +@item -brk +Specify that @value{GDBN} should first send a @code{BREAK} signal to the target +system, in an attempt to reset it, before connecting to a Nindy target. + +@quotation +@emph{Warning:} Many target systems do not have the hardware that this +requires; it only works with a few boards. +@end quotation +@end table + +The standard @samp{-b} option controls the line speed used on the serial +port. + +@c @group +@node Nindy Reset +@subsubsection Nindy reset command + +@table @code +@item reset +@kindex reset +For a Nindy target, this command sends a ``break'' to the remote target +system; this is only useful if the target has been equipped with a +circuit to perform a hard reset (or some other interesting action) when +a break is detected. +@end table +@c @end group + +@node M32R/D +@subsection Mitsubishi M32R/D + +@table @code + +@kindex target m32r +@item target m32r @var{dev} +Mitsubishi M32R/D ROM monitor. + +@end table + +@node M68K +@subsection M68k + +The Motorola m68k configuration includes ColdFire support, and +target command for the following ROM monitors. + +@table @code + +@kindex target abug +@item target abug @var{dev} +ABug ROM monitor for M68K. + +@kindex target cpu32bug +@item target cpu32bug @var{dev} +CPU32BUG monitor, running on a CPU32 (M68K) board. + +@kindex target dbug +@item target dbug @var{dev} +dBUG ROM monitor for Motorola ColdFire. + +@kindex target est +@item target est @var{dev} +EST-300 ICE monitor, running on a CPU32 (M68K) board. + +@kindex target rom68k +@item target rom68k @var{dev} +ROM 68K monitor, running on an M68K IDP board. + +@end table + +If @value{GDBN} is configured with @code{m68*-ericsson-*}, it will +instead have only a single special target command: + +@table @code + +@kindex target es1800 +@item target es1800 @var{dev} +ES-1800 emulator for M68K. + +@end table + +[context?] + +@table @code + +@kindex target rombug +@item target rombug @var{dev} +ROMBUG ROM monitor for OS/9000. + +@end table + +@node M88K +@subsection M88K + +@table @code + +@kindex target bug +@item target bug @var{dev} +BUG monitor, running on a MVME187 (m88k) board. + +@end table + +@node MIPS Embedded +@subsection MIPS Embedded + +@cindex MIPS boards +@value{GDBN} can use the MIPS remote debugging protocol to talk to a +MIPS board attached to a serial line. This is available when +you configure @value{GDBN} with @samp{--target=mips-idt-ecoff}. + +@need 1000 +Use these @value{GDBN} commands to specify the connection to your target board: + +@table @code +@item target mips @var{port} +@kindex target mips @var{port} +To run a program on the board, start up @code{@value{GDBP}} with the +name of your program as the argument. To connect to the board, use the +command @samp{target mips @var{port}}, where @var{port} is the name of +the serial port connected to the board. If the program has not already +been downloaded to the board, you may use the @code{load} command to +download it. You can then use all the usual @value{GDBN} commands. + +For example, this sequence connects to the target board through a serial +port, and loads and runs a program called @var{prog} through the +debugger: + +@example +host$ @value{GDBP} @var{prog} +@value{GDBN} is free software and @dots{} +(@value{GDBP}) target mips /dev/ttyb +(@value{GDBP}) load @var{prog} +(@value{GDBP}) run +@end example + +@item target mips @var{hostname}:@var{portnumber} +On some @value{GDBN} host configurations, you can specify a TCP +connection (for instance, to a serial line managed by a terminal +concentrator) instead of a serial port, using the syntax +@samp{@var{hostname}:@var{portnumber}}. + +@item target pmon @var{port} +@kindex target pmon @var{port} +PMON ROM monitor. + +@item target ddb @var{port} +@kindex target ddb @var{port} +NEC's DDB variant of PMON for Vr4300. + +@item target lsi @var{port} +@kindex target lsi @var{port} +LSI variant of PMON. + +@kindex target r3900 +@item target r3900 @var{dev} +Densan DVE-R3900 ROM monitor for Toshiba R3900 Mips. + +@kindex target array +@item target array @var{dev} +Array Tech LSI33K RAID controller board. + +@end table + + +@noindent +@value{GDBN} also supports these special commands for MIPS targets: + +@table @code +@item set processor @var{args} +@itemx show processor +@kindex set processor @var{args} +@kindex show processor +Use the @code{set processor} command to set the type of MIPS +processor when you want to access processor-type-specific registers. +For example, @code{set processor @var{r3041}} tells @value{GDBN} +to use the CPU registers appropriate for the 3041 chip. +Use the @code{show processor} command to see what MIPS processor @value{GDBN} +is using. Use the @code{info reg} command to see what registers +@value{GDBN} is using. + +@item set mipsfpu double +@itemx set mipsfpu single +@itemx set mipsfpu none +@itemx show mipsfpu +@kindex set mipsfpu +@kindex show mipsfpu +@cindex MIPS remote floating point +@cindex floating point, MIPS remote +If your target board does not support the MIPS floating point +coprocessor, you should use the command @samp{set mipsfpu none} (if you +need this, you may wish to put the command in your @value{GDBN} init +file). This tells @value{GDBN} how to find the return value of +functions which return floating point values. It also allows +@value{GDBN} to avoid saving the floating point registers when calling +functions on the board. If you are using a floating point coprocessor +with only single precision floating point support, as on the @sc{r4650} +processor, use the command @samp{set mipsfpu single}. The default +double precision floating point coprocessor may be selected using +@samp{set mipsfpu double}. + +In previous versions the only choices were double precision or no +floating point, so @samp{set mipsfpu on} will select double precision +and @samp{set mipsfpu off} will select no floating point. + +As usual, you can inquire about the @code{mipsfpu} variable with +@samp{show mipsfpu}. + +@item set remotedebug @var{n} +@itemx show remotedebug +@kindex set remotedebug@r{, MIPS protocol} +@kindex show remotedebug@r{, MIPS protocol} +@cindex @code{remotedebug}, MIPS protocol +@cindex MIPS @code{remotedebug} protocol +@c FIXME! For this to be useful, you must know something about the MIPS +@c FIXME...protocol. Where is it described? +You can see some debugging information about communications with the board +by setting the @code{remotedebug} variable. If you set it to @code{1} using +@samp{set remotedebug 1}, every packet is displayed. If you set it +to @code{2}, every character is displayed. You can check the current value +at any time with the command @samp{show remotedebug}. + +@item set timeout @var{seconds} +@itemx set retransmit-timeout @var{seconds} +@itemx show timeout +@itemx show retransmit-timeout +@cindex @code{timeout}, MIPS protocol +@cindex @code{retransmit-timeout}, MIPS protocol +@kindex set timeout +@kindex show timeout +@kindex set retransmit-timeout +@kindex show retransmit-timeout +You can control the timeout used while waiting for a packet, in the MIPS +remote protocol, with the @code{set timeout @var{seconds}} command. The +default is 5 seconds. Similarly, you can control the timeout used while +waiting for an acknowledgement of a packet with the @code{set +retransmit-timeout @var{seconds}} command. The default is 3 seconds. +You can inspect both values with @code{show timeout} and @code{show +retransmit-timeout}. (These commands are @emph{only} available when +@value{GDBN} is configured for @samp{--target=mips-idt-ecoff}.) + +The timeout set by @code{set timeout} does not apply when @value{GDBN} +is waiting for your program to stop. In that case, @value{GDBN} waits +forever because it has no way of knowing how long the program is going +to run before stopping. +@end table + +@node PowerPC +@subsection PowerPC + +@table @code + +@kindex target dink32 +@item target dink32 @var{dev} +DINK32 ROM monitor. + +@kindex target ppcbug +@item target ppcbug @var{dev} +@kindex target ppcbug1 +@item target ppcbug1 @var{dev} +PPCBUG ROM monitor for PowerPC. + +@kindex target sds +@item target sds @var{dev} +SDS monitor, running on a PowerPC board (such as Motorola's ADS). + +@end table + +@node PA +@subsection HP PA Embedded + +@table @code + +@kindex target op50n +@item target op50n @var{dev} +OP50N monitor, running on an OKI HPPA board. + +@kindex target w89k +@item target w89k @var{dev} +W89K monitor, running on a Winbond HPPA board. + +@end table + +@node SH +@subsection Hitachi SH + +@table @code + +@kindex target hms@r{, with Hitachi SH} +@item target hms @var{dev} +A Hitachi SH board attached via serial line to your host. Use special +commands @code{device} and @code{speed} to control the serial line and +the communications speed used. + +@kindex target e7000@r{, with Hitachi SH} +@item target e7000 @var{dev} +E7000 emulator for Hitachi SH. + +@kindex target sh3@r{, with SH} +@kindex target sh3e@r{, with SH} +@item target sh3 @var{dev} +@item target sh3e @var{dev} +Hitachi SH-3 and SH-3E target systems. + +@end table + +@node Sparclet +@subsection Tsqware Sparclet + +@cindex Sparclet + +@value{GDBN} enables developers to debug tasks running on +Sparclet targets from a Unix host. +@value{GDBN} uses code that runs on +both the Unix host and on the Sparclet target. The program +@code{@value{GDBP}} is installed and executed on the Unix host. + +@table @code +@item remotetimeout @var{args} +@kindex remotetimeout +@value{GDBN} supports the option @code{remotetimeout}. +This option is set by the user, and @var{args} represents the number of +seconds @value{GDBN} waits for responses. +@end table + +@cindex compiling, on Sparclet +When compiling for debugging, include the options @samp{-g} to get debug +information and @samp{-Ttext} to relocate the program to where you wish to +load it on the target. You may also want to add the options @samp{-n} or +@samp{-N} in order to reduce the size of the sections. Example: + +@example +sparclet-aout-gcc prog.c -Ttext 0x12010000 -g -o prog -N +@end example + +You can use @code{objdump} to verify that the addresses are what you intended: + +@example +sparclet-aout-objdump --headers --syms prog +@end example + +@cindex running, on Sparclet +Once you have set +your Unix execution search path to find @value{GDBN}, you are ready to +run @value{GDBN}. From your Unix host, run @code{@value{GDBP}} +(or @code{sparclet-aout-gdb}, depending on your installation). + +@value{GDBN} comes up showing the prompt: + +@example +(gdbslet) +@end example + +@menu +* Sparclet File:: Setting the file to debug +* Sparclet Connection:: Connecting to Sparclet +* Sparclet Download:: Sparclet download +* Sparclet Execution:: Running and debugging +@end menu + +@node Sparclet File +@subsubsection Setting file to debug + +The @value{GDBN} command @code{file} lets you choose with program to debug. + +@example +(gdbslet) file prog +@end example + +@need 1000 +@value{GDBN} then attempts to read the symbol table of @file{prog}. +@value{GDBN} locates +the file by searching the directories listed in the command search +path. +If the file was compiled with debug information (option "-g"), source +files will be searched as well. +@value{GDBN} locates +the source files by searching the directories listed in the directory search +path (@pxref{Environment, ,Your program's environment}). +If it fails +to find a file, it displays a message such as: + +@example +prog: No such file or directory. +@end example + +When this happens, add the appropriate directories to the search paths with +the @value{GDBN} commands @code{path} and @code{dir}, and execute the +@code{target} command again. + +@node Sparclet Connection +@subsubsection Connecting to Sparclet + +The @value{GDBN} command @code{target} lets you connect to a Sparclet target. +To connect to a target on serial port ``@code{ttya}'', type: + +@example +(gdbslet) target sparclet /dev/ttya +Remote target sparclet connected to /dev/ttya +main () at ../prog.c:3 +@end example + +@need 750 +@value{GDBN} displays messages like these: + +@example +Connected to ttya. +@end example + +@node Sparclet Download +@subsubsection Sparclet download + +@cindex download to Sparclet +Once connected to the Sparclet target, +you can use the @value{GDBN} +@code{load} command to download the file from the host to the target. +The file name and load offset should be given as arguments to the @code{load} +command. +Since the file format is aout, the program must be loaded to the starting +address. You can use @code{objdump} to find out what this value is. The load +offset is an offset which is added to the VMA (virtual memory address) +of each of the file's sections. +For instance, if the program +@file{prog} was linked to text address 0x1201000, with data at 0x12010160 +and bss at 0x12010170, in @value{GDBN}, type: + +@example +(gdbslet) load prog 0x12010000 +Loading section .text, size 0xdb0 vma 0x12010000 +@end example + +If the code is loaded at a different address then what the program was linked +to, you may need to use the @code{section} and @code{add-symbol-file} commands +to tell @value{GDBN} where to map the symbol table. + +@node Sparclet Execution +@subsubsection Running and debugging + +@cindex running and debugging Sparclet programs +You can now begin debugging the task using @value{GDBN}'s execution control +commands, @code{b}, @code{step}, @code{run}, etc. See the @value{GDBN} +manual for the list of commands. + +@example +(gdbslet) b main +Breakpoint 1 at 0x12010000: file prog.c, line 3. +(gdbslet) run +Starting program: prog +Breakpoint 1, main (argc=1, argv=0xeffff21c) at prog.c:3 +3 char *symarg = 0; +(gdbslet) step +4 char *execarg = "hello!"; +(gdbslet) +@end example + +@node Sparclite +@subsection Fujitsu Sparclite + +@table @code + +@kindex target sparclite +@item target sparclite @var{dev} +Fujitsu sparclite boards, used only for the purpose of loading. +You must use an additional command to debug the program. +For example: target remote @var{dev} using @value{GDBN} standard +remote protocol. + +@end table + +@node ST2000 +@subsection Tandem ST2000 + +@value{GDBN} may be used with a Tandem ST2000 phone switch, running Tandem's +STDBUG protocol. + +To connect your ST2000 to the host system, see the manufacturer's +manual. Once the ST2000 is physically attached, you can run: + +@example +target st2000 @var{dev} @var{speed} +@end example + +@noindent +to establish it as your debugging environment. @var{dev} is normally +the name of a serial device, such as @file{/dev/ttya}, connected to the +ST2000 via a serial line. You can instead specify @var{dev} as a TCP +connection (for example, to a serial line attached via a terminal +concentrator) using the syntax @code{@var{hostname}:@var{portnumber}}. + +The @code{load} and @code{attach} commands are @emph{not} defined for +this target; you must load your program into the ST2000 as you normally +would for standalone operation. @value{GDBN} reads debugging information +(such as symbols) from a separate, debugging version of the program +available on your host computer. +@c FIXME!! This is terribly vague; what little content is here is +@c basically hearsay. + +@cindex ST2000 auxiliary commands +These auxiliary @value{GDBN} commands are available to help you with the ST2000 +environment: + +@table @code +@item st2000 @var{command} +@kindex st2000 @var{cmd} +@cindex STDBUG commands (ST2000) +@cindex commands to STDBUG (ST2000) +Send a @var{command} to the STDBUG monitor. See the manufacturer's +manual for available commands. + +@item connect +@cindex connect (to STDBUG) +Connect the controlling terminal to the STDBUG command monitor. When +you are done interacting with STDBUG, typing either of two character +sequences gets you back to the @value{GDBN} command prompt: +@kbd{@key{RET}~.} (Return, followed by tilde and period) or +@kbd{@key{RET}~@key{C-d}} (Return, followed by tilde and control-D). +@end table + +@node Z8000 +@subsection Zilog Z8000 + +@cindex Z8000 +@cindex simulator, Z8000 +@cindex Zilog Z8000 simulator + +When configured for debugging Zilog Z8000 targets, @value{GDBN} includes +a Z8000 simulator. + +For the Z8000 family, @samp{target sim} simulates either the Z8002 (the +unsegmented variant of the Z8000 architecture) or the Z8001 (the +segmented variant). The simulator recognizes which architecture is +appropriate by inspecting the object code. + +@table @code +@item target sim @var{args} +@kindex sim +@kindex target sim@r{, with Z8000} +Debug programs on a simulated CPU. If the simulator supports setup +options, specify them via @var{args}. +@end table + +@noindent +After specifying this target, you can debug programs for the simulated +CPU in the same style as programs for your host computer; use the +@code{file} command to load a new program image, the @code{run} command +to run your program, and so on. + +As well as making available all the usual machine registers +(@pxref{Registers, ,Registers}), the Z8000 simulator provides three +additional items of information as specially named registers: + +@table @code + +@item cycles +Counts clock-ticks in the simulator. + +@item insts +Counts instructions run in the simulator. + +@item time +Execution time in 60ths of a second. + +@end table + +You can refer to these values in @value{GDBN} expressions with the usual +conventions; for example, @w{@samp{b fputc if $cycles>5000}} sets a +conditional breakpoint that suspends only after at least 5000 +simulated clock ticks. + +@node Architectures +@section Architectures + +This section describes characteristics of architectures that affect +all uses of @value{GDBN} with the architecture, both native and cross. + +@menu +* A29K:: +* Alpha:: +* MIPS:: +@end menu + +@node A29K +@subsection A29K + +@table @code + +@kindex set rstack_high_address +@cindex AMD 29K register stack +@cindex register stack, AMD29K +@item set rstack_high_address @var{address} +On AMD 29000 family processors, registers are saved in a separate +@dfn{register stack}. There is no way for @value{GDBN} to determine the +extent of this stack. Normally, @value{GDBN} just assumes that the +stack is ``large enough''. This may result in @value{GDBN} referencing +memory locations that do not exist. If necessary, you can get around +this problem by specifying the ending address of the register stack with +the @code{set rstack_high_address} command. The argument should be an +address, which you probably want to precede with @samp{0x} to specify in +hexadecimal. + +@kindex show rstack_high_address +@item show rstack_high_address +Display the current limit of the register stack, on AMD 29000 family +processors. + +@end table + +@node Alpha +@subsection Alpha + +See the following section. + +@node MIPS +@subsection MIPS + +@cindex stack on Alpha +@cindex stack on MIPS +@cindex Alpha stack +@cindex MIPS stack +Alpha- and MIPS-based computers use an unusual stack frame, which +sometimes requires @value{GDBN} to search backward in the object code to +find the beginning of a function. + +@cindex response time, MIPS debugging +To improve response time (especially for embedded applications, where +@value{GDBN} may be restricted to a slow serial line for this search) +you may want to limit the size of this search, using one of these +commands: + +@table @code +@cindex @code{heuristic-fence-post} (Alpha, MIPS) +@item set heuristic-fence-post @var{limit} +Restrict @value{GDBN} to examining at most @var{limit} bytes in its +search for the beginning of a function. A value of @var{0} (the +default) means there is no limit. However, except for @var{0}, the +larger the limit the more bytes @code{heuristic-fence-post} must search +and therefore the longer it takes to run. + +@item show heuristic-fence-post +Display the current limit. +@end table + +@noindent +These commands are available @emph{only} when @value{GDBN} is configured +for debugging programs on Alpha or MIPS processors. + @node Controlling GDB @chapter Controlling @value{GDBN} -You can alter the way @value{GDBN} interacts with you by using -the @code{set} command. For commands controlling how @value{GDBN} displays -data, @pxref{Print Settings, ,Print settings}; other settings are described -here. +You can alter the way @value{GDBN} interacts with you by using the +@code{set} command. For commands controlling how @value{GDBN} displays +data, see @ref{Print Settings, ,Print settings}. Other settings are +described here. @menu * Prompt:: Prompt @@ -8839,9 +12215,10 @@ here. * Screen Size:: Screen size * Numbers:: Numbers * Messages/Warnings:: Optional warnings and messages +* Debugging Output:: Optional messages about internal happenings @end menu -@node Prompt, Editing, Controlling GDB, Controlling GDB +@node Prompt @section Prompt @cindex prompt @@ -8850,10 +12227,10 @@ here. called the @dfn{prompt}. This string is normally @samp{(@value{GDBP})}. You can change the prompt string with the @code{set prompt} command. For instance, when debugging @value{GDBN} with @value{GDBN}, it is useful to change -the prompt in one of the @value{GDBN} sessions so that you can always tell +the prompt in one of the @value{GDBN} sessions so that you can always tell which one you are talking to. -@emph{Note:} @code{set prompt} no longer adds a space for you after the +@emph{Note:} @code{set prompt} does not add a space for you after the prompt you set. This allows you to set a prompt which ends in a space or a prompt that does not. @@ -8867,7 +12244,7 @@ Directs @value{GDBN} to use @var{newprompt} as its prompt string henceforth. Prints a line of the form: @samp{Gdb's prompt is: @var{your-prompt}} @end table -@node Editing, History, Prompt, Controlling GDB +@node Editing @section Command editing @cindex readline @cindex command line editing @@ -8897,7 +12274,7 @@ Disable command line editing. Show whether command line editing is enabled. @end table -@node History, Screen Size, Editing, Controlling GDB +@node History @section Command history @value{GDBN} can keep track of the commands you type during your @@ -8917,7 +12294,8 @@ list, and where it writes the command history from this session when it exits. You can access this list through history expansion or through the history command editing characters listed below. This file defaults to the value of the environment variable @code{GDBHISTFILE}, or to -@file{./.gdb_history} if this variable is not set. +@file{./.gdb_history} (@file{./_gdb_history} on MS-DOS) if this variable +is not set. @cindex history save @kindex set history save @@ -8982,7 +12360,7 @@ These commands display the state of the @value{GDBN} history parameters. @end table @table @code -@kindex show commands +@kindex shows @item show commands Display the last ten commands in the command history. @@ -8993,7 +12371,7 @@ Print ten commands centered on command number @var{n}. Print ten commands just after the commands last printed. @end table -@node Screen Size, Numbers, History, Controlling GDB +@node Screen Size @section Screen size @cindex size of screen @cindex pauses in output @@ -9007,9 +12385,10 @@ determines when to wrap lines of output. Depending on what is being printed, @value{GDBN} tries to break the line at a readable place, rather than simply letting it overflow onto the following line. -Normally @value{GDBN} knows the size of the screen from the termcap data base +Normally @value{GDBN} knows the size of the screen from the terminal +driver software. For example, on Unix @value{GDBN} uses the termcap data base together with the value of the @code{TERM} environment variable and the -@code{stty rows} and @code{stty cols} settings. If this is not correct, +@code{stty rows} and @code{stty cols} settings. If this is not correct, you can override it with the @code{set height} and @code{set width} commands: @@ -9026,26 +12405,27 @@ These @code{set} commands specify a screen height of @var{lpp} lines and a screen width of @var{cpl} characters. The associated @code{show} commands display the current settings. -If you specify a height of zero lines, @value{GDBN} does not pause during -output no matter how long the output is. This is useful if output is to a +If you specify a height of zero lines, @value{GDBN} does not pause during +output no matter how long the output is. This is useful if output is to a file or to an editor buffer. Likewise, you can specify @samp{set width 0} to prevent @value{GDBN} from wrapping its output. @end table -@node Numbers, Messages/Warnings, Screen Size, Controlling GDB +@node Numbers @section Numbers @cindex number representation @cindex entering numbers -You can always enter numbers in octal, decimal, or hexadecimal in @value{GDBN} by -the usual conventions: octal numbers begin with @samp{0}, decimal -numbers end with @samp{.}, and hexadecimal numbers begin with @samp{0x}. -Numbers that begin with none of these are, by default, entered in base -10; likewise, the default display for numbers---when no particular -format is specified---is base 10. You can change the default base for -both input and output with the @code{set radix} command. +You can always enter numbers in octal, decimal, or hexadecimal in +@value{GDBN} by the usual conventions: octal numbers begin with +@samp{0}, decimal numbers end with @samp{.}, and hexadecimal numbers +begin with @samp{0x}. Numbers that begin with none of these are, by +default, entered in base 10; likewise, the default display for +numbers---when no particular format is specified---is base 10. You can +change the default base for both input and output with the @code{set +radix} command. @table @code @kindex set input-radix @@ -9080,13 +12460,13 @@ Display the current default base for numeric input. Display the current default base for numeric display. @end table -@node Messages/Warnings, , Numbers, Controlling GDB +@node Messages/Warnings @section Optional warnings and messages -By default, @value{GDBN} is silent about its inner workings. If you are running -on a slow machine, you may want to use the @code{set verbose} command. -This makes @value{GDBN} tell you when it does a lengthy internal operation, so -you will not think it has crashed. +By default, @value{GDBN} is silent about its inner workings. If you are +running on a slow machine, you may want to use the @code{set verbose} +command. This makes @value{GDBN} tell you when it does a lengthy +internal operation, so you will not think it has crashed. Currently, the messages controlled by @code{set verbose} are those which announce that the symbol table for a source file is being read; @@ -9105,21 +12485,24 @@ Disables @value{GDBN} output of certain informational messages. Displays whether @code{set verbose} is on or off. @end table -By default, if @value{GDBN} encounters bugs in the symbol table of an object -file, it is silent; but if you are debugging a compiler, you may find -this information useful (@pxref{Symbol Errors, ,Errors reading symbol files}). +By default, if @value{GDBN} encounters bugs in the symbol table of an +object file, it is silent; but if you are debugging a compiler, you may +find this information useful (@pxref{Symbol Errors, ,Errors reading +symbol files}). @table @code + @kindex set complaints @item set complaints @var{limit} -Permits @value{GDBN} to output @var{limit} complaints about each type of unusual -symbols before becoming silent about the problem. Set @var{limit} to -zero to suppress all complaints; set it to a large number to prevent -complaints from being suppressed. +Permits @value{GDBN} to output @var{limit} complaints about each type of +unusual symbols before becoming silent about the problem. Set +@var{limit} to zero to suppress all complaints; set it to a large number +to prevent complaints from being suppressed. @kindex show complaints @item show complaints Displays how many symbol complaints @value{GDBN} is permitted to produce. + @end table By default, @value{GDBN} is cautious, and asks what sometimes seems to be a @@ -9136,6 +12519,7 @@ If you are willing to unflinchingly face the consequences of your own commands, you can disable this ``feature'': @table @code + @kindex set confirm @cindex flinching @cindex confirmation @@ -9149,14 +12533,87 @@ Enables confirmation requests (the default). @kindex show confirm @item show confirm Displays state of confirmation requests. + @end table -@node Sequences, Emacs, Controlling GDB, Top +@node Debugging Output +@section Optional messages about internal happenings +@table @code +@kindex set debug arch +@item set debug arch +Turns on or off display of gdbarch debugging info. The default is off +@kindex show debug arch +@item show debug arch +Displays the current state of displaying gdbarch debugging info. +@kindex set debug event +@item set debug event +Turns on or off display of @value{GDBN} event debugging info. The +default is off. +@kindex show debug event +@item show debug event +Displays the current state of displaying @value{GDBN} event debugging +info. +@kindex set debug expression +@item set debug expression +Turns on or off display of @value{GDBN} expression debugging info. The +default is off. +@kindex show debug expression +@item show debug expression +Displays the current state of displaying @value{GDBN} expression +debugging info. +@kindex set debug overload +@item set debug overload +Turns on or off display of @value{GDBN} C@t{++} overload debugging +info. This includes info such as ranking of functions, etc. The default +is off. +@kindex show debug overload +@item show debug overload +Displays the current state of displaying @value{GDBN} C@t{++} overload +debugging info. +@kindex set debug remote +@cindex packets, reporting on stdout +@cindex serial connections, debugging +@item set debug remote +Turns on or off display of reports on all packets sent back and forth across +the serial line to the remote machine. The info is printed on the +@value{GDBN} standard output stream. The default is off. +@kindex show debug remote +@item show debug remote +Displays the state of display of remote packets. +@kindex set debug serial +@item set debug serial +Turns on or off display of @value{GDBN} serial debugging info. The +default is off. +@kindex show debug serial +@item show debug serial +Displays the current state of displaying @value{GDBN} serial debugging +info. +@kindex set debug target +@item set debug target +Turns on or off display of @value{GDBN} target debugging info. This info +includes what is going on at the target level of GDB, as it happens. The +default is off. +@kindex show debug target +@item show debug target +Displays the current state of displaying @value{GDBN} target debugging +info. +@kindex set debug varobj +@item set debug varobj +Turns on or off display of @value{GDBN} variable object debugging +info. The default is off. +@kindex show debug varobj +@item show debug varobj +Displays the current state of displaying @value{GDBN} variable object +debugging info. +@end table + +@node Sequences @chapter Canned Sequences of Commands Aside from breakpoint commands (@pxref{Break Commands, ,Breakpoint -command lists}), @value{GDBN} provides two ways to store sequences of commands -for execution as a unit: user-defined commands and command files. +command lists}), @value{GDBN} provides two ways to store sequences of +commands for execution as a unit: user-defined commands and command +files. @menu * Define:: User-defined commands @@ -9165,33 +12622,36 @@ for execution as a unit: user-defined commands and command files. * Output:: Commands for controlled output @end menu -@node Define, Hooks, Sequences, Sequences +@node Define @section User-defined commands @cindex user-defined command -A @dfn{user-defined command} is a sequence of @value{GDBN} commands to which -you assign a new name as a command. This is done with the @code{define} -command. User commands may accept up to 10 arguments separated by whitespace. -Arguments are accessed within the user command via @var{$arg0@dots{}$arg9}. -A trivial example: +A @dfn{user-defined command} is a sequence of @value{GDBN} commands to +which you assign a new name as a command. This is done with the +@code{define} command. User commands may accept up to 10 arguments +separated by whitespace. Arguments are accessed within the user command +via @var{$arg0@dots{}$arg9}. A trivial example: @smallexample define adder print $arg0 + $arg1 + $arg2 @end smallexample -@noindent To execute the command use: +@noindent +To execute the command use: @smallexample adder 1 2 3 @end smallexample -@noindent This defines the command @code{adder}, which prints the sum of -its three arguments. Note the arguments are text substitutions, so they may +@noindent +This defines the command @code{adder}, which prints the sum of +its three arguments. Note the arguments are text substitutions, so they may reference variables, use complex expressions, or even perform inferior functions calls. @table @code + @kindex define @item define @var{commandname} Define a command named @var{commandname}. If there is already a command @@ -9222,10 +12682,10 @@ evaluates to true. @kindex document @item document @var{commandname} Document the user-defined command @var{commandname}, so that it can be -accessed by @code{help}. The command @var{commandname} must already be -defined. This command reads lines of documentation just as @code{define} -reads the lines of the command definition, ending with @code{end}. -After the @code{document} command is finished, @code{help} on command +accessed by @code{help}. The command @var{commandname} must already be +defined. This command reads lines of documentation just as @code{define} +reads the lines of the command definition, ending with @code{end}. +After the @code{document} command is finished, @code{help} on command @var{commandname} displays the documentation you have written. You may use the @code{document} command again to change the @@ -9240,9 +12700,10 @@ List all user-defined commands, with the first line of the documentation @kindex show user @item show user @itemx show user @var{commandname} -Display the @value{GDBN} commands used to define @var{commandname} (but not its -documentation). If no @var{commandname} is given, display the +Display the @value{GDBN} commands used to define @var{commandname} (but +not its documentation). If no @var{commandname} is given, display the definitions for all user-defined commands. + @end table When user-defined commands are executed, the @@ -9250,25 +12711,44 @@ commands of the definition are not printed. An error in any command stops execution of the user-defined command. If used interactively, commands that would ask for confirmation proceed -without asking when used inside a user-defined command. Many @value{GDBN} -commands that normally print messages to say what they are doing omit the +without asking when used inside a user-defined command. Many @value{GDBN} +commands that normally print messages to say what they are doing omit the messages when used in a user-defined command. -@node Hooks, Command Files, Define, Sequences +@node Hooks @section User-defined command hooks -@cindex command files +@cindex command hooks +@cindex hooks, for commands +@cindex hooks, pre-command -You may define @emph{hooks}, which are a special kind of user-defined +@kindex hook +@kindex hook- +You may define @dfn{hooks}, which are a special kind of user-defined command. Whenever you run the command @samp{foo}, if the user-defined command @samp{hook-foo} exists, it is executed (with no arguments) before that command. +@cindex hooks, post-command +@kindex hookpost +@kindex hookpost- +A hook may also be defined which is run after the command you executed. +Whenever you run the command @samp{foo}, if the user-defined command +@samp{hookpost-foo} exists, it is executed (with no arguments) after +that command. Post-execution hooks may exist simultaneously with +pre-execution hooks, for the same command. + +It is valid for a hook to call the command which it hooks. If this +occurs, the hook is not re-executed, thereby avoiding infinte recursion. + +@c It would be nice if hookpost could be passed a parameter indicating +@c if the command it hooks executed properly or not. FIXME! + +@kindex stop@r{, a pseudo-command} In addition, a pseudo-command, @samp{stop} exists. Defining (@samp{hook-stop}) makes the associated commands execute every time execution stops in your program: before breakpoint commands are run, displays are printed, or the stack frame is printed. -@ifclear BARETARGET For example, to ignore @code{SIGALRM} signals while single-stepping, but treat them normally during normal execution, you could define: @@ -9286,7 +12766,25 @@ define hook-continue handle SIGLARM pass end @end example -@end ifclear + +As a further example, to hook at the begining and end of the @code{echo} +command, and to add extra text to the beginning and end of the message, +you could define: + +@example +define hook-echo +echo <<<--- +end + +define hookpost-echo +echo --->>>\n +end + +(@value{GDBP}) echo Hello World +<<<---Hello World--->>> +(@value{GDBP}) + +@end example You can define a hook for any single-word command in @value{GDBN}, but not for command aliases; you should define a hook for the basic command @@ -9300,28 +12798,45 @@ If an error occurs during the execution of your hook, execution of If you try to define a hook which does not match any known command, you get a warning from the @code{define} command. -@node Command Files, Output, Hooks, Sequences +@node Command Files @section Command files @cindex command files -A command file for @value{GDBN} is a file of lines that are @value{GDBN} -commands. Comments (lines starting with @kbd{#}) may also be included. -An empty line in a command file does nothing; it does not mean to repeat +A command file for @value{GDBN} is a file of lines that are @value{GDBN} +commands. Comments (lines starting with @kbd{#}) may also be included. +An empty line in a command file does nothing; it does not mean to repeat the last command, as it would from the terminal. @cindex init file @cindex @file{.gdbinit} +@cindex @file{gdb.ini} When you start @value{GDBN}, it automatically executes commands from its -@dfn{init files}. These are files named @file{.gdbinit} on Unix, or -@file{gdb.ini} on DOS/Windows. @value{GDBN} reads the init file (if -any) in your home directory, then processes command line options and -operands, and then reads the init file (if any) in the current working -directory. This is so the init file in your home directory can set -options (such as @code{set complaints}) which affect the processing of -the command line options and operands. The init files are not executed -if you use the @samp{-nx} option; @pxref{Mode Options, ,Choosing modes}. - -@ifset GENERIC +@dfn{init files}, normally called @file{.gdbinit}@footnote{The DJGPP +port of @value{GDBN} uses the name @file{gdb.ini} instead, due to the +limitations of file names imposed by DOS filesystems.}. +During startup, @value{GDBN} does the following: + +@enumerate +@item +Reads the init file (if any) in your home directory@footnote{On +DOS/Windows systems, the home directory is the one pointed to by the +@code{HOME} environment variable.}. + +@item +Processes command line options and operands. + +@item +Reads the init file (if any) in the current working directory. + +@item +Reads command files specified by the @samp{-x} option. +@end enumerate + +The init file in your home directory can set options (such as @samp{set +complaints}) that affect subsequent processing of command line options +and operands. Init files are not executed if you use the @samp{-nx} +option (@pxref{Mode Options, ,Choosing modes}). + @cindex init file name On some configurations of @value{GDBN}, the init file is known by a different name (these are typically environments where a specialized @@ -9329,20 +12844,19 @@ form of @value{GDBN} may need to coexist with other forms, hence a different name for the specialized version's init file). These are the environments with special init file names: -@kindex .vxgdbinit +@cindex @file{.vxgdbinit} @itemize @bullet @item -VxWorks (Wind River Systems real-time OS): @samp{.vxgdbinit} +VxWorks (Wind River Systems real-time OS): @file{.vxgdbinit} -@kindex .os68gdbinit +@cindex @file{.os68gdbinit} @item -OS68K (Enea Data Systems real-time OS): @samp{.os68gdbinit} +OS68K (Enea Data Systems real-time OS): @file{.os68gdbinit} -@kindex .esgdbinit +@cindex @file{.esgdbinit} @item -ES-1800 (Ericsson Telecom AB M68000 emulator): @samp{.esgdbinit} +ES-1800 (Ericsson Telecom AB M68000 emulator): @file{.esgdbinit} @end itemize -@end ifset You can also request the execution of a command file with the @code{source} command: @@ -9362,7 +12876,21 @@ without asking when used in a command file. Many @value{GDBN} commands that normally print messages to say what they are doing omit the messages when called from command files. -@node Output, , Command Files, Sequences +@value{GDBN} also accepts command input from standard input. In this +mode, normal output goes to standard output and error output goes to +standard error. Errors in a command file supplied on standard input do +not terminate execution of the command file --- execution continues with +the next command. + +@example +gdb < cmds > log 2>&1 +@end example + +(The syntax above will vary depending on the shell used.) This example +will execute commands from the file @file{cmds}. All output and errors +would be directed to @file{log}. + +@node Output @section Commands for controlled output During the execution of a command file or a user-defined command, normal @@ -9382,7 +12910,7 @@ newline. @strong{No newline is printed unless you specify one.} In addition to the standard C escape sequences, a backslash followed by a space stands for a space. This is useful for displaying a string with spaces at the beginning or the end, since leading and -trailing spaces are otherwise trimmed from all arguments. +trailing spaces are otherwise trimmed from all arguments. To print @samp{@w{ }and foo =@w{ }}, use the command @samp{echo \@w{ }and foo = \@w{ }}. @@ -9407,7 +12935,7 @@ echo onto several lines.\n @item output @var{expression} Print the value of @var{expression} and nothing but that value: no newlines, no @samp{$@var{nn} = }. The value is not entered in the -value history either. @xref{Expressions, ,Expressions}, for more information +value history either. @xref{Expressions, ,Expressions}, for more information on expressions. @item output/@var{fmt} @var{expression} @@ -9422,6 +12950,10 @@ Print the values of the @var{expressions} under the control of either numbers or pointers. Their values are printed as specified by @var{string}, exactly as if your program were to execute the C subroutine +@c FIXME: the above implies that at least all ANSI C formats are +@c supported, but it isn't true: %E and %G don't work (or so it seems). +@c Either this is a bug, or the manual should document what formats are +@c supported. @example printf (@var{string}, @var{expressions}@dots{}); @@ -9438,8 +12970,291 @@ string are the simple ones that consist of backslash followed by a letter. @end table -@ifclear DOSHOST -@node Emacs, GDB Bugs, Sequences, Top +@node TUI +@chapter @value{GDBN} Text User Interface +@cindex TUI + +@menu +* TUI Overview:: TUI overview +* TUI Keys:: TUI key bindings +* TUI Commands:: TUI specific commands +* TUI Configuration:: TUI configuration variables +@end menu + +The @value{GDBN} Text User Interface, TUI in short, +is a terminal interface which uses the @code{curses} library +to show the source file, the assembly output, the program registers +and @value{GDBN} commands in separate text windows. +The TUI is available only when @value{GDBN} is configured +with the @code{--enable-tui} configure option (@pxref{Configure Options}). + +@node TUI Overview +@section TUI overview + +The TUI has two display modes that can be switched while +@value{GDBN} runs: + +@itemize @bullet +@item +A curses (or TUI) mode in which it displays several text +windows on the terminal. + +@item +A standard mode which corresponds to the @value{GDBN} configured without +the TUI. +@end itemize + +In the TUI mode, @value{GDBN} can display several text window +on the terminal: + +@table @emph +@item command +This window is the @value{GDBN} command window with the @value{GDBN} +prompt and the @value{GDBN} outputs. The @value{GDBN} input is still +managed using readline but through the TUI. The @emph{command} +window is always visible. + +@item source +The source window shows the source file of the program. The current +line as well as active breakpoints are displayed in this window. +The current program position is shown with the @samp{>} marker and +active breakpoints are shown with @samp{*} markers. + +@item assembly +The assembly window shows the disassembly output of the program. + +@item register +This window shows the processor registers. It detects when +a register is changed and when this is the case, registers that have +changed are highlighted. + +@end table + +The source, assembly and register windows are attached to the thread +and the frame position. They are updated when the current thread +changes, when the frame changes or when the program counter changes. +These three windows are arranged by the TUI according to several +layouts. The layout defines which of these three windows are visible. +The following layouts are available: + +@itemize @bullet +@item +source + +@item +assembly + +@item +source and assembly + +@item +source and registers + +@item +assembly and registers + +@end itemize + +@node TUI Keys +@section TUI Key Bindings +@cindex TUI key bindings + +The TUI installs several key bindings in the readline keymaps +(@pxref{Command Line Editing}). +They allow to leave or enter in the TUI mode or they operate +directly on the TUI layout and windows. The following key bindings +are installed for both TUI mode and the @value{GDBN} standard mode. + +@table @kbd +@kindex C-x C-a +@item C-x C-a +@kindex C-x a +@itemx C-x a +@kindex C-x A +@itemx C-x A +Enter or leave the TUI mode. When the TUI mode is left, +the curses window management is left and @value{GDBN} operates using +its standard mode writing on the terminal directly. When the TUI +mode is entered, the control is given back to the curses windows. +The screen is then refreshed. + +@kindex C-x 1 +@item C-x 1 +Use a TUI layout with only one window. The layout will +either be @samp{source} or @samp{assembly}. When the TUI mode +is not active, it will switch to the TUI mode. + +Think of this key binding as the Emacs @kbd{C-x 1} binding. + +@kindex C-x 2 +@item C-x 2 +Use a TUI layout with at least two windows. When the current +layout shows already two windows, a next layout with two windows is used. +When a new layout is chosen, one window will always be common to the +previous layout and the new one. + +Think of it as the Emacs @kbd{C-x 2} binding. + +@end table + +The following key bindings are handled only by the TUI mode: + +@table @key +@kindex PgUp +@item PgUp +Scroll the active window one page up. + +@kindex PgDn +@item PgDn +Scroll the active window one page down. + +@kindex Up +@item Up +Scroll the active window one line up. + +@kindex Down +@item Down +Scroll the active window one line down. + +@kindex Left +@item Left +Scroll the active window one column left. + +@kindex Right +@item Right +Scroll the active window one column right. + +@kindex C-L +@item C-L +Refresh the screen. + +@end table + +In the TUI mode, the arrow keys are used by the active window +for scrolling. This means they are not available for readline. It is +necessary to use other readline key bindings such as @key{C-p}, @key{C-n}, +@key{C-b} and @key{C-f}. + +@node TUI Commands +@section TUI specific commands +@cindex TUI commands + +The TUI has specific commands to control the text windows. +These commands are always available, that is they do not depend on +the current terminal mode in which @value{GDBN} runs. When @value{GDBN} +is in the standard mode, using these commands will automatically switch +in the TUI mode. + +@table @code +@item layout next +@kindex layout next +Display the next layout. + +@item layout prev +@kindex layout prev +Display the previous layout. + +@item layout src +@kindex layout src +Display the source window only. + +@item layout asm +@kindex layout asm +Display the assembly window only. + +@item layout split +@kindex layout split +Display the source and assembly window. + +@item layout regs +@kindex layout regs +Display the register window together with the source or assembly window. + +@item focus next | prev | src | asm | regs | split +@kindex focus +Set the focus to the named window. +This command allows to change the active window so that scrolling keys +can be affected to another window. + +@item refresh +@kindex refresh +Refresh the screen. This is similar to using @key{C-L} key. + +@item update +@kindex update +Update the source window and the current execution point. + +@item winheight @var{name} +@var{count} +@itemx winheight @var{name} -@var{count} +@kindex winheight +Change the height of the window @var{name} by @var{count} +lines. Positive counts increase the height, while negative counts +decrease it. + +@end table + +@node TUI Configuration +@section TUI configuration variables +@cindex TUI configuration variables + +The TUI has several configuration variables that control the +appearance of windows on the terminal. + +@table @code +@item set tui border-kind @var{kind} +@kindex set tui border-kind +Select the border appearance for the source, assembly and register windows. +The possible values are the following: +@table @code +@item space +Use a space character to draw the border. + +@item ascii +Use ascii characters + - and | to draw the border. + +@item acs +Use the Alternate Character Set to draw the border. The border is +drawn using character line graphics if the terminal supports them. + +@end table + +@item set tui active-border-mode @var{mode} +@kindex set tui active-border-mode +Select the attributes to display the border of the active window. +The possible values are @code{normal}, @code{standout}, @code{reverse}, +@code{half}, @code{half-standout}, @code{bold} and @code{bold-standout}. + +@item set tui border-mode @var{mode} +@kindex set tui border-mode +Select the attributes to display the border of other windows. +The @var{mode} can be one of the following: +@table @code +@item normal +Use normal attributes to display the border. + +@item standout +Use standout mode. + +@item reverse +Use reverse video mode. + +@item half +Use half bright mode. + +@item half-standout +Use half bright and standout mode. + +@item bold +Use extra bright or bold mode. + +@item bold-standout +Use extra bright or bold and standout mode. + +@end table + +@end table + +@node Emacs @chapter Using @value{GDBN} under @sc{gnu} Emacs @cindex Emacs @@ -9452,9 +13267,7 @@ To use this interface, use the command @kbd{M-x gdb} in Emacs. Give the executable file you want to debug as an argument. This command starts @value{GDBN} as a subprocess of Emacs, with input and output through a newly created Emacs buffer. -@ifset HPPA -(Do not use the @code{-tui} option to run @value{GDBN} from Emacs.) -@end ifset +@c (Do not use the @code{-tui} option to run @value{GDBN} from Emacs.) Using @value{GDBN} under Emacs is just like using @value{GDBN} normally except for two things: @@ -9517,7 +13330,7 @@ Emacs variable @code{gdb-command-name}; for example, @end example @noindent -(preceded by @kbd{ESC ESC}, or typed in the @code{*scratch*} buffer, or +(preceded by @kbd{M-:} or @kbd{ESC :}, or typed in the @code{*scratch*} buffer, or in your @file{.emacs} file) makes Emacs call the program named ``@code{mygdb}'' instead. @@ -9608,17 +13421,17 @@ to correspond properly with the code. @kindex Epoch @kindex inspect -Version 18 of @sc{gnu} Emacs has a built-in window system +Version 18 of @sc{gnu} Emacs has a built-in window system called the @code{epoch} environment. Users of this environment can use a new command, @code{inspect} which performs identically to @code{print} except that each value is printed in its own window. @end ignore -@end ifclear + +@include annotate.texi +@include gdbmi.texinfo @node GDB Bugs -@c links whacked to pacify makeinfo -@c , Command Line Editing, Emacs, Top @chapter Reporting Bugs in @value{GDBN} @cindex bugs in @value{GDBN} @cindex reporting bugs in @value{GDBN} @@ -9638,7 +13451,7 @@ information that enables us to fix the bug. * Bug Reporting:: How to report bugs @end menu -@node Bug Criteria, Bug Reporting, GDB Bugs, GDB Bugs +@node Bug Criteria @section Have you found a bug? @cindex bug criteria @@ -9670,12 +13483,11 @@ If you are an experienced user of debugging tools, your suggestions for improvement of @value{GDBN} are welcome in any case. @end itemize -@node Bug Reporting, , Bug Criteria, GDB Bugs +@node Bug Reporting @section How to report bugs @cindex bug reports @cindex @value{GDBN} bugs, reporting -@ifclear HPPA A number of companies and individuals offer support for @sc{gnu} products. If you obtained @value{GDBN} from a support organization, we recommend you contact that organization first. @@ -9685,15 +13497,14 @@ individuals in the file @file{etc/SERVICE} in the @sc{gnu} Emacs distribution. @c should add a web page ref... -In any event, we also recommend that you send bug reports for -@value{GDBN} to this addresses: - -@example -bug-gdb@@prep.ai.mit.edu -@end example +In any event, we also recommend that you submit bug reports for +@value{GDBN}. The prefered method is to submit them directly using +@uref{http://www.gnu.org/software/gdb/bugs/, @value{GDBN}'s Bugs web +page}. Alternatively, the @email{bug-gdb@@gnu.org, e-mail gateway} can +be used. @strong{Do not send bug reports to @samp{info-gdb}, or to -@samp{help-gdb}, or to any newsgroups.} Most users of @value{GDBN} do +@samp{help-gdb}, or to any newsgroups.} Most users of @value{GDBN} do not want to receive bug reports. Those that do have arranged to receive @samp{bug-gdb}. @@ -9706,25 +13517,6 @@ path back to the sender. Thus, if we need to ask for more information, we may be unable to reach you. For this reason, it is better to send bug reports to the mailing list. -As a last resort, send bug reports on paper to: - -@example -@sc{gnu} Debugger Bugs -Free Software Foundation Inc. -59 Temple Place - Suite 330 -Boston, MA 02111-1307 -USA -@end example -@end ifclear - -@ifset HPPA -If you obtained HP GDB as part of your HP ANSI C or HP ANSI C++ compiler -kit, report problems to your HP Support Representative. - -If you obtained HP GDB from the Hewlett-Packard Web site, report -problems by electronic mail to @code{wdb-www@@ch.hp.com}. -@end ifset - The fundamental principle of reporting bugs usefully is this: @strong{report all the facts}. If you are not sure whether to state a fact or leave it out, state it! @@ -9764,11 +13556,9 @@ the bug in the current version of @value{GDBN}. The type of machine you are using, and the operating system name and version number. -@ifclear HPPA @item What compiler (and its version) was used to compile @value{GDBN}---e.g. ``@value{GCC}--2.8.1''. -@end ifclear @item What compiler (and its version) was used to compile the program you are @@ -9808,7 +13598,6 @@ ours fails to crash, we would know that the bug was not happening for us. If you had not told us to expect a crash, then we would not be able to draw any conclusion from our observations. -@ifclear HPPA @item If you wish to suggest changes to the @value{GDBN} source, send us context diffs. If you even discuss something in the @value{GDBN} source, refer to @@ -9816,7 +13605,7 @@ it by context, not by line number. The line numbers in our development sources will not match those in your sources. Your line numbers would convey no useful information to us. -@end ifclear + @end itemize Here are some things that are not necessary: @@ -9866,21 +13655,17 @@ Such guesses are usually wrong. Even we cannot guess right about such things without first using the debugger to find the facts. @end itemize -@c The readline documentation is distributed with the readline code +@c The readline documentation is distributed with the readline code @c and consists of the two following files: @c rluser.texinfo -@c inc-hist.texi +@c inc-hist.texinfo @c Use -I with makeinfo to point to the appropriate directory, @c environment var TEXINPUTS with TeX. @include rluser.texinfo -@include inc-hist.texi +@include inc-hist.texinfo -@ifclear PRECONFIGURED -@ifclear HPPA @node Formatting Documentation -@c links whacked to pacify makeinfo -@c , Installing GDB, Renamed Commands, Top @appendix Formatting Documentation @cindex @value{GDBN} reference card @@ -9899,8 +13684,8 @@ can format it, using @TeX{}, by typing: make refcard.dvi @end example -The @value{GDBN} reference card is designed to print in @dfn{landscape} -mode on US ``letter'' size paper; +The @value{GDBN} reference card is designed to print in @dfn{landscape} +mode on US ``letter'' size paper; that is, on a sheet 11 inches wide by 8.5 inches high. You will need to specify this form of printing as an option to your @sc{dvi} output program. @@ -9965,43 +13750,12 @@ make gdb.dvi @end example Then give @file{gdb.dvi} to your @sc{dvi} printing program. -@end ifclear -@node Installing GDB, Index, Using History Interactively, Top +@node Installing GDB @appendix Installing @value{GDBN} @cindex configuring @value{GDBN} @cindex installation -@ifset HPPA -If you obtain @value{GDBN} (HP WDB 0.75) as part of your HP ANSI C or -HP ANSI C++ Developer's Kit at HP-UX Release 11.0, you do not have to -take any special action to build or install @value{GDBN}. - -If you obtain @value{GDBN} (HP WDB 0.75) from an HP web site, you may -download either a @code{swinstall}-able package or a source tree, or -both. - -Most customers will want to install the @value{GDBN} binary that is part -of the @code{swinstall}-able package. To do so, use a command of the -form - -@smallexample -/usr/sbin/swinstall -s @var{package-name} WDB -@end smallexample - -Alternatively, it is possible to build @value{GDBN} from the source -distribution. Sophisticated customers who want to modify the debugger -sources to tailor @value{GDBN} to their their needs may wish to do this. -The source distribution consists of a @code{tar}'ed source tree rooted -at @file{gdb-4.16/...}. The instructions that follow describe how to -build a @file{gdb} executable from this source tree. HP believes that -these instructions apply to the WDB source tree that it distributes. -However, HP does not explicitly support building a @file{gdb} for any -non-HP platform from the WDB source tree. It may work, but HP has not -tested it for any platforms other than those described in the WDB 0.75 -Release Notes. -@end ifset - @value{GDBN} comes with a @code{configure} script that automates the process of preparing @value{GDBN} for installation; you can then use @code{make} to build the @code{gdb} program. @@ -10012,8 +13766,8 @@ look at the @file{README} file in the sources; we may have improved the installation procedures since publishing this manual.} @end iftex -The @value{GDBN} distribution includes all the source code you need for -@value{GDBN} in a single directory, whose name is usually composed by +The @value{GDBN} distribution includes all the source code you need for +@value{GDBN} in a single directory, whose name is usually composed by appending the version number to @samp{gdb}. For example, the @value{GDBN} version @value{GDBVN} distribution is in the @@ -10117,7 +13871,7 @@ let @value{GDBN} debug child processes whose programs are not readable. * Configure Options:: Summary of options for configure @end menu -@node Separate Objdir, Config Names, Installing GDB, Installing GDB +@node Separate Objdir @section Compiling @value{GDBN} in another directory If you want to run @value{GDBN} versions for several host or target machines, @@ -10136,7 +13890,7 @@ itself from your working directory. If the path to @code{configure} would be the same as the argument to @samp{--srcdir}, you can leave out the @samp{--srcdir} option; it is assumed.) -For example, with version @value{GDBVN}, you can build @value{GDBN} in a +For example, with version @value{GDBVN}, you can build @value{GDBN} in a separate directory for a Sun 4 like this: @example @@ -10157,9 +13911,9 @@ directory @file{gdb-sun4/libiberty}, and @value{GDBN} itself in @file{gdb-sun4/gdb}. One popular reason to build several @value{GDBN} configurations in separate -directories is to configure @value{GDBN} for cross-compiling (where -@value{GDBN} runs on one machine---the @dfn{host}---while debugging -programs that run on another machine---the @dfn{target}). +directories is to configure @value{GDBN} for cross-compiling (where +@value{GDBN} runs on one machine---the @dfn{host}---while debugging +programs that run on another machine---the @dfn{target}). You specify a cross-debugging target by giving the @samp{--target=@var{target}} option to @code{configure}. @@ -10178,7 +13932,7 @@ directories, you can run @code{make} on them in parallel (for example, if they are NFS-mounted on each of the hosts); they will not interfere with each other. -@node Config Names, Configure Options, Separate Objdir, Installing GDB +@node Config Names @section Specifying names for hosts and targets The specifications used for hosts and targets in the @code{configure} @@ -10220,7 +13974,7 @@ Invalid configuration `i986v': machine `i986v' not recognized @code{config.sub} is also distributed in the @value{GDBN} source directory (@file{gdb-@value{GDBVN}}, for version @value{GDBVN}). -@node Configure Options, , Config Names, Installing GDB +@node Configure Options @section @code{configure} options Here is a summary of the @code{configure} options and arguments that @@ -10288,10 +14042,907 @@ There is no convenient way to generate a list of all available hosts. There are many other options available as well, but they are generally needed for special purposes only. -@end ifclear - -@node Index, , Installing GDB, Top +@node Maintenance Commands +@appendix Maintenance Commands +@cindex maintenance commands +@cindex internal commands + +In addition to commands intended for @value{GDBN} users, @value{GDBN} +includes a number of commands intended for @value{GDBN} developers. +These commands are provided here for reference. + +@table @code +@kindex maint info breakpoints +@item @anchor{maint info breakpoints}maint info breakpoints +Using the same format as @samp{info breakpoints}, display both the +breakpoints you've set explicitly, and those @value{GDBN} is using for +internal purposes. Internal breakpoints are shown with negative +breakpoint numbers. The type column identifies what kind of breakpoint +is shown: + +@table @code +@item breakpoint +Normal, explicitly set breakpoint. + +@item watchpoint +Normal, explicitly set watchpoint. + +@item longjmp +Internal breakpoint, used to handle correctly stepping through +@code{longjmp} calls. + +@item longjmp resume +Internal breakpoint at the target of a @code{longjmp}. + +@item until +Temporary internal breakpoint used by the @value{GDBN} @code{until} command. + +@item finish +Temporary internal breakpoint used by the @value{GDBN} @code{finish} command. + +@item shlib events +Shared library events. + +@end table + +@end table + + +@node Remote Protocol +@appendix @value{GDBN} Remote Serial Protocol + +There may be occasions when you need to know something about the +protocol---for example, if there is only one serial port to your target +machine, you might want your program to do something special if it +recognizes a packet meant for @value{GDBN}. + +In the examples below, @samp{<-} and @samp{->} are used to indicate +transmitted and received data respectfully. + +@cindex protocol, @value{GDBN} remote serial +@cindex serial protocol, @value{GDBN} remote +@cindex remote serial protocol +All @value{GDBN} commands and responses (other than acknowledgments) are +sent as a @var{packet}. A @var{packet} is introduced with the character +@samp{$}, the actual @var{packet-data}, and the terminating character +@samp{#} followed by a two-digit @var{checksum}: + +@example +@code{$}@var{packet-data}@code{#}@var{checksum} +@end example +@noindent + +@cindex checksum, for @value{GDBN} remote +@noindent +The two-digit @var{checksum} is computed as the modulo 256 sum of all +characters between the leading @samp{$} and the trailing @samp{#} (an +eight bit unsigned checksum). + +Implementors should note that prior to @value{GDBN} 5.0 the protocol +specification also included an optional two-digit @var{sequence-id}: + +@example +@code{$}@var{sequence-id}@code{:}@var{packet-data}@code{#}@var{checksum} +@end example + +@cindex sequence-id, for @value{GDBN} remote +@noindent +That @var{sequence-id} was appended to the acknowledgment. @value{GDBN} +has never output @var{sequence-id}s. Stubs that handle packets added +since @value{GDBN} 5.0 must not accept @var{sequence-id}. + +@cindex acknowledgment, for @value{GDBN} remote +When either the host or the target machine receives a packet, the first +response expected is an acknowledgment: either @samp{+} (to indicate +the package was received correctly) or @samp{-} (to request +retransmission): + +@example +<- @code{$}@var{packet-data}@code{#}@var{checksum} +-> @code{+} +@end example +@noindent + +The host (@value{GDBN}) sends @var{command}s, and the target (the +debugging stub incorporated in your program) sends a @var{response}. In +the case of step and continue @var{command}s, the response is only sent +when the operation has completed (the target has again stopped). + +@var{packet-data} consists of a sequence of characters with the +exception of @samp{#} and @samp{$} (see @samp{X} packet for additional +exceptions). + +Fields within the packet should be separated using @samp{,} @samp{;} or +@samp{:}. Except where otherwise noted all numbers are represented in +HEX with leading zeros suppressed. + +Implementors should note that prior to @value{GDBN} 5.0, the character +@samp{:} could not appear as the third character in a packet (as it +would potentially conflict with the @var{sequence-id}). + +Response @var{data} can be run-length encoded to save space. A @samp{*} +means that the next character is an @sc{ascii} encoding giving a repeat count +which stands for that many repetitions of the character preceding the +@samp{*}. The encoding is @code{n+29}, yielding a printable character +where @code{n >=3} (which is where rle starts to win). The printable +characters @samp{$}, @samp{#}, @samp{+} and @samp{-} or with a numeric +value greater than 126 should not be used. + +Some remote systems have used a different run-length encoding mechanism +loosely refered to as the cisco encoding. Following the @samp{*} +character are two hex digits that indicate the size of the packet. + +So: +@example +"@code{0* }" +@end example +@noindent +means the same as "0000". + +The error response returned for some packets includes a two character +error number. That number is not well defined. + +For any @var{command} not supported by the stub, an empty response +(@samp{$#00}) should be returned. That way it is possible to extend the +protocol. A newer @value{GDBN} can tell if a packet is supported based +on that response. + +A stub is required to support the @samp{g}, @samp{G}, @samp{m}, @samp{M}, +@samp{c}, and @samp{s} @var{command}s. All other @var{command}s are +optional. + +Below is a complete list of all currently defined @var{command}s and +their corresponding response @var{data}: +@page +@multitable @columnfractions .30 .30 .40 +@item Packet +@tab Request +@tab Description + +@item extended mode +@tab @code{!} +@tab +Enable extended mode. In extended mode, the remote server is made +persistent. The @samp{R} packet is used to restart the program being +debugged. +@item +@tab reply @samp{OK} +@tab +The remote target both supports and has enabled extended mode. + +@item last signal +@tab @code{?} +@tab +Indicate the reason the target halted. The reply is the same as for step +and continue. +@item +@tab reply +@tab see below + + +@item reserved +@tab @code{a} +@tab Reserved for future use + +@item set program arguments @strong{(reserved)} +@tab @code{A}@var{arglen}@code{,}@var{argnum}@code{,}@var{arg}@code{,...} +@tab +@item +@tab +@tab +Initialized @samp{argv[]} array passed into program. @var{arglen} +specifies the number of bytes in the hex encoded byte stream @var{arg}. +See @file{gdbserver} for more details. +@item +@tab reply @code{OK} +@item +@tab reply @code{E}@var{NN} + +@item set baud @strong{(deprecated)} +@tab @code{b}@var{baud} +@tab +Change the serial line speed to @var{baud}. JTC: @emph{When does the +transport layer state change? When it's received, or after the ACK is +transmitted. In either case, there are problems if the command or the +acknowledgment packet is dropped.} Stan: @emph{If people really wanted +to add something like this, and get it working for the first time, they +ought to modify ser-unix.c to send some kind of out-of-band message to a +specially-setup stub and have the switch happen "in between" packets, so +that from remote protocol's point of view, nothing actually +happened.} + +@item set breakpoint @strong{(deprecated)} +@tab @code{B}@var{addr},@var{mode} +@tab +Set (@var{mode} is @samp{S}) or clear (@var{mode} is @samp{C}) a +breakpoint at @var{addr}. @emph{This has been replaced by the @samp{Z} and +@samp{z} packets.} + +@item continue +@tab @code{c}@var{addr} +@tab +@var{addr} is address to resume. If @var{addr} is omitted, resume at +current address. +@item +@tab reply +@tab see below + +@item continue with signal +@tab @code{C}@var{sig}@code{;}@var{addr} +@tab +Continue with signal @var{sig} (hex signal number). If +@code{;}@var{addr} is omitted, resume at same address. +@item +@tab reply +@tab see below + +@item toggle debug @strong{(deprecated)} +@tab @code{d} +@tab +toggle debug flag. + +@item detach +@tab @code{D} +@tab +Detach @value{GDBN} from the remote system. Sent to the remote target before +@value{GDBN} disconnects. +@item +@tab reply @emph{no response} +@tab +@value{GDBN} does not check for any response after sending this packet. + +@item reserved +@tab @code{e} +@tab Reserved for future use + +@item reserved +@tab @code{E} +@tab Reserved for future use + +@item reserved +@tab @code{f} +@tab Reserved for future use + +@item reserved +@tab @code{F} +@tab Reserved for future use + +@item read registers +@tab @code{g} +@tab Read general registers. +@item +@tab reply @var{XX...} +@tab +Each byte of register data is described by two hex digits. The bytes +with the register are transmitted in target byte order. The size of +each register and their position within the @samp{g} @var{packet} are +determined by the @value{GDBN} internal macros @var{REGISTER_RAW_SIZE} and +@var{REGISTER_NAME} macros. The specification of several standard +@code{g} packets is specified below. +@item +@tab @code{E}@var{NN} +@tab for an error. + +@item write regs +@tab @code{G}@var{XX...} +@tab +See @samp{g} for a description of the @var{XX...} data. +@item +@tab reply @code{OK} +@tab for success +@item +@tab reply @code{E}@var{NN} +@tab for an error + +@item reserved +@tab @code{h} +@tab Reserved for future use + +@item set thread +@tab @code{H}@var{c}@var{t...} +@tab +Set thread for subsequent operations (@samp{m}, @samp{M}, @samp{g}, +@samp{G}, et.al.). @var{c} = @samp{c} for thread used in step and +continue; @var{t...} can be -1 for all threads. @var{c} = @samp{g} for +thread used in other operations. If zero, pick a thread, any thread. +@item +@tab reply @code{OK} +@tab for success +@item +@tab reply @code{E}@var{NN} +@tab for an error + +@c FIXME: JTC: +@c 'H': How restrictive (or permissive) is the thread model. If a +@c thread is selected and stopped, are other threads allowed +@c to continue to execute? As I mentioned above, I think the +@c semantics of each command when a thread is selected must be +@c described. For example: +@c +@c 'g': If the stub supports threads and a specific thread is +@c selected, returns the register block from that thread; +@c otherwise returns current registers. +@c +@c 'G' If the stub supports threads and a specific thread is +@c selected, sets the registers of the register block of +@c that thread; otherwise sets current registers. + +@item cycle step @strong{(draft)} +@tab @code{i}@var{addr}@code{,}@var{nnn} +@tab +Step the remote target by a single clock cycle. If @code{,}@var{nnn} is +present, cycle step @var{nnn} cycles. If @var{addr} is present, cycle +step starting at that address. + +@item signal then cycle step @strong{(reserved)} +@tab @code{I} +@tab +See @samp{i} and @samp{S} for likely syntax and semantics. + +@item reserved +@tab @code{j} +@tab Reserved for future use + +@item reserved +@tab @code{J} +@tab Reserved for future use + +@item kill request +@tab @code{k} +@tab +FIXME: @emph{There is no description of how to operate when a specific +thread context has been selected (i.e.@: does 'k' kill only that thread?)}. + +@item reserved +@tab @code{l} +@tab Reserved for future use + +@item reserved +@tab @code{L} +@tab Reserved for future use + +@item read memory +@tab @code{m}@var{addr}@code{,}@var{length} +@tab +Read @var{length} bytes of memory starting at address @var{addr}. +Neither @value{GDBN} nor the stub assume that sized memory transfers are assumed +using word alligned accesses. FIXME: @emph{A word aligned memory +transfer mechanism is needed.} +@item +@tab reply @var{XX...} +@tab +@var{XX...} is mem contents. Can be fewer bytes than requested if able +to read only part of the data. Neither @value{GDBN} nor the stub assume that +sized memory transfers are assumed using word alligned accesses. FIXME: +@emph{A word aligned memory transfer mechanism is needed.} +@item +@tab reply @code{E}@var{NN} +@tab @var{NN} is errno + +@item write mem +@tab @code{M}@var{addr},@var{length}@code{:}@var{XX...} +@tab +Write @var{length} bytes of memory starting at address @var{addr}. +@var{XX...} is the data. +@item +@tab reply @code{OK} +@tab for success +@item +@tab reply @code{E}@var{NN} +@tab +for an error (this includes the case where only part of the data was +written). + +@item reserved +@tab @code{n} +@tab Reserved for future use + +@item reserved +@tab @code{N} +@tab Reserved for future use + +@item reserved +@tab @code{o} +@tab Reserved for future use + +@item reserved +@tab @code{O} +@tab Reserved for future use + +@item read reg @strong{(reserved)} +@tab @code{p}@var{n...} +@tab +See write register. +@item +@tab return @var{r....} +@tab The hex encoded value of the register in target byte order. + +@item write reg +@tab @code{P}@var{n...}@code{=}@var{r...} +@tab +Write register @var{n...} with value @var{r...}, which contains two hex +digits for each byte in the register (target byte order). +@item +@tab reply @code{OK} +@tab for success +@item +@tab reply @code{E}@var{NN} +@tab for an error + +@item general query +@tab @code{q}@var{query} +@tab +Request info about @var{query}. In general @value{GDBN} queries +have a leading upper case letter. Custom vendor queries should use a +company prefix (in lower case) ex: @samp{qfsf.var}. @var{query} may +optionally be followed by a @samp{,} or @samp{;} separated list. Stubs +must ensure that they match the full @var{query} name. +@item +@tab reply @code{XX...} +@tab Hex encoded data from query. The reply can not be empty. +@item +@tab reply @code{E}@var{NN} +@tab error reply +@item +@tab reply @samp{} +@tab Indicating an unrecognized @var{query}. + +@item general set +@tab @code{Q}@var{var}@code{=}@var{val} +@tab +Set value of @var{var} to @var{val}. See @samp{q} for a discussing of +naming conventions. + +@item reset @strong{(deprecated)} +@tab @code{r} +@tab +Reset the entire system. + +@item remote restart +@tab @code{R}@var{XX} +@tab +Restart the program being debugged. @var{XX}, while needed, is ignored. +This packet is only available in extended mode. +@item +@tab +no reply +@tab +The @samp{R} packet has no reply. + +@item step +@tab @code{s}@var{addr} +@tab +@var{addr} is address to resume. If @var{addr} is omitted, resume at +same address. +@item +@tab reply +@tab see below + +@item step with signal +@tab @code{S}@var{sig}@code{;}@var{addr} +@tab +Like @samp{C} but step not continue. +@item +@tab reply +@tab see below + +@item search +@tab @code{t}@var{addr}@code{:}@var{PP}@code{,}@var{MM} +@tab +Search backwards starting at address @var{addr} for a match with pattern +@var{PP} and mask @var{MM}. @var{PP} and @var{MM} are 4 +bytes. @var{addr} must be at least 3 digits. + +@item thread alive +@tab @code{T}@var{XX} +@tab Find out if the thread XX is alive. +@item +@tab reply @code{OK} +@tab thread is still alive +@item +@tab reply @code{E}@var{NN} +@tab thread is dead + +@item reserved +@tab @code{u} +@tab Reserved for future use + +@item reserved +@tab @code{U} +@tab Reserved for future use + +@item reserved +@tab @code{v} +@tab Reserved for future use + +@item reserved +@tab @code{V} +@tab Reserved for future use + +@item reserved +@tab @code{w} +@tab Reserved for future use + +@item reserved +@tab @code{W} +@tab Reserved for future use + +@item reserved +@tab @code{x} +@tab Reserved for future use + +@item write mem (binary) +@tab @code{X}@var{addr}@code{,}@var{length}@var{:}@var{XX...} +@tab +@var{addr} is address, @var{length} is number of bytes, @var{XX...} is +binary data. The characters @code{$}, @code{#}, and @code{0x7d} are +escaped using @code{0x7d}. +@item +@tab reply @code{OK} +@tab for success +@item +@tab reply @code{E}@var{NN} +@tab for an error + +@item reserved +@tab @code{y} +@tab Reserved for future use + +@item reserved +@tab @code{Y} +@tab Reserved for future use + +@item remove break or watchpoint @strong{(draft)} +@tab @code{z}@var{t}@code{,}@var{addr}@code{,}@var{length} +@tab +See @samp{Z}. + +@item insert break or watchpoint @strong{(draft)} +@tab @code{Z}@var{t}@code{,}@var{addr}@code{,}@var{length} +@tab +@var{t} is type: @samp{0} - software breakpoint, @samp{1} - hardware +breakpoint, @samp{2} - write watchpoint, @samp{3} - read watchpoint, +@samp{4} - access watchpoint; @var{addr} is address; @var{length} is in +bytes. For a software breakpoint, @var{length} specifies the size of +the instruction to be patched. For hardware breakpoints and watchpoints +@var{length} specifies the memory region to be monitored. To avoid +potential problems with duplicate packets, the operations should be +implemented in an idempotent way. +@item +@tab reply @code{E}@var{NN} +@tab for an error +@item +@tab reply @code{OK} +@tab for success +@item +@tab @samp{} +@tab If not supported. + +@item reserved +@tab <other> +@tab Reserved for future use + +@end multitable + +The @samp{C}, @samp{c}, @samp{S}, @samp{s} and @samp{?} packets can +receive any of the below as a reply. In the case of the @samp{C}, +@samp{c}, @samp{S} and @samp{s} packets, that reply is only returned +when the target halts. In the below the exact meaning of @samp{signal +number} is poorly defined. In general one of the UNIX signal numbering +conventions is used. + +@multitable @columnfractions .4 .6 + +@item @code{S}@var{AA} +@tab @var{AA} is the signal number + +@item @code{T}@var{AA}@var{n...}@code{:}@var{r...}@code{;}@var{n...}@code{:}@var{r...}@code{;}@var{n...}@code{:}@var{r...}@code{;} +@tab +@var{AA} = two hex digit signal number; @var{n...} = register number +(hex), @var{r...} = target byte ordered register contents, size defined +by @code{REGISTER_RAW_SIZE}; @var{n...} = @samp{thread}, @var{r...} = +thread process ID, this is a hex integer; @var{n...} = other string not +starting with valid hex digit. @value{GDBN} should ignore this +@var{n...}, @var{r...} pair and go on to the next. This way we can +extend the protocol. + +@item @code{W}@var{AA} +@tab +The process exited, and @var{AA} is the exit status. This is only +applicable for certains sorts of targets. + +@item @code{X}@var{AA} +@tab +The process terminated with signal @var{AA}. + +@item @code{N}@var{AA}@code{;}@var{t...}@code{;}@var{d...}@code{;}@var{b...} @strong{(obsolete)} +@tab +@var{AA} = signal number; @var{t...} = address of symbol "_start"; +@var{d...} = base of data section; @var{b...} = base of bss section. +@emph{Note: only used by Cisco Systems targets. The difference between +this reply and the "qOffsets" query is that the 'N' packet may arrive +spontaneously whereas the 'qOffsets' is a query initiated by the host +debugger.} + +@item @code{O}@var{XX...} +@tab +@var{XX...} is hex encoding of @sc{ascii} data. This can happen at any time +while the program is running and the debugger should continue to wait +for 'W', 'T', etc. + +@end multitable + +The following set and query packets have already been defined. + +@multitable @columnfractions .2 .2 .6 + +@item current thread +@tab @code{q}@code{C} +@tab Return the current thread id. +@item +@tab reply @code{QC}@var{pid} +@tab +Where @var{pid} is a HEX encoded 16 bit process id. +@item +@tab reply * +@tab Any other reply implies the old pid. + +@item all thread ids +@tab @code{q}@code{fThreadInfo} +@item +@tab @code{q}@code{sThreadInfo} +@tab +Obtain a list of active thread ids from the target (OS). Since there +may be too many active threads to fit into one reply packet, this query +works iteratively: it may require more than one query/reply sequence to +obtain the entire list of threads. The first query of the sequence will +be the @code{qf}@code{ThreadInfo} query; subsequent queries in the +sequence will be the @code{qs}@code{ThreadInfo} query. +@item +@tab +@tab NOTE: replaces the @code{qL} query (see below). +@item +@tab reply @code{m}@var{<id>} +@tab A single thread id +@item +@tab reply @code{m}@var{<id>},@var{<id>...} +@tab a comma-separated list of thread ids +@item +@tab reply @code{l} +@tab (lower case 'el') denotes end of list. +@item +@tab +@tab +In response to each query, the target will reply with a list of one +or more thread ids, in big-endian hex, separated by commas. GDB will +respond to each reply with a request for more thread ids (using the +@code{qs} form of the query), until the target responds with @code{l} +(lower-case el, for @code{'last'}). + +@item extra thread info +@tab @code{q}@code{ThreadExtraInfo}@code{,}@var{id} +@tab +@item +@tab +@tab +Where @var{<id>} is a thread-id in big-endian hex. +Obtain a printable string description of a thread's attributes from +the target OS. This string may contain anything that the target OS +thinks is interesting for @value{GDBN} to tell the user about the thread. +The string is displayed in @value{GDBN}'s @samp{info threads} display. +Some examples of possible thread extra info strings are "Runnable", or +"Blocked on Mutex". +@item +@tab reply @var{XX...} +@tab +Where @var{XX...} is a hex encoding of @sc{ascii} data, comprising the +printable string containing the extra information about the thread's +attributes. + +@item query @var{LIST} or @var{threadLIST} @strong{(deprecated)} +@tab @code{q}@code{L}@var{startflag}@var{threadcount}@var{nextthread} +@tab +@item +@tab +@tab +Obtain thread information from RTOS. Where: @var{startflag} (one hex +digit) is one to indicate the first query and zero to indicate a +subsequent query; @var{threadcount} (two hex digits) is the maximum +number of threads the response packet can contain; and @var{nextthread} +(eight hex digits), for subsequent queries (@var{startflag} is zero), is +returned in the response as @var{argthread}. +@item +@tab +@tab NOTE: this query is replaced by the @code{q}@code{fThreadInfo} +query (see above). +@item +@tab reply @code{q}@code{M}@var{count}@var{done}@var{argthread}@var{thread...} +@tab +@item +@tab +@tab +Where: @var{count} (two hex digits) is the number of threads being +returned; @var{done} (one hex digit) is zero to indicate more threads +and one indicates no further threads; @var{argthreadid} (eight hex +digits) is @var{nextthread} from the request packet; @var{thread...} is +a sequence of thread IDs from the target. @var{threadid} (eight hex +digits). See @code{remote.c:parse_threadlist_response()}. + +@item compute CRC of memory block +@tab @code{q}@code{CRC:}@var{addr}@code{,}@var{length} +@tab +@item +@tab reply @code{E}@var{NN} +@tab An error (such as memory fault) +@item +@tab reply @code{C}@var{CRC32} +@tab A 32 bit cyclic redundancy check of the specified memory region. + +@item query sect offs +@tab @code{q}@code{Offsets} +@tab +Get section offsets that the target used when re-locating the downloaded +image. @emph{Note: while a @code{Bss} offset is included in the +response, @value{GDBN} ignores this and instead applies the @code{Data} +offset to the @code{Bss} section.} +@item +@tab reply @code{Text=}@var{xxx}@code{;Data=}@var{yyy}@code{;Bss=}@var{zzz} + +@item thread info request +@tab @code{q}@code{P}@var{mode}@var{threadid} +@tab +@item +@tab +@tab +Returns information on @var{threadid}. Where: @var{mode} is a hex +encoded 32 bit mode; @var{threadid} is a hex encoded 64 bit thread ID. +@item +@tab reply * +@tab +See @code{remote.c:remote_unpack_thread_info_response()}. + +@item remote command +@tab @code{q}@code{Rcmd,}@var{COMMAND} +@tab +@item +@tab +@tab +@var{COMMAND} (hex encoded) is passed to the local interpreter for +execution. Invalid commands should be reported using the output string. +Before the final result packet, the target may also respond with a +number of intermediate @code{O}@var{OUTPUT} console output +packets. @emph{Implementors should note that providing access to a +stubs's interpreter may have security implications}. +@item +@tab reply @code{OK} +@tab +A command response with no output. +@item +@tab reply @var{OUTPUT} +@tab +A command response with the hex encoded output string @var{OUTPUT}. +@item +@tab reply @code{E}@var{NN} +@tab +Indicate a badly formed request. + +@item +@tab reply @samp{} +@tab +When @samp{q}@samp{Rcmd} is not recognized. + +@item symbol lookup +@tab @code{qSymbol::} +@tab +Notify the target that @value{GDBN} is prepared to serve symbol lookup +requests. Accept requests from the target for the values of symbols. +@item +@tab +@tab +@item +@tab reply @code{OK} +@tab +The target does not need to look up any (more) symbols. +@item +@tab reply @code{qSymbol:}@var{sym_name} +@tab +@sp 2 +@noindent +The target requests the value of symbol @var{sym_name} (hex encoded). +@value{GDBN} may provide the value by using the +@code{qSymbol:}@var{sym_value}:@var{sym_name} +message, described below. + +@item symbol value +@tab @code{qSymbol:}@var{sym_value}:@var{sym_name} +@tab +@sp 1 +@noindent +Set the value of SYM_NAME to SYM_VALUE. +@item +@tab +@tab +@var{sym_name} (hex encoded) is the name of a symbol whose value +the target has previously requested. +@item +@tab +@tab +@var{sym_value} (hex) is the value for symbol @var{sym_name}. +If @value{GDBN} cannot supply a value for @var{sym_name}, then this +field will be empty. +@item +@tab reply @code{OK} +@tab +The target does not need to look up any (more) symbols. +@item +@tab reply @code{qSymbol:}@var{sym_name} +@tab +@sp 2 +@noindent +The target requests the value of a new symbol @var{sym_name} (hex encoded). +@value{GDBN} will continue to supply the values of symbols (if available), +until the target ceases to request them. + +@end multitable + +The following @samp{g}/@samp{G} packets have previously been defined. +In the below, some thirty-two bit registers are transferred as sixty-four +bits. Those registers should be zero/sign extended (which?) to fill the +space allocated. Register bytes are transfered in target byte order. +The two nibbles within a register byte are transfered most-significant - +least-significant. + +@multitable @columnfractions .5 .5 + +@item MIPS32 +@tab +All registers are transfered as thirty-two bit quantities in the order: +32 general-purpose; sr; lo; hi; bad; cause; pc; 32 floating-point +registers; fsr; fir; fp. + +@item MIPS64 +@tab +All registers are transfered as sixty-four bit quantities (including +thirty-two bit registers such as @code{sr}). The ordering is the same +as @code{MIPS32}. + +@end multitable + +Example sequence of a target being re-started. Notice how the restart +does not get any direct output: + +@example +<- @code{R00} +-> @code{+} +@emph{target restarts} +<- @code{?} +-> @code{+} +-> @code{T001:1234123412341234} +<- @code{+} +@end example + +Example sequence of a target being stepped by a single instruction: + +@example +<- @code{G1445...} +-> @code{+} +<- @code{s} +-> @code{+} +@emph{time passes} +-> @code{T001:1234123412341234} +<- @code{+} +<- @code{g} +-> @code{+} +-> @code{1455...} +<- @code{+} +@end example + +@include gpl.texi + +@include fdl.texi + +@node Index @unnumbered Index @printindex cp @@ -10312,5 +14963,4 @@ needed for special purposes only. % Blame: doc@cygnus.com, 1991. @end tex -@contents @bye diff --git a/contrib/gdb/gdb/doc/stabs.texinfo b/contrib/gdb/gdb/doc/stabs.texinfo index 7e74917..2a14dcc 100644 --- a/contrib/gdb/gdb/doc/stabs.texinfo +++ b/contrib/gdb/gdb/doc/stabs.texinfo @@ -6,7 +6,7 @@ @ifinfo @format START-INFO-DIR-ENTRY -* Stabs: (stabs). The "stabs" debugging information format. +* Stabs: (stabs). The "stabs" debugging information format. END-INFO-DIR-ENTRY @end format @end ifinfo @@ -14,24 +14,20 @@ END-INFO-DIR-ENTRY @ifinfo This document describes the stabs debugging symbol tables. -Copyright 1992, 93, 94, 95, 97, 1998 Free Software Foundation, Inc. +Copyright 1992,1993,1994,1995,1997,1998,2000,2001 + Free Software Foundation, Inc. Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon, and David MacKenzie. -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,'' +and with the Back-Cover Texts as in (a) below. -@ignore -Permission is granted to process this file through Tex and print the -results, provided the printed document carries copying permission -notice identical to this one except for the removal of this paragraph -(this paragraph not being relevant to the printed manual). - -@end ignore -Permission is granted to copy or distribute modified versions of this -manual under the terms of the GPL (for which purpose this text may be -regarded as a program in the language TeX). +(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify +this GNU Manual, like GNU software. Copies published by the Free +Software Foundation raise funds for GNU development.'' @end ifinfo @setchapternewpage odd @@ -43,7 +39,7 @@ regarded as a program in the language TeX). @page @tex \def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ -\xdef\manvers{\$Revision: 2.128 $} % For use in headers, footers too +\xdef\manvers{\$Revision: 2.130 $} % For use in headers, footers too {\parskip=0pt \hfill Cygnus Support\par \hfill \manvers\par @@ -52,12 +48,18 @@ regarded as a program in the language TeX). @end tex @vskip 0pt plus 1filll -Copyright @copyright{} 1992, 93, 94, 95, 97, 1998 Free Software Foundation, Inc. +Copyright @copyright{} 1992,1993,1994,1995,1997,1998,2000,2001 Free Software Foundation, Inc. Contributed by Cygnus Support. -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,'' +and with the Back-Cover Texts as in (a) below. + +(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify +this GNU Manual, like GNU software. Copies published by the Free +Software Foundation raise funds for GNU development.'' @end titlepage @@ -79,13 +81,17 @@ This document describes the stabs debugging format. * Symbol Descriptors:: Table of symbol descriptors * Type Descriptors:: Table of type descriptors * Expanded Reference:: Reference information by stab type -* Questions:: Questions and anomolies +* Questions:: Questions and anomalies * Stab Sections:: In some object file formats, stabs are in sections. * Symbol Types Index:: Index of symbolic stab symbol type names. @end menu @end ifinfo +@c TeX can handle the contents at the start but makeinfo 3.12 can not +@iftex +@contents +@end iftex @node Overview @chapter Overview of Stabs @@ -242,9 +248,8 @@ A @var{type-number} is often a single number. The GNU and Sun tools additionally permit a @var{type-number} to be a pair (@var{file-number},@var{filetype-number}) (the parentheses appear in the string, and serve to distinguish the two cases). The @var{file-number} -is a number starting with 1 which is incremented for each seperate -source file in the compilation (e.g., in C, each header file gets a -different number). The @var{filetype-number} is a number starting with +is 0 for the base source file, 1 for the first included file, 2 for the +next, and so on. The @var{filetype-number} is a number starting with 1 which is incremented for each new type defined in the file. (Separating the file number and the type number permits the @code{N_BINCL} optimization to succeed more often; see @ref{Include @@ -482,7 +487,7 @@ significant data in the @code{N_EINCL} symbol. @code{N_BINCL} and If the linker detects that two source files have identical stabs between an @code{N_BINCL} and @code{N_EINCL} pair (as will generally be the case for a header file), then it only puts out the stabs once. Each -additional occurance is replaced by an @code{N_EXCL} symbol. I believe +additional occurrence is replaced by an @code{N_EXCL} symbol. I believe the GNU linker and the Sun (both SunOS4 and Solaris) linker are the only ones which supports this feature. @@ -872,7 +877,7 @@ produces the following stabs: .stabn 224,0,0,LBE2 # @r{224 is N_RBRAC} @end example -@xref{Procedures} for more information on the @code{N_FUN} stab, and +See @ref{Procedures} for more information on the @code{N_FUN} stab, and @ref{Block Structure} for more information on the @code{N_LBRAC} and @code{N_RBRAC} stabs. @@ -1316,7 +1321,7 @@ of specifying builtin types do not specify everything that a debugger would need to know about the type---in some cases they merely specify enough information to distinguish the type from other types. -The traditional way to define builtin types is convolunted, so new ways +The traditional way to define builtin types is convoluted, so new ways have been invented to describe them. Sun's @code{acc} uses special builtin type descriptors (@samp{b} and @samp{R}), and IBM uses negative type numbers. GDB accepts all three ways, as of version 4.8; dbx just @@ -1324,7 +1329,7 @@ accepts the traditional builtin types and perhaps one of the other two formats. The following sections describe each of these formats. @menu -* Traditional Builtin Types:: Put on your seatbelts and prepare for kludgery +* Traditional Builtin Types:: Put on your seat belts and prepare for kludgery * Builtin Type Descriptors:: Builtin types with special type descriptors * Negative Type Numbers:: Builtin types using negative type numbers @end menu @@ -1478,7 +1483,7 @@ IEEE 64-bit (double precision) floating point format. These are for complex numbers. A comment in the GDB source describes them as Fortran @code{complex}, @code{double complex}, and @code{complex*16}, respectively, but what does that mean? (i.e., Single -precision? Double precison?). +precision? Double precision?). @item 6 (NF_LDOUBLE) Long double. This should probably only be used for Sun format @@ -1817,7 +1822,7 @@ The bound is passed by value on the stack at offset @var{offset} from the argument list. @item a @var{register-number} -The bound is pased by reference in register number +The bound is passed by reference in register number @var{register-number}. @item t @var{register-number} @@ -2010,9 +2015,9 @@ The encoding of structures in stabs can be shown with an example. The following source code declares a structure tag and defines an instance of the structure in global scope. Then a @code{typedef} equates the -structure tag with a new type. Seperate stabs are generated for the +structure tag with a new type. Separate stabs are generated for the structure tag, the structure @code{typedef}, and the structure instance. The -stabs for the tag and the @code{typedef} are emited when the definitions are +stabs for the tag and the @code{typedef} are emitted when the definitions are encountered. Since the structure elements are not initialized, the stab and code for the structure variable itself is located at the end of the program in the bss section. @@ -2052,7 +2057,7 @@ types. For these, the type following the @samp{@var{name}:} part of the element description is a simple type reference. The other two structure elements are new types. In this case there is a type definition embedded after the @samp{@var{name}:}. The type definition for the -array element looks just like a type definition for a standalone array. +array element looks just like a type definition for a stand-alone array. The @code{s_next} field is a pointer to the same kind of structure that the field is an element of. So the definition of structure type 16 contains a type definition for an element which is a pointer to type 16. @@ -2119,7 +2124,7 @@ The stab for the union tag, however, is located preceding the code for the procedure in which it is defined. The stab type is @code{N_LSYM}. This would seem to imply that the union type is file scope, like the struct type @code{s_tag}. This is not true. The contents and position of the stab -for @code{u_type} do not convey any infomation about its procedure local +for @code{u_type} do not convey any information about its procedure local scope. @c FIXME: phony line break. Can probably be fixed by using an example @@ -2398,7 +2403,7 @@ Symnum n_type n_othr n_desc n_value n_strx String * Protections:: * Method Modifiers:: * Virtual Methods:: -* Inheritence:: +* Inheritance:: * Virtual Base Classes:: * Static Members:: @end menu @@ -2524,7 +2529,7 @@ would signify a local variable. A stab describing a C++ class type is similar in format to a stab describing a C struct, with each class member shown as a field in the structure. The part of the struct format describing fields is -expanded to include extra information relevent to C++ class members. +expanded to include extra information relevant to C++ class members. In addition, if the class has multiple base classes or virtual functions the struct format outside of the field parts is also augmented. @@ -2559,7 +2564,7 @@ The name ends with a period, and any characters except the period can occur in the @var{operator-name} string. The next part of the method description represents the arguments to the -method, preceeded by a colon and ending with a semi-colon. The types of +method, preceded by a colon and ending with a semi-colon. The types of the arguments are expressed in the same way argument types are expressed in C++ name mangling. In this example an @code{int} and a @code{char} map to @samp{ic}. @@ -2651,7 +2656,7 @@ mangling. @c GDB. But gpcompare.texi doesn't seem to be in the FSF GCC. @example -.stabs "name:symbol_desriptor(global function)return_type(int)", +.stabs "name:symbol_descriptor(global function)return_type(int)", N_FUN, NIL, NIL, code_addr_of_method_start .stabs "Ameth__5baseAic:F1",36,0,0,_Ameth__5baseAic @@ -2660,8 +2665,8 @@ mangling. Here is the stab for the @code{this} pointer implicit argument. The name of the @code{this} pointer is always @code{this}. Type 19, the @code{this} pointer is defined as a pointer to type 20, @code{baseA}, -but a stab defining @code{baseA} has not yet been emited. Since the -compiler knows it will be emited shortly, here it just outputs a cross +but a stab defining @code{baseA} has not yet been emitted. Since the +compiler knows it will be emitted shortly, here it just outputs a cross reference to the undefined symbol, by prefixing the symbol name with @samp{xs}. @@ -2729,8 +2734,8 @@ never start with those things. @section Protections In the simple class definition shown above all member data and -functions were publicly accessable. The example that follows -contrasts public, protected and privately accessable fields and shows +functions were publicly accessible. The example that follows +contrasts public, protected and privately accessible fields and shows how these protections are encoded in C++ stabs. If the character following the @samp{@var{field-name}:} part of the @@ -2773,7 +2778,7 @@ The @code{prot} field has protected visibility (@samp{/1}), type char (@samp{2}) and offset and size @samp{,32,8;}. The @code{pub} field has type float (@samp{12}), and offset and size @samp{,64,32;}. -Protections for member functions are signified by one digit embeded in +Protections for member functions are signified by one digit embedded in the field part of the stab describing the method. The digit is 0 if private, 1 if protected and 2 if public. Consider the C++ class definition below: @@ -2799,7 +2804,7 @@ descriptors apply to the class name struct tag and struct type. meth_name::type_def(22)=sym_desc(method)returning(int); :args(int);protection(private)modifier(normal)virtual(no); meth_name::type_def(23)=sym_desc(method)returning(char); - :args(char);protection(protected)modifier(normal)virual(no); + :args(char);protection(protected)modifier(normal)virtual(no); meth_name::type_def(24)=sym_desc(method)returning(float); :args(float);protection(public)modifier(normal)virtual(no);;", N_LSYM,NIL,NIL,NIL @@ -2840,7 +2845,7 @@ This class is described by the following stab: meth_name(VolatileMeth)::type_def(22)=sym_desc(method) returning(char);:arg(char);protection(public)modifier(volatile)virt(no) meth_name(ConstVolMeth)::type_def(23)=sym_desc(method) - returning(float);:arg(float);protection(public)modifer(const volatile) + returning(float);:arg(float);protection(public)modifier(const volatile) virtual(no);;", @dots{} @end display @@ -2903,7 +2908,7 @@ The first number represents the vtable index of the method. This is a semi-colon. The second number is a type reference to the first base class in the -inheritence hierarchy defining the virtual member function. In this +inheritance hierarchy defining the virtual member function. In this case the class stab describes a base class so the virtual function is not overriding any other definition of the method. Therefore the reference is to the type number of the class that the stab is @@ -2915,7 +2920,7 @@ third marks the end of the struct definition. For classes containing virtual functions the very last section of the string part of the stab holds a type reference to the first base -class. This is preceeded by @samp{~%} and followed by a final semi-colon. +class. This is preceded by @samp{~%} and followed by a final semi-colon. @display .stabs "class_name(A):type_def(20)=sym_desc(struct)struct_bytes(8) @@ -2936,22 +2941,22 @@ class. This is preceeded by @samp{~%} and followed by a final semi-colon. A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0 @end example -@node Inheritence -@section Inheritence +@node Inheritance +@section Inheritance Stabs describing C++ derived classes include additional sections that -describe the inheritence hierarchy of the class. A derived class stab +describe the inheritance hierarchy of the class. A derived class stab also encodes the number of base classes. For each base class it tells -if the base class is virtual or not, and if the inheritence is private +if the base class is virtual or not, and if the inheritance is private or public. It also gives the offset into the object of the portion of the object corresponding to each base class. -This additional information is embeded in the class stab following the +This additional information is embedded in the class stab following the number of bytes in the struct. First the number of base classes appears bracketed by an exclamation point and a comma. Then for each base type there repeats a series: a virtual character, a -visibilty character, a number, a comma, another number, and a +visibility character, a number, a comma, another number, and a semi-colon. The virtual character is @samp{1} if the base class is virtual and @@ -3029,11 +3034,11 @@ the derivation of this class is encoded as follows. @display .stabs "derived_class_name:symbol_descriptors(struct tag&type)= type_descriptor(struct)struct_bytes(32)!num_bases(3), - base_virtual(no)inheritence_public(no)base_offset(0), + base_virtual(no)inheritance_public(no)base_offset(0), base_class_type_ref(A); - base_virtual(yes)inheritence_public(no)base_offset(NIL), + base_virtual(yes)inheritance_public(no)base_offset(NIL), base_class_type_ref(B); - base_virtual(no)inheritence_public(yes)base_offset(64), + base_virtual(no)inheritance_public(yes)base_offset(64), base_class_type_ref(C); @dots{} @end display @@ -3048,10 +3053,10 @@ the derivation of this class is encoded as follows. @node Virtual Base Classes @section Virtual Base Classes -A derived class object consists of a concatination in memory of the data +A derived class object consists of a concatenation in memory of the data areas defined by each base class, starting with the leftmost and ending with the rightmost in the list of base classes. The exception to this -rule is for virtual inheritence. In the example above, class @code{D} +rule is for virtual inheritance. In the example above, class @code{D} inherits virtually from base class @code{B}. This means that an instance of a @code{D} object will not contain its own @code{B} part but merely a pointer to a @code{B} part, known as a virtual base pointer. @@ -3370,7 +3375,7 @@ for more information about their use. Variable on the stack; see @ref{Stack Variables}. @item : -C++ nested symbol; see @xref{Nested Symbols} +C++ nested symbol; see @xref{Nested Symbols}. @item a Parameter passed by reference in register; see @ref{Reference Parameters}. @@ -3505,7 +3510,7 @@ Open array; see @ref{Arrays}. @item b Pascal space type (AIX); see @ref{Miscellaneous Types}. Builtin integer type (Sun); see @ref{Builtin Type Descriptors}. Const and volatile -qualfied type (OS9000). +qualified type (OS9000). @item B Volatile-qualified type; see @ref{Miscellaneous Types}. @@ -3854,11 +3859,11 @@ In GNU C stabs, there seems to be no way to differentiate tag types: structures, unions, and enums (symbol descriptor @samp{T}) and typedefs (symbol descriptor @samp{t}) defined at file scope from types defined locally to a procedure or other more local scope. They all use the @code{N_LSYM} -stab type. Types defined at procedure scope are emited after the +stab type. Types defined at procedure scope are emitted after the @code{N_RBRAC} of the preceding function and before the code of the procedure in which they are defined. This is exactly the same as types defined in the source file between the two procedure bodies. -GDB overcompensates by placing all types in block #1, the block for +GDB over-compensates by placing all types in block #1, the block for symbols of file scope. This is true for default, @samp{-ansi} and @samp{-traditional} compiler options. (Bugs gcc/1063, gdb/1066.) @@ -4015,5 +4020,12 @@ However, no one has yet designed or implemented such a scheme. @printindex fn +@c TeX can handle the contents at the start but makeinfo 3.12 can not +@ifinfo +@contents +@end ifinfo +@ifhtml @contents +@end ifhtml + @bye diff --git a/contrib/gdb/gdb/exec.c b/contrib/gdb/gdb/exec.c index 6cb9e59..b07175e 100644 --- a/contrib/gdb/gdb/exec.c +++ b/contrib/gdb/gdb/exec.c @@ -1,22 +1,24 @@ /* Work with executable files, for GDB. - Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1997, 1998 - Free Software Foundation, Inc. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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 "frame.h" @@ -26,6 +28,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "language.h" #include "symfile.h" #include "objfiles.h" +#include "completer.h" +#include "value.h" #ifdef USG #include <sys/types.h> @@ -44,31 +48,29 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "xcoffsolib.h" -struct vmap *map_vmap PARAMS ((bfd *, bfd *)); +struct vmap *map_vmap (bfd *, bfd *); -void (*file_changed_hook) PARAMS ((char *)); +void (*file_changed_hook) (char *); /* Prototypes for local functions */ -static void add_to_section_table PARAMS ((bfd *, sec_ptr, PTR)); +static void add_to_section_table (bfd *, sec_ptr, PTR); -static void exec_close PARAMS ((int)); +static void exec_close (int); -static void file_command PARAMS ((char *, int)); +static void file_command (char *, int); -static void set_section_command PARAMS ((char *, int)); +static void set_section_command (char *, int); -static void exec_files_info PARAMS ((struct target_ops *)); +static void exec_files_info (struct target_ops *); -static void bfdsec_to_vmap PARAMS ((bfd *, sec_ptr, PTR)); +static void bfdsec_to_vmap (bfd *, sec_ptr, PTR); -static int ignore PARAMS ((CORE_ADDR, char *)); +static int ignore (CORE_ADDR, char *); -static void init_exec_ops PARAMS ((void)); +static void init_exec_ops (void); -void _initialize_exec PARAMS ((void)); - -extern int info_verbose; +void _initialize_exec (void); /* The target vector for executable files. */ @@ -88,26 +90,32 @@ int write_files = 0; #define NEED_TEXT_START_END (0) #endif CORE_ADDR text_start = 0; -CORE_ADDR text_end = 0; +CORE_ADDR text_end = 0; struct vmap *vmap; +void +exec_open (char *args, int from_tty) +{ + target_preopen (from_tty); + exec_file_attach (args, from_tty); +} + /* ARGSUSED */ static void -exec_close (quitting) - int quitting; +exec_close (int quitting) { int need_symtab_cleanup = 0; struct vmap *vp, *nxt; - - for (nxt = vmap; nxt != NULL; ) + + for (nxt = vmap; nxt != NULL;) { vp = nxt; nxt = vp->nxt; /* if there is an objfile associated with this bfd, - free_objfile() will do proper cleanup of objfile *and* bfd. */ - + free_objfile() will do proper cleanup of objfile *and* bfd. */ + if (vp->objfile) { free_objfile (vp->objfile); @@ -120,12 +128,12 @@ exec_close (quitting) vp->name, bfd_errmsg (bfd_get_error ())); /* FIXME: This routine is #if 0'd in symfile.c. What should we - be doing here? Should we just free everything in - vp->objfile->symtabs? Should free_objfile do that? - FIXME-as-well: free_objfile already free'd vp->name, so it isn't - valid here. */ + be doing here? Should we just free everything in + vp->objfile->symtabs? Should free_objfile do that? + FIXME-as-well: free_objfile already free'd vp->name, so it isn't + valid here. */ free_named_symtabs (vp->name); - free (vp); + xfree (vp); } vmap = NULL; @@ -137,84 +145,79 @@ exec_close (quitting) if (!bfd_close (exec_bfd)) warning ("cannot close \"%s\": %s", name, bfd_errmsg (bfd_get_error ())); - free (name); + xfree (name); exec_bfd = NULL; } if (exec_ops.to_sections) { - free ((PTR)exec_ops.to_sections); + xfree (exec_ops.to_sections); exec_ops.to_sections = NULL; exec_ops.to_sections_end = NULL; } } +void +exec_file_clear (int from_tty) +{ + /* Remove exec file. */ + unpush_target (&exec_ops); + + if (from_tty) + printf_unfiltered ("No executable file now.\n"); +} + /* Process the first arg in ARGS as the new exec file. - This function is intended to be behave essentially the same - as exec_file_command, except that the latter will detect when - a target is being debugged, and will ask the user whether it - should be shut down first. (If the answer is "no", then the - new file is ignored.) + This function is intended to be behave essentially the same + as exec_file_command, except that the latter will detect when + a target is being debugged, and will ask the user whether it + should be shut down first. (If the answer is "no", then the + new file is ignored.) - This file is used by exec_file_command, to do the work of opening - and processing the exec file after any prompting has happened. + This file is used by exec_file_command, to do the work of opening + and processing the exec file after any prompting has happened. - And, it is used by child_attach, when the attach command was - given a pid but not a exec pathname, and the attach command could - figure out the pathname from the pid. (In this case, we shouldn't - ask the user whether the current target should be shut down -- - we're supplying the exec pathname late for good reason.) */ + And, it is used by child_attach, when the attach command was + given a pid but not a exec pathname, and the attach command could + figure out the pathname from the pid. (In this case, we shouldn't + ask the user whether the current target should be shut down -- + we're supplying the exec pathname late for good reason.) + + ARGS is assumed to be the filename. */ void -exec_file_attach (args, from_tty) - char *args; - int from_tty; +exec_file_attach (char *filename, int from_tty) { - char **argv; - char *filename; - /* Remove any previous exec file. */ unpush_target (&exec_ops); /* Now open and digest the file the user requested, if any. */ - if (args) + if (!filename) + { + if (from_tty) + printf_unfiltered ("No executable file now.\n"); + } + else { char *scratch_pathname; int scratch_chan; - - /* Scan through the args and pick up the first non option arg - as the filename. */ - - argv = buildargv (args); - if (argv == NULL) - nomem (0); - make_cleanup ((make_cleanup_func) freeargv, (char *) argv); - - for (; (*argv != NULL) && (**argv == '-'); argv++) {;} - if (*argv == NULL) - error ("no exec file name was specified"); - - filename = tilde_expand (*argv); - make_cleanup (free, filename); - - scratch_chan = openp (getenv ("PATH"), 1, filename, - write_files? O_RDWR|O_BINARY: O_RDONLY|O_BINARY, 0, + scratch_chan = openp (getenv ("PATH"), 1, filename, + write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0, &scratch_pathname); -#if defined(__GO32__) || defined(_WIN32) +#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__) if (scratch_chan < 0) - { - char *exename = alloca (strlen (filename) + 5); - strcat (strcpy (exename, filename), ".exe"); - scratch_chan = openp (getenv ("PATH"), 1, exename, write_files ? - O_RDWR|O_BINARY : O_RDONLY|O_BINARY, 0, &scratch_pathname); - } + { + char *exename = alloca (strlen (filename) + 5); + strcat (strcpy (exename, filename), ".exe"); + scratch_chan = openp (getenv ("PATH"), 1, exename, write_files ? + O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0, &scratch_pathname); + } #endif if (scratch_chan < 0) perror_with_name (filename); - fcntl (scratch_chan, F_SETFD, 1); exec_bfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); if (!exec_bfd) @@ -222,12 +225,12 @@ exec_file_attach (args, from_tty) scratch_pathname, bfd_errmsg (bfd_get_error ())); /* At this point, scratch_pathname and exec_bfd->name both point to the - same malloc'd string. However exec_close() will attempt to free it - via the exec_bfd->name pointer, so we need to make another copy and - leave exec_bfd as the new owner of the original copy. */ - scratch_pathname = strdup (scratch_pathname); - make_cleanup (free, scratch_pathname); - + same malloc'd string. However exec_close() will attempt to free it + via the exec_bfd->name pointer, so we need to make another copy and + leave exec_bfd as the new owner of the original copy. */ + scratch_pathname = xstrdup (scratch_pathname); + make_cleanup (xfree, scratch_pathname); + if (!bfd_check_format (exec_bfd, bfd_object)) { /* Make sure to close exec_bfd, or else "run" might try to use @@ -238,7 +241,7 @@ exec_file_attach (args, from_tty) } /* FIXME - This should only be run for RS6000, but the ifdef is a poor - way to accomplish. */ + way to accomplish. */ #ifdef IBM6000_TARGET /* Setup initial vmap. */ @@ -254,34 +257,34 @@ exec_file_attach (args, from_tty) #endif /* IBM6000_TARGET */ if (build_section_table (exec_bfd, &exec_ops.to_sections, - &exec_ops.to_sections_end)) + &exec_ops.to_sections_end)) { /* Make sure to close exec_bfd, or else "run" might try to use it. */ exec_close (0); - error ("\"%s\": can't find the file sections: %s", + error ("\"%s\": can't find the file sections: %s", scratch_pathname, bfd_errmsg (bfd_get_error ())); } /* text_end is sometimes used for where to put call dummies. A - few ports use these for other purposes too. */ + few ports use these for other purposes too. */ if (NEED_TEXT_START_END) { struct section_table *p; - + /* Set text_start to the lowest address of the start of any readonly code section and set text_end to the highest address of the end of any readonly code section. */ /* FIXME: The comment above does not match the code. The code checks for sections with are either code *or* readonly. */ - text_start = ~(CORE_ADDR)0; - text_end = (CORE_ADDR)0; + text_start = ~(CORE_ADDR) 0; + text_end = (CORE_ADDR) 0; for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) if (bfd_get_section_flags (p->bfd, p->the_bfd_section) & (SEC_CODE | SEC_READONLY)) { - if (text_start > p->addr) + if (text_start > p->addr) text_start = p->addr; if (text_end < p->endaddr) text_end = p->endaddr; @@ -298,27 +301,47 @@ exec_file_attach (args, from_tty) if (exec_file_display_hook) (*exec_file_display_hook) (filename); } - else if (from_tty) - printf_unfiltered ("No executable file now.\n"); } /* Process the first arg in ARGS as the new exec file. - Note that we have to explicitly ignore additional args, since we can - be called from file_command(), which also calls symbol_file_command() - which can take multiple args. */ + Note that we have to explicitly ignore additional args, since we can + be called from file_command(), which also calls symbol_file_command() + which can take multiple args. + + If ARGS is NULL, we just want to close the exec file. */ -void -exec_file_command (args, from_tty) - char *args; - int from_tty; +static void +exec_file_command (char *args, int from_tty) { char **argv; char *filename; - + target_preopen (from_tty); - exec_file_attach (args, from_tty); + if (args) + { + /* Scan through the args and pick up the first non option arg + as the filename. */ + + argv = buildargv (args); + if (argv == NULL) + nomem (0); + + make_cleanup_freeargv (argv); + + for (; (*argv != NULL) && (**argv == '-'); argv++) + {; + } + if (*argv == NULL) + error ("No executable file name was specified"); + + filename = tilde_expand (*argv); + make_cleanup (xfree, filename); + exec_file_attach (filename, from_tty); + } + else + exec_file_attach (NULL, from_tty); } /* Set both the exec file and the symbol file, in one command. @@ -326,9 +349,7 @@ exec_file_command (args, from_tty) command was added? */ static void -file_command (arg, from_tty) - char *arg; - int from_tty; +file_command (char *arg, int from_tty) { /* FIXME, if we lose on reading the symbol file, we should revert the exec file, but that's rough. */ @@ -337,19 +358,16 @@ file_command (arg, from_tty) if (file_changed_hook) file_changed_hook (arg); } - + /* Locate all mappable sections of a BFD file. table_pp_char is a char * to get it through bfd_map_over_sections; we cast it back to its proper type. */ static void -add_to_section_table (abfd, asect, table_pp_char) - bfd *abfd; - sec_ptr asect; - PTR table_pp_char; +add_to_section_table (bfd *abfd, sec_ptr asect, PTR table_pp_char) { - struct section_table **table_pp = (struct section_table **)table_pp_char; + struct section_table **table_pp = (struct section_table **) table_pp_char; flagword aflag; aflag = bfd_get_section_flags (abfd, asect); @@ -368,29 +386,25 @@ add_to_section_table (abfd, asect, table_pp_char) Returns 0 if OK, 1 on error. */ int -build_section_table (some_bfd, start, end) - bfd *some_bfd; - struct section_table **start, **end; +build_section_table (bfd *some_bfd, struct section_table **start, + struct section_table **end) { unsigned count; count = bfd_count_sections (some_bfd); if (*start) - free ((PTR)*start); + xfree (* start); *start = (struct section_table *) xmalloc (count * sizeof (**start)); *end = *start; - bfd_map_over_sections (some_bfd, add_to_section_table, (char *)end); + bfd_map_over_sections (some_bfd, add_to_section_table, (char *) end); if (*end > *start + count) - abort(); + internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* We could realloc the table, but it probably loses for most files. */ return 0; } static void -bfdsec_to_vmap(abfd, sect, arg3) - bfd *abfd; - sec_ptr sect; - PTR arg3; +bfdsec_to_vmap (bfd *abfd, sec_ptr sect, PTR arg3) { struct vmap_and_bfd *vmap_bfd = (struct vmap_and_bfd *) arg3; struct vmap *vp; @@ -420,9 +434,7 @@ bfdsec_to_vmap(abfd, sect, arg3) Return the new vmap. */ struct vmap * -map_vmap (abfd, arch) - bfd *abfd; - bfd *arch; +map_vmap (bfd *abfd, bfd *arch) { struct vmap_and_bfd vmap_bfd; struct vmap *vp, **vpp; @@ -433,7 +445,7 @@ map_vmap (abfd, arch) vp->bfd = abfd; vp->name = bfd_get_filename (arch ? arch : abfd); vp->member = arch ? bfd_get_filename (abfd) : ""; - + vmap_bfd.pbfd = arch; vmap_bfd.pvmap = vp; bfd_map_over_sections (abfd, bfdsec_to_vmap, &vmap_bfd); @@ -453,33 +465,30 @@ map_vmap (abfd, arch) Result is a length: - 0: We cannot handle this address and length. - > 0: We have handled N bytes starting at this address. - (If N == length, we did it all.) We might be able - to handle more bytes beyond this length, but no - promises. - < 0: We cannot handle this address, but if somebody - else handles (-N) bytes, we can start from there. + 0: We cannot handle this address and length. + > 0: We have handled N bytes starting at this address. + (If N == length, we did it all.) We might be able + to handle more bytes beyond this length, but no + promises. + < 0: We cannot handle this address, but if somebody + else handles (-N) bytes, we can start from there. - The same routine is used to handle both core and exec files; - we just tail-call it with more arguments to select between them. */ + The same routine is used to handle both core and exec files; + we just tail-call it with more arguments to select between them. */ int -xfer_memory (memaddr, myaddr, len, write, target) - CORE_ADDR memaddr; - char *myaddr; - int len; - int write; - struct target_ops *target; +xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, + struct mem_attrib *attrib, + struct target_ops *target) { boolean res; struct section_table *p; CORE_ADDR nextsectaddr, memend; - boolean (*xfer_fn) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); - asection *section; + boolean (*xfer_fn) (bfd *, sec_ptr, PTR, file_ptr, bfd_size_type); + asection *section = NULL; if (len <= 0) - abort(); + internal_error (__FILE__, __LINE__, "failed internal consistency check"); if (overlay_debugging) { @@ -492,56 +501,13 @@ xfer_memory (memaddr, myaddr, len, write, target) xfer_fn = write ? bfd_set_section_contents : bfd_get_section_contents; nextsectaddr = memend; -#if 0 /* Stu's implementation */ -/* If a section has been specified, try to use it. Note that we cannot use the - specified section directly. This is because it usually comes from the - symbol file, which may be different from the exec or core file. Instead, we - have to lookup the specified section by name in the bfd associated with - to_sections. */ - - if (target_memory_bfd_section) - { - asection *s; - bfd *abfd; - asection *target_section; - bfd *target_bfd; - - s = target_memory_bfd_section; - abfd = s->owner; - - target_bfd = target->to_sections->bfd; - target_section = bfd_get_section_by_name (target_bfd, bfd_section_name (abfd, s)); - - if (target_section) - { - bfd_vma sec_addr; - bfd_size_type sec_size; - - sec_addr = bfd_section_vma (target_bfd, target_section); - sec_size = target_section->_raw_size; - - /* Make sure the requested memory starts inside the section. */ - - if (memaddr >= sec_addr - && memaddr < sec_addr + sec_size) - { - /* Cut back length in case request overflows the end of the section. */ - len = min (len, sec_addr + sec_size - memaddr); - - res = xfer_fn (target_bfd, target_section, myaddr, memaddr - sec_addr, len); - - return res ? len : 0; - } - } - } -#endif /* 0, Stu's implementation */ for (p = target->to_sections; p < target->to_sections_end; p++) { if (overlay_debugging && section && p->the_bfd_section && strcmp (section->name, p->the_bfd_section->name) != 0) - continue; /* not the section we need */ + continue; /* not the section we need */ if (memaddr >= p->addr) - if (memend <= p->endaddr) + if (memend <= p->endaddr) { /* Entire transfer is within this section. */ res = xfer_fn (p->bfd, p->the_bfd_section, myaddr, @@ -553,7 +519,7 @@ xfer_memory (memaddr, myaddr, len, write, target) /* This section ends before the transfer starts. */ continue; } - else + else { /* This section overlaps the transfer. Just do half. */ len = p->endaddr - memaddr; @@ -566,36 +532,20 @@ xfer_memory (memaddr, myaddr, len, write, target) } if (nextsectaddr >= memend) - return 0; /* We can't help */ + return 0; /* We can't help */ else - return - (nextsectaddr - memaddr); /* Next boundary where we can help */ + return -(nextsectaddr - memaddr); /* Next boundary where we can help */ } - -#ifdef FIXME -#ifdef REG_STACK_SEGMENT -/* MOVE TO BFD... */ - /* Pyramids and AM29000s have an extra segment in the virtual address space - for the (control) stack of register-window frames. The AM29000 folk - call it the "register stack" rather than the "memory stack". */ - else if (memaddr >= reg_stack_start && memaddr < reg_stack_end) - { - i = min (len, reg_stack_end - memaddr); - fileptr = memaddr - reg_stack_start + reg_stack_offset; - wanna_xfer = coredata; - } -#endif /* REG_STACK_SEGMENT */ -#endif /* FIXME */ + void -print_section_info (t, abfd) - struct target_ops *t; - bfd *abfd; +print_section_info (struct target_ops *t, bfd *abfd) { struct section_table *p; - printf_filtered ("\t`%s', ", bfd_get_filename(abfd)); + printf_filtered ("\t`%s', ", bfd_get_filename (abfd)); wrap_here (" "); - printf_filtered ("file type %s.\n", bfd_get_target(abfd)); + printf_filtered ("file type %s.\n", bfd_get_target (abfd)); if (abfd == exec_bfd) { printf_filtered ("\tEntry point: "); @@ -620,8 +570,7 @@ print_section_info (t, abfd) } static void -exec_files_info (t) - struct target_ops *t; +exec_files_info (struct target_ops *t) { print_section_info (t, exec_bfd); @@ -630,22 +579,64 @@ exec_files_info (t) struct vmap *vp; printf_unfiltered ("\tMapping info for file `%s'.\n", vmap->name); - printf_unfiltered ("\t %8.8s %8.8s %8.8s %8.8s %8.8s %s\n", - "tstart", "tend", "dstart", "dend", "section", - "file(member)"); - - for (vp = vmap; vp; vp = vp->nxt) - printf_unfiltered ("\t0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x %s%s%s%s\n", - vp->tstart, vp->tend, vp->dstart, vp->dend, vp->name, - *vp->member ? "(" : "", vp->member, - *vp->member ? ")" : ""); + printf_unfiltered ("\t %*s %*s %*s %*s %8.8s %s\n", + strlen_paddr (), "tstart", + strlen_paddr (), "tend", + strlen_paddr (), "dstart", + strlen_paddr (), "dend", + "section", + "file(member)"); + + for (vp = vmap; vp; vp = vp->nxt) + printf_unfiltered ("\t0x%s 0x%s 0x%s 0x%s %s%s%s%s\n", + paddr (vp->tstart), + paddr (vp->tend), + paddr (vp->dstart), + paddr (vp->dend), + vp->name, + *vp->member ? "(" : "", vp->member, + *vp->member ? ")" : ""); + } +} + +/* msnyder 5/21/99: + exec_set_section_offsets sets the offsets of all the sections + in the exec objfile. */ + +void +exec_set_section_offsets (bfd_signed_vma text_off, bfd_signed_vma data_off, + bfd_signed_vma bss_off) +{ + struct section_table *sect; + + for (sect = exec_ops.to_sections; + sect < exec_ops.to_sections_end; + sect++) + { + flagword flags; + + flags = bfd_get_section_flags (exec_bfd, sect->the_bfd_section); + + if (flags & SEC_CODE) + { + sect->addr += text_off; + sect->endaddr += text_off; + } + else if (flags & (SEC_DATA | SEC_LOAD)) + { + sect->addr += data_off; + sect->endaddr += data_off; + } + else if (flags & SEC_ALLOC) + { + sect->addr += bss_off; + sect->endaddr += bss_off; + } } } static void -set_section_command (args, from_tty) - char *args; - int from_tty; +set_section_command (char *args, int from_tty) { struct section_table *p; char *secname; @@ -658,23 +649,25 @@ set_section_command (args, from_tty) error ("Must specify section name and its virtual address"); /* Parse out section name */ - for (secname = args; !isspace(*args); args++) ; + for (secname = args; !isspace (*args); args++); seclen = args - secname; /* Parse out new virtual address */ secaddr = parse_and_eval_address (args); - for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) { - if (!strncmp (secname, bfd_section_name (exec_bfd, p->the_bfd_section), seclen) - && bfd_section_name (exec_bfd, p->the_bfd_section)[seclen] == '\0') { - offset = secaddr - p->addr; - p->addr += offset; - p->endaddr += offset; - if (from_tty) - exec_files_info(&exec_ops); - return; + for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) + { + if (!strncmp (secname, bfd_section_name (exec_bfd, p->the_bfd_section), seclen) + && bfd_section_name (exec_bfd, p->the_bfd_section)[seclen] == '\0') + { + offset = secaddr - p->addr; + p->addr += offset; + p->endaddr += offset; + if (from_tty) + exec_files_info (&exec_ops); + return; + } } - } if (seclen >= sizeof (secprint)) seclen = sizeof (secprint) - 1; strncpy (secprint, secname, seclen); @@ -687,24 +680,36 @@ set_section_command (args, from_tty) breakpoint_init_inferior). */ static int -ignore (addr, contents) - CORE_ADDR addr; - char *contents; +ignore (CORE_ADDR addr, char *contents) { return 0; } +/* Find mapped memory. */ + +extern void +exec_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR, + unsigned long, + int, int, int, + void *), + void *)) +{ + exec_ops.to_find_memory_regions = func; +} + +static char *exec_make_note_section (bfd *, int *); + /* Fill in the exec file target vector. Very few entries need to be defined. */ -void -init_exec_ops () +static void +init_exec_ops (void) { exec_ops.to_shortname = "exec"; exec_ops.to_longname = "Local exec file"; exec_ops.to_doc = "Use an executable file as a target.\n\ Specify the filename of the executable file."; - exec_ops.to_open = exec_file_command; + exec_ops.to_open = exec_open; exec_ops.to_close = exec_close; exec_ops.to_attach = find_default_attach; exec_ops.to_require_attach = find_default_require_attach; @@ -717,11 +722,12 @@ Specify the filename of the executable file."; exec_ops.to_clone_and_follow_inferior = find_default_clone_and_follow_inferior; exec_ops.to_stratum = file_stratum; exec_ops.to_has_memory = 1; - exec_ops.to_magic = OPS_MAGIC; + exec_ops.to_make_corefile_notes = exec_make_note_section; + exec_ops.to_magic = OPS_MAGIC; } void -_initialize_exec () +_initialize_exec (void) { struct cmd_list_element *c; @@ -740,24 +746,30 @@ No arg means to have no executable file and no symbols.", &cmdlist); } c = add_cmd ("exec-file", class_files, exec_file_command, - "Use FILE as program for getting contents of pure memory.\n\ + "Use FILE as program for getting contents of pure memory.\n\ If FILE cannot be found as specified, your execution directory path\n\ is searched for a command of that name.\n\ No arg means have no executable file.", &cmdlist); c->completer = filename_completer; add_com ("section", class_files, set_section_command, - "Change the base address of section SECTION of the exec file to ADDR.\n\ + "Change the base address of section SECTION of the exec file to ADDR.\n\ This can be used if the exec file does not contain section addresses,\n\ (such as in the a.out format), or when the addresses specified in the\n\ file itself are wrong. Each section must be changed separately. The\n\ ``info files'' command lists all the sections and their addresses."); add_show_from_set - (add_set_cmd ("write", class_support, var_boolean, (char *)&write_files, + (add_set_cmd ("write", class_support, var_boolean, (char *) &write_files, "Set writing into executable and core files.", &setlist), &showlist); - + add_target (&exec_ops); } + +static char * +exec_make_note_section (bfd *obfd, int *note_size) +{ + error ("Can't create a corefile"); +} diff --git a/contrib/gdb/gdb/gdbserver/gdbreplay.c b/contrib/gdb/gdb/gdbserver/gdbreplay.c index 4f70a94..dce4079 100644 --- a/contrib/gdb/gdb/gdbserver/gdbreplay.c +++ b/contrib/gdb/gdb/gdbserver/gdbreplay.c @@ -1,23 +1,25 @@ /* Replay a remote debug session logfile for GDB. - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright 1996, 1998, 1999, 2000 Free Software Foundation, Inc. Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver. -This file is part of GDB. + 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 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. + 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. */ + 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 "config.h" #include <stdio.h> #include <sys/file.h> #include <netinet/in.h> @@ -26,9 +28,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <netinet/tcp.h> #include <signal.h> #include <ctype.h> -#include <errno.h> -#include <string.h> #include <fcntl.h> +#include <errno.h> /* Sort of a hack... */ #define EOL (EOF - 1) @@ -40,13 +41,17 @@ static int remote_desc; Then return to command level. */ void -perror_with_name (string) - char *string; +perror_with_name (char *string) { - char *err; +#ifndef STDC_HEADERS + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; +#endif + const char *err; char *combined; - err = strerror(errno); + err = (errno < sys_nerr) ? sys_errlist[errno] : "unknown error"; combined = (char *) alloca (strlen (err) + strlen (string) + 3); strcpy (combined, string); strcat (combined, ": "); @@ -57,11 +62,7 @@ perror_with_name (string) } static void -sync_error (fp, desc, expect, got) - FILE *fp; - char *desc; - int expect; - int got; +sync_error (FILE *fp, char *desc, int expect, int got) { fprintf (stderr, "\n%s\n", desc); fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n", @@ -71,7 +72,7 @@ sync_error (fp, desc, expect, got) } void -remote_close() +remote_close (void) { close (remote_desc); } @@ -80,8 +81,7 @@ remote_close() NAME is the filename used for communication. */ void -remote_open (name) - char *name; +remote_open (char *name) { extern char *strchr (); @@ -97,7 +97,6 @@ remote_open (name) int port; struct sockaddr_in sockaddr; int tmp; - struct protoent *protoent; int tmp_desc; port_str = strchr (name, ':'); @@ -110,40 +109,36 @@ remote_open (name) /* Allow rapid reuse of this port. */ tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, - sizeof(tmp)); + setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, + sizeof (tmp)); sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons(port); + sockaddr.sin_port = htons (port); sockaddr.sin_addr.s_addr = INADDR_ANY; - if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr)) + if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) || listen (tmp_desc, 1)) perror_with_name ("Can't bind address"); tmp = sizeof (sockaddr); - remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp); + remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp); if (remote_desc == -1) perror_with_name ("Accept failed"); - protoent = getprotobyname ("tcp"); - if (!protoent) - perror_with_name ("getprotobyname"); - /* Enable TCP keep alive process. */ tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); + setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp)); /* Tell TCP not to delay small packets. This greatly speeds up - interactive response. */ + interactive response. */ tmp = 1; - setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY, - (char *)&tmp, sizeof(tmp)); + setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (tmp)); close (tmp_desc); /* No longer need this */ - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply - exits when the remote side dies. */ + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply + exits when the remote side dies. */ } fcntl (remote_desc, F_SETFL, FASYNC); @@ -152,8 +147,8 @@ remote_open (name) fflush (stderr); } -static int tohex (ch) - int ch; +static int +tohex (int ch) { if (ch >= '0' && ch <= '9') { @@ -173,8 +168,7 @@ static int tohex (ch) } static int -logchar (fp) - FILE *fp; +logchar (FILE *fp) { int ch; int ch2; @@ -193,13 +187,26 @@ logchar (fp) fflush (stdout); switch (ch) { - case '\\': break; - case 'b': ch = '\b'; break; - case 'f': ch = '\f'; break; - case 'n': ch = '\n'; break; - case 'r': ch = '\r'; break; - case 't': ch = '\t'; break; - case 'v': ch = '\v'; break; + case '\\': + break; + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case 'v': + ch = '\v'; + break; case 'x': ch2 = fgetc (fp); fputc (ch2, stdout); @@ -224,8 +231,7 @@ logchar (fp) blank) up until a \n is read from fp (which is not matched) */ void -expect (fp) - FILE *fp; +expect (FILE *fp) { int fromlog; unsigned char fromgdb; @@ -243,7 +249,8 @@ expect (fp) break; } read (remote_desc, &fromgdb, 1); - } while (fromlog == fromgdb); + } + while (fromlog == fromgdb); if (fromlog != EOL) { sync_error (fp, "Sync error during read of gdb packet", fromlog, @@ -255,8 +262,7 @@ expect (fp) \n is read from fp (which is discarded and not sent to gdb). */ void -play (fp) - FILE *fp; +play (FILE *fp) { int fromlog; char ch; @@ -274,9 +280,7 @@ play (fp) } int -main (argc, argv) - int argc; - char *argv[]; +main (int argc, char *argv[]) { FILE *fp; int ch; @@ -291,7 +295,7 @@ main (argc, argv) if (fp == NULL) { perror_with_name (argv[1]); - } + } remote_open (argv[2]); while ((ch = logchar (fp)) != EOF) { @@ -314,4 +318,3 @@ main (argc, argv) remote_close (); exit (0); } - diff --git a/contrib/gdb/gdb/gdbserver/utils.c b/contrib/gdb/gdb/gdbserver/utils.c index 75a6a34..a8ea9a1 100644 --- a/contrib/gdb/gdb/gdbserver/utils.c +++ b/contrib/gdb/gdb/gdbserver/utils.c @@ -1,21 +1,23 @@ /* General utility routines for the remote server for GDB. - Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc. + Copyright 1986, 1989, 1993, 1995, 1996, 1997, 1999, 2000, 2002 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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 "server.h" #include <stdio.h> @@ -28,9 +30,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ Then return to command level. */ void -perror_with_name (string) - char *string; +perror_with_name (char *string) { +#ifndef STDC_HEADERS + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; +#endif const char *err; char *combined; @@ -51,35 +57,16 @@ perror_with_name (string) STRING is the error message, used as a fprintf string, and ARG is passed as an argument to it. */ -#ifdef ANSI_PROTOTYPES NORETURN void -error (const char *string, ...) -#else -void -error (va_alist) - va_dcl -#endif +error (const char *string,...) { extern jmp_buf toplevel; va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, string); -#else - va_start (args); -#endif fflush (stdout); -#ifdef ANSI_PROTOTYPES vfprintf (stderr, string, args); -#else - { - char *string1; - - string1 = va_arg (args, char *); - vfprintf (stderr, string1, args); - } -#endif fprintf (stderr, "\n"); - longjmp(toplevel, 1); + longjmp (toplevel, 1); } /* Print an error message and exit reporting failure. @@ -88,24 +75,25 @@ error (va_alist) /* VARARGS */ NORETURN void -#ifdef ANSI_PROTOTYPES -fatal (char *string, ...) -#else -fatal (va_alist) - va_dcl -#endif +fatal (const char *string,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, string); -#else - char *string; - va_start (args); - string = va_arg (args, char *); -#endif fprintf (stderr, "gdb: "); vfprintf (stderr, string, args); fprintf (stderr, "\n"); va_end (args); exit (1); } + +/* VARARGS */ +void +warning (const char *string,...) +{ + va_list args; + va_start (args, string); + fprintf (stderr, "gdb: "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); +} diff --git a/contrib/gdb/gdb/i386-tdep.c b/contrib/gdb/gdb/i386-tdep.c index fbbb879..b2ddd28 100644 --- a/contrib/gdb/gdb/i386-tdep.c +++ b/contrib/gdb/gdb/i386-tdep.c @@ -1,22 +1,24 @@ /* Intel 386 target-dependent stuff. - Copyright (C) 1988, 1989, 1991, 1994, 1995, 1996, 1998 + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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_string.h" @@ -28,52 +30,189 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "symtab.h" #include "gdbcmd.h" #include "command.h" +#include "arch-utils.h" +#include "regcache.h" +#include "doublest.h" +#include "value.h" +#include "gdb_assert.h" -static long i386_get_frame_setup PARAMS ((CORE_ADDR)); +#include "elf-bfd.h" -static void i386_follow_jump PARAMS ((void)); +#include "i386-tdep.h" -static void codestream_read PARAMS ((unsigned char *, int)); +#undef XMALLOC +#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) -static void codestream_seek PARAMS ((CORE_ADDR)); +/* Names of the registers. The first 10 registers match the register + numbering scheme used by GCC for stabs and DWARF. */ +static char *i386_register_names[] = +{ + "eax", "ecx", "edx", "ebx", + "esp", "ebp", "esi", "edi", + "eip", "eflags", "cs", "ss", + "ds", "es", "fs", "gs", + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + "fctrl", "fstat", "ftag", "fiseg", + "fioff", "foseg", "fooff", "fop", + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "mxcsr" +}; + +/* i386_register_offset[i] is the offset into the register file of the + start of register number i. We initialize this from + i386_register_size. */ +static int i386_register_offset[MAX_NUM_REGS]; + +/* i386_register_size[i] is the number of bytes of storage in GDB's + register array occupied by register i. */ +static int i386_register_size[MAX_NUM_REGS] = { + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 10, 10, 10, 10, + 10, 10, 10, 10, + 4, 4, 4, 4, + 4, 4, 4, 4, + 16, 16, 16, 16, + 16, 16, 16, 16, + 4 +}; + +/* Return the name of register REG. */ + +char * +i386_register_name (int reg) +{ + if (reg < 0) + return NULL; + if (reg >= sizeof (i386_register_names) / sizeof (*i386_register_names)) + return NULL; + + return i386_register_names[reg]; +} + +/* Return the offset into the register array of the start of register + number REG. */ +int +i386_register_byte (int reg) +{ + return i386_register_offset[reg]; +} -static unsigned char codestream_fill PARAMS ((int)); +/* Return the number of bytes of storage in GDB's register array + occupied by register REG. */ + +int +i386_register_raw_size (int reg) +{ + return i386_register_size[reg]; +} -CORE_ADDR skip_trampoline_code PARAMS ((CORE_ADDR, char *)); +/* Return the size in bytes of the virtual type of register REG. */ -static int gdb_print_insn_i386 (bfd_vma, disassemble_info *); +int +i386_register_virtual_size (int reg) +{ + return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (reg)); +} + +/* Convert stabs register number REG to the appropriate register + number used by GDB. */ + +int +i386_stab_reg_to_regnum (int reg) +{ + /* This implements what GCC calls the "default" register map. */ + if (reg >= 0 && reg <= 7) + { + /* General registers. */ + return reg; + } + else if (reg >= 12 && reg <= 19) + { + /* Floating-point registers. */ + return reg - 12 + FP0_REGNUM; + } + else if (reg >= 21 && reg <= 28) + { + /* SSE registers. */ + return reg - 21 + XMM0_REGNUM; + } + else if (reg >= 29 && reg <= 36) + { + /* MMX registers. */ + /* FIXME: kettenis/2001-07-28: Should we have the MMX registers + as pseudo-registers? */ + return reg - 29 + FP0_REGNUM; + } + + /* This will hopefully provoke a warning. */ + return NUM_REGS + NUM_PSEUDO_REGS; +} -void _initialize_i386_tdep PARAMS ((void)); +/* Convert Dwarf register number REG to the appropriate register + number used by GDB. */ -/* This is the variable the is set with "set disassembly-flavor", - and its legitimate values. */ -static char att_flavor[] = "att"; -static char intel_flavor[] = "intel"; -static char *valid_flavors[] = { +int +i386_dwarf_reg_to_regnum (int reg) +{ + /* The DWARF register numbering includes %eip and %eflags, and + numbers the floating point registers differently. */ + if (reg >= 0 && reg <= 9) + { + /* General registers. */ + return reg; + } + else if (reg >= 11 && reg <= 18) + { + /* Floating-point registers. */ + return reg - 11 + FP0_REGNUM; + } + else if (reg >= 21) + { + /* The SSE and MMX registers have identical numbers as in stabs. */ + return i386_stab_reg_to_regnum (reg); + } + + /* This will hopefully provoke a warning. */ + return NUM_REGS + NUM_PSEUDO_REGS; +} + + +/* This is the variable that is set with "set disassembly-flavor", and + its legitimate values. */ +static const char att_flavor[] = "att"; +static const char intel_flavor[] = "intel"; +static const char *valid_flavors[] = +{ att_flavor, intel_flavor, NULL }; -static char *disassembly_flavor = att_flavor; - -/* Stdio style buffering was used to minimize calls to ptrace, but this - buffering did not take into account that the code section being accessed - may not be an even number of buffers long (even if the buffer is only - sizeof(int) long). In cases where the code section size happened to - be a non-integral number of buffers long, attempting to read the last - buffer would fail. Simply using target_read_memory and ignoring errors, - rather than read_memory, is not the correct solution, since legitimate - access errors would then be totally ignored. To properly handle this - situation and continue to use buffering would require that this code - be able to determine the minimum code section size granularity (not the - alignment of the section itself, since the actual failing case that - pointed out this problem had a section alignment of 4 but was not a - multiple of 4 bytes long), on a target by target basis, and then - adjust it's buffer size accordingly. This is messy, but potentially - feasible. It probably needs the bfd library's help and support. For - now, the buffer size is set to 1. (FIXME -fnf) */ - -#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */ +static const char *disassembly_flavor = att_flavor; + +/* Stdio style buffering was used to minimize calls to ptrace, but + this buffering did not take into account that the code section + being accessed may not be an even number of buffers long (even if + the buffer is only sizeof(int) long). In cases where the code + section size happened to be a non-integral number of buffers long, + attempting to read the last buffer would fail. Simply using + target_read_memory and ignoring errors, rather than read_memory, is + not the correct solution, since legitimate access errors would then + be totally ignored. To properly handle this situation and continue + to use buffering would require that this code be able to determine + the minimum code section size granularity (not the alignment of the + section itself, since the actual failing case that pointed out this + problem had a section alignment of 4 but was not a multiple of 4 + bytes long), on a target by target basis, and then adjust it's + buffer size accordingly. This is messy, but potentially feasible. + It probably needs the bfd library's help and support. For now, the + buffer size is set to 1. (FIXME -fnf) */ + +#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */ static CORE_ADDR codestream_next_addr; static CORE_ADDR codestream_addr; static unsigned char codestream_buf[CODESTREAM_BUFSIZ]; @@ -81,43 +220,41 @@ static int codestream_off; static int codestream_cnt; #define codestream_tell() (codestream_addr + codestream_off) -#define codestream_peek() (codestream_cnt == 0 ? \ - codestream_fill(1): codestream_buf[codestream_off]) -#define codestream_get() (codestream_cnt-- == 0 ? \ - codestream_fill(0) : codestream_buf[codestream_off++]) - -static unsigned char -codestream_fill (peek_flag) - int peek_flag; +#define codestream_peek() \ + (codestream_cnt == 0 ? \ + codestream_fill(1) : codestream_buf[codestream_off]) +#define codestream_get() \ + (codestream_cnt-- == 0 ? \ + codestream_fill(0) : codestream_buf[codestream_off++]) + +static unsigned char +codestream_fill (int peek_flag) { codestream_addr = codestream_next_addr; codestream_next_addr += CODESTREAM_BUFSIZ; codestream_off = 0; codestream_cnt = CODESTREAM_BUFSIZ; read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ); - + if (peek_flag) - return (codestream_peek()); + return (codestream_peek ()); else - return (codestream_get()); + return (codestream_get ()); } static void -codestream_seek (place) - CORE_ADDR place; +codestream_seek (CORE_ADDR place) { codestream_next_addr = place / CODESTREAM_BUFSIZ; codestream_next_addr *= CODESTREAM_BUFSIZ; codestream_cnt = 0; codestream_fill (1); - while (codestream_tell() != place) + while (codestream_tell () != place) codestream_get (); } static void -codestream_read (buf, count) - unsigned char *buf; - int count; +codestream_read (unsigned char *buf, int count) { unsigned char *p; int i; @@ -125,11 +262,12 @@ codestream_read (buf, count) for (i = 0; i < count; i++) *p++ = codestream_get (); } + -/* next instruction is a jump, move to target */ +/* If the next instruction is a jump, move to its target. */ static void -i386_follow_jump () +i386_follow_jump (void) { unsigned char buf[4]; long delta; @@ -149,14 +287,15 @@ i386_follow_jump () switch (codestream_get ()) { case 0xe9: - /* relative jump: if data16 == 0, disp32, else disp16 */ + /* Relative jump: if data16 == 0, disp32, else disp16. */ if (data16) { codestream_read (buf, 2); delta = extract_signed_integer (buf, 2); - /* include size of jmp inst (including the 0x66 prefix). */ - pos += delta + 4; + /* Include the size of the jmp instruction (including the + 0x66 prefix). */ + pos += delta + 4; } else { @@ -167,7 +306,7 @@ i386_follow_jump () } break; case 0xeb: - /* relative jump, disp8 (ignore data16) */ + /* Relative jump, disp8 (ignore data16). */ codestream_read (buf, 1); /* Sign-extend it. */ delta = extract_signed_integer (buf, 1); @@ -178,17 +317,14 @@ i386_follow_jump () codestream_seek (pos); } -/* - * find & return amound a local space allocated, and advance codestream to - * first register push (if any) - * - * if entry sequence doesn't make sense, return -1, and leave - * codestream pointer random - */ +/* Find & return the amount a local space allocated, and advance the + codestream to the first register push (if any). + + If the entry sequence doesn't make sense, return -1, and leave + codestream pointer at a random spot. */ static long -i386_get_frame_setup (pc) - CORE_ADDR pc; +i386_get_frame_setup (CORE_ADDR pc) { unsigned char op; @@ -200,24 +336,22 @@ i386_get_frame_setup (pc) if (op == 0x58) /* popl %eax */ { - /* - * this function must start with - * - * popl %eax 0x58 - * xchgl %eax, (%esp) 0x87 0x04 0x24 - * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 - * - * (the system 5 compiler puts out the second xchg - * inst, and the assembler doesn't try to optimize it, - * so the 'sib' form gets generated) - * - * this sequence is used to get the address of the return - * buffer for a function that returns a structure - */ + /* This function must start with + + popl %eax 0x58 + xchgl %eax, (%esp) 0x87 0x04 0x24 + or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 + + (the System V compiler puts out the second `xchg' + instruction, and the assembler doesn't try to optimize it, so + the 'sib' form gets generated). This sequence is used to get + the address of the return buffer for a function that returns + a structure. */ int pos; unsigned char buf[4]; - static unsigned char proto1[3] = { 0x87,0x04,0x24 }; - static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; + static unsigned char proto1[3] = { 0x87, 0x04, 0x24 }; + static unsigned char proto2[4] = { 0x87, 0x44, 0x24, 0x00 }; + pos = codestream_tell (); codestream_read (buf, 4); if (memcmp (buf, proto1, 3) == 0) @@ -226,25 +360,26 @@ i386_get_frame_setup (pc) pos += 4; codestream_seek (pos); - op = codestream_get (); /* update next opcode */ + op = codestream_get (); /* Update next opcode. */ } if (op == 0x68 || op == 0x6a) { - /* - * this function may start with - * - * pushl constant - * call _probe - * addl $4, %esp - * followed by - * pushl %ebp - * etc. - */ + /* This function may start with + + pushl constant + call _probe + addl $4, %esp + + followed by + + pushl %ebp + + etc. */ int pos; unsigned char buf[8]; - /* Skip past the pushl instruction; it has either a one-byte + /* Skip past the `pushl' instruction; it has either a one-byte or a four-byte operand, depending on the opcode. */ pos = codestream_tell (); if (op == 0x68) @@ -253,151 +388,206 @@ i386_get_frame_setup (pc) pos += 1; codestream_seek (pos); - /* Read the following 8 bytes, which should be "call _probe" (6 bytes) - followed by "addl $4,%esp" (2 bytes). */ + /* Read the following 8 bytes, which should be "call _probe" (6 + bytes) followed by "addl $4,%esp" (2 bytes). */ codestream_read (buf, sizeof (buf)); if (buf[0] == 0xe8 && buf[6] == 0xc4 && buf[7] == 0x4) pos += sizeof (buf); codestream_seek (pos); - op = codestream_get (); /* update next opcode */ + op = codestream_get (); /* Update next opcode. */ } if (op == 0x55) /* pushl %ebp */ - { - /* check for movl %esp, %ebp - can be written two ways */ + { + /* Check for "movl %esp, %ebp" -- can be written in two ways. */ switch (codestream_get ()) { case 0x8b: if (codestream_get () != 0xec) - return (-1); + return -1; break; case 0x89: if (codestream_get () != 0xe5) - return (-1); + return -1; break; default: - return (-1); + return -1; } - /* check for stack adjustment - * - * subl $XXX, %esp - * - * note: you can't subtract a 16 bit immediate - * from a 32 bit reg, so we don't have to worry - * about a data16 prefix - */ + /* Check for stack adjustment + + subl $XXX, %esp + + NOTE: You can't subtract a 16 bit immediate from a 32 bit + reg, so we don't have to worry about a data16 prefix. */ op = codestream_peek (); if (op == 0x83) { - /* subl with 8 bit immed */ + /* `subl' with 8 bit immediate. */ codestream_get (); if (codestream_get () != 0xec) - /* Some instruction starting with 0x83 other than subl. */ + /* Some instruction starting with 0x83 other than `subl'. */ { codestream_seek (codestream_tell () - 2); return 0; } - /* subl with signed byte immediate - * (though it wouldn't make sense to be negative) - */ - return (codestream_get()); + /* `subl' with signed byte immediate (though it wouldn't + make sense to be negative). */ + return (codestream_get ()); } else if (op == 0x81) { char buf[4]; - /* Maybe it is subl with 32 bit immedediate. */ - codestream_get(); + /* Maybe it is `subl' with a 32 bit immedediate. */ + codestream_get (); if (codestream_get () != 0xec) - /* Some instruction starting with 0x81 other than subl. */ + /* Some instruction starting with 0x81 other than `subl'. */ { codestream_seek (codestream_tell () - 2); return 0; } - /* It is subl with 32 bit immediate. */ - codestream_read ((unsigned char *)buf, 4); + /* It is `subl' with a 32 bit immediate. */ + codestream_read ((unsigned char *) buf, 4); return extract_signed_integer (buf, 4); } else { - return (0); + return 0; } } else if (op == 0xc8) { char buf[2]; - /* enter instruction: arg is 16 bit unsigned immed */ - codestream_read ((unsigned char *)buf, 2); - codestream_get (); /* flush final byte of enter instruction */ + /* `enter' with 16 bit unsigned immediate. */ + codestream_read ((unsigned char *) buf, 2); + codestream_get (); /* Flush final byte of enter instruction. */ return extract_unsigned_integer (buf, 2); } return (-1); } +/* Return the chain-pointer for FRAME. In the case of the i386, the + frame's nominal address is the address of a 4-byte word containing + the calling frame's address. */ + +CORE_ADDR +i386_frame_chain (struct frame_info *frame) +{ + if (frame->signal_handler_caller) + return frame->frame; + + if (! inside_entry_file (frame->pc)) + return read_memory_unsigned_integer (frame->frame, 4); + + return 0; +} + +/* Determine whether the function invocation represented by FRAME does + not have a from on the stack associated with it. If it does not, + return non-zero, otherwise return zero. */ + +int +i386_frameless_function_invocation (struct frame_info *frame) +{ + if (frame->signal_handler_caller) + return 0; + + return frameless_look_for_prologue (frame); +} + +/* Return the saved program counter for FRAME. */ + +CORE_ADDR +i386_frame_saved_pc (struct frame_info *frame) +{ + /* FIXME: kettenis/2001-05-09: Conditionalizing the next bit of code + on SIGCONTEXT_PC_OFFSET and I386V4_SIGTRAMP_SAVED_PC should be + considered a temporary hack. I plan to come up with something + better when we go multi-arch. */ +#if defined (SIGCONTEXT_PC_OFFSET) || defined (I386V4_SIGTRAMP_SAVED_PC) + if (frame->signal_handler_caller) + return sigtramp_saved_pc (frame); +#endif + + return read_memory_unsigned_integer (frame->frame + 4, 4); +} + +CORE_ADDR +i386go32_frame_saved_pc (struct frame_info *frame) +{ + return read_memory_integer (frame->frame + 4, 4); +} + +/* Immediately after a function call, return the saved pc. */ + +CORE_ADDR +i386_saved_pc_after_call (struct frame_info *frame) +{ + return read_memory_unsigned_integer (read_register (SP_REGNUM), 4); +} + /* Return number of args passed to a frame. Can return -1, meaning no way to tell. */ int -i386_frame_num_args (fi) - struct frame_info *fi; +i386_frame_num_args (struct frame_info *fi) { #if 1 return -1; #else /* This loses because not only might the compiler not be popping the - args right after the function call, it might be popping args from both - this call and a previous one, and we would say there are more args - than there really are. */ + args right after the function call, it might be popping args from + both this call and a previous one, and we would say there are + more args than there really are. */ - int retpc; - unsigned char op; + int retpc; + unsigned char op; struct frame_info *pfi; - /* on the 386, the instruction following the call could be: + /* On the i386, the instruction following the call could be: popl %ecx - one arg addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits - anything else - zero args */ + anything else - zero args. */ int frameless; - FRAMELESS_FUNCTION_INVOCATION (fi, frameless); + frameless = FRAMELESS_FUNCTION_INVOCATION (fi); if (frameless) - /* In the absence of a frame pointer, GDB doesn't get correct values - for nameless arguments. Return -1, so it doesn't print any - nameless arguments. */ + /* In the absence of a frame pointer, GDB doesn't get correct + values for nameless arguments. Return -1, so it doesn't print + any nameless arguments. */ return -1; - pfi = get_prev_frame_info (fi); + pfi = get_prev_frame (fi); if (pfi == 0) { - /* Note: this can happen if we are looking at the frame for - main, because FRAME_CHAIN_VALID won't let us go into - start. If we have debugging symbols, that's not really - a big deal; it just means it will only show as many arguments - to main as are declared. */ + /* NOTE: This can happen if we are looking at the frame for + main, because FRAME_CHAIN_VALID won't let us go into start. + If we have debugging symbols, that's not really a big deal; + it just means it will only show as many arguments to main as + are declared. */ return -1; } else { - retpc = pfi->pc; - op = read_memory_integer (retpc, 1); - if (op == 0x59) - /* pop %ecx */ - return 1; + retpc = pfi->pc; + op = read_memory_integer (retpc, 1); + if (op == 0x59) /* pop %ecx */ + return 1; else if (op == 0x83) { - op = read_memory_integer (retpc+1, 1); - if (op == 0xc4) - /* addl $<signed imm 8 bits>, %esp */ - return (read_memory_integer (retpc+2,1)&0xff)/4; + op = read_memory_integer (retpc + 1, 1); + if (op == 0xc4) + /* addl $<signed imm 8 bits>, %esp */ + return (read_memory_integer (retpc + 2, 1) & 0xff) / 4; else return 0; } - else if (op == 0x81) - { /* add with 32 bit immediate */ - op = read_memory_integer (retpc+1, 1); - if (op == 0xc4) - /* addl $<imm 32>, %esp */ - return read_memory_integer (retpc+2, 4) / 4; + else if (op == 0x81) /* `add' with 32 bit immediate. */ + { + op = read_memory_integer (retpc + 1, 1); + if (op == 0xc4) + /* addl $<imm 32>, %esp */ + return read_memory_integer (retpc + 2, 4) / 4; else return 0; } @@ -409,138 +599,137 @@ i386_frame_num_args (fi) #endif } -/* - * parse the first few instructions of the function to see - * what registers were stored. - * - * We handle these cases: - * - * The startup sequence can be at the start of the function, - * or the function can start with a branch to startup code at the end. - * - * %ebp can be set up with either the 'enter' instruction, or - * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, - * but was once used in the sys5 compiler) - * - * Local space is allocated just below the saved %ebp by either the - * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has - * a 16 bit unsigned argument for space to allocate, and the - * 'addl' instruction could have either a signed byte, or - * 32 bit immediate. - * - * Next, the registers used by this function are pushed. In - * the sys5 compiler they will always be in the order: %edi, %esi, %ebx - * (and sometimes a harmless bug causes it to also save but not restore %eax); - * however, the code below is willing to see the pushes in any order, - * and will handle up to 8 of them. - * - * If the setup sequence is at the end of the function, then the - * next instruction will be a branch back to the start. - */ +/* Parse the first few instructions the function to see what registers + were stored. + + We handle these cases: + + The startup sequence can be at the start of the function, or the + function can start with a branch to startup code at the end. + + %ebp can be set up with either the 'enter' instruction, or "pushl + %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was + once used in the System V compiler). + + Local space is allocated just below the saved %ebp by either the + 'enter' instruction, or by "subl $<size>, %esp". 'enter' has a 16 + bit unsigned argument for space to allocate, and the 'addl' + instruction could have either a signed byte, or 32 bit immediate. + + Next, the registers used by this function are pushed. With the + System V compiler they will always be in the order: %edi, %esi, + %ebx (and sometimes a harmless bug causes it to also save but not + restore %eax); however, the code below is willing to see the pushes + in any order, and will handle up to 8 of them. + + If the setup sequence is at the end of the function, then the next + instruction will be a branch back to the start. */ void -i386_frame_find_saved_regs (fip, fsrp) - struct frame_info *fip; - struct frame_saved_regs *fsrp; +i386_frame_init_saved_regs (struct frame_info *fip) { long locals = -1; unsigned char op; CORE_ADDR dummy_bottom; - CORE_ADDR adr; + CORE_ADDR addr; CORE_ADDR pc; int i; - - memset (fsrp, 0, sizeof *fsrp); - - /* if frame is the end of a dummy, compute where the - * beginning would be - */ + + if (fip->saved_regs) + return; + + frame_saved_regs_zalloc (fip); + + /* If the frame is the end of a dummy, compute where the beginning + would be. */ dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH; - - /* check if the PC is in the stack, in a dummy frame */ - if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + + /* Check if the PC points in the stack, in a dummy frame. */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) { - /* all regs were saved by push_call_dummy () */ - adr = fip->frame; - for (i = 0; i < NUM_REGS; i++) + /* All registers were saved by push_call_dummy. */ + addr = fip->frame; + for (i = 0; i < NUM_REGS; i++) { - adr -= REGISTER_RAW_SIZE (i); - fsrp->regs[i] = adr; + addr -= REGISTER_RAW_SIZE (i); + fip->saved_regs[i] = addr; } return; } - + pc = get_pc_function_start (fip->pc); if (pc != 0) locals = i386_get_frame_setup (pc); - - if (locals >= 0) + + if (locals >= 0) { - adr = fip->frame - 4 - locals; - for (i = 0; i < 8; i++) + addr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) { op = codestream_get (); if (op < 0x50 || op > 0x57) break; #ifdef I386_REGNO_TO_SYMMETRY /* Dynix uses different internal numbering. Ick. */ - fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr; + fip->saved_regs[I386_REGNO_TO_SYMMETRY (op - 0x50)] = addr; #else - fsrp->regs[op - 0x50] = adr; + fip->saved_regs[op - 0x50] = addr; #endif - adr -= 4; + addr -= 4; } } - - fsrp->regs[PC_REGNUM] = fip->frame + 4; - fsrp->regs[FP_REGNUM] = fip->frame; + + fip->saved_regs[PC_REGNUM] = fip->frame + 4; + fip->saved_regs[FP_REGNUM] = fip->frame; } -/* return pc of first real instruction */ +/* Return PC of first real instruction. */ int -i386_skip_prologue (pc) - int pc; +i386_skip_prologue (int pc) { unsigned char op; int i; - static unsigned char pic_pat[6] = { 0xe8, 0, 0, 0, 0, /* call 0x0 */ - 0x5b, /* popl %ebx */ - }; + static unsigned char pic_pat[6] = + { 0xe8, 0, 0, 0, 0, /* call 0x0 */ + 0x5b, /* popl %ebx */ + }; CORE_ADDR pos; - + if (i386_get_frame_setup (pc) < 0) return (pc); - - /* found valid frame setup - codestream now points to - * start of push instructions for saving registers - */ - - /* skip over register saves */ + + /* Found valid frame setup -- codestream now points to start of push + instructions for saving registers. */ + + /* Skip over register saves. */ for (i = 0; i < 8; i++) { op = codestream_peek (); - /* break if not pushl inst */ - if (op < 0x50 || op > 0x57) + /* Break if not `pushl' instrunction. */ + if (op < 0x50 || op > 0x57) break; codestream_get (); } - /* The native cc on SVR4 in -K PIC mode inserts the following code to get - the address of the global offset table (GOT) into register %ebx. - call 0x0 - popl %ebx - movl %ebx,x(%ebp) (optional) - addl y,%ebx + /* The native cc on SVR4 in -K PIC mode inserts the following code + to get the address of the global offset table (GOT) into register + %ebx + + call 0x0 + popl %ebx + movl %ebx,x(%ebp) (optional) + addl y,%ebx + This code is with the rest of the prologue (at the end of the function), so we have to skip it to get to the first real instruction at the start of the function. */ - + pos = codestream_tell (); for (i = 0; i < 6; i++) { op = codestream_get (); - if (pic_pat [i] != op) + if (pic_pat[i] != op) break; } if (i == 6) @@ -549,72 +738,94 @@ i386_skip_prologue (pc) long delta = 6; op = codestream_get (); - if (op == 0x89) /* movl %ebx, x(%ebp) */ + if (op == 0x89) /* movl %ebx, x(%ebp) */ { op = codestream_get (); - if (op == 0x5d) /* one byte offset from %ebp */ + if (op == 0x5d) /* One byte offset from %ebp. */ { delta += 3; codestream_read (buf, 1); } - else if (op == 0x9d) /* four byte offset from %ebp */ + else if (op == 0x9d) /* Four byte offset from %ebp. */ { delta += 6; codestream_read (buf, 4); } - else /* unexpected instruction */ - delta = -1; - op = codestream_get (); + else /* Unexpected instruction. */ + delta = -1; + op = codestream_get (); } - /* addl y,%ebx */ - if (delta > 0 && op == 0x81 && codestream_get () == 0xc3) + /* addl y,%ebx */ + if (delta > 0 && op == 0x81 && codestream_get () == 0xc3) { - pos += delta + 6; + pos += delta + 6; } } codestream_seek (pos); - + i386_follow_jump (); - + return (codestream_tell ()); } void -i386_push_dummy_frame () +i386_push_dummy_frame (void) { CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR fp; int regnum; char regbuf[MAX_REGISTER_RAW_SIZE]; - + sp = push_word (sp, read_register (PC_REGNUM)); sp = push_word (sp, read_register (FP_REGNUM)); - write_register (FP_REGNUM, sp); + fp = sp; for (regnum = 0; regnum < NUM_REGS; regnum++) { read_register_gen (regnum, regbuf); sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum)); } write_register (SP_REGNUM, sp); + write_register (FP_REGNUM, fp); +} + +/* Insert the (relative) function address into the call sequence + stored at DYMMY. */ + +void +i386_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, + struct value **args, struct type *type, int gcc_p) +{ + int from, to, delta, loc; + + loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); + from = loc + 5; + to = (int)(fun); + delta = to - from; + + *((char *)(dummy) + 1) = (delta & 0xff); + *((char *)(dummy) + 2) = ((delta >> 8) & 0xff); + *((char *)(dummy) + 3) = ((delta >> 16) & 0xff); + *((char *)(dummy) + 4) = ((delta >> 24) & 0xff); } void -i386_pop_frame () +i386_pop_frame (void) { struct frame_info *frame = get_current_frame (); CORE_ADDR fp; int regnum; - struct frame_saved_regs fsr; char regbuf[MAX_REGISTER_RAW_SIZE]; - + fp = FRAME_FP (frame); - get_frame_saved_regs (frame, &fsr); - for (regnum = 0; regnum < NUM_REGS; regnum++) + i386_frame_init_saved_regs (frame); + + for (regnum = 0; regnum < NUM_REGS; regnum++) { - CORE_ADDR adr; - adr = fsr.regs[regnum]; - if (adr) + CORE_ADDR addr; + addr = frame->saved_regs[regnum]; + if (addr) { - read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum)); + read_memory (addr, regbuf, REGISTER_RAW_SIZE (regnum)); write_register_bytes (REGISTER_BYTE (regnum), regbuf, REGISTER_RAW_SIZE (regnum)); } @@ -624,24 +835,35 @@ i386_pop_frame () write_register (SP_REGNUM, fp + 8); flush_cached_frames (); } + #ifdef GET_LONGJMP_TARGET -/* Figure out where the longjmp will land. Slurp the args out of the stack. - We expect the first arg to be a pointer to the jmp_buf structure from which - we extract the pc (JB_PC) that we will land at. The pc is copied into PC. - This routine returns true on success. */ +/* FIXME: Multi-arching does not set JB_PC and JB_ELEMENT_SIZE yet. + Fill in with dummy value to enable compilation. */ +#ifndef JB_PC +#define JB_PC 0 +#endif /* JB_PC */ + +#ifndef JB_ELEMENT_SIZE +#define JB_ELEMENT_SIZE 4 +#endif /* JB_ELEMENT_SIZE */ + +/* Figure out where the longjmp will land. Slurp the args out of the + stack. We expect the first arg to be a pointer to the jmp_buf + structure from which we extract the pc (JB_PC) that we will land + at. The pc is copied into PC. This routine returns true on + success. */ int -get_longjmp_target(pc) - CORE_ADDR *pc; +get_longjmp_target (CORE_ADDR *pc) { char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; CORE_ADDR sp, jb_addr; sp = read_register (SP_REGNUM); - if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */ + if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack. */ buf, TARGET_PTR_BIT / TARGET_CHAR_BIT)) return 0; @@ -658,38 +880,257 @@ get_longjmp_target(pc) } #endif /* GET_LONGJMP_TARGET */ + + +CORE_ADDR +i386_push_arguments (int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + sp = default_push_arguments (nargs, args, sp, struct_return, struct_addr); + + if (struct_return) + { + char buf[4]; + + sp -= 4; + store_address (buf, 4, struct_addr); + write_memory (sp, buf, 4); + } + + return sp; +} + +void +i386_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +{ + /* Do nothing. Everything was already done by i386_push_arguments. */ +} + +/* These registers are used for returning integers (and on some + targets also for returning `struct' and `union' values when their + size and alignment match an integer type). */ +#define LOW_RETURN_REGNUM 0 /* %eax */ +#define HIGH_RETURN_REGNUM 2 /* %edx */ + +/* Extract from an array REGBUF containing the (raw) register state, a + function return value of TYPE, and copy that, in virtual format, + into VALBUF. */ + +void +i386_extract_return_value (struct type *type, char *regbuf, char *valbuf) +{ + int len = TYPE_LENGTH (type); + + if (TYPE_CODE (type) == TYPE_CODE_STRUCT + && TYPE_NFIELDS (type) == 1) + { + i386_extract_return_value (TYPE_FIELD_TYPE (type, 0), regbuf, valbuf); + return; + } + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + { + if (NUM_FREGS == 0) + { + warning ("Cannot find floating-point return value."); + memset (valbuf, 0, len); + return; + } + + /* Floating-point return values can be found in %st(0). Convert + its contents to the desired type. This is probably not + exactly how it would happen on the target itself, but it is + the best we can do. */ + convert_typed_floating (®buf[REGISTER_BYTE (FP0_REGNUM)], + builtin_type_i387_ext, valbuf, type); + } + else + { + int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM); + int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM); + + if (len <= low_size) + memcpy (valbuf, ®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], len); + else if (len <= (low_size + high_size)) + { + memcpy (valbuf, + ®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], low_size); + memcpy (valbuf + low_size, + ®buf[REGISTER_BYTE (HIGH_RETURN_REGNUM)], len - low_size); + } + else + internal_error (__FILE__, __LINE__, + "Cannot extract return value of %d bytes long.", len); + } +} + +/* Write into the appropriate registers a function return value stored + in VALBUF of type TYPE, given in virtual format. */ void -i386_extract_return_value(type, regbuf, valbuf) - struct type *type; - char regbuf[REGISTER_BYTES]; - char *valbuf; -{ -/* On AIX, floating point values are returned in floating point registers. */ -#ifdef I386_AIX_TARGET - if (TYPE_CODE_FLT == TYPE_CODE(type)) - { - double d; - /* 387 %st(0), gcc uses this */ - floatformat_to_double (&floatformat_i387_ext, - ®buf[REGISTER_BYTE(FP0_REGNUM)], - &d); - store_floating (valbuf, TYPE_LENGTH (type), d); +i386_store_return_value (struct type *type, char *valbuf) +{ + int len = TYPE_LENGTH (type); + + if (TYPE_CODE (type) == TYPE_CODE_STRUCT + && TYPE_NFIELDS (type) == 1) + { + i386_store_return_value (TYPE_FIELD_TYPE (type, 0), valbuf); + return; + } + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + { + unsigned int fstat; + char buf[FPU_REG_RAW_SIZE]; + + if (NUM_FREGS == 0) + { + warning ("Cannot set floating-point return value."); + return; + } + + /* Returning floating-point values is a bit tricky. Apart from + storing the return value in %st(0), we have to simulate the + state of the FPU at function return point. */ + + /* Convert the value found in VALBUF to the extended + floating-point format used by the FPU. This is probably + not exactly how it would happen on the target itself, but + it is the best we can do. */ + convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext); + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf, + FPU_REG_RAW_SIZE); + + /* Set the top of the floating-point register stack to 7. The + actual value doesn't really matter, but 7 is what a normal + function return would end up with if the program started out + with a freshly initialized FPU. */ + fstat = read_register (FSTAT_REGNUM); + fstat |= (7 << 11); + write_register (FSTAT_REGNUM, fstat); + + /* Mark %st(1) through %st(7) as empty. Since we set the top of + the floating-point register stack to 7, the appropriate value + for the tag word is 0x3fff. */ + write_register (FTAG_REGNUM, 0x3fff); } else -#endif /* I386_AIX_TARGET */ - { - memcpy (valbuf, regbuf, TYPE_LENGTH (type)); + { + int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM); + int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM); + + if (len <= low_size) + write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM), valbuf, len); + else if (len <= (low_size + high_size)) + { + write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM), + valbuf, low_size); + write_register_bytes (REGISTER_BYTE (HIGH_RETURN_REGNUM), + valbuf + low_size, len - low_size); + } + else + internal_error (__FILE__, __LINE__, + "Cannot store return value of %d bytes long.", len); + } +} + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR. */ + +CORE_ADDR +i386_extract_struct_value_address (char *regbuf) +{ + return extract_address (®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], + REGISTER_RAW_SIZE (LOW_RETURN_REGNUM)); +} + + +/* Return the GDB type object for the "standard" data type of data in + register REGNUM. Perhaps %esi and %edi should go here, but + potentially they could be used for things other than address. */ + +struct type * +i386_register_virtual_type (int regnum) +{ + if (regnum == PC_REGNUM || regnum == FP_REGNUM || regnum == SP_REGNUM) + return lookup_pointer_type (builtin_type_void); + + if (IS_FP_REGNUM (regnum)) + return builtin_type_i387_ext; + + if (IS_SSE_REGNUM (regnum)) + return builtin_type_v4sf; + + return builtin_type_int; +} + +/* Return true iff register REGNUM's virtual format is different from + its raw format. Note that this definition assumes that the host + supports IEEE 32-bit floats, since it doesn't say that SSE + registers need conversion. Even if we can't find a counterexample, + this is still sloppy. */ + +int +i386_register_convertible (int regnum) +{ + return IS_FP_REGNUM (regnum); +} + +/* Convert data from raw format for register REGNUM in buffer FROM to + virtual format with type TYPE in buffer TO. */ + +void +i386_register_convert_to_virtual (int regnum, struct type *type, + char *from, char *to) +{ + gdb_assert (IS_FP_REGNUM (regnum)); + + /* We only support floating-point values. */ + if (TYPE_CODE (type) != TYPE_CODE_FLT) + { + warning ("Cannot convert floating-point register value " + "to non-floating-point type."); + memset (to, 0, TYPE_LENGTH (type)); + return; } + + /* Convert to TYPE. This should be a no-op if TYPE is equivalent to + the extended floating-point format used by the FPU. */ + convert_typed_floating (from, builtin_type_i387_ext, to, type); } +/* Convert data from virtual format with type TYPE in buffer FROM to + raw format for register REGNUM in buffer TO. */ + +void +i386_register_convert_to_raw (struct type *type, int regnum, + char *from, char *to) +{ + gdb_assert (IS_FP_REGNUM (regnum)); + + /* We only support floating-point values. */ + if (TYPE_CODE (type) != TYPE_CODE_FLT) + { + warning ("Cannot convert non-floating-point type " + "to floating-point register value."); + memset (to, 0, TYPE_LENGTH (type)); + return; + } + + /* Convert from TYPE. This should be a no-op if TYPE is equivalent + to the extended floating-point format used by the FPU. */ + convert_typed_floating (from, type, to, builtin_type_i387_ext); +} + + #ifdef I386V4_SIGTRAMP_SAVED_PC -/* Get saved user PC for sigtramp from the pushed ucontext on the stack - for all three variants of SVR4 sigtramps. */ +/* Get saved user PC for sigtramp from the pushed ucontext on the + stack for all three variants of SVR4 sigtramps. */ CORE_ADDR -i386v4_sigtramp_saved_pc (frame) - struct frame_info *frame; +i386v4_sigtramp_saved_pc (struct frame_info *frame) { CORE_ADDR saved_pc_offset = 4; char *name = NULL; @@ -710,25 +1151,25 @@ i386v4_sigtramp_saved_pc (frame) return read_memory_integer (read_register (SP_REGNUM) + saved_pc_offset, 4); } #endif /* I386V4_SIGTRAMP_SAVED_PC */ + #ifdef STATIC_TRANSFORM_NAME -/* SunPRO encodes the static variables. This is not related to C++ mangling, - it is done for C too. */ +/* SunPRO encodes the static variables. This is not related to C++ + mangling, it is done for C too. */ char * -sunpro_static_transform_name (name) - char *name; +sunpro_static_transform_name (char *name) { char *p; if (IS_STATIC_TRANSFORM_NAME (name)) { - /* For file-local statics there will be a period, a bunch - of junk (the contents of which match a string given in the - N_OPT), a period and the name. For function-local statics - there will be a bunch of junk (which seems to change the - second character from 'A' to 'B'), a period, the name of the - function, and the name. So just skip everything before the - last period. */ + /* For file-local statics there will be a period, a bunch of + junk (the contents of which match a string given in the + N_OPT), a period and the name. For function-local statics + there will be a bunch of junk (which seems to change the + second character from 'A' to 'B'), a period, the name of the + function, and the name. So just skip everything before the + last period. */ p = strrchr (name, '.'); if (p != NULL) name = p + 1; @@ -736,64 +1177,208 @@ sunpro_static_transform_name (name) return name; } #endif /* STATIC_TRANSFORM_NAME */ + - - -/* Stuff for WIN32 PE style DLL's but is pretty generic really. */ +/* Stuff for WIN32 PE style DLL's but is pretty generic really. */ CORE_ADDR -skip_trampoline_code (pc, name) - CORE_ADDR pc; - char *name; +skip_trampoline_code (CORE_ADDR pc, char *name) { if (pc && read_memory_unsigned_integer (pc, 2) == 0x25ff) /* jmp *(dest) */ { - unsigned long indirect = read_memory_unsigned_integer (pc+2, 4); + unsigned long indirect = read_memory_unsigned_integer (pc + 2, 4); struct minimal_symbol *indsym = indirect ? lookup_minimal_symbol_by_pc (indirect) : 0; - char *symname = indsym ? SYMBOL_NAME(indsym) : 0; + char *symname = indsym ? SYMBOL_NAME (indsym) : 0; - if (symname) + if (symname) { - if (strncmp (symname,"__imp_", 6) == 0 - || strncmp (symname,"_imp_", 5) == 0) + if (strncmp (symname, "__imp_", 6) == 0 + || strncmp (symname, "_imp_", 5) == 0) return name ? 1 : read_memory_unsigned_integer (indirect, 4); } } - return 0; /* not a trampoline */ + return 0; /* Not a trampoline. */ } + + +/* We have two flavours of disassembly. The machinery on this page + deals with switching between those. */ static int -gdb_print_insn_i386 (memaddr, info) - bfd_vma memaddr; - disassemble_info * info; +gdb_print_insn_i386 (bfd_vma memaddr, disassemble_info *info) { - /* XXX remove when binutils 2.9.2 is imported */ -#if 0 if (disassembly_flavor == att_flavor) return print_insn_i386_att (memaddr, info); else if (disassembly_flavor == intel_flavor) return print_insn_i386_intel (memaddr, info); -#else - return print_insn_i386 (memaddr, info); -#endif + /* Never reached -- disassembly_flavour is always either att_flavor + or intel_flavor. */ + internal_error (__FILE__, __LINE__, "failed internal consistency check"); +} + + +static void +process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj) +{ + int *os_ident_ptr = obj; + const char *name; + unsigned int sect_size; + + name = bfd_get_section_name (abfd, sect); + sect_size = bfd_section_size (abfd, sect); + if (strcmp (name, ".note.ABI-tag") == 0 && sect_size > 0) + { + unsigned int name_length, data_length, note_type; + char *note = alloca (sect_size); + + bfd_get_section_contents (abfd, sect, note, + (file_ptr) 0, (bfd_size_type) sect_size); + + name_length = bfd_h_get_32 (abfd, note); + data_length = bfd_h_get_32 (abfd, note + 4); + note_type = bfd_h_get_32 (abfd, note + 8); + + if (name_length == 4 && data_length == 16 && note_type == 1 + && strcmp (note + 12, "GNU") == 0) + { + int os_number = bfd_h_get_32 (abfd, note + 16); + + /* The case numbers are from abi-tags in glibc. */ + switch (os_number) + { + case 0: + *os_ident_ptr = ELFOSABI_LINUX; + break; + case 1: + *os_ident_ptr = ELFOSABI_HURD; + break; + case 2: + *os_ident_ptr = ELFOSABI_SOLARIS; + break; + default: + internal_error (__FILE__, __LINE__, + "process_note_abi_sections: " + "unknown OS number %d", os_number); + break; + } + } + } +} + +struct gdbarch * +i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch_tdep *tdep; + struct gdbarch *gdbarch; + int os_ident; + + if (info.abfd != NULL + && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) + { + os_ident = elf_elfheader (info.abfd)->e_ident[EI_OSABI]; + + /* If os_ident is 0, it is not necessarily the case that we're + on a SYSV system. (ELFOSABI_NONE is defined to be 0.) + GNU/Linux uses a note section to record OS/ABI info, but + leaves e_ident[EI_OSABI] zero. So we have to check for note + sections too. */ + if (os_ident == ELFOSABI_NONE) + bfd_map_over_sections (info.abfd, + process_note_abi_tag_sections, + &os_ident); + + /* If that didn't help us, revert to some non-standard checks. */ + if (os_ident == ELFOSABI_NONE) + { + /* FreeBSD folks are naughty; they stored the string + "FreeBSD" in the padding of the e_ident field of the ELF + header. */ + if (strcmp (&elf_elfheader (info.abfd)->e_ident[8], "FreeBSD") == 0) + os_ident = ELFOSABI_FREEBSD; + } + } + else + os_ident = -1; + + for (arches = gdbarch_list_lookup_by_info (arches, &info); + arches != NULL; + arches = gdbarch_list_lookup_by_info (arches->next, &info)) + { + tdep = gdbarch_tdep (arches->gdbarch); + if (tdep && tdep->os_ident == os_ident) + return arches->gdbarch; + } + + /* Allocate space for the new architecture. */ + tdep = XMALLOC (struct gdbarch_tdep); + gdbarch = gdbarch_alloc (&info, tdep); + + tdep->os_ident = os_ident; + + /* FIXME: kettenis/2001-11-24: Although not all IA-32 processors + have the SSE registers, it's easier to set the default to 8. */ + tdep->num_xmm_regs = 8; + + set_gdbarch_use_generic_dummy_frames (gdbarch, 0); + + /* Call dummy code. */ + set_gdbarch_call_dummy_location (gdbarch, ON_STACK); + set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 5); + set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); + set_gdbarch_call_dummy_p (gdbarch, 1); + set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); + + set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register); + set_gdbarch_push_arguments (gdbarch, i386_push_arguments); + + set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack); + + /* NOTE: tm-i386nw.h and tm-i386v4.h override this. */ + set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid); + + /* NOTE: tm-i386aix.h, tm-i386bsd.h, tm-i386os9k.h, tm-linux.h, + tm-ptx.h, tm-symmetry.h currently override this. Sigh. */ + set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SSE_REGS); + + return gdbarch; } +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_i386_tdep (void); + void -_initialize_i386_tdep () +_initialize_i386_tdep (void) { + register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init); + + /* Initialize the table saying where each register starts in the + register file. */ + { + int i, offset; + + offset = 0; + for (i = 0; i < MAX_NUM_REGS; i++) + { + i386_register_offset[i] = offset; + offset += i386_register_size[i]; + } + } + tm_print_insn = gdb_print_insn_i386; tm_print_insn_info.mach = bfd_lookup_arch (bfd_arch_i386, 0)->mach; - /* Add the variable that controls the disassembly flavor */ - add_show_from_set( - add_set_enum_cmd ("disassembly-flavor", no_class, - valid_flavors, - (char *) &disassembly_flavor, - "Set the disassembly flavor, the valid values are \"att\" and \"intel\", \ -and the default value is \"att\".", - &setlist), - &showlist); + /* Add the variable that controls the disassembly flavor. */ + { + struct cmd_list_element *new_cmd; - + new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class, + valid_flavors, + &disassembly_flavor, + "\ +Set the disassembly flavor, the valid values are \"att\" and \"intel\", \ +and the default value is \"att\".", + &setlist); + add_show_from_set (new_cmd, &showlist); + } } diff --git a/contrib/gdb/gdb/i386b-nat.c b/contrib/gdb/gdb/i386b-nat.c index 8749e81..be8fd45 100644 --- a/contrib/gdb/gdb/i386b-nat.c +++ b/contrib/gdb/gdb/i386b-nat.c @@ -1,21 +1,23 @@ /* Native-dependent code for BSD Unix running on i386's, for GDB. - Copyright 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc. + Copyright 1988, 1989, 1991, 1992, 1994, 1995, 1996, 1998, 1999, 2000, + 2001 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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" @@ -25,45 +27,45 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <machine/reg.h> #include <machine/frame.h> #include "inferior.h" +#include "gdbcore.h" /* for registers_fetched() */ +#include "regcache.h" void -fetch_inferior_registers(regno) - int regno; +fetch_inferior_registers (int regno) { struct reg inferior_registers; - ptrace (PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &inferior_registers, 0); - memcpy (®isters[REGISTER_BYTE (0)], &inferior_registers, 4*NUM_REGS); + ptrace (PT_GETREGS, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) & inferior_registers, 0); + memcpy (®isters[REGISTER_BYTE (0)], &inferior_registers, 4 * NUM_REGS); registers_fetched (); } void -store_inferior_registers(regno) - int regno; +store_inferior_registers (int regno) { struct reg inferior_registers; - memcpy (&inferior_registers, ®isters[REGISTER_BYTE (0)], 4*NUM_REGS); - ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &inferior_registers, 0); + memcpy (&inferior_registers, ®isters[REGISTER_BYTE (0)], 4 * NUM_REGS); + ptrace (PT_SETREGS, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) & inferior_registers, 0); } -struct md_core { +struct md_core +{ struct reg intreg; struct fpreg freg; }; void -fetch_core_registers (core_reg_sect, core_reg_size, which, ignore) - char *core_reg_sect; - unsigned core_reg_size; - int which; - CORE_ADDR ignore; +fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, + CORE_ADDR ignore) { - struct md_core *core_reg = (struct md_core *)core_reg_sect; + struct md_core *core_reg = (struct md_core *) core_reg_sect; /* integer registers */ - memcpy(®isters[REGISTER_BYTE (0)], &core_reg->intreg, - sizeof(struct reg)); + memcpy (®isters[REGISTER_BYTE (0)], &core_reg->intreg, + sizeof (struct reg)); /* floating point registers */ /* XXX */ } @@ -72,36 +74,17 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, ignore) #include <machine/reg.h> -/* Some systems don't provide all the registers on a trap. Use SS as a - default if so. */ - -#ifndef tDS -#define tDS tSS -#endif -#ifndef tES -#define tES tSS -#endif -#ifndef tFS -#define tFS tSS -#endif -#ifndef tGS -#define tGS tSS -#endif - -/* These tables map between the registers on a trap frame, and the register - order used by the rest of GDB. */ /* this table must line up with REGISTER_NAMES in tm-i386.h */ /* symbols like 'tEAX' come from <machine/reg.h> */ -static int tregmap[] = +static int tregmap[] = { tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI, - tEIP, tEFLAGS, tCS, tSS, - tDS, tES, tFS, tGS + tEIP, tEFLAGS, tCS, tSS }; #ifdef sEAX -static int sregmap[] = +static int sregmap[] = { sEAX, sECX, sEDX, sEBX, sESP, sEBP, sESI, sEDI, @@ -112,12 +95,11 @@ static int sregmap[] = /* FreeBSD has decided to collapse the s* and t* symbols. So if the s* ones aren't around, use the t* ones for sregmap too. */ -static int sregmap[] = +static int sregmap[] = { tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI, - tEIP, tEFLAGS, tCS, tSS, - tDS, tES, tFS, tGS + tEIP, tEFLAGS, tCS, tSS }; #endif /* No sEAX */ @@ -125,9 +107,7 @@ static int sregmap[] = place where ES is stored. */ int -i386_register_u_addr (blockend, regnum) - int blockend; - int regnum; +i386_register_u_addr (int blockend, int regnum) { /* The following condition is a kludge to get at the proper register map depending upon the state of pcb_flag. @@ -146,10 +126,11 @@ i386_register_u_addr (blockend, regnum) #ifdef FLOAT_INFO #include "expression.h" -#include "language.h" /* for local_hex_string */ +#include "language.h" /* for local_hex_string */ #include "floatformat.h" #include <sys/param.h> +#include <sys/dir.h> #include <signal.h> #include <sys/ioctl.h> #include <fcntl.h> @@ -159,134 +140,103 @@ i386_register_u_addr (blockend, regnum) #include <sys/time.h> #include <sys/resource.h> #include <sys/uio.h> -#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ +#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ #include <sys/user.h> #undef curpcb #include <sys/file.h> #include "gdb_stat.h" #include <sys/ptrace.h> -extern void print_387_control_word (); /* i387-tdep.h */ +extern void print_387_control_word (); /* i387-tdep.h */ extern void print_387_status_word (); #define fpstate save87 #define U_FPSTATE(u) u.u_pcb.pcb_savefpu -static void -i387_to_double (from, to) - char *from; - char *to; -{ - long *lp; - /* push extended mode on 387 stack, then pop in double mode - * - * first, set exception masks so no error is generated - - * number will be rounded to inf or 0, if necessary - */ - asm ("pushl %eax"); /* grab a stack slot */ - asm ("fstcw (%esp)"); /* get 387 control word */ - asm ("movl (%esp),%eax"); /* save old value */ - asm ("orl $0x3f,%eax"); /* mask all exceptions */ - asm ("pushl %eax"); - asm ("fldcw (%esp)"); /* load new value into 387 */ - - asm ("movl 8(%ebp),%eax"); - asm ("fldt (%eax)"); /* push extended number on 387 stack */ - asm ("fwait"); - asm ("movl 12(%ebp),%eax"); - asm ("fstpl (%eax)"); /* pop double */ - asm ("fwait"); - - asm ("popl %eax"); /* flush modified control word */ - asm ("fnclex"); /* clear exceptions */ - asm ("fldcw (%esp)"); /* restore original control word */ - asm ("popl %eax"); /* flush saved copy */ -} - -struct env387 -{ - unsigned short control; - unsigned short r0; - unsigned short status; - unsigned short r1; - unsigned short tag; - unsigned short r2; - unsigned long eip; - unsigned short code_seg; - unsigned short opcode; - unsigned long operand; - unsigned short operand_seg; - unsigned short r3; - unsigned char regs[8][10]; -}; +struct env387 + { + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; + }; static void -print_387_status (status, ep) - unsigned short status; - struct env387 *ep; +print_387_status (unsigned short status, struct env387 *ep) { int i; int bothstatus; int top; int fpreg; - + bothstatus = ((status != 0) && (ep->status != 0)); - if (status != 0) + if (status != 0) { if (bothstatus) printf_unfiltered ("u: "); - print_387_status_word ((unsigned int)status); + print_387_status_word ((unsigned int) status); } - - if (ep->status != 0) + + if (ep->status != 0) { if (bothstatus) printf_unfiltered ("e: "); - print_387_status_word ((unsigned int)ep->status); + print_387_status_word ((unsigned int) ep->status); } - - print_387_control_word ((unsigned int)ep->control); - printf_unfiltered ("last instruction: "); - 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)); + + print_387_control_word ((unsigned int) 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--) + + printf_unfiltered ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) { - int st_regno; double val; - - /* The physical regno `fpreg' is only relevant as an index into the - * tag word. Logical `%st' numbers are required for indexing ep->regs. - */ - st_regno = (fpreg + 8 - top) & 7; - printf_unfiltered ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " "); + printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); - switch ((ep->tag >> (fpreg * 2)) & 3) + 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; + 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[st_regno][i]); - - i387_to_double((char *) ep->regs[st_regno], (char *) &val); + printf_unfiltered ("%02x", ep->regs[fpreg][i]); + + floatformat_to_double (&floatformat_i387_ext, (char *) ep->regs[fpreg], + &val); printf_unfiltered (" %g\n", val); } } -void -i386_float_info () +i386_float_info (void) { - struct user u; /* just for address computations */ + struct user u; /* just for address computations */ int i; /* fpstate defined in <sys/user.h> */ struct fpstate *fpstatep; @@ -295,65 +245,47 @@ i386_float_info () char fpvalid; unsigned int rounded_addr; unsigned int rounded_size; - /*extern int corechan;*/ + /*extern int corechan; */ int skip; - extern int inferior_pid; - - uaddr = (char *)&U_FPSTATE(u) - (char *)&u; - if (inferior_pid) + + uaddr = (char *) &U_FPSTATE (u) - (char *) &u; + if (! ptid_equal (inferior_ptid, null_ptid)) { int *ip; - + rounded_addr = uaddr & -sizeof (int); rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + sizeof (int) - 1) / sizeof (int); skip = uaddr - rounded_addr; - - ip = (int *)buf; - for (i = 0; i < rounded_size; i++) + + ip = (int *) buf; + for (i = 0; i < rounded_size; i++) { - *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0); + *ip++ = ptrace (PT_READ_U, PIDGET (inferior_ptid), + (caddr_t) rounded_addr, 0); rounded_addr += sizeof (int); } - } - else + } + else { - printf("float info: can't do a core file (yet)\n"); + printf ("float info: can't do a core file (yet)\n"); return; #if 0 if (lseek (corechan, uaddr, 0) < 0) perror_with_name ("seek on core file"); - if (myread (corechan, buf, sizeof (struct fpstate)) < 0) - perror_with_name ("read from core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); skip = 0; #endif } -#ifdef __FreeBSD__ - fpstatep = (struct fpstate *)(buf + skip); - print_387_status (fpstatep->sv_ex_sw, (struct env387 *)fpstatep); -#else - print_387_status (0, (struct env387 *)buf); -#endif + print_387_status (0, (struct env387 *) buf); } -#endif /* FLOAT_INFO */ int -kernel_u_size () +kernel_u_size (void) { return (sizeof (struct user)); } -#ifdef SETUP_ARBITRARY_FRAME -#include "frame.h" -struct frame_info * -setup_arbitrary_frame (argc, argv) - int argc; - CORE_ADDR *argv; -{ - if (argc != 2) - error ("i386 frame specifications require two arguments: sp and pc"); - - return create_new_frame (argv[0], argv[1]); -} -#endif /* SETUP_ARBITRARY_FRAME */ +#endif diff --git a/contrib/gdb/gdb/infptrace.c b/contrib/gdb/gdb/infptrace.c index b2eabbb..777a5b4 100644 --- a/contrib/gdb/gdb/infptrace.c +++ b/contrib/gdb/gdb/infptrace.c @@ -1,29 +1,34 @@ /* Low level Unix child interface to ptrace, for GDB when running under Unix. - Copyright 1988, 89, 90, 91, 92, 93, 94, 95, 96, 1998 + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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 "frame.h" #include "inferior.h" #include "target.h" #include "gdb_string.h" -#include "wait.h" +#include "regcache.h" + +#include "gdb_wait.h" + #include "command.h" #ifdef USG @@ -31,15 +36,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #endif #include <sys/param.h> +#include "gdb_dirent.h" #include <signal.h> #include <sys/ioctl.h> #ifdef HAVE_PTRACE_H -# include <ptrace.h> +#include <ptrace.h> #else -# ifdef HAVE_SYS_PTRACE_H -# include <sys/ptrace.h> -# endif +#ifdef HAVE_SYS_PTRACE_H +#include <sys/ptrace.h> +#endif #endif #if !defined (PT_READ_I) @@ -96,26 +102,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #endif /* !FETCH_INFERIOR_REGISTERS */ #if !defined (CHILD_XFER_MEMORY) -static void udot_info PARAMS ((char *, int)); +static void udot_info (char *, int); #endif #if !defined (FETCH_INFERIOR_REGISTERS) -static void fetch_register PARAMS ((int)); -static void store_register PARAMS ((int)); +static void fetch_register (int); +static void store_register (int); #endif -void _initialize_kernel_u_addr PARAMS ((void)); -void _initialize_infptrace PARAMS ((void)); - +void _initialize_kernel_u_addr (void); +void _initialize_infptrace (void); + /* This function simply calls ptrace with the given arguments. It exists so that all calls to ptrace are isolated in this machine-dependent file. */ int -call_ptrace (request, pid, addr, data) - int request, pid; - PTRACE_ARG3_TYPE addr; - int data; +call_ptrace (int request, int pid, PTRACE_ARG3_TYPE addr, int data) { int pt_status = 0; @@ -127,25 +130,26 @@ call_ptrace (request, pid, addr, data) #endif #if defined(PT_SETTRC) /* If the parent can be told to attach to us, try to do it. */ - if (request == PT_SETTRC) { - errno = 0; - pt_status = ptrace (PT_SETTRC, pid, addr, data -#if defined (FIVE_ARG_PTRACE) - /* Deal with HPUX 8.0 braindamage. We never use the - calls which require the fifth argument. */ - , 0 + if (request == PT_SETTRC) + { + errno = 0; +#if !defined (FIVE_ARG_PTRACE) + pt_status = ptrace (PT_SETTRC, pid, addr, data); +#else + /* Deal with HPUX 8.0 braindamage. We never use the + calls which require the fifth argument. */ + pt_status = ptrace (PT_SETTRC, pid, addr, data, 0); #endif - ); - - if (errno) perror_with_name ("ptrace"); + if (errno) + perror_with_name ("ptrace"); #if 0 - printf (" = %d\n", pt_status); + printf (" = %d\n", pt_status); #endif - if (pt_status < 0) - return pt_status; - else - return parent_attach_all (pid, addr, data); - } + if (pt_status < 0) + return pt_status; + else + return parent_attach_all (pid, addr, data); + } #endif #if defined(PT_CONTIN1) @@ -166,13 +170,14 @@ call_ptrace (request, pid, addr, data) saved_errno = errno; errno = 0; #endif - pt_status = ptrace (request, pid, addr, data -#if defined (FIVE_ARG_PTRACE) - /* Deal with HPUX 8.0 braindamage. We never use the - calls which require the fifth argument. */ - , 0 +#if !defined (FIVE_ARG_PTRACE) + pt_status = ptrace (request, pid, addr, data); +#else + /* Deal with HPUX 8.0 braindamage. We never use the + calls which require the fifth argument. */ + pt_status = ptrace (request, pid, addr, data, 0); #endif - ); + #if 0 if (errno) printf (" [errno = %d]", errno); @@ -194,23 +199,22 @@ call_ptrace (request, pid, addr, data) hook before returning. */ int -ptrace_wait (pid, status) - int pid; - int *status; +ptrace_wait (ptid_t ptid, int *status) { int wstate; wstate = wait (status); - target_post_wait (wstate, *status); + target_post_wait (pid_to_ptid (wstate), *status); return wstate; } void -kill_inferior () +kill_inferior (void) { int status; + int pid = PIDGET (inferior_ptid); - if (inferior_pid == 0) + if (pid == 0) return; /* This once used to call "kill" to kill the inferior just in case @@ -221,8 +225,8 @@ kill_inferior () The kill call causes problems under hpux10, so it's been removed; if this causes problems we'll deal with them as they arise. */ - ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0); - ptrace_wait (0, &status); + ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0); + ptrace_wait (null_ptid, &status); target_mourn_inferior (); } @@ -233,18 +237,17 @@ kill_inferior () If SIGNAL is nonzero, give it that signal. */ void -child_resume (pid, step, signal) - int pid; - int step; - enum target_signal signal; +child_resume (ptid_t ptid, int step, enum target_signal signal) { + int pid = PIDGET (ptid); + errno = 0; if (pid == -1) /* Resume all threads. */ /* I think this only gets used in the non-threaded case, where "resume - all threads" and "resume inferior_pid" are the same. */ - pid = inferior_pid; + all threads" and "resume inferior_ptid" are the same. */ + pid = PIDGET (inferior_ptid); /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where it was. (If GDB wanted it to start some other way, we have already @@ -257,10 +260,10 @@ child_resume (pid, step, signal) if (step) { - if (SOFTWARE_SINGLE_STEP_P) - abort(); /* Make sure this doesn't happen. */ + if (SOFTWARE_SINGLE_STEP_P ()) + internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* Make sure this doesn't happen. */ else - ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, + ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, target_signal_to_host (signal)); } else @@ -268,16 +271,17 @@ child_resume (pid, step, signal) target_signal_to_host (signal)); if (errno) - perror_with_name ("ptrace"); + { + perror_with_name ("ptrace"); + } } #endif /* CHILD_RESUME */ - + #ifdef ATTACH_DETACH /* Start debugging the process whose number is PID. */ int -attach (pid) - int pid; +attach (int pid) { errno = 0; ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0); @@ -292,11 +296,11 @@ attach (pid) SIGNAL = 0 means just continue it. */ void -detach (signal) - int signal; +detach (int signal) { errno = 0; - ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + ptrace (PT_DETACH, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) 1, + signal); if (errno) perror_with_name ("ptrace"); attach_flag = 0; @@ -316,7 +320,7 @@ CORE_ADDR kernel_u_addr; #endif /* KERNEL_U_ADDR_BSD. */ void -_initialize_kernel_u_addr () +_initialize_kernel_u_addr (void) { #if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS) struct nlist names[2]; @@ -326,7 +330,8 @@ _initialize_kernel_u_addr () if (nlist ("/vmunix", names) == 0) kernel_u_addr = names[0].n_value; else - fatal ("Unable to get kernel u area address."); + internal_error (__FILE__, __LINE__, + "Unable to get kernel u area address."); #endif /* KERNEL_U_ADDR_BSD. */ } @@ -339,28 +344,23 @@ _initialize_kernel_u_addr () /* U_REGS_OFFSET is the offset of the registers within the u area. */ #if !defined (U_REGS_OFFSET) #define U_REGS_OFFSET \ - ptrace (PT_READ_U, inferior_pid, \ + ptrace (PT_READ_U, PIDGET (inferior_ptid), \ (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ - KERNEL_U_ADDR #endif -/* Registers we shouldn't try to fetch. */ -#if !defined (CANNOT_FETCH_REGISTER) -#define CANNOT_FETCH_REGISTER(regno) 0 -#endif - /* Fetch one register. */ static void -fetch_register (regno) - int regno; +fetch_register (int regno) { /* This isn't really an address. But ptrace thinks of it as one. */ CORE_ADDR regaddr; - char mess[128]; /* For messages */ + char mess[128]; /* For messages */ register int i; - unsigned int offset; /* Offset of registers within the u area. */ - char buf[MAX_REGISTER_RAW_SIZE]; + unsigned int offset; /* Offset of registers within the u area. */ + char *buf = alloca (MAX_REGISTER_RAW_SIZE); + int tid; if (CANNOT_FETCH_REGISTER (regno)) { @@ -369,18 +369,23 @@ fetch_register (regno) return; } + /* Overload thread id onto process id */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* no thread id, just use process id */ + offset = U_REGS_OFFSET; regaddr = register_addr (regno, offset); for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid, - (PTRACE_ARG3_TYPE) regaddr, 0); + *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid, + (PTRACE_ARG3_TYPE) regaddr, 0); regaddr += sizeof (PTRACE_XFER_TYPE); if (errno != 0) { - sprintf (mess, "reading register %s (#%d)", REGISTER_NAME (regno), regno); + sprintf (mess, "reading register %s (#%d)", + REGISTER_NAME (regno), regno); perror_with_name (mess); } } @@ -393,8 +398,7 @@ fetch_register (regno) Otherwise, REGNO specifies which register (so we can save time). */ void -fetch_inferior_registers (regno) - int regno; +fetch_inferior_registers (int regno) { if (regno >= 0) { @@ -402,47 +406,53 @@ fetch_inferior_registers (regno) } else { - for (regno = 0; regno < ARCH_NUM_REGS; regno++) + for (regno = 0; regno < NUM_REGS; regno++) { fetch_register (regno); } } } -/* Registers we shouldn't try to store. */ -#if !defined (CANNOT_STORE_REGISTER) -#define CANNOT_STORE_REGISTER(regno) 0 -#endif - /* Store one register. */ static void -store_register (regno) - int regno; +store_register (int regno) { /* This isn't really an address. But ptrace thinks of it as one. */ CORE_ADDR regaddr; - char mess[128]; /* For messages */ + char mess[128]; /* For messages */ register int i; - unsigned int offset; /* Offset of registers within the u area. */ + unsigned int offset; /* Offset of registers within the u area. */ + int tid; + char *buf = alloca (MAX_REGISTER_RAW_SIZE); if (CANNOT_STORE_REGISTER (regno)) { return; } + /* Overload thread id onto process id */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* no thread id, just use process id */ + offset = U_REGS_OFFSET; regaddr = register_addr (regno, offset); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) + + /* Put the contents of regno into a local buffer */ + regcache_collect (regno, buf); + + /* Store the local buffer into the inferior a chunk at the time. */ + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, - *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); + ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) (buf + i)); regaddr += sizeof (PTRACE_XFER_TYPE); if (errno != 0) { - sprintf (mess, "writing register %s (#%d)", REGISTER_NAME (regno), regno); + sprintf (mess, "writing register %s (#%d)", + REGISTER_NAME (regno), regno); perror_with_name (mess); } } @@ -453,8 +463,7 @@ store_register (regno) Otherwise, REGNO specifies which register (so we can save time). */ void -store_inferior_registers (regno) - int regno; +store_inferior_registers (int regno) { if (regno >= 0) { @@ -462,7 +471,7 @@ store_inferior_registers (regno) } else { - for (regno = 0; regno < ARCH_NUM_REGS; regno++) + for (regno = 0; regno < NUM_REGS; regno++) { store_register (regno); } @@ -471,95 +480,102 @@ store_inferior_registers (regno) #endif /* !defined (FETCH_INFERIOR_REGISTERS). */ +/* Set an upper limit on alloca. */ +#ifndef GDB_MAX_ALLOCA +#define GDB_MAX_ALLOCA 0x1000 +#endif + #if !defined (CHILD_XFER_MEMORY) /* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory - in the NEW_SUN_PTRACE case. - It ought to be straightforward. But it appears that writing did - not write the data that I specified. I cannot understand where - it got the data that it actually did write. */ - -/* Copy LEN bytes to or from inferior's memory starting at MEMADDR - to debugger memory starting at MYADDR. Copy to inferior if - WRITE is nonzero. - - Returns the length copied, which is either the LEN argument or zero. - This xfer function does not do partial moves, since child_ops - doesn't allow memory operations to cross below us in the target stack - anyway. */ + in the NEW_SUN_PTRACE case. It ought to be straightforward. But + it appears that writing did not write the data that I specified. I + cannot understand where it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR to + debugger memory starting at MYADDR. Copy to inferior if WRITE is + nonzero. TARGET is ignored. + + Returns the length copied, which is either the LEN argument or + zero. This xfer function does not do partial moves, since + child_ops doesn't allow memory operations to cross below us in the + target stack anyway. */ int -child_xfer_memory (memaddr, myaddr, len, write, target) - CORE_ADDR memaddr; - char *myaddr; - int len; - int write; - struct target_ops *target; /* ignored */ +child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, + struct mem_attrib *attrib, struct target_ops *target) { - register int i; + int i; /* Round starting address down to longword boundary. */ - register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE); + CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); /* Round ending address up; get number of longwords that makes. */ - register int count - = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) - / sizeof (PTRACE_XFER_TYPE); + int count = ((((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE)); + int alloc = count * sizeof (PTRACE_XFER_TYPE); + PTRACE_XFER_TYPE *buffer; + struct cleanup *old_chain = NULL; + /* Allocate buffer of that many longwords. */ - register PTRACE_XFER_TYPE *buffer - = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + if (len < GDB_MAX_ALLOCA) + { + buffer = (PTRACE_XFER_TYPE *) alloca (alloc); + } + else + { + buffer = (PTRACE_XFER_TYPE *) xmalloc (alloc); + old_chain = make_cleanup (xfree, buffer); + } if (write) { - /* Fill start and end extra bytes of buffer with existing memory data. */ - - if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) { - /* Need part of initial word -- fetch it. */ - buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, - 0); - } - - if (count > 1) /* FIXME, avoid if even boundary */ + /* Fill start and end extra bytes of buffer with existing memory + data. */ + if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) { - buffer[count - 1] - = ptrace (PT_READ_I, inferior_pid, - ((PTRACE_ARG3_TYPE) - (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))), - 0); + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_READ_I, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) addr, 0); } - /* Copy data to be written over corresponding part of buffer */ + if (count > 1) /* FIXME, avoid if even boundary. */ + { + buffer[count - 1] = + ptrace (PT_READ_I, PIDGET (inferior_ptid), + ((PTRACE_ARG3_TYPE) + (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))), 0); + } + /* Copy data to be written over corresponding part of buffer. */ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), - myaddr, - len); + myaddr, len); /* Write the entire buffer. */ - for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, - buffer[i]); + ptrace (PT_WRITE_D, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) addr, buffer[i]); if (errno) - { + { /* Using the appropriate one (I or D) is necessary for - Gould NP1, at least. */ + Gould NP1, at least. */ errno = 0; - ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, - buffer[i]); + ptrace (PT_WRITE_I, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) addr, buffer[i]); } if (errno) return 0; } #ifdef CLEAR_INSN_CACHE - CLEAR_INSN_CACHE(); + CLEAR_INSN_CACHE (); #endif } else { - /* Read all the longwords */ + /* Read all the longwords. */ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - buffer[i] = ptrace (PT_READ_I, inferior_pid, + buffer[i] = ptrace (PT_READ_I, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) addr, 0); if (errno) return 0; @@ -571,25 +587,26 @@ child_xfer_memory (memaddr, myaddr, len, write, target) (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len); } + + if (old_chain != NULL) + do_cleanups (old_chain); return len; } - + static void -udot_info (dummy1, dummy2) - char *dummy1; - int dummy2; +udot_info (char *dummy1, int dummy2) { #if defined (KERNEL_U_SIZE) - int udot_off; /* Offset into user struct */ - int udot_val; /* Value from user struct at udot_off */ - char mess[128]; /* For messages */ + int udot_off; /* Offset into user struct */ + int udot_val; /* Value from user struct at udot_off */ + char mess[128]; /* For messages */ #endif - if (!target_has_execution) - { - error ("The program is not being run."); - } + if (!target_has_execution) + { + error ("The program is not being run."); + } #if !defined (KERNEL_U_SIZE) @@ -611,7 +628,7 @@ udot_info (dummy1, dummy2) } printf_filtered ("%04x:", udot_off); } - udot_val = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) udot_off, 0); + udot_val = ptrace (PT_READ_U, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) udot_off, 0); if (errno != 0) { sprintf (mess, "\nreading user struct at offset 0x%x", udot_off); @@ -625,10 +642,10 @@ udot_info (dummy1, dummy2) #endif } #endif /* !defined (CHILD_XFER_MEMORY). */ - + void -_initialize_infptrace () +_initialize_infptrace (void) { #if !defined (CHILD_XFER_MEMORY) add_info ("udot", udot_info, diff --git a/contrib/gdb/gdb/main.c b/contrib/gdb/gdb/main.c index 1733e10..7ef8647 100644 --- a/contrib/gdb/gdb/main.c +++ b/contrib/gdb/gdb/main.c @@ -1,30 +1,31 @@ /* Top level stuff for GDB, the GNU debugger. - Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995 + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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 <setjmp.h> -#include <unistd.h> #include "top.h" #include "target.h" #include "inferior.h" -#include "call-cmds.h" +#include "symfile.h" +#include "gdbcore.h" #include "getopt.h" @@ -33,19 +34,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <ctype.h> #include "gdb_string.h" - -/* Temporary variable for SET_TOP_LEVEL. */ - -static int top_level_val; - -/* Do a setjmp on error_return and quit_return. catch_errors is - generally a cleaner way to do this, but main() would look pretty - ugly if it had to use catch_errors each time. */ - -#define SET_TOP_LEVEL() \ - (((top_level_val = SIGSETJMP (error_return)) \ - ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (SIGJMP_BUF))) \ - , top_level_val) +#include "event-loop.h" +#include "ui-out.h" /* If nonzero, display time usage both at startup and for each command. */ @@ -55,6 +45,15 @@ int display_time; int display_space; +/* Whether this is the async version or not. The async version is + invoked on the command line with the -nw --async options. In this + version, the usual command_loop is substituted by and event loop which + processes UI events asynchronously. */ +int event_loop_p = 1; + +/* Has an interpreter been specified and if so, which. */ +char *interpreter_p; + /* Whether this is the command line version or not */ int tui_version = 0; @@ -64,34 +63,67 @@ int xdb_commands = 0; /* Whether dbx commands will be handled */ int dbx_commands = 0; -GDB_FILE *gdb_stdout; -GDB_FILE *gdb_stderr; +struct ui_file *gdb_stdout; +struct ui_file *gdb_stderr; +struct ui_file *gdb_stdlog; +struct ui_file *gdb_stdtarg; + +/* Used to initialize error() - defined in utils.c */ + +extern void error_init (void); /* Whether to enable writing into executable and core files */ extern int write_files; -static void print_gdb_help PARAMS ((GDB_FILE *)); -extern void gdb_init PARAMS ((char *)); +static void print_gdb_help (struct ui_file *); /* These two are used to set the external editor commands when gdb is farming out files to be edited by another program. */ -extern int enable_external_editor; -extern char * external_editor_command; +extern char *external_editor_command; -#ifdef __CYGWIN__ -#include <windows.h> /* for MAX_PATH */ -#include <sys/cygwin.h> /* for cygwin32_conv_to_posix_path */ -#endif +/* Call command_loop. If it happens to return, pass that through as a + non-zero return status. */ -int -main (argc, argv) - int argc; - char **argv; +static int +captured_command_loop (void *data) { + if (command_loop_hook == NULL) + command_loop (); + else + command_loop_hook (); + /* FIXME: cagney/1999-11-05: A correct command_loop() implementaton + would clean things up (restoring the cleanup chain) to the state + they were just prior to the call. Technically, this means that + the do_cleanups() below is redundant. Unfortunately, many FUNCs + are not that well behaved. do_cleanups should either be replaced + with a do_cleanups call (to cover the problem) or an assertion + check to detect bad FUNCs code. */ + do_cleanups (ALL_CLEANUPS); + /* If the command_loop returned, normally (rather than threw an + error) we try to quit. If the quit is aborted, catch_errors() + which called this catch the signal and restart the command + loop. */ + quit_command (NULL, instream == stdin); + return 1; +} + +struct captured_main_args + { + int argc; + char **argv; + }; + +static int +captured_main (void *data) +{ + struct captured_main_args *context = data; + int argc = context->argc; + char **argv = context->argv; int count; static int quiet = 0; static int batch = 0; + static int set_args = 0; /* Pointers to various arguments from command line. */ char *symarg = NULL; @@ -117,7 +149,7 @@ main (argc, argv) int dirsize; /* Number of elements used. */ int ndir; - + struct stat homebuf, cwdbuf; char *homedir, *homeinit; @@ -125,8 +157,6 @@ main (argc, argv) long time_at_startup = get_run_time (); - int gdb_file_size; - START_PROGRESS (argv[0], 0); #ifdef MPW @@ -143,11 +173,6 @@ main (argc, argv) alloca (4 - i); #endif - /* If error() is called from initialization code, just exit */ - if (SET_TOP_LEVEL ()) { - exit(1); - } - cmdsize = 1; cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg)); ncmd = 0; @@ -163,19 +188,13 @@ main (argc, argv) getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); current_directory = gdb_dirbuf; - gdb_file_size = sizeof(GDB_FILE); - - gdb_stdout = (GDB_FILE *)xmalloc (gdb_file_size); - gdb_stdout->ts_streamtype = afile; - gdb_stdout->ts_filestream = stdout; - gdb_stdout->ts_strbuf = NULL; - gdb_stdout->ts_buflen = 0; + gdb_stdout = stdio_fileopen (stdout); + gdb_stderr = stdio_fileopen (stderr); + gdb_stdlog = gdb_stderr; /* for moment */ + gdb_stdtarg = gdb_stderr; /* for moment */ - gdb_stderr = (GDB_FILE *)xmalloc (gdb_file_size); - gdb_stderr->ts_streamtype = afile; - gdb_stderr->ts_filestream = stderr; - gdb_stderr->ts_strbuf = NULL; - gdb_stderr->ts_buflen = 0; + /* initialize error() */ + error_init (); /* Parse arguments and options. */ { @@ -184,59 +203,73 @@ main (argc, argv) short option (or arbitrary numbers starting at 10 for those with no equivalent). */ static struct option long_options[] = - { + { + {"async", no_argument, &event_loop_p, 1}, + {"noasync", no_argument, &event_loop_p, 0}, #if defined(TUI) - {"tui", no_argument, &tui_version, 1}, + {"tui", no_argument, &tui_version, 1}, #endif - {"xdb", no_argument, &xdb_commands, 1}, - {"dbx", no_argument, &dbx_commands, 1}, - {"readnow", no_argument, &readnow_symbol_files, 1}, - {"r", no_argument, &readnow_symbol_files, 1}, - {"mapped", no_argument, &mapped_symbol_files, 1}, - {"m", no_argument, &mapped_symbol_files, 1}, - {"quiet", no_argument, &quiet, 1}, - {"q", no_argument, &quiet, 1}, - {"silent", no_argument, &quiet, 1}, - {"nx", no_argument, &inhibit_gdbinit, 1}, - {"n", no_argument, &inhibit_gdbinit, 1}, - {"batch", no_argument, &batch, 1}, - {"epoch", no_argument, &epoch_interface, 1}, - - /* This is a synonym for "--annotate=1". --annotate is now preferred, - but keep this here for a long time because people will be running - emacses which use --fullname. */ - {"fullname", no_argument, 0, 'f'}, - {"f", no_argument, 0, 'f'}, - - {"annotate", required_argument, 0, 12}, - {"help", no_argument, &print_help, 1}, - {"se", required_argument, 0, 10}, - {"symbols", required_argument, 0, 's'}, - {"s", required_argument, 0, 's'}, - {"exec", required_argument, 0, 'e'}, - {"e", required_argument, 0, 'e'}, - {"core", required_argument, 0, 'c'}, - {"c", required_argument, 0, 'c'}, - {"command", required_argument, 0, 'x'}, - {"version", no_argument, &print_version, 1}, - {"x", required_argument, 0, 'x'}, - {"directory", required_argument, 0, 'd'}, - {"cd", required_argument, 0, 11}, - {"tty", required_argument, 0, 't'}, - {"baud", required_argument, 0, 'b'}, - {"b", required_argument, 0, 'b'}, - {"nw", no_argument, &use_windows, 0}, - {"nowindows", no_argument, &use_windows, 0}, - {"w", no_argument, &use_windows, 1}, - {"windows", no_argument, &use_windows, 1}, - {"statistics", no_argument, 0, 13}, - {"write", no_argument, &write_files, 1}, + {"xdb", no_argument, &xdb_commands, 1}, + {"dbx", no_argument, &dbx_commands, 1}, + {"readnow", no_argument, &readnow_symbol_files, 1}, + {"r", no_argument, &readnow_symbol_files, 1}, + {"mapped", no_argument, &mapped_symbol_files, 1}, + {"m", no_argument, &mapped_symbol_files, 1}, + {"quiet", no_argument, &quiet, 1}, + {"q", no_argument, &quiet, 1}, + {"silent", no_argument, &quiet, 1}, + {"nx", no_argument, &inhibit_gdbinit, 1}, + {"n", no_argument, &inhibit_gdbinit, 1}, + {"batch", no_argument, &batch, 1}, + {"epoch", no_argument, &epoch_interface, 1}, + + /* This is a synonym for "--annotate=1". --annotate is now preferred, + but keep this here for a long time because people will be running + emacses which use --fullname. */ + {"fullname", no_argument, 0, 'f'}, + {"f", no_argument, 0, 'f'}, + + {"annotate", required_argument, 0, 12}, + {"help", no_argument, &print_help, 1}, + {"se", required_argument, 0, 10}, + {"symbols", required_argument, 0, 's'}, + {"s", required_argument, 0, 's'}, + {"exec", required_argument, 0, 'e'}, + {"e", required_argument, 0, 'e'}, + {"core", required_argument, 0, 'c'}, + {"c", required_argument, 0, 'c'}, + {"pid", required_argument, 0, 'p'}, + {"p", required_argument, 0, 'p'}, + {"command", required_argument, 0, 'x'}, + {"version", no_argument, &print_version, 1}, + {"x", required_argument, 0, 'x'}, +#ifdef GDBTK + {"tclcommand", required_argument, 0, 'z'}, + {"enable-external-editor", no_argument, 0, 'y'}, + {"editor-command", required_argument, 0, 'w'}, +#endif + {"ui", required_argument, 0, 'i'}, + {"interpreter", required_argument, 0, 'i'}, + {"i", required_argument, 0, 'i'}, + {"directory", required_argument, 0, 'd'}, + {"d", required_argument, 0, 'd'}, + {"cd", required_argument, 0, 11}, + {"tty", required_argument, 0, 't'}, + {"baud", required_argument, 0, 'b'}, + {"b", required_argument, 0, 'b'}, + {"nw", no_argument, &use_windows, 0}, + {"nowindows", no_argument, &use_windows, 0}, + {"w", no_argument, &use_windows, 1}, + {"windows", no_argument, &use_windows, 1}, + {"statistics", no_argument, 0, 13}, + {"write", no_argument, &write_files, 1}, + {"args", no_argument, &set_args, 1}, /* Allow machine descriptions to add more options... */ #ifdef ADDITIONAL_OPTIONS - ADDITIONAL_OPTIONS + ADDITIONAL_OPTIONS #endif - {0, no_argument, 0, 0} - }; + {0, no_argument, 0, 0} + }; while (1) { @@ -244,7 +277,7 @@ main (argc, argv) c = getopt_long_only (argc, argv, "", long_options, &option_index); - if (c == EOF) + if (c == EOF || set_args) break; /* Long option that takes an argument. */ @@ -286,21 +319,49 @@ main (argc, argv) case 'c': corearg = optarg; break; + case 'p': + /* "corearg" is shared by "--core" and "--pid" */ + corearg = optarg; + break; case 'x': cmdarg[ncmd++] = optarg; if (ncmd >= cmdsize) { cmdsize *= 2; - cmdarg = (char **) xrealloc ((char *)cmdarg, + cmdarg = (char **) xrealloc ((char *) cmdarg, cmdsize * sizeof (*cmdarg)); } break; +#ifdef GDBTK + case 'z': + { +extern int gdbtk_test (char *); + if (!gdbtk_test (optarg)) + { + fprintf_unfiltered (gdb_stderr, "%s: unable to load tclcommand file \"%s\"", + argv[0], optarg); + exit (1); + } + break; + } + case 'y': + /* Backwards compatibility only. */ + break; + case 'w': + { + external_editor_command = xstrdup (optarg); + break; + } +#endif /* GDBTK */ + case 'i': + interpreter_p = optarg; + break; case 'd': dirarg[ndir++] = optarg; if (ndir >= dirsize) { dirsize *= 2; - dirarg = (char **) xrealloc ((char *)dirarg, + dirarg = (char **) xrealloc ((char *) dirarg, dirsize * sizeof (*dirarg)); } break; @@ -319,7 +380,7 @@ main (argc, argv) if (i == 0 && p == optarg) /* Don't use *_filtered or warning() (which relies on - current_target) until after initialize_all_files(). */ + current_target) until after initialize_all_files(). */ fprintf_unfiltered (gdb_stderr, @@ -336,23 +397,23 @@ main (argc, argv) if (i == 0 && p == optarg) /* Don't use *_filtered or warning() (which relies on - current_target) until after initialize_all_files(). */ + current_target) until after initialize_all_files(). */ fprintf_unfiltered (gdb_stderr, - "warning: could not set timeout limit to `%s'.\n", optarg); + "warning: could not set timeout limit to `%s'.\n", optarg); else remote_timeout = i; } break; #ifdef ADDITIONAL_OPTION_CASES - ADDITIONAL_OPTION_CASES + ADDITIONAL_OPTION_CASES #endif case '?': fprintf_unfiltered (gdb_stderr, - "Use `%s --help' for a complete list of options.\n", - argv[0]); + "Use `%s --help' for a complete list of options.\n", + argv[0]); exit (1); } } @@ -372,34 +433,54 @@ main (argc, argv) window system. */ if (tui_version) use_windows = 0; -#endif +#endif - /* OK, that's all the options. The other arguments are filenames. */ - count = 0; - for (; optind < argc; optind++) - switch (++count) - { - case 1: - symarg = argv[optind]; - execarg = argv[optind]; - break; - case 2: - corearg = argv[optind]; - break; - case 3: - fprintf_unfiltered (gdb_stderr, - "Excess command line arguments ignored. (%s%s)\n", - argv[optind], (optind == argc - 1) ? "" : " ..."); - break; - } + if (set_args) + { + /* The remaining options are the command-line options for the + inferior. The first one is the sym/exec file, and the rest + are arguments. */ + if (optind >= argc) + { + fprintf_unfiltered (gdb_stderr, + "%s: `--args' specified but no program specified\n", + argv[0]); + exit (1); + } + symarg = argv[optind]; + execarg = argv[optind]; + ++optind; + set_inferior_args_vector (argc - optind, &argv[optind]); + } + else + { + /* OK, that's all the options. The other arguments are filenames. */ + count = 0; + for (; optind < argc; optind++) + switch (++count) + { + case 1: + symarg = argv[optind]; + execarg = argv[optind]; + break; + case 2: + /* The documentation says this can be a "ProcID" as well. + We will try it as both a corefile and a pid. */ + corearg = argv[optind]; + break; + case 3: + fprintf_unfiltered (gdb_stderr, + "Excess command line arguments ignored. (%s%s)\n", + argv[optind], (optind == argc - 1) ? "" : " ..."); + break; + } + } if (batch) quiet = 1; } -#if defined(TUI) - if (tui_version) - init_ui_hook = tuiInit; -#endif + /* Initialize all files. Give the interpreter a chance to take + control of the console via the init_ui_hook()) */ gdb_init (argv[0]); /* Do these (and anything which might call wrap_here or *_filtered) @@ -422,12 +503,12 @@ main (argc, argv) if (!quiet) { /* Print all the junk at the top, with trailing "..." if we are about - to read a symbol file (possibly slowly). */ + to read a symbol file (possibly slowly). */ print_gdb_version (gdb_stdout); if (symarg) printf_filtered (".."); - wrap_here(""); - gdb_flush (gdb_stdout); /* Force to screen during slow operations */ + wrap_here (""); + gdb_flush (gdb_stdout); /* Force to screen during slow operations */ } error_pre_print = "\n\n"; @@ -440,21 +521,7 @@ main (argc, argv) *before* all the command line arguments are processed; it sets global parameters, which are independent of what file you are debugging or what directory you are in. */ -#ifdef __CYGWIN32__ - { - char * tmp = getenv ("HOME"); - - if (tmp != NULL) - { - homedir = (char *) alloca (MAX_PATH+1); - cygwin32_conv_to_posix_path (tmp, homedir); - } - else - homedir = NULL; - } -#else - homedir = getenv ("HOME"); -#endif + homedir = getenv ("HOME"); if (homedir) { homeinit = (char *) alloca (strlen (homedir) + @@ -465,62 +532,49 @@ main (argc, argv) if (!inhibit_gdbinit) { - if (!SET_TOP_LEVEL ()) - source_command (homeinit, 0); + catch_command_errors (source_command, homeinit, 0, RETURN_MASK_ALL); } - do_cleanups (ALL_CLEANUPS); /* Do stats; no need to do them elsewhere since we'll only - need them if homedir is set. Make sure that they are - zero in case one of them fails (this guarantees that they - won't match if either exists). */ - + need them if homedir is set. Make sure that they are + zero in case one of them fails (this guarantees that they + won't match if either exists). */ + memset (&homebuf, 0, sizeof (struct stat)); memset (&cwdbuf, 0, sizeof (struct stat)); - + stat (homeinit, &homebuf); - stat (gdbinit, &cwdbuf); /* We'll only need this if - homedir was set. */ + stat (gdbinit, &cwdbuf); /* We'll only need this if + homedir was set. */ } /* Now perform all the actions indicated by the arguments. */ if (cdarg != NULL) { - if (!SET_TOP_LEVEL ()) - { - cd_command (cdarg, 0); - } + catch_command_errors (cd_command, cdarg, 0, RETURN_MASK_ALL); } - do_cleanups (ALL_CLEANUPS); for (i = 0; i < ndir; i++) - if (!SET_TOP_LEVEL ()) - directory_command (dirarg[i], 0); - free ((PTR)dirarg); - do_cleanups (ALL_CLEANUPS); + catch_command_errors (directory_command, dirarg[i], 0, RETURN_MASK_ALL); + xfree (dirarg); if (execarg != NULL && symarg != NULL && STREQ (execarg, symarg)) { - /* The exec file and the symbol-file are the same. If we can't open - it, better only print one error message. */ - if (!SET_TOP_LEVEL ()) - { - exec_file_command (execarg, !batch); - symbol_file_command (symarg, 0); - } + /* The exec file and the symbol-file are the same. If we can't + open it, better only print one error message. + catch_command_errors returns non-zero on success! */ + if (catch_command_errors (exec_file_attach, execarg, !batch, RETURN_MASK_ALL)) + catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL); } else { if (execarg != NULL) - if (!SET_TOP_LEVEL ()) - exec_file_command (execarg, !batch); + catch_command_errors (exec_file_attach, execarg, !batch, RETURN_MASK_ALL); if (symarg != NULL) - if (!SET_TOP_LEVEL ()) - symbol_file_command (symarg, 0); + catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL); } - do_cleanups (ALL_CLEANUPS); /* After the symbol file has been read, print a newline to get us beyond the copyright line... But errors should still set off @@ -533,17 +587,24 @@ main (argc, argv) if (corearg != NULL) { - if (!SET_TOP_LEVEL ()) - core_file_command (corearg, !batch); - else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ()) - attach_command (corearg, !batch); + /* corearg may be either a corefile or a pid. + If its first character is a digit, try attach first + and then corefile. Otherwise try corefile first. */ + + if (isdigit (corearg[0])) + { + if (catch_command_errors (attach_command, corearg, + !batch, RETURN_MASK_ALL) == 0) + catch_command_errors (core_file_command, corearg, + !batch, RETURN_MASK_ALL); + } + else /* Can't be a pid, better be a corefile. */ + catch_command_errors (core_file_command, corearg, + !batch, RETURN_MASK_ALL); } - do_cleanups (ALL_CLEANUPS); if (ttyarg != NULL) - if (!SET_TOP_LEVEL ()) - tty_command (ttyarg, !batch); - do_cleanups (ALL_CLEANUPS); + catch_command_errors (tty_command, ttyarg, !batch, RETURN_MASK_ALL); #ifdef ADDITIONAL_OPTION_HANDLER ADDITIONAL_OPTION_HANDLER; @@ -556,31 +617,39 @@ main (argc, argv) /* Read the .gdbinit file in the current directory, *if* it isn't the same as the $HOME/.gdbinit file (it should exist, also). */ - + if (!homedir || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat))) if (!inhibit_gdbinit) { - if (!SET_TOP_LEVEL ()) - source_command (gdbinit, 0); + catch_command_errors (source_command, gdbinit, 0, RETURN_MASK_ALL); } - do_cleanups (ALL_CLEANUPS); for (i = 0; i < ncmd; i++) { - if (!SET_TOP_LEVEL ()) +#if 0 + /* NOTE: cagney/1999-11-03: SET_TOP_LEVEL() was a macro that + expanded into a call to setjmp(). */ + if (!SET_TOP_LEVEL ()) /* NB: This is #if 0'd out */ { + /* NOTE: I am commenting this out, because it is not clear + where this feature is used. It is very old and + undocumented. ezannoni: 1999-05-04 */ +#if 0 if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0') read_command_file (stdin); else +#endif source_command (cmdarg[i], !batch); do_cleanups (ALL_CLEANUPS); } +#endif + catch_command_errors (source_command, cmdarg[i], !batch, RETURN_MASK_ALL); } - free ((PTR)cmdarg); + xfree (cmdarg); /* Read in the old history after all the command files have been read. */ - init_history(); + init_history (); if (batch) { @@ -618,15 +687,13 @@ main (argc, argv) #endif } - /* The default command loop. - The WIN32 Gui calls this main to set up gdb's state, and - has its own command loop. */ -#if !defined _WIN32 || defined __GNUC__ +#if 0 + /* FIXME: cagney/1999-11-06: The original main loop was like: */ while (1) { if (!SET_TOP_LEVEL ()) { - do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */ + do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */ /* GUIs generally have their own command loop, mainloop, or whatever. This is a good place to gain control because many error conditions will end up here via longjmp(). */ @@ -634,36 +701,69 @@ main (argc, argv) command_loop_hook (); else command_loop (); - quit_command ((char *)0, instream == stdin); + quit_command ((char *) 0, instream == stdin); } } - - /* No exit -- exit is through quit_command. */ + /* NOTE: If the command_loop() returned normally, the loop would + attempt to exit by calling the function quit_command(). That + function would either call exit() or throw an error returning + control to SET_TOP_LEVEL. */ + /* NOTE: The function do_cleanups() was called once each time round + the loop. The usefulness of the call isn't clear. If an error + was thrown, everything would have already been cleaned up. If + command_loop() returned normally and quit_command() was called, + either exit() or error() (again cleaning up) would be called. */ #endif + /* NOTE: cagney/1999-11-07: There is probably no reason for not + moving this loop and the code found in captured_command_loop() + into the command_loop() proper. The main thing holding back that + change - SET_TOP_LEVEL() - has been eliminated. */ + while (1) + { + catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); + } + /* No exit -- exit is through quit_command. */ +} +int +main (int argc, char **argv) +{ + struct captured_main_args args; + args.argc = argc; + args.argv = argv; + catch_errors (captured_main, &args, "", RETURN_MASK_ALL); + return 0; } + /* Don't use *_filtered for printing help. We don't want to prompt for continue no matter how small the screen or how much we're going to print. */ static void -print_gdb_help (stream) - GDB_FILE *stream; +print_gdb_help (struct ui_file *stream) { - fputs_unfiltered ("\ + fputs_unfiltered ("\ This is the GNU debugger. Usage:\n\n\ - gdb [options] [executable-file [core-file or process-id]]\n\n\ + gdb [options] [executable-file [core-file or process-id]]\n\ + gdb [options] --args executable-file [inferior-arguments ...]\n\n\ Options:\n\n\ ", stream); - fputs_unfiltered ("\ + fputs_unfiltered ("\ + --args Arguments after executable-file are passed to inferior\n\ +", stream); + fputs_unfiltered ("\ + --[no]async Enable (disable) asynchronous version of CLI\n\ +", stream); + fputs_unfiltered ("\ -b BAUDRATE Set serial port baud rate used for remote debugging.\n\ --batch Exit after processing options.\n\ --cd=DIR Change current directory to DIR.\n\ --command=FILE Execute GDB commands from FILE.\n\ --core=COREFILE Analyze the core dump COREFILE.\n\ + --pid=PID Attach to running process PID.\n\ ", stream); - fputs_unfiltered ("\ + fputs_unfiltered ("\ --dbx DBX compatibility mode.\n\ --directory=DIR Search for source files in DIR.\n\ --epoch Output information used by epoch emacs-GDB interface.\n\ @@ -671,111 +771,41 @@ Options:\n\n\ --fullname Output information used by emacs-GDB interface.\n\ --help Print this message.\n\ ", stream); - fputs_unfiltered ("\ + fputs_unfiltered ("\ + --interpreter=INTERP\n\ + Select a specific interpreter / user interface\n\ +", stream); + fputs_unfiltered ("\ --mapped Use mapped symbol files if supported on this system.\n\ --nw Do not use a window interface.\n\ - --nx Do not read .gdbinit file.\n\ + --nx Do not read ", stream); + fputs_unfiltered (gdbinit, stream); + fputs_unfiltered (" file.\n\ --quiet Do not print version number on startup.\n\ --readnow Fully read symbol files on first access.\n\ ", stream); - fputs_unfiltered ("\ + fputs_unfiltered ("\ --se=FILE Use FILE as symbol file and executable file.\n\ --symbols=SYMFILE Read symbols from SYMFILE.\n\ --tty=TTY Use TTY for input/output by the program being debugged.\n\ ", stream); #if defined(TUI) - fputs_unfiltered ("\ + fputs_unfiltered ("\ --tui Use a terminal user interface.\n\ ", stream); #endif - fputs_unfiltered ("\ + fputs_unfiltered ("\ --version Print version information and then exit.\n\ -w Use a window interface.\n\ --write Set writing into executable and core files.\n\ --xdb XDB compatibility mode.\n\ ", stream); #ifdef ADDITIONAL_OPTION_HELP - fputs_unfiltered (ADDITIONAL_OPTION_HELP, stream); + fputs_unfiltered (ADDITIONAL_OPTION_HELP, stream); #endif - fputs_unfiltered ("\n\ + fputs_unfiltered ("\n\ For more information, type \"help\" from within GDB, or consult the\n\ GDB manual (available as on-line info or a printed manual).\n\ -Report bugs to \"bug-gdb@prep.ai.mit.edu\".\ +Report bugs to \"bug-gdb@gnu.org\".\ ", stream); } - - -void -init_proc () -{ -} - -void -proc_remove_foreign (pid) - int pid; -{ -} - -/* All 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. */ - -void -fputs_unfiltered (linebuffer, stream) - const char *linebuffer; - GDB_FILE *stream; -{ -#if defined(TUI) - extern int tui_owns_terminal; -#endif - /* If anything (GUI, TUI) wants to capture GDB output, this is - * the place... the way to do it is to set up - * fputs_unfiltered_hook. - * Our TUI ("gdb -tui") used to hook output, but in the - * new (XDB style) scheme, we do not do that anymore... - RT - */ - if (fputs_unfiltered_hook - && (stream == gdb_stdout - || stream == gdb_stderr)) - fputs_unfiltered_hook (linebuffer, stream); - 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) { - gdb_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) { - gdb_file_adjust_strbuf(strlen(linebuffer), stream); - strcat(stream->ts_strbuf, linebuffer); - } else fputs (linebuffer, stream->ts_filestream); - } - - -#else - if (stream->ts_streamtype == astring) { - gdb_file_adjust_strbuf(strlen(linebuffer), stream); - strcat(stream->ts_strbuf, linebuffer); - } else fputs (linebuffer, stream->ts_filestream); -#endif - } -} diff --git a/contrib/gdb/gdb/objfiles.c b/contrib/gdb/gdb/objfiles.c index 971a7d4..e2a6f85 100644 --- a/contrib/gdb/gdb/objfiles.c +++ b/contrib/gdb/gdb/objfiles.c @@ -1,22 +1,24 @@ /* GDB routines for manipulating objfiles. - Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. Contributed by Cygnus Support, using pieces from other GDB modules. -This file is part of GDB. + 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 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. + 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. */ + 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. */ /* This file contains support routines for creating, manipulating, and destroying objfile structures. */ @@ -35,33 +37,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "obstack.h" #include "gdb_string.h" +#include "breakpoint.h" + /* Prototypes for local functions */ #if defined(USE_MMALLOC) && defined(HAVE_MMAP) -static int -open_existing_mapped_file PARAMS ((char *, long, int)); +#include "mmalloc.h" -static int -open_mapped_file PARAMS ((char *filename, long mtime, int mapped)); +static int open_existing_mapped_file (char *, long, int); -static PTR -map_to_file PARAMS ((int)); +static int open_mapped_file (char *filename, long mtime, int flags); -#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ +static PTR map_to_file (int); -static void -add_to_objfile_sections PARAMS ((bfd *, sec_ptr, PTR)); +#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ + +static void add_to_objfile_sections (bfd *, sec_ptr, PTR); /* Externally visible variables that are owned by this module. See declarations in objfile.h for more info. */ -struct objfile *object_files; /* Linked list of all objfiles */ +struct objfile *object_files; /* Linked list of all objfiles */ struct objfile *current_objfile; /* For symbol file being read in */ struct objfile *symfile_objfile; /* Main symbol table loaded from */ struct objfile *rt_common_objfile; /* For runtime common symbols */ -int mapped_symbol_files; /* Try to use mapped symbol files */ +int mapped_symbol_files; /* Try to use mapped symbol files */ /* Locate all mappable sections of a BFD file. objfile_p_char is a char * to get it through @@ -71,11 +73,13 @@ int mapped_symbol_files; /* Try to use mapped symbol files */ #define TARGET_KEEP_SECTION(ASECT) 0 #endif +/* Called via bfd_map_over_sections to build up the section table that + the objfile references. The objfile contains pointers to the start + of the table (objfile->sections) and to the first location after + the end of the table (objfile->sections_end). */ + static void -add_to_objfile_sections (abfd, asect, objfile_p_char) - bfd *abfd; - sec_ptr asect; - PTR objfile_p_char; +add_to_objfile_sections (bfd *abfd, sec_ptr asect, PTR objfile_p_char) { struct objfile *objfile = (struct objfile *) objfile_p_char; struct obj_section section; @@ -83,7 +87,7 @@ add_to_objfile_sections (abfd, asect, objfile_p_char) aflag = bfd_get_section_flags (abfd, asect); - if (!(aflag & SEC_ALLOC) && !(TARGET_KEEP_SECTION(asect))) + if (!(aflag & SEC_ALLOC) && !(TARGET_KEEP_SECTION (asect))) return; if (0 == bfd_section_size (abfd, asect)) @@ -94,17 +98,28 @@ add_to_objfile_sections (abfd, asect, objfile_p_char) section.ovly_mapped = 0; section.addr = bfd_section_vma (abfd, asect); section.endaddr = section.addr + bfd_section_size (abfd, asect); - obstack_grow (&objfile->psymbol_obstack, (char *) §ion, sizeof(section)); + obstack_grow (&objfile->psymbol_obstack, (char *) §ion, sizeof (section)); objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1); } /* Builds a section table for OBJFILE. Returns 0 if OK, 1 on error (in which case bfd_error contains the - error). */ + error). + + Note that while we are building the table, which goes into the + psymbol obstack, we hijack the sections_end pointer to instead hold + a count of the number of sections. When bfd_map_over_sections + returns, this count is used to compute the pointer to the end of + the sections table, which then overwrites the count. + + Also note that the OFFSET and OVLY_MAPPED in each table entry + are initialized to zero. + + Also note that if anything else writes to the psymbol obstack while + we are building the table, we're pretty much hosed. */ int -build_objfile_section_table (objfile) - struct objfile *objfile; +build_objfile_section_table (struct objfile *objfile) { /* objfile->sections can be already set when reading a mapped symbol file. I believe that we do need to rebuild the section table in @@ -113,134 +128,132 @@ build_objfile_section_table (objfile) waste some memory. */ objfile->sections_end = 0; - bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *)objfile); + bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *) objfile); objfile->sections = (struct obj_section *) obstack_finish (&objfile->psymbol_obstack); objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end; - return(0); + return (0); } -/* Given a pointer to an initialized bfd (ABFD) and a flag that indicates - whether or not an objfile is to be mapped (MAPPED), allocate a new objfile - struct, fill it in as best we can, link it into the list of all known - objfiles, and return a pointer to the new objfile struct. +/* Given a pointer to an initialized bfd (ABFD) and some flag bits + allocate a new objfile struct, fill it in as best we can, link it + into the list of all known objfiles, and return a pointer to the + new objfile struct. - USER_LOADED is simply recorded in the objfile. This record offers a way for - run_command to remove old objfile entries which are no longer valid (i.e., - are associated with an old inferior), but to preserve ones that the user - explicitly loaded via the add-symbol-file command. - - IS_SOLIB is also simply recorded in the objfile. */ + The FLAGS word contains various bits (OBJF_*) that can be taken as + requests for specific operations, like trying to open a mapped + version of the objfile (OBJF_MAPPED). Other bits like + OBJF_SHARED are simply copied through to the new objfile flags + member. */ struct objfile * -allocate_objfile (abfd, mapped, user_loaded, is_solib) - bfd *abfd; - int mapped; - int user_loaded; - int is_solib; +allocate_objfile (bfd *abfd, int flags) { struct objfile *objfile = NULL; struct objfile *last_one = NULL; - mapped |= mapped_symbol_files; + if (mapped_symbol_files) + flags |= OBJF_MAPPED; #if defined(USE_MMALLOC) && defined(HAVE_MMAP) if (abfd != NULL) - { + { - /* If we can support mapped symbol files, try to open/reopen the - mapped file that corresponds to the file from which we wish to - read symbols. If the objfile is to be mapped, we must malloc - the structure itself using the mmap version, and arrange that - all memory allocation for the objfile uses the mmap routines. - If we are reusing an existing mapped file, from which we get - our objfile pointer, we have to make sure that we update the - pointers to the alloc/free functions in the obstack, in case - these functions have moved within the current gdb. */ - - int fd; - - fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd), - mapped); - if (fd >= 0) - { - PTR md; - - if ((md = map_to_file (fd)) == NULL) - { - close (fd); - } - else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL) - { - /* Update memory corruption handler function addresses. */ - init_malloc (md); - objfile -> md = md; - objfile -> mmfd = fd; - /* Update pointers to functions to *our* copies */ - obstack_chunkfun (&objfile -> psymbol_cache.cache, xmmalloc); - obstack_freefun (&objfile -> psymbol_cache.cache, mfree); - obstack_chunkfun (&objfile -> psymbol_obstack, xmmalloc); - obstack_freefun (&objfile -> psymbol_obstack, mfree); - obstack_chunkfun (&objfile -> symbol_obstack, xmmalloc); - obstack_freefun (&objfile -> symbol_obstack, mfree); - obstack_chunkfun (&objfile -> type_obstack, xmmalloc); - obstack_freefun (&objfile -> type_obstack, mfree); - /* If already in objfile list, unlink it. */ - unlink_objfile (objfile); - /* Forget things specific to a particular gdb, may have changed. */ - objfile -> sf = NULL; - } - else - { - - /* Set up to detect internal memory corruption. MUST be - done before the first malloc. See comments in - init_malloc() and mmcheck(). */ - - init_malloc (md); - - objfile = (struct objfile *) - xmmalloc (md, sizeof (struct objfile)); - memset (objfile, 0, sizeof (struct objfile)); - objfile -> md = md; - objfile -> mmfd = fd; - objfile -> flags |= OBJF_MAPPED; - mmalloc_setkey (objfile -> md, 0, objfile); - obstack_specify_allocation_with_arg (&objfile -> psymbol_cache.cache, - 0, 0, xmmalloc, mfree, - objfile -> md); - obstack_specify_allocation_with_arg (&objfile -> psymbol_obstack, - 0, 0, xmmalloc, mfree, - objfile -> md); - obstack_specify_allocation_with_arg (&objfile -> symbol_obstack, - 0, 0, xmmalloc, mfree, - objfile -> md); - obstack_specify_allocation_with_arg (&objfile -> type_obstack, - 0, 0, xmmalloc, mfree, - objfile -> md); - } - } + /* If we can support mapped symbol files, try to open/reopen the + mapped file that corresponds to the file from which we wish to + read symbols. If the objfile is to be mapped, we must malloc + the structure itself using the mmap version, and arrange that + all memory allocation for the objfile uses the mmap routines. + If we are reusing an existing mapped file, from which we get + our objfile pointer, we have to make sure that we update the + pointers to the alloc/free functions in the obstack, in case + these functions have moved within the current gdb. */ + + int fd; + + fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd), + flags); + if (fd >= 0) + { + PTR md; - if (mapped && (objfile == NULL)) - { - warning ("symbol table for '%s' will not be mapped", - bfd_get_filename (abfd)); - } - } -#else /* !defined(USE_MMALLOC) || !defined(HAVE_MMAP) */ + if ((md = map_to_file (fd)) == NULL) + { + close (fd); + } + else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL) + { + /* Update memory corruption handler function addresses. */ + init_malloc (md); + objfile->md = md; + objfile->mmfd = fd; + /* Update pointers to functions to *our* copies */ + obstack_chunkfun (&objfile->psymbol_cache.cache, xmmalloc); + obstack_freefun (&objfile->psymbol_cache.cache, xmfree); + obstack_chunkfun (&objfile->psymbol_obstack, xmmalloc); + obstack_freefun (&objfile->psymbol_obstack, xmfree); + obstack_chunkfun (&objfile->symbol_obstack, xmmalloc); + obstack_freefun (&objfile->symbol_obstack, xmfree); + obstack_chunkfun (&objfile->type_obstack, xmmalloc); + obstack_freefun (&objfile->type_obstack, xmfree); + /* If already in objfile list, unlink it. */ + unlink_objfile (objfile); + /* Forget things specific to a particular gdb, may have changed. */ + objfile->sf = NULL; + } + else + { + + /* Set up to detect internal memory corruption. MUST be + done before the first malloc. See comments in + init_malloc() and mmcheck(). */ + + init_malloc (md); + + objfile = (struct objfile *) + xmmalloc (md, sizeof (struct objfile)); + memset (objfile, 0, sizeof (struct objfile)); + objfile->md = md; + objfile->mmfd = fd; + objfile->flags |= OBJF_MAPPED; + mmalloc_setkey (objfile->md, 0, objfile); + obstack_specify_allocation_with_arg (&objfile->psymbol_cache.cache, + 0, 0, xmmalloc, xmfree, + objfile->md); + obstack_specify_allocation_with_arg (&objfile->psymbol_obstack, + 0, 0, xmmalloc, xmfree, + objfile->md); + obstack_specify_allocation_with_arg (&objfile->symbol_obstack, + 0, 0, xmmalloc, xmfree, + objfile->md); + obstack_specify_allocation_with_arg (&objfile->type_obstack, + 0, 0, xmmalloc, xmfree, + objfile->md); + } + } + + if ((flags & OBJF_MAPPED) && (objfile == NULL)) + { + warning ("symbol table for '%s' will not be mapped", + bfd_get_filename (abfd)); + flags &= ~OBJF_MAPPED; + } + } +#else /* !defined(USE_MMALLOC) || !defined(HAVE_MMAP) */ - if (mapped) + if (flags & OBJF_MAPPED) { warning ("mapped symbol tables are not supported on this machine; missing or broken mmap()."); /* Turn off the global flag so we don't try to do mapped symbol tables - any more, which shuts up gdb unless the user specifically gives the - "mapped" keyword again. */ + any more, which shuts up gdb unless the user specifically gives the + "mapped" keyword again. */ mapped_symbol_files = 0; + flags &= ~OBJF_MAPPED; } -#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ +#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ /* If we don't support mapped symbol files, didn't ask for the file to be mapped, or failed to open the mapped file for some reason, then revert @@ -250,60 +263,64 @@ allocate_objfile (abfd, mapped, user_loaded, is_solib) { objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); memset (objfile, 0, sizeof (struct objfile)); - objfile -> md = NULL; - obstack_specify_allocation (&objfile -> psymbol_cache.cache, 0, 0, - xmalloc, free); - obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc, - free); - obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc, - free); - obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc, - free); + objfile->md = NULL; + obstack_specify_allocation (&objfile->psymbol_cache.cache, 0, 0, + xmalloc, xfree); + obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0, xmalloc, + xfree); + obstack_specify_allocation (&objfile->symbol_obstack, 0, 0, xmalloc, + xfree); + obstack_specify_allocation (&objfile->type_obstack, 0, 0, xmalloc, + xfree); + flags &= ~OBJF_MAPPED; } /* Update the per-objfile information that comes from the bfd, ensuring that any data that is reference is saved in the per-objfile data region. */ - objfile -> obfd = abfd; - if (objfile -> name != NULL) + objfile->obfd = abfd; + if (objfile->name != NULL) { - mfree (objfile -> md, objfile -> name); + xmfree (objfile->md, objfile->name); } if (abfd != NULL) { - objfile -> name = mstrsave (objfile -> md, bfd_get_filename (abfd)); - objfile -> mtime = bfd_get_mtime (abfd); + objfile->name = mstrsave (objfile->md, bfd_get_filename (abfd)); + objfile->mtime = bfd_get_mtime (abfd); /* Build section table. */ if (build_objfile_section_table (objfile)) { - error ("Can't find the file sections in `%s': %s", - objfile -> name, bfd_errmsg (bfd_get_error ())); + error ("Can't find the file sections in `%s': %s", + objfile->name, bfd_errmsg (bfd_get_error ())); } } + /* Initialize the section indexes for this objfile, so that we can + later detect if they are used w/o being properly assigned to. */ + + objfile->sect_index_text = -1; + objfile->sect_index_data = -1; + objfile->sect_index_bss = -1; + objfile->sect_index_rodata = -1; + /* Add this file onto the tail of the linked list of other such files. */ - objfile -> next = NULL; + objfile->next = NULL; if (object_files == NULL) object_files = objfile; else { for (last_one = object_files; - last_one -> next; - last_one = last_one -> next); - last_one -> next = objfile; + last_one->next; + last_one = last_one->next); + last_one->next = objfile; } - /* Record whether this objfile was created because the user explicitly - caused it (e.g., used the add-symbol-file command). - */ - objfile -> user_loaded = user_loaded; - - /* Record whether this objfile definitely represents a solib. */ - objfile -> is_solib = is_solib; + /* Save passed in flag bits. */ + objfile->flags |= flags; return (objfile); } @@ -311,8 +328,7 @@ allocate_objfile (abfd, mapped, user_loaded, is_solib) /* Put OBJFILE at the front of the list. */ void -objfile_to_front (objfile) - struct objfile *objfile; +objfile_to_front (struct objfile *objfile) { struct objfile **objp; for (objp = &object_files; *objp != NULL; objp = &((*objp)->next)) @@ -343,20 +359,22 @@ objfile_to_front (objfile) between the OBJFILE and the list. */ void -unlink_objfile (objfile) - struct objfile *objfile; +unlink_objfile (struct objfile *objfile) { - struct objfile** objpp; + struct objfile **objpp; - for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp) -> next)) + for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp)->next)) { - if (*objpp == objfile) + if (*objpp == objfile) { - *objpp = (*objpp) -> next; - objfile -> next = NULL; - break; + *objpp = (*objpp)->next; + objfile->next = NULL; + return; } } + + internal_error (__FILE__, __LINE__, + "unlink_objfile: objfile already unlinked"); } @@ -367,7 +385,7 @@ unlink_objfile (objfile) Things which we do NOT free because they are not in malloc'd memory or not in memory specific to the objfile include: - objfile -> sf + objfile -> sf FIXME: If the objfile is using reusable symbol information (via mmalloc), then we need to take into account the fact that more than one process @@ -377,8 +395,7 @@ unlink_objfile (objfile) we free objects in the reusable area. */ void -free_objfile (objfile) - struct objfile *objfile; +free_objfile (struct objfile *objfile) { /* First do any symbol file specific actions required when we are finished with a particular symbol file. Note that if the objfile @@ -387,20 +404,20 @@ free_objfile (objfile) freeing things which are valid only during this particular gdb execution, or leaving them to be reused during the next one. */ - if (objfile -> sf != NULL) + if (objfile->sf != NULL) { - (*objfile -> sf -> sym_finish) (objfile); + (*objfile->sf->sym_finish) (objfile); } /* We always close the bfd. */ - if (objfile -> obfd != NULL) + if (objfile->obfd != NULL) { char *name = bfd_get_filename (objfile->obfd); - if (!bfd_close (objfile -> obfd)) + if (!bfd_close (objfile->obfd)) warning ("cannot close \"%s\": %s", name, bfd_errmsg (bfd_get_error ())); - free (name); + xfree (name); } /* Remove it from the chain of all objfiles. */ @@ -419,98 +436,95 @@ free_objfile (objfile) symbol table was blown away. How much still needs to be done is unknown, but we play it safe for now and keep each action until it is shown to be no longer needed. */ - -#if defined (CLEAR_SOLIB) - CLEAR_SOLIB (); - /* CLEAR_SOLIB closes the bfd's for any shared libraries. But - the to_sections for a core file might refer to those bfd's. So - detach any core file. */ - { - struct target_ops *t = find_core_target (); - if (t != NULL) - (t->to_detach) (NULL, 0); - } -#endif + /* I *think* all our callers call clear_symtab_users. If so, no need to call this here. */ clear_pc_function_cache (); /* The last thing we do is free the objfile struct itself for the - non-reusable case, or detach from the mapped file for the reusable - case. Note that the mmalloc_detach or the mfree is the last thing - we can do with this objfile. */ + non-reusable case, or detach from the mapped file for the + reusable case. Note that the mmalloc_detach or the xmfree() is + the last thing we can do with this objfile. */ #if defined(USE_MMALLOC) && defined(HAVE_MMAP) - if (objfile -> flags & OBJF_MAPPED) + if (objfile->flags & OBJF_MAPPED) { /* Remember the fd so we can close it. We can't close it before - doing the detach, and after the detach the objfile is gone. */ + doing the detach, and after the detach the objfile is gone. */ int mmfd; - mmfd = objfile -> mmfd; - mmalloc_detach (objfile -> md); + mmfd = objfile->mmfd; + mmalloc_detach (objfile->md); objfile = NULL; close (mmfd); } -#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ +#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ /* If we still have an objfile, then either we don't support reusable objfiles or this one was not reusable. So free it normally. */ if (objfile != NULL) { - if (objfile -> name != NULL) + if (objfile->name != NULL) { - mfree (objfile -> md, objfile -> name); + xmfree (objfile->md, objfile->name); } if (objfile->global_psymbols.list) - mfree (objfile->md, objfile->global_psymbols.list); + xmfree (objfile->md, objfile->global_psymbols.list); if (objfile->static_psymbols.list) - mfree (objfile->md, objfile->static_psymbols.list); + xmfree (objfile->md, objfile->static_psymbols.list); /* Free the obstacks for non-reusable objfiles */ - obstack_free (&objfile -> psymbol_cache.cache, 0); - obstack_free (&objfile -> psymbol_obstack, 0); - obstack_free (&objfile -> symbol_obstack, 0); - obstack_free (&objfile -> type_obstack, 0); - mfree (objfile -> md, objfile); + free_bcache (&objfile->psymbol_cache); + obstack_free (&objfile->psymbol_obstack, 0); + obstack_free (&objfile->symbol_obstack, 0); + obstack_free (&objfile->type_obstack, 0); + xmfree (objfile->md, objfile); objfile = NULL; } } +static void +do_free_objfile_cleanup (void *obj) +{ + free_objfile (obj); +} + +struct cleanup * +make_cleanup_free_objfile (struct objfile *obj) +{ + return make_cleanup (do_free_objfile_cleanup, obj); +} /* Free all the object files at once and clean up their users. */ void -free_all_objfiles () +free_all_objfiles (void) { struct objfile *objfile, *temp; ALL_OBJFILES_SAFE (objfile, temp) - { - free_objfile (objfile); - } + { + free_objfile (objfile); + } clear_symtab_users (); } /* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS entries in new_offsets. */ void -objfile_relocate (objfile, new_offsets) - struct objfile *objfile; - struct section_offsets *new_offsets; +objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets) { - struct section_offsets *delta = (struct section_offsets *) - alloca (sizeof (struct section_offsets) - + objfile->num_sections * sizeof (delta->offsets)); + struct section_offsets *delta = + (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS); { int i; int something_changed = 0; for (i = 0; i < objfile->num_sections; ++i) { - ANOFFSET (delta, i) = + delta->offsets[i] = ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i); if (ANOFFSET (delta, i) != 0) something_changed = 1; @@ -524,71 +538,72 @@ objfile_relocate (objfile, new_offsets) struct symtab *s; ALL_OBJFILE_SYMTABS (objfile, s) - { - struct linetable *l; - struct blockvector *bv; - int i; - - /* First the line table. */ - l = LINETABLE (s); - if (l) - { - for (i = 0; i < l->nitems; ++i) - l->item[i].pc += ANOFFSET (delta, s->block_line_section); - } - - /* Don't relocate a shared blockvector more than once. */ - if (!s->primary) - continue; - - bv = BLOCKVECTOR (s); - for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i) - { - struct block *b; - int j; - - b = BLOCKVECTOR_BLOCK (bv, i); - BLOCK_START (b) += ANOFFSET (delta, s->block_line_section); - BLOCK_END (b) += ANOFFSET (delta, s->block_line_section); - - for (j = 0; j < BLOCK_NSYMS (b); ++j) - { - struct symbol *sym = BLOCK_SYM (b, j); - /* The RS6000 code from which this was taken skipped - any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE. - But I'm leaving out that test, on the theory that - they can't possibly pass the tests below. */ - if ((SYMBOL_CLASS (sym) == LOC_LABEL - || SYMBOL_CLASS (sym) == LOC_STATIC - || SYMBOL_CLASS (sym) == LOC_INDIRECT) - && SYMBOL_SECTION (sym) >= 0) - { - SYMBOL_VALUE_ADDRESS (sym) += - ANOFFSET (delta, SYMBOL_SECTION (sym)); - } + { + struct linetable *l; + struct blockvector *bv; + int i; + + /* First the line table. */ + l = LINETABLE (s); + if (l) + { + for (i = 0; i < l->nitems; ++i) + l->item[i].pc += ANOFFSET (delta, s->block_line_section); + } + + /* Don't relocate a shared blockvector more than once. */ + if (!s->primary) + continue; + + bv = BLOCKVECTOR (s); + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i) + { + struct block *b; + struct symbol *sym; + int j; + + b = BLOCKVECTOR_BLOCK (bv, i); + BLOCK_START (b) += ANOFFSET (delta, s->block_line_section); + BLOCK_END (b) += ANOFFSET (delta, s->block_line_section); + + ALL_BLOCK_SYMBOLS (b, j, sym) + { + fixup_symbol_section (sym, objfile); + + /* The RS6000 code from which this was taken skipped + any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE. + But I'm leaving out that test, on the theory that + they can't possibly pass the tests below. */ + if ((SYMBOL_CLASS (sym) == LOC_LABEL + || SYMBOL_CLASS (sym) == LOC_STATIC + || SYMBOL_CLASS (sym) == LOC_INDIRECT) + && SYMBOL_SECTION (sym) >= 0) + { + SYMBOL_VALUE_ADDRESS (sym) += + ANOFFSET (delta, SYMBOL_SECTION (sym)); + } #ifdef MIPS_EFI_SYMBOL_NAME - /* Relocate Extra Function Info for ecoff. */ + /* Relocate Extra Function Info for ecoff. */ - else - if (SYMBOL_CLASS (sym) == LOC_CONST - && SYMBOL_NAMESPACE (sym) == LABEL_NAMESPACE - && STRCMP (SYMBOL_NAME (sym), MIPS_EFI_SYMBOL_NAME) == 0) - ecoff_relocate_efi (sym, ANOFFSET (delta, + else if (SYMBOL_CLASS (sym) == LOC_CONST + && SYMBOL_NAMESPACE (sym) == LABEL_NAMESPACE + && strcmp (SYMBOL_NAME (sym), MIPS_EFI_SYMBOL_NAME) == 0) + ecoff_relocate_efi (sym, ANOFFSET (delta, s->block_line_section)); #endif - } - } - } + } + } + } } { struct partial_symtab *p; ALL_OBJFILE_PSYMTABS (objfile, p) - { - p->textlow += ANOFFSET (delta, SECT_OFF_TEXT); - p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT); - } + { + p->textlow += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); + p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); + } } { @@ -597,22 +612,28 @@ objfile_relocate (objfile, new_offsets) for (psym = objfile->global_psymbols.list; psym < objfile->global_psymbols.next; psym++) - if (SYMBOL_SECTION (*psym) >= 0) - SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta, - SYMBOL_SECTION (*psym)); + { + fixup_psymbol_section (*psym, objfile); + if (SYMBOL_SECTION (*psym) >= 0) + SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta, + SYMBOL_SECTION (*psym)); + } for (psym = objfile->static_psymbols.list; psym < objfile->static_psymbols.next; psym++) - if (SYMBOL_SECTION (*psym) >= 0) - SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta, - SYMBOL_SECTION (*psym)); + { + fixup_psymbol_section (*psym, objfile); + if (SYMBOL_SECTION (*psym) >= 0) + SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta, + SYMBOL_SECTION (*psym)); + } } { struct minimal_symbol *msym; ALL_OBJFILE_MSYMBOLS (objfile, msym) if (SYMBOL_SECTION (msym) >= 0) - SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym)); + SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym)); } /* Relocating different sections by different amounts may cause the symbols to be out of order. */ @@ -621,59 +642,52 @@ objfile_relocate (objfile, new_offsets) { int i; for (i = 0; i < objfile->num_sections; ++i) - ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i); + (objfile->section_offsets)->offsets[i] = ANOFFSET (new_offsets, i); } + if (objfile->ei.entry_point != ~(CORE_ADDR) 0) + { + /* Relocate ei.entry_point with its section offset, use SECT_OFF_TEXT + only as a fallback. */ + struct obj_section *s; + s = find_pc_section (objfile->ei.entry_point); + if (s) + objfile->ei.entry_point += ANOFFSET (delta, s->the_bfd_section->index); + else + objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); + } + { struct obj_section *s; bfd *abfd; abfd = objfile->obfd; - for (s = objfile->sections; - s < objfile->sections_end; ++s) + ALL_OBJFILE_OSECTIONS (objfile, s) { - flagword flags; - - flags = bfd_get_section_flags (abfd, s->the_bfd_section); - - if (flags & SEC_CODE) - { - s->addr += ANOFFSET (delta, SECT_OFF_TEXT); - s->endaddr += ANOFFSET (delta, SECT_OFF_TEXT); - } - else if (flags & (SEC_DATA | SEC_LOAD)) - { - s->addr += ANOFFSET (delta, SECT_OFF_DATA); - s->endaddr += ANOFFSET (delta, SECT_OFF_DATA); - } - else if (flags & SEC_ALLOC) - { - s->addr += ANOFFSET (delta, SECT_OFF_BSS); - s->endaddr += ANOFFSET (delta, SECT_OFF_BSS); - } + int idx = s->the_bfd_section->index; + + s->addr += ANOFFSET (delta, idx); + s->endaddr += ANOFFSET (delta, idx); } } - if (objfile->ei.entry_point != ~(CORE_ADDR)0) - objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT); - if (objfile->ei.entry_func_lowpc != INVALID_ENTRY_LOWPC) { - objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT); - objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT); + objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); + objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); } if (objfile->ei.entry_file_lowpc != INVALID_ENTRY_LOWPC) { - objfile->ei.entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT); - objfile->ei.entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT); + objfile->ei.entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); + objfile->ei.entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); } if (objfile->ei.main_func_lowpc != INVALID_ENTRY_LOWPC) { - objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT); - objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT); + objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); + objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile)); } /* Relocate breakpoints as necessary, after things are relocated. */ @@ -685,17 +699,17 @@ objfile_relocate (objfile, new_offsets) available, nonzero otherwise. */ int -have_partial_symbols () +have_partial_symbols (void) { struct objfile *ofp; ALL_OBJFILES (ofp) - { - if (ofp -> psymtabs != NULL) - { - return 1; - } - } + { + if (ofp->psymtabs != NULL) + { + return 1; + } + } return 0; } @@ -704,17 +718,17 @@ have_partial_symbols () available, nonzero otherwise. */ int -have_full_symbols () +have_full_symbols (void) { struct objfile *ofp; ALL_OBJFILES (ofp) - { - if (ofp -> symtabs != NULL) - { - return 1; - } - } + { + if (ofp->symtabs != NULL) + { + return 1; + } + } return 0; } @@ -722,19 +736,19 @@ have_full_symbols () /* This operations deletes all objfile entries that represent solibs that weren't explicitly loaded by the user, via e.g., the add-symbol-file command. - */ + */ void -objfile_purge_solibs () +objfile_purge_solibs (void) { - struct objfile * objf; - struct objfile * temp; + struct objfile *objf; + struct objfile *temp; ALL_OBJFILES_SAFE (objf, temp) { /* We assume that the solib package has been purged already, or will be soon. - */ - if (! objf->user_loaded && objf->is_solib) + */ + if (!(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED)) free_objfile (objf); } } @@ -745,17 +759,17 @@ objfile_purge_solibs () available, nonzero otherwise. */ int -have_minimal_symbols () +have_minimal_symbols (void) { struct objfile *ofp; ALL_OBJFILES (ofp) - { - if (ofp -> msymbols != NULL) - { - return 1; - } - } + { + if (ofp->msymbols != NULL) + { + return 1; + } + } return 0; } @@ -781,10 +795,7 @@ have_minimal_symbols () Otherwise, returns the open file descriptor. */ static int -open_existing_mapped_file (symsfilename, mtime, mapped) - char *symsfilename; - long mtime; - int mapped; +open_existing_mapped_file (char *symsfilename, long mtime, int flags) { int fd = -1; struct stat sbuf; @@ -793,7 +804,7 @@ open_existing_mapped_file (symsfilename, mtime, mapped) { if (sbuf.st_mtime < mtime) { - if (!mapped) + if (!(flags & OBJF_MAPPED)) { warning ("mapped symbol file `%s' is out of date, ignored it", symsfilename); @@ -836,10 +847,7 @@ open_existing_mapped_file (symsfilename, mtime, mapped) /bin for example). */ static int -open_mapped_file (filename, mtime, mapped) - char *filename; - long mtime; - int mapped; +open_mapped_file (char *filename, long mtime, int flags) { int fd; char *symsfilename; @@ -847,12 +855,12 @@ open_mapped_file (filename, mtime, mapped) /* First try to open an existing file in the current directory, and then try the directory where the symbol file is located. */ - symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL); - if ((fd = open_existing_mapped_file (symsfilename, mtime, mapped)) < 0) + symsfilename = concat ("./", lbasename (filename), ".syms", (char *) NULL); + if ((fd = open_existing_mapped_file (symsfilename, mtime, flags)) < 0) { - free (symsfilename); + xfree (symsfilename); symsfilename = concat (filename, ".syms", (char *) NULL); - fd = open_existing_mapped_file (symsfilename, mtime, mapped); + fd = open_existing_mapped_file (symsfilename, mtime, flags); } /* If we don't have an open file by now, then either the file does not @@ -864,10 +872,10 @@ open_mapped_file (filename, mtime, mapped) By default the file is rw for everyone, with the user's umask taking care of turning off the permissions the user wants off. */ - if ((fd < 0) && mapped) + if ((fd < 0) && (flags & OBJF_MAPPED)) { - free (symsfilename); - symsfilename = concat ("./", basename (filename), ".syms", + xfree (symsfilename); + symsfilename = concat ("./", lbasename (filename), ".syms", (char *) NULL); if ((fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) { @@ -879,13 +887,12 @@ open_mapped_file (filename, mtime, mapped) } } - free (symsfilename); + xfree (symsfilename); return (fd); } static PTR -map_to_file (fd) - int fd; +map_to_file (int fd) { PTR md; CORE_ADDR mapto; @@ -912,8 +919,8 @@ map_to_file (fd) if (mapto != 0) { /* To avoid reusing the freshly created mapping file, at the - address selected by mmap, we must truncate it before trying - to do an attach at the address we want. */ + address selected by mmap, we must truncate it before trying + to do an attach at the address we want. */ ftruncate (fd, 0); md = mmalloc_attach (fd, (PTR) mapto); if (md != NULL) @@ -926,7 +933,7 @@ map_to_file (fd) return (md); } -#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ +#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */ /* Returns a section whose range includes PC and SECTION, or NULL if none found. Note the distinction between the return type, @@ -935,54 +942,61 @@ map_to_file (fd) contains a pointer to the bfd struct sec section. */ struct obj_section * -find_pc_sect_section (pc, section) - CORE_ADDR pc; - struct sec *section; +find_pc_sect_section (CORE_ADDR pc, struct sec *section) { struct obj_section *s; struct objfile *objfile; - - ALL_OBJFILES (objfile) - for (s = objfile->sections; s < objfile->sections_end; ++s) -#if defined(HPUXHPPA) - if ((section == 0 || section == s->the_bfd_section) && - s->addr <= pc && pc <= s->endaddr) -#else - if ((section == 0 || section == s->the_bfd_section) && - s->addr <= pc && pc < s->endaddr) -#endif - return(s); - return(NULL); + ALL_OBJSECTIONS (objfile, s) + if ((section == 0 || section == s->the_bfd_section) && + s->addr <= pc && pc < s->endaddr) + return (s); + + return (NULL); } /* Returns a section whose range includes PC or NULL if none found. Backward compatibility, no section. */ struct obj_section * -find_pc_section(pc) - CORE_ADDR pc; +find_pc_section (CORE_ADDR pc) { return find_pc_sect_section (pc, find_pc_mapped_section (pc)); } - + /* In SVR4, we recognize a trampoline by it's section name. That is, if the pc is in a section named ".plt" then we are in a trampoline. */ int -in_plt_section(pc, name) - CORE_ADDR pc; - char *name; +in_plt_section (CORE_ADDR pc, char *name) { struct obj_section *s; int retval = 0; - - s = find_pc_section(pc); - + + s = find_pc_section (pc); + retval = (s != NULL && s->the_bfd_section->name != NULL && STREQ (s->the_bfd_section->name, ".plt")); - return(retval); + return (retval); } + +/* Return nonzero if NAME is in the import list of OBJFILE. Else + return zero. */ + +int +is_in_import_list (char *name, struct objfile *objfile) +{ + register int i; + + if (!objfile || !name || !*name) + return 0; + + for (i = 0; i < objfile->import_list_size; i++) + if (objfile->import_list[i] && STREQ (name, objfile->import_list[i])) + return 1; + return 0; +} + diff --git a/contrib/gdb/gdb/remote.c b/contrib/gdb/gdb/remote.c index 81c23fc..2d70baf 100644 --- a/contrib/gdb/gdb/remote.c +++ b/contrib/gdb/gdb/remote.c @@ -1,410 +1,344 @@ /* Remote target communications for serial-line targets in custom GDB protocol - Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 1998 - 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. */ - -/* Remote communication protocol. - - A debug packet whose contents are <data> - is encapsulated for transmission in the form: - - $ <data> # CSUM1 CSUM2 - - <data> must be ASCII alphanumeric and cannot include characters - '$' or '#'. If <data> starts with two characters followed by - ':', then the existing stubs interpret this as a sequence number. - - CSUM1 and CSUM2 are ascii hex representation of an 8-bit - checksum of <data>, the most significant nibble is sent first. - the hex digits 0-9,a-f are used. - - Receiver responds with: - - + - if CSUM is correct and ready for next packet - - - if CSUM is incorrect - - <data> is as follows: - Most values are encoded in ascii hex digits. Signal numbers are according - to the numbering in target.h. - - Request Packet - - set thread Hct... Set thread for subsequent operations. - c = 'c' for thread used in step and - continue; t... can be -1 for all - threads. - c = 'g' for thread used in other - operations. If zero, pick a thread, - any thread. - reply OK for success - ENN for an error. - - read registers g - reply XX....X Each byte of register data - is described by two hex digits. - Registers are in the internal order - for GDB, and the bytes in a register - are in the same order the machine uses. - or ENN for an error. - - write regs GXX..XX Each byte of register data - is described by two hex digits. - reply OK for success - ENN for an error - - write reg Pn...=r... Write register n... with value r..., - which contains two hex digits for each - byte in the register (target byte - order). - reply OK for success - ENN for an error - (not supported by all stubs). - - read mem mAA..AA,LLLL AA..AA is address, LLLL is length. - reply XX..XX XX..XX is mem contents - Can be fewer bytes than requested - if able to read only part of the data. - or ENN NN is errno - - write mem MAA..AA,LLLL:XX..XX - AA..AA is address, - LLLL is number of bytes, - XX..XX is data - reply OK for success - ENN for an error (this includes the case - where only part of the data was - written). - - write mem XAA..AA,LLLL:XX..XX - (binary) AA..AA is address, - LLLL is number of bytes, - XX..XX is binary data - reply OK for success - ENN for an error - - continue cAA..AA AA..AA is address to resume - If AA..AA is omitted, - resume at same address. - - step sAA..AA AA..AA is address to resume - If AA..AA is omitted, - resume at same address. - - continue with Csig;AA..AA Continue with signal sig (hex signal - signal number). If ;AA..AA is omitted, - resume at same address. - - step with Ssig;AA..AA Like 'C' but step not continue. - signal - - last signal ? Reply the current reason for stopping. - This is the same reply as is generated - for step or cont : SAA where AA is the - signal number. - - detach D Reply OK. - - There is no immediate reply to step or cont. - The reply comes when the machine stops. - It is SAA AA is the signal number. - - or... TAAn...:r...;n...:r...;n...:r...; - AA = signal number - n... = register number (hex) - r... = register contents - n... = `thread' - r... = thread process ID. This is - a hex integer. - n... = other string not starting - with valid hex digit. - gdb should ignore this n,r pair - and go on to the next. This way - we can extend the protocol. - or... WAA The process exited, and AA is - the exit status. This is only - applicable for certains sorts of - targets. - or... XAA The process terminated with signal - AA. - or... OXX..XX XX..XX is hex encoding of ASCII data. This - can happen at any time while the - program is running and the debugger - should continue to wait for - 'W', 'T', etc. - - thread alive TXX Find out if the thread XX is alive. - reply OK thread is still alive - ENN thread is dead - - remote restart RXX Restart the remote server - - extended ops ! Use the extended remote protocol. - Sticky -- only needs to be set once. - - kill request k - - toggle debug d toggle debug flag (see 386 & 68k stubs) - reset r reset -- see sparc stub. - reserved <other> On other requests, the stub should - ignore the request and send an empty - response ($#<checksum>). This way - we can extend the protocol and GDB - can tell whether the stub it is - talking to uses the old or the new. - search tAA:PP,MM Search backwards starting at address - AA for a match with pattern PP and - mask MM. PP and MM are 4 bytes. - Not supported by all stubs. - - general query qXXXX Request info about XXXX. - general set QXXXX=yyyy Set value of XXXX to yyyy. - query sect offs qOffsets Get section offsets. Reply is - Text=xxx;Data=yyy;Bss=zzz - - Responses can be run-length encoded to save space. A '*' means that - the next character is an ASCII encoding giving a repeat count which - stands for that many repititions of the character preceding the '*'. - The encoding is n+29, yielding a printable character where n >=3 - (which is where rle starts to win). Don't use an n > 126. - - So - "0* " means the same as "0000". */ + + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001, 2002 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. */ + +/* See the GDB User Guide for details of the GDB remote protocol. */ #include "defs.h" #include "gdb_string.h" #include <ctype.h> #include <fcntl.h> -#include "frame.h" #include "inferior.h" #include "bfd.h" #include "symfile.h" #include "target.h" -#include "wait.h" -/*#include "terminal.h"*/ +/*#include "terminal.h" */ #include "gdbcmd.h" #include "objfiles.h" #include "gdb-stabs.h" #include "gdbthread.h" +#include "remote.h" +#include "regcache.h" +#include "value.h" +#include "gdb_assert.h" -#include "dcache.h" - +#include <ctype.h> +#include <sys/time.h> #ifdef USG #include <sys/types.h> #endif +#include "event-loop.h" +#include "event-top.h" +#include "inf-loop.h" + #include <signal.h> #include "serial.h" -/* Prototypes for local functions */ - -static int remote_write_bytes PARAMS ((CORE_ADDR memaddr, - char *myaddr, int len)); +#include "gdbcore.h" /* for exec_bfd */ -static int remote_read_bytes PARAMS ((CORE_ADDR memaddr, - char *myaddr, int len)); - -static void remote_files_info PARAMS ((struct target_ops *ignore)); - -static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char * myaddr, - int len, int should_write, - struct target_ops * target)); - -static void remote_prepare_to_store PARAMS ((void)); - -static void remote_fetch_registers PARAMS ((int regno)); - -static void remote_resume PARAMS ((int pid, int step, - enum target_signal siggnal)); +/* Prototypes for local functions */ +static void cleanup_sigint_signal_handler (void *dummy); +static void initialize_sigint_signal_handler (void); +static int getpkt_sane (char *buf, long sizeof_buf, int forever); -static int remote_start_remote PARAMS ((PTR)); +static void handle_remote_sigint (int); +static void handle_remote_sigint_twice (int); +static void async_remote_interrupt (gdb_client_data); +void async_remote_interrupt_twice (gdb_client_data); -static void remote_open PARAMS ((char *name, int from_tty)); +static void build_remote_gdbarch_data (void); -static void extended_remote_open PARAMS ((char *name, int from_tty)); +static int remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len); -static void remote_open_1 PARAMS ((char *, int, struct target_ops *, - int extended_p)); +static int remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len); -static void remote_close PARAMS ((int quitting)); +static void remote_files_info (struct target_ops *ignore); -static void remote_store_registers PARAMS ((int regno)); +static int remote_xfer_memory (CORE_ADDR memaddr, char *myaddr, + int len, int should_write, + struct mem_attrib *attrib, + struct target_ops *target); -static void remote_mourn PARAMS ((void)); +static void remote_prepare_to_store (void); -static void extended_remote_restart PARAMS ((void)); +static void remote_fetch_registers (int regno); -static void extended_remote_mourn PARAMS ((void)); +static void remote_resume (ptid_t ptid, int step, + enum target_signal siggnal); +static void remote_async_resume (ptid_t ptid, int step, + enum target_signal siggnal); +static int remote_start_remote (PTR); -static void extended_remote_create_inferior PARAMS ((char *, char *, char **)); +static void remote_open (char *name, int from_tty); +static void remote_async_open (char *name, int from_tty); -static void remote_mourn_1 PARAMS ((struct target_ops *)); +static void extended_remote_open (char *name, int from_tty); +static void extended_remote_async_open (char *name, int from_tty); -static void remote_send PARAMS ((char *buf)); +static void remote_open_1 (char *, int, struct target_ops *, int extended_p); +static void remote_async_open_1 (char *, int, struct target_ops *, + int extended_p); -static int readchar PARAMS ((int timeout)); +static void remote_close (int quitting); -static int remote_wait PARAMS ((int pid, struct target_waitstatus * status)); +static void remote_store_registers (int regno); -static void remote_kill PARAMS ((void)); +static void remote_mourn (void); +static void remote_async_mourn (void); -static int tohex PARAMS ((int nib)); +static void extended_remote_restart (void); -static void remote_detach PARAMS ((char *args, int from_tty)); +static void extended_remote_mourn (void); -static void remote_interrupt PARAMS ((int signo)); +static void extended_remote_create_inferior (char *, char *, char **); +static void extended_remote_async_create_inferior (char *, char *, char **); -static void interrupt_query PARAMS ((void)); +static void remote_mourn_1 (struct target_ops *); -static void set_thread PARAMS ((int, int)); +static void remote_send (char *buf, long sizeof_buf); -static int remote_thread_alive PARAMS ((int)); +static int readchar (int timeout); -static void get_offsets PARAMS ((void)); +static ptid_t remote_wait (ptid_t ptid, + struct target_waitstatus *status); +static ptid_t remote_async_wait (ptid_t ptid, + struct target_waitstatus *status); -static int read_frame PARAMS ((char *)); +static void remote_kill (void); +static void remote_async_kill (void); -static int remote_insert_breakpoint PARAMS ((CORE_ADDR, char *)); +static int tohex (int nib); -static int remote_remove_breakpoint PARAMS ((CORE_ADDR, char *)); +static void remote_detach (char *args, int from_tty); +static void remote_async_detach (char *args, int from_tty); -static int hexnumlen PARAMS ((ULONGEST num)); +static void remote_interrupt (int signo); -static void init_remote_ops PARAMS ((void)); +static void remote_interrupt_twice (int signo); -static void init_extended_remote_ops PARAMS ((void)); +static void interrupt_query (void); -static void remote_stop PARAMS ((void)); +static void set_thread (int, int); -static int ishex PARAMS ((int ch, int *val)); +static int remote_thread_alive (ptid_t); -static int stubhex PARAMS ((int ch)); +static void get_offsets (void); -static int remote_query PARAMS ((int/*char*/, char *, char *, int *)); +static long read_frame (char *buf, long sizeof_buf); -static int hexnumstr PARAMS ((char *, ULONGEST)); +static int remote_insert_breakpoint (CORE_ADDR, char *); -static CORE_ADDR remote_address_masked PARAMS ((CORE_ADDR)); +static int remote_remove_breakpoint (CORE_ADDR, char *); -static void print_packet PARAMS ((char *)); +static int hexnumlen (ULONGEST num); -static unsigned long crc32 PARAMS ((unsigned char *, int, unsigned int)); +static void init_remote_ops (void); -static void compare_sections_command PARAMS ((char *, int)); +static void init_extended_remote_ops (void); -static void packet_command PARAMS ((char *, int)); +static void init_remote_cisco_ops (void); -static int stub_unpack_int PARAMS ((char *buff, int fieldlength)); +static struct target_ops remote_cisco_ops; -char *unpack_varlen_hex PARAMS ((char *buff, int *result)); +static void remote_stop (void); -static char *unpack_nibble PARAMS ((char *buf, int *val)); +static int ishex (int ch, int *val); -static char *pack_nibble PARAMS ((char *buf, int nibble)); +static int stubhex (int ch); -static char *pack_hex_byte PARAMS ((char *pkt, int/*unsigned char*/ byte)); +static int remote_query (int /*char */ , char *, char *, int *); -static char *unpack_byte PARAMS ((char *buf, int *value)); +static int hexnumstr (char *, ULONGEST); -static char *pack_int PARAMS ((char *buf, int value)); +static int hexnumnstr (char *, ULONGEST, int); -static char *unpack_int PARAMS ((char *buf, int *value)); +static CORE_ADDR remote_address_masked (CORE_ADDR); -static char *unpack_string PARAMS ((char *src, char *dest, int length)); +static void print_packet (char *); -static char *pack_threadid PARAMS ((char *pkt, threadref *id)); +static unsigned long crc32 (unsigned char *, int, unsigned int); -static char *unpack_threadid PARAMS ((char *inbuf, threadref *id)); +static void compare_sections_command (char *, int); -void int_to_threadref PARAMS ((threadref *id, int value)); +static void packet_command (char *, int); -static int threadref_to_int PARAMS ((threadref *ref)); +static int stub_unpack_int (char *buff, int fieldlength); -static void copy_threadref PARAMS ((threadref *dest, threadref *src)); +static ptid_t remote_current_thread (ptid_t oldptid); -static int threadmatch PARAMS ((threadref *dest, threadref *src)); +static void remote_find_new_threads (void); -static char *pack_threadinfo_request PARAMS ((char *pkt, int mode, - threadref *id)); +static void record_currthread (int currthread); -static int remote_unpack_thread_info_response PARAMS ((char *pkt, - threadref *expectedref, - struct gdb_ext_thread_info *info)); +static int fromhex (int a); +static int hex2bin (const char *hex, char *bin, int count); -static int remote_get_threadinfo PARAMS ((threadref *threadid, - int fieldset, /*TAG mask */ - struct gdb_ext_thread_info *info)); +static int bin2hex (const char *bin, char *hex, int count); -static int adapt_remote_get_threadinfo PARAMS ((gdb_threadref *ref, - int selection, - struct gdb_ext_thread_info *info)); +static int putpkt_binary (char *buf, int cnt); -static char *pack_threadlist_request PARAMS ((char *pkt, int startflag, - int threadcount, - threadref *nextthread)); +static void check_binary_download (CORE_ADDR addr); -static int parse_threadlist_response PARAMS ((char *pkt, - int result_limit, - threadref *original_echo, - threadref *resultlist, - int *doneflag)); +struct packet_config; -static int remote_get_threadlist PARAMS ((int startflag, - threadref *nextthread, - int result_limit, - int *done, - int *result_count, - threadref *threadlist)); +static void show_packet_config_cmd (struct packet_config *config); -typedef int (*rmt_thread_action) (threadref *ref, void *context); +static void update_packet_config (struct packet_config *config); -static int remote_threadlist_iterator PARAMS ((rmt_thread_action stepfunction, - void *context, int looplimit)); +/* Define the target subroutine names */ -static int remote_newthread_step PARAMS ((threadref *ref, void *context)); +void open_remote_target (char *, int, struct target_ops *, int); -static int remote_current_thread PARAMS ((int oldpid)); +void _initialize_remote (void); -int remote_find_new_threads PARAMS ((void)); +/* Description of the remote protocol. Strictly speeking, when the + target is open()ed, remote.c should create a per-target description + of the remote protocol using that target's architecture. + Unfortunatly, the target stack doesn't include local state. For + the moment keep the information in the target's architecture + object. Sigh.. */ -static void record_currthread PARAMS ((int currthread)); +struct packet_reg +{ + long offset; /* Offset into G packet. */ + long regnum; /* GDB's internal register number. */ + LONGEST pnum; /* Remote protocol register number. */ + int in_g_packet; /* Always part of G packet. */ + /* long size in bytes; == REGISTER_RAW_SIZE (regnum); at present. */ + /* char *name; == REGISTER_NAME (regnum); at present. */ +}; -static void init_remote_threads PARAMS ((void)); +struct remote_state +{ + /* Description of the remote protocol registers. */ + long sizeof_g_packet; + + /* Description of the remote protocol registers indexed by REGNUM + (making an array of NUM_REGS + NUM_PSEUDO_REGS in size). */ + struct packet_reg *regs; + + /* This is the size (in chars) of the first response to the ``g'' + packet. It is used as a heuristic when determining the maximum + size of memory-read and memory-write packets. A target will + typically only reserve a buffer large enough to hold the ``g'' + packet. The size does not include packet overhead (headers and + trailers). */ + long actual_register_packet_size; + + /* This is the maximum size (in chars) of a non read/write packet. + It is also used as a cap on the size of read/write packets. */ + long remote_packet_size; +}; -/* exported functions */ +/* Handle for retreving the remote protocol data from gdbarch. */ +static struct gdbarch_data *remote_gdbarch_data_handle; -extern int fromhex PARAMS ((int a)); +static struct remote_state * +get_remote_state () +{ + return gdbarch_data (remote_gdbarch_data_handle); +} -extern void getpkt PARAMS ((char *buf, int forever)); +static void * +init_remote_state (struct gdbarch *gdbarch) +{ + int regnum; + struct remote_state *rs = xmalloc (sizeof (struct remote_state)); -extern int putpkt PARAMS ((char *buf)); + /* Start out by having the remote protocol mimic the existing + behavour - just copy in the description of the register cache. */ + rs->sizeof_g_packet = REGISTER_BYTES; /* OK use. */ -static int putpkt_binary PARAMS ((char *buf, int cnt)); + /* Assume a 1:1 regnum<->pnum table. */ + rs->regs = xcalloc (NUM_REGS + NUM_PSEUDO_REGS, sizeof (struct packet_reg)); + for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++) + { + struct packet_reg *r = &rs->regs[regnum]; + r->pnum = regnum; + r->regnum = regnum; + r->offset = REGISTER_BYTE (regnum); + r->in_g_packet = (regnum < NUM_REGS); + /* ...size = REGISTER_RAW_SIZE (regnum); */ + /* ...name = REGISTER_NAME (regnum); */ + } -void remote_console_output PARAMS ((char *)); + /* Default maximum number of characters in a packet body. Many + remote stubs have a hardwired buffer size of 400 bytes + (c.f. BUFMAX in m68k-stub.c and i386-stub.c). BUFMAX-1 is used + as the maximum packet-size to ensure that the packet and an extra + NUL character can always fit in the buffer. This stops GDB + trashing stubs that try to squeeze an extra NUL into what is + already a full buffer (As of 1999-12-04 that was most stubs. */ + rs->remote_packet_size = 400 - 1; + + /* Should rs->sizeof_g_packet needs more space than the + default, adjust the size accordingly. Remember that each byte is + encoded as two characters. 32 is the overhead for the packet + header / footer. NOTE: cagney/1999-10-26: I suspect that 8 + (``$NN:G...#NN'') is a better guess, the below has been padded a + little. */ + if (rs->sizeof_g_packet > ((rs->remote_packet_size - 32) / 2)) + rs->remote_packet_size = (rs->sizeof_g_packet * 2 + 32); + + /* This one is filled in when a ``g'' packet is received. */ + rs->actual_register_packet_size = 0; -static void check_binary_download PARAMS ((CORE_ADDR addr)); + return rs; +} -/* Define the target subroutine names */ +static void +free_remote_state (struct gdbarch *gdbarch, void *pointer) +{ + struct remote_state *data = pointer; + xfree (data->regs); + xfree (data); +} -void open_remote_target PARAMS ((char *, int, struct target_ops *, int)); +static struct packet_reg * +packet_reg_from_regnum (struct remote_state *rs, long regnum) +{ + if (regnum < 0 && regnum >= NUM_REGS + NUM_PSEUDO_REGS) + return NULL; + else + { + struct packet_reg *r = &rs->regs[regnum]; + gdb_assert (r->regnum == regnum); + return r; + } +} -void _initialize_remote PARAMS ((void)); +static struct packet_reg * +packet_reg_from_pnum (struct remote_state *rs, LONGEST pnum) +{ + int i; + for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) + { + struct packet_reg *r = &rs->regs[i]; + if (r->pnum == pnum) + return r; + } + return NULL; +} /* */ @@ -412,16 +346,21 @@ static struct target_ops remote_ops; static struct target_ops extended_remote_ops; -static struct target_thread_vector remote_thread_vec; +/* Temporary target ops. Just like the remote_ops and + extended_remote_ops, but with asynchronous support. */ +static struct target_ops remote_async_ops; + +static struct target_ops extended_async_remote_ops; -/* This was 5 seconds, which is a long time to sit and wait. - Unless this is going though some terminal server or multiplexer or - other form of hairy serial connection, I would think 2 seconds would - be plenty. */ +/* FIXME: cagney/1999-09-23: Even though getpkt was called with + ``forever'' still use the normal timeout mechanism. This is + currently used by the ASYNC code to guarentee that target reads + during the initial connect always time-out. Once getpkt has been + modified to return a timeout indication and, in turn + remote_wait()/wait_for_inferior() have gained a timeout parameter + this can go away. */ +static int wait_forever_enabled_p = 1; -/* Changed to allow option to set timeout value. - was static int remote_timeout = 2; */ -extern int remote_timeout; /* This variable chooses whether to send a ^C or a break when the user requests program interruption. Although ^C is usually what remote @@ -430,53 +369,14 @@ extern int remote_timeout; static int remote_break; -/* Has the user attempted to interrupt the target? If so, then offer - the user the opportunity to bail out completely if he interrupts - again. */ -static int interrupted_already = 0; - /* Descriptor for I/O to remote machine. Initialize it to NULL so that remote_open knows that we don't have a file open when the program starts. */ -static serial_t remote_desc = NULL; - -/* This variable (available to the user via "set remotebinarydownload") - dictates whether downloads are sent in binary (via the 'X' packet). - We assume that the stub can, and attempt to do it. This will be cleared if - the stub does not understand it. This switch is still needed, though - in cases when the packet is supported in the stub, but the connection - does not allow it (i.e., 7-bit serial connection only). */ -static int remote_binary_download = 1; - -/* Have we already checked whether binary downloads work? */ -static int remote_binary_checked; - -/* Having this larger than 400 causes us to be incompatible with m68k-stub.c - and i386-stub.c. Normally, no one would notice because it only matters - for writing large chunks of memory (e.g. in downloads). Also, this needs - to be more than 400 if required to hold the registers (see below, where - we round it up based on REGISTER_BYTES). */ -#define PBUFSIZ 400 - -/* Maximum number of bytes to read/write at once. The value here - is chosen to fill up a packet (the headers account for the 32). */ -#define MAXBUFBYTES ((PBUFSIZ-32)/2) - -/* Round up PBUFSIZ to hold all the registers, at least. */ -/* The blank line after the #if seems to be required to work around a - bug in HP's PA compiler. */ -#if REGISTER_BYTES > MAXBUFBYTES - -#undef PBUFSIZ -#define PBUFSIZ (REGISTER_BYTES * 2 + 32) -#endif - -/* This variable sets the number of bytes to be written to the target - in a single packet. Normally PBUFSIZ is satisfactory, but some - targets need smaller values (perhaps because the receiving end - is slow). */ +static struct serial *remote_desc = NULL; -static int remote_write_size = PBUFSIZ; +/* This is set by the target (thru the 'S' message) + to denote that the target is in kernel mode. */ +static int cisco_kernel_mode = 0; /* This variable sets the number of bits in an address that are to be sent in a memory ("M" or "m") packet. Normally, after stripping @@ -491,205 +391,600 @@ static int remote_write_size = PBUFSIZ; static int remote_address_size; -/* This is the size (in chars) of the first response to the `g' command. This - is used to limit the size of the memory read and write commands to prevent - stub buffers from overflowing. The size does not include headers and - trailers, it is only the payload size. */ +/* Tempoary to track who currently owns the terminal. See + target_async_terminal_* for more details. */ -static int remote_register_buf_size = 0; +static int remote_async_terminal_ours_p; -/* Should we try the 'P' request? If this is set to one when the stub - doesn't support 'P', the only consequence is some unnecessary traffic. */ -static int stub_supports_P = 1; + +/* User configurable variables for the number of characters in a + memory read/write packet. MIN ((rs->remote_packet_size), + rs->sizeof_g_packet) is the default. Some targets need smaller + values (fifo overruns, et.al.) and some users need larger values + (speed up transfers). The variables ``preferred_*'' (the user + request), ``current_*'' (what was actually set) and ``forced_*'' + (Positive - a soft limit, negative - a hard limit). */ + +struct memory_packet_config +{ + char *name; + long size; + int fixed_p; +}; -/* These are pointers to hook functions that may be set in order to - modify resume/wait behavior for a particular architecture. */ +/* Compute the current size of a read/write packet. Since this makes + use of ``actual_register_packet_size'' the computation is dynamic. */ -void (*target_resume_hook) PARAMS ((void)); -void (*target_wait_loop_hook) PARAMS ((void)); +static long +get_memory_packet_size (struct memory_packet_config *config) +{ + struct remote_state *rs = get_remote_state (); + /* NOTE: The somewhat arbitrary 16k comes from the knowledge (folk + law?) that some hosts don't cope very well with large alloca() + calls. Eventually the alloca() code will be replaced by calls to + xmalloc() and make_cleanups() allowing this restriction to either + be lifted or removed. */ +#ifndef MAX_REMOTE_PACKET_SIZE +#define MAX_REMOTE_PACKET_SIZE 16384 +#endif + /* NOTE: 16 is just chosen at random. */ +#ifndef MIN_REMOTE_PACKET_SIZE +#define MIN_REMOTE_PACKET_SIZE 16 +#endif + long what_they_get; + if (config->fixed_p) + { + if (config->size <= 0) + what_they_get = MAX_REMOTE_PACKET_SIZE; + else + what_they_get = config->size; + } + else + { + what_they_get = (rs->remote_packet_size); + /* Limit the packet to the size specified by the user. */ + if (config->size > 0 + && what_they_get > config->size) + what_they_get = config->size; + /* Limit it to the size of the targets ``g'' response. */ + if ((rs->actual_register_packet_size) > 0 + && what_they_get > (rs->actual_register_packet_size)) + what_they_get = (rs->actual_register_packet_size); + } + if (what_they_get > MAX_REMOTE_PACKET_SIZE) + what_they_get = MAX_REMOTE_PACKET_SIZE; + if (what_they_get < MIN_REMOTE_PACKET_SIZE) + what_they_get = MIN_REMOTE_PACKET_SIZE; + return what_they_get; +} - -/* - * Support for quasi-interactive control of device through GDB port. - * While we're waiting for an event to occur, chat with the running device. - */ -#define REMOTE_CHAT -#ifdef REMOTE_CHAT +/* Update the size of a read/write packet. If they user wants + something really big then do a sanity check. */ + +static void +set_memory_packet_size (char *args, struct memory_packet_config *config) +{ + int fixed_p = config->fixed_p; + long size = config->size; + if (args == NULL) + error ("Argument required (integer, `fixed' or `limited')."); + else if (strcmp (args, "hard") == 0 + || strcmp (args, "fixed") == 0) + fixed_p = 1; + else if (strcmp (args, "soft") == 0 + || strcmp (args, "limit") == 0) + fixed_p = 0; + else + { + char *end; + size = strtoul (args, &end, 0); + if (args == end) + error ("Invalid %s (bad syntax).", config->name); +#if 0 + /* Instead of explicitly capping the size of a packet to + MAX_REMOTE_PACKET_SIZE or dissallowing it, the user is + instead allowed to set the size to something arbitrarily + large. */ + if (size > MAX_REMOTE_PACKET_SIZE) + error ("Invalid %s (too large).", config->name); +#endif + } + /* Extra checks? */ + if (fixed_p && !config->fixed_p) + { + if (! query ("The target may not be able to correctly handle a %s\n" + "of %ld bytes. Change the packet size? ", + config->name, size)) + error ("Packet size not changed."); + } + /* Update the config. */ + config->fixed_p = fixed_p; + config->size = size; +} + +static void +show_memory_packet_size (struct memory_packet_config *config) +{ + printf_filtered ("The %s is %ld. ", config->name, config->size); + if (config->fixed_p) + printf_filtered ("Packets are fixed at %ld bytes.\n", + get_memory_packet_size (config)); + else + printf_filtered ("Packets are limited to %ld bytes.\n", + get_memory_packet_size (config)); +} + +static struct memory_packet_config memory_write_packet_config = +{ + "memory-write-packet-size", +}; + +static void +set_memory_write_packet_size (char *args, int from_tty) +{ + set_memory_packet_size (args, &memory_write_packet_config); +} -extern int quit_flag; +static void +show_memory_write_packet_size (char *args, int from_tty) +{ + show_memory_packet_size (&memory_write_packet_config); +} -static char tty_input[256]; -static int escape_count; -static int echo_check; -static int remote_chat = 0; +static long +get_memory_write_packet_size (void) +{ + return get_memory_packet_size (&memory_write_packet_config); +} -enum read_stat { - READ_MORE, - FATAL_ERROR, - ENTER_DEBUG +static struct memory_packet_config memory_read_packet_config = +{ + "memory-read-packet-size", }; -static enum read_stat -readtarget() +static void +set_memory_read_packet_size (char *args, int from_tty) { - int j; - int data; + set_memory_packet_size (args, &memory_read_packet_config); +} - /* Loop until the socket doesn't have any more data */ - while ((data = readchar(0)) >= 0) { +static void +show_memory_read_packet_size (char *args, int from_tty) +{ + show_memory_packet_size (&memory_read_packet_config); +} - /* Check for the escape sequence */ - if (data == '|') { - /* If this is the fourth escape, get out */ - if (++escape_count == 4) - return (ENTER_DEBUG); - continue; /* Not the fourth, continue */ +static long +get_memory_read_packet_size (void) +{ + struct remote_state *rs = get_remote_state (); + long size = get_memory_packet_size (&memory_read_packet_config); + /* FIXME: cagney/1999-11-07: Functions like getpkt() need to get an + extra buffer size argument before the memory read size can be + increased beyond (rs->remote_packet_size). */ + if (size > (rs->remote_packet_size)) + size = (rs->remote_packet_size); + return size; +} - } else { - /* - * Not an escape any more, Ensure any pending ones are flushed - */ - for (j = 1; j <= escape_count; j++) - putchar('|'); - escape_count = 0; - } + +/* Generic configuration support for packets the stub optionally + supports. Allows the user to specify the use of the packet as well + as allowing GDB to auto-detect support in the remote stub. */ - if (data == '\r') /* If this is a return character */ - continue; /* just supress it */ +enum packet_support + { + PACKET_SUPPORT_UNKNOWN = 0, + PACKET_ENABLE, + PACKET_DISABLE + }; - if (echo_check != -1) { /* If we are checking for an echo */ - /* If this might be an echo */ - if (tty_input[echo_check] == data) { - echo_check++; /* Note one more character match */ - continue; /* Go and loop */ - } else { +struct packet_config + { + char *name; + char *title; + enum cmd_auto_boolean detect; + enum packet_support support; + }; - if ((data == '\n') && (tty_input[echo_check] == '\r')) { - /* If this is the end of the line */ - echo_check = -1; /* No more echo supression */ - continue; /* Go and loop */ - } +/* Analyze a packet's return value and update the packet config + accordingly. */ - /* Not an echo, print out the data */ - for (j = 0; j < echo_check; j++) - putchar(tty_input[j]); +enum packet_result +{ + PACKET_ERROR, + PACKET_OK, + PACKET_UNKNOWN +}; - echo_check = -1;/* No more echo checking */ - } - } - putchar(data); /* Output the character */ +static void +update_packet_config (struct packet_config *config) +{ + switch (config->detect) + { + case CMD_AUTO_BOOLEAN_TRUE: + config->support = PACKET_ENABLE; + break; + case CMD_AUTO_BOOLEAN_FALSE: + config->support = PACKET_DISABLE; + break; + case CMD_AUTO_BOOLEAN_AUTO: + config->support = PACKET_SUPPORT_UNKNOWN; + break; } - return (READ_MORE); /* Indicate to read some more */ } -static enum read_stat -readtty() +static void +show_packet_config_cmd (struct packet_config *config) { - enum read_stat status; - int tty_bc; + char *support = "internal-error"; + switch (config->support) + { + case PACKET_ENABLE: + support = "enabled"; + break; + case PACKET_DISABLE: + support = "disabled"; + break; + case PACKET_SUPPORT_UNKNOWN: + support = "unknown"; + break; + } + switch (config->detect) + { + case CMD_AUTO_BOOLEAN_AUTO: + printf_filtered ("Support for remote protocol `%s' (%s) packet is auto-detected, currently %s.\n", + config->name, config->title, support); + break; + case CMD_AUTO_BOOLEAN_TRUE: + case CMD_AUTO_BOOLEAN_FALSE: + printf_filtered ("Support for remote protocol `%s' (%s) packet is currently %s.\n", + config->name, config->title, support); + break; + } +} - /* First, read a buffer full from the terminal */ - if ((tty_bc = read(fileno(stdin), tty_input, sizeof(tty_input) - 1)) < 0) { - perror_with_name("readtty: read failed"); - return (FATAL_ERROR); +static void +add_packet_config_cmd (struct packet_config *config, + char *name, + char *title, + void (*set_func) (char *args, int from_tty, + struct cmd_list_element * + c), + void (*show_func) (char *name, + int from_tty), + struct cmd_list_element **set_remote_list, + struct cmd_list_element **show_remote_list, + int legacy) +{ + struct cmd_list_element *set_cmd; + struct cmd_list_element *show_cmd; + char *set_doc; + char *show_doc; + char *cmd_name; + config->name = name; + config->title = title; + config->detect = CMD_AUTO_BOOLEAN_AUTO; + config->support = PACKET_SUPPORT_UNKNOWN; + xasprintf (&set_doc, "Set use of remote protocol `%s' (%s) packet", + name, title); + xasprintf (&show_doc, "Show current use of remote protocol `%s' (%s) packet", + name, title); + /* set/show TITLE-packet {auto,on,off} */ + xasprintf (&cmd_name, "%s-packet", title); + set_cmd = add_set_auto_boolean_cmd (cmd_name, class_obscure, + &config->detect, set_doc, + set_remote_list); + set_cmd_sfunc (set_cmd, set_func); + show_cmd = add_cmd (cmd_name, class_obscure, show_func, show_doc, + show_remote_list); + /* set/show remote NAME-packet {auto,on,off} -- legacy */ + if (legacy) + { + char *legacy_name; + xasprintf (&legacy_name, "%s-packet", name); + add_alias_cmd (legacy_name, cmd_name, class_obscure, 0, + set_remote_list); + add_alias_cmd (legacy_name, cmd_name, class_obscure, 0, + show_remote_list); } +} - /* Turn trailing newlines into returns */ - if (tty_input[tty_bc - 1] == '\n') - tty_input[tty_bc - 1] = '\r'; +static enum packet_result +packet_ok (const char *buf, struct packet_config *config) +{ + if (buf[0] != '\0') + { + /* The stub recognized the packet request. Check that the + operation succeeded. */ + switch (config->support) + { + case PACKET_SUPPORT_UNKNOWN: + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, + "Packet %s (%s) is supported\n", + config->name, config->title); + config->support = PACKET_ENABLE; + break; + case PACKET_DISABLE: + internal_error (__FILE__, __LINE__, + "packet_ok: attempt to use a disabled packet"); + break; + case PACKET_ENABLE: + break; + } + if (buf[0] == 'O' && buf[1] == 'K' && buf[2] == '\0') + /* "OK" - definitly OK. */ + return PACKET_OK; + if (buf[0] == 'E' + && isxdigit (buf[1]) && isxdigit (buf[2]) + && buf[3] == '\0') + /* "Enn" - definitly an error. */ + return PACKET_ERROR; + /* The packet may or may not be OK. Just assume it is */ + return PACKET_OK; + } + else + { + /* The stub does not support the packet. */ + switch (config->support) + { + case PACKET_ENABLE: + if (config->detect == CMD_AUTO_BOOLEAN_AUTO) + /* If the stub previously indicated that the packet was + supported then there is a protocol error.. */ + error ("Protocol error: %s (%s) conflicting enabled responses.", + config->name, config->title); + else + /* The user set it wrong. */ + error ("Enabled packet %s (%s) not recognized by stub", + config->name, config->title); + break; + case PACKET_SUPPORT_UNKNOWN: + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, + "Packet %s (%s) is NOT supported\n", + config->name, config->title); + config->support = PACKET_DISABLE; + break; + case PACKET_DISABLE: + break; + } + return PACKET_UNKNOWN; + } +} - if ((tty_input[0] == '~') && (tty_bc == 3)) - switch (tty_input[1]) { - case 'b': /* ~b\n = send break & gdb */ - SERIAL_SEND_BREAK (remote_desc); - /* fall through */ +/* Should we try the 'qSymbol' (target symbol lookup service) request? */ +static struct packet_config remote_protocol_qSymbol; - case 'c': /* ~c\n = return to gdb */ - return (ENTER_DEBUG); - } - - /* Make this a zero terminated string and write it out */ - tty_input[tty_bc] = '\0'; +static void +set_remote_protocol_qSymbol_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_qSymbol); +} - if (SERIAL_WRITE(remote_desc, tty_input, tty_bc)) { - perror_with_name("readtty: write failed"); - return (FATAL_ERROR); - } +static void +show_remote_protocol_qSymbol_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_qSymbol); +} - return (READ_MORE); +/* Should we try the 'e' (step over range) request? */ +static struct packet_config remote_protocol_e; + +static void +set_remote_protocol_e_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_e); } -static int -remote_talk() +static void +show_remote_protocol_e_packet_cmd (char *args, int from_tty) { - fd_set input; - int tablesize; - enum read_stat status; - int panic_flag = 0; - char buf[4]; + show_packet_config_cmd (&remote_protocol_e); +} + - escape_count = 0; - echo_check = -1; +/* Should we try the 'E' (step over range / w signal #) request? */ +static struct packet_config remote_protocol_E; - tablesize = getdtablesize(); +static void +set_remote_protocol_E_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_E); +} - for (;;) { +static void +show_remote_protocol_E_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_E); +} + - /* - * Check for anything from our socket - doesn't block. Note that this - * must be done *before* the select as there may be buffered I/O - * waiting to be processed. - */ - if ((status = readtarget()) != READ_MORE) - return (status); +/* Should we try the 'P' (set register) request? */ - fflush(stdout); /* Flush output before blocking */ +static struct packet_config remote_protocol_P; - /* Now block on more socket input or TTY input */ - FD_ZERO(&input); - FD_SET(fileno(stdin), &input); - FD_SET(remote_desc->fd, &input); +static void +set_remote_protocol_P_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_P); +} - status = select(tablesize, &input, 0, 0, 0); - if ((status < 0) && (errno != EINTR)) { - perror_with_name("remote_talk: select"); - return (FATAL_ERROR); - } +static void +show_remote_protocol_P_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_P); +} - /* Handle Control-C typed */ - if (quit_flag) { - if ((++panic_flag) == 3) { - printf("\nAre you repeating Control-C to terminate " - "the session? (y/n) [n] "); - fgets(buf, 3, stdin); - if (buf[0] == 'y') { - pop_target(); /* Clean up */ - error("Debugging terminated by user interrupt"); - } - panic_flag = 0; - } - quit_flag = 0; - SERIAL_WRITE(remote_desc, "\003", 1); - continue; - } +/* Should we try one of the 'Z' requests? */ - /* Handle terminal input */ - if (FD_ISSET(fileno(stdin), &input)) { - panic_flag = 0; - status = readtty(); - if (status != READ_MORE) - return (status); - echo_check = 0; - } +enum Z_packet_type +{ + Z_PACKET_SOFTWARE_BP, + Z_PACKET_HARDWARE_BP, + Z_PACKET_WRITE_WP, + Z_PACKET_READ_WP, + Z_PACKET_ACCESS_WP, + NR_Z_PACKET_TYPES +}; + +static struct packet_config remote_protocol_Z[NR_Z_PACKET_TYPES]; + +/* FIXME: Instead of having all these boiler plate functions, the + command callback should include a context argument. */ + +static void +set_remote_protocol_Z_software_bp_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP]); +} + +static void +show_remote_protocol_Z_software_bp_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP]); +} + +static void +set_remote_protocol_Z_hardware_bp_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_Z[Z_PACKET_HARDWARE_BP]); +} + +static void +show_remote_protocol_Z_hardware_bp_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_HARDWARE_BP]); +} + +static void +set_remote_protocol_Z_write_wp_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_Z[Z_PACKET_WRITE_WP]); +} + +static void +show_remote_protocol_Z_write_wp_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_WRITE_WP]); +} + +static void +set_remote_protocol_Z_read_wp_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_Z[Z_PACKET_READ_WP]); +} + +static void +show_remote_protocol_Z_read_wp_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_READ_WP]); +} + +static void +set_remote_protocol_Z_access_wp_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_Z[Z_PACKET_ACCESS_WP]); +} + +static void +show_remote_protocol_Z_access_wp_packet_cmd (char *args, int from_tty) +{ + show_packet_config_cmd (&remote_protocol_Z[Z_PACKET_ACCESS_WP]); +} + +/* For compatibility with older distributions. Provide a ``set remote + Z-packet ...'' command that updates all the Z packet types. */ + +static enum cmd_auto_boolean remote_Z_packet_detect; + +static void +set_remote_protocol_Z_packet_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + int i; + for (i = 0; i < NR_Z_PACKET_TYPES; i++) + { + remote_protocol_Z[i].detect = remote_Z_packet_detect; + update_packet_config (&remote_protocol_Z[i]); + } +} + +static void +show_remote_protocol_Z_packet_cmd (char *args, int from_tty) +{ + int i; + for (i = 0; i < NR_Z_PACKET_TYPES; i++) + { + show_packet_config_cmd (&remote_protocol_Z[i]); } } -#endif /* REMOTE_CHAT */ +/* Should we try the 'X' (remote binary download) packet? + + This variable (available to the user via "set remote X-packet") + dictates whether downloads are sent in binary (via the 'X' packet). + We assume that the stub can, and attempt to do it. This will be + cleared if the stub does not understand it. This switch is still + needed, though in cases when the packet is supported in the stub, + but the connection does not allow it (i.e., 7-bit serial connection + only). */ + +static struct packet_config remote_protocol_binary_download; + +/* Should we try the 'ThreadInfo' query packet? + + This variable (NOT available to the user: auto-detect only!) + determines whether GDB will use the new, simpler "ThreadInfo" + query or the older, more complex syntax for thread queries. + This is an auto-detect variable (set to true at each connect, + and set to false when the target fails to recognize it). */ + +static int use_threadinfo_query; +static int use_threadextra_query; + +static void +set_remote_protocol_binary_download_cmd (char *args, + int from_tty, + struct cmd_list_element *c) +{ + update_packet_config (&remote_protocol_binary_download); +} + +static void +show_remote_protocol_binary_download_cmd (char *args, + int from_tty) +{ + show_packet_config_cmd (&remote_protocol_binary_download); +} + + +/* Tokens for use by the asynchronous signal handlers for SIGINT */ +PTR sigint_remote_twice_token; +PTR sigint_remote_token; + +/* These are pointers to hook functions that may be set in order to + modify resume/wait behavior for a particular architecture. */ + +void (*target_resume_hook) (void); +void (*target_wait_loop_hook) (void); + + /* These are the threads which we last sent to the remote system. -1 for all or -2 for not sent yet. */ static int general_thread; -static int cont_thread; +static int continue_thread; /* Call this function as a result of 1) A halt indication (T packet) containing a thread id @@ -698,32 +993,29 @@ static int cont_thread; */ static void -record_currthread (currthread) - int currthread; +record_currthread (int currthread) { -#if 0 /* target_wait must not modify inferior_pid! */ - inferior_pid = currthread; -#endif general_thread = currthread; -#if 0 /* setting cont_thread has a different meaning - from having the target report its thread id. */ - cont_thread = currthread; -#endif + /* If this is a new thread, add it to GDB's thread list. If we leave it up to WFI to do this, bad things will happen. */ - if (!in_thread_list (currthread)) - add_thread (currthread); + if (!in_thread_list (pid_to_ptid (currthread))) + { + add_thread (pid_to_ptid (currthread)); + ui_out_text (uiout, "[New "); + ui_out_text (uiout, target_pid_to_str (pid_to_ptid (currthread))); + ui_out_text (uiout, "]\n"); + } } #define MAGIC_NULL_PID 42000 static void -set_thread (th, gen) - int th; - int gen; +set_thread (int th, int gen) { - char buf[PBUFSIZ]; - int state = gen ? general_thread : cont_thread; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + int state = gen ? general_thread : continue_thread; if (state == th) return; @@ -740,28 +1032,27 @@ set_thread (th, gen) else sprintf (&buf[2], "%x", th); putpkt (buf); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); if (gen) general_thread = th; else - cont_thread = th; + continue_thread = th; } /* Return nonzero if the thread TH is still alive on the remote system. */ static int -remote_thread_alive (th) - int th; +remote_thread_alive (ptid_t ptid) { - char buf[PBUFSIZ]; + int tid = PIDGET (ptid); + char buf[16]; - buf[0] = 'T'; - if (th < 0) - sprintf (&buf[1], "-%08x", -th); + if (tid < 0) + sprintf (buf, "T-%08x", -tid); else - sprintf (&buf[1], "%08x", th); + sprintf (buf, "T%08x", tid); putpkt (buf); - getpkt (buf, 0); + getpkt (buf, sizeof (buf), 0); return (buf[0] == 'O' && buf[1] == 'K'); } @@ -771,16 +1062,117 @@ remote_thread_alive (th) remote protocol in general. There is a matching unit test module in libstub. */ +#define OPAQUETHREADBYTES 8 + +/* a 64 bit opaque identifier */ +typedef unsigned char threadref[OPAQUETHREADBYTES]; + +/* WARNING: This threadref data structure comes from the remote O.S., libstub + protocol encoding, and remote.c. it is not particularly changable */ + +/* Right now, the internal structure is int. We want it to be bigger. + Plan to fix this. + */ + +typedef int gdb_threadref; /* internal GDB thread reference */ + +/* gdb_ext_thread_info is an internal GDB data structure which is + equivalint to the reply of the remote threadinfo packet */ + +struct gdb_ext_thread_info + { + threadref threadid; /* External form of thread reference */ + int active; /* Has state interesting to GDB? , regs, stack */ + char display[256]; /* Brief state display, name, blocked/syspended */ + char shortname[32]; /* To be used to name threads */ + char more_display[256]; /* Long info, statistics, queue depth, whatever */ + }; + +/* The volume of remote transfers can be limited by submitting + a mask containing bits specifying the desired information. + Use a union of these values as the 'selection' parameter to + get_thread_info. FIXME: Make these TAG names more thread specific. + */ + +#define TAG_THREADID 1 +#define TAG_EXISTS 2 +#define TAG_DISPLAY 4 +#define TAG_THREADNAME 8 +#define TAG_MOREDISPLAY 16 + #define BUF_THREAD_ID_SIZE (OPAQUETHREADBYTES*2) +char *unpack_varlen_hex (char *buff, int *result); + +static char *unpack_nibble (char *buf, int *val); + +static char *pack_nibble (char *buf, int nibble); + +static char *pack_hex_byte (char *pkt, int /*unsigned char */ byte); + +static char *unpack_byte (char *buf, int *value); + +static char *pack_int (char *buf, int value); + +static char *unpack_int (char *buf, int *value); + +static char *unpack_string (char *src, char *dest, int length); + +static char *pack_threadid (char *pkt, threadref * id); + +static char *unpack_threadid (char *inbuf, threadref * id); + +void int_to_threadref (threadref * id, int value); + +static int threadref_to_int (threadref * ref); + +static void copy_threadref (threadref * dest, threadref * src); + +static int threadmatch (threadref * dest, threadref * src); + +static char *pack_threadinfo_request (char *pkt, int mode, threadref * id); + +static int remote_unpack_thread_info_response (char *pkt, + threadref * expectedref, + struct gdb_ext_thread_info + *info); + + +static int remote_get_threadinfo (threadref * threadid, int fieldset, /*TAG mask */ + struct gdb_ext_thread_info *info); + +static int adapt_remote_get_threadinfo (gdb_threadref * ref, + int selection, + struct gdb_ext_thread_info *info); + +static char *pack_threadlist_request (char *pkt, int startflag, + int threadcount, + threadref * nextthread); + +static int parse_threadlist_response (char *pkt, + int result_limit, + threadref * original_echo, + threadref * resultlist, int *doneflag); + +static int remote_get_threadlist (int startflag, + threadref * nextthread, + int result_limit, + int *done, + int *result_count, threadref * threadlist); + +typedef int (*rmt_thread_action) (threadref * ref, void *context); + +static int remote_threadlist_iterator (rmt_thread_action stepfunction, + void *context, int looplimit); + +static int remote_newthread_step (threadref * ref, void *context); + /* encode 64 bits in 16 chars of hex */ static const char hexchars[] = "0123456789abcdef"; static int -ishex (ch, val) - int ch; - int *val; +ishex (int ch, int *val) { if ((ch >= 'a') && (ch <= 'f')) { @@ -801,8 +1193,7 @@ ishex (ch, val) } static int -stubhex (ch) - int ch; +stubhex (int ch) { if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; @@ -814,9 +1205,7 @@ stubhex (ch) } static int -stub_unpack_int (buff, fieldlength) - char *buff; - int fieldlength; +stub_unpack_int (char *buff, int fieldlength) { int nibble; int retval = 0; @@ -833,9 +1222,8 @@ stub_unpack_int (buff, fieldlength) } char * -unpack_varlen_hex (buff, result) - char *buff; /* packet to parse */ - int *result; +unpack_varlen_hex (char *buff, /* packet to parse */ + int *result) { int nibble; int retval = 0; @@ -851,27 +1239,21 @@ unpack_varlen_hex (buff, result) } static char * -unpack_nibble (buf, val) - char *buf; - int *val; +unpack_nibble (char *buf, int *val) { ishex (*buf++, val); return buf; } static char * -pack_nibble (buf, nibble) - char *buf; - int nibble; +pack_nibble (char *buf, int nibble) { *buf++ = hexchars[(nibble & 0x0f)]; return buf; } static char * -pack_hex_byte (pkt, byte) - char *pkt; - int byte; +pack_hex_byte (char *pkt, int byte) { *pkt++ = hexchars[(byte >> 4) & 0xf]; *pkt++ = hexchars[(byte & 0xf)]; @@ -879,18 +1261,14 @@ pack_hex_byte (pkt, byte) } static char * -unpack_byte (buf, value) - char *buf; - int *value; +unpack_byte (char *buf, int *value) { *value = stub_unpack_int (buf, 2); return buf + 2; } static char * -pack_int (buf, value) - char *buf; - int value; +pack_int (char *buf, int value) { buf = pack_hex_byte (buf, (value >> 24) & 0xff); buf = pack_hex_byte (buf, (value >> 16) & 0xff); @@ -900,21 +1278,17 @@ pack_int (buf, value) } static char * -unpack_int (buf, value) - char *buf; - int *value; +unpack_int (char *buf, int *value) { *value = stub_unpack_int (buf, 8); return buf + 8; } -#if 0 /* currently unused, uncomment when needed */ -static char *pack_string PARAMS ((char *pkt, char *string)); +#if 0 /* currently unused, uncomment when needed */ +static char *pack_string (char *pkt, char *string); static char * -pack_string (pkt, string) - char *pkt; - char *string; +pack_string (char *pkt, char *string) { char ch; int len; @@ -935,10 +1309,7 @@ pack_string (pkt, string) #endif /* 0 (unused) */ static char * -unpack_string (src, dest, length) - char *src; - char *dest; - int length; +unpack_string (char *src, char *dest, int length) { while (length--) *dest++ = *src++; @@ -947,9 +1318,7 @@ unpack_string (src, dest, length) } static char * -pack_threadid (pkt, id) - char *pkt; - threadref *id; +pack_threadid (char *pkt, threadref *id) { char *limit; unsigned char *altid; @@ -963,9 +1332,7 @@ pack_threadid (pkt, id) static char * -unpack_threadid (inbuf, id) - char *inbuf; - threadref *id; +unpack_threadid (char *inbuf, threadref *id) { char *altref; char *limit = inbuf + BUF_THREAD_ID_SIZE; @@ -988,9 +1355,7 @@ unpack_threadid (inbuf, id) function. */ void -int_to_threadref (id, value) - threadref *id; - int value; +int_to_threadref (threadref *id, int value) { unsigned char *scan; @@ -1007,8 +1372,7 @@ int_to_threadref (id, value) } static int -threadref_to_int (ref) - threadref *ref; +threadref_to_int (threadref *ref) { int i, value = 0; unsigned char *scan; @@ -1022,9 +1386,7 @@ threadref_to_int (ref) } static void -copy_threadref (dest, src) - threadref *dest; - threadref *src; +copy_threadref (threadref *dest, threadref *src) { int i; unsigned char *csrc, *cdest; @@ -1037,9 +1399,7 @@ copy_threadref (dest, src) } static int -threadmatch (dest, src) - threadref *dest; - threadref *src; +threadmatch (threadref *dest, threadref *src) { /* things are broken right now, so just assume we got a match */ #if 0 @@ -1057,20 +1417,17 @@ threadmatch (dest, src) } /* - threadid:1, # always request threadid - context_exists:2, - display:4, - unique_name:8, - more_display:16 -*/ + threadid:1, # always request threadid + context_exists:2, + display:4, + unique_name:8, + more_display:16 + */ /* Encoding: 'Q':8,'P':8,mask:32,threadid:64 */ static char * -pack_threadinfo_request (pkt, mode, id) - char *pkt; - int mode; - threadref *id; +pack_threadinfo_request (char *pkt, int mode, threadref *id) { *pkt++ = 'q'; /* Info Query */ *pkt++ = 'P'; /* process or thread info */ @@ -1084,24 +1441,23 @@ pack_threadinfo_request (pkt, mode, id) /* Tagging the fields allows us to request specific fields and to add more fields as time goes by */ -#define TAG_THREADID 1 /* Echo the thread identifier */ -#define TAG_EXISTS 2 /* Is this process defined enough to - fetch registers and its stack */ -#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */ -#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */ -#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about - the process*/ +#define TAG_THREADID 1 /* Echo the thread identifier */ +#define TAG_EXISTS 2 /* Is this process defined enough to + fetch registers and its stack */ +#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */ +#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */ +#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about + the process */ static int -remote_unpack_thread_info_response (pkt, expectedref, info) - char *pkt; - threadref *expectedref; - struct gdb_ext_thread_info *info; +remote_unpack_thread_info_response (char *pkt, threadref *expectedref, + struct gdb_ext_thread_info *info) { + struct remote_state *rs = get_remote_state (); int mask, length; unsigned int tag; threadref ref; - char *limit = pkt + PBUFSIZ; /* plausable parsing limit */ + char *limit = pkt + (rs->remote_packet_size); /* plausable parsing limit */ int retval = 1; /* info->threadid = 0; FIXME: implement zero_threadref */ @@ -1125,7 +1481,7 @@ remote_unpack_thread_info_response (pkt, expectedref, info) /* Loop on tagged fields , try to bail if somthing goes wrong */ - while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */ + while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */ { pkt = unpack_int (pkt, &tag); /* tag */ pkt = unpack_byte (pkt, &length); /* length */ @@ -1185,17 +1541,16 @@ remote_unpack_thread_info_response (pkt, expectedref, info) } static int -remote_get_threadinfo (threadid, fieldset, info) - threadref *threadid; - int fieldset; /* TAG mask */ - struct gdb_ext_thread_info *info; +remote_get_threadinfo (threadref *threadid, int fieldset, /* TAG mask */ + struct gdb_ext_thread_info *info) { + struct remote_state *rs = get_remote_state (); int result; - char threadinfo_pkt[PBUFSIZ]; + char *threadinfo_pkt = alloca (rs->remote_packet_size); pack_threadinfo_request (threadinfo_pkt, fieldset, threadid); putpkt (threadinfo_pkt); - getpkt (threadinfo_pkt, 0); + getpkt (threadinfo_pkt, (rs->remote_packet_size), 0); result = remote_unpack_thread_info_response (threadinfo_pkt + 2, threadid, info); return result; @@ -1205,10 +1560,8 @@ remote_get_threadinfo (threadid, fieldset, info) representation of a threadid. */ static int -adapt_remote_get_threadinfo (ref, selection, info) - gdb_threadref *ref; - int selection; - struct gdb_ext_thread_info *info; +adapt_remote_get_threadinfo (gdb_threadref *ref, int selection, + struct gdb_ext_thread_info *info) { threadref lclref; @@ -1219,11 +1572,8 @@ adapt_remote_get_threadinfo (ref, selection, info) /* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */ static char * -pack_threadlist_request (pkt, startflag, threadcount, nextthread) - char *pkt; - int startflag; - int threadcount; - threadref *nextthread; +pack_threadlist_request (char *pkt, int startflag, int threadcount, + threadref *nextthread) { *pkt++ = 'q'; /* info query packet */ *pkt++ = 'L'; /* Process LIST or threadLIST request */ @@ -1237,20 +1587,17 @@ pack_threadlist_request (pkt, startflag, threadcount, nextthread) /* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */ static int -parse_threadlist_response (pkt, result_limit, original_echo, resultlist, - doneflag) - char *pkt; - int result_limit; - threadref *original_echo; - threadref *resultlist; - int *doneflag; +parse_threadlist_response (char *pkt, int result_limit, + threadref *original_echo, threadref *resultlist, + int *doneflag) { + struct remote_state *rs = get_remote_state (); char *limit; int count, resultcount, done; resultcount = 0; /* Assume the 'q' and 'M chars have been stripped. */ - limit = pkt + (PBUFSIZ - BUF_THREAD_ID_SIZE); /* done parse past here */ + limit = pkt + ((rs->remote_packet_size) - BUF_THREAD_ID_SIZE); /* done parse past here */ pkt = unpack_byte (pkt, &count); /* count field */ pkt = unpack_nibble (pkt, &done); /* The first threadid is the argument threadid. */ @@ -1267,29 +1614,23 @@ parse_threadlist_response (pkt, result_limit, original_echo, resultlist, } static int -remote_get_threadlist (startflag, nextthread, result_limit, - done, result_count, threadlist) - int startflag; - threadref *nextthread; - int result_limit; - int *done; - int *result_count; - threadref *threadlist; - +remote_get_threadlist (int startflag, threadref *nextthread, int result_limit, + int *done, int *result_count, threadref *threadlist) { + struct remote_state *rs = get_remote_state (); static threadref echo_nextthread; - char threadlist_packet[PBUFSIZ]; - char t_response[PBUFSIZ]; + char *threadlist_packet = alloca (rs->remote_packet_size); + char *t_response = alloca (rs->remote_packet_size); int result = 1; /* Trancate result limit to be smaller than the packet size */ - if ((((result_limit + 1) * BUF_THREAD_ID_SIZE) + 10) >= PBUFSIZ) - result_limit = (PBUFSIZ / BUF_THREAD_ID_SIZE) - 2; + if ((((result_limit + 1) * BUF_THREAD_ID_SIZE) + 10) >= (rs->remote_packet_size)) + result_limit = ((rs->remote_packet_size) / BUF_THREAD_ID_SIZE) - 2; pack_threadlist_request (threadlist_packet, startflag, result_limit, nextthread); putpkt (threadlist_packet); - getpkt (t_response, 0); + getpkt (t_response, (rs->remote_packet_size), 0); *result_count = parse_threadlist_response (t_response + 2, result_limit, &echo_nextthread, @@ -1340,10 +1681,8 @@ remote_get_threadlist (startflag, nextthread, result_limit, #define MAXTHREADLISTRESULTS 32 static int -remote_threadlist_iterator (stepfunction, context, looplimit) - rmt_thread_action stepfunction; - void *context; - int looplimit; +remote_threadlist_iterator (rmt_thread_action stepfunction, void *context, + int looplimit) { int done, i, result_count; int startflag = 1; @@ -1381,63 +1720,169 @@ remote_threadlist_iterator (stepfunction, context, looplimit) } static int -remote_newthread_step (ref, context) - threadref *ref; - void *context; +remote_newthread_step (threadref *ref, void *context) { - int pid; + ptid_t ptid; + + ptid = pid_to_ptid (threadref_to_int (ref)); - pid = threadref_to_int (ref); - if (!in_thread_list (pid)) - add_thread (pid); + if (!in_thread_list (ptid)) + add_thread (ptid); return 1; /* continue iterator */ } #define CRAZY_MAX_THREADS 1000 -static int -remote_current_thread (oldpid) - int oldpid; +static ptid_t +remote_current_thread (ptid_t oldpid) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); putpkt ("qC"); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); if (buf[0] == 'Q' && buf[1] == 'C') - return strtol (&buf[2], NULL, 16); + return pid_to_ptid (strtol (&buf[2], NULL, 16)); else return oldpid; } -int -remote_find_new_threads () -{ - int ret; +/* Find new threads for info threads command. + * Original version, using John Metzler's thread protocol. + */ - ret = remote_threadlist_iterator (remote_newthread_step, 0, - CRAZY_MAX_THREADS); - if (inferior_pid == MAGIC_NULL_PID) /* ack ack ack */ - inferior_pid = remote_current_thread (inferior_pid); - return ret; +static void +remote_find_new_threads (void) +{ + remote_threadlist_iterator (remote_newthread_step, 0, + CRAZY_MAX_THREADS); + if (PIDGET (inferior_ptid) == MAGIC_NULL_PID) /* ack ack ack */ + inferior_ptid = remote_current_thread (inferior_ptid); } -/* Initialize the thread vector which is used by threads.c */ -/* The thread stub is a package, it has an initializer */ +/* + * Find all threads for info threads command. + * Uses new thread protocol contributed by Cisco. + * Falls back and attempts to use the older method (above) + * if the target doesn't respond to the new method. + */ static void -init_remote_threads () +remote_threads_info (void) { - remote_thread_vec.find_new_threads = remote_find_new_threads; - remote_thread_vec.get_thread_info = adapt_remote_get_threadinfo; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + char *bufp; + int tid; + + if (remote_desc == 0) /* paranoia */ + error ("Command can only be used when connected to the remote target."); + + if (use_threadinfo_query) + { + putpkt ("qfThreadInfo"); + bufp = buf; + getpkt (bufp, (rs->remote_packet_size), 0); + if (bufp[0] != '\0') /* q packet recognized */ + { + while (*bufp++ == 'm') /* reply contains one or more TID */ + { + do + { + tid = strtol (bufp, &bufp, 16); + if (tid != 0 && !in_thread_list (pid_to_ptid (tid))) + add_thread (pid_to_ptid (tid)); + } + while (*bufp++ == ','); /* comma-separated list */ + putpkt ("qsThreadInfo"); + bufp = buf; + getpkt (bufp, (rs->remote_packet_size), 0); + } + return; /* done */ + } + } + + /* Else fall back to old method based on jmetzler protocol. */ + use_threadinfo_query = 0; + remote_find_new_threads (); + return; +} + +/* + * Collect a descriptive string about the given thread. + * The target may say anything it wants to about the thread + * (typically info about its blocked / runnable state, name, etc.). + * This string will appear in the info threads display. + * + * Optional: targets are not required to implement this function. + */ + +static char * +remote_threads_extra_info (struct thread_info *tp) +{ + struct remote_state *rs = get_remote_state (); + int result; + int set; + threadref id; + struct gdb_ext_thread_info threadinfo; + static char display_buf[100]; /* arbitrary... */ + char *bufp = alloca (rs->remote_packet_size); + int n = 0; /* position in display_buf */ + + if (remote_desc == 0) /* paranoia */ + internal_error (__FILE__, __LINE__, + "remote_threads_extra_info"); + + if (use_threadextra_query) + { + sprintf (bufp, "qThreadExtraInfo,%x", PIDGET (tp->ptid)); + putpkt (bufp); + getpkt (bufp, (rs->remote_packet_size), 0); + if (bufp[0] != 0) + { + n = min (strlen (bufp) / 2, sizeof (display_buf)); + result = hex2bin (bufp, display_buf, n); + display_buf [result] = '\0'; + return display_buf; + } + } + + /* If the above query fails, fall back to the old method. */ + use_threadextra_query = 0; + set = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME + | TAG_MOREDISPLAY | TAG_DISPLAY; + int_to_threadref (&id, PIDGET (tp->ptid)); + if (remote_get_threadinfo (&id, set, &threadinfo)) + if (threadinfo.active) + { + if (*threadinfo.shortname) + n += sprintf(&display_buf[0], " Name: %s,", threadinfo.shortname); + if (*threadinfo.display) + n += sprintf(&display_buf[n], " State: %s,", threadinfo.display); + if (*threadinfo.more_display) + n += sprintf(&display_buf[n], " Priority: %s", + threadinfo.more_display); + + if (n > 0) + { + /* for purely cosmetic reasons, clear up trailing commas */ + if (',' == display_buf[n-1]) + display_buf[n-1] = ' '; + return display_buf; + } + } + return NULL; } + /* Restart the remote side; this is an extended protocol operation. */ static void -extended_remote_restart () +extended_remote_restart (void) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); /* Send the restart command; for reasons I don't understand the remote side really expects a number after the "R". */ @@ -1448,39 +1893,35 @@ extended_remote_restart () /* Now query for status so this looks just like we restarted gdbserver from scratch. */ putpkt ("?"); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); } /* Clean up connection to a remote debugger. */ /* ARGSUSED */ static void -remote_close (quitting) - int quitting; +remote_close (int quitting) { if (remote_desc) - SERIAL_CLOSE (remote_desc); + serial_close (remote_desc); remote_desc = NULL; } /* Query the remote side for the text, data and bss offsets. */ static void -get_offsets () +get_offsets (void) { - char buf[PBUFSIZ], *ptr; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + char *ptr; int lose; CORE_ADDR text_addr, data_addr, bss_addr; struct section_offsets *offs; -#ifdef REMOTE_CHAT - if (remote_chat) - (void) remote_talk(); -#endif /* REMOTE_CHAT */ - putpkt ("qOffsets"); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); if (buf[0] == '\000') return; /* Return silently. Stub doesn't support @@ -1533,113 +1974,387 @@ get_offsets () if (symfile_objfile == NULL) return; - offs = (struct section_offsets *) alloca (sizeof (struct section_offsets) - + symfile_objfile->num_sections - * sizeof (offs->offsets)); - memcpy (offs, symfile_objfile->section_offsets, - sizeof (struct section_offsets) - + symfile_objfile->num_sections - * sizeof (offs->offsets)); + offs = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS); + memcpy (offs, symfile_objfile->section_offsets, SIZEOF_SECTION_OFFSETS); - ANOFFSET (offs, SECT_OFF_TEXT) = text_addr; + offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_addr; /* This is a temporary kludge to force data and bss to use the same offsets because that's what nlmconv does now. The real solution requires changes to the stub and remote.c that I don't have time to do right now. */ - ANOFFSET (offs, SECT_OFF_DATA) = data_addr; - ANOFFSET (offs, SECT_OFF_BSS) = data_addr; + offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_addr; + offs->offsets[SECT_OFF_BSS (symfile_objfile)] = data_addr; objfile_relocate (symfile_objfile, offs); } +/* + * Cisco version of section offsets: + * + * Instead of having GDB query the target for the section offsets, + * Cisco lets the target volunteer the information! It's also in + * a different format, so here are the functions that will decode + * a section offset packet from a Cisco target. + */ + +/* + * Function: remote_cisco_section_offsets + * + * Returns: zero for success, non-zero for failure + */ + +static int +remote_cisco_section_offsets (bfd_vma text_addr, + bfd_vma data_addr, + bfd_vma bss_addr, + bfd_signed_vma *text_offs, + bfd_signed_vma *data_offs, + bfd_signed_vma *bss_offs) +{ + bfd_vma text_base, data_base, bss_base; + struct minimal_symbol *start; + asection *sect; + bfd *abfd; + int len; + + if (symfile_objfile == NULL) + return -1; /* no can do nothin' */ + + start = lookup_minimal_symbol ("_start", NULL, NULL); + if (start == NULL) + return -1; /* Can't find "_start" symbol */ + + data_base = bss_base = 0; + text_base = SYMBOL_VALUE_ADDRESS (start); + + abfd = symfile_objfile->obfd; + for (sect = abfd->sections; + sect != 0; + sect = sect->next) + { + const char *p = bfd_get_section_name (abfd, sect); + len = strlen (p); + if (strcmp (p + len - 4, "data") == 0) /* ends in "data" */ + if (data_base == 0 || + data_base > bfd_get_section_vma (abfd, sect)) + data_base = bfd_get_section_vma (abfd, sect); + if (strcmp (p + len - 3, "bss") == 0) /* ends in "bss" */ + if (bss_base == 0 || + bss_base > bfd_get_section_vma (abfd, sect)) + bss_base = bfd_get_section_vma (abfd, sect); + } + *text_offs = text_addr - text_base; + *data_offs = data_addr - data_base; + *bss_offs = bss_addr - bss_base; + if (remote_debug) + { + char tmp[128]; + + sprintf (tmp, "VMA: text = 0x"); + sprintf_vma (tmp + strlen (tmp), text_addr); + sprintf (tmp + strlen (tmp), " data = 0x"); + sprintf_vma (tmp + strlen (tmp), data_addr); + sprintf (tmp + strlen (tmp), " bss = 0x"); + sprintf_vma (tmp + strlen (tmp), bss_addr); + fprintf_filtered (gdb_stdlog, tmp); + fprintf_filtered (gdb_stdlog, + "Reloc offset: text = 0x%s data = 0x%s bss = 0x%s\n", + paddr_nz (*text_offs), + paddr_nz (*data_offs), + paddr_nz (*bss_offs)); + } + + return 0; +} + +/* + * Function: remote_cisco_objfile_relocate + * + * Relocate the symbol file for a remote target. + */ + +void +remote_cisco_objfile_relocate (bfd_signed_vma text_off, bfd_signed_vma data_off, + bfd_signed_vma bss_off) +{ + struct section_offsets *offs; + + if (text_off != 0 || data_off != 0 || bss_off != 0) + { + /* FIXME: This code assumes gdb-stabs.h is being used; it's + broken for xcoff, dwarf, sdb-coff, etc. But there is no + simple canonical representation for this stuff. */ + + offs = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS); + memcpy (offs, symfile_objfile->section_offsets, SIZEOF_SECTION_OFFSETS); + + offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_off; + offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_off; + offs->offsets[SECT_OFF_BSS (symfile_objfile)] = bss_off; + + /* First call the standard objfile_relocate. */ + objfile_relocate (symfile_objfile, offs); + + /* Now we need to fix up the section entries already attached to + the exec target. These entries will control memory transfers + from the exec file. */ + + exec_set_section_offsets (text_off, data_off, bss_off); + } +} + /* Stub for catch_errors. */ static int -remote_start_remote (dummy) - PTR dummy; +remote_start_remote_dummy (void *dummy) { - immediate_quit = 1; /* Allow user to interrupt it */ + start_remote (); /* Initialize gdb process mechanisms */ + return 1; +} + +static int +remote_start_remote (PTR dummy) +{ + immediate_quit++; /* Allow user to interrupt it */ /* Ack any packet which the remote side has already sent. */ - SERIAL_WRITE (remote_desc, "+", 1); + serial_write (remote_desc, "+", 1); /* Let the stub know that we want it to return the thread. */ set_thread (-1, 0); - inferior_pid = remote_current_thread (inferior_pid); + inferior_ptid = remote_current_thread (inferior_ptid); get_offsets (); /* Get text, data & bss offsets */ putpkt ("?"); /* initiate a query from remote machine */ - immediate_quit = 0; + immediate_quit--; - start_remote (); /* Initialize gdb process mechanisms */ - return 1; + return remote_start_remote_dummy (dummy); } /* Open a connection to a remote debugger. NAME is the filename used for communication. */ static void -remote_open (name, from_tty) - char *name; - int from_tty; +remote_open (char *name, int from_tty) { remote_open_1 (name, from_tty, &remote_ops, 0); } +/* Just like remote_open, but with asynchronous support. */ +static void +remote_async_open (char *name, int from_tty) +{ + remote_async_open_1 (name, from_tty, &remote_async_ops, 0); +} + /* Open a connection to a remote debugger using the extended remote gdb protocol. NAME is the filename used for communication. */ static void -extended_remote_open (name, from_tty) - char *name; - int from_tty; +extended_remote_open (char *name, int from_tty) { - remote_open_1 (name, from_tty, &extended_remote_ops, 1/*extended_p*/); + remote_open_1 (name, from_tty, &extended_remote_ops, 1 /*extended_p */ ); +} + +/* Just like extended_remote_open, but with asynchronous support. */ +static void +extended_remote_async_open (char *name, int from_tty) +{ + remote_async_open_1 (name, from_tty, &extended_async_remote_ops, 1 /*extended_p */ ); } /* Generic code for opening a connection to a remote target. */ -static DCACHE *remote_dcache; +static void +init_all_packet_configs (void) +{ + int i; + update_packet_config (&remote_protocol_e); + update_packet_config (&remote_protocol_E); + update_packet_config (&remote_protocol_P); + update_packet_config (&remote_protocol_qSymbol); + for (i = 0; i < NR_Z_PACKET_TYPES; i++) + update_packet_config (&remote_protocol_Z[i]); + /* Force remote_write_bytes to check whether target supports binary + downloading. */ + update_packet_config (&remote_protocol_binary_download); +} + +/* Symbol look-up. */ + +static void +remote_check_symbols (struct objfile *objfile) +{ + struct remote_state *rs = get_remote_state (); + char *msg, *reply, *tmp; + struct minimal_symbol *sym; + int end; + + if (remote_protocol_qSymbol.support == PACKET_DISABLE) + return; + + msg = alloca (rs->remote_packet_size); + reply = alloca (rs->remote_packet_size); + + /* Invite target to request symbol lookups. */ + + putpkt ("qSymbol::"); + getpkt (reply, (rs->remote_packet_size), 0); + packet_ok (reply, &remote_protocol_qSymbol); + + while (strncmp (reply, "qSymbol:", 8) == 0) + { + tmp = &reply[8]; + end = hex2bin (tmp, msg, strlen (tmp) / 2); + msg[end] = '\0'; + sym = lookup_minimal_symbol (msg, NULL, NULL); + if (sym == NULL) + sprintf (msg, "qSymbol::%s", &reply[8]); + else + sprintf (msg, "qSymbol:%s:%s", + paddr_nz (SYMBOL_VALUE_ADDRESS (sym)), + &reply[8]); + putpkt (msg); + getpkt (reply, (rs->remote_packet_size), 0); + } +} static void -remote_open_1 (name, from_tty, target, extended_p) - char *name; - int from_tty; - struct target_ops *target; - int extended_p; +remote_open_1 (char *name, int from_tty, struct target_ops *target, + int extended_p) { + struct remote_state *rs = get_remote_state (); if (name == 0) - error ("To open a remote debug connection, you need to specify what\n\ -serial device is attached to the remote system (e.g. /dev/ttya)."); + error ("To open a remote debug connection, you need to specify what\n" + "serial device is attached to the remote system\n" + "(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.)."); + + /* See FIXME above */ + wait_forever_enabled_p = 1; target_preopen (from_tty); unpush_target (target); - remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes); - - remote_desc = SERIAL_OPEN (name); + remote_desc = serial_open (name); if (!remote_desc) perror_with_name (name); if (baud_rate != -1) { - if (SERIAL_SETBAUDRATE (remote_desc, baud_rate)) + if (serial_setbaudrate (remote_desc, baud_rate)) { - SERIAL_CLOSE (remote_desc); + serial_close (remote_desc); perror_with_name (name); } } + serial_raw (remote_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + serial_flush_input (remote_desc); + + if (from_tty) + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } + push_target (target); /* Switch to using remote target now */ + + init_all_packet_configs (); + + general_thread = -2; + continue_thread = -2; + + /* Probe for ability to use "ThreadInfo" query, as required. */ + use_threadinfo_query = 1; + use_threadextra_query = 1; + + /* Without this, some commands which require an active target (such + as kill) won't work. This variable serves (at least) double duty + as both the pid of the target process (if it has such), and as a + flag indicating that a target is active. These functions should + be split out into seperate variables, especially since GDB will + someday have a notion of debugging several processes. */ + + inferior_ptid = pid_to_ptid (MAGIC_NULL_PID); +#ifdef SOLIB_CREATE_INFERIOR_HOOK + /* First delete any symbols previously loaded from shared libraries. */ + no_shared_libraries (NULL, 0); +#endif + + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (remote_start_remote, NULL, + "Couldn't establish connection to remote target\n", + RETURN_MASK_ALL)) + { + pop_target (); + return; + } + + if (extended_p) + { + /* Tell the remote that we are using the extended protocol. */ + char *buf = alloca (rs->remote_packet_size); + putpkt ("!"); + getpkt (buf, (rs->remote_packet_size), 0); + } +#ifdef SOLIB_CREATE_INFERIOR_HOOK + /* FIXME: need a master target_open vector from which all + remote_opens can be called, so that stuff like this can + go there. Failing that, the following code must be copied + to the open function for any remote target that wants to + support svr4 shared libraries. */ + + /* Set up to detect and load shared libraries. */ + if (exec_bfd) /* No use without an exec file. */ + { + SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid)); + remote_check_symbols (symfile_objfile); + } +#endif +} - SERIAL_RAW (remote_desc); +/* Just like remote_open but with asynchronous support. */ +static void +remote_async_open_1 (char *name, int from_tty, struct target_ops *target, + int extended_p) +{ + struct remote_state *rs = get_remote_state (); + if (name == 0) + error ("To open a remote debug connection, you need to specify what\n" + "serial device is attached to the remote system\n" + "(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.)."); + + target_preopen (from_tty); + + unpush_target (target); + + remote_desc = serial_open (name); + if (!remote_desc) + perror_with_name (name); + + if (baud_rate != -1) + { + if (serial_setbaudrate (remote_desc, baud_rate)) + { + serial_close (remote_desc); + perror_with_name (name); + } + } + + serial_raw (remote_desc); /* If there is something sitting in the buffer we might take it as a response to a command, which would be bad. */ - SERIAL_FLUSH_INPUT (remote_desc); + serial_flush_input (remote_desc); if (from_tty) { @@ -1647,25 +2362,17 @@ serial device is attached to the remote system (e.g. /dev/ttya)."); puts_filtered (name); puts_filtered ("\n"); } - push_target (target); /* Switch to using remote target now */ - /* The target vector does not have the thread functions in it yet, - so we use this function to call back into the thread module and - register the thread vector and its contained functions. */ - bind_target_thread_vector (&remote_thread_vec); + push_target (target); /* Switch to using remote target now */ - /* Start out by trying the 'P' request to set registers. We set - this each time that we open a new target so that if the user - switches from one stub to another, we can (if the target is - closed and reopened) cope. */ - stub_supports_P = 1; + init_all_packet_configs (); general_thread = -2; - cont_thread = -2; + continue_thread = -2; - /* Force remote_write_bytes to check whether target supports - binary downloading. */ - remote_binary_checked = 0; + /* Probe for ability to use "ThreadInfo" query, as required. */ + use_threadinfo_query = 1; + use_threadextra_query = 1; /* Without this, some commands which require an active target (such as kill) won't work. This variable serves (at least) double duty @@ -1673,26 +2380,60 @@ serial device is attached to the remote system (e.g. /dev/ttya)."); flag indicating that a target is active. These functions should be split out into seperate variables, especially since GDB will someday have a notion of debugging several processes. */ + inferior_ptid = pid_to_ptid (MAGIC_NULL_PID); + + /* With this target we start out by owning the terminal. */ + remote_async_terminal_ours_p = 1; + + /* FIXME: cagney/1999-09-23: During the initial connection it is + assumed that the target is already ready and able to respond to + requests. Unfortunately remote_start_remote() eventually calls + wait_for_inferior() with no timeout. wait_forever_enabled_p gets + around this. Eventually a mechanism that allows + wait_for_inferior() to expect/get timeouts will be + implemented. */ + wait_forever_enabled_p = 0; + +#ifdef SOLIB_CREATE_INFERIOR_HOOK + /* First delete any symbols previously loaded from shared libraries. */ + no_shared_libraries (NULL, 0); +#endif - inferior_pid = MAGIC_NULL_PID; /* Start the remote connection; if error (0), discard this target. In particular, if the user quits, be sure to discard it (we'd be in an inconsistent state otherwise). */ - if (!catch_errors (remote_start_remote, NULL, - "Couldn't establish connection to remote target\n", + if (!catch_errors (remote_start_remote, NULL, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) { pop_target (); + wait_forever_enabled_p = 1; return; } + wait_forever_enabled_p = 1; + if (extended_p) { - /* tell the remote that we're using the extended protocol. */ - char buf[PBUFSIZ]; + /* Tell the remote that we are using the extended protocol. */ + char *buf = alloca (rs->remote_packet_size); putpkt ("!"); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); } +#ifdef SOLIB_CREATE_INFERIOR_HOOK + /* FIXME: need a master target_open vector from which all + remote_opens can be called, so that stuff like this can + go there. Failing that, the following code must be copied + to the open function for any remote target that wants to + support svr4 shared libraries. */ + + /* Set up to detect and load shared libraries. */ + if (exec_bfd) /* No use without an exec file. */ + { + SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid)); + remote_check_symbols (symfile_objfile); + } +#endif } /* This takes a program previously attached to and detaches it. After @@ -1701,29 +2442,51 @@ serial device is attached to the remote system (e.g. /dev/ttya)."); die when it hits one. */ static void -remote_detach (args, from_tty) - char *args; - int from_tty; +remote_detach (char *args, int from_tty) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); if (args) error ("Argument given to \"detach\" when remotely debugging."); /* Tell the remote target to detach. */ strcpy (buf, "D"); - remote_send (buf); + remote_send (buf, (rs->remote_packet_size)); - pop_target (); + target_mourn_inferior (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); + +} + +/* Same as remote_detach, but with async support. */ +static void +remote_async_detach (char *args, int from_tty) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + /* Tell the remote target to detach. */ + strcpy (buf, "D"); + remote_send (buf, (rs->remote_packet_size)); + + /* Unregister the file descriptor from the event loop. */ + if (target_is_async_p ()) + serial_async (remote_desc, NULL, 0); + + target_mourn_inferior (); if (from_tty) puts_filtered ("Ending remote debugging.\n"); } /* Convert hex digit A to a number. */ -int -fromhex (a) - int a; +static int +fromhex (int a) { if (a >= '0' && a <= '9') return a - '0'; @@ -1731,20 +2494,55 @@ fromhex (a) return a - 'a' + 10; else if (a >= 'A' && a <= 'F') return a - 'A' + 10; - else + else error ("Reply contains invalid hex digit %d", a); } +static int +hex2bin (const char *hex, char *bin, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + if (hex[0] == 0 || hex[1] == 0) + { + /* Hex string is short, or of uneven length. + Return the count that has been converted so far. */ + return i; + } + *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + return i; +} + /* Convert number NIB to a hex digit. */ static int -tohex (nib) - int nib; +tohex (int nib) { if (nib < 10) - return '0'+nib; + return '0' + nib; else - return 'a'+nib-10; + return 'a' + nib - 10; +} + +static int +bin2hex (const char *bin, char *hex, int count) +{ + int i; + /* May use a length, or a nul-terminated string as input. */ + if (count == 0) + count = strlen (bin); + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; } /* Tell the remote machine to resume. */ @@ -1754,19 +2552,18 @@ static enum target_signal last_sent_signal = TARGET_SIGNAL_0; static int last_sent_step; static void -remote_resume (pid, step, siggnal) - int pid, step; - enum target_signal siggnal; +remote_resume (ptid_t ptid, int step, enum target_signal siggnal) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + int pid = PIDGET (ptid); + char *p; if (pid == -1) set_thread (0, 0); /* run any thread */ else set_thread (pid, 0); /* run this thread */ - dcache_flush (remote_dcache); - last_sent_signal = siggnal; last_sent_step = step; @@ -1775,61 +2572,304 @@ remote_resume (pid, step, siggnal) if (target_resume_hook) (*target_resume_hook) (); + + /* The s/S/c/C packets do not return status. So if the target does + not support the S or C packets, the debug agent returns an empty + string which is detected in remote_wait(). This protocol defect + is fixed in the e/E packets. */ + + if (step && step_range_end) + { + /* If the target does not support the 'E' packet, we try the 'S' + packet. Ideally we would fall back to the 'e' packet if that + too is not supported. But that would require another copy of + the code to issue the 'e' packet (and fall back to 's' if not + supported) in remote_wait(). */ + + if (siggnal != TARGET_SIGNAL_0) + { + if (remote_protocol_E.support != PACKET_DISABLE) + { + p = buf; + *p++ = 'E'; + *p++ = tohex (((int) siggnal >> 4) & 0xf); + *p++ = tohex (((int) siggnal) & 0xf); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) step_range_start); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) step_range_end); + *p++ = 0; + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + if (packet_ok (buf, &remote_protocol_E) == PACKET_OK) + return; + } + } + else + { + if (remote_protocol_e.support != PACKET_DISABLE) + { + p = buf; + *p++ = 'e'; + p += hexnumstr (p, (ULONGEST) step_range_start); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) step_range_end); + *p++ = 0; + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + if (packet_ok (buf, &remote_protocol_e) == PACKET_OK) + return; + } + } + } + if (siggnal != TARGET_SIGNAL_0) { buf[0] = step ? 'S' : 'C'; - buf[1] = tohex (((int)siggnal >> 4) & 0xf); - buf[2] = tohex ((int)siggnal & 0xf); + buf[1] = tohex (((int) siggnal >> 4) & 0xf); + buf[2] = tohex (((int) siggnal) & 0xf); buf[3] = '\0'; } else - strcpy (buf, step ? "s": "c"); + strcpy (buf, step ? "s" : "c"); putpkt (buf); } + +/* Same as remote_resume, but with async support. */ +static void +remote_async_resume (ptid_t ptid, int step, enum target_signal siggnal) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + int pid = PIDGET (ptid); + char *p; + + if (pid == -1) + set_thread (0, 0); /* run any thread */ + else + set_thread (pid, 0); /* run this thread */ + + last_sent_signal = siggnal; + last_sent_step = step; + + /* A hook for when we need to do something at the last moment before + resumption. */ + if (target_resume_hook) + (*target_resume_hook) (); + + /* The s/S/c/C packets do not return status. So if the target does + not support the S or C packets, the debug agent returns an empty + string which is detected in remote_wait(). This protocol defect + is fixed in the e/E packets. */ + + if (step && step_range_end) + { + /* If the target does not support the 'E' packet, we try the 'S' + packet. Ideally we would fall back to the 'e' packet if that + too is not supported. But that would require another copy of + the code to issue the 'e' packet (and fall back to 's' if not + supported) in remote_wait(). */ + + if (siggnal != TARGET_SIGNAL_0) + { + if (remote_protocol_E.support != PACKET_DISABLE) + { + p = buf; + *p++ = 'E'; + *p++ = tohex (((int) siggnal >> 4) & 0xf); + *p++ = tohex (((int) siggnal) & 0xf); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) step_range_start); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) step_range_end); + *p++ = 0; + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + if (packet_ok (buf, &remote_protocol_E) == PACKET_OK) + goto register_event_loop; + } + } + else + { + if (remote_protocol_e.support != PACKET_DISABLE) + { + p = buf; + *p++ = 'e'; + p += hexnumstr (p, (ULONGEST) step_range_start); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) step_range_end); + *p++ = 0; + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + if (packet_ok (buf, &remote_protocol_e) == PACKET_OK) + goto register_event_loop; + } + } + } + + if (siggnal != TARGET_SIGNAL_0) + { + buf[0] = step ? 'S' : 'C'; + buf[1] = tohex (((int) siggnal >> 4) & 0xf); + buf[2] = tohex ((int) siggnal & 0xf); + buf[3] = '\0'; + } + else + strcpy (buf, step ? "s" : "c"); + + putpkt (buf); + +register_event_loop: + /* We are about to start executing the inferior, let's register it + with the event loop. NOTE: this is the one place where all the + execution commands end up. We could alternatively do this in each + of the execution commands in infcmd.c.*/ + /* FIXME: ezannoni 1999-09-28: We may need to move this out of here + into infcmd.c in order to allow inferior function calls to work + NOT asynchronously. */ + if (event_loop_p && target_can_async_p ()) + target_async (inferior_event_handler, 0); + /* Tell the world that the target is now executing. */ + /* FIXME: cagney/1999-09-23: Is it the targets responsibility to set + this? Instead, should the client of target just assume (for + async targets) that the target is going to start executing? Is + this information already found in the continuation block? */ + if (target_is_async_p ()) + target_executing = 1; +} -/* Send ^C to target to halt it. Target will respond, and send us a - packet. */ -static void (*ofunc) PARAMS ((int)); +/* Set up the signal handler for SIGINT, while the target is + executing, ovewriting the 'regular' SIGINT signal handler. */ +static void +initialize_sigint_signal_handler (void) +{ + sigint_remote_token = + create_async_signal_handler (async_remote_interrupt, NULL); + signal (SIGINT, handle_remote_sigint); +} +/* Signal handler for SIGINT, while the target is executing. */ static void -remote_interrupt (signo) - int signo; +handle_remote_sigint (int sig) { - remote_stop (); - signal (signo, remote_interrupt); + signal (sig, handle_remote_sigint_twice); + sigint_remote_twice_token = + create_async_signal_handler (async_remote_interrupt_twice, NULL); + mark_async_signal_handler_wrapper (sigint_remote_token); } - + +/* Signal handler for SIGINT, installed after SIGINT has already been + sent once. It will take effect the second time that the user sends + a ^C. */ static void -remote_stop () +handle_remote_sigint_twice (int sig) { - if (!interrupted_already) - { - /* Send a break or a ^C, depending on user preference. */ - interrupted_already = 1; + signal (sig, handle_sigint); + sigint_remote_twice_token = + create_async_signal_handler (inferior_event_handler_wrapper, NULL); + mark_async_signal_handler_wrapper (sigint_remote_twice_token); +} - if (remote_debug) - printf_unfiltered ("remote_stop called\n"); +/* Perform the real interruption of the target execution, in response + to a ^C. */ +static void +async_remote_interrupt (gdb_client_data arg) +{ + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n"); - if (remote_break) - SERIAL_SEND_BREAK (remote_desc); - else - SERIAL_WRITE (remote_desc, "\003", 1); - } - else + target_stop (); +} + +/* Perform interrupt, if the first attempt did not succeed. Just give + up on the target alltogether. */ +void +async_remote_interrupt_twice (gdb_client_data arg) +{ + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n"); + /* Do something only if the target was not killed by the previous + cntl-C. */ + if (target_executing) { - signal (SIGINT, ofunc); interrupt_query (); - signal (SIGINT, remote_interrupt); - interrupted_already = 0; + signal (SIGINT, handle_remote_sigint); } } +/* Reinstall the usual SIGINT handlers, after the target has + stopped. */ +static void +cleanup_sigint_signal_handler (void *dummy) +{ + signal (SIGINT, handle_sigint); + if (sigint_remote_twice_token) + delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_twice_token); + if (sigint_remote_token) + delete_async_signal_handler ((struct async_signal_handler **) & sigint_remote_token); +} + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ +static void (*ofunc) (int); + +/* The command line interface's stop routine. This function is installed + as a signal handler for SIGINT. The first time a user requests a + stop, we call remote_stop to send a break or ^C. If there is no + response from the target (it didn't stop when the user requested it), + we ask the user if he'd like to detach from the target. */ +static void +remote_interrupt (int signo) +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, remote_interrupt_twice); + + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n"); + + target_stop (); +} + +/* The user typed ^C twice. */ + +static void +remote_interrupt_twice (int signo) +{ + signal (signo, ofunc); + interrupt_query (); + signal (signo, remote_interrupt); +} + +/* This is the generic stop called via the target vector. When a target + interrupt is requested, either by the command line or the GUI, we + will eventually end up here. */ +static void +remote_stop (void) +{ + /* Send a break or a ^C, depending on user preference. */ + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "remote_stop called\n"); + + if (remote_break) + serial_send_break (remote_desc); + else + serial_write (remote_desc, "\003", 1); +} + /* Ask the user what to do when an interrupt is received. */ static void -interrupt_query () +interrupt_query (void) { target_terminal_ours (); @@ -1837,45 +2877,87 @@ interrupt_query () Give up (and stop debugging it)? ")) { target_mourn_inferior (); - return_to_top_level (RETURN_QUIT); + throw_exception (RETURN_QUIT); } target_terminal_inferior (); } +/* Enable/disable target terminal ownership. Most targets can use + terminal groups to control terminal ownership. Remote targets are + different in that explicit transfer of ownership to/from GDB/target + is required. */ + +static void +remote_async_terminal_inferior (void) +{ + /* FIXME: cagney/1999-09-27: Shouldn't need to test for + sync_execution here. This function should only be called when + GDB is resuming the inferior in the forground. A background + resume (``run&'') should leave GDB in control of the terminal and + consequently should not call this code. */ + if (!sync_execution) + return; + /* FIXME: cagney/1999-09-27: Closely related to the above. Make + calls target_terminal_*() idenpotent. The event-loop GDB talking + to an asynchronous target with a synchronous command calls this + function from both event-top.c and infrun.c/infcmd.c. Once GDB + stops trying to transfer the terminal to the target when it + shouldn't this guard can go away. */ + if (!remote_async_terminal_ours_p) + return; + delete_file_handler (input_fd); + remote_async_terminal_ours_p = 0; + initialize_sigint_signal_handler (); + /* NOTE: At this point we could also register our selves as the + recipient of all input. Any characters typed could then be + passed on down to the target. */ +} + +static void +remote_async_terminal_ours (void) +{ + /* See FIXME in remote_async_terminal_inferior. */ + if (!sync_execution) + return; + /* See FIXME in remote_async_terminal_inferior. */ + if (remote_async_terminal_ours_p) + return; + cleanup_sigint_signal_handler (NULL); + add_file_handler (input_fd, stdin_event_handler, 0); + remote_async_terminal_ours_p = 1; +} + /* If nonzero, ignore the next kill. */ int kill_kludge; void -remote_console_output (msg) - char *msg; +remote_console_output (char *msg) { char *p; - for (p = msg; *p; p +=2) + for (p = msg; p[0] && p[1]; p += 2) { char tb[2]; char c = fromhex (p[0]) * 16 + fromhex (p[1]); tb[0] = c; tb[1] = 0; - if (target_output_hook) - target_output_hook (tb); - else - fputs_filtered (tb, gdb_stdout); + fputs_unfiltered (tb, gdb_stdtarg); } + gdb_flush (gdb_stdtarg); } -/* Wait until the remote machine stops, then return, storing status in - STATUS just as `wait' would. Returns "pid" (though it's not clear - what, if anything, that means in the case of this target). */ +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. + Returns "pid", which in the case of a multi-threaded + remote OS, is the thread-id. */ -static int -remote_wait (pid, status) - int pid; - struct target_waitstatus *status; +static ptid_t +remote_wait (ptid_t ptid, struct target_waitstatus *status) { - unsigned char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + unsigned char *buf = alloca (rs->remote_packet_size); int thread_num = -1; status->kind = TARGET_WAITKIND_EXITED; @@ -1885,18 +2967,12 @@ remote_wait (pid, status) { unsigned char *p; -#ifdef REMOTE_CHAT - if (remote_chat) - (void) remote_talk(); -#endif /* REMOTE_CHAT */ - - interrupted_already = 0; ofunc = signal (SIGINT, remote_interrupt); - getpkt ((char *) buf, 1); + getpkt (buf, (rs->remote_packet_size), 1); signal (SIGINT, ofunc); /* This is a hook for when we need to do something (perhaps the - collection of trace data) every time the target stops. */ + collection of trace data) every time the target stops. */ if (target_wait_loop_hook) (*target_wait_loop_hook) (); @@ -1908,27 +2984,27 @@ remote_wait (pid, status) case 'T': /* Status with PC, SP, FP, ... */ { int i; - long regno; - char regs[MAX_REGISTER_RAW_SIZE]; + char* regs = (char*) alloca (MAX_REGISTER_RAW_SIZE); /* Expedited reply, containing Signal, {regno, reg} repeat */ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where - ss = signal number - n... = register number - r... = register contents - */ + ss = signal number + n... = register number + r... = register contents + */ p = &buf[3]; /* after Txx */ while (*p) { unsigned char *p1; char *p_temp; + int fieldsize; - /* Read the register number */ - regno = strtol ((const char *) p, &p_temp, 16); - p1 = (unsigned char *)p_temp; + /* Read the ``P'' register number. */ + LONGEST pnum = strtol ((const char *) p, &p_temp, 16); + p1 = (unsigned char *) p_temp; - if (p1 == p) /* No register number present here */ + if (p1 == p) /* No register number present here */ { p1 = (unsigned char *) strchr ((const char *) p, ':'); if (p1 == NULL) @@ -1944,6 +3020,7 @@ Packet: '%s'\n", } else { + struct packet_reg *reg = packet_reg_from_pnum (rs, pnum); p = p1; if (*p++ != ':') @@ -1951,25 +3028,22 @@ Packet: '%s'\n", Packet: '%s'\n", p, buf); - if (regno >= NUM_REGS) - warning ("Remote sent bad register number %ld: %s\n\ + if (reg == NULL) + warning ("Remote sent bad register number %s: %s\n\ Packet: '%s'\n", - regno, p, buf); + phex_nz (pnum, 0), p, buf); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i++) - { - if (p[0] == 0 || p[1] == 0) - warning ("Remote reply is too short: %s", buf); - regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); - p += 2; - } - supply_register (regno, regs); + fieldsize = hex2bin (p, regs, REGISTER_RAW_SIZE (reg->regnum)); + p += 2 * fieldsize; + if (fieldsize < REGISTER_RAW_SIZE (reg->regnum)) + warning ("Remote reply is too short: %s", buf); + supply_register (reg->regnum, regs); } if (*p++ != ';') { warning ("Remote register badly formatted: %s", buf); - warning (" here: %s",p); + warning (" here: %s", p); } } } @@ -1979,7 +3053,72 @@ Packet: '%s'\n", status->value.sig = (enum target_signal) (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + if (buf[3] == 'p') + { + /* Export Cisco kernel mode as a convenience variable + (so that it can be used in the GDB prompt if desired). */ + + if (cisco_kernel_mode == 1) + set_internalvar (lookup_internalvar ("cisco_kernel_mode"), + value_from_string ("PDEBUG-")); + cisco_kernel_mode = 0; + thread_num = strtol ((const char *) &buf[4], NULL, 16); + record_currthread (thread_num); + } + else if (buf[3] == 'k') + { + /* Export Cisco kernel mode as a convenience variable + (so that it can be used in the GDB prompt if desired). */ + + if (cisco_kernel_mode == 1) + set_internalvar (lookup_internalvar ("cisco_kernel_mode"), + value_from_string ("KDEBUG-")); + cisco_kernel_mode = 1; + } goto got_status; + case 'N': /* Cisco special: status and offsets */ + { + bfd_vma text_addr, data_addr, bss_addr; + bfd_signed_vma text_off, data_off, bss_off; + unsigned char *p1; + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + if (symfile_objfile == NULL) + { + warning ("Relocation packet received with no symbol file. \ +Packet Dropped"); + goto got_status; + } + + /* Relocate object file. Buffer format is NAATT;DD;BB + * where AA is the signal number, TT is the new text + * address, DD * is the new data address, and BB is the + * new bss address. */ + + p = &buf[3]; + text_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + data_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + bss_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p) + warning ("Malformed relocation packet: Packet '%s'", buf); + + if (remote_cisco_section_offsets (text_addr, data_addr, bss_addr, + &text_off, &data_off, &bss_off) + == 0) + if (text_off != 0 || data_off != 0 || bss_off != 0) + remote_cisco_objfile_relocate (text_off, data_off, bss_off); + + goto got_status; + } case 'W': /* Target exited */ { /* The remote process exited. */ @@ -2001,7 +3140,7 @@ Packet: '%s'\n", if (last_sent_signal != TARGET_SIGNAL_0) { /* Zero length reply means that we tried 'S' or 'C' and - the remote system doesn't support it. */ + the remote system doesn't support it. */ target_terminal_ours_for_output (); printf_filtered ("Can't send signals to this remote system. %s not sent.\n", @@ -2019,21 +3158,234 @@ Packet: '%s'\n", continue; } } - got_status: +got_status: if (thread_num != -1) { - /* Initial thread value can only be acquired via wait, so deal with - this marker which is used before the first thread value is - acquired. */ - if (inferior_pid == MAGIC_NULL_PID) + return pid_to_ptid (thread_num); + } + return inferior_ptid; +} + +/* Async version of remote_wait. */ +static ptid_t +remote_async_wait (ptid_t ptid, struct target_waitstatus *status) +{ + struct remote_state *rs = get_remote_state (); + unsigned char *buf = alloca (rs->remote_packet_size); + int thread_num = -1; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + while (1) + { + unsigned char *p; + + if (!target_is_async_p ()) + ofunc = signal (SIGINT, remote_interrupt); + /* FIXME: cagney/1999-09-27: If we're in async mode we should + _never_ wait for ever -> test on target_is_async_p(). + However, before we do that we need to ensure that the caller + knows how to take the target into/out of async mode. */ + getpkt (buf, (rs->remote_packet_size), wait_forever_enabled_p); + if (!target_is_async_p ()) + signal (SIGINT, ofunc); + + /* This is a hook for when we need to do something (perhaps the + collection of trace data) every time the target stops. */ + if (target_wait_loop_hook) + (*target_wait_loop_hook) (); + + switch (buf[0]) { - inferior_pid = thread_num; - if (!in_thread_list (inferior_pid)) - add_thread (inferior_pid); + case 'E': /* Error of some sort */ + warning ("Remote failure reply: %s", buf); + continue; + case 'T': /* Status with PC, SP, FP, ... */ + { + int i; + char* regs = (char*) alloca (MAX_REGISTER_RAW_SIZE); + + /* Expedited reply, containing Signal, {regno, reg} repeat */ + /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where + ss = signal number + n... = register number + r... = register contents + */ + p = &buf[3]; /* after Txx */ + + while (*p) + { + unsigned char *p1; + char *p_temp; + int fieldsize; + + /* Read the register number */ + long pnum = strtol ((const char *) p, &p_temp, 16); + p1 = (unsigned char *) p_temp; + + if (p1 == p) /* No register number present here */ + { + p1 = (unsigned char *) strchr ((const char *) p, ':'); + if (p1 == NULL) + warning ("Malformed packet(a) (missing colon): %s\n\ +Packet: '%s'\n", + p, buf); + if (strncmp ((const char *) p, "thread", p1 - p) == 0) + { + p_temp = unpack_varlen_hex (++p1, &thread_num); + record_currthread (thread_num); + p = (unsigned char *) p_temp; + } + } + else + { + struct packet_reg *reg = packet_reg_from_pnum (rs, pnum); + p = p1; + if (*p++ != ':') + warning ("Malformed packet(b) (missing colon): %s\n\ +Packet: '%s'\n", + p, buf); + + if (reg == NULL) + warning ("Remote sent bad register number %ld: %s\n\ +Packet: '%s'\n", + pnum, p, buf); + + fieldsize = hex2bin (p, regs, REGISTER_RAW_SIZE (reg->regnum)); + p += 2 * fieldsize; + if (fieldsize < REGISTER_RAW_SIZE (reg->regnum)) + warning ("Remote reply is too short: %s", buf); + supply_register (reg->regnum, regs); + } + + if (*p++ != ';') + { + warning ("Remote register badly formatted: %s", buf); + warning (" here: %s", p); + } + } + } + /* fall through */ + case 'S': /* Old style status, just signal only */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + if (buf[3] == 'p') + { + /* Export Cisco kernel mode as a convenience variable + (so that it can be used in the GDB prompt if desired). */ + + if (cisco_kernel_mode == 1) + set_internalvar (lookup_internalvar ("cisco_kernel_mode"), + value_from_string ("PDEBUG-")); + cisco_kernel_mode = 0; + thread_num = strtol ((const char *) &buf[4], NULL, 16); + record_currthread (thread_num); + } + else if (buf[3] == 'k') + { + /* Export Cisco kernel mode as a convenience variable + (so that it can be used in the GDB prompt if desired). */ + + if (cisco_kernel_mode == 1) + set_internalvar (lookup_internalvar ("cisco_kernel_mode"), + value_from_string ("KDEBUG-")); + cisco_kernel_mode = 1; + } + goto got_status; + case 'N': /* Cisco special: status and offsets */ + { + bfd_vma text_addr, data_addr, bss_addr; + bfd_signed_vma text_off, data_off, bss_off; + unsigned char *p1; + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + if (symfile_objfile == NULL) + { + warning ("Relocation packet recieved with no symbol file. \ +Packet Dropped"); + goto got_status; + } + + /* Relocate object file. Buffer format is NAATT;DD;BB + * where AA is the signal number, TT is the new text + * address, DD * is the new data address, and BB is the + * new bss address. */ + + p = &buf[3]; + text_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + data_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + bss_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p) + warning ("Malformed relocation packet: Packet '%s'", buf); + + if (remote_cisco_section_offsets (text_addr, data_addr, bss_addr, + &text_off, &data_off, &bss_off) + == 0) + if (text_off != 0 || data_off != 0 || bss_off != 0) + remote_cisco_objfile_relocate (text_off, data_off, bss_off); + + goto got_status; + } + case 'W': /* Target exited */ + { + /* The remote process exited. */ + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]); + goto got_status; + } + case 'X': + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + kill_kludge = 1; + + goto got_status; + case 'O': /* Console output */ + remote_console_output (buf + 1); + /* Return immediately to the event loop. The event loop will + still be waiting on the inferior afterwards. */ + status->kind = TARGET_WAITKIND_IGNORE; + goto got_status; + case '\0': + if (last_sent_signal != TARGET_SIGNAL_0) + { + /* Zero length reply means that we tried 'S' or 'C' and + the remote system doesn't support it. */ + target_terminal_ours_for_output (); + printf_filtered + ("Can't send signals to this remote system. %s not sent.\n", + target_signal_to_name (last_sent_signal)); + last_sent_signal = TARGET_SIGNAL_0; + target_terminal_inferior (); + + strcpy ((char *) buf, last_sent_step ? "s" : "c"); + putpkt ((char *) buf); + continue; + } + /* else fallthrough */ + default: + warning ("Invalid remote reply: %s", buf); + continue; } - return thread_num; } - return inferior_pid; +got_status: + if (thread_num != -1) + { + return pid_to_ptid (thread_num); + } + return inferior_ptid; } /* Number of bytes of registers this stub implements. */ @@ -2041,28 +3393,41 @@ Packet: '%s'\n", static int register_bytes_found; /* Read the remote registers into the block REGS. */ -/* Currently we just read all the registers, so we don't use regno. */ +/* Currently we just read all the registers, so we don't use regnum. */ /* ARGSUSED */ static void -remote_fetch_registers (regno) - int regno; +remote_fetch_registers (int regnum) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); int i; char *p; - char regs[REGISTER_BYTES]; + char *regs = alloca (rs->sizeof_g_packet); + + set_thread (PIDGET (inferior_ptid), 1); - set_thread (inferior_pid, 1); + if (regnum >= 0) + { + struct packet_reg *reg = packet_reg_from_regnum (rs, regnum); + gdb_assert (reg != NULL); + if (!reg->in_g_packet) + internal_error (__FILE__, __LINE__, + "Attempt to fetch a non G-packet register when this " + "remote.c does not support the p-packet."); + } sprintf (buf, "g"); - remote_send (buf); + remote_send (buf, (rs->remote_packet_size)); - if (remote_register_buf_size == 0) - remote_register_buf_size = strlen (buf); + /* Save the size of the packet sent to us by the target. Its used + as a heuristic when determining the max size of packets that the + target can safely receive. */ + if ((rs->actual_register_packet_size) == 0) + (rs->actual_register_packet_size) = strlen (buf); /* Unimplemented registers read as all bits zero. */ - memset (regs, 0, REGISTER_BYTES); + memset (regs, 0, rs->sizeof_g_packet); /* We can get out of synch in various cases. If the first character in the buffer is not a hex character, assume that has happened @@ -2072,8 +3437,9 @@ remote_fetch_registers (regno) && buf[0] != 'x') /* New: unavailable register value */ { if (remote_debug) - printf_unfiltered ("Bad register packet; fetching a new packet\n"); - getpkt (buf, 0); + fprintf_unfiltered (gdb_stdlog, + "Bad register packet; fetching a new packet\n"); + getpkt (buf, (rs->remote_packet_size), 0); } /* Reply describes registers byte by byte, each byte encoded as two @@ -2081,7 +3447,7 @@ remote_fetch_registers (regno) register cacheing/storage mechanism. */ p = buf; - for (i = 0; i < REGISTER_BYTES; i++) + for (i = 0; i < rs->sizeof_g_packet; i++) { if (p[0] == 0) break; @@ -2093,7 +3459,7 @@ remote_fetch_registers (regno) goto supply_them; } if (p[0] == 'x' && p[1] == 'x') - regs[i] = 0; /* 'x' */ + regs[i] = 0; /* 'x' */ else regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); p += 2; @@ -2102,18 +3468,24 @@ remote_fetch_registers (regno) if (i != register_bytes_found) { register_bytes_found = i; -#ifdef REGISTER_BYTES_OK - if (!REGISTER_BYTES_OK (i)) + if (REGISTER_BYTES_OK_P () + && !REGISTER_BYTES_OK (i)) warning ("Remote reply is too short: %s", buf); -#endif } - - supply_them: - for (i = 0; i < NUM_REGS; i++) + + supply_them: { - supply_register (i, ®s[REGISTER_BYTE(i)]); - if (buf[REGISTER_BYTE(i) * 2] == 'x') - register_valid[i] = -1; /* register value not available */ + int i; + for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) + { + struct packet_reg *r = &rs->regs[i]; + if (r->in_g_packet) + { + supply_register (r->regnum, regs + r->offset); + if (buf[r->offset * 2] == 'x') + set_register_cached (i, -1); + } + } } } @@ -2121,111 +3493,120 @@ remote_fetch_registers (regno) 'G' request), we have to read out the ones we don't want to change first. */ -static void -remote_prepare_to_store () +static void +remote_prepare_to_store (void) { /* Make sure the entire registers array is valid. */ - read_register_bytes (0, (char *)NULL, REGISTER_BYTES); + switch (remote_protocol_P.support) + { + case PACKET_DISABLE: + case PACKET_SUPPORT_UNKNOWN: + /* NOTE: This isn't rs->sizeof_g_packet because here, we are + forcing the register cache to read its and not the target + registers. */ + read_register_bytes (0, (char *) NULL, REGISTER_BYTES); /* OK use. */ + break; + case PACKET_ENABLE: + break; + } +} + +/* Helper: Attempt to store REGNUM using the P packet. Return fail IFF + packet was not recognized. */ + +static int +store_register_using_P (int regnum) +{ + struct remote_state *rs = get_remote_state (); + struct packet_reg *reg = packet_reg_from_regnum (rs, regnum); + /* Try storing a single register. */ + char *buf = alloca (rs->remote_packet_size); + char *regp = alloca (MAX_REGISTER_RAW_SIZE); + char *p; + int i; + + sprintf (buf, "P%s=", phex_nz (reg->pnum, 0)); + p = buf + strlen (buf); + regcache_collect (reg->regnum, regp); + bin2hex (regp, p, REGISTER_RAW_SIZE (reg->regnum)); + remote_send (buf, rs->remote_packet_size); + + return buf[0] != '\0'; } -/* Store register REGNO, or all registers if REGNO == -1, from the contents - of REGISTERS. FIXME: ignores errors. */ + +/* Store register REGNUM, or all registers if REGNUM == -1, from the contents + of the register cache buffer. FIXME: ignores errors. */ static void -remote_store_registers (regno) - int regno; +remote_store_registers (int regnum) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf; + char *regs; int i; char *p; - set_thread (inferior_pid, 1); + set_thread (PIDGET (inferior_ptid), 1); - if (regno >= 0 && stub_supports_P) + if (regnum >= 0) { - /* Try storing a single register. */ - char *regp; - - sprintf (buf, "P%x=", regno); - p = buf + strlen (buf); - regp = ®isters[REGISTER_BYTE (regno)]; - for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i) + switch (remote_protocol_P.support) { - *p++ = tohex ((regp[i] >> 4) & 0xf); - *p++ = tohex (regp[i] & 0xf); - } - *p = '\0'; - remote_send (buf); - if (buf[0] != '\0') - { - /* The stub understands the 'P' request. We are done. */ - return; + case PACKET_DISABLE: + break; + case PACKET_ENABLE: + if (store_register_using_P (regnum)) + return; + else + error ("Protocol error: P packet not recognized by stub"); + case PACKET_SUPPORT_UNKNOWN: + if (store_register_using_P (regnum)) + { + /* The stub recognized the 'P' packet. Remember this. */ + remote_protocol_P.support = PACKET_ENABLE; + return; + } + else + { + /* The stub does not support the 'P' packet. Use 'G' + instead, and don't try using 'P' in the future (it + will just waste our time). */ + remote_protocol_P.support = PACKET_DISABLE; + break; + } } - - /* The stub does not support the 'P' request. Use 'G' instead, - and don't try using 'P' in the future (it will just waste our - time). */ - stub_supports_P = 0; } - buf[0] = 'G'; + /* Extract all the registers in the regcache copying them into a + local buffer. */ + { + int i; + regs = alloca (rs->sizeof_g_packet); + memset (regs, rs->sizeof_g_packet, 0); + for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) + { + struct packet_reg *r = &rs->regs[i]; + if (r->in_g_packet) + regcache_collect (r->regnum, regs + r->offset); + } + } /* Command describes registers byte by byte, each byte encoded as two hex characters. */ - - p = buf + 1; + buf = alloca (rs->remote_packet_size); + p = buf; + *p++ = 'G'; /* remote_prepare_to_store insures that register_bytes_found gets set. */ - for (i = 0; i < register_bytes_found; i++) - { - *p++ = tohex ((registers[i] >> 4) & 0xf); - *p++ = tohex (registers[i] & 0xf); - } - *p = '\0'; - - remote_send (buf); -} - -/* Use of the data cache *used* to be disabled because it loses for looking - at and changing hardware I/O ports and the like. Accepting `volatile' - would perhaps be one way to fix it. Another idea would be to use the - executable file for the text segment (for all SEC_CODE sections? - For all SEC_READONLY sections?). This has problems if you want to - actually see what the memory contains (e.g. self-modifying code, - clobbered memory, user downloaded the wrong thing). - - Because it speeds so much up, it's now enabled, if you're playing - with registers you turn it of (set remotecache 0). */ - -/* Read a word from remote address ADDR and return it. - This goes through the data cache. */ - -#if 0 /* unused? */ -static int -remote_fetch_word (addr) - CORE_ADDR addr; -{ - return dcache_fetch (remote_dcache, addr); + bin2hex (regs, p, register_bytes_found); + remote_send (buf, (rs->remote_packet_size)); } - -/* Write a word WORD into remote address ADDR. - This goes through the data cache. */ - -static void -remote_store_word (addr, word) - CORE_ADDR addr; - int word; -{ - dcache_poke (remote_dcache, addr, word); -} -#endif /* 0 (unused?) */ - /* Return the number of hex digits in num. */ static int -hexnumlen (num) - ULONGEST num; +hexnumlen (ULONGEST num) { int i; @@ -2235,32 +3616,38 @@ hexnumlen (num) return max (i, 1); } -/* Set BUF to the hex digits representing NUM. */ +/* Set BUF to the minimum number of hex digits representing NUM. */ static int -hexnumstr (buf, num) - char *buf; - ULONGEST num; +hexnumstr (char *buf, ULONGEST num) { - int i; int len = hexnumlen (num); + return hexnumnstr (buf, num, len); +} + + +/* Set BUF to the hex digits representing NUM, padded to WIDTH characters. */ - buf[len] = '\0'; +static int +hexnumnstr (char *buf, ULONGEST num, int width) +{ + int i; - for (i = len - 1; i >= 0; i--) + buf[width] = '\0'; + + for (i = width - 1; i >= 0; i--) { - buf[i] = "0123456789abcdef" [(num & 0xf)]; + buf[i] = "0123456789abcdef"[(num & 0xf)]; num >>= 4; } - return len; + return width; } /* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */ static CORE_ADDR -remote_address_masked (addr) - CORE_ADDR addr; +remote_address_masked (CORE_ADDR addr) { if (remote_address_size > 0 && remote_address_size < (sizeof (ULONGEST) * 8)) @@ -2278,37 +3665,54 @@ remote_address_masked (addr) This is accomplished by sending a no-op memory write of zero length to the target at the specified address. It does not suffice to send the whole packet, since many stubs strip the eighth bit and subsequently - compute a wrong checksum, which causes real havoc with remote_write_bytes. */ + compute a wrong checksum, which causes real havoc with remote_write_bytes. + + NOTE: This can still lose if the serial line is not eight-bit + clean. In cases like this, the user should clear "remote + X-packet". */ + static void -check_binary_download (addr) - CORE_ADDR addr; +check_binary_download (CORE_ADDR addr) { - if (remote_binary_download && !remote_binary_checked) + struct remote_state *rs = get_remote_state (); + switch (remote_protocol_binary_download.support) { - char buf[PBUFSIZ], *p; - remote_binary_checked = 1; - - p = buf; - *p++ = 'X'; - p += hexnumstr (p, (ULONGEST) addr); - *p++ = ','; - p += hexnumstr (p, (ULONGEST) 0); - *p++ = ':'; - *p = '\0'; - - putpkt_binary (buf, (int) (p - buf)); - getpkt (buf, 0); - - if (buf[0] == '\0') - remote_binary_download = 0; - } + case PACKET_DISABLE: + break; + case PACKET_ENABLE: + break; + case PACKET_SUPPORT_UNKNOWN: + { + char *buf = alloca (rs->remote_packet_size); + char *p; + + p = buf; + *p++ = 'X'; + p += hexnumstr (p, (ULONGEST) addr); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) 0); + *p++ = ':'; + *p = '\0'; + + putpkt_binary (buf, (int) (p - buf)); + getpkt (buf, (rs->remote_packet_size), 0); - if (remote_debug) - { - if (remote_binary_download) - printf_unfiltered ("binary downloading suppported by target\n"); - else - printf_unfiltered ("binary downloading NOT suppported by target\n"); + if (buf[0] == '\0') + { + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, + "binary downloading NOT suppported by target\n"); + remote_protocol_binary_download.support = PACKET_DISABLE; + } + else + { + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, + "binary downloading suppported by target\n"); + remote_protocol_binary_download.support = PACKET_ENABLE; + } + break; + } } } @@ -2318,129 +3722,136 @@ check_binary_download (addr) MYADDR is the address of the buffer in our space. LEN is the number of bytes. - Returns number of bytes transferred, or 0 for error. */ + Returns number of bytes transferred, or 0 (setting errno) for + error. Only transfer a single packet. */ static int -remote_write_bytes (memaddr, myaddr, len) - CORE_ADDR memaddr; - char *myaddr; - int len; +remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len) { + unsigned char *buf; int max_buf_size; /* Max size of packet output buffer */ - int origlen; + unsigned char *p; + unsigned char *plen; + long sizeof_buf; + int plenlen; + int todo; + int nr_bytes; /* Verify that the target can support a binary download */ check_binary_download (memaddr); - /* Chop the transfer down if necessary */ + /* Determine the max packet size. */ + max_buf_size = get_memory_write_packet_size (); + sizeof_buf = max_buf_size + 1; /* Space for trailing NUL */ + buf = alloca (sizeof_buf); - max_buf_size = min (remote_write_size, PBUFSIZ); - if (remote_register_buf_size != 0) - max_buf_size = min (max_buf_size, remote_register_buf_size); - - /* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */ + /* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */ max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4; - origlen = len; - while (len > 0) - { - unsigned char buf[PBUFSIZ]; - unsigned char *p, *plen; - int todo; - int i; - - /* construct "M"<memaddr>","<len>":" */ - /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */ - memaddr = remote_address_masked (memaddr); - p = buf; - if (remote_binary_download) - { - *p++ = 'X'; - todo = min (len, max_buf_size); - } - else - { - *p++ = 'M'; - todo = min (len, max_buf_size / 2); /* num bytes that will fit */ - } - - p += hexnumstr (p, (ULONGEST) memaddr); - *p++ = ','; - - plen = p; /* remember where len field goes */ - p += hexnumstr (p, (ULONGEST) todo); - *p++ = ':'; - *p = '\0'; - - /* We send target system values byte by byte, in increasing byte - addresses, each byte encoded as two hex characters (or one - binary character). */ - if (remote_binary_download) - { - int escaped = 0; - for (i = 0; - (i < todo) && (i + escaped) < (max_buf_size - 2); - i++) - { - switch (myaddr[i] & 0xff) - { - case '$': - case '#': - case 0x7d: - /* These must be escaped */ - escaped++; - *p++ = 0x7d; - *p++ = (myaddr[i] & 0xff) ^ 0x20; - break; - default: - *p++ = myaddr[i] & 0xff; - break; - } - } - - if (i < todo) - { - /* Escape chars have filled up the buffer prematurely, - and we have actually sent fewer bytes than planned. - Fix-up the length field of the packet. */ - - /* FIXME: will fail if new len is a shorter string than - old len. */ + /* construct "M"<memaddr>","<len>":" */ + /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */ + p = buf; - plen += hexnumstr (plen, (ULONGEST) i); - *plen++ = ':'; - } - } - else + /* Append [XM]. Compute a best guess of the number of bytes + actually transfered. */ + switch (remote_protocol_binary_download.support) + { + case PACKET_ENABLE: + *p++ = 'X'; + /* Best guess at number of bytes that will fit. */ + todo = min (len, max_buf_size); + break; + case PACKET_DISABLE: + *p++ = 'M'; + /* num bytes that will fit */ + todo = min (len, max_buf_size / 2); + break; + case PACKET_SUPPORT_UNKNOWN: + internal_error (__FILE__, __LINE__, + "remote_write_bytes: bad internal state"); + default: + internal_error (__FILE__, __LINE__, "bad switch"); + } + + /* Append <memaddr> */ + memaddr = remote_address_masked (memaddr); + p += hexnumstr (p, (ULONGEST) memaddr); + *p++ = ','; + + /* Append <len>. Retain the location/size of <len>. It may + need to be adjusted once the packet body has been created. */ + plen = p; + plenlen = hexnumstr (p, (ULONGEST) todo); + p += plenlen; + *p++ = ':'; + *p = '\0'; + + /* Append the packet body. */ + switch (remote_protocol_binary_download.support) + { + case PACKET_ENABLE: + /* Binary mode. Send target system values byte by byte, in + increasing byte addresses. Only escape certain critical + characters. */ + for (nr_bytes = 0; + (nr_bytes < todo) && (p - buf) < (max_buf_size - 2); + nr_bytes++) { - for (i = 0; i < todo; i++) + switch (myaddr[nr_bytes] & 0xff) { - *p++ = tohex ((myaddr[i] >> 4) & 0xf); - *p++ = tohex (myaddr[i] & 0xf); + case '$': + case '#': + case 0x7d: + /* These must be escaped */ + *p++ = 0x7d; + *p++ = (myaddr[nr_bytes] & 0xff) ^ 0x20; + break; + default: + *p++ = myaddr[nr_bytes] & 0xff; + break; } - *p = '\0'; } - - putpkt_binary (buf, (int) (p - buf)); - getpkt (buf, 0); - - if (buf[0] == 'E') + if (nr_bytes < todo) { - /* There is no correspondance between what the remote protocol uses - for errors and errno codes. We would like a cleaner way of - representing errors (big enough to include errno codes, bfd_error - codes, and others). But for now just return EIO. */ - errno = EIO; - return 0; + /* Escape chars have filled up the buffer prematurely, + and we have actually sent fewer bytes than planned. + Fix-up the length field of the packet. Use the same + number of characters as before. */ + + plen += hexnumnstr (plen, (ULONGEST) nr_bytes, plenlen); + *plen = ':'; /* overwrite \0 from hexnumnstr() */ } - - /* Increment by i, not by todo, in case escape chars - caused us to send fewer bytes than we'd planned. */ - myaddr += i; - memaddr += i; - len -= i; + break; + case PACKET_DISABLE: + /* Normal mode: Send target system values byte by byte, in + increasing byte addresses. Each byte is encoded as a two hex + value. */ + nr_bytes = bin2hex (myaddr, p, todo); + p += 2 * nr_bytes; + break; + case PACKET_SUPPORT_UNKNOWN: + internal_error (__FILE__, __LINE__, + "remote_write_bytes: bad internal state"); + default: + internal_error (__FILE__, __LINE__, "bad switch"); } - return origlen; + + putpkt_binary (buf, (int) (p - buf)); + getpkt (buf, sizeof_buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol + uses for errors and errno codes. We would like a cleaner way + of representing errors (big enough to include errno codes, + bfd_error codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + + /* Return NR_BYTES, not TODO, in case escape chars caused us to send fewer + bytes than we'd planned. */ + return nr_bytes; } /* Read memory data directly from the remote machine. @@ -2451,30 +3862,34 @@ remote_write_bytes (memaddr, myaddr, len) Returns number of bytes transferred, or 0 for error. */ +/* NOTE: cagney/1999-10-18: This function (and its siblings in other + remote targets) shouldn't attempt to read the entire buffer. + Instead it should read a single packet worth of data and then + return the byte size of that packet to the caller. The caller (its + caller and its callers caller ;-) already contains code for + handling partial reads. */ + static int -remote_read_bytes (memaddr, myaddr, len) - CORE_ADDR memaddr; - char *myaddr; - int len; +remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len) { + char *buf; int max_buf_size; /* Max size of packet output buffer */ + long sizeof_buf; int origlen; - /* Chop the transfer down if necessary */ - - max_buf_size = min (remote_write_size, PBUFSIZ); - if (remote_register_buf_size != 0) - max_buf_size = min (max_buf_size, remote_register_buf_size); + /* Create a buffer big enough for this packet. */ + max_buf_size = get_memory_read_packet_size (); + sizeof_buf = max_buf_size + 1; /* Space for trailing NUL */ + buf = alloca (sizeof_buf); origlen = len; while (len > 0) { - char buf[PBUFSIZ]; char *p; int todo; int i; - todo = min (len, max_buf_size / 2); /* num bytes that will fit */ + todo = min (len, max_buf_size / 2); /* num bytes that will fit */ /* construct "m"<memaddr>","<len>" */ /* sprintf (buf, "m%lx,%x", (unsigned long) memaddr, todo); */ @@ -2487,7 +3902,7 @@ remote_read_bytes (memaddr, myaddr, len) *p = '\0'; putpkt (buf); - getpkt (buf, 0); + getpkt (buf, sizeof_buf, 0); if (buf[0] == 'E') { @@ -2499,18 +3914,15 @@ remote_read_bytes (memaddr, myaddr, len) return 0; } - /* Reply describes memory byte by byte, - each byte encoded as two hex characters. */ + /* Reply describes memory byte by byte, + each byte encoded as two hex characters. */ p = buf; - for (i = 0; i < todo; i++) + if ((i = hex2bin (p, myaddr, todo)) < todo) { - if (p[0] == 0 || p[1] == 0) - /* Reply is short. This means that we were able to read - only part of what we wanted to. */ - return i + (origlen - len); - myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]); - p += 2; + /* Reply is short. This means that we were able to read + only part of what we wanted to. */ + return i + (origlen - len); } myaddr += todo; memaddr += todo; @@ -2520,56 +3932,47 @@ remote_read_bytes (memaddr, myaddr, len) } /* Read or write LEN bytes from inferior memory at MEMADDR, - transferring to or from debugger address MYADDR. Write to inferior - if SHOULD_WRITE is nonzero. Returns length of data written or - read; 0 for error. */ + transferring to or from debugger address BUFFER. Write to inferior if + SHOULD_WRITE is nonzero. Returns length of data written or read; 0 + for error. TARGET is unused. */ /* ARGSUSED */ static int -remote_xfer_memory (memaddr, myaddr, len, should_write, target) - CORE_ADDR memaddr; - char *myaddr; - int len; - int should_write; - struct target_ops *target; /* ignored */ -{ -#ifdef REMOTE_TRANSLATE_XFER_ADDRESS - CORE_ADDR targaddr; - int targlen; - REMOTE_TRANSLATE_XFER_ADDRESS (memaddr, len, targaddr, targlen); - if (targlen == 0) +remote_xfer_memory (CORE_ADDR mem_addr, char *buffer, int mem_len, + int should_write, struct mem_attrib *attrib, + struct target_ops *target) +{ + CORE_ADDR targ_addr; + int targ_len; + int res; + + REMOTE_TRANSLATE_XFER_ADDRESS (mem_addr, mem_len, &targ_addr, &targ_len); + if (targ_len <= 0) return 0; - memaddr = targaddr; - len = targlen; -#endif - return dcache_xfer_memory (remote_dcache, memaddr, myaddr, - len, should_write); + if (should_write) + res = remote_write_bytes (targ_addr, buffer, targ_len); + else + res = remote_read_bytes (targ_addr, buffer, targ_len); + + return res; } - + #if 0 /* Enable after 4.12. */ void -remote_search (len, data, mask, startaddr, increment, lorange, hirange - addr_found, data_found) - int len; - char *data; - char *mask; - CORE_ADDR startaddr; - int increment; - CORE_ADDR lorange; - CORE_ADDR hirange; - CORE_ADDR *addr_found; - char *data_found; +remote_search (int len, char *data, char *mask, CORE_ADDR startaddr, + int increment, CORE_ADDR lorange, CORE_ADDR hirange, + CORE_ADDR *addr_found, char *data_found) { if (increment == -4 && len == 4) { long mask_long, data_long; long data_found_long; CORE_ADDR addr_we_found; - char buf[PBUFSIZ]; + char *buf = alloca (rs->remote_packet_size); long returned_long[2]; char *p; @@ -2577,7 +3980,7 @@ remote_search (len, data, mask, startaddr, increment, lorange, hirange data_long = extract_unsigned_integer (data, len); sprintf (buf, "t%x:%x,%x", startaddr, data_long, mask_long); putpkt (buf); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); if (buf[0] == '\0') { /* The stub doesn't support the 't' request. We might want to @@ -2623,8 +4026,7 @@ remote_search (len, data, mask, startaddr, increment, lorange, hirange #endif /* 0 */ static void -remote_files_info (ignore) - struct target_ops *ignore; +remote_files_info (struct target_ops *ignore) { puts_filtered ("Debugging a target over a serial line.\n"); } @@ -2635,35 +4037,39 @@ remote_files_info (ignore) /* Read a single character from the remote end, masking it down to 7 bits. */ static int -readchar (timeout) - int timeout; +readchar (int timeout) { int ch; - ch = SERIAL_READCHAR (remote_desc, timeout); + ch = serial_readchar (remote_desc, timeout); + + if (ch >= 0) + return (ch & 0x7f); - switch (ch) + switch ((enum serial_rc) ch) { case SERIAL_EOF: + target_mourn_inferior (); error ("Remote connection closed"); + /* no return */ case SERIAL_ERROR: perror_with_name ("Remote communication error"); + /* no return */ case SERIAL_TIMEOUT: - return ch; - default: - return ch & 0x7f; + break; } + return ch; } /* Send the command in BUF to the remote machine, and read the reply into BUF. Report an error if we get an error reply. */ static void -remote_send (buf) - char *buf; +remote_send (char *buf, + long sizeof_buf) { putpkt (buf); - getpkt (buf, 0); + getpkt (buf, sizeof_buf, 0); if (buf[0] == 'E') error ("Remote failure reply: %s", buf); @@ -2673,35 +4079,34 @@ remote_send (buf) string notation. */ static void -print_packet (buf) - char *buf; +print_packet (char *buf) { puts_filtered ("\""); - while (*buf) - gdb_printchar (*buf++, gdb_stdout, '"'); + fputstr_filtered (buf, '"', gdb_stdout); puts_filtered ("\""); } int -putpkt (buf) - char *buf; +putpkt (char *buf) { return putpkt_binary (buf, strlen (buf)); } /* Send a packet to the remote machine, with error checking. The data - of the packet is in BUF. The string in BUF can be at most PBUFSIZ - 5 + of the packet is in BUF. The string in BUF can be at most (rs->remote_packet_size) - 5 to account for the $, # and checksum, and for a possible /0 if we are debugging (remote_debug) and want to print the sent packet as a string */ static int -putpkt_binary (buf, cnt) - char *buf; - int cnt; +putpkt_binary (char *buf, int cnt) { + struct remote_state *rs = get_remote_state (); int i; unsigned char csum = 0; - char buf2[PBUFSIZ]; + char *buf2 = alloca (cnt + 6); + long sizeof_junkbuf = (rs->remote_packet_size); + char *junkbuf = alloca (sizeof_junkbuf); + int ch; int tcount = 0; char *p; @@ -2709,9 +4114,6 @@ putpkt_binary (buf, cnt) /* Copy the packet into buffer BUF2, encapsulating it and giving it a checksum. */ - if (cnt > (int) sizeof (buf2) - 5) /* Prosanity check */ - abort (); - p = buf2; *p++ = '$'; @@ -2733,10 +4135,12 @@ putpkt_binary (buf, cnt) if (remote_debug) { *p = '\0'; - printf_unfiltered ("Sending packet: %s...", buf2); - gdb_flush (gdb_stdout); + fprintf_unfiltered (gdb_stdlog, "Sending packet: "); + fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog); + fprintf_unfiltered (gdb_stdlog, "..."); + gdb_flush (gdb_stdlog); } - if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) + if (serial_write (remote_desc, buf2, p - buf2)) perror_with_name ("putpkt: write failed"); /* read until either a timeout occurs (-2) or '+' is read */ @@ -2744,11 +4148,12 @@ putpkt_binary (buf, cnt) { ch = readchar (remote_timeout); - if (remote_debug) + if (remote_debug) { switch (ch) { case '+': + case '-': case SERIAL_TIMEOUT: case '$': if (started_error_output) @@ -2763,41 +4168,34 @@ putpkt_binary (buf, cnt) { case '+': if (remote_debug) - printf_unfiltered ("Ack\n"); + fprintf_unfiltered (gdb_stdlog, "Ack\n"); return 1; + case '-': + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "Nak\n"); case SERIAL_TIMEOUT: - tcount ++; + tcount++; if (tcount > 3) return 0; break; /* Retransmit buffer */ case '$': { - char junkbuf[PBUFSIZ]; - - /* It's probably an old response, and we're out of sync. - Just gobble up the packet and ignore it. */ - getpkt (junkbuf, 0); - continue; /* Now, go look for + */ - } - -#ifdef REMOTE_CHAT - case '|': - { - if (!started_error_output) - continue; - /* else fall through */ + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "Packet instead of Ack, ignoring it\n"); + /* It's probably an old response, and we're out of sync. + Just gobble up the packet and ignore it. */ + read_frame (junkbuf, sizeof_junkbuf); + continue; /* Now, go look for + */ } -#endif /* REMOTE_CHAT */ - default: if (remote_debug) { if (!started_error_output) { started_error_output = 1; - printf_unfiltered ("putpkt: Junk: "); + fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: "); } - putchar_unfiltered (ch & 0177); + fputc_unfiltered (ch & 0177, gdb_stdlog); } continue; } @@ -2806,10 +4204,10 @@ putpkt_binary (buf, cnt) #if 0 /* This is wrong. If doing a long backtrace, the user should be - able to get out next time we call QUIT, without anything as - violent as interrupt_query. If we want to provide a way out of - here without getting to the next QUIT, it should be based on - hitting ^C twice as in remote_wait. */ + able to get out next time we call QUIT, without anything as + violent as interrupt_query. If we want to provide a way out of + here without getting to the next QUIT, it should be based on + hitting ^C twice as in remote_wait. */ if (quit_flag) { quit_flag = 0; @@ -2819,118 +4217,183 @@ putpkt_binary (buf, cnt) } } +static int remote_cisco_mode; + /* Come here after finding the start of the frame. Collect the rest into BUF, verifying the checksum, length, and handling run-length - compression. Returns 0 on any error, 1 on success. */ + compression. No more than sizeof_buf-1 characters are read so that + the buffer can be NUL terminated. -static int -read_frame (buf) - char *buf; + Returns -1 on error, number of characters in buffer (ignoring the + trailing NULL) on success. (could be extended to return one of the + SERIAL status indications). */ + +static long +read_frame (char *buf, + long sizeof_buf) { unsigned char csum; - char *bp; + long bc; int c; csum = 0; - bp = buf; + bc = 0; while (1) { + /* ASSERT (bc < sizeof_buf - 1) - space for trailing NUL */ c = readchar (remote_timeout); - switch (c) { case SERIAL_TIMEOUT: if (remote_debug) - puts_filtered ("Timeout in mid-packet, retrying\n"); - return 0; + fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog); + return -1; case '$': if (remote_debug) - puts_filtered ("Saw new packet start in middle of old one\n"); - return 0; /* Start a new packet, count retries */ + fputs_filtered ("Saw new packet start in middle of old one\n", + gdb_stdlog); + return -1; /* Start a new packet, count retries */ case '#': { unsigned char pktcsum; + int check_0 = 0; + int check_1 = 0; - *bp = '\000'; + buf[bc] = '\0'; - pktcsum = fromhex (readchar (remote_timeout)) << 4; - pktcsum |= fromhex (readchar (remote_timeout)); + check_0 = readchar (remote_timeout); + if (check_0 >= 0) + check_1 = readchar (remote_timeout); + + if (check_0 == SERIAL_TIMEOUT || check_1 == SERIAL_TIMEOUT) + { + if (remote_debug) + fputs_filtered ("Timeout in checksum, retrying\n", gdb_stdlog); + return -1; + } + else if (check_0 < 0 || check_1 < 0) + { + if (remote_debug) + fputs_filtered ("Communication error in checksum\n", gdb_stdlog); + return -1; + } + pktcsum = (fromhex (check_0) << 4) | fromhex (check_1); if (csum == pktcsum) - return 1; + return bc; - if (remote_debug) + if (remote_debug) { - printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=", - pktcsum, csum); - puts_filtered (buf); - puts_filtered ("\n"); + fprintf_filtered (gdb_stdlog, + "Bad checksum, sentsum=0x%x, csum=0x%x, buf=", + pktcsum, csum); + fputs_filtered (buf, gdb_stdlog); + fputs_filtered ("\n", gdb_stdlog); } - return 0; + /* Number of characters in buffer ignoring trailing + NUL. */ + return -1; } case '*': /* Run length encoding */ - csum += c; - c = readchar (remote_timeout); - csum += c; - c = c - ' ' + 3; /* Compute repeat count */ + { + int repeat; + csum += c; + if (remote_cisco_mode == 0) + { + c = readchar (remote_timeout); + csum += c; + repeat = c - ' ' + 3; /* Compute repeat count */ + } + else + { + /* Cisco's run-length encoding variant uses two + hex chars to represent the repeat count. */ + + c = readchar (remote_timeout); + csum += c; + repeat = fromhex (c) << 4; + c = readchar (remote_timeout); + csum += c; + repeat += fromhex (c); + } - if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1) - { - memset (bp, *(bp - 1), c); - bp += c; - continue; - } + /* The character before ``*'' is repeated. */ - *bp = '\0'; - printf_filtered ("Repeat count %d too large for buffer: ", c); - puts_filtered (buf); - puts_filtered ("\n"); - return 0; + if (repeat > 0 && repeat <= 255 + && bc > 0 + && bc + repeat - 1 < sizeof_buf - 1) + { + memset (&buf[bc], buf[bc - 1], repeat); + bc += repeat; + continue; + } + buf[bc] = '\0'; + printf_filtered ("Repeat count %d too large for buffer: ", repeat); + puts_filtered (buf); + puts_filtered ("\n"); + return -1; + } default: - if (bp < buf + PBUFSIZ - 1) + if (bc < sizeof_buf - 1) { - *bp++ = c; + buf[bc++] = c; csum += c; continue; } - *bp = '\0'; + buf[bc] = '\0'; puts_filtered ("Remote packet too long: "); puts_filtered (buf); puts_filtered ("\n"); - return 0; + return -1; } } } /* Read a packet from the remote machine, with error checking, and - store it in BUF. BUF is expected to be of size PBUFSIZ. If - FOREVER, wait forever rather than timing out; this is used while - the target is executing user code. */ - + store it in BUF. If FOREVER, wait forever rather than timing out; + this is used (in synchronous mode) to wait for a target that is is + executing user code to stop. */ +/* FIXME: ezannoni 2000-02-01 this wrapper is necessary so that we + don't have to change all the calls to getpkt to deal with the + return value, because at the moment I don't know what the right + thing to do it for those. */ void -getpkt (buf, forever) - char *buf; - int forever; +getpkt (char *buf, + long sizeof_buf, + int forever) +{ + int timed_out; + + timed_out = getpkt_sane (buf, sizeof_buf, forever); +} + + +/* Read a packet from the remote machine, with error checking, and + store it in BUF. If FOREVER, wait forever rather than timing out; + this is used (in synchronous mode) to wait for a target that is is + executing user code to stop. If FOREVER == 0, this function is + allowed to time out gracefully and return an indication of this to + the caller. */ +static int +getpkt_sane (char *buf, + long sizeof_buf, + int forever) { int c; int tries; int timeout; int val; - strcpy (buf,"timeout"); + strcpy (buf, "timeout"); if (forever) { -#ifdef MAINTENANCE_CMDS timeout = watchdog > 0 ? watchdog : -1; -#else - timeout = -1; -#endif } else @@ -2941,12 +4404,12 @@ getpkt (buf, forever) for (tries = 1; tries <= MAX_TRIES; tries++) { /* This can loop forever if the remote side sends us characters - continuously, but if it pauses, we'll get a zero from readchar - because of timeout. Then we'll count that as a retry. */ + continuously, but if it pauses, we'll get a zero from readchar + because of timeout. Then we'll count that as a retry. */ /* Note that we will only wait forever prior to the start of a packet. - After that, we expect characters to arrive at a brisk pace. They - should show up within remote_timeout intervals. */ + After that, we expect characters to arrive at a brisk pace. They + should show up within remote_timeout intervals. */ do { @@ -2954,15 +4417,14 @@ getpkt (buf, forever) if (c == SERIAL_TIMEOUT) { -#ifdef MAINTENANCE_CMDS - if (forever) /* Watchdog went off. Kill the target. */ + if (forever) /* Watchdog went off? Kill the target. */ { + QUIT; target_mourn_inferior (); error ("Watchdog has expired. Target detached.\n"); } -#endif if (remote_debug) - puts_filtered ("Timed out.\n"); + fputs_filtered ("Timed out.\n", gdb_stdlog); goto retry; } } @@ -2970,30 +4432,61 @@ getpkt (buf, forever) /* We've found the start of a packet, now collect the data. */ - val = read_frame (buf); + val = read_frame (buf, sizeof_buf); - if (val == 1) + if (val >= 0) { if (remote_debug) - fprintf_unfiltered (gdb_stdout, "Packet received: %s\n", buf); - SERIAL_WRITE (remote_desc, "+", 1); - return; + { + fprintf_unfiltered (gdb_stdlog, "Packet received: "); + fputstr_unfiltered (buf, 0, gdb_stdlog); + fprintf_unfiltered (gdb_stdlog, "\n"); + } + serial_write (remote_desc, "+", 1); + return 0; } /* Try the whole thing again. */ retry: - SERIAL_WRITE (remote_desc, "-", 1); + serial_write (remote_desc, "-", 1); } /* We have tried hard enough, and just can't receive the packet. Give up. */ printf_unfiltered ("Ignoring packet error, continuing...\n"); - SERIAL_WRITE (remote_desc, "+", 1); + serial_write (remote_desc, "+", 1); + return 1; } static void -remote_kill () +remote_kill (void) +{ + /* For some mysterious reason, wait_for_inferior calls kill instead of + mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */ + if (kill_kludge) + { + kill_kludge = 0; + target_mourn_inferior (); + return; + } + + /* Use catch_errors so the user can quit from gdb even when we aren't on + speaking terms with the remote system. */ + catch_errors ((catch_errors_ftype *) putpkt, "k", "", RETURN_MASK_ERROR); + + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. For the existing stubs, kill is a noop. */ + target_mourn_inferior (); +} + +/* Async version of remote_kill. */ +static void +remote_async_kill (void) { + /* Unregister the file descriptor from the event loop. */ + if (target_is_async_p ()) + serial_async (remote_desc, NULL, 0); + /* For some mysterious reason, wait_for_inferior calls kill instead of mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */ if (kill_kludge) @@ -3013,13 +4506,19 @@ remote_kill () } static void -remote_mourn () +remote_mourn (void) { remote_mourn_1 (&remote_ops); } static void -extended_remote_mourn () +remote_async_mourn (void) +{ + remote_mourn_1 (&remote_async_ops); +} + +static void +extended_remote_mourn (void) { /* We do _not_ want to mourn the target like this; this will remove the extended remote target from the target stack, @@ -3033,8 +4532,7 @@ extended_remote_mourn () /* Worker function for remote_mourn. */ static void -remote_mourn_1 (target) - struct target_ops *target; +remote_mourn_1 (struct target_ops *target) { unpush_target (target); generic_mourn_inferior (); @@ -3048,10 +4546,7 @@ remote_mourn_1 (target) we're debugging, arguments and an environment. */ static void -extended_remote_create_inferior (exec_file, args, env) - char *exec_file; - char *args; - char **env; +extended_remote_create_inferior (char *exec_file, char *args, char **env) { /* Rip out the breakpoints; we'll reinsert them after restarting the remote server. */ @@ -3071,7 +4566,34 @@ extended_remote_create_inferior (exec_file, args, env) proceed (-1, TARGET_SIGNAL_0, 0); } +/* Async version of extended_remote_create_inferior. */ +static void +extended_remote_async_create_inferior (char *exec_file, char *args, char **env) +{ + /* Rip out the breakpoints; we'll reinsert them after restarting + the remote server. */ + remove_breakpoints (); + + /* If running asynchronously, register the target file descriptor + with the event loop. */ + if (event_loop_p && target_can_async_p ()) + target_async (inferior_event_handler, 0); + + /* Now restart the remote server. */ + extended_remote_restart (); + + /* Now put the breakpoints back in. This way we're safe if the + restart function works via a unix fork on the remote side. */ + insert_breakpoints (); + + /* Clean up from the last time we were running. */ + clear_proceed_status (); + + /* Let the remote process run. */ + proceed (-1, TARGET_SIGNAL_0, 0); +} + /* On some machines, e.g. 68k, we may use a different breakpoint instruction than other targets; in those use REMOTE_BREAKPOINT instead of just BREAKPOINT. Also, bi-endian targets may define LITTLE_REMOTE_BREAKPOINT @@ -3109,18 +4631,52 @@ static unsigned char little_break_insn[] = LITTLE_REMOTE_BREAKPOINT; is accomplished via BREAKPOINT_MAX). */ static int -remote_insert_breakpoint (addr, contents_cache) - CORE_ADDR addr; - char *contents_cache; +remote_insert_breakpoint (CORE_ADDR addr, char *contents_cache) { + struct remote_state *rs = get_remote_state (); #ifdef REMOTE_BREAKPOINT int val; +#endif + int bp_size; + + /* Try the "Z" s/w breakpoint packet if it is not already disabled. + If it succeeds, then set the support to PACKET_ENABLE. If it + fails, and the user has explicitly requested the Z support then + report an error, otherwise, mark it disabled and go on. */ + + if (remote_protocol_Z[Z_PACKET_SOFTWARE_BP].support != PACKET_DISABLE) + { + char *buf = alloca (rs->remote_packet_size); + char *p = buf; + + addr = remote_address_masked (addr); + *(p++) = 'Z'; + *(p++) = '0'; + *(p++) = ','; + p += hexnumstr (p, (ULONGEST) addr); + BREAKPOINT_FROM_PC (&addr, &bp_size); + sprintf (p, ",%d", bp_size); + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_SOFTWARE_BP])) + { + case PACKET_ERROR: + return -1; + case PACKET_OK: + return 0; + case PACKET_UNKNOWN: + break; + } + } + +#ifdef REMOTE_BREAKPOINT val = target_read_memory (addr, contents_cache, sizeof big_break_insn); if (val == 0) { - if (TARGET_BYTE_ORDER == BIG_ENDIAN) + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) val = target_write_memory (addr, (char *) big_break_insn, sizeof big_break_insn); else @@ -3135,10 +4691,31 @@ remote_insert_breakpoint (addr, contents_cache) } static int -remote_remove_breakpoint (addr, contents_cache) - CORE_ADDR addr; - char *contents_cache; +remote_remove_breakpoint (CORE_ADDR addr, char *contents_cache) { + struct remote_state *rs = get_remote_state (); + int bp_size; + + if (remote_protocol_Z[Z_PACKET_SOFTWARE_BP].support != PACKET_DISABLE) + { + char *buf = alloca (rs->remote_packet_size); + char *p = buf; + + *(p++) = 'z'; + *(p++) = '0'; + *(p++) = ','; + + addr = remote_address_masked (addr); + p += hexnumstr (p, (ULONGEST) addr); + BREAKPOINT_FROM_PC (&addr, &bp_size); + sprintf (p, ",%d", bp_size); + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + return (buf[0] == 'E'); + } + #ifdef REMOTE_BREAKPOINT return target_write_memory (addr, contents_cache, sizeof big_break_insn); #else @@ -3146,6 +4723,175 @@ remote_remove_breakpoint (addr, contents_cache) #endif /* REMOTE_BREAKPOINT */ } +static int +watchpoint_to_Z_packet (int type) +{ + switch (type) + { + case hw_write: + return 2; + break; + case hw_read: + return 3; + break; + case hw_access: + return 4; + break; + default: + internal_error (__FILE__, __LINE__, + "hw_bp_to_z: bad watchpoint type %d", type); + } +} + +/* FIXME: This function should be static and a member of the remote + target vector. */ + +int +remote_insert_watchpoint (CORE_ADDR addr, int len, int type) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + char *p; + enum Z_packet_type packet = watchpoint_to_Z_packet (type); + + if (remote_protocol_Z[packet].support == PACKET_DISABLE) + error ("Can't set hardware watchpoints without the '%s' (%s) packet\n", + remote_protocol_Z[packet].name, + remote_protocol_Z[packet].title); + + sprintf (buf, "Z%x,", packet); + p = strchr (buf, '\0'); + addr = remote_address_masked (addr); + p += hexnumstr (p, (ULONGEST) addr); + sprintf (p, ",%x", len); + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + switch (packet_ok (buf, &remote_protocol_Z[packet])) + { + case PACKET_ERROR: + case PACKET_UNKNOWN: + return -1; + case PACKET_OK: + return 0; + } + internal_error (__FILE__, __LINE__, + "remote_insert_watchpoint: reached end of function"); +} + +/* FIXME: This function should be static and a member of the remote + target vector. */ + +int +remote_remove_watchpoint (CORE_ADDR addr, int len, int type) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + char *p; + enum Z_packet_type packet = watchpoint_to_Z_packet (type); + + if (remote_protocol_Z[packet].support == PACKET_DISABLE) + error ("Can't clear hardware watchpoints without the '%s' (%s) packet\n", + remote_protocol_Z[packet].name, + remote_protocol_Z[packet].title); + + sprintf (buf, "z%x,", packet); + p = strchr (buf, '\0'); + addr = remote_address_masked (addr); + p += hexnumstr (p, (ULONGEST) addr); + sprintf (p, ",%x", len); + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + switch (packet_ok (buf, &remote_protocol_Z[packet])) + { + case PACKET_ERROR: + case PACKET_UNKNOWN: + return -1; + case PACKET_OK: + return 0; + } + internal_error (__FILE__, __LINE__, + "remote_remove_watchpoint: reached end of function"); +} + +/* FIXME: This function should be static and a member of the remote + target vector. */ + +int +remote_insert_hw_breakpoint (CORE_ADDR addr, int len) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + char *p = buf; + + if (remote_protocol_Z[Z_PACKET_HARDWARE_BP].support == PACKET_DISABLE) + error ("Can't set hardware breakpoint without the '%s' (%s) packet\n", + remote_protocol_Z[Z_PACKET_HARDWARE_BP].name, + remote_protocol_Z[Z_PACKET_HARDWARE_BP].title); + + *(p++) = 'Z'; + *(p++) = '1'; + *(p++) = ','; + + addr = remote_address_masked (addr); + p += hexnumstr (p, (ULONGEST) addr); + sprintf (p, ",%x", len); + + putpkt (buf); + getpkt (buf, (rs->remote_packet_size), 0); + + switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_HARDWARE_BP])) + { + case PACKET_ERROR: + case PACKET_UNKNOWN: + return -1; + case PACKET_OK: + return 0; + } + internal_error (__FILE__, __LINE__, + "remote_remove_watchpoint: reached end of function"); +} + +/* FIXME: This function should be static and a member of the remote + target vector. */ + +int +remote_remove_hw_breakpoint (CORE_ADDR addr, int len) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + char *p = buf; + + if (remote_protocol_Z[Z_PACKET_HARDWARE_BP].support == PACKET_DISABLE) + error ("Can't clear hardware breakpoint without the '%s' (%s) packet\n", + remote_protocol_Z[Z_PACKET_HARDWARE_BP].name, + remote_protocol_Z[Z_PACKET_HARDWARE_BP].title); + + *(p++) = 'z'; + *(p++) = '1'; + *(p++) = ','; + + addr = remote_address_masked (addr); + p += hexnumstr (p, (ULONGEST) addr); + sprintf (p, ",%x", len); + + putpkt(buf); + getpkt (buf, (rs->remote_packet_size), 0); + + switch (packet_ok (buf, &remote_protocol_Z[Z_PACKET_HARDWARE_BP])) + { + case PACKET_ERROR: + case PACKET_UNKNOWN: + return -1; + case PACKET_OK: + return 0; + } + internal_error (__FILE__, __LINE__, + "remote_remove_watchpoint: reached end of function"); +} + /* Some targets are only capable of doing downloads, and afterwards they switch to the remote serial protocol. This function provides a clean way to get from the download target to the remote target. @@ -3157,9 +4903,7 @@ remote_remove_breakpoint (addr, contents_cache) already..." message. Usually a call to pop_target() suffices. */ void -push_remote_target (name, from_tty) - char *name; - int from_tty; +push_remote_target (char *name, int from_tty) { printf_filtered ("Switching to remote protocol\n"); remote_open (name, from_tty); @@ -3169,11 +4913,8 @@ push_remote_target (name, from_tty) certain remote_ops overridden. */ void -open_remote_target (name, from_tty, target, extended_p) - char *name; - int from_tty; - struct target_ops *target; - int extended_p; +open_remote_target (char *name, int from_tty, struct target_ops *target, + int extended_p) { printf_filtered ("Selecting the %sremote protocol\n", (extended_p ? "extended-" : "")); @@ -3182,26 +4923,24 @@ open_remote_target (name, from_tty, target, extended_p) /* Table used by the crc32 function to calcuate the checksum. */ -static unsigned long crc32_table[256] = {0, 0}; +static unsigned long crc32_table[256] = +{0, 0}; static unsigned long -crc32 (buf, len, crc) - unsigned char *buf; - int len; - unsigned int crc; +crc32 (unsigned char *buf, int len, unsigned int crc) { - if (! crc32_table[1]) + if (!crc32_table[1]) { /* Initialize the CRC table and the decoding table. */ int i, j; unsigned int c; for (i = 0; i < 256; i++) - { - for (c = i << 24, j = 8; j > 0; --j) - c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); - crc32_table[i] = c; - } + { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); + crc32_table[i] = c; + } } while (len--) @@ -3219,16 +4958,23 @@ crc32 (buf, len, crc) Useful for verifying the image on the target against the exec file. Depends on the target understanding the new "qCRC:" request. */ +/* FIXME: cagney/1999-10-26: This command should be broken down into a + target method (target verify memory) and generic version of the + actual command. This will allow other high-level code (especially + generic_load()) to make use of this target functionality. */ + static void -compare_sections_command (args, from_tty) - char *args; - int from_tty; +compare_sections_command (char *args, int from_tty) { + struct remote_state *rs = get_remote_state (); asection *s; unsigned long host_crc, target_crc; extern bfd *exec_bfd; struct cleanup *old_chain; - char *tmp, *sectdata, *sectname, buf[PBUFSIZ]; + char *tmp; + char *sectdata; + const char *sectname; + char *buf = alloca (rs->remote_packet_size); bfd_size_type size; bfd_vma lma; int matched = 0; @@ -3240,20 +4986,20 @@ compare_sections_command (args, from_tty) strcmp (current_target.to_shortname, "remote") != 0) error ("command can only be used with remote target"); - for (s = exec_bfd->sections; s; s = s->next) + for (s = exec_bfd->sections; s; s = s->next) { if (!(s->flags & SEC_LOAD)) - continue; /* skip non-loadable section */ + continue; /* skip non-loadable section */ size = bfd_get_section_size_before_reloc (s); if (size == 0) - continue; /* skip zero-length section */ + continue; /* skip zero-length section */ - sectname = (char *) bfd_get_section_name (exec_bfd, s); + sectname = bfd_get_section_name (exec_bfd, s); if (args && strcmp (args, sectname) != 0) - continue; /* not the section selected by user */ + continue; /* not the section selected by user */ - matched = 1; /* do this section */ + matched = 1; /* do this section */ lma = s->lma; /* FIXME: assumes lma can fit into long */ sprintf (buf, "qCRC:%lx,%lx", (long) lma, (long) size); @@ -3261,11 +5007,11 @@ compare_sections_command (args, from_tty) /* be clever; compute the host_crc before waiting for target reply */ sectdata = xmalloc (size); - old_chain = make_cleanup (free, sectdata); + old_chain = make_cleanup (xfree, sectdata); bfd_get_section_contents (exec_bfd, s, sectdata, 0, size); host_crc = crc32 ((unsigned char *) sectdata, size, 0xffffffff); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); if (buf[0] == 'E') error ("target memory fault, section %s, range 0x%08x -- 0x%08x", sectname, lma, lma + size); @@ -3275,15 +5021,15 @@ compare_sections_command (args, from_tty) for (target_crc = 0, tmp = &buf[1]; *tmp; tmp++) target_crc = target_crc * 16 + fromhex (*tmp); - printf_filtered ("Section %s, range 0x%08x -- 0x%08x: ", - sectname, lma, lma + size); + printf_filtered ("Section %s, range 0x%s -- 0x%s: ", + sectname, paddr (lma), paddr (lma + size)); if (host_crc == target_crc) printf_filtered ("matched.\n"); else - { - printf_filtered ("MIS-MATCHED!\n"); - mismatched++; - } + { + printf_filtered ("MIS-MATCHED!\n"); + mismatched++; + } do_cleanups (old_chain); } @@ -3295,41 +5041,37 @@ the loaded file\n"); } static int -remote_query (query_type, buf, outbuf, bufsiz) - int query_type; - char *buf; - char *outbuf; - int *bufsiz; +remote_query (int query_type, char *buf, char *outbuf, int *bufsiz) { + struct remote_state *rs = get_remote_state (); int i; - char buf2[PBUFSIZ]; + char *buf2 = alloca (rs->remote_packet_size); char *p2 = &buf2[0]; - char *p = buf; - if (! bufsiz) + if (!bufsiz) error ("null pointer to remote bufer size specified"); - /* minimum outbuf size is PBUFSIZE - if bufsiz is not large enough let + /* minimum outbuf size is (rs->remote_packet_size) - if bufsiz is not large enough let the caller know and return what the minimum size is */ /* Note: a zero bufsiz can be used to query the minimum buffer size */ - if ( *bufsiz < PBUFSIZ ) + if (*bufsiz < (rs->remote_packet_size)) { - *bufsiz = PBUFSIZ; + *bufsiz = (rs->remote_packet_size); return -1; } /* except for querying the minimum buffer size, target must be open */ - if (! remote_desc) + if (!remote_desc) error ("remote query is only available after target open"); /* we only take uppercase letters as query types, at least for now */ - if ( (query_type < 'A') || (query_type > 'Z') ) + if ((query_type < 'A') || (query_type > 'Z')) error ("invalid remote query type"); - if (! buf) + if (!buf) error ("null remote query specified"); - if (! outbuf) + if (!outbuf) error ("remote query requires a buffer to receive data"); outbuf[0] = '\0'; @@ -3342,39 +5084,97 @@ remote_query (query_type, buf, outbuf, bufsiz) plus one extra in case we are debugging (remote_debug), we have PBUFZIZ - 7 left to pack the query string */ i = 0; - while ( buf[i] && (i < (PBUFSIZ - 8)) ) + while (buf[i] && (i < ((rs->remote_packet_size) - 8))) { /* bad caller may have sent forbidden characters */ - if ( (!isprint(buf[i])) || (buf[i] == '$') || (buf[i] == '#') ) - error ("illegal characters in query string"); + if ((!isprint (buf[i])) || (buf[i] == '$') || (buf[i] == '#')) + error ("illegal characters in query string"); *p2++ = buf[i]; i++; } *p2 = buf[i]; - if ( buf[i] ) + if (buf[i]) error ("query larger than available buffer"); i = putpkt (buf2); - if ( i < 0 ) return i; + if (i < 0) + return i; - getpkt (outbuf, 0); + getpkt (outbuf, *bufsiz, 0); return 0; } static void -packet_command (args, from_tty) - char *args; - int from_tty; +remote_rcmd (char *command, + struct ui_file *outbuf) +{ + struct remote_state *rs = get_remote_state (); + int i; + char *buf = alloca (rs->remote_packet_size); + char *p = buf; + + if (!remote_desc) + error ("remote rcmd is only available after target open"); + + /* Send a NULL command across as an empty command */ + if (command == NULL) + command = ""; + + /* The query prefix */ + strcpy (buf, "qRcmd,"); + p = strchr (buf, '\0'); + + if ((strlen (buf) + strlen (command) * 2 + 8/*misc*/) > (rs->remote_packet_size)) + error ("\"monitor\" command ``%s'' is too long\n", command); + + /* Encode the actual command */ + bin2hex (command, p, 0); + + if (putpkt (buf) < 0) + error ("Communication problem with target\n"); + + /* get/display the response */ + while (1) + { + /* XXX - see also tracepoint.c:remote_get_noisy_reply() */ + buf[0] = '\0'; + getpkt (buf, (rs->remote_packet_size), 0); + if (buf[0] == '\0') + error ("Target does not support this command\n"); + if (buf[0] == 'O' && buf[1] != 'K') + { + remote_console_output (buf + 1); /* 'O' message from stub */ + continue; + } + if (strcmp (buf, "OK") == 0) + break; + if (strlen (buf) == 3 && buf[0] == 'E' + && isdigit (buf[1]) && isdigit (buf[2])) + { + error ("Protocol error with Rcmd"); + } + for (p = buf; p[0] != '\0' && p[1] != '\0'; p += 2) + { + char c = (fromhex (p[0]) << 4) + fromhex (p[1]); + fputc_unfiltered (c, outbuf); + } + break; + } +} + +static void +packet_command (char *args, int from_tty) { - char buf[PBUFSIZ]; + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); - if (! remote_desc) + if (!remote_desc) error ("command can only be used with remote target"); - if (! args) + if (!args) error ("remote-packet command requires packet text as argument"); puts_filtered ("sending: "); @@ -3382,7 +5182,7 @@ packet_command (args, from_tty) puts_filtered ("\n"); putpkt (args); - getpkt (buf, 0); + getpkt (buf, (rs->remote_packet_size), 0); puts_filtered ("received: "); print_packet (buf); puts_filtered ("\n"); @@ -3391,30 +5191,28 @@ packet_command (args, from_tty) #if 0 /* --------- UNIT_TEST for THREAD oriented PACKETS ------------------------- */ -static void display_thread_info PARAMS ((struct gdb_ext_thread_info *info)); +static void display_thread_info (struct gdb_ext_thread_info *info); -static void threadset_test_cmd PARAMS ((char *cmd, int tty)); +static void threadset_test_cmd (char *cmd, int tty); -static void threadalive_test PARAMS ((char *cmd, int tty)); +static void threadalive_test (char *cmd, int tty); -static void threadlist_test_cmd PARAMS ((char *cmd, int tty)); +static void threadlist_test_cmd (char *cmd, int tty); -int get_and_display_threadinfo PARAMS ((threadref *ref)); +int get_and_display_threadinfo (threadref * ref); -static void threadinfo_test_cmd PARAMS ((char *cmd, int tty)); +static void threadinfo_test_cmd (char *cmd, int tty); -static int thread_display_step PARAMS ((threadref *ref, void *context)); +static int thread_display_step (threadref * ref, void *context); -static void threadlist_update_test_cmd PARAMS ((char *cmd, int tty)); +static void threadlist_update_test_cmd (char *cmd, int tty); -static void init_remote_threadtests PARAMS ((void)); +static void init_remote_threadtests (void); -#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid */ +#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid */ static void -threadset_test_cmd (cmd, tty) - char *cmd; - int tty; +threadset_test_cmd (char *cmd, int tty) { int sample_thread = SAMPLE_THREAD; @@ -3424,24 +5222,20 @@ threadset_test_cmd (cmd, tty) static void -threadalive_test (cmd, tty) - char *cmd; - int tty; +threadalive_test (char *cmd, int tty) { int sample_thread = SAMPLE_THREAD; - if (remote_thread_alive (sample_thread)) + if (remote_thread_alive (pid_to_ptid (sample_thread))) printf_filtered ("PASS: Thread alive test\n"); else printf_filtered ("FAIL: Thread alive test\n"); } -void output_threadid PARAMS ((char *title, threadref * ref)); +void output_threadid (char *title, threadref * ref); void -output_threadid (title, ref) - char *title; - threadref *ref; +output_threadid (char *title, threadref *ref) { char hexid[20]; @@ -3451,9 +5245,7 @@ output_threadid (title, ref) } static void -threadlist_test_cmd (cmd, tty) - char *cmd; - int tty; +threadlist_test_cmd (char *cmd, int tty) { int startflag = 1; threadref nextthread; @@ -3475,8 +5267,7 @@ threadlist_test_cmd (cmd, tty) } void -display_thread_info (info) - struct gdb_ext_thread_info *info; +display_thread_info (struct gdb_ext_thread_info *info) { output_threadid ("Threadid: ", &info->threadid); printf_filtered ("Name: %s\n ", info->shortname); @@ -3485,8 +5276,7 @@ display_thread_info (info) } int -get_and_display_threadinfo (ref) - threadref *ref; +get_and_display_threadinfo (threadref *ref) { int result; int set; @@ -3500,9 +5290,7 @@ get_and_display_threadinfo (ref) } static void -threadinfo_test_cmd (cmd, tty) - char *cmd; - int tty; +threadinfo_test_cmd (char *cmd, int tty) { int athread = SAMPLE_THREAD; threadref thread; @@ -3515,18 +5303,14 @@ threadinfo_test_cmd (cmd, tty) } static int -thread_display_step (ref, context) - threadref *ref; - void *context; +thread_display_step (threadref *ref, void *context) { /* output_threadid(" threadstep ",ref); *//* simple test */ return get_and_display_threadinfo (ref); } static void -threadlist_update_test_cmd (cmd, tty) - char *cmd; - int tty; +threadlist_update_test_cmd (char *cmd, int tty) { printf_filtered ("Remote Threadlist update test\n"); remote_threadlist_iterator (thread_display_step, 0, CRAZY_MAX_THREADS); @@ -3549,77 +5333,682 @@ init_remote_threadtests (void) #endif /* 0 */ +/* Convert a thread ID to a string. Returns the string in a static + buffer. */ + +static char * +remote_pid_to_str (ptid_t ptid) +{ + static char buf[30]; + + sprintf (buf, "Thread %d", PIDGET (ptid)); + return buf; +} + static void -init_remote_ops () +init_remote_ops (void) { - remote_ops.to_shortname = "remote"; + remote_ops.to_shortname = "remote"; remote_ops.to_longname = "Remote serial target in gdb-specific protocol"; - remote_ops.to_doc = + remote_ops.to_doc = "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ -Specify the serial device it is connected to (e.g. /dev/ttya)."; - remote_ops.to_open = remote_open; - remote_ops.to_close = remote_close; +Specify the serial device it is connected to\n\ +(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.)."; + remote_ops.to_open = remote_open; + remote_ops.to_close = remote_close; remote_ops.to_detach = remote_detach; - remote_ops.to_resume = remote_resume; + remote_ops.to_resume = remote_resume; remote_ops.to_wait = remote_wait; remote_ops.to_fetch_registers = remote_fetch_registers; remote_ops.to_store_registers = remote_store_registers; remote_ops.to_prepare_to_store = remote_prepare_to_store; - remote_ops.to_xfer_memory = remote_xfer_memory; - remote_ops.to_files_info = remote_files_info; + remote_ops.to_xfer_memory = remote_xfer_memory; + remote_ops.to_files_info = remote_files_info; remote_ops.to_insert_breakpoint = remote_insert_breakpoint; remote_ops.to_remove_breakpoint = remote_remove_breakpoint; - remote_ops.to_kill = remote_kill; - remote_ops.to_load = generic_load; + remote_ops.to_kill = remote_kill; + remote_ops.to_load = generic_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_thread_alive = remote_thread_alive; + remote_ops.to_find_new_threads = remote_threads_info; + remote_ops.to_pid_to_str = remote_pid_to_str; + remote_ops.to_extra_thread_info = remote_threads_extra_info; remote_ops.to_stop = remote_stop; remote_ops.to_query = remote_query; + remote_ops.to_rcmd = remote_rcmd; remote_ops.to_stratum = process_stratum; - remote_ops.to_has_all_memory = 1; - remote_ops.to_has_memory = 1; - remote_ops.to_has_stack = 1; - remote_ops.to_has_registers = 1; - remote_ops.to_has_execution = 1; - remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */ - remote_ops.to_magic = OPS_MAGIC; + remote_ops.to_has_all_memory = 1; + remote_ops.to_has_memory = 1; + remote_ops.to_has_stack = 1; + remote_ops.to_has_registers = 1; + remote_ops.to_has_execution = 1; + remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */ + remote_ops.to_magic = OPS_MAGIC; } /* Set up the extended remote vector by making a copy of the standard remote vector and adding to it. */ static void -init_extended_remote_ops () +init_extended_remote_ops (void) { extended_remote_ops = remote_ops; - extended_remote_ops.to_shortname = "extended-remote"; - extended_remote_ops.to_longname = + extended_remote_ops.to_shortname = "extended-remote"; + extended_remote_ops.to_longname = "Extended remote serial target in gdb-specific protocol"; - extended_remote_ops.to_doc = + extended_remote_ops.to_doc = "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ Specify the serial device it is connected to (e.g. /dev/ttya).", - extended_remote_ops.to_open = extended_remote_open; + extended_remote_ops.to_open = extended_remote_open; extended_remote_ops.to_create_inferior = extended_remote_create_inferior; extended_remote_ops.to_mourn_inferior = extended_remote_mourn; -} +} + +/* + * Command: info remote-process + * + * This implements Cisco's version of the "info proc" command. + * + * This query allows the target stub to return an arbitrary string + * (or strings) giving arbitrary information about the target process. + * This is optional; the target stub isn't required to implement it. + * + * Syntax: qfProcessInfo request first string + * qsProcessInfo request subsequent string + * reply: 'O'<hex-encoded-string> + * 'l' last reply (empty) + */ + +static void +remote_info_process (char *args, int from_tty) +{ + struct remote_state *rs = get_remote_state (); + char *buf = alloca (rs->remote_packet_size); + + if (remote_desc == 0) + error ("Command can only be used when connected to the remote target."); + + putpkt ("qfProcessInfo"); + getpkt (buf, (rs->remote_packet_size), 0); + if (buf[0] == 0) + return; /* Silently: target does not support this feature. */ + + if (buf[0] == 'E') + error ("info proc: target error."); + + while (buf[0] == 'O') /* Capitol-O packet */ + { + remote_console_output (&buf[1]); + putpkt ("qsProcessInfo"); + getpkt (buf, (rs->remote_packet_size), 0); + } +} + +/* + * Target Cisco + */ + +static void +remote_cisco_open (char *name, int from_tty) +{ + if (name == 0) + error ("To open a remote debug connection, you need to specify what \n" + "device is attached to the remote system (e.g. host:port)."); + + /* See FIXME above */ + wait_forever_enabled_p = 1; + + target_preopen (from_tty); + + unpush_target (&remote_cisco_ops); + + remote_desc = serial_open (name); + if (!remote_desc) + perror_with_name (name); + + /* + * If a baud rate was specified on the gdb command line it will + * be greater than the initial value of -1. If it is, use it otherwise + * default to 9600 + */ + + baud_rate = (baud_rate > 0) ? baud_rate : 9600; + if (serial_setbaudrate (remote_desc, baud_rate)) + { + serial_close (remote_desc); + perror_with_name (name); + } + + serial_raw (remote_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + serial_flush_input (remote_desc); + + if (from_tty) + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } + + remote_cisco_mode = 1; + + push_target (&remote_cisco_ops); /* Switch to using cisco target now */ + + init_all_packet_configs (); + + general_thread = -2; + continue_thread = -2; + + /* Probe for ability to use "ThreadInfo" query, as required. */ + use_threadinfo_query = 1; + use_threadextra_query = 1; + + /* Without this, some commands which require an active target (such + as kill) won't work. This variable serves (at least) double duty + as both the pid of the target process (if it has such), and as a + flag indicating that a target is active. These functions should + be split out into seperate variables, especially since GDB will + someday have a notion of debugging several processes. */ + inferior_ptid = pid_to_ptid (MAGIC_NULL_PID); + + /* Start the remote connection; if error (0), discard this target. */ + + if (!catch_errors (remote_start_remote_dummy, (char *) 0, + "Couldn't establish connection to remote target\n", + RETURN_MASK_ALL)) + { + pop_target (); + return; + } +} + +static void +remote_cisco_close (int quitting) +{ + remote_cisco_mode = 0; + remote_close (quitting); +} + +static void +remote_cisco_mourn (void) +{ + remote_mourn_1 (&remote_cisco_ops); +} + +enum +{ + READ_MORE, + FATAL_ERROR, + ENTER_DEBUG, + DISCONNECT_TELNET +} +minitelnet_return; + +/* Shared between readsocket() and readtty(). The size is arbitrary, + however all targets are known to support a 400 character packet. */ +static char tty_input[400]; + +static int escape_count; +static int echo_check; +extern int quit_flag; + +static int +readsocket (void) +{ + int data; + + /* Loop until the socket doesn't have any more data */ + + while ((data = readchar (0)) >= 0) + { + /* Check for the escape sequence */ + if (data == '|') + { + /* If this is the fourth escape, get out */ + if (++escape_count == 4) + { + return ENTER_DEBUG; + } + else + { /* This is a '|', but not the fourth in a row. + Continue without echoing it. If it isn't actually + one of four in a row, it'll be echoed later. */ + continue; + } + } + else + /* Not a '|' */ + { + /* Ensure any pending '|'s are flushed. */ + + for (; escape_count > 0; escape_count--) + putchar ('|'); + } + + if (data == '\r') /* If this is a return character, */ + continue; /* - just supress it. */ + + if (echo_check != -1) /* Check for echo of user input. */ + { + if (tty_input[echo_check] == data) + { + gdb_assert (echo_check <= sizeof (tty_input)); + echo_check++; /* Character matched user input: */ + continue; /* Continue without echoing it. */ + } + else if ((data == '\n') && (tty_input[echo_check] == '\r')) + { /* End of the line (and of echo checking). */ + echo_check = -1; /* No more echo supression */ + continue; /* Continue without echoing. */ + } + else + { /* Failed check for echo of user input. + We now have some suppressed output to flush! */ + int j; + + for (j = 0; j < echo_check; j++) + putchar (tty_input[j]); + echo_check = -1; + } + } + putchar (data); /* Default case: output the char. */ + } + + if (data == SERIAL_TIMEOUT) /* Timeout returned from readchar. */ + return READ_MORE; /* Try to read some more */ + else + return FATAL_ERROR; /* Trouble, bail out */ +} + +static int +readtty (void) +{ + int tty_bytecount; + + /* First, read a buffer full from the terminal */ + tty_bytecount = read (fileno (stdin), tty_input, sizeof (tty_input) - 1); + if (tty_bytecount == -1) + { + perror ("readtty: read failed"); + return FATAL_ERROR; + } + + /* Remove a quoted newline. */ + if (tty_input[tty_bytecount - 1] == '\n' && + tty_input[tty_bytecount - 2] == '\\') /* line ending in backslash */ + { + tty_input[--tty_bytecount] = 0; /* remove newline */ + tty_input[--tty_bytecount] = 0; /* remove backslash */ + } + + /* Turn trailing newlines into returns */ + if (tty_input[tty_bytecount - 1] == '\n') + tty_input[tty_bytecount - 1] = '\r'; + + /* If the line consists of a ~, enter debugging mode. */ + if ((tty_input[0] == '~') && (tty_bytecount == 2)) + return ENTER_DEBUG; + + /* Make this a zero terminated string and write it out */ + tty_input[tty_bytecount] = 0; + if (serial_write (remote_desc, tty_input, tty_bytecount)) + { + perror_with_name ("readtty: write failed"); + return FATAL_ERROR; + } + + return READ_MORE; +} + +static int +minitelnet (void) +{ + fd_set input; /* file descriptors for select */ + int tablesize; /* max number of FDs for select */ + int status; + int quit_count = 0; + + extern int escape_count; /* global shared by readsocket */ + extern int echo_check; /* ditto */ + + escape_count = 0; + echo_check = -1; + + tablesize = 8 * sizeof (input); + + for (;;) + { + /* Check for anything from our socket - doesn't block. Note that + this must be done *before* the select as there may be + buffered I/O waiting to be processed. */ + + if ((status = readsocket ()) == FATAL_ERROR) + { + error ("Debugging terminated by communications error"); + } + else if (status != READ_MORE) + { + return (status); + } + + fflush (stdout); /* Flush output before blocking */ + + /* Now block on more socket input or TTY input */ + + FD_ZERO (&input); + FD_SET (fileno (stdin), &input); + FD_SET (deprecated_serial_fd (remote_desc), &input); + + status = select (tablesize, &input, 0, 0, 0); + if ((status == -1) && (errno != EINTR)) + { + error ("Communications error on select %d", errno); + } + + /* Handle Control-C typed */ + + if (quit_flag) + { + if ((++quit_count) == 2) + { + if (query ("Interrupt GDB? ")) + { + printf_filtered ("Interrupted by user.\n"); + throw_exception (RETURN_QUIT); + } + quit_count = 0; + } + quit_flag = 0; + + if (remote_break) + serial_send_break (remote_desc); + else + serial_write (remote_desc, "\003", 1); + + continue; + } + + /* Handle console input */ + + if (FD_ISSET (fileno (stdin), &input)) + { + quit_count = 0; + echo_check = 0; + status = readtty (); + if (status == READ_MORE) + continue; + + return status; /* telnet session ended */ + } + } +} + +static ptid_t +remote_cisco_wait (ptid_t ptid, struct target_waitstatus *status) +{ + if (minitelnet () != ENTER_DEBUG) + { + error ("Debugging session terminated by protocol error"); + } + putpkt ("?"); + return remote_wait (ptid, status); +} + +static void +init_remote_cisco_ops (void) +{ + remote_cisco_ops.to_shortname = "cisco"; + remote_cisco_ops.to_longname = "Remote serial target in cisco-specific protocol"; + remote_cisco_ops.to_doc = + "Use a remote machine via TCP, using a cisco-specific protocol.\n\ +Specify the serial device it is connected to (e.g. host:2020)."; + remote_cisco_ops.to_open = remote_cisco_open; + remote_cisco_ops.to_close = remote_cisco_close; + remote_cisco_ops.to_detach = remote_detach; + remote_cisco_ops.to_resume = remote_resume; + remote_cisco_ops.to_wait = remote_cisco_wait; + remote_cisco_ops.to_fetch_registers = remote_fetch_registers; + remote_cisco_ops.to_store_registers = remote_store_registers; + remote_cisco_ops.to_prepare_to_store = remote_prepare_to_store; + remote_cisco_ops.to_xfer_memory = remote_xfer_memory; + remote_cisco_ops.to_files_info = remote_files_info; + remote_cisco_ops.to_insert_breakpoint = remote_insert_breakpoint; + remote_cisco_ops.to_remove_breakpoint = remote_remove_breakpoint; + remote_cisco_ops.to_kill = remote_kill; + remote_cisco_ops.to_load = generic_load; + remote_cisco_ops.to_mourn_inferior = remote_cisco_mourn; + remote_cisco_ops.to_thread_alive = remote_thread_alive; + remote_cisco_ops.to_find_new_threads = remote_threads_info; + remote_cisco_ops.to_pid_to_str = remote_pid_to_str; + remote_cisco_ops.to_extra_thread_info = remote_threads_extra_info; + remote_cisco_ops.to_stratum = process_stratum; + remote_cisco_ops.to_has_all_memory = 1; + remote_cisco_ops.to_has_memory = 1; + remote_cisco_ops.to_has_stack = 1; + remote_cisco_ops.to_has_registers = 1; + remote_cisco_ops.to_has_execution = 1; + remote_cisco_ops.to_magic = OPS_MAGIC; +} + +static int +remote_can_async_p (void) +{ + /* We're async whenever the serial device is. */ + return (current_target.to_async_mask_value) && serial_can_async_p (remote_desc); +} + +static int +remote_is_async_p (void) +{ + /* We're async whenever the serial device is. */ + return (current_target.to_async_mask_value) && serial_is_async_p (remote_desc); +} + +/* Pass the SERIAL event on and up to the client. One day this code + will be able to delay notifying the client of an event until the + point where an entire packet has been received. */ + +static void (*async_client_callback) (enum inferior_event_type event_type, void *context); +static void *async_client_context; +static serial_event_ftype remote_async_serial_handler; + +static void +remote_async_serial_handler (struct serial *scb, void *context) +{ + /* Don't propogate error information up to the client. Instead let + the client find out about the error by querying the target. */ + async_client_callback (INF_REG_EVENT, async_client_context); +} + +static void +remote_async (void (*callback) (enum inferior_event_type event_type, void *context), void *context) +{ + if (current_target.to_async_mask_value == 0) + internal_error (__FILE__, __LINE__, + "Calling remote_async when async is masked"); + + if (callback != NULL) + { + serial_async (remote_desc, remote_async_serial_handler, NULL); + async_client_callback = callback; + async_client_context = context; + } + else + serial_async (remote_desc, NULL, NULL); +} + +/* Target async and target extended-async. + + This are temporary targets, until it is all tested. Eventually + async support will be incorporated int the usual 'remote' + target. */ + +static void +init_remote_async_ops (void) +{ + remote_async_ops.to_shortname = "async"; + remote_async_ops.to_longname = "Remote serial target in async version of the gdb-specific protocol"; + remote_async_ops.to_doc = + "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + remote_async_ops.to_open = remote_async_open; + remote_async_ops.to_close = remote_close; + remote_async_ops.to_detach = remote_async_detach; + remote_async_ops.to_resume = remote_async_resume; + remote_async_ops.to_wait = remote_async_wait; + remote_async_ops.to_fetch_registers = remote_fetch_registers; + remote_async_ops.to_store_registers = remote_store_registers; + remote_async_ops.to_prepare_to_store = remote_prepare_to_store; + remote_async_ops.to_xfer_memory = remote_xfer_memory; + remote_async_ops.to_files_info = remote_files_info; + remote_async_ops.to_insert_breakpoint = remote_insert_breakpoint; + remote_async_ops.to_remove_breakpoint = remote_remove_breakpoint; + remote_async_ops.to_terminal_inferior = remote_async_terminal_inferior; + remote_async_ops.to_terminal_ours = remote_async_terminal_ours; + remote_async_ops.to_kill = remote_async_kill; + remote_async_ops.to_load = generic_load; + remote_async_ops.to_mourn_inferior = remote_async_mourn; + remote_async_ops.to_thread_alive = remote_thread_alive; + remote_async_ops.to_find_new_threads = remote_threads_info; + remote_async_ops.to_pid_to_str = remote_pid_to_str; + remote_async_ops.to_extra_thread_info = remote_threads_extra_info; + remote_async_ops.to_stop = remote_stop; + remote_async_ops.to_query = remote_query; + remote_async_ops.to_rcmd = remote_rcmd; + remote_async_ops.to_stratum = process_stratum; + remote_async_ops.to_has_all_memory = 1; + remote_async_ops.to_has_memory = 1; + remote_async_ops.to_has_stack = 1; + remote_async_ops.to_has_registers = 1; + remote_async_ops.to_has_execution = 1; + remote_async_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */ + remote_async_ops.to_can_async_p = remote_can_async_p; + remote_async_ops.to_is_async_p = remote_is_async_p; + remote_async_ops.to_async = remote_async; + remote_async_ops.to_async_mask_value = 1; + remote_async_ops.to_magic = OPS_MAGIC; +} + +/* Set up the async extended remote vector by making a copy of the standard + remote vector and adding to it. */ + +static void +init_extended_async_remote_ops (void) +{ + extended_async_remote_ops = remote_async_ops; + + extended_async_remote_ops.to_shortname = "extended-async"; + extended_async_remote_ops.to_longname = + "Extended remote serial target in async gdb-specific protocol"; + extended_async_remote_ops.to_doc = + "Use a remote computer via a serial line, using an async gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", + extended_async_remote_ops.to_open = extended_remote_async_open; + extended_async_remote_ops.to_create_inferior = extended_remote_async_create_inferior; + extended_async_remote_ops.to_mourn_inferior = extended_remote_mourn; +} + +static void +set_remote_cmd (char *args, int from_tty) +{ +} + +static void +show_remote_cmd (char *args, int from_tty) +{ + + show_remote_protocol_Z_packet_cmd (args, from_tty); + show_remote_protocol_e_packet_cmd (args, from_tty); + show_remote_protocol_E_packet_cmd (args, from_tty); + show_remote_protocol_P_packet_cmd (args, from_tty); + show_remote_protocol_qSymbol_packet_cmd (args, from_tty); + show_remote_protocol_binary_download_cmd (args, from_tty); +} + +static void +build_remote_gdbarch_data (void) +{ + remote_address_size = TARGET_ADDR_BIT; +} + +/* Saved pointer to previous owner of the new_objfile event. */ +static void (*remote_new_objfile_chain) (struct objfile *); + +/* Function to be called whenever a new objfile (shlib) is detected. */ +static void +remote_new_objfile (struct objfile *objfile) +{ + if (remote_desc != 0) /* Have a remote connection */ + { + remote_check_symbols (objfile); + } + /* Call predecessor on chain, if any. */ + if (remote_new_objfile_chain != 0 && + remote_desc == 0) + remote_new_objfile_chain (objfile); +} void -_initialize_remote () +_initialize_remote (void) { + static struct cmd_list_element *remote_set_cmdlist; + static struct cmd_list_element *remote_show_cmdlist; + struct cmd_list_element *tmpcmd; + + /* architecture specific data */ + remote_gdbarch_data_handle = register_gdbarch_data (init_remote_state, + free_remote_state); + + /* Old tacky stuff. NOTE: This comes after the remote protocol so + that the remote protocol has been initialized. */ + register_gdbarch_swap (&remote_address_size, + sizeof (&remote_address_size), NULL); + register_gdbarch_swap (NULL, 0, build_remote_gdbarch_data); + init_remote_ops (); add_target (&remote_ops); init_extended_remote_ops (); add_target (&extended_remote_ops); - init_remote_threads (); + + init_remote_async_ops (); + add_target (&remote_async_ops); + + init_extended_async_remote_ops (); + add_target (&extended_async_remote_ops); + + init_remote_cisco_ops (); + add_target (&remote_cisco_ops); + + /* Hook into new objfile notification. */ + remote_new_objfile_chain = target_new_objfile_hook; + target_new_objfile_hook = remote_new_objfile; + #if 0 init_remote_threadtests (); #endif - add_cmd ("compare-sections", class_obscure, compare_sections_command, + /* set/show remote ... */ + + add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, "\ +Remote protocol specific variables\n\ +Configure various remote-protocol specific variables such as\n\ +the packets being used", + &remote_set_cmdlist, "set remote ", + 0/*allow-unknown*/, &setlist); + add_prefix_cmd ("remote", class_maintenance, show_remote_cmd, "\ +Remote protocol specific variables\n\ +Configure various remote-protocol specific variables such as\n\ +the packets being used", + &remote_show_cmdlist, "show remote ", + 0/*allow-unknown*/, &showlist); + + add_cmd ("compare-sections", class_obscure, compare_sections_command, "Compare section data on target to the exec file.\n\ -Argument is a single section name (default: all loaded sections).", +Argument is a single section name (default: all loaded sections).", &cmdlist); add_cmd ("packet", class_maintenance, packet_command, @@ -3631,48 +6020,150 @@ response packet. GDB supplies the initial `$' character, and the\n\ terminating `#' character and checksum.", &maintenancelist); -#ifdef REMOTE_CHAT add_show_from_set - (add_set_cmd ("remotechat", no_class, - var_zinteger, (char *)&remote_chat, - "Set remote port interacts with target.\n", - &setlist), - &showlist); -#endif /* REMOTE_CHAT */ - - add_show_from_set - (add_set_cmd ("remotetimeout", no_class, - var_integer, (char *)&remote_timeout, - "Set timeout value for remote read.\n", - &setlist), - &showlist); - - add_show_from_set - (add_set_cmd ("remotebreak", no_class, - var_integer, (char *)&remote_break, - "Set whether to send break if interrupted.\n", - &setlist), + (add_set_boolean_cmd ("remotebreak", no_class, &remote_break, + "Set whether to send break if interrupted.\n", + &setlist), &showlist); - add_show_from_set - (add_set_cmd ("remotewritesize", no_class, - var_integer, (char *)&remote_write_size, - "Set the maximum number of bytes per memory write packet.\n", - &setlist), - &showlist); + /* Install commands for configuring memory read/write packets. */ + + add_cmd ("remotewritesize", no_class, set_memory_write_packet_size, + "Set the maximum number of bytes per memory write packet (deprecated).\n", + &setlist); + add_cmd ("remotewritesize", no_class, show_memory_write_packet_size, + "Show the maximum number of bytes per memory write packet (deprecated).\n", + &showlist); + add_cmd ("memory-write-packet-size", no_class, + set_memory_write_packet_size, + "Set the maximum number of bytes per memory-write packet.\n" + "Specify the number of bytes in a packet or 0 (zero) for the\n" + "default packet size. The actual limit is further reduced\n" + "dependent on the target. Specify ``fixed'' to disable the\n" + "further restriction and ``limit'' to enable that restriction\n", + &remote_set_cmdlist); + add_cmd ("memory-read-packet-size", no_class, + set_memory_read_packet_size, + "Set the maximum number of bytes per memory-read packet.\n" + "Specify the number of bytes in a packet or 0 (zero) for the\n" + "default packet size. The actual limit is further reduced\n" + "dependent on the target. Specify ``fixed'' to disable the\n" + "further restriction and ``limit'' to enable that restriction\n", + &remote_set_cmdlist); + add_cmd ("memory-write-packet-size", no_class, + show_memory_write_packet_size, + "Show the maximum number of bytes per memory-write packet.\n", + &remote_show_cmdlist); + add_cmd ("memory-read-packet-size", no_class, + show_memory_read_packet_size, + "Show the maximum number of bytes per memory-read packet.\n", + &remote_show_cmdlist); - remote_address_size = TARGET_PTR_BIT; - add_show_from_set + add_show_from_set (add_set_cmd ("remoteaddresssize", class_obscure, - var_integer, (char *)&remote_address_size, + var_integer, (char *) &remote_address_size, "Set the maximum size of the address (in bits) \ in a memory packet.\n", &setlist), - &showlist); + &showlist); - add_show_from_set (add_set_cmd ("remotebinarydownload", no_class, - var_boolean, (char *) &remote_binary_download, - "Set binary downloads.\n", &setlist), - &showlist); -} + add_packet_config_cmd (&remote_protocol_binary_download, + "X", "binary-download", + set_remote_protocol_binary_download_cmd, + show_remote_protocol_binary_download_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 1); +#if 0 + /* XXXX - should ``set remotebinarydownload'' be retained for + compatibility. */ + add_show_from_set + (add_set_cmd ("remotebinarydownload", no_class, + var_boolean, (char *) &remote_binary_download, + "Set binary downloads.\n", &setlist), + &showlist); +#endif + add_info ("remote-process", remote_info_process, + "Query the remote system for process info."); + + add_packet_config_cmd (&remote_protocol_qSymbol, + "qSymbol", "symbol-lookup", + set_remote_protocol_qSymbol_packet_cmd, + show_remote_protocol_qSymbol_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + + add_packet_config_cmd (&remote_protocol_e, + "e", "step-over-range", + set_remote_protocol_e_packet_cmd, + show_remote_protocol_e_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + /* Disable by default. The ``e'' packet has nasty interactions with + the threading code - it relies on global state. */ + remote_protocol_e.detect = CMD_AUTO_BOOLEAN_FALSE; + update_packet_config (&remote_protocol_e); + + add_packet_config_cmd (&remote_protocol_E, + "E", "step-over-range-w-signal", + set_remote_protocol_E_packet_cmd, + show_remote_protocol_E_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + /* Disable by default. The ``e'' packet has nasty interactions with + the threading code - it relies on global state. */ + remote_protocol_E.detect = CMD_AUTO_BOOLEAN_FALSE; + update_packet_config (&remote_protocol_E); + + add_packet_config_cmd (&remote_protocol_P, + "P", "set-register", + set_remote_protocol_P_packet_cmd, + show_remote_protocol_P_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 1); + + add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_SOFTWARE_BP], + "Z0", "software-breakpoint", + set_remote_protocol_Z_software_bp_packet_cmd, + show_remote_protocol_Z_software_bp_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + + add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_HARDWARE_BP], + "Z1", "hardware-breakpoint", + set_remote_protocol_Z_hardware_bp_packet_cmd, + show_remote_protocol_Z_hardware_bp_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + + add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_WRITE_WP], + "Z2", "write-watchpoint", + set_remote_protocol_Z_write_wp_packet_cmd, + show_remote_protocol_Z_write_wp_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + + add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_READ_WP], + "Z3", "read-watchpoint", + set_remote_protocol_Z_read_wp_packet_cmd, + show_remote_protocol_Z_read_wp_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + + add_packet_config_cmd (&remote_protocol_Z[Z_PACKET_ACCESS_WP], + "Z4", "access-watchpoint", + set_remote_protocol_Z_access_wp_packet_cmd, + show_remote_protocol_Z_access_wp_packet_cmd, + &remote_set_cmdlist, &remote_show_cmdlist, + 0); + + /* Keep the old ``set remote Z-packet ...'' working. */ + tmpcmd = add_set_auto_boolean_cmd ("Z-packet", class_obscure, + &remote_Z_packet_detect, + "\ +Set use of remote protocol `Z' packets", &remote_set_cmdlist); + set_cmd_sfunc (tmpcmd, set_remote_protocol_Z_packet_cmd); + add_cmd ("Z-packet", class_obscure, show_remote_protocol_Z_packet_cmd, + "Show use of remote protocol `Z' packets ", + &remote_show_cmdlist); +} diff --git a/contrib/gdb/gdb/ser-unix.c b/contrib/gdb/gdb/ser-unix.c index d804de1..f7ab28a 100644 --- a/contrib/gdb/gdb/ser-unix.c +++ b/contrib/gdb/gdb/ser-unix.c @@ -1,37 +1,43 @@ /* Serial interface for local (hardwired) serial ports on Un*x like systems - Copyright 1992, 1993, 1994, 1998 Free Software Foundation, Inc. + Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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 "serial.h" +#include "ser-unix.h" + #include <fcntl.h> #include <sys/types.h> #include "terminal.h" -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif +#include <sys/socket.h> +#include <sys/time.h> + +#include "gdb_string.h" +#include "event-loop.h" #ifdef HAVE_TERMIOS struct hardwire_ttystate -{ - struct termios termios; -}; + { + struct termios termios; + }; #endif /* termios */ #ifdef HAVE_TERMIO @@ -42,59 +48,62 @@ struct hardwire_ttystate bewildering. So we don't attempt it. */ struct hardwire_ttystate -{ - struct termio termio; -}; + { + struct termio termio; + }; #endif /* termio */ #ifdef HAVE_SGTTY -/* Needed for the code which uses select(). We would include <sys/select.h> - too if it existed on all systems. */ -#include <sys/time.h> - struct hardwire_ttystate -{ - struct sgttyb sgttyb; - struct tchars tc; - struct ltchars ltc; - /* Line discipline flags. */ - int lmode; -}; + { + struct sgttyb sgttyb; + struct tchars tc; + struct ltchars ltc; + /* Line discipline flags. */ + int lmode; + }; #endif /* sgtty */ -static int hardwire_open PARAMS ((serial_t scb, const char *name)); -static void hardwire_raw PARAMS ((serial_t scb)); -static int wait_for PARAMS ((serial_t scb, int timeout)); -static int hardwire_readchar PARAMS ((serial_t scb, int timeout)); -static int rate_to_code PARAMS ((int rate)); -static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate)); -static int hardwire_write PARAMS ((serial_t scb, const char *str, int len)); -static void hardwire_close PARAMS ((serial_t scb)); -static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); -static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); -static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb)); -static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); -static int hardwire_noflush_set_tty_state PARAMS ((serial_t, serial_ttystate, - serial_ttystate)); -static void hardwire_print_tty_state PARAMS ((serial_t, serial_ttystate)); -static int hardwire_drain_output PARAMS ((serial_t)); -static int hardwire_flush_output PARAMS ((serial_t)); -static int hardwire_flush_input PARAMS ((serial_t)); -static int hardwire_send_break PARAMS ((serial_t)); -static int hardwire_setstopbits PARAMS ((serial_t, int)); - -void _initialize_ser_hardwire PARAMS ((void)); - -#ifdef __CYGWIN32__ -extern void (*ui_loop_hook) PARAMS ((int)); -#endif +static int hardwire_open (struct serial *scb, const char *name); +static void hardwire_raw (struct serial *scb); +static int wait_for (struct serial *scb, int timeout); +static int hardwire_readchar (struct serial *scb, int timeout); +static int do_hardwire_readchar (struct serial *scb, int timeout); +static int generic_readchar (struct serial *scb, int timeout, + int (*do_readchar) (struct serial *scb, + int timeout)); +static int rate_to_code (int rate); +static int hardwire_setbaudrate (struct serial *scb, int rate); +static void hardwire_close (struct serial *scb); +static int get_tty_state (struct serial *scb, + struct hardwire_ttystate * state); +static int set_tty_state (struct serial *scb, + struct hardwire_ttystate * state); +static serial_ttystate hardwire_get_tty_state (struct serial *scb); +static int hardwire_set_tty_state (struct serial *scb, serial_ttystate state); +static int hardwire_noflush_set_tty_state (struct serial *, serial_ttystate, + serial_ttystate); +static void hardwire_print_tty_state (struct serial *, serial_ttystate, + struct ui_file *); +static int hardwire_drain_output (struct serial *); +static int hardwire_flush_output (struct serial *); +static int hardwire_flush_input (struct serial *); +static int hardwire_send_break (struct serial *); +static int hardwire_setstopbits (struct serial *, int); + +static int do_unix_readchar (struct serial *scb, int timeout); +static timer_handler_func push_event; +static handler_func fd_event; +static void reschedule (struct serial *scb); + +void _initialize_ser_hardwire (void); + +extern int (*ui_loop_hook) (int); /* Open up a real live device for serial I/O */ static int -hardwire_open(scb, name) - serial_t scb; - const char *name; +hardwire_open (struct serial *scb, const char *name) { scb->fd = open (name, O_RDWR); if (scb->fd < 0) @@ -104,12 +113,10 @@ hardwire_open(scb, name) } static int -get_tty_state (scb, state) - serial_t scb; - struct hardwire_ttystate *state; +get_tty_state (struct serial *scb, struct hardwire_ttystate *state) { #ifdef HAVE_TERMIOS - if (tcgetattr(scb->fd, &state->termios) < 0) + if (tcgetattr (scb->fd, &state->termios) < 0) return -1; return 0; @@ -136,12 +143,10 @@ get_tty_state (scb, state) } static int -set_tty_state(scb, state) - serial_t scb; - struct hardwire_ttystate *state; +set_tty_state (struct serial *scb, struct hardwire_ttystate *state) { #ifdef HAVE_TERMIOS - if (tcsetattr(scb->fd, TCSANOW, &state->termios) < 0) + if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0) return -1; return 0; @@ -168,43 +173,39 @@ set_tty_state(scb, state) } static serial_ttystate -hardwire_get_tty_state(scb) - serial_t scb; +hardwire_get_tty_state (struct serial *scb) { struct hardwire_ttystate *state; - state = (struct hardwire_ttystate *)xmalloc(sizeof *state); + state = (struct hardwire_ttystate *) xmalloc (sizeof *state); - if (get_tty_state(scb, state)) + if (get_tty_state (scb, state)) return NULL; - return (serial_ttystate)state; + return (serial_ttystate) state; } static int -hardwire_set_tty_state(scb, ttystate) - serial_t scb; - serial_ttystate ttystate; +hardwire_set_tty_state (struct serial *scb, serial_ttystate ttystate) { struct hardwire_ttystate *state; - state = (struct hardwire_ttystate *)ttystate; + state = (struct hardwire_ttystate *) ttystate; - return set_tty_state(scb, state); + return set_tty_state (scb, state); } static int -hardwire_noflush_set_tty_state (scb, new_ttystate, old_ttystate) - serial_t scb; - serial_ttystate new_ttystate; - serial_ttystate old_ttystate; +hardwire_noflush_set_tty_state (struct serial *scb, + serial_ttystate new_ttystate, + serial_ttystate old_ttystate) { struct hardwire_ttystate new_state; #ifdef HAVE_SGTTY struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate; #endif - new_state = *(struct hardwire_ttystate *)new_ttystate; + new_state = *(struct hardwire_ttystate *) new_ttystate; /* Don't change in or out of raw mode; we don't want to flush input. termio and termios have no such restriction; for them flushing input @@ -228,63 +229,65 @@ hardwire_noflush_set_tty_state (scb, new_ttystate, old_ttystate) } static void -hardwire_print_tty_state (scb, ttystate) - serial_t scb; - serial_ttystate ttystate; +hardwire_print_tty_state (struct serial *scb, + serial_ttystate ttystate, + struct ui_file *stream) { struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate; int i; #ifdef HAVE_TERMIOS - printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n", - state->termios.c_iflag, state->termios.c_oflag); - printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x\n", - state->termios.c_cflag, state->termios.c_lflag); + fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n", + (int) state->termios.c_iflag, + (int) state->termios.c_oflag); + fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n", + (int) state->termios.c_cflag, + (int) state->termios.c_lflag); #if 0 /* This not in POSIX, and is not really documented by those systems which have it (at least not Sun). */ - printf_filtered ("c_line = 0x%x.\n", state->termios.c_line); + fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line); #endif - printf_filtered ("c_cc: "); + fprintf_filtered (stream, "c_cc: "); for (i = 0; i < NCCS; i += 1) - printf_filtered ("0x%x ", state->termios.c_cc[i]); - printf_filtered ("\n"); + fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]); + fprintf_filtered (stream, "\n"); #endif #ifdef HAVE_TERMIO - printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n", - state->termio.c_iflag, state->termio.c_oflag); - printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", - state->termio.c_cflag, state->termio.c_lflag, - state->termio.c_line); - printf_filtered ("c_cc: "); + fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n", + state->termio.c_iflag, state->termio.c_oflag); + fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", + state->termio.c_cflag, state->termio.c_lflag, + state->termio.c_line); + fprintf_filtered (stream, "c_cc: "); for (i = 0; i < NCC; i += 1) - printf_filtered ("0x%x ", state->termio.c_cc[i]); - printf_filtered ("\n"); + fprintf_filtered (stream, "0x%x ", state->termio.c_cc[i]); + fprintf_filtered (stream, "\n"); #endif #ifdef HAVE_SGTTY - printf_filtered ("sgttyb.sg_flags = 0x%x.\n", state->sgttyb.sg_flags); + fprintf_filtered (stream, "sgttyb.sg_flags = 0x%x.\n", + state->sgttyb.sg_flags); - printf_filtered ("tchars: "); - for (i = 0; i < (int)sizeof (struct tchars); i++) - printf_filtered ("0x%x ", ((unsigned char *)&state->tc)[i]); - printf_filtered ("\n"); + fprintf_filtered (stream, "tchars: "); + for (i = 0; i < (int) sizeof (struct tchars); i++) + fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->tc)[i]); + fprintf_filtered (stream, "\n"); - printf_filtered ("ltchars: "); - for (i = 0; i < (int)sizeof (struct ltchars); i++) - printf_filtered ("0x%x ", ((unsigned char *)&state->ltc)[i]); - printf_filtered ("\n"); + fprintf_filtered (stream, "ltchars: "); + for (i = 0; i < (int) sizeof (struct ltchars); i++) + fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->ltc)[i]); + fprintf_filtered (stream, "\n"); - printf_filtered ("lmode: 0x%x\n", state->lmode); + fprintf_filtered (stream, "lmode: 0x%x\n", state->lmode); #endif } /* Wait for the output to drain away, as opposed to flushing (discarding) it */ static int -hardwire_drain_output (scb) - serial_t scb; +hardwire_drain_output (struct serial *scb) { #ifdef HAVE_TERMIOS return tcdrain (scb->fd); @@ -309,12 +312,11 @@ hardwire_drain_output (scb) return (ioctl (scb->fd, TIOCSETP, &state.sgttyb)); } } -#endif +#endif } static int -hardwire_flush_output (scb) - serial_t scb; +hardwire_flush_output (struct serial *scb) { #ifdef HAVE_TERMIOS return tcflush (scb->fd, TCOFLUSH); @@ -327,15 +329,13 @@ hardwire_flush_output (scb) #ifdef HAVE_SGTTY /* This flushes both input and output, but we can't do better. */ return ioctl (scb->fd, TIOCFLUSH, 0); -#endif +#endif } static int -hardwire_flush_input (scb) - serial_t scb; +hardwire_flush_input (struct serial *scb) { - scb->bufcnt = 0; - scb->bufp = scb->buf; + ser_unix_flush_input (scb); #ifdef HAVE_TERMIOS return tcflush (scb->fd, TCIFLUSH); @@ -348,12 +348,11 @@ hardwire_flush_input (scb) #ifdef HAVE_SGTTY /* This flushes both input and output, but we can't do better. */ return ioctl (scb->fd, TIOCFLUSH, 0); -#endif +#endif } static int -hardwire_send_break (scb) - serial_t scb; +hardwire_send_break (struct serial *scb) { #ifdef HAVE_TERMIOS return tcsendbreak (scb->fd, 0); @@ -379,23 +378,22 @@ hardwire_send_break (scb) status = ioctl (scb->fd, TIOCCBRK, 0); return status; } -#endif +#endif } static void -hardwire_raw(scb) - serial_t scb; +hardwire_raw (struct serial *scb) { struct hardwire_ttystate state; - if (get_tty_state(scb, &state)) - fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); + if (get_tty_state (scb, &state)) + fprintf_unfiltered (gdb_stderr, "get_tty_state failed: %s\n", safe_strerror (errno)); #ifdef HAVE_TERMIOS state.termios.c_iflag = 0; state.termios.c_oflag = 0; state.termios.c_lflag = 0; - state.termios.c_cflag &= ~(CSIZE|PARENB); + state.termios.c_cflag &= ~(CSIZE | PARENB); state.termios.c_cflag |= CLOCAL | CS8; state.termios.c_cc[VMIN] = 0; state.termios.c_cc[VTIME] = 0; @@ -405,7 +403,7 @@ hardwire_raw(scb) state.termio.c_iflag = 0; state.termio.c_oflag = 0; state.termio.c_lflag = 0; - state.termio.c_cflag &= ~(CSIZE|PARENB); + state.termio.c_cflag &= ~(CSIZE | PARENB); state.termio.c_cflag |= CLOCAL | CS8; state.termio.c_cc[VMIN] = 0; state.termio.c_cc[VTIME] = 0; @@ -419,7 +417,7 @@ hardwire_raw(scb) scb->current_timeout = 0; if (set_tty_state (scb, &state)) - fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); + fprintf_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", safe_strerror (errno)); } /* Wait for input on scb, with timeout seconds. Returns 0 on success, @@ -429,48 +427,51 @@ hardwire_raw(scb) timeout occur in the read() in hardwire_read(). */ +/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent + ser_unix*() until the old TERMIOS/SGTTY/... timer code has been + flushed. . */ + +/* NOTE: cagney/1999-09-30: Much of the code below is dead. The only + possible values of the TIMEOUT parameter are ONE and ZERO. + Consequently all the code that tries to handle the possability of + an overflowed timer is unnecessary. */ + static int -wait_for(scb, timeout) - serial_t scb; - int timeout; +wait_for (struct serial *scb, int timeout) { -#ifndef __CYGWIN32__ - scb->timeout_remaining = 0; -#endif - #ifdef HAVE_SGTTY - { - struct timeval tv; - fd_set readfds; - - FD_ZERO (&readfds); - - tv.tv_sec = timeout; - tv.tv_usec = 0; - - FD_SET(scb->fd, &readfds); - - while (1) - { - int numfds; - - if (timeout >= 0) - numfds = select(scb->fd+1, &readfds, 0, 0, &tv); + while (1) + { + struct timeval tv; + fd_set readfds; + int numfds; + + /* NOTE: Some OS's can scramble the READFDS when the select() + call fails (ex the kernel with Red Hat 5.2). Initialize all + arguments before each call. */ + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO (&readfds); + FD_SET (scb->fd, &readfds); + + if (timeout >= 0) + numfds = select (scb->fd + 1, &readfds, 0, 0, &tv); + else + numfds = select (scb->fd + 1, &readfds, 0, 0, 0); + + if (numfds <= 0) + if (numfds == 0) + return SERIAL_TIMEOUT; + else if (errno == EINTR) + continue; else - numfds = select(scb->fd+1, &readfds, 0, 0, 0); + return SERIAL_ERROR; /* Got an error from select or poll */ - if (numfds <= 0) - if (numfds == 0) - return SERIAL_TIMEOUT; - else if (errno == EINTR) - continue; - else - return SERIAL_ERROR; /* Got an error from select or poll */ - - return 0; - } - } -#endif /* HAVE_SGTTY */ + return 0; + } +#endif /* HAVE_SGTTY */ #if defined HAVE_TERMIO || defined HAVE_TERMIOS if (timeout == scb->current_timeout) @@ -481,8 +482,8 @@ wait_for(scb, timeout) { struct hardwire_ttystate state; - if (get_tty_state(scb, &state)) - fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); + if (get_tty_state (scb, &state)) + fprintf_unfiltered (gdb_stderr, "get_tty_state failed: %s\n", safe_strerror (errno)); #ifdef HAVE_TERMIOS if (timeout < 0) @@ -534,68 +535,80 @@ wait_for(scb, timeout) #endif if (set_tty_state (scb, &state)) - fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); + fprintf_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", safe_strerror (errno)); return 0; } -#endif /* HAVE_TERMIO || HAVE_TERMIOS */ +#endif /* HAVE_TERMIO || HAVE_TERMIOS */ } /* Read a character with user-specified timeout. TIMEOUT is number of seconds to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns char if successful. Returns SERIAL_TIMEOUT if timeout expired, EOF if line dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */ + +/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent + ser_unix*() until the old TERMIOS/SGTTY/... timer code has been + flushed. */ + +/* NOTE: cagney/1999-09-16: This function is not identical to + ser_unix_readchar() as part of replacing it with ser_unix*() + merging will be required - this code handles the case where read() + times out due to no data while ser_unix_readchar() doesn't expect + that. */ + static int -hardwire_readchar (scb, timeout) - serial_t scb; - int timeout; +do_hardwire_readchar (struct serial *scb, int timeout) { - int status; -#ifdef __CYGWIN32__ - int t; -#endif + int status, delta; + int detach = 0; - if (scb->bufcnt-- > 0) - return *scb->bufp++; - -#ifdef __CYGWIN32__ if (timeout > 0) timeout++; -#endif + /* We have to be able to keep the GUI alive here, so we break the original + timeout into steps of 1 second, running the "keep the GUI alive" hook + each time through the loop. + Also, timeout = 0 means to poll, so we just set the delta to 0, so we + will only go through the loop once. */ + + delta = (timeout == 0 ? 0 : 1); while (1) { -#ifdef __CYGWIN32__ - t = timeout == 0 ? 0 : 1; - scb->timeout_remaining = timeout < 0 ? timeout : timeout - t; - status = wait_for (scb, t); - /* -2 means disable timer */ + /* N.B. The UI may destroy our world (for instance by calling + remote_stop,) in which case we want to get out of here as + quickly as possible. It is not safe to touch scb, since + someone else might have freed it. The ui_loop_hook signals that + we should exit by returning 1. */ + if (ui_loop_hook) - ui_loop_hook (-2); -#else - status = wait_for (scb, timeout); -#endif + detach = ui_loop_hook (0); + + if (detach) + return SERIAL_TIMEOUT; + + scb->timeout_remaining = (timeout < 0 ? timeout : timeout - delta); + status = wait_for (scb, delta); + if (status < 0) return status; - scb->bufcnt = read (scb->fd, scb->buf, BUFSIZ); + status = read (scb->fd, scb->buf, BUFSIZ); - if (scb->bufcnt <= 0) + if (status <= 0) { - if (scb->bufcnt == 0) + if (status == 0) { /* Zero characters means timeout (it could also be EOF, but - we don't (yet at least) distinguish). */ + we don't (yet at least) distinguish). */ if (scb->timeout_remaining > 0) { timeout = scb->timeout_remaining; continue; } -#ifdef __CYGWIN32__ - else if (scb->timeout_remaining < 0) - continue; -#endif + else if (scb->timeout_remaining < 0) + continue; else return SERIAL_TIMEOUT; } @@ -605,12 +618,20 @@ hardwire_readchar (scb, timeout) return SERIAL_ERROR; /* Got an error from read */ } + scb->bufcnt = status; scb->bufcnt--; scb->bufp = scb->buf; return *scb->bufp++; } } +static int +hardwire_readchar (struct serial *scb, int timeout) +{ + return generic_readchar (scb, timeout, do_hardwire_readchar); +} + + #ifndef B19200 #define B19200 EXTA #endif @@ -629,65 +650,152 @@ static struct } baudtab[] = { - {50, B50}, - {75, B75}, - {110, B110}, - {134, B134}, - {150, B150}, - {200, B200}, - {300, B300}, - {600, B600}, - {1200, B1200}, - {1800, B1800}, - {2400, B2400}, - {4800, B4800}, - {9600, B9600}, - {19200, B19200}, - {38400, B38400}, + { + 50, B50 + } + , + { + 75, B75 + } + , + { + 110, B110 + } + , + { + 134, B134 + } + , + { + 150, B150 + } + , + { + 200, B200 + } + , + { + 300, B300 + } + , + { + 600, B600 + } + , + { + 1200, B1200 + } + , + { + 1800, B1800 + } + , + { + 2400, B2400 + } + , + { + 4800, B4800 + } + , + { + 9600, B9600 + } + , + { + 19200, B19200 + } + , + { + 38400, B38400 + } + , #ifdef B57600 - {57600, B57600}, -#endif -#ifdef B76800 - {76800, B76800}, + { + 57600, B57600 + } + , #endif #ifdef B115200 - {115200, B115200}, + { + 115200, B115200 + } + , #endif #ifdef B230400 - {230400, B230400}, + { + 230400, B230400 + } + , #endif #ifdef B460800 - {460800, B460800}, + { + 460800, B460800 + } + , #endif - {-1, -1}, + { + -1, -1 + } + , }; -static int -rate_to_code(rate) - int rate; +static int +rate_to_code (int rate) { int i; for (i = 0; baudtab[i].rate != -1; i++) - if (rate == baudtab[i].rate) - return baudtab[i].code; - + { + /* test for perfect macth. */ + if (rate == baudtab[i].rate) + return baudtab[i].code; + else + { + /* check if it is in between valid values. */ + if (rate < baudtab[i].rate) + { + if (i) + { + warning ("Invalid baud rate %d. Closest values are %d and %d.", + rate, baudtab[i - 1].rate, baudtab[i].rate); + } + else + { + warning ("Invalid baud rate %d. Minimum value is %d.", + rate, baudtab[0].rate); + } + return -1; + } + } + } + + /* The requested speed was too large. */ + warning ("Invalid baud rate %d. Maximum value is %d.", + rate, baudtab[i - 1].rate); return -1; } static int -hardwire_setbaudrate(scb, rate) - serial_t scb; - int rate; +hardwire_setbaudrate (struct serial *scb, int rate) { struct hardwire_ttystate state; + int baud_code = rate_to_code (rate); + + if (baud_code < 0) + { + /* The baud rate was not valid. + A warning has already been issued. */ + errno = EINVAL; + return -1; + } - if (get_tty_state(scb, &state)) + if (get_tty_state (scb, &state)) return -1; #ifdef HAVE_TERMIOS - cfsetospeed (&state.termios, rate_to_code (rate)); - cfsetispeed (&state.termios, rate_to_code (rate)); + cfsetospeed (&state.termios, baud_code); + cfsetispeed (&state.termios, baud_code); #endif #ifdef HAVE_TERMIO @@ -696,26 +804,24 @@ hardwire_setbaudrate(scb, rate) #endif state.termio.c_cflag &= ~(CBAUD | CIBAUD); - state.termio.c_cflag |= rate_to_code (rate); + state.termio.c_cflag |= baud_code; #endif #ifdef HAVE_SGTTY - state.sgttyb.sg_ispeed = rate_to_code (rate); - state.sgttyb.sg_ospeed = rate_to_code (rate); + state.sgttyb.sg_ispeed = baud_code; + state.sgttyb.sg_ospeed = baud_code; #endif return set_tty_state (scb, &state); } static int -hardwire_setstopbits(scb, num) - serial_t scb; - int num; +hardwire_setstopbits (struct serial *scb, int num) { struct hardwire_ttystate state; int newbit; - if (get_tty_state(scb, &state)) + if (get_tty_state (scb, &state)) return -1; switch (num) @@ -735,14 +841,14 @@ hardwire_setstopbits(scb, num) if (!newbit) state.termios.c_cflag &= ~CSTOPB; else - state.termios.c_cflag |= CSTOPB; /* two bits */ + state.termios.c_cflag |= CSTOPB; /* two bits */ #endif #ifdef HAVE_TERMIO if (!newbit) state.termio.c_cflag &= ~CSTOPB; else - state.termio.c_cflag |= CSTOPB; /* two bits */ + state.termio.c_cflag |= CSTOPB; /* two bits */ #endif #ifdef HAVE_SGTTY @@ -752,17 +858,258 @@ hardwire_setstopbits(scb, num) return set_tty_state (scb, &state); } +static void +hardwire_close (struct serial *scb) +{ + if (scb->fd < 0) + return; + + close (scb->fd); + scb->fd = -1; +} + + +/* Generic operations used by all UNIX/FD based serial interfaces. */ + +serial_ttystate +ser_unix_nop_get_tty_state (struct serial *scb) +{ + /* allocate a dummy */ + return (serial_ttystate) XMALLOC (int); +} + +int +ser_unix_nop_set_tty_state (struct serial *scb, serial_ttystate ttystate) +{ + return 0; +} + +void +ser_unix_nop_raw (struct serial *scb) +{ + return; /* Always in raw mode */ +} + +/* Wait for input on scb, with timeout seconds. Returns 0 on success, + otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */ + +int +ser_unix_wait_for (struct serial *scb, int timeout) +{ + while (1) + { + int numfds; + struct timeval tv; + fd_set readfds, exceptfds; + + /* NOTE: Some OS's can scramble the READFDS when the select() + call fails (ex the kernel with Red Hat 5.2). Initialize all + arguments before each call. */ + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO (&readfds); + FD_ZERO (&exceptfds); + FD_SET (scb->fd, &readfds); + FD_SET (scb->fd, &exceptfds); + + if (timeout >= 0) + numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv); + else + numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0); + + if (numfds <= 0) + { + if (numfds == 0) + return SERIAL_TIMEOUT; + else if (errno == EINTR) + continue; + else + return SERIAL_ERROR; /* Got an error from select or poll */ + } + + return 0; + } +} + +/* Read a character with user-specified timeout. TIMEOUT is number of seconds + to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns + char if successful. Returns -2 if timeout expired, EOF if line dropped + dead, or -3 for any other error (see errno in that case). */ + static int -hardwire_write(scb, str, len) - serial_t scb; - const char *str; - int len; +do_unix_readchar (struct serial *scb, int timeout) +{ + int status; + int delta; + + /* We have to be able to keep the GUI alive here, so we break the original + timeout into steps of 1 second, running the "keep the GUI alive" hook + each time through the loop. + + Also, timeout = 0 means to poll, so we just set the delta to 0, so we + will only go through the loop once. */ + + delta = (timeout == 0 ? 0 : 1); + while (1) + { + + /* N.B. The UI may destroy our world (for instance by calling + remote_stop,) in which case we want to get out of here as + quickly as possible. It is not safe to touch scb, since + someone else might have freed it. The ui_loop_hook signals that + we should exit by returning 1. */ + + if (ui_loop_hook) + { + if (ui_loop_hook (0)) + return SERIAL_TIMEOUT; + } + + status = ser_unix_wait_for (scb, delta); + if (timeout > 0) + timeout -= delta; + + /* If we got a character or an error back from wait_for, then we can + break from the loop before the timeout is completed. */ + + if (status != SERIAL_TIMEOUT) + { + break; + } + + /* If we have exhausted the original timeout, then generate + a SERIAL_TIMEOUT, and pass it out of the loop. */ + + else if (timeout == 0) + { + status = SERIAL_TIMEOUT; + break; + } + } + + if (status < 0) + return status; + + while (1) + { + status = read (scb->fd, scb->buf, BUFSIZ); + if (status != -1 || errno != EINTR) + break; + } + + if (status <= 0) + { + if (status == 0) + return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to + distinguish between EOF & timeouts + someday] */ + else + return SERIAL_ERROR; /* Got an error from read */ + } + + scb->bufcnt = status; + scb->bufcnt--; + scb->bufp = scb->buf; + return *scb->bufp++; +} + +/* Perform operations common to both old and new readchar. */ + +/* Return the next character from the input FIFO. If the FIFO is + empty, call the SERIAL specific routine to try and read in more + characters. + + Initially data from the input FIFO is returned (fd_event() + pre-reads the input into that FIFO. Once that has been emptied, + further data is obtained by polling the input FD using the device + specific readchar() function. Note: reschedule() is called after + every read. This is because there is no guarentee that the lower + level fd_event() poll_event() code (which also calls reschedule()) + will be called. */ + +static int +generic_readchar (struct serial *scb, int timeout, + int (do_readchar) (struct serial *scb, int timeout)) +{ + int ch; + if (scb->bufcnt > 0) + { + ch = *scb->bufp; + scb->bufcnt--; + scb->bufp++; + } + else if (scb->bufcnt < 0) + { + /* Some errors/eof are are sticky. */ + ch = scb->bufcnt; + } + else + { + ch = do_readchar (scb, timeout); + if (ch < 0) + { + switch ((enum serial_rc) ch) + { + case SERIAL_EOF: + case SERIAL_ERROR: + /* Make the error/eof stick. */ + scb->bufcnt = ch; + break; + case SERIAL_TIMEOUT: + scb->bufcnt = 0; + break; + } + } + } + reschedule (scb); + return ch; +} + +int +ser_unix_readchar (struct serial *scb, int timeout) +{ + return generic_readchar (scb, timeout, do_unix_readchar); +} + +int +ser_unix_nop_noflush_set_tty_state (struct serial *scb, + serial_ttystate new_ttystate, + serial_ttystate old_ttystate) +{ + return 0; +} + +void +ser_unix_nop_print_tty_state (struct serial *scb, + serial_ttystate ttystate, + struct ui_file *stream) +{ + /* Nothing to print. */ + return; +} + +int +ser_unix_nop_setbaudrate (struct serial *scb, int rate) +{ + return 0; /* Never fails! */ +} + +int +ser_unix_nop_setstopbits (struct serial *scb, int num) +{ + return 0; /* Never fails! */ +} + +int +ser_unix_write (struct serial *scb, const char *str, int len) { int cc; while (len > 0) { - cc = write(scb->fd, str, len); + cc = write (scb->fd, str, len); if (cc < 0) return 1; @@ -772,40 +1119,245 @@ hardwire_write(scb, str, len) return 0; } -static void -hardwire_close(scb) - serial_t scb; +int +ser_unix_nop_flush_output (struct serial *scb) { - if (scb->fd < 0) - return; + return 0; +} - close(scb->fd); - scb->fd = -1; +int +ser_unix_flush_input (struct serial *scb) +{ + if (scb->bufcnt >= 0) + { + scb->bufcnt = 0; + scb->bufp = scb->buf; + return 0; + } + else + return SERIAL_ERROR; +} + +int +ser_unix_nop_send_break (struct serial *scb) +{ + return 0; +} + +int +ser_unix_nop_drain_output (struct serial *scb) +{ + return 0; } -static struct serial_ops hardwire_ops = -{ - "hardwire", - 0, - hardwire_open, - hardwire_close, - hardwire_readchar, - hardwire_write, - hardwire_flush_output, - hardwire_flush_input, - hardwire_send_break, - hardwire_raw, - hardwire_get_tty_state, - hardwire_set_tty_state, - hardwire_print_tty_state, - hardwire_noflush_set_tty_state, - hardwire_setbaudrate, - hardwire_setstopbits, - hardwire_drain_output, /* wait for output to drain */ + + +/* Event handling for ASYNC serial code. + + At any time the SERIAL device either: has an empty FIFO and is + waiting on a FD event; or has a non-empty FIFO/error condition and + is constantly scheduling timer events. + + ASYNC only stops pestering its client when it is de-async'ed or it + is told to go away. */ + +/* Value of scb->async_state: */ +enum { + /* >= 0 (TIMER_SCHEDULED) */ + /* The ID of the currently scheduled timer event. This state is + rarely encountered. Timer events are one-off so as soon as the + event is delivered the state is shanged to NOTHING_SCHEDULED. */ + FD_SCHEDULED = -1, + /* The fd_event() handler is scheduled. It is called when ever the + file descriptor becomes ready. */ + NOTHING_SCHEDULED = -2 + /* Either no task is scheduled (just going into ASYNC mode) or a + timer event has just gone off and the current state has been + forced into nothing scheduled. */ }; +/* Identify and schedule the next ASYNC task based on scb->async_state + and scb->buf* (the input FIFO). A state machine is used to avoid + the need to make redundant calls into the event-loop - the next + scheduled task is only changed when needed. */ + +static void +reschedule (struct serial *scb) +{ + if (serial_is_async_p (scb)) + { + int next_state; + switch (scb->async_state) + { + case FD_SCHEDULED: + if (scb->bufcnt == 0) + next_state = FD_SCHEDULED; + else + { + delete_file_handler (scb->fd); + next_state = create_timer (0, push_event, scb); + } + break; + case NOTHING_SCHEDULED: + if (scb->bufcnt == 0) + { + add_file_handler (scb->fd, fd_event, scb); + next_state = FD_SCHEDULED; + } + else + { + next_state = create_timer (0, push_event, scb); + } + break; + default: /* TIMER SCHEDULED */ + if (scb->bufcnt == 0) + { + delete_timer (scb->async_state); + add_file_handler (scb->fd, fd_event, scb); + next_state = FD_SCHEDULED; + } + else + next_state = scb->async_state; + break; + } + if (serial_debug_p (scb)) + { + switch (next_state) + { + case FD_SCHEDULED: + if (scb->async_state != FD_SCHEDULED) + fprintf_unfiltered (gdb_stdlog, "[fd%d->fd-scheduled]\n", + scb->fd); + break; + default: /* TIMER SCHEDULED */ + if (scb->async_state == FD_SCHEDULED) + fprintf_unfiltered (gdb_stdlog, "[fd%d->timer-scheduled]\n", + scb->fd); + break; + } + } + scb->async_state = next_state; + } +} + +/* FD_EVENT: This is scheduled when the input FIFO is empty (and there + is no pending error). As soon as data arrives, it is read into the + input FIFO and the client notified. The client should then drain + the FIFO using readchar(). If the FIFO isn't immediatly emptied, + push_event() is used to nag the client until it is. */ + +static void +fd_event (int error, void *context) +{ + struct serial *scb = context; + if (error != 0) + { + scb->bufcnt = SERIAL_ERROR; + } + else if (scb->bufcnt == 0) + { + /* Prime the input FIFO. The readchar() function is used to + pull characters out of the buffer. See also + generic_readchar(). */ + int nr; + do + { + nr = read (scb->fd, scb->buf, BUFSIZ); + } + while (nr == -1 && errno == EINTR); + if (nr == 0) + { + scb->bufcnt = SERIAL_EOF; + } + else if (nr > 0) + { + scb->bufcnt = nr; + scb->bufp = scb->buf; + } + else + { + scb->bufcnt = SERIAL_ERROR; + } + } + scb->async_handler (scb, scb->async_context); + reschedule (scb); +} + +/* PUSH_EVENT: The input FIFO is non-empty (or there is a pending + error). Nag the client until all the data has been read. In the + case of errors, the client will need to close or de-async the + device before naging stops. */ + +static void +push_event (void *context) +{ + struct serial *scb = context; + scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */ + scb->async_handler (scb, scb->async_context); + /* re-schedule */ + reschedule (scb); +} + +/* Put the SERIAL device into/out-of ASYNC mode. */ + +void +ser_unix_async (struct serial *scb, + int async_p) +{ + if (async_p) + { + /* Force a re-schedule. */ + scb->async_state = NOTHING_SCHEDULED; + if (serial_debug_p (scb)) + fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n", + scb->fd); + reschedule (scb); + } + else + { + if (serial_debug_p (scb)) + fprintf_unfiltered (gdb_stdlog, "[fd%d->synchronous]\n", + scb->fd); + /* De-schedule whatever tasks are currently scheduled. */ + switch (scb->async_state) + { + case FD_SCHEDULED: + delete_file_handler (scb->fd); + break; + NOTHING_SCHEDULED: + break; + default: /* TIMER SCHEDULED */ + delete_timer (scb->async_state); + break; + } + } +} + void -_initialize_ser_hardwire () +_initialize_ser_hardwire (void) { - serial_add_interface (&hardwire_ops); + struct serial_ops *ops = XMALLOC (struct serial_ops); + memset (ops, sizeof (struct serial_ops), 0); + ops->name = "hardwire"; + ops->next = 0; + ops->open = hardwire_open; + ops->close = hardwire_close; + /* FIXME: Don't replace this with the equivalent ser_unix*() until + the old TERMIOS/SGTTY/... timer code has been flushed. cagney + 1999-09-16. */ + ops->readchar = hardwire_readchar; + ops->write = ser_unix_write; + ops->flush_output = hardwire_flush_output; + ops->flush_input = hardwire_flush_input; + ops->send_break = hardwire_send_break; + ops->go_raw = hardwire_raw; + ops->get_tty_state = hardwire_get_tty_state; + ops->set_tty_state = hardwire_set_tty_state; + ops->print_tty_state = hardwire_print_tty_state; + ops->noflush_set_tty_state = hardwire_noflush_set_tty_state; + ops->setbaudrate = hardwire_setbaudrate; + ops->setstopbits = hardwire_setstopbits; + ops->drain_output = hardwire_drain_output; + ops->async = ser_unix_async; + serial_add_interface (ops); } diff --git a/contrib/gdb/gdb/solib.c b/contrib/gdb/gdb/solib.c index 7f602f8..c47c438 100644 --- a/contrib/gdb/gdb/solib.c +++ b/contrib/gdb/gdb/solib.c @@ -1,48 +1,30 @@ -/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger. - Copyright 1990, 91, 92, 93, 94, 95, 96, 98, 1999 +/* Handle shared libraries for GDB, the GNU Debugger. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001 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 file is part of GDB. -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. + 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. -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. */ + 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. -/* $FreeBSD$ */ + 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" -/* This file is only compilable if link.h is available. */ - -#ifdef HAVE_LINK_H - #include <sys/types.h> -#include <signal.h> -#include "gdb_string.h" -#include <sys/param.h> #include <fcntl.h> -#include <unistd.h> - -#ifndef SVR4_SHARED_LIBS - /* SunOS shared libs need the nlist structure. */ -#include <a.out.h> -#else -#include "elf/external.h" -#include "elf/common.h" -#endif - -#include <link.h> - +#include "gdb_string.h" #include "symtab.h" #include "bfd.h" #include "symfile.h" @@ -51,209 +33,180 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "command.h" #include "target.h" #include "frame.h" -#include "gnu-regex.h" +#include "gdb_regex.h" #include "inferior.h" #include "environ.h" #include "language.h" #include "gdbcmd.h" +#include "completer.h" +#include "filenames.h" /* for DOSish file names */ -#define MAX_PATH_SIZE 512 /* FIXME: Should be dynamic */ - -/* On SVR4 systems, a list of symbols in the dynamic linker where - GDB can try to place a breakpoint to monitor shared library - events. - - If none of these symbols are found, or other errors occur, then - SVR4 systems will fall back to using a symbol as the "startup - mapping complete" breakpoint address. */ - -#ifdef SVR4_SHARED_LIBS -static char *solib_break_names[] = { - "r_debug_state", - "_r_debug_state", - "_dl_debug_state", - "rtld_db_dlactivity", - NULL -}; -#endif - -#define BKPT_AT_SYMBOL 1 - -#if defined (BKPT_AT_SYMBOL) && defined (SVR4_SHARED_LIBS) -static char *bkpt_names[] = { -#ifdef SOLIB_BKPT_NAME - SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */ -#endif - "_start", - "main", - NULL -}; -#endif - -/* Symbols which are used to locate the base of the link map structures. */ - -#ifndef SVR4_SHARED_LIBS -static char *debug_base_symbols[] = { - "_DYNAMIC", - "_DYNAMIC__MGC", - NULL -}; -#endif - -static char *main_name_list[] = { - "main_$main", - NULL -}; +#include "solist.h" -/* local data declarations */ +/* external data declarations */ -#ifndef SVR4_SHARED_LIBS - -#define LM_ADDR(so) ((so) -> lm.lm_addr) -#define LM_NEXT(so) ((so) -> lm.lm_next) -#define LM_NAME(so) ((so) -> lm.lm_name) -/* Test for first link map entry; first entry is a shared library. */ -#define IGNORE_FIRST_LINK_MAP_ENTRY(x) (0) -static struct link_dynamic dynamic_copy; -static struct link_dynamic_2 ld_2_copy; -static struct ld_debug debug_copy; -static CORE_ADDR debug_addr; -static CORE_ADDR flag_addr; - -#else /* SVR4_SHARED_LIBS */ - -#define LM_ADDR(so) ((so) -> lm.l_addr) -#define LM_NEXT(so) ((so) -> lm.l_next) -#define LM_NAME(so) ((so) -> lm.l_name) -/* Test for first link map entry; first entry is the exec-file. */ -#define IGNORE_FIRST_LINK_MAP_ENTRY(x) ((x).l_prev == NULL) -static struct r_debug debug_copy; -char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ - -#endif /* !SVR4_SHARED_LIBS */ - -struct so_list { - struct so_list *next; /* next structure in linked list */ - 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 *abfd; -}; +/* FIXME: gdbarch needs to control this variable */ +struct target_so_ops *current_target_so_ops; -static struct so_list *so_list_head; /* List of known shared objects */ -static CORE_ADDR debug_base; /* Base of dynamic linker structures */ -static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ +/* local data declarations */ -static int solib_cleanup_queued = 0; /* make_run_cleanup called */ +static struct so_list *so_list_head; /* List of known shared objects */ -extern int -fdmatch PARAMS ((int, int)); /* In libiberty */ +static int solib_cleanup_queued = 0; /* make_run_cleanup called */ /* Local function prototypes */ -static void -do_clear_solib PARAMS ((PTR)); - -static int -match_main PARAMS ((char *)); - -static void -special_symbol_handling PARAMS ((struct so_list *)); +static void do_clear_solib (PTR); -static void -sharedlibrary_command PARAMS ((char *, int)); +/* If non-zero, this is a prefix that will be added to the front of the name + shared libraries with an absolute filename for loading. */ +static char *solib_absolute_prefix = NULL; -static int -enable_break PARAMS ((void)); +/* If non-empty, this is a search path for loading non-absolute shared library + symbol files. This takes precedence over the environment variables PATH + and LD_LIBRARY_PATH. */ +static char *solib_search_path = NULL; -static void -info_sharedlibrary_command PARAMS ((char *, int)); +/* -static int symbol_add_stub PARAMS ((PTR)); + GLOBAL FUNCTION -static struct so_list * -alloc_solib PARAMS ((struct link_map *)); + solib_open -- Find a shared library file and open it. -static void -free_solib PARAMS ((struct so_list *)); + SYNOPSIS -static struct so_list * -find_solib PARAMS ((struct so_list *, int maybe_changed)); + int solib_open (char *in_patname, char **found_pathname); -static struct link_map * -first_link_map_member PARAMS ((void)); + DESCRIPTION -static CORE_ADDR -locate_base PARAMS ((void)); + Global variable SOLIB_ABSOLUTE_PREFIX is used as a prefix directory + to search for shared libraries if they have an absolute path. -static int solib_map_sections PARAMS ((PTR)); + Global variable SOLIB_SEARCH_PATH is used as a prefix directory + (or set of directories, as in LD_LIBRARY_PATH) to search for all + shared libraries if not found in SOLIB_ABSOLUTE_PREFIX. -#ifdef SVR4_SHARED_LIBS + Search order: + * If path is absolute, look in SOLIB_ABSOLUTE_PREFIX. + * If path is absolute or relative, look for it literally (unmodified). + * Look in SOLIB_SEARCH_PATH. + * Look in inferior's $PATH. + * Look in inferior's $LD_LIBRARY_PATH. -static CORE_ADDR -elf_locate_base PARAMS ((void)); + RETURNS -#else + file handle for opened solib, or -1 for failure. */ -static int -disable_break PARAMS ((void)); +int +solib_open (char *in_pathname, char **found_pathname) +{ + int found_file = -1; + char *temp_pathname = NULL; + char *p = in_pathname; -static void -allocate_rt_common_objfile PARAMS ((void)); + while (*p && !IS_DIR_SEPARATOR (*p)) + p++; -static void -solib_add_common_symbols PARAMS ((struct rtc_symb *)); + if (*p) + { + if (! IS_ABSOLUTE_PATH (in_pathname) || solib_absolute_prefix == NULL) + temp_pathname = in_pathname; + else + { + int prefix_len = strlen (solib_absolute_prefix); + + /* Remove trailing slashes from absolute prefix. */ + while (prefix_len > 0 + && IS_DIR_SEPARATOR (solib_absolute_prefix[prefix_len - 1])) + prefix_len--; + + /* Cat the prefixed pathname together. */ + temp_pathname = alloca (prefix_len + strlen (in_pathname) + 1); + strncpy (temp_pathname, solib_absolute_prefix, prefix_len); + temp_pathname[prefix_len] = '\0'; + strcat (temp_pathname, in_pathname); + } -#endif + /* Now see if we can open it. */ + found_file = open (temp_pathname, O_RDONLY, 0); + } -void _initialize_solib PARAMS ((void)); + /* If the search in solib_absolute_prefix failed, and the path name is + absolute at this point, make it relative. (openp will try and open the + file according to its absolute path otherwise, which is not what we want.) + Affects subsequent searches for this solib. */ + if (found_file < 0 && IS_ABSOLUTE_PATH (in_pathname)) + { + /* First, get rid of any drive letters etc. */ + while (!IS_DIR_SEPARATOR (*in_pathname)) + in_pathname++; -/* If non-zero, this is a prefix that will be added to the front of the name - shared libraries with an absolute filename for loading. */ -static char *solib_absolute_prefix = NULL; + /* Next, get rid of all leading dir separators. */ + while (IS_DIR_SEPARATOR (*in_pathname)) + in_pathname++; + } + + /* If not found, next search the solib_search_path (if any). */ + if (found_file < 0 && solib_search_path != NULL) + found_file = openp (solib_search_path, + 1, in_pathname, O_RDONLY, 0, &temp_pathname); + + /* If not found, next search the solib_search_path (if any) for the basename + only (ignoring the path). This is to allow reading solibs from a path + that differs from the opened path. */ + if (found_file < 0 && solib_search_path != NULL) + found_file = openp (solib_search_path, + 1, lbasename (in_pathname), O_RDONLY, 0, + &temp_pathname); + + /* If not found, next search the inferior's $PATH environment variable. */ + if (found_file < 0 && solib_search_path != NULL) + found_file = openp (get_in_environ (inferior_environ, "PATH"), + 1, in_pathname, O_RDONLY, 0, &temp_pathname); + + /* If not found, next search the inferior's $LD_LIBRARY_PATH + environment variable. */ + if (found_file < 0 && solib_search_path != NULL) + found_file = openp (get_in_environ (inferior_environ, "LD_LIBRARY_PATH"), + 1, in_pathname, O_RDONLY, 0, &temp_pathname); + + /* Done. If not found, tough luck. Return found_file and + (optionally) found_pathname. */ + if (found_pathname != NULL && temp_pathname != NULL) + *found_pathname = xstrdup (temp_pathname); + return found_file; +} -/* If non-empty, this is a search path for loading non-absolute shared library - symbol files. This takes precedence over the environment variables PATH - and LD_LIBRARY_PATH. */ -static char *solib_search_path = NULL; /* -LOCAL FUNCTION + LOCAL FUNCTION - solib_map_sections -- open bfd and build sections for shared lib + solib_map_sections -- open bfd and build sections for shared lib -SYNOPSIS + SYNOPSIS - static int solib_map_sections (struct so_list *so) + static int solib_map_sections (struct so_list *so) -DESCRIPTION + 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. + 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 + 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?). + 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 int -solib_map_sections (arg) - PTR arg; +solib_map_sections (PTR arg) { struct so_list *so = (struct so_list *) arg; /* catch_errors bogon */ char *filename; @@ -262,52 +215,18 @@ solib_map_sections (arg) struct section_table *p; struct cleanup *old_chain; bfd *abfd; - - filename = tilde_expand (so -> so_name); - - if (solib_absolute_prefix && ROOTED_P (filename)) - /* Prefix shared libraries with absolute filenames with - SOLIB_ABSOLUTE_PREFIX. */ - { - char *pfxed_fn; - int pfx_len; - - pfx_len = strlen (solib_absolute_prefix); - - /* Remove trailing slashes. */ - while (pfx_len > 0 && SLASH_P (solib_absolute_prefix[pfx_len - 1])) - pfx_len--; - - pfxed_fn = xmalloc (pfx_len + strlen (filename) + 1); - strcpy (pfxed_fn, solib_absolute_prefix); - strcat (pfxed_fn, filename); - free (filename); - filename = pfxed_fn; - } - - old_chain = make_cleanup (free, filename); + filename = tilde_expand (so->so_name); - scratch_chan = -1; + old_chain = make_cleanup (xfree, filename); + scratch_chan = solib_open (filename, &scratch_pathname); - if (solib_search_path) - scratch_chan = openp (solib_search_path, - 1, filename, O_RDONLY, 0, &scratch_pathname); - if (scratch_chan < 0) - scratch_chan = openp (get_in_environ (inferior_environ, "PATH"), - 1, filename, O_RDONLY, 0, &scratch_pathname); - if (scratch_chan < 0) - { - scratch_chan = openp (get_in_environ - (inferior_environ, "LD_LIBRARY_PATH"), - 1, filename, O_RDONLY, 0, &scratch_pathname); - } if (scratch_chan < 0) { perror_with_name (filename); } - /* Leave scratch_pathname allocated. abfd->name will point to it. */ + /* Leave scratch_pathname allocated. abfd->name will point to it. */ abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); if (!abfd) { @@ -315,14 +234,15 @@ solib_map_sections (arg) error ("Could not open `%s' as an executable file: %s", scratch_pathname, bfd_errmsg (bfd_get_error ())); } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ - so -> abfd = abfd; - abfd -> cacheable = true; + so->abfd = abfd; + abfd->cacheable = 1; - /* copy full path name into so_name, so that later symbol_file_add can find - it */ - if (strlen (scratch_pathname) >= MAX_PATH_SIZE) - error ("Full path name length of shared library exceeds MAX_PATH_SIZE in so_list structure."); + /* copy full path name into so_name, so that later symbol_file_add + can find it */ + if (strlen (scratch_pathname) >= SO_NAME_MAX_PATH_SIZE) + error ("Full path name length of shared library exceeds SO_NAME_MAX_PATH_SIZE in so_list structure."); strcpy (so->so_name, scratch_pathname); if (!bfd_check_format (abfd, bfd_object)) @@ -330,23 +250,21 @@ solib_map_sections (arg) error ("\"%s\": not in executable format: %s.", scratch_pathname, bfd_errmsg (bfd_get_error ())); } - if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + if (build_section_table (abfd, &so->sections, &so->sections_end)) { - error ("Can't find the file sections in `%s': %s", + error ("Can't find the file sections in `%s': %s", bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); } - for (p = so -> sections; p < so -> sections_end; p++) + 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 -> the_bfd_section -> name, ".text")) + object's file by the base address to which the object was actually + mapped. */ + TARGET_SO_RELOCATE_SECTION_ADDRESSES (so, p); + if (STREQ (p->the_bfd_section->name, ".text")) { - so -> textsection = p; + so->textsection = p; } } @@ -356,1687 +274,611 @@ solib_map_sections (arg) return (1); } -#ifndef SVR4_SHARED_LIBS - -/* Allocate the runtime common object file. */ +/* LOCAL FUNCTION -static void -allocate_rt_common_objfile () -{ - struct objfile *objfile; - struct objfile *last_one; - - objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); - memset (objfile, 0, sizeof (struct objfile)); - objfile -> md = NULL; - obstack_specify_allocation (&objfile -> psymbol_cache.cache, 0, 0, - xmalloc, free); - obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc, - free); - obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc, - free); - obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc, - free); - objfile -> name = mstrsave (objfile -> md, "rt_common"); - - /* Add this file onto the tail of the linked list of other such files. */ - - objfile -> next = NULL; - if (object_files == NULL) - object_files = objfile; - else - { - for (last_one = object_files; - last_one -> next; - last_one = last_one -> next); - last_one -> next = objfile; - } - - rt_common_objfile = objfile; -} - -/* Read all dynamically loaded common symbol definitions from the inferior - and put them into the minimal symbol table for the runtime common - objfile. */ - -static void -solib_add_common_symbols (rtc_symp) - struct rtc_symb *rtc_symp; -{ - struct rtc_symb inferior_rtc_symb; - struct nlist inferior_rtc_nlist; - int len; - char *name; - - /* Remove any runtime common symbols from previous runs. */ - - if (rt_common_objfile != NULL && rt_common_objfile -> minimal_symbol_count) - { - obstack_free (&rt_common_objfile -> symbol_obstack, 0); - obstack_specify_allocation (&rt_common_objfile -> symbol_obstack, 0, 0, - xmalloc, free); - rt_common_objfile -> minimal_symbol_count = 0; - rt_common_objfile -> msymbols = NULL; - } + free_so --- free a `struct so_list' object - init_minimal_symbol_collection (); - make_cleanup ((make_cleanup_func) discard_minimal_symbols, 0); + SYNOPSIS - while (rtc_symp) - { - read_memory ((CORE_ADDR) rtc_symp, - (char *) &inferior_rtc_symb, - sizeof (inferior_rtc_symb)); - read_memory ((CORE_ADDR) inferior_rtc_symb.rtc_sp, - (char *) &inferior_rtc_nlist, - sizeof(inferior_rtc_nlist)); - if (inferior_rtc_nlist.n_type == N_COMM) - { - /* FIXME: The length of the symbol name is not available, but in the - current implementation the common symbol is allocated immediately - behind the name of the symbol. */ - len = inferior_rtc_nlist.n_value - inferior_rtc_nlist.n_un.n_strx; - - name = xmalloc (len); - read_memory ((CORE_ADDR) inferior_rtc_nlist.n_un.n_name, name, len); - - /* Allocate the runtime common objfile if necessary. */ - if (rt_common_objfile == NULL) - allocate_rt_common_objfile (); - - prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value, - mst_bss, rt_common_objfile); - free (name); - } - rtc_symp = inferior_rtc_symb.rtc_next; - } - - /* Install any minimal symbols that have been collected as the current - minimal symbols for the runtime common objfile. */ - - install_minimal_symbols (rt_common_objfile); -} - -#endif /* SVR4_SHARED_LIBS */ - - -#ifdef SVR4_SHARED_LIBS - -static CORE_ADDR -bfd_lookup_symbol PARAMS ((bfd *, char *)); - -/* + void free_so (struct so_list *so) -LOCAL FUNCTION + DESCRIPTION - bfd_lookup_symbol -- lookup the value for a specific symbol + Free the storage associated with the `struct so_list' object SO. + If we have opened a BFD for SO, close it. -SYNOPSIS + The caller is responsible for removing SO from whatever list it is + a member of. If we have placed SO's sections in some target's + section table, the caller is responsible for removing them. - CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) + This function doesn't mess with objfiles at all. If there is an + objfile associated with SO that needs to be removed, the caller is + responsible for taking care of that. */ -DESCRIPTION - - An expensive way to lookup the value of a single symbol for - bfd's that are only temporary anyway. This is used by the - shared library support to find the address of the debugger - interface structures in the shared library. - - Note that 0 is specifically allowed as an error return (no - such symbol). -*/ - -static CORE_ADDR -bfd_lookup_symbol (abfd, symname) - bfd *abfd; - char *symname; +void +free_so (struct so_list *so) { - long storage_needed; - asymbol *sym; - asymbol **symbol_table; - unsigned int number_of_symbols; - unsigned int i; - struct cleanup *back_to; - CORE_ADDR symaddr = 0; - - storage_needed = bfd_get_symtab_upper_bound (abfd); + char *bfd_filename = 0; - if (storage_needed > 0) + if (so->sections) + xfree (so->sections); + + if (so->abfd) { - symbol_table = (asymbol **) xmalloc (storage_needed); - back_to = make_cleanup (free, (PTR)symbol_table); - number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); - - for (i = 0; i < number_of_symbols; i++) - { - sym = *symbol_table++; - if (STREQ (sym -> name, symname)) - { - /* Bfd symbols are section relative. */ - symaddr = sym -> value + sym -> section -> vma; - break; - } - } - do_cleanups (back_to); + bfd_filename = bfd_get_filename (so->abfd); + if (! bfd_close (so->abfd)) + warning ("cannot close \"%s\": %s", + bfd_filename, bfd_errmsg (bfd_get_error ())); } - if (symaddr) return (symaddr); + if (bfd_filename) + xfree (bfd_filename); - storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd); + TARGET_SO_FREE_SO (so); - if (storage_needed > 0) - { - symbol_table = (asymbol **) xmalloc (storage_needed); - back_to = make_cleanup (free, (PTR)symbol_table); - number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table); - - for (i = 0; i < number_of_symbols; i++) - { - sym = *symbol_table++; - if (STREQ (sym -> name, symname)) - { - /* Bfd symbols are section relative. */ - symaddr = sym -> value + sym -> section -> vma; - break; - } - } - do_cleanups (back_to); - } - return (symaddr); + xfree (so); } -#ifdef HANDLE_SVR4_EXEC_EMULATORS - -/* - Solaris BCP (the part of Solaris which allows it to run SunOS4 - a.out files) throws in another wrinkle. Solaris does not fill - in the usual a.out link map structures when running BCP programs, - the only way to get at them is via groping around in the dynamic - linker. - The dynamic linker and it's structures are located in the shared - C library, which gets run as the executable's "interpreter" by - the kernel. - - Note that we can assume nothing about the process state at the time - we need to find these structures. We may be stopped on the first - instruction of the interpreter (C shared library), the first - instruction of the executable itself, or somewhere else entirely - (if we attached to the process for example). -*/ - -static char *debug_base_symbols[] = { - "r_debug", /* Solaris 2.3 */ - "_r_debug", /* Solaris 2.1, 2.2 */ - NULL -}; - -static int -look_for_base PARAMS ((int, CORE_ADDR)); - -/* - -LOCAL FUNCTION - - look_for_base -- examine file for each mapped address segment -SYNOPSYS - - static int look_for_base (int fd, CORE_ADDR baseaddr) - -DESCRIPTION - - This function is passed to proc_iterate_over_mappings, which - causes it to get called once for each mapped address space, with - an open file descriptor for the file mapped to that space, and the - base address of that mapped space. - - Our job is to find the debug base symbol in the file that this - fd is open on, if it exists, and if so, initialize the dynamic - linker structure base address debug_base. - - Note that this is a computationally expensive proposition, since - we basically have to open a bfd on every call, so we specifically - avoid opening the exec file. - */ +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ static int -look_for_base (fd, baseaddr) - int fd; - CORE_ADDR baseaddr; +symbol_add_stub (PTR arg) { - bfd *interp_bfd; - CORE_ADDR address = 0; - char **symbolp; + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + struct section_addr_info *sap; - /* If the fd is -1, then there is no file that corresponds to this - mapped memory segment, so skip it. Also, if the fd corresponds - to the exec file, skip it as well. */ - - if (fd == -1 - || (exec_bfd != NULL - && fdmatch (fileno ((FILE *)(exec_bfd -> iostream)), fd))) + /* Have we already loaded this shared object? */ + ALL_OBJFILES (so->objfile) { - return (0); + if (strcmp (so->objfile->name, so->so_name) == 0) + return 1; } - /* Try to open whatever random file this fd corresponds to. Note that - we have no way currently to find the filename. Don't gripe about - any problems we might have, just fail. */ + sap = build_section_addr_info_from_section_table (so->sections, + so->sections_end); - if ((interp_bfd = bfd_fdopenr ("unnamed", gnutarget, fd)) == NULL) - { - return (0); - } - if (!bfd_check_format (interp_bfd, bfd_object)) - { - /* FIXME-leak: on failure, might not free all memory associated with - interp_bfd. */ - bfd_close (interp_bfd); - return (0); - } + so->objfile = symbol_file_add (so->so_name, so->from_tty, + sap, 0, OBJF_SHARED); + free_section_addr_info (sap); - /* Now try to find our debug base symbol in this file, which we at - least know to be a valid ELF executable or shared library. */ - - for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++) - { - address = bfd_lookup_symbol (interp_bfd, *symbolp); - if (address != 0) - { - break; - } - } - if (address == 0) - { - /* FIXME-leak: on failure, might not free all memory associated with - interp_bfd. */ - bfd_close (interp_bfd); - return (0); - } - - /* Eureka! We found the symbol. But now we may need to relocate it - by the base address. If the symbol's value is less than the base - address of the shared library, then it hasn't yet been relocated - by the dynamic linker, and we have to do it ourself. FIXME: Note - that we make the assumption that the first segment that corresponds - to the shared library has the base address to which the library - was relocated. */ - - if (address < baseaddr) - { - address += baseaddr; - } - debug_base = address; - /* FIXME-leak: on failure, might not free all memory associated with - interp_bfd. */ - bfd_close (interp_bfd); return (1); } -#endif /* HANDLE_SVR4_EXEC_EMULATORS */ -/* -LOCAL FUNCTION +/* LOCAL FUNCTION - elf_locate_base -- locate the base address of dynamic linker structs - for SVR4 elf targets. + update_solib_list --- synchronize GDB's shared object list with inferior's -SYNOPSIS + SYNOPSIS - CORE_ADDR elf_locate_base (void) + void update_solib_list (int from_tty, struct target_ops *TARGET) -DESCRIPTION + Extract the list of currently loaded shared objects from the + inferior, and compare it with the list of shared objects currently + in GDB's so_list_head list. Edit so_list_head to bring it in sync + with the inferior's new list. - For SVR4 elf targets the address of the dynamic linker's runtime - structure is contained within the dynamic info section in the - executable file. The dynamic section is also mapped into the - inferior address space. Because the runtime loader fills in the - real address before starting the inferior, we have to read in the - dynamic info section from the inferior address space. - If there are any errors while trying to find the address, we - silently return 0, otherwise the found address is returned. + If we notice that the inferior has unloaded some shared objects, + free any symbolic info GDB had read about those shared objects. - */ + Don't load symbolic info for any new shared objects; just add them + to the list, and leave their symbols_loaded flag clear. -static CORE_ADDR -elf_locate_base () -{ - sec_ptr dyninfo_sect; - int dyninfo_sect_size; - CORE_ADDR dyninfo_addr; - char *buf; - char *bufend; - - /* Find the start address of the .dynamic section. */ - dyninfo_sect = bfd_get_section_by_name (exec_bfd, ".dynamic"); - if (dyninfo_sect == NULL) - return 0; - dyninfo_addr = bfd_section_vma (exec_bfd, dyninfo_sect); - - /* Read in .dynamic section, silently ignore errors. */ - dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect); - buf = alloca (dyninfo_sect_size); - if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size)) - return 0; - - /* Find the DT_DEBUG entry in the the .dynamic section. - For mips elf we look for DT_MIPS_RLD_MAP, mips elf apparently has - no DT_DEBUG entries. */ -#ifndef TARGET_ELF64 - for (bufend = buf + dyninfo_sect_size; - buf < bufend; - buf += sizeof (Elf32_External_Dyn)) - { - Elf32_External_Dyn *x_dynp = (Elf32_External_Dyn *)buf; - long dyn_tag; - CORE_ADDR dyn_ptr; - - dyn_tag = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_tag); - if (dyn_tag == DT_NULL) - break; - else if (dyn_tag == DT_DEBUG) - { - dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); - return dyn_ptr; - } -#ifdef DT_MIPS_RLD_MAP - else if (dyn_tag == DT_MIPS_RLD_MAP) - { - char pbuf[TARGET_PTR_BIT / HOST_CHAR_BIT]; - - /* DT_MIPS_RLD_MAP contains a pointer to the address - of the dynamic link structure. */ - dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); - if (target_read_memory (dyn_ptr, pbuf, sizeof (pbuf))) - return 0; - return extract_unsigned_integer (pbuf, sizeof (pbuf)); - } -#endif - } -#else /* ELF64 */ - for (bufend = buf + dyninfo_sect_size; - buf < bufend; - buf += sizeof (Elf64_External_Dyn)) - { - Elf64_External_Dyn *x_dynp = (Elf64_External_Dyn *)buf; - long dyn_tag; - CORE_ADDR dyn_ptr; - - dyn_tag = bfd_h_get_64 (exec_bfd, (bfd_byte *) x_dynp->d_tag); - if (dyn_tag == DT_NULL) - break; - else if (dyn_tag == DT_DEBUG) - { - dyn_ptr = bfd_h_get_64 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); - return dyn_ptr; - } - } -#endif - - /* DT_DEBUG entry not found. */ - return 0; -} - -#endif /* SVR4_SHARED_LIBS */ - -/* - -LOCAL FUNCTION - - locate_base -- locate the base address of dynamic linker structs - -SYNOPSIS - - CORE_ADDR locate_base (void) - -DESCRIPTION - - For both the SunOS and SVR4 shared library implementations, if the - inferior executable has been linked dynamically, there is a single - address somewhere in the inferior's data space which is the key to - locating all of the dynamic linker's runtime structures. This - address is the value of the debug base symbol. The job of this - function is to find and return that address, or to return 0 if there - is no such address (the executable is statically linked for example). - - For SunOS, the job is almost trivial, since the dynamic linker and - all of it's structures are statically linked to the executable at - link time. Thus the symbol for the address we are looking for has - already been added to the minimal symbol table for the executable's - objfile at the time the symbol file's symbols were read, and all we - have to do is look it up there. Note that we explicitly do NOT want - to find the copies in the shared library. + If FROM_TTY is non-null, feel free to print messages about what + we're doing. - The SVR4 version is a bit more complicated because the address - is contained somewhere in the dynamic info section. We have to go - to a lot more work to discover the address of the debug base symbol. - Because of this complexity, we cache the value we find and return that - value on subsequent invocations. Note there is no copy in the - executable symbol tables. - - */ - -static CORE_ADDR -locate_base () -{ - -#ifndef SVR4_SHARED_LIBS - - struct minimal_symbol *msymbol; - CORE_ADDR address = 0; - char **symbolp; - - /* For SunOS, we want to limit the search for the debug base symbol to the - executable being debugged, since there is a duplicate named symbol in the - shared library. We don't want the shared library versions. */ - - for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++) - { - msymbol = lookup_minimal_symbol (*symbolp, NULL, symfile_objfile); - if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) - { - address = SYMBOL_VALUE_ADDRESS (msymbol); - return (address); - } - } - return (0); - -#else /* SVR4_SHARED_LIBS */ - - /* Check to see if we have a currently valid address, and if so, avoid - doing all this work again and just return the cached address. If - we have no cached address, try to locate it in the dynamic info - section for ELF executables. */ - - if (debug_base == 0) - { - if (exec_bfd != NULL - && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour) - debug_base = elf_locate_base (); -#ifdef HANDLE_SVR4_EXEC_EMULATORS - /* Try it the hard way for emulated executables. */ - else if (inferior_pid != 0 && target_has_execution) - proc_iterate_over_mappings (look_for_base); -#endif - } - return (debug_base); - -#endif /* !SVR4_SHARED_LIBS */ - -} - -/* - -LOCAL FUNCTION - - first_link_map_member -- locate first member in dynamic linker's map - -SYNOPSIS - - static struct link_map *first_link_map_member (void) - -DESCRIPTION - - Read in a copy of the first member in the inferior's dynamic - link map from the inferior's dynamic linker structures, and return - a pointer to the copy in our address space. -*/ - -static struct link_map * -first_link_map_member () -{ - struct link_map *lm = NULL; - -#ifndef SVR4_SHARED_LIBS - - read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy)); - if (dynamic_copy.ld_version >= 2) - { - /* It is a version that we can deal with, so read in the secondary - structure and find the address of the link map list from it. */ - read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, (char *) &ld_2_copy, - sizeof (struct link_dynamic_2)); - lm = ld_2_copy.ld_loaded; - } - -#else /* SVR4_SHARED_LIBS */ - - read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug)); - /* FIXME: Perhaps we should validate the info somehow, perhaps by - checking r_version for a known version number, or r_state for - RT_CONSISTENT. */ - lm = debug_copy.r_map; - -#endif /* !SVR4_SHARED_LIBS */ - - return (lm); -} - -/* - -LOCAL FUNCTION - - free_solib -- free a so_list structure - -SYNOPSIS - - void free_solib (struct so_list *so_list_ptr) - -DESCRIPTION - - Free the memory used by a struct so_list. - - */ + If TARGET is non-null, add the sections of all new shared objects + to TARGET's section table. Note that this doesn't remove any + sections for shared objects that have been unloaded, and it + doesn't check to see if the new shared objects are already present in + the section table. But we only use this for core files and + processes we've just attached to, so that's okay. */ void -free_solib (so) - struct so_list *so; -{ - char *bfd_filename; - if (so -> sections) - { - free ((PTR)so -> sections); - } - if (so -> abfd) - { - bfd_filename = bfd_get_filename (so -> abfd); - if (!bfd_close (so -> abfd)) - warning ("cannot close \"%s\": %s", - bfd_filename, bfd_errmsg (bfd_get_error ())); - } - else - /* This happens for the executable on SVR4. */ - bfd_filename = NULL; - - if (bfd_filename) - free ((PTR)bfd_filename); - free ((PTR)so); -} - -/* - -LOCAL FUNCTION - - alloc_solib -- free a so_list structure - -SYNOPSIS - - struct so_list *alloc_solib (struct link_map *lm) - -DESCRIPTION - - Allocate the struct so_list to cache debugging information - for a struct link_map entry in the target. - - */ - -struct so_list * -alloc_solib (lm) - struct link_map *lm; +update_solib_list (int from_tty, struct target_ops *target) { - struct so_list *new; - - /* 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; - - read_memory ((CORE_ADDR) lm, (char *) &(new -> lm), - sizeof (struct link_map)); - /* For SVR4 versions, the first entry in the link map is for the - inferior executable, so we must ignore it. For some versions of - SVR4, it has no name. For others (Solaris 2.3 for example), it - does have a name, so we can no longer use a missing name to - decide when to ignore it. */ - if (!IGNORE_FIRST_LINK_MAP_ENTRY (new -> lm)) - { - int errcode; - char *buffer; - target_read_string ((CORE_ADDR) LM_NAME (new), &buffer, - MAX_PATH_SIZE - 1, &errcode); - if (errcode != 0) - error ("find_solib: Can't read pathname for load map: %s\n", - safe_strerror (errcode)); - strncpy (new -> so_name, buffer, MAX_PATH_SIZE - 1); - new -> so_name[MAX_PATH_SIZE - 1] = '\0'; - free (buffer); - solib_map_sections (new); - } - - return new; -} - -/* - -LOCAL FUNCTION - - find_solib -- step through list of shared objects - -SYNOPSIS - - struct so_list *find_solib (struct so_list *so_list_ptr, int maybe_changed) - -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>. - - If it is expected that the contents of the shared library list has changed - (e.g. when the special shared library breakpoint is hit) then pass non-zero - for maybe_changed, otherwise zero. - */ + struct so_list *inferior = TARGET_SO_CURRENT_SOS (); + struct so_list *gdb, **gdb_link; + + /* If we are attaching to a running process for which we + have not opened a symbol file, we may be able to get its + symbols now! */ + if (attach_flag && + symfile_objfile == NULL) + catch_errors (TARGET_SO_OPEN_SYMBOL_FILE_OBJECT, (PTR) &from_tty, + "Error reading attached process's symbol file.\n", + RETURN_MASK_ALL); + + /* Since this function might actually add some elements to the + so_list_head list, arrange for it to be cleaned up when + appropriate. */ + if (!solib_cleanup_queued) + { + make_run_cleanup (do_clear_solib, NULL); + solib_cleanup_queued = 1; + } + + /* GDB and the inferior's dynamic linker each maintain their own + list of currently loaded shared objects; we want to bring the + former in sync with the latter. Scan both lists, seeing which + shared objects appear where. There are three cases: + + - A shared object appears on both lists. This means that GDB + knows about it already, and it's still loaded in the inferior. + Nothing needs to happen. + + - A shared object appears only on GDB's list. This means that + the inferior has unloaded it. We should remove the shared + object from GDB's tables. + + - A shared object appears only on the inferior's list. This + means that it's just been loaded. We should add it to GDB's + tables. + + So we walk GDB's list, checking each entry to see if it appears + in the inferior's list too. If it does, no action is needed, and + we remove it from the inferior's list. If it doesn't, the + inferior has unloaded it, and we remove it from GDB's list. By + the time we're done walking GDB's list, the inferior's list + contains only the new shared objects, which we then add. */ + + gdb = so_list_head; + gdb_link = &so_list_head; + while (gdb) + { + struct so_list *i = inferior; + struct so_list **i_link = &inferior; + + /* Check to see whether the shared object *gdb also appears in + the inferior's current list. */ + while (i) + { + if (! strcmp (gdb->so_original_name, i->so_original_name)) + break; -static struct so_list * -find_solib (so_list_ptr, maybe_changed) - struct so_list *so_list_ptr; /* Last lm or NULL for first one */ - int maybe_changed; /* non-zero if shlib list might have changed */ -{ - struct link_map *lm = NULL; - struct so_list *new; - struct so_list *so_list_next; - struct so_list *p, **prev; - - if (so_list_ptr == NULL) - { - struct so_list **map; + i_link = &i->next; + i = *i_link; + } - /* If we have not already read in the dynamic linking structures - from the inferior, lookup the address of the base structure. */ - if (debug_base == 0) - debug_base = locate_base (); - if (debug_base != 0) + /* If the shared object appears on the inferior's list too, then + it's still loaded, so we don't need to do anything. Delete + it from the inferior's list, and leave it on GDB's list. */ + if (i) { - /* Read the base structure in and find the address of the first - link map list member. */ - lm = first_link_map_member (); + *i_link = i->next; + free_so (i); + gdb_link = &gdb->next; + gdb = *gdb_link; } + + /* If it's not on the inferior's list, remove it from GDB's tables. */ else - lm = NULL; + { + *gdb_link = gdb->next; - prev = &so_list_head; - so_list_ptr = so_list_head; - } - else - { - /* We have been called before, and are in the process of walking - the shared library list. Advance to the next shared object. + /* Unless the user loaded it explicitly, free SO's objfile. */ + if (gdb->objfile && ! (gdb->objfile->flags & OBJF_USERLOADED)) + free_objfile (gdb->objfile); - Always read from the target to check to see if any were - added, but be quiet if we can't read from the target any more. */ - int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr, - (char *) &(so_list_ptr -> lm), - sizeof (struct link_map)); + /* Some targets' section tables might be referring to + sections from so->abfd; remove them. */ + remove_target_sections (gdb->abfd); - if (status == 0) - { - lm = LM_NEXT (so_list_ptr); - } - else - { - lm = NULL; + free_so (gdb); + gdb = *gdb_link; } - - prev = &so_list_ptr -> next; - so_list_ptr = so_list_ptr -> next; } - /* If we don't believe that the list has changed, just return the cached copy. */ - if (!maybe_changed) - return (so_list_ptr); + /* Now the inferior's list contains only shared objects that don't + appear in GDB's list --- those that are newly loaded. Add them + to GDB's shared object list. */ + if (inferior) + { + struct so_list *i; - /* At this point, lm is the address of the next list element in the target and - so_list_ptr is our cached entry for it. */ + /* Add the new shared objects to GDB's list. */ + *gdb_link = inferior; - if (lm != NULL) - { - if (so_list_ptr == NULL || so_list_ptr -> lmaddr != lm) + /* Fill in the rest of each of the `struct so_list' nodes. */ + for (i = inferior; i; i = i->next) { - /* We have detected a change in the list. Check for a deletion by searching - forward in the cached list */ - if (so_list_ptr) - { - for (p = so_list_ptr -> next; p; p = p -> next) - if (p -> lmaddr == lm) - break; - } - else - p = NULL; + i->from_tty = from_tty; + + /* Fill in the rest of the `struct so_list' node. */ + catch_errors (solib_map_sections, i, + "Error while mapping shared library sections:\n", + RETURN_MASK_ALL); - if (p) + /* If requested, add the shared object's sections to the TARGET's + section table. Do this immediately after mapping the object so + that later nodes in the list can query this object, as is needed + in solib-osf.c. */ + if (target) { - /* This lib has been deleted */ - while (so_list_ptr != p) + int count = (i->sections_end - i->sections); + if (count > 0) { - *prev = so_list_ptr -> next; - free_solib (so_list_ptr); - so_list_ptr = *prev; + int space = target_resize_to_sections (target, count); + memcpy (target->to_sections + space, + i->sections, + count * sizeof (i->sections[0])); } } - else - { - /* A new lib has been inserted into the list */ - new = alloc_solib (lm); - new -> next = so_list_ptr; - *prev = new; - so_list_ptr = new; - } } } - else - { - if (so_list_ptr != NULL) - { - so_list_head = new; - - if (! solib_cleanup_queued) - { - make_run_cleanup (do_clear_solib, NULL); - solib_cleanup_queued = 1; - } - - } - so_list_next = new; - if (lm) - target_read_memory ((CORE_ADDR) lm, (char *) &(new -> lm), - sizeof (struct link_map)); - /* For SVR4 versions, the first entry in the link map is for the - inferior executable, so we must ignore it. For some versions of - SVR4, it has no name. For others (Solaris 2.3 for example), it - does have a name, so we can no longer use a missing name to - decide when to ignore it. */ - if (lm && new && !IGNORE_FIRST_LINK_MAP_ENTRY (new -> lm)) - { - int errcode; - char *buffer; - target_read_string ((CORE_ADDR) LM_NAME (new), &buffer, - MAX_PATH_SIZE - 1, &errcode); - if (errcode != 0) - { - warning ("find_solib: Can't read pathname for load map: %s\n", - safe_strerror (errcode)); - return (so_list_next); - } - strncpy (new -> so_name, buffer, MAX_PATH_SIZE - 1); - new -> so_name[MAX_PATH_SIZE - 1] = '\0'; - free (buffer); - catch_errors (solib_map_sections, new, - "Error while mapping shared library sections:\n", - RETURN_MASK_ALL); - } - } - - return (so_list_ptr); } -/* A small stub to get us past the arg-passing pinhole of catch_errors. */ -static int -symbol_add_stub (arg) - PTR arg; -{ - register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ - CORE_ADDR text_addr = 0; +/* GLOBAL FUNCTION - if (so -> textsection) - text_addr = so -> textsection -> addr; - else if (so -> abfd != NULL) - { - asection *lowest_sect; - - /* If we didn't find a mapped non zero sized .text section, set up - text_addr so that the relocation in symbol_file_add does no harm. */ - - lowest_sect = bfd_get_section_by_name (so -> abfd, ".text"); - if (lowest_sect == NULL) - bfd_map_over_sections (so -> abfd, find_lowest_section, - (PTR) &lowest_sect); - if (lowest_sect) - text_addr = bfd_section_vma (so -> abfd, lowest_sect) - + (CORE_ADDR) LM_ADDR (so); - } - - ALL_OBJFILES (so -> objfile) - { - if (strcmp (so -> objfile -> name, so -> so_name) == 0) - return 1; - } - so -> objfile = - symbol_file_add (so -> so_name, so -> from_tty, - text_addr, - 0, 0, 0, 0, 1); - return (1); -} + solib_add -- read in symbol info for newly added shared libraries -/* This function will check the so name to see if matches the main list. - In some system the main object is in the list, which we want to exclude */ + SYNOPSIS -static int match_main (soname) - char *soname; -{ - char **mainp; + void solib_add (char *pattern, int from_tty, struct target_ops + *TARGET, int readsyms) - for (mainp = main_name_list; *mainp != NULL; mainp++) - { - if (strcmp (soname, *mainp) == 0) - return (1); - } + DESCRIPTION - return (0); -} + Read in symbolic information for any shared objects whose names + match PATTERN. (If we've already read a shared object's symbol + info, leave it alone.) If PATTERN is zero, read them all. -/* + If READSYMS is 0, defer reading symbolic information until later + but still do any needed low level processing. -GLOBAL FUNCTION + FROM_TTY and TARGET are as described for update_solib_list, above. */ - solib_add -- add a shared library file to the symtab and section list +void +solib_add (char *pattern, int from_tty, struct target_ops *target, int readsyms) +{ + struct so_list *gdb; -SYNOPSIS + if (pattern) + { + char *re_err = re_comp (pattern); - void solib_add (char *arg_string, int from_tty, - struct target_ops *target) + if (re_err) + error ("Invalid regexp: %s", re_err); + } -DESCRIPTION + update_solib_list (from_tty, target); -*/ + /* Walk the list of currently loaded shared libraries, and read + symbols for any that match the pattern --- or any whose symbols + aren't already loaded, if no pattern was given. */ + { + int any_matches = 0; + int loaded_any_symbols = 0; -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. */ - if (target) - { - /* Count how many new section_table entries there are. */ - so = NULL; - count = 0; - while ((so = find_solib (so, 1)) != NULL) + for (gdb = so_list_head; gdb; gdb = gdb->next) + if (! pattern || re_exec (gdb->so_name)) { - if (so -> so_name[0] && !match_main (so -> so_name)) - { - count += so -> sections_end - so -> sections; - } - } - - if (count) - { - int update_coreops; - - /* We must update the to_sections field in the core_ops structure - here, otherwise we dereference a potential dangling pointer - for each call to target_read/write_memory within this routine. */ - update_coreops = core_ops.to_sections == target->to_sections; - - /* 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); - - /* Update the to_sections field in the core_ops structure - if needed. */ - if (update_coreops) - { - core_ops.to_sections = target->to_sections; - core_ops.to_sections_end = target->to_sections_end; - } + any_matches = 1; - /* Add these section table entries to the target's table. */ - while ((so = find_solib (so, 1)) != NULL) + if (gdb->symbols_loaded) { - 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; - } + if (from_tty) + printf_unfiltered ("Symbols already loaded for %s\n", + gdb->so_name); } - } - } - - /* Now add the symbol files. */ - while ((so = find_solib (so, 1)) != NULL) - { - if (so -> so_name[0] && re_exec (so -> so_name) && - !match_main (so -> so_name)) - { - so -> from_tty = from_tty; - if (so -> symbols_loaded) + else if (readsyms) { - if (from_tty) + if (catch_errors + (symbol_add_stub, gdb, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) { - printf_unfiltered ("Symbols already loaded for %s\n", so -> so_name); + if (from_tty) + printf_unfiltered ("Loaded symbols for %s\n", + gdb->so_name); + gdb->symbols_loaded = 1; + loaded_any_symbols = 1; } } - else if (catch_errors - (symbol_add_stub, so, - "Error while reading shared library symbols:\n", - RETURN_MASK_ALL)) - { - so_last = so; - so -> symbols_loaded = 1; - } } - } - /* Getting new symbols may change our opinion about what is - frameless. */ - if (so_last) - reinit_frame_cache (); + if (from_tty && pattern && ! any_matches) + printf_unfiltered + ("No loaded shared libraries match the pattern `%s'.\n", pattern); + + if (loaded_any_symbols) + { + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); - if (so_last) - special_symbol_handling (so_last); + TARGET_SO_SPECIAL_SYMBOL_HANDLING (); + } + } } + /* -LOCAL FUNCTION + LOCAL FUNCTION - info_sharedlibrary_command -- code for "info sharedlibrary" + info_sharedlibrary_command -- code for "info sharedlibrary" -SYNOPSIS + SYNOPSIS - static void info_sharedlibrary_command () + static void info_sharedlibrary_command () -DESCRIPTION + DESCRIPTION - Walk through the shared library list and print information - about each attached library. -*/ + 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; +info_sharedlibrary_command (char *ignore, int from_tty) { - register struct so_list *so = NULL; /* link map state variable */ + register struct so_list *so = NULL; /* link map state variable */ int header_done = 0; int addr_width; char *addr_fmt; - if (exec_bfd == NULL) + if (TARGET_PTR_BIT == 32) + { + addr_width = 8 + 4; + addr_fmt = "08l"; + } + else if (TARGET_PTR_BIT == 64) + { + addr_width = 16 + 4; + addr_fmt = "016l"; + } + else { - printf_unfiltered ("No exec file.\n"); - return; + internal_error (__FILE__, __LINE__, + "TARGET_PTR_BIT returned unknown size %d", + TARGET_PTR_BIT); } -#ifndef TARGET_ELF64 - addr_width = 8+4; - addr_fmt = "08l"; -#else - addr_width = 16+4; - addr_fmt = "016l"; -#endif + update_solib_list (from_tty, 0); - while ((so = find_solib (so, 0)) != NULL) + for (so = so_list_head; so; so = so->next) { - if (so -> so_name[0]) + if (so->so_name[0]) { if (!header_done) { - printf_unfiltered("%-*s%-*s%-12s%s\n", addr_width, "From", - addr_width, "To", "Syms Read", - "Shared Object Library"); + printf_unfiltered ("%-*s%-*s%-12s%s\n", addr_width, "From", + addr_width, "To", "Syms Read", + "Shared Object Library"); header_done++; } printf_unfiltered ("%-*s", addr_width, - local_hex_string_custom ((unsigned long) LM_ADDR (so), - addr_fmt)); + so->textsection != NULL + ? longest_local_hex_string_custom ( + (LONGEST) so->textsection->addr, + addr_fmt) + : ""); printf_unfiltered ("%-*s", addr_width, - local_hex_string_custom ((unsigned long) so -> lmend, - addr_fmt)); - printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No"); - printf_unfiltered ("%s\n", so -> so_name); + so->textsection != NULL + ? longest_local_hex_string_custom ( + (LONGEST) so->textsection->endaddr, + addr_fmt) + : ""); + printf_unfiltered ("%-12s", so->symbols_loaded ? "Yes" : "No"); + printf_unfiltered ("%s\n", so->so_name); } } if (so_list_head == NULL) { - printf_unfiltered ("No shared libraries loaded at this time.\n"); + printf_unfiltered ("No shared libraries loaded at this time.\n"); } } /* -GLOBAL FUNCTION + GLOBAL FUNCTION - solib_address -- check to see if an address is in a shared lib + solib_address -- check to see if an address is in a shared lib -SYNOPSIS + SYNOPSIS - char * solib_address (CORE_ADDR address) + char * solib_address (CORE_ADDR address) -DESCRIPTION + 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. + 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. - For example, this routine is called at one point to disable - breakpoints which are in shared libraries that are not currently - mapped in. + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. */ char * -solib_address (address) - CORE_ADDR address; +solib_address (CORE_ADDR address) { - register struct so_list *so = 0; /* link map state variable */ - - while ((so = find_solib (so, 0)) != NULL) + register struct so_list *so = 0; /* link map state variable */ + + for (so = so_list_head; so; so = so->next) { - if (so -> so_name[0]) + struct section_table *p; + + for (p = so->sections; p < so->sections_end; p++) { - if ((address >= (CORE_ADDR) LM_ADDR (so)) && - (address < (CORE_ADDR) so -> lmend)) + if (p->addr <= address && address < p->endaddr) return (so->so_name); } } + return (0); } /* Called by free_all_symtabs */ -void -clear_solib() +void +clear_solib (void) { - struct so_list *next; - char *bfd_filename; - + /* This function is expected to handle ELF shared libraries. It is + also used on Solaris, which can run either ELF or a.out binaries + (for compatibility with SunOS 4), both of which can use shared + libraries. So we don't know whether we have an ELF executable or + an a.out executable until the user chooses an executable file. + + ELF shared libraries don't get mapped into the address space + until after the program starts, so we'd better not try to insert + breakpoints in them immediately. We have to wait until the + dynamic linker has loaded them; we'll hit a bp_shlib_event + breakpoint (look for calls to create_solib_event_breakpoint) when + it's ready. + + SunOS shared libraries seem to be different --- they're present + as soon as the process begins execution, so there's no need to + put off inserting breakpoints. There's also nowhere to put a + bp_shlib_event breakpoint, so if we put it off, we'll never get + around to it. + + So: disable breakpoints only if we're using ELF shared libs. */ + if (exec_bfd != NULL + && bfd_get_flavour (exec_bfd) != bfd_target_aout_flavour) + disable_breakpoints_in_shlibs (1); + while (so_list_head) { - next = so_list_head -> next; - free_solib (so_list_head); - so_list_head = next; + struct so_list *so = so_list_head; + so_list_head = so->next; + if (so->abfd) + remove_target_sections (so->abfd); + free_so (so); } - debug_base = 0; + + TARGET_SO_CLEAR_SOLIB (); } static void -do_clear_solib (dummy) - PTR dummy; +do_clear_solib (PTR dummy) { solib_cleanup_queued = 0; clear_solib (); } -#ifdef SVR4_SHARED_LIBS - -/* Return 1 if PC lies in the dynamic symbol resolution code of the - SVR4 run time loader. */ - -static CORE_ADDR interp_text_sect_low; -static CORE_ADDR interp_text_sect_high; -static CORE_ADDR interp_plt_sect_low; -static CORE_ADDR interp_plt_sect_high; - -int -in_svr4_dynsym_resolve_code (pc) - CORE_ADDR pc; -{ - return ((pc >= interp_text_sect_low && pc < interp_text_sect_high) - || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high) - || in_plt_section (pc, NULL)); -} -#endif - -/* - -LOCAL FUNCTION - - disable_break -- remove the "mapping changed" breakpoint +/* GLOBAL FUNCTION -SYNOPSIS + solib_create_inferior_hook -- shared library startup support - static int disable_break () + SYNOPSIS -DESCRIPTION + void solib_create_inferior_hook() - Removes the breakpoint that gets hit when the dynamic linker - completes a mapping change. + DESCRIPTION -*/ - -#ifndef SVR4_SHARED_LIBS + 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. */ -static int -disable_break () +void +solib_create_inferior_hook (void) { - int status = 1; - -#ifndef SVR4_SHARED_LIBS - - int in_debugger = 0; - - /* Read the debugger structure from the inferior to retrieve the - address of the breakpoint and the original contents of the - breakpoint address. Remove the breakpoint by writing the original - contents back. */ - - read_memory (debug_addr, (char *) &debug_copy, sizeof (debug_copy)); - - /* Set `in_debugger' to zero now. */ - - write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); - - breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr; - write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst, - sizeof (debug_copy.ldd_bp_inst)); - -#else /* SVR4_SHARED_LIBS */ - - /* Note that breakpoint address and original contents are in our address - space, so we just need to write the original contents back. */ - - if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) - { - status = 0; - } - -#endif /* !SVR4_SHARED_LIBS */ - - /* For the SVR4 version, we always know the breakpoint address. For the - SunOS version we don't know it until the above code is executed. - Grumble if we are stopped anywhere besides the breakpoint address. */ - - if (stop_pc != breakpoint_addr) - { - warning ("stopped at unknown breakpoint while handling shared libraries"); - } - - return (status); + TARGET_SO_SOLIB_CREATE_INFERIOR_HOOK (); } -#endif /* #ifdef SVR4_SHARED_LIBS */ - -/* - -LOCAL FUNCTION - - enable_break -- arrange for dynamic linker to hit breakpoint - -SYNOPSIS - - int enable_break (void) - -DESCRIPTION - - Both the SunOS and the SVR4 dynamic linkers have, as part of their - debugger interface, support for arranging for the inferior to hit - a breakpoint after mapping in the shared libraries. This function - enables that breakpoint. - - For SunOS, there is a special flag location (in_debugger) which we - set to 1. When the dynamic linker sees this flag set, it will set - a breakpoint at a location known only to itself, after saving the - original contents of that place and the breakpoint address itself, - in it's own internal structures. When we resume the inferior, it - will eventually take a SIGTRAP when it runs into the breakpoint. - We handle this (in a different place) by restoring the contents of - the breakpointed location (which is only known after it stops), - chasing around to locate the shared libraries that have been - loaded, then resuming. - - For SVR4, the debugger interface structure contains a member (r_brk) - which is statically initialized at the time the shared library is - built, to the offset of a function (_r_debug_state) which is guaran- - teed to be called once before mapping in a library, and again when - the mapping is complete. At the time we are examining this member, - it contains only the unrelocated offset of the function, so we have - to do our own relocation. Later, when the dynamic linker actually - runs, it relocates r_brk to be the actual address of _r_debug_state(). - - The debugger interface structure also contains an enumeration which - is set to either RT_ADD or RT_DELETE prior to changing the mapping, - depending upon whether or not the library is being mapped or unmapped, - and then set to RT_CONSISTENT after the library is mapped/unmapped. -*/ - -static int -enable_break () -{ - int success = 0; - -#ifndef SVR4_SHARED_LIBS - - int j; - int in_debugger; - - /* Get link_dynamic structure */ - - j = target_read_memory (debug_base, (char *) &dynamic_copy, - sizeof (dynamic_copy)); - if (j) - { - /* unreadable */ - return (0); - } - - /* Calc address of debugger interface structure */ - - debug_addr = (CORE_ADDR) dynamic_copy.ldd; - - /* Calc address of `in_debugger' member of debugger interface structure */ - - flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger - - (char *) &debug_copy); - - /* Write a value of 1 to this member. */ - - in_debugger = 1; - write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); - success = 1; +/* GLOBAL FUNCTION -#else /* SVR4_SHARED_LIBS */ + in_solib_dynsym_resolve_code -- check to see if an address is in + dynamic loader's dynamic symbol + resolution code -#ifdef BKPT_AT_SYMBOL + SYNOPSIS - struct minimal_symbol *msymbol; - char **bkpt_namep; - asection *interp_sect; + int in_solib_dynsym_resolve_code (CORE_ADDR pc) - /* First, remove all the solib event breakpoints. Their addresses - may have changed since the last time we ran the program. */ - remove_solib_event_breakpoints (); + DESCRIPTION -#ifdef SVR4_SHARED_LIBS - interp_text_sect_low = interp_text_sect_high = 0; - interp_plt_sect_low = interp_plt_sect_high = 0; - - /* Find the .interp section; if not found, warn the user and drop - into the old breakpoint at symbol code. */ - interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); - if (interp_sect) - { - unsigned int interp_sect_size; - char *buf; - CORE_ADDR load_addr; - bfd *tmp_bfd; - CORE_ADDR sym_addr = 0; - - /* Read the contents of the .interp section into a local buffer; - the contents specify the dynamic linker this program uses. */ - interp_sect_size = bfd_section_size (exec_bfd, interp_sect); - buf = alloca (interp_sect_size); - bfd_get_section_contents (exec_bfd, interp_sect, - buf, 0, interp_sect_size); - - /* Now we need to figure out where the dynamic linker was - loaded so that we can load its symbols and place a breakpoint - in the dynamic linker itself. - - This address is stored on the stack. However, I've been unable - to find any magic formula to find it for Solaris (appears to - be trivial on GNU/Linux). Therefore, we have to try an alternate - mechanism to find the dynamic linker's base address. */ - tmp_bfd = bfd_openr (buf, gnutarget); - if (tmp_bfd == NULL) - goto bkpt_at_symbol; - - /* Make sure the dynamic linker's really a useful object. */ - if (!bfd_check_format (tmp_bfd, bfd_object)) - { - warning ("Unable to grok dynamic linker %s as an object file", buf); - bfd_close (tmp_bfd); - goto bkpt_at_symbol; - } - - /* We find the dynamic linker's base address by examining the - current pc (which point at the entry point for the dynamic - linker) and subtracting the offset of the entry point. */ - load_addr = read_pc () - tmp_bfd->start_address; - - /* Record the relocated start and end address of the dynamic linker - text and plt section for in_svr4_dynsym_resolve_code. */ - interp_sect = bfd_get_section_by_name (tmp_bfd, ".text"); - if (interp_sect) - { - interp_text_sect_low = - bfd_section_vma (tmp_bfd, interp_sect) + load_addr; - interp_text_sect_high = - interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect); - } - interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt"); - if (interp_sect) - { - interp_plt_sect_low = - bfd_section_vma (tmp_bfd, interp_sect) + load_addr; - interp_plt_sect_high = - interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect); - } - - /* Now try to set a breakpoint in the dynamic linker. */ - for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++) - { - sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep); - if (sym_addr != 0) - break; - } - - /* We're done with the temporary bfd. */ - bfd_close (tmp_bfd); - - if (sym_addr != 0) - { - create_solib_event_breakpoint (load_addr + sym_addr); - return 1; - } - - /* For whatever reason we couldn't set a breakpoint in the dynamic - linker. Warn and drop into the old code. */ -bkpt_at_symbol: - warning ("Unable to find dynamic linker breakpoint function.\nGDB will be unable to debug shared library initializers\nand track explicitly loaded dynamic code."); - } -#endif - - /* Scan through the list of symbols, trying to look up the symbol and - set a breakpoint there. Terminate loop when we/if we succeed. */ - - breakpoint_addr = 0; - for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) - { - msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, symfile_objfile); - if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) - { - create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol)); - return 1; - } - } - - /* Nothing good happened. */ - success = 0; - -#endif /* BKPT_AT_SYMBOL */ - -#endif /* !SVR4_SHARED_LIBS */ + Determine if PC is in the dynamic linker's symbol resolution + code. Return 1 if so, 0 otherwise. +*/ - return (success); -} - -/* - -GLOBAL FUNCTION - - solib_create_inferior_hook -- shared library startup support - -SYNOPSIS - - void solib_create_inferior_hook() - -DESCRIPTION - - When gdb starts up the inferior, it nurses it along (through the - shell) until it is ready to execute it's first instruction. At this - point, this function gets called via expansion of the macro - SOLIB_CREATE_INFERIOR_HOOK. - - For SunOS executables, this first instruction is typically the - one at "_start", or a similar text label, regardless of whether - the executable is statically or dynamically linked. The runtime - startup code takes care of dynamically linking in any shared - libraries, once gdb allows the inferior to continue. - - For SVR4 executables, this first instruction is either the first - instruction in the dynamic linker (for dynamically linked - executables) or the instruction at "start" for statically linked - executables. For dynamically linked executables, the system - first exec's /lib/libc.so.N, which contains the dynamic linker, - and starts it running. The dynamic linker maps in any needed - shared libraries, maps in the actual user executable, and then - jumps to "start" in the user executable. - - For both SunOS shared libraries, and SVR4 shared libraries, we - can arrange to cooperate with the dynamic linker to discover the - names of shared libraries that are dynamically linked, and the - base addresses to which they are linked. - - This function is responsible for discovering those names and - addresses, and saving sufficient information about them to allow - their symbols to be read at a later time. - -FIXME - - Between enable_break() and disable_break(), this code does not - properly handle hitting breakpoints which the user might have - set in the startup code or in the dynamic linker itself. Proper - handling will probably have to wait until the implementation is - changed to use the "breakpoint handler function" method. - - Also, what if child has exit()ed? Must exit loop somehow. - */ - -void -solib_create_inferior_hook() +int +in_solib_dynsym_resolve_code (CORE_ADDR pc) { - /* If we are using the BKPT_AT_SYMBOL code, then we don't need the base - yet. In fact, in the case of a SunOS4 executable being run on - Solaris, we can't get it yet. find_solib will get it when it needs - it. */ -#if !(defined (SVR4_SHARED_LIBS) && defined (BKPT_AT_SYMBOL)) - if ((debug_base = locate_base ()) == 0) - { - /* Can't find the symbol or the executable is statically linked. */ - return; - } -#endif - - if (!enable_break ()) - { - warning ("shared library handler failed to enable breakpoint"); - return; - } - -#if !defined(SVR4_SHARED_LIBS) || defined(_SCO_DS) - /* SCO and SunOS need the loop below, other systems should be using the - special shared library breakpoints and the shared library breakpoint - service routine. - - Now run the target. It will eventually hit the breakpoint, at - which point all of the libraries will have been mapped in and we - can go groveling around in the dynamic linker structures to find - out what we need to know about them. */ - - clear_proceed_status (); - stop_soon_quietly = 1; - stop_signal = TARGET_SIGNAL_0; - do - { - target_resume (-1, 0, stop_signal); - wait_for_inferior (); - } - while (stop_signal != TARGET_SIGNAL_TRAP); - stop_soon_quietly = 0; - -#if !defined(_SCO_DS) - /* We are now either at the "mapping complete" breakpoint (or somewhere - else, a condition we aren't prepared to deal with anyway), so adjust - the PC as necessary after a breakpoint, disable the breakpoint, and - add any shared libraries that were mapped in. */ - - if (DECR_PC_AFTER_BREAK) - { - stop_pc -= DECR_PC_AFTER_BREAK; - write_register (PC_REGNUM, stop_pc); - } - - if (!disable_break ()) - { - warning ("shared library handler failed to disable breakpoint"); - } - - if (auto_solib_add) - solib_add ((char *) 0, 0, (struct target_ops *) 0); -#endif /* ! _SCO_DS */ -#endif + return TARGET_SO_IN_DYNSYM_RESOLVE_CODE (pc); } /* -LOCAL FUNCTION - - special_symbol_handling -- additional shared library symbol handling - -SYNOPSIS + LOCAL FUNCTION - void special_symbol_handling (struct so_list *so) + sharedlibrary_command -- handle command to explicitly add library -DESCRIPTION + SYNOPSIS - Once the symbols from a shared object have been loaded in the usual - way, we are called to do any system specific symbol handling that - is needed. + static void sharedlibrary_command (char *args, int from_tty) - For SunOS4, this consists of grunging around in the dynamic - linkers structures to find symbol definitions for "common" symbols - and adding them to the minimal symbol table for the runtime common - objfile. + DESCRIPTION -*/ + */ static void -special_symbol_handling (so) -struct so_list *so; +sharedlibrary_command (char *args, int from_tty) { -#ifndef SVR4_SHARED_LIBS - int j; - - if (debug_addr == 0) - { - /* Get link_dynamic structure */ - - j = target_read_memory (debug_base, (char *) &dynamic_copy, - sizeof (dynamic_copy)); - if (j) - { - /* unreadable */ - return; - } - - /* Calc address of debugger interface structure */ - /* FIXME, this needs work for cross-debugging of core files - (byteorder, size, alignment, etc). */ - - debug_addr = (CORE_ADDR) dynamic_copy.ldd; - } - - /* Read the debugger structure from the inferior, just to make sure - we have a current copy. */ - - j = target_read_memory (debug_addr, (char *) &debug_copy, - sizeof (debug_copy)); - if (j) - return; /* unreadable */ - - /* Get common symbol definitions for the loaded object. */ - - if (debug_copy.ldd_cp) - { - solib_add_common_symbols (debug_copy.ldd_cp); - } - -#endif /* !SVR4_SHARED_LIBS */ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0, 1); } +/* LOCAL FUNCTION -/* - -LOCAL FUNCTION - - sharedlibrary_command -- handle command to explicitly add library - -SYNOPSIS + no_shared_libraries -- handle command to explicitly discard symbols + from shared libraries. - static void sharedlibrary_command (char *args, int from_tty) + DESCRIPTION -DESCRIPTION - -*/ + Implements the command "nosharedlibrary", which discards symbols + that have been auto-loaded from shared libraries. Symbols from + shared libraries that were added by explicit request of the user + are not discarded. Also called from remote.c. */ -static void -sharedlibrary_command (args, from_tty) -char *args; -int from_tty; +void +no_shared_libraries (char *ignored, int from_tty) { - dont_repeat (); - solib_add (args, from_tty, (struct target_ops *) 0); + objfile_purge_solibs (); + do_clear_solib (NULL); } -#endif /* HAVE_LINK_H */ - void -_initialize_solib() +_initialize_solib (void) { -#ifdef HAVE_LINK_H + struct cmd_list_element *c; add_com ("sharedlibrary", class_files, sharedlibrary_command, "Load shared object library symbols for files matching REGEXP."); - add_info ("sharedlibrary", info_sharedlibrary_command, + add_info ("sharedlibrary", info_sharedlibrary_command, "Status of loaded shared object libraries."); + add_com ("nosharedlibrary", class_files, no_shared_libraries, + "Unload all shared object library symbols."); add_show_from_set - (add_set_cmd ("auto-solib-add", class_support, var_zinteger, + (add_set_cmd ("auto-solib-add", class_support, var_boolean, (char *) &auto_solib_add, "Set autoloading of shared library symbols.\n\ -If nonzero, symbols from all shared object libraries will be loaded\n\ -automatically when the inferior begins execution or when the dynamic linker\n\ -informs gdb that a new library has been loaded. Otherwise, symbols\n\ -must be loaded manually, using `sharedlibrary'.", +If \"on\", symbols from all shared object libraries will be loaded\n\ +automatically when the inferior begins execution, when the dynamic linker\n\ +informs gdb that a new library has been loaded, or when attaching to the\n\ +inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.", &setlist), &showlist); - add_show_from_set - (add_set_cmd ("solib-absolute-prefix", class_support, var_filename, - (char *) &solib_absolute_prefix, - "Set prefix for loading absolute shared library symbol files.\n\ + c = add_set_cmd ("solib-absolute-prefix", class_support, var_filename, + (char *) &solib_absolute_prefix, + "Set prefix for loading absolute shared library symbol files.\n\ For other (relative) files, you can add values using `set solib-search-path'.", - &setlist), - &showlist); - add_show_from_set - (add_set_cmd ("solib-search-path", class_support, var_string, - (char *) &solib_search_path, - "Set the search path for loading non-absolute shared library symbol files.\n\ -This takes precedence over the environment variables PATH and LD_LIBRARY_PATH.", - &setlist), - &showlist); + &setlist); + add_show_from_set (c, &showlist); + c->completer = filename_completer; -#endif /* HAVE_LINK_H */ + c = add_set_cmd ("solib-search-path", class_support, var_string, + (char *) &solib_search_path, + "Set the search path for loading non-absolute shared library symbol files.\n\ +This takes precedence over the environment variables PATH and LD_LIBRARY_PATH.", + &setlist); + add_show_from_set (c, &showlist); + c->completer = filename_completer; } diff --git a/contrib/gdb/gdb/symtab.c b/contrib/gdb/gdb/symtab.c index 1354df5..e464b0b 100644 --- a/contrib/gdb/gdb/symtab.c +++ b/contrib/gdb/gdb/symtab.c @@ -1,22 +1,25 @@ /* Symbol table lookup for the GNU debugger, GDB. - Copyright 1986, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 1998 - Free Software Foundation, Inc. -This file is part of GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software + Foundation, Inc. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This file is part of GDB. -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. + 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. -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. */ + 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 "symtab.h" @@ -29,11 +32,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "objfiles.h" #include "gdbcmd.h" #include "call-cmds.h" -#include "gnu-regex.h" +#include "gdb_regex.h" #include "expression.h" #include "language.h" #include "demangle.h" #include "inferior.h" +#include "linespec.h" +#include "filenames.h" /* for FILENAME_CMP */ #include "obstack.h" @@ -42,73 +47,66 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdb_string.h" #include "gdb_stat.h" #include <ctype.h> +#include "cp-abi.h" /* Prototype for one function in parser-defs.h, instead of including that entire file. */ -extern char * find_template_name_end PARAMS ((char *)); +extern char *find_template_name_end (char *); /* Prototypes for local functions */ -static int find_methods PARAMS ((struct type *, char *, struct symbol **)); - -static void completion_list_add_name PARAMS ((char *, char *, int, char *, - char *)); - -static void build_canonical_line_spec PARAMS ((struct symtab_and_line *, - char *, char ***)); +static void completion_list_add_name (char *, char *, int, char *, char *); -static struct symtabs_and_lines decode_line_2 PARAMS ((struct symbol *[], - int, int, char ***)); +static void rbreak_command (char *, int); -static void rbreak_command PARAMS ((char *, int)); +static void types_info (char *, int); -static void types_info PARAMS ((char *, int)); +static void functions_info (char *, int); -static void functions_info PARAMS ((char *, int)); +static void variables_info (char *, int); -static void variables_info PARAMS ((char *, int)); +static void sources_info (char *, int); -static void sources_info PARAMS ((char *, int)); +static void output_source_filename (char *, int *); -static void output_source_filename PARAMS ((char *, int *)); +static int find_line_common (struct linetable *, int, int *); -char *operator_chars PARAMS ((char *, char **)); +/* This one is used by linespec.c */ -static int find_line_common PARAMS ((struct linetable *, int, int *)); +char *operator_chars (char *p, char **end); -static struct partial_symbol *lookup_partial_symbol PARAMS - ((struct partial_symtab *, const char *, - int, namespace_enum)); +static struct partial_symbol *lookup_partial_symbol (struct partial_symtab *, + const char *, int, + namespace_enum); -static struct partial_symbol *fixup_psymbol_section PARAMS ((struct - partial_symbol *, struct objfile *)); +static struct symbol *lookup_symbol_aux (const char *name, const + struct block *block, const + namespace_enum namespace, int + *is_a_field_of_this, struct + symtab **symtab); -static struct symtab *lookup_symtab_1 PARAMS ((char *)); -static void cplusplus_hint PARAMS ((char *)); - -static struct symbol *find_active_alias PARAMS ((struct symbol *sym, - CORE_ADDR addr)); +static struct symbol *find_active_alias (struct symbol *sym, CORE_ADDR addr); /* This flag is used in hppa-tdep.c, and set in hp-symtab-read.c */ /* Signals the presence of objects compiled by HP compilers */ int hp_som_som_object_present = 0; -static void fixup_section PARAMS ((struct general_symbol_info *, - struct objfile *)); +static void fixup_section (struct general_symbol_info *, struct objfile *); + +static int file_matches (char *, char **, int); -static int file_matches PARAMS ((char *, char **, int)); +static void print_symbol_info (namespace_enum, + struct symtab *, struct symbol *, int, char *); -static void print_symbol_info PARAMS ((namespace_enum, - struct symtab *, struct symbol *, - int, char *)); +static void print_msymbol_info (struct minimal_symbol *); -static void print_msymbol_info PARAMS ((struct minimal_symbol *)); +static void symtab_symbol_info (char *, namespace_enum, int); -static void symtab_symbol_info PARAMS ((char *, namespace_enum, int)); +static void overload_list_add_symbol (struct symbol *sym, char *oload_name); -void _initialize_symtab PARAMS ((void)); +void _initialize_symtab (void); /* */ @@ -121,15 +119,12 @@ struct type *builtin_type_error; const struct block *block_found; -char no_symtab_msg[] = "No symbol table is loaded. Use the \"file\" command."; - /* While the C++ support is still in flux, issue a possibly helpful hint on using the new command completion feature on single quoted demangled C++ symbols. Remove when loose ends are cleaned up. FIXME -fnf */ static void -cplusplus_hint (name) - char *name; +cplusplus_hint (char *name) { while (*name == '\'') name++; @@ -141,39 +136,53 @@ cplusplus_hint (name) psymtabs. *If* there is no '/' in the name, a match after a '/' in the symtab filename will also work. */ -static struct symtab * -lookup_symtab_1 (name) - char *name; +struct symtab * +lookup_symtab (const char *name) { register struct symtab *s; register struct partial_symtab *ps; - register char *slash; register struct objfile *objfile; + char *real_path = NULL; - got_symtab: + /* Here we are interested in canonicalizing an absolute path, not + absolutizing a relative path. */ + if (IS_ABSOLUTE_PATH (name)) + real_path = gdb_realpath (name); + +got_symtab: /* First, search for an exact match */ ALL_SYMTABS (objfile, s) - if (STREQ (name, s->filename)) - return s; + { + if (FILENAME_CMP (name, s->filename) == 0) + { + xfree (real_path); + return s; + } + /* If the user gave us an absolute path, try to find the file in + this symtab and use its absolute path. */ + if (real_path != NULL) + { + char *rp = symtab_to_filename (s); + if (FILENAME_CMP (real_path, rp) == 0) + { + xfree (real_path); + return s; + } + } + } - slash = strchr (name, '/'); + xfree (real_path); /* Now, search for a matching tail (only if name doesn't have any dirs) */ - if (!slash) + if (lbasename (name) == name) ALL_SYMTABS (objfile, s) - { - char *p = s -> filename; - char *tail = strrchr (p, '/'); - - if (tail) - p = tail + 1; - - if (STREQ (p, name)) - return s; - } + { + if (FILENAME_CMP (lbasename (s->filename), name) == 0) + return s; + } /* Same search rules as above apply here, but now we look thru the psymtabs. */ @@ -182,9 +191,9 @@ lookup_symtab_1 (name) if (!ps) return (NULL); - if (ps -> readin) + if (ps->readin) error ("Internal: readin %s pst for `%s' found when no symtab found.", - ps -> filename, name); + ps->filename, name); s = PSYMTAB_TO_SYMTAB (ps); @@ -202,74 +211,54 @@ lookup_symtab_1 (name) goto got_symtab; } -/* Lookup the symbol table of a source file named NAME. Try a couple - of variations if the first lookup doesn't work. */ - -struct symtab * -lookup_symtab (name) - char *name; -{ - register struct symtab *s; -#if 0 - register char *copy; -#endif - - s = lookup_symtab_1 (name); - if (s) return s; - -#if 0 - /* This screws c-exp.y:yylex if there is both a type "tree" and a symtab - "tree.c". */ - - /* If name not found as specified, see if adding ".c" helps. */ - /* Why is this? Is it just a user convenience? (If so, it's pretty - questionable in the presence of C++, FORTRAN, etc.). It's not in - the GDB manual. */ - - copy = (char *) alloca (strlen (name) + 3); - strcpy (copy, name); - strcat (copy, ".c"); - s = lookup_symtab_1 (copy); - if (s) return s; -#endif /* 0 */ - - /* We didn't find anything; die. */ - return 0; -} - /* Lookup the partial symbol table of a source file named NAME. *If* there is no '/' in the name, a match after a '/' in the psymtab filename will also work. */ struct partial_symtab * -lookup_partial_symtab (name) -char *name; +lookup_partial_symtab (const char *name) { register struct partial_symtab *pst; register struct objfile *objfile; - - ALL_PSYMTABS (objfile, pst) - { - if (STREQ (name, pst -> filename)) - { - return (pst); - } - } + char *real_path = NULL; - /* Now, search for a matching tail (only if name doesn't have any dirs) */ + /* Here we are interested in canonicalizing an absolute path, not + absolutizing a relative path. */ + if (IS_ABSOLUTE_PATH (name)) + real_path = gdb_realpath (name); - if (!strchr (name, '/')) - ALL_PSYMTABS (objfile, pst) + ALL_PSYMTABS (objfile, pst) + { + if (FILENAME_CMP (name, pst->filename) == 0) + { + xfree (real_path); + return (pst); + } + /* If the user gave us an absolute path, try to find the file in + this symtab and use its absolute path. */ + if (real_path != NULL) { - char *p = pst -> filename; - char *tail = strrchr (p, '/'); + if (pst->fullname == NULL) + source_full_path_of (pst->filename, &pst->fullname); + if (pst->fullname != NULL + && FILENAME_CMP (real_path, pst->fullname) == 0) + { + xfree (real_path); + return pst; + } + } + } - if (tail) - p = tail + 1; + xfree (real_path); - if (STREQ (p, name)) - return (pst); - } + /* Now, search for a matching tail (only if name doesn't have any dirs) */ + + if (lbasename (name) == name) + ALL_PSYMTABS (objfile, pst) + { + if (FILENAME_CMP (lbasename (pst->filename), name) == 0) + return (pst); + } return (NULL); } @@ -280,9 +269,7 @@ char *name; specified by SIGNATURE_ID. Note that this function is g++ specific. */ char * -gdb_mangle_name (type, method_id, signature_id) - struct type *type; - int method_id, signature_id; +gdb_mangle_name (struct type *type, int method_id, int signature_id) { int mangled_name_len; char *mangled_name; @@ -297,28 +284,31 @@ gdb_mangle_name (type, method_id, signature_id) int is_full_physname_constructor; int is_constructor; - int is_destructor = DESTRUCTOR_PREFIX_P (physname); + int is_destructor = is_destructor_name (physname); /* Need a new type prefix. */ char *const_prefix = method->is_const ? "C" : ""; char *volatile_prefix = method->is_volatile ? "V" : ""; char buf[20]; int len = (newname == NULL ? 0 : strlen (newname)); - is_full_physname_constructor = - ((physname[0]=='_' && physname[1]=='_' && - (isdigit(physname[2]) || physname[2]=='Q' || physname[2]=='t')) - || (strncmp(physname, "__ct", 4) == 0)); + /* Nothing to do if physname already contains a fully mangled v3 abi name + or an operator name. */ + if ((physname[0] == '_' && physname[1] == 'Z') + || is_operator_name (field_name)) + return xstrdup (physname); + + is_full_physname_constructor = is_constructor_name (physname); is_constructor = - is_full_physname_constructor || (newname && STREQ(field_name, newname)); + is_full_physname_constructor || (newname && STREQ (field_name, newname)); if (!is_destructor) - is_destructor = (strncmp(physname, "__dt", 4) == 0); + is_destructor = (strncmp (physname, "__dt", 4) == 0); if (is_destructor || is_full_physname_constructor) { - mangled_name = (char*) xmalloc(strlen(physname)+1); - strcpy(mangled_name, physname); + mangled_name = (char *) xmalloc (strlen (physname) + 1); + strcpy (mangled_name, physname); return mangled_name; } @@ -329,7 +319,7 @@ gdb_mangle_name (type, method_id, signature_id) else if (physname[0] == 't' || physname[0] == 'Q') { /* The physname for template and qualified methods already includes - the class name. */ + the class name. */ sprintf (buf, "__%s%s", const_prefix, volatile_prefix); newname = NULL; len = 0; @@ -339,27 +329,10 @@ gdb_mangle_name (type, method_id, signature_id) sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); } mangled_name_len = ((is_constructor ? 0 : strlen (field_name)) - + strlen (buf) + len - + strlen (physname) - + 1); + + strlen (buf) + len + strlen (physname) + 1); - /* Only needed for GNU-mangled names. ANSI-mangled names - work with the normal mechanisms. */ - if (OPNAME_PREFIX_P (field_name)) { - const char *opname = cplus_mangle_opname (field_name + 3, 0); - if (opname == NULL) - error ("No mangling for \"%s\"", field_name); - mangled_name_len += strlen (opname); - mangled_name = (char *)xmalloc (mangled_name_len); - - strncpy (mangled_name, field_name, 3); - mangled_name[3] = '\0'; - strcat (mangled_name, opname); - } - else - { - mangled_name = (char *)xmalloc (mangled_name_len); + mangled_name = (char *) xmalloc (mangled_name_len); if (is_constructor) mangled_name[0] = '\0'; else @@ -368,69 +341,70 @@ gdb_mangle_name (type, method_id, signature_id) strcat (mangled_name, buf); /* If the class doesn't have a name, i.e. newname NULL, then we just mangle it using 0 for the length of the class. Thus it gets mangled - as something starting with `::' rather than `classname::'. */ + as something starting with `::' rather than `classname::'. */ if (newname != NULL) strcat (mangled_name, newname); strcat (mangled_name, physname); return (mangled_name); } - + /* Find which partial symtab on contains PC and SECTION. Return 0 if none. */ struct partial_symtab * -find_pc_sect_psymtab (pc, section) - CORE_ADDR pc; - asection *section; +find_pc_sect_psymtab (CORE_ADDR pc, asection *section) { register struct partial_symtab *pst; register struct objfile *objfile; + struct minimal_symbol *msymbol; + + /* If we know that this is not a text address, return failure. This is + necessary because we loop based on texthigh and textlow, which do + not include the data ranges. */ + msymbol = lookup_minimal_symbol_by_pc_section (pc, section); + if (msymbol + && (msymbol->type == mst_data + || msymbol->type == mst_bss + || msymbol->type == mst_abs + || msymbol->type == mst_file_data + || msymbol->type == mst_file_bss)) + return NULL; ALL_PSYMTABS (objfile, pst) - { -#if defined(HPUXHPPA) - if (pc >= pst->textlow && pc <= pst->texthigh) -#else - if (pc >= pst->textlow && pc < pst->texthigh) -#endif - { - struct minimal_symbol *msymbol; - struct partial_symtab *tpst; - - /* An objfile that has its functions reordered might have - many partial symbol tables containing the PC, but - we want the partial symbol table that contains the - function containing the PC. */ - if (!(objfile->flags & OBJF_REORDERED) && - section == 0) /* can't validate section this way */ - return (pst); - - msymbol = lookup_minimal_symbol_by_pc_section (pc, section); - if (msymbol == NULL) - return (pst); - - for (tpst = pst; tpst != NULL; tpst = tpst->next) - { -#if defined(HPUXHPPA) - if (pc >= tpst->textlow && pc <= tpst->texthigh) -#else - if (pc >= tpst->textlow && pc < tpst->texthigh) -#endif - { - struct partial_symbol *p; + { + if (pc >= pst->textlow && pc < pst->texthigh) + { + struct partial_symtab *tpst; + + /* An objfile that has its functions reordered might have + many partial symbol tables containing the PC, but + we want the partial symbol table that contains the + function containing the PC. */ + if (!(objfile->flags & OBJF_REORDERED) && + section == 0) /* can't validate section this way */ + return (pst); - p = find_pc_sect_psymbol (tpst, pc, section); - if (p != NULL - && SYMBOL_VALUE_ADDRESS(p) - == SYMBOL_VALUE_ADDRESS (msymbol)) - return (tpst); - } - } + if (msymbol == NULL) return (pst); - } - } + + for (tpst = pst; tpst != NULL; tpst = tpst->next) + { + if (pc >= tpst->textlow && pc < tpst->texthigh) + { + struct partial_symbol *p; + + p = find_pc_sect_psymbol (tpst, pc, section); + if (p != NULL + && SYMBOL_VALUE_ADDRESS (p) + == SYMBOL_VALUE_ADDRESS (msymbol)) + return (tpst); + } + } + return (pst); + } + } return (NULL); } @@ -438,8 +412,7 @@ find_pc_sect_psymtab (pc, section) Backward compatibility, no section */ struct partial_symtab * -find_pc_psymtab (pc) - CORE_ADDR pc; +find_pc_psymtab (CORE_ADDR pc) { return find_pc_sect_psymtab (pc, find_pc_mapped_section (pc)); } @@ -448,14 +421,12 @@ find_pc_psymtab (pc) Return 0 if none. Check all psymtabs if PSYMTAB is 0. */ struct partial_symbol * -find_pc_sect_psymbol (psymtab, pc, section) - struct partial_symtab *psymtab; - CORE_ADDR pc; - asection *section; +find_pc_sect_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc, + asection *section) { struct partial_symbol *best = NULL, *p, **pp; CORE_ADDR best_pc; - + if (!psymtab) psymtab = find_pc_sect_psymtab (pc, section); if (!psymtab) @@ -468,8 +439,8 @@ find_pc_sect_psymbol (psymtab, pc, section) find_pc_partial_function doesn't use a minimal symbol and thus cache a bad endaddr. */ for (pp = psymtab->objfile->global_psymbols.list + psymtab->globals_offset; - (pp - (psymtab->objfile->global_psymbols.list + psymtab->globals_offset) - < psymtab->n_global_syms); + (pp - (psymtab->objfile->global_psymbols.list + psymtab->globals_offset) + < psymtab->n_global_syms); pp++) { p = *pp; @@ -480,7 +451,7 @@ find_pc_sect_psymbol (psymtab, pc, section) || (psymtab->textlow == 0 && best_pc == 0 && SYMBOL_VALUE_ADDRESS (p) == 0))) { - if (section) /* match on a specific section */ + if (section) /* match on a specific section */ { fixup_psymbol_section (p, psymtab->objfile); if (SYMBOL_BFD_SECTION (p) != section) @@ -492,8 +463,8 @@ find_pc_sect_psymbol (psymtab, pc, section) } for (pp = psymtab->objfile->static_psymbols.list + psymtab->statics_offset; - (pp - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset) - < psymtab->n_static_syms); + (pp - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset) + < psymtab->n_static_syms); pp++) { p = *pp; @@ -501,10 +472,10 @@ find_pc_sect_psymbol (psymtab, pc, section) && SYMBOL_CLASS (p) == LOC_BLOCK && pc >= SYMBOL_VALUE_ADDRESS (p) && (SYMBOL_VALUE_ADDRESS (p) > best_pc - || (psymtab->textlow == 0 + || (psymtab->textlow == 0 && best_pc == 0 && SYMBOL_VALUE_ADDRESS (p) == 0))) { - if (section) /* match on a specific section */ + if (section) /* match on a specific section */ { fixup_psymbol_section (p, psymtab->objfile); if (SYMBOL_BFD_SECTION (p) != section) @@ -522,9 +493,7 @@ find_pc_sect_psymbol (psymtab, pc, section) Check all psymtabs if PSYMTAB is 0. Backwards compatibility, no section. */ struct partial_symbol * -find_pc_psymbol (psymtab, pc) - struct partial_symtab *psymtab; - CORE_ADDR pc; +find_pc_psymbol (struct partial_symtab *psymtab, CORE_ADDR pc) { return find_pc_sect_psymbol (psymtab, pc, find_pc_mapped_section (pc)); } @@ -533,21 +502,20 @@ find_pc_psymbol (psymtab, pc) out of the minimal symbols and stash that in the debug symbol. */ static void -fixup_section (ginfo, objfile) - struct general_symbol_info *ginfo; - struct objfile *objfile; +fixup_section (struct general_symbol_info *ginfo, struct objfile *objfile) { struct minimal_symbol *msym; msym = lookup_minimal_symbol (ginfo->name, NULL, objfile); if (msym) - ginfo->bfd_section = SYMBOL_BFD_SECTION (msym); + { + ginfo->bfd_section = SYMBOL_BFD_SECTION (msym); + ginfo->section = SYMBOL_SECTION (msym); + } } struct symbol * -fixup_symbol_section (sym, objfile) - struct symbol *sym; - struct objfile *objfile; +fixup_symbol_section (struct symbol *sym, struct objfile *objfile) { if (!sym) return NULL; @@ -560,10 +528,8 @@ fixup_symbol_section (sym, objfile) return sym; } -static struct partial_symbol * -fixup_psymbol_section (psym, objfile) - struct partial_symbol *psym; - struct objfile *objfile; +struct partial_symbol * +fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile) { if (!psym) return NULL; @@ -598,42 +564,85 @@ fixup_psymbol_section (psym, objfile) can probably assume it will never hit the C++ code). */ struct symbol * -lookup_symbol (name, block, namespace, is_a_field_of_this, symtab) - const char *name; - register const struct block *block; - const namespace_enum namespace; - int *is_a_field_of_this; - struct symtab **symtab; +lookup_symbol (const char *name, const struct block *block, + const namespace_enum namespace, int *is_a_field_of_this, + struct symtab **symtab) +{ + char *modified_name = NULL; + char *modified_name2 = NULL; + int needtofreename = 0; + struct symbol *returnval; + + if (case_sensitivity == case_sensitive_off) + { + char *copy; + int len, i; + + len = strlen (name); + copy = (char *) alloca (len + 1); + for (i= 0; i < len; i++) + copy[i] = tolower (name[i]); + copy[len] = 0; + modified_name = copy; + } + else + modified_name = (char *) name; + + /* If we are using C++ language, demangle the name before doing a lookup, so + we can always binary search. */ + if (current_language->la_language == language_cplus) + { + modified_name2 = cplus_demangle (modified_name, DMGL_ANSI | DMGL_PARAMS); + if (modified_name2) + { + modified_name = modified_name2; + needtofreename = 1; + } + } + + returnval = lookup_symbol_aux (modified_name, block, namespace, + is_a_field_of_this, symtab); + if (needtofreename) + xfree (modified_name2); + + return returnval; +} + +static struct symbol * +lookup_symbol_aux (const char *name, const struct block *block, + const namespace_enum namespace, int *is_a_field_of_this, + struct symtab **symtab) { register struct symbol *sym; register struct symtab *s = NULL; register struct partial_symtab *ps; - struct blockvector *bv; + register struct blockvector *bv; register struct objfile *objfile = NULL; register struct block *b; register struct minimal_symbol *msymbol; + /* Search specified block and its superiors. */ while (block != 0) { sym = lookup_block_symbol (block, name, namespace); - if (sym) + if (sym) { block_found = block; if (symtab != NULL) { /* Search the list of symtabs for one which contains the - address of the start of this block. */ + address of the start of this block. */ ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - if (BLOCK_START (b) <= BLOCK_START (block) - && BLOCK_END (b) > BLOCK_START (block)) - goto found; - } -found: + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + if (BLOCK_START (b) <= BLOCK_START (block) + && BLOCK_END (b) > BLOCK_START (block)) + goto found; + } + found: *symtab = s; } @@ -664,22 +673,22 @@ found: struct block *b; /* Find the right symtab. */ ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - if (BLOCK_START (b) <= BLOCK_START (block) - && BLOCK_END (b) > BLOCK_START (block)) - { - sym = lookup_block_symbol (b, name, VAR_NAMESPACE); - if (sym) - { - block_found = b; - if (symtab != NULL) - *symtab = s; - return fixup_symbol_section (sym, objfile); - } - } - } + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + if (BLOCK_START (b) <= BLOCK_START (block) + && BLOCK_END (b) > BLOCK_START (block)) + { + sym = lookup_block_symbol (b, name, VAR_NAMESPACE); + if (sym) + { + block_found = b; + if (symtab != NULL) + *symtab = s; + return fixup_symbol_section (sym, objfile); + } + } + } } @@ -688,7 +697,7 @@ found: if (is_a_field_of_this) { struct value *v = value_of_this (0); - + *is_a_field_of_this = 0; if (v && check_field (v, name)) { @@ -703,34 +712,34 @@ found: check the psymtab's. If a psymtab indicates the existence of the desired name as a global, then do psymtab-to-symtab conversion on the fly and return the found symbol. */ - + ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, namespace); - if (sym) - { - block_found = block; - if (symtab != NULL) - *symtab = s; - return fixup_symbol_section (sym, objfile); - } - } + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return fixup_symbol_section (sym, objfile); + } + } #ifndef HPUXHPPA /* Check for the possibility of the symbol being a function or a mangled variable that is stored in one of the minimal symbol tables. Eventually, all global symbols might be resolved in this way. */ - + if (namespace == VAR_NAMESPACE) { msymbol = lookup_minimal_symbol (name, NULL, NULL); if (msymbol != NULL) { s = find_pc_sect_symtab (SYMBOL_VALUE_ADDRESS (msymbol), - SYMBOL_BFD_SECTION (msymbol)); + SYMBOL_BFD_SECTION (msymbol)); if (s != NULL) { /* This is a function which has a symtab for its address. */ @@ -738,26 +747,27 @@ found: block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), namespace); - /* We kept static functions in minimal symbol table as well as - in static scope. We want to find them in the symbol table. */ - if (!sym) { + /* We kept static functions in minimal symbol table as well as + in static scope. We want to find them in the symbol table. */ + if (!sym) + { block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), namespace); } /* sym == 0 if symbol was found in the minimal symbol table - but not in the symtab. - Return 0 to use the msymbol definition of "foo_". + but not in the symtab. + Return 0 to use the msymbol definition of "foo_". - This happens for Fortran "foo_" symbols, - which are "foo" in the symtab. + This happens for Fortran "foo_" symbols, + which are "foo" in the symtab. - This can also happen if "asm" is used to make a - regular symbol but not a debugging symbol, e.g. - asm(".globl _main"); - asm("_main:"); - */ + This can also happen if "asm" is used to make a + regular symbol but not a debugging symbol, e.g. + asm(".globl _main"); + asm("_main:"); + */ if (symtab != NULL) *symtab = s; @@ -768,46 +778,46 @@ found: && !STREQ (name, SYMBOL_NAME (msymbol))) { /* This is a mangled variable, look it up by its - mangled name. */ - return lookup_symbol (SYMBOL_NAME (msymbol), block, - namespace, is_a_field_of_this, symtab); + mangled name. */ + return lookup_symbol_aux (SYMBOL_NAME (msymbol), block, + namespace, is_a_field_of_this, symtab); } /* There are no debug symbols for this file, or we are looking for an unmangled variable. Try to find a matching static symbol below. */ } } - + #endif ALL_PSYMTABS (objfile, ps) - { - if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace)) - { - s = PSYMTAB_TO_SYMTAB(ps); - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, namespace); - if (!sym) - { - /* This shouldn't be necessary, but as a last resort - * try looking in the statics even though the psymtab - * claimed the symbol was global. It's possible that - * the psymtab gets it wrong in some cases. - */ - block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, namespace); - if (!sym) - error ("Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\ + { + if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace)) + { + s = PSYMTAB_TO_SYMTAB (ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + { + /* This shouldn't be necessary, but as a last resort + * try looking in the statics even though the psymtab + * claimed the symbol was global. It's possible that + * the psymtab gets it wrong in some cases. + */ + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + error ("Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ (if a template, try specifying an instantiation: %s<type>).", - name, ps->filename, name, name); - } - if (symtab != NULL) - *symtab = s; - return fixup_symbol_section (sym, objfile); - } - } + name, ps->filename, name, name); + } + if (symtab != NULL) + *symtab = s; + return fixup_symbol_section (sym, objfile); + } + } /* Now search all static file-level symbols. Not strictly correct, but more useful than an error. @@ -817,47 +827,47 @@ found: conversion on the fly and return the found symbol. */ ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, namespace); - if (sym) - { - block_found = block; - if (symtab != NULL) - *symtab = s; - return fixup_symbol_section (sym, objfile); - } - } + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return fixup_symbol_section (sym, objfile); + } + } ALL_PSYMTABS (objfile, ps) - { - if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace)) - { - s = PSYMTAB_TO_SYMTAB(ps); - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, namespace); - if (!sym) - { - /* This shouldn't be necessary, but as a last resort - * try looking in the globals even though the psymtab - * claimed the symbol was static. It's possible that - * the psymtab gets it wrong in some cases. - */ - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, namespace); - if (!sym) - error ("Internal: static symbol `%s' found in %s psymtab but not in symtab.\n\ + { + if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace)) + { + s = PSYMTAB_TO_SYMTAB (ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + { + /* This shouldn't be necessary, but as a last resort + * try looking in the globals even though the psymtab + * claimed the symbol was static. It's possible that + * the psymtab gets it wrong in some cases. + */ + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + error ("Internal: static symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ (if a template, try specifying an instantiation: %s<type>).", - name, ps->filename, name, name); - } - if (symtab != NULL) - *symtab = s; - return fixup_symbol_section (sym, objfile); - } - } + name, ps->filename, name, name); + } + if (symtab != NULL) + *symtab = s; + return fixup_symbol_section (sym, objfile); + } + } #ifdef HPUXHPPA @@ -875,28 +885,28 @@ found: though... is it saying we need to do the "minsym" check before the static check in this case? */ - + if (namespace == VAR_NAMESPACE) { msymbol = lookup_minimal_symbol (name, NULL, NULL); if (msymbol != NULL) { - /* OK, we found a minimal symbol in spite of not - * finding any symbol. There are various possible - * explanations for this. One possibility is the symbol - * exists in code not compiled -g. Another possibility - * is that the 'psymtab' isn't doing its job. - * A third possibility, related to #2, is that we were confused - * by name-mangling. For instance, maybe the psymtab isn't - * doing its job because it only know about demangled - * names, but we were given a mangled name... - */ - - /* We first use the address in the msymbol to try to - * locate the appropriate symtab. Note that find_pc_symtab() - * has a side-effect of doing psymtab-to-symtab expansion, - * for the found symtab. - */ + /* OK, we found a minimal symbol in spite of not + * finding any symbol. There are various possible + * explanations for this. One possibility is the symbol + * exists in code not compiled -g. Another possibility + * is that the 'psymtab' isn't doing its job. + * A third possibility, related to #2, is that we were confused + * by name-mangling. For instance, maybe the psymtab isn't + * doing its job because it only know about demangled + * names, but we were given a mangled name... + */ + + /* We first use the address in the msymbol to try to + * locate the appropriate symtab. Note that find_pc_symtab() + * has a side-effect of doing psymtab-to-symtab expansion, + * for the found symtab. + */ s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)); if (s != NULL) { @@ -904,50 +914,51 @@ found: block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), namespace); - /* We kept static functions in minimal symbol table as well as - in static scope. We want to find them in the symbol table. */ - if (!sym) - { + /* We kept static functions in minimal symbol table as well as + in static scope. We want to find them in the symbol table. */ + if (!sym) + { block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), namespace); } - /* If we found one, return it */ - if (sym) { - if (symtab != NULL) - *symtab = s; - return sym; - } + /* If we found one, return it */ + if (sym) + { + if (symtab != NULL) + *symtab = s; + return sym; + } /* If we get here with sym == 0, the symbol was - found in the minimal symbol table - but not in the symtab. - Fall through and return 0 to use the msymbol - definition of "foo_". - (Note that outer code generally follows up a call - to this routine with a call to lookup_minimal_symbol(), - so a 0 return means we'll just flow into that other routine). - - This happens for Fortran "foo_" symbols, - which are "foo" in the symtab. - - This can also happen if "asm" is used to make a - regular symbol but not a debugging symbol, e.g. - asm(".globl _main"); - asm("_main:"); - */ + found in the minimal symbol table + but not in the symtab. + Fall through and return 0 to use the msymbol + definition of "foo_". + (Note that outer code generally follows up a call + to this routine with a call to lookup_minimal_symbol(), + so a 0 return means we'll just flow into that other routine). + + This happens for Fortran "foo_" symbols, + which are "foo" in the symtab. + + This can also happen if "asm" is used to make a + regular symbol but not a debugging symbol, e.g. + asm(".globl _main"); + asm("_main:"); + */ } - /* If the lookup-by-address fails, try repeating the - * entire lookup process with the symbol name from - * the msymbol (if different from the original symbol name). - */ + /* If the lookup-by-address fails, try repeating the + * entire lookup process with the symbol name from + * the msymbol (if different from the original symbol name). + */ else if (MSYMBOL_TYPE (msymbol) != mst_text && MSYMBOL_TYPE (msymbol) != mst_file_text && !STREQ (name, SYMBOL_NAME (msymbol))) { - return lookup_symbol (SYMBOL_NAME (msymbol), block, - namespace, is_a_field_of_this, symtab); + return lookup_symbol_aux (SYMBOL_NAME (msymbol), block, + namespace, is_a_field_of_this, symtab); } } } @@ -958,39 +969,36 @@ found: *symtab = NULL; return 0; } - + /* Look, in partial_symtab PST, for symbol NAME. Check the global symbols if GLOBAL, the static symbols if not */ static struct partial_symbol * -lookup_partial_symbol (pst, name, global, namespace) - struct partial_symtab *pst; - const char *name; - int global; - namespace_enum namespace; +lookup_partial_symbol (struct partial_symtab *pst, const char *name, int global, + namespace_enum namespace) { + struct partial_symbol *temp; struct partial_symbol **start, **psym; struct partial_symbol **top, **bottom, **center; int length = (global ? pst->n_global_syms : pst->n_static_syms); int do_linear_search = 1; - + if (length == 0) { return (NULL); } - start = (global ? pst->objfile->global_psymbols.list + pst->globals_offset : - pst->objfile->static_psymbols.list + pst->statics_offset ); - - if (global) /* This means we can use a binary search. */ + pst->objfile->static_psymbols.list + pst->statics_offset); + + if (global) /* This means we can use a binary search. */ { do_linear_search = 0; /* Binary search. This search is guaranteed to end with center pointing at the earliest partial symbol with the correct - name. At that point *all* partial symbols with that name - will be checked against the correct namespace. */ + name. At that point *all* partial symbols with that name + will be checked against the correct namespace. */ bottom = start; top = start + length - 1; @@ -998,15 +1006,13 @@ lookup_partial_symbol (pst, name, global, namespace) { center = bottom + (top - bottom) / 2; if (!(center < top)) - abort (); + internal_error (__FILE__, __LINE__, "failed internal consistency check"); if (!do_linear_search - && (SYMBOL_LANGUAGE (*center) == language_cplus - || SYMBOL_LANGUAGE (*center) == language_java - )) + && (SYMBOL_LANGUAGE (*center) == language_java)) { do_linear_search = 1; } - if (STRCMP (SYMBOL_NAME (*center), name) >= 0) + if (strcmp (SYMBOL_SOURCE_NAME (*center), name) >= 0) { top = center; } @@ -1016,14 +1022,18 @@ lookup_partial_symbol (pst, name, global, namespace) } } if (!(top == bottom)) - abort (); - while (STREQ (SYMBOL_NAME (*top), name)) + internal_error (__FILE__, __LINE__, "failed internal consistency check"); + + /* djb - 2000-06-03 - Use SYMBOL_MATCHES_NAME, not a strcmp, so + we don't have to force a linear search on C++. Probably holds true + for JAVA as well, no way to check.*/ + while (SYMBOL_MATCHES_NAME (*top,name)) { if (SYMBOL_NAMESPACE (*top) == namespace) { - return (*top); + return (*top); } - top ++; + top++; } } @@ -1031,7 +1041,7 @@ lookup_partial_symbol (pst, name, global, namespace) we should also do a linear search. */ if (do_linear_search) - { + { for (psym = start; psym < start + length; psym++) { if (namespace == SYMBOL_NAMESPACE (*psym)) @@ -1056,8 +1066,7 @@ lookup_partial_symbol (pst, name, global, namespace) struct type * -lookup_transparent_type (name) - const char *name; +lookup_transparent_type (const char *name) { register struct symbol *sym; register struct symtab *s = NULL; @@ -1065,51 +1074,50 @@ lookup_transparent_type (name) struct blockvector *bv; register struct objfile *objfile; register struct block *block; - register struct minimal_symbol *msymbol; /* Now search all the global symbols. Do the symtab's first, then check the psymtab's. If a psymtab indicates the existence of the desired name as a global, then do psymtab-to-symtab conversion on the fly and return the found symbol. */ - + ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); - if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) - { - return SYMBOL_TYPE (sym); - } - } + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); + if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + { + return SYMBOL_TYPE (sym); + } + } ALL_PSYMTABS (objfile, ps) - { - if (!ps->readin && lookup_partial_symbol (ps, name, 1, STRUCT_NAMESPACE)) - { - s = PSYMTAB_TO_SYMTAB(ps); - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); - if (!sym) - { - /* This shouldn't be necessary, but as a last resort - * try looking in the statics even though the psymtab - * claimed the symbol was global. It's possible that - * the psymtab gets it wrong in some cases. - */ - block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); - if (!sym) - error ("Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\ + { + if (!ps->readin && lookup_partial_symbol (ps, name, 1, STRUCT_NAMESPACE)) + { + s = PSYMTAB_TO_SYMTAB (ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); + if (!sym) + { + /* This shouldn't be necessary, but as a last resort + * try looking in the statics even though the psymtab + * claimed the symbol was global. It's possible that + * the psymtab gets it wrong in some cases. + */ + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); + if (!sym) + error ("Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ (if a template, try specifying an instantiation: %s<type>).", - name, ps->filename, name, name); - } - if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) - return SYMBOL_TYPE (sym); - } - } + name, ps->filename, name, name); + } + if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + return SYMBOL_TYPE (sym); + } + } /* Now search the static file-level symbols. Not strictly correct, but more useful than an error. @@ -1120,43 +1128,43 @@ lookup_transparent_type (name) */ ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); - if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) - { - return SYMBOL_TYPE (sym); - } - } + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); + if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + { + return SYMBOL_TYPE (sym); + } + } ALL_PSYMTABS (objfile, ps) - { - if (!ps->readin && lookup_partial_symbol (ps, name, 0, STRUCT_NAMESPACE)) - { - s = PSYMTAB_TO_SYMTAB(ps); - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); - if (!sym) - { - /* This shouldn't be necessary, but as a last resort - * try looking in the globals even though the psymtab - * claimed the symbol was static. It's possible that - * the psymtab gets it wrong in some cases. - */ - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); - if (!sym) - error ("Internal: static symbol `%s' found in %s psymtab but not in symtab.\n\ + { + if (!ps->readin && lookup_partial_symbol (ps, name, 0, STRUCT_NAMESPACE)) + { + s = PSYMTAB_TO_SYMTAB (ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); + if (!sym) + { + /* This shouldn't be necessary, but as a last resort + * try looking in the globals even though the psymtab + * claimed the symbol was static. It's possible that + * the psymtab gets it wrong in some cases. + */ + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_NAMESPACE); + if (!sym) + error ("Internal: static symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ (if a template, try specifying an instantiation: %s<type>).", - name, ps->filename, name, name); - } - if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) - return SYMBOL_TYPE (sym); - } - } + name, ps->filename, name, name); + } + if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + return SYMBOL_TYPE (sym); + } + } return (struct type *) 0; } @@ -1166,18 +1174,18 @@ lookup_transparent_type (name) executables that have no main() ? */ struct partial_symtab * -find_main_psymtab () +find_main_psymtab (void) { register struct partial_symtab *pst; register struct objfile *objfile; ALL_PSYMTABS (objfile, pst) - { - if (lookup_partial_symbol (pst, "main", 1, VAR_NAMESPACE)) - { - return (pst); - } - } + { + if (lookup_partial_symbol (pst, main_name (), 1, VAR_NAMESPACE)) + { + return (pst); + } + } return (NULL); } @@ -1193,10 +1201,8 @@ find_main_psymtab () tested for a match. */ struct symbol * -lookup_block_symbol (block, name, namespace) - register const struct block *block; - const char *name; - const namespace_enum namespace; +lookup_block_symbol (register const struct block *block, const char *name, + const namespace_enum namespace) { register int bot, top, inc; register struct symbol *sym; @@ -1208,10 +1214,8 @@ lookup_block_symbol (block, name, namespace) if (BLOCK_SHOULD_SORT (block)) { /* Reset the linear search flag so if the binary search fails, we - won't do the linear search once unless we find some reason to - do so, such as finding a C++ symbol during the binary search. - Note that for C++ modules, ALL the symbols in a block should - end up marked as C++ symbols. */ + won't do the linear search once unless we find some reason to + do so */ do_linear_search = 0; top = BLOCK_NSYMS (block); @@ -1229,22 +1233,19 @@ lookup_block_symbol (block, name, namespace) } inc = (inc >> 1) + bot; sym = BLOCK_SYM (block, inc); - if (!do_linear_search - && (SYMBOL_LANGUAGE (sym) == language_cplus - || SYMBOL_LANGUAGE (sym) == language_java - )) + if (!do_linear_search && (SYMBOL_LANGUAGE (sym) == language_java)) { do_linear_search = 1; } - if (SYMBOL_NAME (sym)[0] < name[0]) + if (SYMBOL_SOURCE_NAME (sym)[0] < name[0]) { bot = inc; } - else if (SYMBOL_NAME (sym)[0] > name[0]) + else if (SYMBOL_SOURCE_NAME (sym)[0] > name[0]) { top = inc; } - else if (STRCMP (SYMBOL_NAME (sym), name) < 0) + else if (strcmp (SYMBOL_SOURCE_NAME (sym), name) < 0) { bot = inc; } @@ -1255,37 +1256,33 @@ lookup_block_symbol (block, name, namespace) } /* Now scan forward until we run out of symbols, find one whose - name is greater than NAME, or find one we want. If there is - more than one symbol with the right name and namespace, we - return the first one; I believe it is now impossible for us - to encounter two symbols with the same name and namespace - here, because blocks containing argument symbols are no - longer sorted. */ + name is greater than NAME, or find one we want. If there is + more than one symbol with the right name and namespace, we + return the first one; I believe it is now impossible for us + to encounter two symbols with the same name and namespace + here, because blocks containing argument symbols are no + longer sorted. */ top = BLOCK_NSYMS (block); while (bot < top) { sym = BLOCK_SYM (block, bot); - inc = SYMBOL_NAME (sym)[0] - name[0]; - if (inc == 0) - { - inc = STRCMP (SYMBOL_NAME (sym), name); - } - if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace) - { - return (sym); - } - if (inc > 0) + if (SYMBOL_NAMESPACE (sym) == namespace && + SYMBOL_MATCHES_NAME (sym, name)) { - break; + return sym; } + if (SYMBOL_SOURCE_NAME (sym)[0] > name[0]) + { + break; + } bot++; } } /* Here if block isn't sorted, or we fail to find a match during the binary search above. If during the binary search above, we find a - symbol which is a C++ symbol, then we have re-enabled the linear + symbol which is a Java symbol, then we have re-enabled the linear search flag which was reset when starting the binary search. This loop is equivalent to the loop above, but hacked greatly for speed. @@ -1307,13 +1304,27 @@ lookup_block_symbol (block, name, namespace) SYMBOL_MATCHES_NAME (sym, name)) { /* If SYM has aliases, then use any alias that is active - at the current PC. If no alias is active at the current - PC, then use the main symbol. + at the current PC. If no alias is active at the current + PC, then use the main symbol. - ?!? Is checking the current pc correct? Is this routine - ever called to look up a symbol from another context? */ - if (SYMBOL_ALIASES (sym)) - sym = find_active_alias (sym, read_pc ()); + ?!? Is checking the current pc correct? Is this routine + ever called to look up a symbol from another context? + + FIXME: No, it's not correct. If someone sets a + conditional breakpoint at an address, then the + breakpoint's `struct expression' should refer to the + `struct symbol' appropriate for the breakpoint's + address, which may not be the PC. + + Even if it were never called from another context, + it's totally bizarre for lookup_symbol's behavior to + depend on the value of the inferior's current PC. We + should pass in the appropriate PC as well as the + block. The interface to lookup_symbol should change + to require the caller to provide a PC. */ + + if (SYMBOL_ALIASES (sym)) + sym = find_active_alias (sym, read_pc ()); sym_found = sym; if (SYMBOL_CLASS (sym) != LOC_ARG && @@ -1339,9 +1350,7 @@ lookup_block_symbol (block, name, namespace) If no alias is active, then return SYM. */ static struct symbol * -find_active_alias (sym, addr) - struct symbol *sym; - CORE_ADDR addr; +find_active_alias (struct symbol *sym, CORE_ADDR addr) { struct range_list *r; struct alias_list *aliases; @@ -1352,7 +1361,7 @@ find_active_alias (sym, addr) while (aliases) { if (!SYMBOL_RANGES (aliases->sym)) - return aliases->sym; + return aliases->sym; for (r = SYMBOL_RANGES (aliases->sym); r; r = r->next) { if (r->start <= addr && r->end > addr) @@ -1364,14 +1373,13 @@ find_active_alias (sym, addr) /* Nothing found, return the main symbol. */ return sym; } - + /* Return the symbol for the function which contains a specified lexical block, described by a struct block BL. */ struct symbol * -block_function (bl) - struct block *bl; +block_function (struct block *bl) { while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0) bl = BLOCK_SUPERBLOCK (bl); @@ -1383,9 +1391,7 @@ block_function (bl) psymtabs and read in another symtab if necessary. */ struct symtab * -find_pc_sect_symtab (pc, section) - CORE_ADDR pc; - asection *section; +find_pc_sect_symtab (CORE_ADDR pc, asection *section) { register struct block *b; struct blockvector *bv; @@ -1394,6 +1400,21 @@ find_pc_sect_symtab (pc, section) register struct partial_symtab *ps; register struct objfile *objfile; CORE_ADDR distance = 0; + struct minimal_symbol *msymbol; + + /* If we know that this is not a text address, return failure. This is + necessary because we loop based on the block's high and low code + addresses, which do not include the data ranges, and because + we call find_pc_sect_psymtab which has a similar restriction based + on the partial_symtab's texthigh and textlow. */ + msymbol = lookup_minimal_symbol_by_pc_section (pc, section); + if (msymbol + && (msymbol->type == mst_data + || msymbol->type == mst_bss + || msymbol->type == mst_abs + || msymbol->type == mst_file_data + || msymbol->type == mst_file_bss)) + return NULL; /* Search all symtabs for the one whose file contains our address, and which is the smallest of all the ones containing the address. This is designed @@ -1411,51 +1432,47 @@ find_pc_sect_symtab (pc, section) For these, the symtab we are looking for is not necessarily read in. */ ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - if (BLOCK_START (b) <= pc -#if defined(HPUXHPPA) - && BLOCK_END (b) >= pc -#else - && BLOCK_END (b) > pc -#endif - && (distance == 0 - || BLOCK_END (b) - BLOCK_START (b) < distance)) - { - /* For an objfile that has its functions reordered, - find_pc_psymtab will find the proper partial symbol table - and we simply return its corresponding symtab. */ - /* In order to better support objfiles that contain both - stabs and coff debugging info, we continue on if a psymtab - can't be found. */ - if ((objfile->flags & OBJF_REORDERED) && objfile->psymtabs) - { - ps = find_pc_sect_psymtab (pc, section); - if (ps) - return PSYMTAB_TO_SYMTAB (ps); - } - if (section != 0) - { - int i; + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc + && (distance == 0 + || BLOCK_END (b) - BLOCK_START (b) < distance)) + { + /* For an objfile that has its functions reordered, + find_pc_psymtab will find the proper partial symbol table + and we simply return its corresponding symtab. */ + /* In order to better support objfiles that contain both + stabs and coff debugging info, we continue on if a psymtab + can't be found. */ + if ((objfile->flags & OBJF_REORDERED) && objfile->psymtabs) + { + ps = find_pc_sect_psymtab (pc, section); + if (ps) + return PSYMTAB_TO_SYMTAB (ps); + } + if (section != 0) + { + int i; - for (i = 0; i < b->nsyms; i++) - { - fixup_symbol_section (b->sym[i], objfile); - if (section == SYMBOL_BFD_SECTION (b->sym[i])) - break; - } - if (i >= b->nsyms) - continue; /* no symbol in this symtab matches section */ - } - distance = BLOCK_END (b) - BLOCK_START (b); - best_s = s; - } - } + for (i = 0; i < b->nsyms; i++) + { + fixup_symbol_section (b->sym[i], objfile); + if (section == SYMBOL_BFD_SECTION (b->sym[i])) + break; + } + if (i >= b->nsyms) + continue; /* no symbol in this symtab matches section */ + } + distance = BLOCK_END (b) - BLOCK_START (b); + best_s = s; + } + } if (best_s != NULL) - return(best_s); + return (best_s); s = NULL; ps = find_pc_sect_psymtab (pc, section); @@ -1465,10 +1482,9 @@ find_pc_sect_symtab (pc, section) /* Might want to error() here (in case symtab is corrupt and will cause a core dump), but maybe we can successfully continue, so let's not. */ - /* FIXME-32x64: assumes pc fits in a long */ warning ("\ -(Internal error: pc 0x%lx in read in psymtab, but not in symtab.)\n", - (unsigned long) pc); +(Internal error: pc 0x%s in read in psymtab, but not in symtab.)\n", + paddr_nz (pc)); s = PSYMTAB_TO_SYMTAB (ps); } return (s); @@ -1478,13 +1494,12 @@ find_pc_sect_symtab (pc, section) read in another symtab if necessary. Backward compatibility, no section */ struct symtab * -find_pc_symtab (pc) - CORE_ADDR pc; +find_pc_symtab (CORE_ADDR pc) { return find_pc_sect_symtab (pc, find_pc_mapped_section (pc)); } - + #if 0 /* Find the closest symbol value (of any sort -- function or variable) @@ -1495,10 +1510,7 @@ find_pc_symtab (pc) line *0x2345" cause psymtabs to be converted to symtabs). */ struct symbol * -find_addr_symbol (addr, symtabp, symaddrp) - CORE_ADDR addr; - struct symtab **symtabp; - CORE_ADDR *symaddrp; +find_addr_symbol (CORE_ADDR addr, struct symtab **symtabp, CORE_ADDR *symaddrp) { struct symtab *symtab, *best_symtab; struct objfile *objfile; @@ -1515,61 +1527,61 @@ find_addr_symbol (addr, symtabp, symaddrp) /* FIXME -- we should pull in all the psymtabs, too! */ ALL_SYMTABS (objfile, symtab) - { - /* Search the global and static blocks in this symtab for - the closest symbol-address to the desired address. */ + { + /* Search the global and static blocks in this symtab for + the closest symbol-address to the desired address. */ - for (blocknum = GLOBAL_BLOCK; blocknum <= STATIC_BLOCK; blocknum++) - { - QUIT; - block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), blocknum); - top = BLOCK_NSYMS (block); - for (bot = 0; bot < top; bot++) - { - sym = BLOCK_SYM (block, bot); - switch (SYMBOL_CLASS (sym)) - { - case LOC_STATIC: - case LOC_LABEL: - sym_addr = SYMBOL_VALUE_ADDRESS (sym); - break; + for (blocknum = GLOBAL_BLOCK; blocknum <= STATIC_BLOCK; blocknum++) + { + QUIT; + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), blocknum); + top = BLOCK_NSYMS (block); + for (bot = 0; bot < top; bot++) + { + sym = BLOCK_SYM (block, bot); + switch (SYMBOL_CLASS (sym)) + { + case LOC_STATIC: + case LOC_LABEL: + sym_addr = SYMBOL_VALUE_ADDRESS (sym); + break; + + case LOC_INDIRECT: + sym_addr = SYMBOL_VALUE_ADDRESS (sym); + /* An indirect symbol really lives at *sym_addr, + * so an indirection needs to be done. + * However, I am leaving this commented out because it's + * expensive, and it's possible that symbolization + * could be done without an active process (in + * case this read_memory will fail). RT + sym_addr = read_memory_unsigned_integer + (sym_addr, TARGET_PTR_BIT / TARGET_CHAR_BIT); + */ + break; - case LOC_INDIRECT: - sym_addr = SYMBOL_VALUE_ADDRESS (sym); - /* An indirect symbol really lives at *sym_addr, - * so an indirection needs to be done. - * However, I am leaving this commented out because it's - * expensive, and it's possible that symbolization - * could be done without an active process (in - * case this read_memory will fail). RT - sym_addr = read_memory_unsigned_integer - (sym_addr, TARGET_PTR_BIT / TARGET_CHAR_BIT); - */ - break; - - case LOC_BLOCK: - sym_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); - break; + case LOC_BLOCK: + sym_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + break; - default: - continue; - } + default: + continue; + } - if (sym_addr <= addr) - if (sym_addr > best_sym_addr) - { - /* Quit if we found an exact match. */ - best_sym = sym; - best_sym_addr = sym_addr; - best_symtab = symtab; - if (sym_addr == addr) - goto done; - } - } - } - } + if (sym_addr <= addr) + if (sym_addr > best_sym_addr) + { + /* Quit if we found an exact match. */ + best_sym = sym; + best_sym_addr = sym_addr; + best_symtab = symtab; + if (sym_addr == addr) + goto done; + } + } + } + } - done: +done: if (symtabp) *symtabp = best_symtab; if (symaddrp) @@ -1578,7 +1590,7 @@ find_addr_symbol (addr, symtabp, symaddrp) } #endif /* 0 */ -/* Find the source file and line number for a given PC value and section. +/* Find the source file and line number for a given PC value and SECTION. Return a structure containing a symtab pointer, a line number, and a pc range for the entire source line. The value's .pc field is NOT the specified pc. @@ -1596,10 +1608,7 @@ find_addr_symbol (addr, symtabp, symaddrp) /* If it's worth the effort, we could be using a binary search. */ struct symtab_and_line -find_pc_sect_line (pc, section, notcurrent) - CORE_ADDR pc; - struct sec *section; - int notcurrent; +find_pc_sect_line (CORE_ADDR pc, struct sec *section, int notcurrent) { struct symtab *s; register struct linetable *l; @@ -1635,19 +1644,26 @@ find_pc_sect_line (pc, section, notcurrent) But what we want is the statement containing the instruction. Fudge the pc to make sure we get that. */ - INIT_SAL (&val); /* initialize to zeroes */ + INIT_SAL (&val); /* initialize to zeroes */ + + /* It's tempting to assume that, if we can't find debugging info for + any function enclosing PC, that we shouldn't search for line + number info, either. However, GAS can emit line number info for + assembly files --- very helpful when debugging hand-written + assembly code. In such a case, we'd have no debug info for the + function, but we would have line info. */ if (notcurrent) pc -= 1; - /* elz: added this because this function returned the wrong + /* elz: added this because this function returned the wrong information if the pc belongs to a stub (import/export) to call a shlib function. This stub would be anywhere between two functions in the target, and the line info was erroneously taken to be the one of the line before the pc. - */ + */ /* RT: Further explanation: - * + * We have stubs (trampolines) inserted between procedures. * * Example: "shr1" exists in a shared library, and a "shr1" stub also @@ -1684,31 +1700,31 @@ find_pc_sect_line (pc, section, notcurrent) * check for the address being the same, to avoid an * infinite recursion. */ - msymbol = lookup_minimal_symbol_by_pc(pc); - if (msymbol != NULL) + msymbol = lookup_minimal_symbol_by_pc (pc); + if (msymbol != NULL) if (MSYMBOL_TYPE (msymbol) == mst_solib_trampoline) - { - mfunsym = lookup_minimal_symbol_text (SYMBOL_NAME (msymbol), NULL, NULL); - if (mfunsym == NULL) - /* I eliminated this warning since it is coming out - * in the following situation: - * gdb shmain // test program with shared libraries - * (gdb) break shr1 // function in shared lib - * Warning: In stub for ... - * In the above situation, the shared lib is not loaded yet, - * so of course we can't find the real func/line info, - * but the "break" still works, and the warning is annoying. - * So I commented out the warning. RT */ - /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_NAME(msymbol)) */; - /* fall through */ - else if (SYMBOL_VALUE(mfunsym) == SYMBOL_VALUE(msymbol)) - /* Avoid infinite recursion */ - /* See above comment about why warning is commented out */ - /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_NAME(msymbol)) */; - /* fall through */ - else - return find_pc_line( SYMBOL_VALUE (mfunsym), 0); - } + { + mfunsym = lookup_minimal_symbol_text (SYMBOL_NAME (msymbol), NULL, NULL); + if (mfunsym == NULL) + /* I eliminated this warning since it is coming out + * in the following situation: + * gdb shmain // test program with shared libraries + * (gdb) break shr1 // function in shared lib + * Warning: In stub for ... + * In the above situation, the shared lib is not loaded yet, + * so of course we can't find the real func/line info, + * but the "break" still works, and the warning is annoying. + * So I commented out the warning. RT */ + /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_NAME(msymbol)) */ ; + /* fall through */ + else if (SYMBOL_VALUE (mfunsym) == SYMBOL_VALUE (msymbol)) + /* Avoid infinite recursion */ + /* See above comment about why warning is commented out */ + /* warning ("In stub for %s; unable to find real function/line info", SYMBOL_NAME(msymbol)) */ ; + /* fall through */ + else + return find_pc_line (SYMBOL_VALUE (mfunsym), 0); + } s = find_pc_sect_symtab (pc, section); @@ -1732,7 +1748,7 @@ find_pc_sect_line (pc, section, notcurrent) /* Find the best line in this symtab. */ l = LINETABLE (s); if (!l) - continue; + continue; len = l->nitems; if (len <= 0) { @@ -1747,7 +1763,7 @@ find_pc_sect_line (pc, section, notcurrent) item = l->item; /* Get first line info */ /* Is this file's first line closer than the first lines of other files? - If so, record this file, and its first line, as best alternate. */ + If so, record this file, and its first line, as best alternate. */ if (item->pc > pc && (!alt || item->pc < alt->pc)) { alt = item; @@ -1765,22 +1781,29 @@ find_pc_sect_line (pc, section, notcurrent) } /* At this point, prev points at the line whose start addr is <= pc, and - item points at the next line. If we ran off the end of the linetable - (pc >= start of the last line), then prev == item. If pc < start of - the first line, prev will not be set. */ + item points at the next line. If we ran off the end of the linetable + (pc >= start of the last line), then prev == item. If pc < start of + the first line, prev will not be set. */ /* Is this file's best line closer than the best in the other files? - If so, record this file, and its best line, as best so far. */ + If so, record this file, and its best line, as best so far. */ if (prev && (!best || prev->pc > best->pc)) { best = prev; best_symtab = s; - /* If another line is in the linetable, and its PC is closer - than the best_end we currently have, take it as best_end. */ - if (i < len && (best_end == 0 || best_end > item->pc)) - best_end = item->pc; + + /* Discard BEST_END if it's before the PC of the current BEST. */ + if (best_end <= best->pc) + best_end = 0; } + + /* If another line (denoted by ITEM) is in the linetable and its + PC is after BEST's PC, but before the current BEST_END, then + use ITEM's PC as the new best_end. */ + if (best && i < len && item->pc > best->pc + && (best_end == 0 || best_end > item->pc)) + best_end = item->pc; } if (!best_symtab) @@ -1796,12 +1819,20 @@ find_pc_sect_line (pc, section, notcurrent) val.line = alt->line - 1; /* Don't return line 0, that means that we didn't find the line. */ - if (val.line == 0) ++val.line; + if (val.line == 0) + ++val.line; val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); val.end = alt->pc; } } + else if (best->line == 0) + { + /* If our best fit is in a range of PC's for which no line + number info is available (line number is zero) then we didn't + find any valid line information. */ + val.pc = pc; + } else { val.symtab = best_symtab; @@ -1821,22 +1852,16 @@ find_pc_sect_line (pc, section, notcurrent) /* Backward compatibility (no section) */ struct symtab_and_line -find_pc_line (pc, notcurrent) - CORE_ADDR pc; - int notcurrent; +find_pc_line (CORE_ADDR pc, int notcurrent) { - asection *section; + asection *section; section = find_pc_overlay (pc); if (pc_in_unmapped_range (pc, section)) pc = overlay_mapped_address (pc, section); return find_pc_sect_line (pc, section, notcurrent); } - -static struct symtab* find_line_symtab PARAMS ((struct symtab *, int, - int *, int *)); - /* Find line number LINE in any symtab whose name is the same as SYMTAB. @@ -1847,12 +1872,8 @@ static struct symtab* find_line_symtab PARAMS ((struct symtab *, int, If not found, return NULL. */ -static struct symtab* -find_line_symtab (symtab, line, index, exact_match) - struct symtab *symtab; - int line; - int *index; - int *exact_match; +struct symtab * +find_line_symtab (struct symtab *symtab, int line, int *index, int *exact_match) { int exact; @@ -1870,15 +1891,15 @@ find_line_symtab (symtab, line, index, exact_match) if (best_index < 0 || !exact) { /* Didn't find an exact match. So we better keep looking for - another symtab with the same name. In the case of xcoff, - multiple csects for one source file (produced by IBM's FORTRAN - compiler) produce multiple symtabs (this is unavoidable - assuming csects can be at arbitrary places in memory and that - the GLOBAL_BLOCK of a symtab has a begin and end address). */ + another symtab with the same name. In the case of xcoff, + multiple csects for one source file (produced by IBM's FORTRAN + compiler) produce multiple symtabs (this is unavoidable + assuming csects can be at arbitrary places in memory and that + the GLOBAL_BLOCK of a symtab has a begin and end address). */ /* BEST is the smallest linenumber > LINE so far seen, - or 0 if none has been seen so far. - BEST_INDEX and BEST_LINETABLE identify the item for it. */ + or 0 if none has been seen so far. + BEST_INDEX and BEST_LINETABLE identify the item for it. */ int best; struct objfile *objfile; @@ -1890,34 +1911,34 @@ find_line_symtab (symtab, line, index, exact_match) best = 0; ALL_SYMTABS (objfile, s) - { - struct linetable *l; - int ind; + { + struct linetable *l; + int ind; - if (!STREQ (symtab->filename, s->filename)) - continue; - l = LINETABLE (s); - ind = find_line_common (l, line, &exact); - if (ind >= 0) - { - if (exact) - { - best_index = ind; - best_linetable = l; - best_symtab = s; - goto done; - } - if (best == 0 || l->item[ind].line < best) - { - best = l->item[ind].line; - best_index = ind; - best_linetable = l; - best_symtab = s; - } - } - } + if (!STREQ (symtab->filename, s->filename)) + continue; + l = LINETABLE (s); + ind = find_line_common (l, line, &exact); + if (ind >= 0) + { + if (exact) + { + best_index = ind; + best_linetable = l; + best_symtab = s; + goto done; + } + if (best == 0 || l->item[ind].line < best) + { + best = l->item[ind].line; + best_index = ind; + best_linetable = l; + best_symtab = s; + } + } + } } - done: +done: if (best_index < 0) return NULL; @@ -1934,10 +1955,7 @@ find_line_symtab (symtab, line, index, exact_match) The source file is specified with a struct symtab. */ int -find_line_pc (symtab, line, pc) - struct symtab *symtab; - int line; - CORE_ADDR *pc; +find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc) { struct linetable *l; int ind; @@ -1964,15 +1982,14 @@ find_line_pc (symtab, line, pc) Returns 0 if could not find the specified line. */ int -find_line_pc_range (sal, startptr, endptr) - struct symtab_and_line sal; - CORE_ADDR *startptr, *endptr; +find_line_pc_range (struct symtab_and_line sal, CORE_ADDR *startptr, + CORE_ADDR *endptr) { CORE_ADDR startaddr; struct symtab_and_line found_sal; startaddr = sal.pc; - if (startaddr==0 && !find_line_pc (sal.symtab, sal.line, &startaddr)) + if (startaddr == 0 && !find_line_pc (sal.symtab, sal.line, &startaddr)) return 0; /* This whole function is based on address. For example, if line 10 has @@ -2004,10 +2021,8 @@ find_line_pc_range (sal, startptr, endptr) Set *EXACT_MATCH nonzero if the value returned is an exact match. */ static int -find_line_common (l, lineno, exact_match) - register struct linetable *l; - register int lineno; - int *exact_match; +find_line_common (register struct linetable *l, register int lineno, + int *exact_match) { register int i; register int len; @@ -2050,9 +2065,7 @@ find_line_common (l, lineno, exact_match) } int -find_pc_line_pc_range (pc, startptr, endptr) - CORE_ADDR pc; - CORE_ADDR *startptr, *endptr; +find_pc_line_pc_range (CORE_ADDR pc, CORE_ADDR *startptr, CORE_ADDR *endptr) { struct symtab_and_line sal; sal = find_pc_line (pc, 0); @@ -2066,13 +2079,8 @@ find_pc_line_pc_range (pc, startptr, endptr) If the argument FUNFIRSTLINE is nonzero, we want the first line of real code inside the function. */ -static struct symtab_and_line -find_function_start_sal PARAMS ((struct symbol *sym, int)); - -static struct symtab_and_line -find_function_start_sal (sym, funfirstline) - struct symbol *sym; - int funfirstline; +struct symtab_and_line +find_function_start_sal (struct symbol *sym, int funfirstline) { CORE_ADDR pc; struct symtab_and_line sal; @@ -2080,16 +2088,16 @@ find_function_start_sal (sym, funfirstline) pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); fixup_symbol_section (sym, NULL); if (funfirstline) - { /* skip "first line" of function (which is actually its prologue) */ + { /* skip "first line" of function (which is actually its prologue) */ asection *section = SYMBOL_BFD_SECTION (sym); /* If function is in an unmapped overlay, use its unmapped LMA - address, so that SKIP_PROLOGUE has something unique to work on */ + address, so that SKIP_PROLOGUE has something unique to work on */ if (section_is_overlay (section) && !section_is_mapped (section)) pc = overlay_unmapped_address (pc, section); pc += FUNCTION_START_OFFSET; - SKIP_PROLOGUE (pc); + pc = SKIP_PROLOGUE (pc); /* For overlays, map pc back into its mapped VMA range */ pc = overlay_mapped_address (pc, section); @@ -2116,15 +2124,13 @@ find_function_start_sal (sym, funfirstline) return sal; } - + /* If P is of the form "operator[ \t]+..." where `...' is some legitimate operator text, return a pointer to the beginning of the substring of the operator text. Otherwise, return "". */ char * -operator_chars (p, end) - char *p; - char **end; +operator_chars (char *p, char **end) { *end = ""; if (strncmp (p, "operator", 8)) @@ -2133,7 +2139,7 @@ operator_chars (p, end) /* Don't get faked out by `operator' being part of a longer identifier. */ - if (isalpha(*p) || *p == '_' || *p == '$' || *p == '\0') + if (isalpha (*p) || *p == '_' || *p == '$' || *p == '\0') return *end; /* Allow some whitespace between `operator' and the operator symbol. */ @@ -2142,1205 +2148,182 @@ operator_chars (p, end) /* Recognize 'operator TYPENAME'. */ - if (isalpha(*p) || *p == '_' || *p == '$') + if (isalpha (*p) || *p == '_' || *p == '$') { - register char *q = p+1; - while (isalnum(*q) || *q == '_' || *q == '$') + register char *q = p + 1; + while (isalnum (*q) || *q == '_' || *q == '$') q++; *end = q; return p; } - switch (*p) - { - case '!': - case '=': - case '*': - case '/': - case '%': - case '^': - if (p[1] == '=') - *end = p+2; - else - *end = p+1; - return p; - case '<': - case '>': - case '+': - case '-': - case '&': - case '|': - if (p[1] == '=' || p[1] == p[0]) - *end = p+2; - else - *end = p+1; - return p; - case '~': - case ',': - *end = p+1; - return p; - case '(': - if (p[1] != ')') - error ("`operator ()' must be specified without whitespace in `()'"); - *end = p+2; - return p; - case '?': - if (p[1] != ':') - error ("`operator ?:' must be specified without whitespace in `?:'"); - *end = p+2; - return p; - case '[': - if (p[1] != ']') - error ("`operator []' must be specified without whitespace in `[]'"); - *end = p+2; - return p; - default: - error ("`operator %s' not supported", p); - break; - } - *end = ""; - return *end; -} - -/* Return the number of methods described for TYPE, including the - methods from types it derives from. This can't be done in the symbol - reader because the type of the baseclass might still be stubbed - when the definition of the derived class is parsed. */ - -static int total_number_of_methods PARAMS ((struct type *type)); - -static int -total_number_of_methods (type) - struct type *type; -{ - int n; - int count; - - CHECK_TYPEDEF (type); - if (TYPE_CPLUS_SPECIFIC (type) == NULL) - return 0; - count = TYPE_NFN_FIELDS_TOTAL (type); - - for (n = 0; n < TYPE_N_BASECLASSES (type); n++) - count += total_number_of_methods (TYPE_BASECLASS (type, n)); - - return count; -} - -/* Recursive helper function for decode_line_1. - Look for methods named NAME in type T. - Return number of matches. - Put matches in SYM_ARR, which should have been allocated with - a size of total_number_of_methods (T) * sizeof (struct symbol *). - Note that this function is g++ specific. */ - -static int -find_methods (t, name, sym_arr) - struct type *t; - char *name; - struct symbol **sym_arr; -{ - int i1 = 0; - int ibase; - struct symbol *sym_class; - char *class_name = type_name_no_tag (t); - - /* Ignore this class if it doesn't have a name. This is ugly, but - unless we figure out how to get the physname without the name of - the class, then the loop can't do any good. */ - if (class_name - && (sym_class = lookup_symbol (class_name, - (struct block *)NULL, - STRUCT_NAMESPACE, - (int *)NULL, - (struct symtab **)NULL))) - { - int method_counter; - - /* FIXME: Shouldn't this just be CHECK_TYPEDEF (t)? */ - t = SYMBOL_TYPE (sym_class); - - /* Loop over each method name. At this level, all overloads of a name - are counted as a single name. There is an inner loop which loops over - each overload. */ - - for (method_counter = TYPE_NFN_FIELDS (t) - 1; - method_counter >= 0; - --method_counter) - { - int field_counter; - char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter); - char dem_opname[64]; - - if (strncmp (method_name, "__", 2) == 0 || - strncmp (method_name, "op", 2) == 0 || - strncmp (method_name, "type", 4) == 0) - { - if (cplus_demangle_opname (method_name, dem_opname, DMGL_ANSI)) - method_name = dem_opname; - else if (cplus_demangle_opname (method_name, dem_opname, 0)) - method_name = dem_opname; - } - - if (STREQ (name, method_name)) - /* Find all the overloaded methods with that name. */ - for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1; - field_counter >= 0; - --field_counter) + while (*p) + switch (*p) + { + case '\\': /* regexp quoting */ + if (p[1] == '*') + { + if (p[2] == '=') /* 'operator\*=' */ + *end = p + 3; + else /* 'operator\*' */ + *end = p + 2; + return p; + } + else if (p[1] == '[') + { + if (p[2] == ']') + error ("mismatched quoting on brackets, try 'operator\\[\\]'"); + else if (p[2] == '\\' && p[3] == ']') { - struct fn_field *f; - char *phys_name; - - f = TYPE_FN_FIELDLIST1 (t, method_counter); - - if (TYPE_FN_FIELD_STUB (f, field_counter)) - { - char *tmp_name; - - tmp_name = gdb_mangle_name (t, - method_counter, - field_counter); - phys_name = alloca (strlen (tmp_name) + 1); - strcpy (phys_name, tmp_name); - free (tmp_name); - } - else - phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter); - - /* Destructor is handled by caller, dont add it to the list */ - if (DESTRUCTOR_PREFIX_P (phys_name)) - continue; - - sym_arr[i1] = lookup_symbol (phys_name, - NULL, VAR_NAMESPACE, - (int *) NULL, - (struct symtab **) NULL); - if (sym_arr[i1]) - i1++; - else - { - /* This error message gets printed, but the method - still seems to be found - fputs_filtered("(Cannot find method ", gdb_stdout); - fprintf_symbol_filtered (gdb_stdout, phys_name, - language_cplus, - DMGL_PARAMS | DMGL_ANSI); - fputs_filtered(" - possibly inlined.)\n", gdb_stdout); - */ - } + *end = p + 4; /* 'operator\[\]' */ + return p; } - } - } - - /* Only search baseclasses if there is no match yet, since names in - derived classes override those in baseclasses. - - FIXME: The above is not true; it is only true of member functions - if they have the same number of arguments (??? - section 13.1 of the - ARM says the function members are not in the same scope but doesn't - really spell out the rules in a way I understand. In any case, if - the number of arguments differ this is a case in which we can overload - rather than hiding without any problem, and gcc 2.4.5 does overload - rather than hiding in this case). */ - - if (i1 == 0) - for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++) - i1 += find_methods (TYPE_BASECLASS (t, ibase), name, sym_arr + i1); - - return i1; -} - -/* Helper function for decode_line_1. - Build a canonical line spec in CANONICAL if it is non-NULL and if - the SAL has a symtab. - If SYMNAME is non-NULL the canonical line spec is `filename:symname'. - If SYMNAME is NULL the line number from SAL is used and the canonical - line spec is `filename:linenum'. */ - -static void -build_canonical_line_spec (sal, symname, canonical) - struct symtab_and_line *sal; - char *symname; - char ***canonical; -{ - char **canonical_arr; - char *canonical_name; - char *filename; - struct symtab *s = sal->symtab; - - if (s == (struct symtab *)NULL - || s->filename == (char *)NULL - || canonical == (char ***)NULL) - return; - - canonical_arr = (char **) xmalloc (sizeof (char *)); - *canonical = canonical_arr; - - filename = s->filename; - if (symname != NULL) - { - canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2); - sprintf (canonical_name, "%s:%s", filename, symname); - } - else - { - canonical_name = xmalloc (strlen (filename) + 30); - sprintf (canonical_name, "%s:%d", filename, sal->line); - } - canonical_arr[0] = canonical_name; -} - -/* Parse a string that specifies a line number. - Pass the address of a char * variable; that variable will be - advanced over the characters actually parsed. - - The string can be: - - LINENUM -- that line number in current file. PC returned is 0. - FILE:LINENUM -- that line in that file. PC returned is 0. - FUNCTION -- line number of openbrace of that function. - PC returned is the start of the function. - VARIABLE -- line number of definition of that variable. - PC returned is 0. - FILE:FUNCTION -- likewise, but prefer functions in that file. - *EXPR -- line in which address EXPR appears. - - FUNCTION may be an undebuggable function found in minimal symbol table. - - If the argument FUNFIRSTLINE is nonzero, we want the first line - of real code inside a function when a function is specified, and it is - not OK to specify a variable or type to get its line number. - - DEFAULT_SYMTAB specifies the file to use if none is specified. - It defaults to current_source_symtab. - DEFAULT_LINE specifies the line number to use for relative - line numbers (that start with signs). Defaults to current_source_line. - If CANONICAL is non-NULL, store an array of strings containing the canonical - line specs there if necessary. Currently overloaded member functions and - line numbers or static functions without a filename yield a canonical - line spec. The array and the line spec strings are allocated on the heap, - it is the callers responsibility to free them. - - Note that it is possible to return zero for the symtab - if no file is validly specified. Callers must check that. - Also, the line number returned may be invalid. */ - -/* We allow single quotes in various places. This is a hideous - kludge, which exists because the completer can't yet deal with the - lack of single quotes. FIXME: write a linespec_completer which we - can use as appropriate instead of make_symbol_completion_list. */ - -struct symtabs_and_lines -decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical) - char **argptr; - int funfirstline; - struct symtab *default_symtab; - int default_line; - char ***canonical; -{ - struct symtabs_and_lines values; -#ifdef HPPA_COMPILER_BUG - /* FIXME: The native HP 9000/700 compiler has a bug which appears - when optimizing this file with target i960-vxworks. I haven't - been able to construct a simple test case. The problem is that - in the second call to SKIP_PROLOGUE below, the compiler somehow - does not realize that the statement val = find_pc_line (...) will - change the values of the fields of val. It extracts the elements - into registers at the top of the block, and does not update the - registers after the call to find_pc_line. You can check this by - inserting a printf at the end of find_pc_line to show what values - it is returning for val.pc and val.end and another printf after - the call to see what values the function actually got (remember, - this is compiling with cc -O, with this patch removed). You can - also examine the assembly listing: search for the second call to - skip_prologue; the LDO statement before the next call to - find_pc_line loads the address of the structure which - find_pc_line will return; if there is a LDW just before the LDO, - which fetches an element of the structure, then the compiler - still has the bug. - - Setting val to volatile avoids the problem. We must undef - volatile, because the HPPA native compiler does not define - __STDC__, although it does understand volatile, and so volatile - will have been defined away in defs.h. */ -#undef volatile - volatile struct symtab_and_line val; -#define volatile /*nothing*/ -#else - struct symtab_and_line val; -#endif - register char *p, *p1; - char *q, *pp, *ii, *p2; -#if 0 - char *q1; -#endif - register struct symtab *s; - - register struct symbol *sym; - /* The symtab that SYM was found in. */ - struct symtab *sym_symtab; - - register CORE_ADDR pc; - register struct minimal_symbol *msymbol; - char *copy; - struct symbol *sym_class; - int i1; - int is_quoted; - int has_parens; - int has_if = 0; - struct symbol **sym_arr; - struct type *t; - char *saved_arg = *argptr; - extern char *gdb_completer_quote_characters; - - INIT_SAL (&val); /* initialize to zeroes */ - - /* Defaults have defaults. */ - - if (default_symtab == 0) - { - default_symtab = current_source_symtab; - default_line = current_source_line; - } - - /* See if arg is *PC */ - - if (**argptr == '*') - { - (*argptr)++; - pc = parse_and_eval_address_1 (argptr); - - values.sals = (struct symtab_and_line *) - xmalloc (sizeof (struct symtab_and_line)); - - values.nelts = 1; - values.sals[0] = find_pc_line (pc, 0); - values.sals[0].pc = pc; - values.sals[0].section = find_pc_overlay (pc); - - return values; - } - - /* 'has_if' is for the syntax: - * (gdb) break foo if (a==b) - */ - if ((ii = strstr(*argptr, " if ")) != NULL || - (ii = strstr(*argptr, "\tif ")) != NULL || - (ii = strstr(*argptr, " if\t")) != NULL || - (ii = strstr(*argptr, "\tif\t")) != NULL || - (ii = strstr(*argptr, " if(")) != NULL || - (ii = strstr(*argptr, "\tif( ")) != NULL) - has_if = 1; - /* Temporarily zap out "if (condition)" to not - * confuse the parenthesis-checking code below. - * This is undone below. Do not change ii!! - */ - if (has_if) { - *ii = '\0'; - } - - /* Set various flags. - * 'has_parens' is important for overload checking, where - * we allow things like: - * (gdb) break c::f(int) - */ - - /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */ - - is_quoted = (**argptr - && strchr (gdb_completer_quote_characters, **argptr) != NULL); - - has_parens = ((pp = strchr (*argptr, '(')) != NULL - && (pp = strchr (pp, ')')) != NULL); - - /* Now that we're safely past the has_parens check, - * put back " if (condition)" so outer layers can see it - */ - if (has_if) - *ii = ' '; - - /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */ - /* May also be CLASS::MEMBER, or NAMESPACE::NAME */ - /* Look for ':', but ignore inside of <> */ - - s = NULL; - for (p = *argptr; *p; p++) - { - if (p[0] == '<') - { - char * temp_end = find_template_name_end (p); - if (!temp_end) - error ("malformed template specification in command"); - p = temp_end; - } - if (p[0] == ':' || p[0] == ' ' || p[0] == '\t' || !*p) + else + error ("nothing is allowed between '[' and ']'"); + } + else + { + /* Gratuitous qoute: skip it and move on. */ + p++; + continue; + } break; - if (p[0] == '.' && strchr (p, ':') == NULL) /* Java qualified method. */ - { - /* Find the *last* '.', since the others are package qualifiers. */ - for (p1 = p; *p1; p1++) - { - if (*p1 == '.') - p = p1; - } - break; - } - } - while (p[0] == ' ' || p[0] == '\t') p++; - - if ((p[0] == ':' || p[0] == '.') && !has_parens) - { - /* C++ */ - /* ... or Java */ - if (is_quoted) *argptr = *argptr+1; - if (p[0] == '.' || p[1] ==':') - { - int ix; - char * saved_arg2 = *argptr; - char * temp_end; - /* First check for "global" namespace specification, - of the form "::foo". If found, skip over the colons - and jump to normal symbol processing */ - if ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')) - saved_arg2 += 2; - - /* We have what looks like a class or namespace - scope specification (A::B), possibly with many - levels of namespaces or classes (A::B::C::D). - - Some versions of the HP ANSI C++ compiler (as also possibly - other compilers) generate class/function/member names with - embedded double-colons if they are inside namespaces. To - handle this, we loop a few times, considering larger and - larger prefixes of the string as though they were single - symbols. So, if the initially supplied string is - A::B::C::D::foo, we have to look up "A", then "A::B", - then "A::B::C", then "A::B::C::D", and finally - "A::B::C::D::foo" as single, monolithic symbols, because - A, B, C or D may be namespaces. - - Note that namespaces can nest only inside other - namespaces, and not inside classes. So we need only - consider *prefixes* of the string; there is no need to look up - "B::C" separately as a symbol in the previous example. */ - - p2 = p; /* save for restart */ - while (1) - { - /* Extract the class name. */ - p1 = p; - while (p != *argptr && p[-1] == ' ') --p; - copy = (char *) alloca (p - *argptr + 1); - memcpy (copy, *argptr, p - *argptr); - copy[p - *argptr] = 0; - - /* Discard the class name from the arg. */ - p = p1 + (p1[0] == ':' ? 2 : 1); - while (*p == ' ' || *p == '\t') p++; - *argptr = p; - - sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0, - (struct symtab **)NULL); - - if (sym_class && - (t = check_typedef (SYMBOL_TYPE (sym_class)), - (TYPE_CODE (t) == TYPE_CODE_STRUCT - || TYPE_CODE (t) == TYPE_CODE_UNION))) - { - /* Arg token is not digits => try it as a function name - Find the next token(everything up to end or next blank). */ - if (**argptr - && strchr (gdb_completer_quote_characters, **argptr) != NULL) - { - p = skip_quoted(*argptr); - *argptr = *argptr + 1; - } - else - { - p = *argptr; - while (*p && *p!=' ' && *p!='\t' && *p!=',' && *p!=':') p++; - } -/* - q = operator_chars (*argptr, &q1); - if (q1 - q) - { - char *opname; - char *tmp = alloca (q1 - q + 1); - memcpy (tmp, q, q1 - q); - tmp[q1 - q] = '\0'; - opname = cplus_mangle_opname (tmp, DMGL_ANSI); - if (opname == NULL) - { - error_begin (); - printf_filtered ("no mangling for \"%s\"\n", tmp); - cplusplus_hint (saved_arg); - return_to_top_level (RETURN_ERROR); - } - copy = (char*) alloca (3 + strlen(opname)); - sprintf (copy, "__%s", opname); - p = q1; - } - else -*/ - { - copy = (char *) alloca (p - *argptr + 1 ); - memcpy (copy, *argptr, p - *argptr); - copy[p - *argptr] = '\0'; - if (p != *argptr - && copy[p - *argptr - 1] - && strchr (gdb_completer_quote_characters, - copy[p - *argptr - 1]) != NULL) - copy[p - *argptr - 1] = '\0'; - } - - /* no line number may be specified */ - while (*p == ' ' || *p == '\t') p++; - *argptr = p; - - sym = 0; - i1 = 0; /* counter for the symbol array */ - sym_arr = (struct symbol **) alloca(total_number_of_methods (t) - * sizeof(struct symbol *)); - - if (destructor_name_p (copy, t)) - { - /* Destructors are a special case. */ - int m_index, f_index; - - if (get_destructor_fn_field (t, &m_index, &f_index)) - { - struct fn_field *f = TYPE_FN_FIELDLIST1 (t, m_index); - - sym_arr[i1] = - lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, f_index), - NULL, VAR_NAMESPACE, (int *) NULL, - (struct symtab **)NULL); - if (sym_arr[i1]) - i1++; - } - } - else - i1 = find_methods (t, copy, sym_arr); - if (i1 == 1) - { - /* There is exactly one field with that name. */ - sym = sym_arr[0]; - - if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) - { - values.sals = (struct symtab_and_line *) - xmalloc (sizeof (struct symtab_and_line)); - values.nelts = 1; - values.sals[0] = find_function_start_sal (sym, - funfirstline); - } - else - { - values.nelts = 0; - } - return values; - } - if (i1 > 0) - { - /* There is more than one field with that name - (overloaded). Ask the user which one to use. */ - return decode_line_2 (sym_arr, i1, funfirstline, canonical); - } - else - { - char *tmp; - - if (OPNAME_PREFIX_P (copy)) - { - tmp = (char *)alloca (strlen (copy+3) + 9); - strcpy (tmp, "operator "); - strcat (tmp, copy+3); - } - else - tmp = copy; - error_begin (); - if (tmp[0] == '~') - printf_filtered - ("the class `%s' does not have destructor defined\n", - SYMBOL_SOURCE_NAME(sym_class)); - else - printf_filtered - ("the class %s does not have any method named %s\n", - SYMBOL_SOURCE_NAME(sym_class), tmp); - cplusplus_hint (saved_arg); - return_to_top_level (RETURN_ERROR); - } - } - - /* Move pointer up to next possible class/namespace token */ - p = p2 + 1; /* restart with old value +1 */ - /* Move pointer ahead to next double-colon */ - while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\'')) { - if (p[0] == '<') { - temp_end = find_template_name_end (p); - if (!temp_end) - error ("malformed template specification in command"); - p = temp_end; - } - else if ((p[0] == ':') && (p[1] == ':')) - break; /* found double-colon */ - else - p++; - } - - if (*p != ':') - break; /* out of the while (1) */ - - p2 = p; /* save restart for next time around */ - *argptr = saved_arg2; /* restore argptr */ - } /* while (1) */ - - /* Last chance attempt -- check entire name as a symbol */ - /* Use "copy" in preparation for jumping out of this block, - to be consistent with usage following the jump target */ - copy = (char *) alloca (p - saved_arg2 + 1); - memcpy (copy, saved_arg2, p - saved_arg2); - /* Note: if is_quoted should be true, we snuff out quote here anyway */ - copy[p-saved_arg2] = '\000'; - /* Set argptr to skip over the name */ - *argptr = (*p == '\'') ? p + 1 : p; - /* Look up entire name */ - sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab); - s = (struct symtab *) 0; - /* Prepare to jump: restore the " if (condition)" so outer layers see it */ - if (has_if) - *ii = ' '; - /* Symbol was found --> jump to normal symbol processing. - Code following "symbol_found" expects "copy" to have the - symbol name, "sym" to have the symbol pointer, "s" to be - a specified file's symtab, and sym_symtab to be the symbol's - symtab. */ - /* By jumping there we avoid falling through the FILE:LINE and - FILE:FUNC processing stuff below */ - if (sym) - goto symbol_found; - - /* Couldn't find any interpretation as classes/namespaces, so give up */ - error_begin (); - /* The quotes are important if copy is empty. */ - printf_filtered - ("Can't find member of namespace, class, struct, or union named \"%s\"\n", copy); - cplusplus_hint (saved_arg); - return_to_top_level (RETURN_ERROR); - } - /* end of C++ */ - - - /* Extract the file name. */ - p1 = p; - while (p != *argptr && p[-1] == ' ') --p; - copy = (char *) alloca (p - *argptr + 1); - memcpy (copy, *argptr, p - *argptr); - copy[p - *argptr] = 0; - - /* Find that file's data. */ - s = lookup_symtab (copy); - if (s == 0) - { - if (!have_full_symbols () && !have_partial_symbols ()) - error (no_symtab_msg); - error ("No source file named %s.", copy); - } - - /* Discard the file name from the arg. */ - p = p1 + 1; - while (*p == ' ' || *p == '\t') p++; - *argptr = p; - } - else { - /* Check if what we have till now is a symbol name */ - - /* We may be looking at a template instantiation such - as "foo<int>". Check here whether we know about it, - instead of falling through to the code below which - handles ordinary function names, because that code - doesn't like seeing '<' and '>' in a name -- the - skip_quoted call doesn't go past them. So see if we - can figure it out right now. */ - - copy = (char *) alloca (p - *argptr + 1); - memcpy (copy, *argptr, p - *argptr); - copy[p - *argptr] = '\000'; - sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab); - if (sym) { - /* Yes, we have a symbol; jump to symbol processing */ - /* Code after symbol_found expects S, SYM_SYMTAB, SYM, - and COPY to be set correctly */ - if (has_if) - *ii = ' '; - *argptr = (*p == '\'') ? p + 1 : p; - s = (struct symtab *) 0; - goto symbol_found; - } - /* Otherwise fall out from here and go to file/line spec - processing, etc. */ - } - - /* S is specified file's symtab, or 0 if no file specified. - arg no longer contains the file name. */ - - /* Check whether arg is all digits (and sign) */ - - q = *argptr; - if (*q == '-' || *q == '+') q++; - while (*q >= '0' && *q <= '9') - q++; - - if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ',')) - { - /* We found a token consisting of all digits -- at least one digit. */ - enum sign {none, plus, minus} sign = none; - - /* We might need a canonical line spec if no file was specified. */ - int need_canonical = (s == 0) ? 1 : 0; - - /* This is where we need to make sure that we have good defaults. - We must guarantee that this section of code is never executed - when we are called with just a function name, since - select_source_symtab calls us with such an argument */ - - if (s == 0 && default_symtab == 0) - { - select_source_symtab (0); - default_symtab = current_source_symtab; - default_line = current_source_line; - } - - if (**argptr == '+') - sign = plus, (*argptr)++; - else if (**argptr == '-') - sign = minus, (*argptr)++; - val.line = atoi (*argptr); - switch (sign) - { - case plus: - if (q == *argptr) - val.line = 5; - if (s == 0) - val.line = default_line + val.line; - break; - case minus: - if (q == *argptr) - val.line = 15; - if (s == 0) - val.line = default_line - val.line; - else - val.line = 1; - break; - case none: - break; /* No need to adjust val.line. */ - } - - while (*q == ' ' || *q == '\t') q++; - *argptr = q; - if (s == 0) - s = default_symtab; - - /* It is possible that this source file has more than one symtab, - and that the new line number specification has moved us from the - default (in s) to a new one. */ - val.symtab = find_line_symtab (s, val.line, NULL, NULL); - if (val.symtab == 0) - val.symtab = s; - - val.pc = 0; - values.sals = (struct symtab_and_line *) - xmalloc (sizeof (struct symtab_and_line)); - values.sals[0] = val; - values.nelts = 1; - if (need_canonical) - build_canonical_line_spec (values.sals, NULL, canonical); - return values; - } - - /* Arg token is not digits => try it as a variable name - Find the next token (everything up to end or next whitespace). */ - - if (**argptr == '$') /* May be a convenience variable */ - p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1)); /* One or two $ chars possible */ - else if (is_quoted) - { - p = skip_quoted (*argptr); - if (p[-1] != '\'') - error ("Unmatched single quote."); - } - else if (has_parens) - { - p = pp+1; - } - else - { - p = skip_quoted(*argptr); - } - - copy = (char *) alloca (p - *argptr + 1); - memcpy (copy, *argptr, p - *argptr); - copy[p - *argptr] = '\0'; - if (p != *argptr - && copy[0] - && copy[0] == copy [p - *argptr - 1] - && strchr (gdb_completer_quote_characters, copy[0]) != NULL) - { - copy [p - *argptr - 1] = '\0'; - copy++; - } - while (*p == ' ' || *p == '\t') p++; - *argptr = p; - - /* If it starts with $: may be a legitimate variable or routine name - (e.g. HP-UX millicode routines such as $$dyncall), or it may - be history value, or it may be a convenience variable */ - - if (*copy == '$') - { - value_ptr valx; - int index = 0; - int need_canonical = 0; - - p = (copy[1] == '$') ? copy + 2 : copy + 1; - while (*p >= '0' && *p <= '9') - p++; - if (!*p) /* reached end of token without hitting non-digit */ - { - /* We have a value history reference */ - sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index); - valx = access_value_history ((copy[1] == '$') ? -index : index); - if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT) - error ("History values used in line specs must have integer values."); - } - else - { - /* Not all digits -- may be user variable/function or a - convenience variable */ - - /* Look up entire name as a symbol first */ - sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab); - s = (struct symtab *) 0; - need_canonical = 1; - /* Symbol was found --> jump to normal symbol processing. - Code following "symbol_found" expects "copy" to have the - symbol name, "sym" to have the symbol pointer, "s" to be - a specified file's symtab, and sym_symtab to be the symbol's - symtab. */ - if (sym) - goto symbol_found; - - /* If symbol was not found, look in minimal symbol tables */ - msymbol = lookup_minimal_symbol (copy, 0, 0); - /* Min symbol was found --> jump to minsym processing. */ - if (msymbol) - goto minimal_symbol_found; - - /* Not a user variable or function -- must be convenience variable */ - need_canonical = (s == 0) ? 1 : 0; - valx = value_of_internalvar (lookup_internalvar (copy + 1)); - if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT) - error ("Convenience variables used in line specs must have integer values."); - } - - /* Either history value or convenience value from above, in valx */ - val.symtab = s ? s : default_symtab; - val.line = value_as_long (valx); - val.pc = 0; - - values.sals = (struct symtab_and_line *)xmalloc (sizeof val); - values.sals[0] = val; - values.nelts = 1; - - if (need_canonical) - build_canonical_line_spec (values.sals, NULL, canonical); - - return values; - } - - - /* Look up that token as a variable. - If file specified, use that file's per-file block to start with. */ - - sym = lookup_symbol (copy, - (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) - : get_selected_block ()), - VAR_NAMESPACE, 0, &sym_symtab); - -symbol_found: /* We also jump here from inside the C++ class/namespace - code on finding a symbol of the form "A::B::C" */ - - if (sym != NULL) - { - if (SYMBOL_CLASS (sym) == LOC_BLOCK) - { - /* Arg is the name of a function */ - values.sals = (struct symtab_and_line *) - xmalloc (sizeof (struct symtab_and_line)); - values.sals[0] = find_function_start_sal (sym, funfirstline); - values.nelts = 1; - - /* Don't use the SYMBOL_LINE; if used at all it points to - the line containing the parameters or thereabouts, not - the first line of code. */ - - /* We might need a canonical line spec if it is a static - function. */ - if (s == 0) - { - struct blockvector *bv = BLOCKVECTOR (sym_symtab); - struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - if (lookup_block_symbol (b, copy, VAR_NAMESPACE) != NULL) - build_canonical_line_spec (values.sals, copy, canonical); - } - return values; - } - else - { - if (funfirstline) - error ("\"%s\" is not a function", copy); - else if (SYMBOL_LINE (sym) != 0) - { - /* We know its line number. */ - values.sals = (struct symtab_and_line *) - xmalloc (sizeof (struct symtab_and_line)); - values.nelts = 1; - memset (&values.sals[0], 0, sizeof (values.sals[0])); - values.sals[0].symtab = sym_symtab; - values.sals[0].line = SYMBOL_LINE (sym); - return values; - } - else - /* This can happen if it is compiled with a compiler which doesn't - put out line numbers for variables. */ - /* FIXME: Shouldn't we just set .line and .symtab to zero - and return? For example, "info line foo" could print - the address. */ - error ("Line number not known for symbol \"%s\"", copy); - } - } - - msymbol = lookup_minimal_symbol (copy, NULL, NULL); - -minimal_symbol_found: /* We also jump here from the case for variables - that begin with '$' */ - - if (msymbol != NULL) - { - values.sals = (struct symtab_and_line *) - xmalloc (sizeof (struct symtab_and_line)); - values.sals[0] = find_pc_sect_line ( SYMBOL_VALUE_ADDRESS (msymbol), - (struct sec *)0,0 ); - values.sals[0].section = SYMBOL_BFD_SECTION (msymbol); - if (funfirstline) - { - values.sals[0].pc += FUNCTION_START_OFFSET; - SKIP_PROLOGUE (values.sals[0].pc); - } - values.nelts = 1; - return values; - } - - if (!have_full_symbols () && - !have_partial_symbols () && !have_minimal_symbols ()) - error (no_symtab_msg); - - error ("Function \"%s\" not defined.", copy); - return values; /* for lint */ -} + case '!': + case '=': + case '*': + case '/': + case '%': + case '^': + if (p[1] == '=') + *end = p + 2; + else + *end = p + 1; + return p; + case '<': + case '>': + case '+': + case '-': + case '&': + case '|': + if (p[0] == '-' && p[1] == '>') + { + /* Struct pointer member operator 'operator->'. */ + if (p[2] == '*') + { + *end = p + 3; /* 'operator->*' */ + return p; + } + else if (p[2] == '\\') + { + *end = p + 4; /* Hopefully 'operator->\*' */ + return p; + } + else + { + *end = p + 2; /* 'operator->' */ + return p; + } + } + if (p[1] == '=' || p[1] == p[0]) + *end = p + 2; + else + *end = p + 1; + return p; + case '~': + case ',': + *end = p + 1; + return p; + case '(': + if (p[1] != ')') + error ("`operator ()' must be specified without whitespace in `()'"); + *end = p + 2; + return p; + case '?': + if (p[1] != ':') + error ("`operator ?:' must be specified without whitespace in `?:'"); + *end = p + 2; + return p; + case '[': + if (p[1] != ']') + error ("`operator []' must be specified without whitespace in `[]'"); + *end = p + 2; + return p; + default: + error ("`operator %s' not supported", p); + break; + } -struct symtabs_and_lines -decode_line_spec (string, funfirstline) - char *string; - int funfirstline; -{ - struct symtabs_and_lines sals; - if (string == 0) - error ("Empty line specification."); - sals = decode_line_1 (&string, funfirstline, - current_source_symtab, current_source_line, - (char ***)NULL); - if (*string) - error ("Junk at end of line specification: %s", string); - return sals; + *end = ""; + return *end; } + -/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to - operate on (ask user if necessary). - If CANONICAL is non-NULL return a corresponding array of mangled names - as canonical line specs there. */ - -static struct symtabs_and_lines -decode_line_2 (sym_arr, nelts, funfirstline, canonical) - struct symbol *sym_arr[]; - int nelts; - int funfirstline; - char ***canonical; +/* If FILE is not already in the table of files, return zero; + otherwise return non-zero. Optionally add FILE to the table if ADD + is non-zero. If *FIRST is non-zero, forget the old table + contents. */ +static int +filename_seen (const char *file, int add, int *first) { - struct symtabs_and_lines values, return_values; - char *args, *arg1; - int i; - char *prompt; - char *symname; - struct cleanup *old_chain; - char **canonical_arr = (char **)NULL; - - values.sals = (struct symtab_and_line *) - alloca (nelts * sizeof(struct symtab_and_line)); - return_values.sals = (struct symtab_and_line *) - xmalloc (nelts * sizeof(struct symtab_and_line)); - old_chain = make_cleanup (free, return_values.sals); + /* Table of files seen so far. */ + static const char **tab = NULL; + /* Allocated size of tab in elements. + Start with one 256-byte block (when using GNU malloc.c). + 24 is the malloc overhead when range checking is in effect. */ + static int tab_alloc_size = (256 - 24) / sizeof (char *); + /* Current size of tab in elements. */ + static int tab_cur_size; + const char **p; - if (canonical) + if (*first) { - canonical_arr = (char **) xmalloc (nelts * sizeof (char *)); - make_cleanup (free, canonical_arr); - memset (canonical_arr, 0, nelts * sizeof (char *)); - *canonical = canonical_arr; + if (tab == NULL) + tab = (const char **) xmalloc (tab_alloc_size * sizeof (*tab)); + tab_cur_size = 0; } - i = 0; - printf_unfiltered("[0] cancel\n[1] all\n"); - while (i < nelts) - { - INIT_SAL (&return_values.sals[i]); /* initialize to zeroes */ - INIT_SAL (&values.sals[i]); - if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK) - { - values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline); - printf_unfiltered ("[%d] %s at %s:%d\n", - (i+2), - SYMBOL_SOURCE_NAME (sym_arr[i]), - values.sals[i].symtab->filename, - values.sals[i].line); - } - else - printf_unfiltered ("?HERE\n"); - i++; - } - - if ((prompt = getenv ("PS2")) == NULL) - { - prompt = "> "; - } - args = command_line_input (prompt, 0, "overload-choice"); - - if (args == 0 || *args == 0) - error_no_arg ("one or more choice numbers"); + /* Is FILE in tab? */ + for (p = tab; p < tab + tab_cur_size; p++) + if (strcmp (*p, file) == 0) + return 1; - i = 0; - while (*args) + /* No; maybe add it to tab. */ + if (add) { - int num; - - arg1 = args; - while (*arg1 >= '0' && *arg1 <= '9') arg1++; - if (*arg1 && *arg1 != ' ' && *arg1 != '\t') - error ("Arguments must be choice numbers."); - - num = atoi (args); - - if (num == 0) - error ("cancelled"); - else if (num == 1) - { - if (canonical_arr) - { - for (i = 0; i < nelts; i++) - { - if (canonical_arr[i] == NULL) - { - symname = SYMBOL_NAME (sym_arr[i]); - canonical_arr[i] = savestring (symname, strlen (symname)); - } - } - } - memcpy (return_values.sals, values.sals, - (nelts * sizeof(struct symtab_and_line))); - return_values.nelts = nelts; - discard_cleanups (old_chain); - return return_values; - } - - if (num >= nelts + 2) + if (tab_cur_size == tab_alloc_size) { - printf_unfiltered ("No choice number %d.\n", num); + tab_alloc_size *= 2; + tab = (const char **) xrealloc ((char *) tab, + tab_alloc_size * sizeof (*tab)); } - else - { - num -= 2; - if (values.sals[num].pc) - { - if (canonical_arr) - { - symname = SYMBOL_NAME (sym_arr[num]); - make_cleanup (free, symname); - canonical_arr[i] = savestring (symname, strlen (symname)); - } - return_values.sals[i++] = values.sals[num]; - values.sals[num].pc = 0; - } - else - { - printf_unfiltered ("duplicate request for %d ignored.\n", num); - } - } - - args = arg1; - while (*args == ' ' || *args == '\t') args++; + tab[tab_cur_size++] = file; } - return_values.nelts = i; - discard_cleanups (old_chain); - return return_values; + + return 0; } - /* Slave routine for sources_info. Force line breaks at ,'s. NAME is the name to print and *FIRST is nonzero if this is the first name printed. Set *FIRST to zero. */ static void -output_source_filename (name, first) - char *name; - int *first; +output_source_filename (char *name, int *first) { - /* Table of files printed so far. Since a single source file can - result in several partial symbol tables, we need to avoid printing - it more than once. Note: if some of the psymtabs are read in and - some are not, it gets printed both under "Source files for which - symbols have been read" and "Source files for which symbols will - be read in on demand". I consider this a reasonable way to deal - with the situation. I'm not sure whether this can also happen for + /* Since a single source file can result in several partial symbol + tables, we need to avoid printing it more than once. Note: if + some of the psymtabs are read in and some are not, it gets + printed both under "Source files for which symbols have been + read" and "Source files for which symbols will be read in on + demand". I consider this a reasonable way to deal with the + situation. I'm not sure whether this can also happen for symtabs; it doesn't hurt to check. */ - static char **tab = NULL; - /* Allocated size of tab in elements. - Start with one 256-byte block (when using GNU malloc.c). - 24 is the malloc overhead when range checking is in effect. */ - static int tab_alloc_size = (256 - 24) / sizeof (char *); - /* Current size of tab in elements. */ - static int tab_cur_size; - - char **p; - if (*first) + /* Was NAME already seen? */ + if (filename_seen (name, 1, first)) { - if (tab == NULL) - tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab)); - tab_cur_size = 0; - } - - /* Is NAME in tab? */ - for (p = tab; p < tab + tab_cur_size; p++) - if (STREQ (*p, name)) /* Yes; don't print it again. */ return; - /* No; add it to tab. */ - if (tab_cur_size == tab_alloc_size) - { - tab_alloc_size *= 2; - tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab)); } - tab[tab_cur_size++] = name; - + /* No; print it and reset *FIRST. */ if (*first) { *first = 0; @@ -3352,60 +2335,55 @@ output_source_filename (name, first) wrap_here (""); fputs_filtered (name, gdb_stdout); -} +} static void -sources_info (ignore, from_tty) - char *ignore; - int from_tty; +sources_info (char *ignore, int from_tty) { register struct symtab *s; register struct partial_symtab *ps; register struct objfile *objfile; int first; - + if (!have_full_symbols () && !have_partial_symbols ()) { - error (no_symtab_msg); + error ("No symbol table is loaded. Use the \"file\" command."); } - + printf_filtered ("Source files for which symbols have been read in:\n\n"); first = 1; ALL_SYMTABS (objfile, s) - { - output_source_filename (s -> filename, &first); - } + { + output_source_filename (s->filename, &first); + } printf_filtered ("\n\n"); - + printf_filtered ("Source files for which symbols will be read in on demand:\n\n"); first = 1; ALL_PSYMTABS (objfile, ps) - { - if (!ps->readin) - { - output_source_filename (ps -> filename, &first); - } - } + { + if (!ps->readin) + { + output_source_filename (ps->filename, &first); + } + } printf_filtered ("\n"); } static int -file_matches (file, files, nfiles) - char *file; - char *files[]; - int nfiles; +file_matches (char *file, char *files[], int nfiles) { int i; if (file != NULL && nfiles != 0) { for (i = 0; i < nfiles; i++) - { - if (strcmp (files[i], basename (file)) == 0) - return 1; - } + { + if (strcmp (files[i], lbasename (file)) == 0) + return 1; + } } else if (nfiles == 0) return 1; @@ -3414,8 +2392,7 @@ file_matches (file, files, nfiles) /* Free any memory associated with a search. */ void -free_search_symbols (symbols) - struct symbol_search *symbols; +free_search_symbols (struct symbol_search *symbols) { struct symbol_search *p; struct symbol_search *next; @@ -3423,30 +2400,87 @@ free_search_symbols (symbols) for (p = symbols; p != NULL; p = next) { next = p->next; - free (p); + xfree (p); } } +static void +do_free_search_symbols_cleanup (void *symbols) +{ + free_search_symbols (symbols); +} + +struct cleanup * +make_cleanup_free_search_symbols (struct symbol_search *symbols) +{ + return make_cleanup (do_free_search_symbols_cleanup, symbols); +} + +/* Helper function for sort_search_symbols and qsort. Can only + sort symbols, not minimal symbols. */ +static int +compare_search_syms (const void *sa, const void *sb) +{ + struct symbol_search **sym_a = (struct symbol_search **) sa; + struct symbol_search **sym_b = (struct symbol_search **) sb; + + return strcmp (SYMBOL_SOURCE_NAME ((*sym_a)->symbol), + SYMBOL_SOURCE_NAME ((*sym_b)->symbol)); +} + +/* Sort the ``nfound'' symbols in the list after prevtail. Leave + prevtail where it is, but update its next pointer to point to + the first of the sorted symbols. */ +static struct symbol_search * +sort_search_symbols (struct symbol_search *prevtail, int nfound) +{ + struct symbol_search **symbols, *symp, *old_next; + int i; + + symbols = (struct symbol_search **) xmalloc (sizeof (struct symbol_search *) + * nfound); + symp = prevtail->next; + for (i = 0; i < nfound; i++) + { + symbols[i] = symp; + symp = symp->next; + } + /* Generally NULL. */ + old_next = symp; + + qsort (symbols, nfound, sizeof (struct symbol_search *), + compare_search_syms); + + symp = prevtail; + for (i = 0; i < nfound; i++) + { + symp->next = symbols[i]; + symp = symp->next; + } + symp->next = old_next; + + xfree (symbols); + return symp; +} + /* Search the symbol table for matches to the regular expression REGEXP, returning the results in *MATCHES. Only symbols of KIND are searched: - FUNCTIONS_NAMESPACE - search all functions - TYPES_NAMESPACE - search all type names - METHODS_NAMESPACE - search all methods NOT IMPLEMENTED - VARIABLES_NAMESPACE - search all symbols, excluding functions, type names, - and constants (enums) + FUNCTIONS_NAMESPACE - search all functions + TYPES_NAMESPACE - search all type names + METHODS_NAMESPACE - search all methods NOT IMPLEMENTED + VARIABLES_NAMESPACE - search all symbols, excluding functions, type names, + and constants (enums) free_search_symbols should be called when *MATCHES is no longer needed. -*/ + + The results are sorted locally; each symtab's global and static blocks are + separately alphabetized. + */ void -search_symbols (regexp, kind, nfiles, files, matches) - char *regexp; - namespace_enum kind; - int nfiles; - char *files[]; - struct symbol_search **matches; - +search_symbols (char *regexp, namespace_enum kind, int nfiles, char *files[], + struct symbol_search **matches) { register struct symtab *s; register struct partial_symtab *ps; @@ -3462,13 +2496,17 @@ search_symbols (regexp, kind, nfiles, files, matches) char *val; int found_misc = 0; static enum minimal_symbol_type types[] - = {mst_data, mst_text, mst_abs, mst_unknown}; + = + {mst_data, mst_text, mst_abs, mst_unknown}; static enum minimal_symbol_type types2[] - = {mst_bss, mst_file_text, mst_abs, mst_unknown}; + = + {mst_bss, mst_file_text, mst_abs, mst_unknown}; static enum minimal_symbol_type types3[] - = {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown}; + = + {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown}; static enum minimal_symbol_type types4[] - = {mst_file_bss, mst_text, mst_abs, mst_unknown}; + = + {mst_file_bss, mst_text, mst_abs, mst_unknown}; enum minimal_symbol_type ourtype; enum minimal_symbol_type ourtype2; enum minimal_symbol_type ourtype3; @@ -3478,13 +2516,13 @@ search_symbols (regexp, kind, nfiles, files, matches) struct symbol_search *tail; struct cleanup *old_chain = NULL; - if (kind < LABEL_NAMESPACE) + if (kind < VARIABLES_NAMESPACE) error ("must search on specific namespace"); - ourtype = types[(int) (kind - LABEL_NAMESPACE)]; - ourtype2 = types2[(int) (kind - LABEL_NAMESPACE)]; - ourtype3 = types3[(int) (kind - LABEL_NAMESPACE)]; - ourtype4 = types4[(int) (kind - LABEL_NAMESPACE)]; + ourtype = types[(int) (kind - VARIABLES_NAMESPACE)]; + ourtype2 = types2[(int) (kind - VARIABLES_NAMESPACE)]; + ourtype3 = types3[(int) (kind - VARIABLES_NAMESPACE)]; + ourtype4 = types4[(int) (kind - VARIABLES_NAMESPACE)]; sr = *matches = NULL; tail = NULL; @@ -3498,31 +2536,31 @@ search_symbols (regexp, kind, nfiles, files, matches) char *opend; char *opname = operator_chars (regexp, &opend); if (*opname) - { - int fix = -1; /* -1 means ok; otherwise number of spaces needed. */ - if (isalpha(*opname) || *opname == '_' || *opname == '$') - { - /* There should 1 space between 'operator' and 'TYPENAME'. */ - if (opname[-1] != ' ' || opname[-2] == ' ') - fix = 1; - } - else - { - /* There should 0 spaces between 'operator' and 'OPERATOR'. */ - if (opname[-1] == ' ') - fix = 0; - } - /* If wrong number of spaces, fix it. */ - if (fix >= 0) - { - char *tmp = (char*) alloca(opend-opname+10); - sprintf(tmp, "operator%.*s%s", fix, " ", opname); - regexp = tmp; - } - } - + { + int fix = -1; /* -1 means ok; otherwise number of spaces needed. */ + if (isalpha (*opname) || *opname == '_' || *opname == '$') + { + /* There should 1 space between 'operator' and 'TYPENAME'. */ + if (opname[-1] != ' ' || opname[-2] == ' ') + fix = 1; + } + else + { + /* There should 0 spaces between 'operator' and 'OPERATOR'. */ + if (opname[-1] == ' ') + fix = 0; + } + /* If wrong number of spaces, fix it. */ + if (fix >= 0) + { + char *tmp = (char *) alloca (8 + fix + strlen (opname) + 1); + sprintf (tmp, "operator%.*s%s", fix, " ", opname); + regexp = tmp; + } + } + if (0 != (val = re_comp (regexp))) - error ("Invalid regexp (%s): %s", val, regexp); + error ("Invalid regexp (%s): %s", val, regexp); } /* Search through the partial symtabs *first* for all symbols @@ -3530,53 +2568,54 @@ search_symbols (regexp, kind, nfiles, files, matches) the machinery below. */ ALL_PSYMTABS (objfile, ps) - { - struct partial_symbol **bound, **gbound, **sbound; - int keep_going = 1; - - if (ps->readin) continue; - - gbound = objfile->global_psymbols.list + ps->globals_offset + ps->n_global_syms; - sbound = objfile->static_psymbols.list + ps->statics_offset + ps->n_static_syms; - bound = gbound; - - /* Go through all of the symbols stored in a partial - symtab in one loop. */ - psym = objfile->global_psymbols.list + ps->globals_offset; - while (keep_going) - { - if (psym >= bound) - { - if (bound == gbound && ps->n_static_syms != 0) - { - psym = objfile->static_psymbols.list + ps->statics_offset; - bound = sbound; - } - else - keep_going = 0; - continue; - } - else - { - QUIT; - - /* If it would match (logic taken from loop below) - load the file and go on to the next one */ - if (file_matches (ps->filename, files, nfiles) - && ((regexp == NULL || SYMBOL_MATCHES_REGEXP (*psym)) - && ((kind == VARIABLES_NAMESPACE && SYMBOL_CLASS (*psym) != LOC_TYPEDEF - && SYMBOL_CLASS (*psym) != LOC_BLOCK) - || (kind == FUNCTIONS_NAMESPACE && SYMBOL_CLASS (*psym) == LOC_BLOCK) - || (kind == TYPES_NAMESPACE && SYMBOL_CLASS (*psym) == LOC_TYPEDEF) - || (kind == METHODS_NAMESPACE && SYMBOL_CLASS (*psym) == LOC_BLOCK)))) - { - PSYMTAB_TO_SYMTAB(ps); - keep_going = 0; - } - } - psym++; - } - } + { + struct partial_symbol **bound, **gbound, **sbound; + int keep_going = 1; + + if (ps->readin) + continue; + + gbound = objfile->global_psymbols.list + ps->globals_offset + ps->n_global_syms; + sbound = objfile->static_psymbols.list + ps->statics_offset + ps->n_static_syms; + bound = gbound; + + /* Go through all of the symbols stored in a partial + symtab in one loop. */ + psym = objfile->global_psymbols.list + ps->globals_offset; + while (keep_going) + { + if (psym >= bound) + { + if (bound == gbound && ps->n_static_syms != 0) + { + psym = objfile->static_psymbols.list + ps->statics_offset; + bound = sbound; + } + else + keep_going = 0; + continue; + } + else + { + QUIT; + + /* If it would match (logic taken from loop below) + load the file and go on to the next one */ + if (file_matches (ps->filename, files, nfiles) + && ((regexp == NULL || SYMBOL_MATCHES_REGEXP (*psym)) + && ((kind == VARIABLES_NAMESPACE && SYMBOL_CLASS (*psym) != LOC_TYPEDEF + && SYMBOL_CLASS (*psym) != LOC_BLOCK) + || (kind == FUNCTIONS_NAMESPACE && SYMBOL_CLASS (*psym) == LOC_BLOCK) + || (kind == TYPES_NAMESPACE && SYMBOL_CLASS (*psym) == LOC_TYPEDEF) + || (kind == METHODS_NAMESPACE && SYMBOL_CLASS (*psym) == LOC_BLOCK)))) + { + PSYMTAB_TO_SYMTAB (ps); + keep_going = 0; + } + } + psym++; + } + } /* Here, we search through the minimal symbol tables for functions and variables that match, and force their symbols to be read. @@ -3589,82 +2628,93 @@ search_symbols (regexp, kind, nfiles, files, matches) to determine if the variable has debug info. If the lookup fails, set found_misc so that we will rescan to print any matching symbols without debug info. - */ + */ if (nfiles == 0 && (kind == VARIABLES_NAMESPACE || kind == FUNCTIONS_NAMESPACE)) { ALL_MSYMBOLS (objfile, msymbol) - { - if (MSYMBOL_TYPE (msymbol) == ourtype || - MSYMBOL_TYPE (msymbol) == ourtype2 || - MSYMBOL_TYPE (msymbol) == ourtype3 || - MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) - { - if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))) - { - if (kind == FUNCTIONS_NAMESPACE - || lookup_symbol (SYMBOL_NAME (msymbol), - (struct block *) NULL, - VAR_NAMESPACE, - 0, (struct symtab **) NULL) == NULL) - found_misc = 1; - } - } - } - } + { + if (MSYMBOL_TYPE (msymbol) == ourtype || + MSYMBOL_TYPE (msymbol) == ourtype2 || + MSYMBOL_TYPE (msymbol) == ourtype3 || + MSYMBOL_TYPE (msymbol) == ourtype4) + { + if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) + { + if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))) + { + if (kind == FUNCTIONS_NAMESPACE + || lookup_symbol (SYMBOL_NAME (msymbol), + (struct block *) NULL, + VAR_NAMESPACE, + 0, (struct symtab **) NULL) == NULL) + found_misc = 1; + } + } + } + } } ALL_SYMTABS (objfile, s) - { - bv = BLOCKVECTOR (s); - /* Often many files share a blockvector. - Scan each blockvector only once so that - we don't get every symbol many times. - It happens that the first symtab in the list - for any given blockvector is the main file. */ - if (bv != prev_bv) - for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) - { - b = BLOCKVECTOR_BLOCK (bv, i); - /* Skip the sort if this block is always sorted. */ - if (!BLOCK_SHOULD_SORT (b)) - sort_block_syms (b); - for (j = 0; j < BLOCK_NSYMS (b); j++) - { - QUIT; - sym = BLOCK_SYM (b, j); - if (file_matches (s->filename, files, nfiles) - && ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym)) - && ((kind == VARIABLES_NAMESPACE && SYMBOL_CLASS (sym) != LOC_TYPEDEF - && SYMBOL_CLASS (sym) != LOC_BLOCK - && SYMBOL_CLASS (sym) != LOC_CONST) - || (kind == FUNCTIONS_NAMESPACE && SYMBOL_CLASS (sym) == LOC_BLOCK) - || (kind == TYPES_NAMESPACE && SYMBOL_CLASS (sym) == LOC_TYPEDEF) - || (kind == METHODS_NAMESPACE && SYMBOL_CLASS (sym) == LOC_BLOCK)))) - { - /* match */ - psr = (struct symbol_search *) xmalloc (sizeof (struct symbol_search)); - psr->block = i; - psr->symtab = s; - psr->symbol = sym; - psr->msymbol = NULL; - psr->next = NULL; - if (tail == NULL) - { - sr = psr; - old_chain = make_cleanup ((make_cleanup_func) - free_search_symbols, sr); - } - else - tail->next = psr; - tail = psr; - } - } - } - prev_bv = bv; - } + { + bv = BLOCKVECTOR (s); + /* Often many files share a blockvector. + Scan each blockvector only once so that + we don't get every symbol many times. + It happens that the first symtab in the list + for any given blockvector is the main file. */ + if (bv != prev_bv) + for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) + { + struct symbol_search *prevtail = tail; + int nfound = 0; + b = BLOCKVECTOR_BLOCK (bv, i); + for (j = 0; j < BLOCK_NSYMS (b); j++) + { + QUIT; + sym = BLOCK_SYM (b, j); + if (file_matches (s->filename, files, nfiles) + && ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym)) + && ((kind == VARIABLES_NAMESPACE && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK + && SYMBOL_CLASS (sym) != LOC_CONST) + || (kind == FUNCTIONS_NAMESPACE && SYMBOL_CLASS (sym) == LOC_BLOCK) + || (kind == TYPES_NAMESPACE && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + || (kind == METHODS_NAMESPACE && SYMBOL_CLASS (sym) == LOC_BLOCK)))) + { + /* match */ + psr = (struct symbol_search *) xmalloc (sizeof (struct symbol_search)); + psr->block = i; + psr->symtab = s; + psr->symbol = sym; + psr->msymbol = NULL; + psr->next = NULL; + if (tail == NULL) + sr = psr; + else + tail->next = psr; + tail = psr; + nfound ++; + } + } + if (nfound > 0) + { + if (prevtail == NULL) + { + struct symbol_search dummy; + + dummy.next = sr; + tail = sort_search_symbols (&dummy, nfound); + sr = dummy.next; + + old_chain = make_cleanup_free_search_symbols (sr); + } + else + tail = sort_search_symbols (prevtail, nfound); + } + } + prev_bv = bv; + } /* If there are no eyes, avoid all contact. I mean, if there are no debug symbols, then print directly from the msymbol_vector. */ @@ -3672,44 +2722,43 @@ search_symbols (regexp, kind, nfiles, files, matches) if (found_misc || kind != FUNCTIONS_NAMESPACE) { ALL_MSYMBOLS (objfile, msymbol) - { - if (MSYMBOL_TYPE (msymbol) == ourtype || - MSYMBOL_TYPE (msymbol) == ourtype2 || - MSYMBOL_TYPE (msymbol) == ourtype3 || - MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) - { - /* Functions: Look up by address. */ - if (kind != FUNCTIONS_NAMESPACE || - (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))) - { - /* Variables/Absolutes: Look up by name */ - if (lookup_symbol (SYMBOL_NAME (msymbol), - (struct block *) NULL, VAR_NAMESPACE, - 0, (struct symtab **) NULL) == NULL) - { - /* match */ - psr = (struct symbol_search *) xmalloc (sizeof (struct symbol_search)); - psr->block = i; - psr->msymbol = msymbol; - psr->symtab = NULL; - psr->symbol = NULL; - psr->next = NULL; - if (tail == NULL) - { - sr = psr; - old_chain = make_cleanup ((make_cleanup_func) - free_search_symbols, &sr); - } - else - tail->next = psr; - tail = psr; - } - } - } - } - } + { + if (MSYMBOL_TYPE (msymbol) == ourtype || + MSYMBOL_TYPE (msymbol) == ourtype2 || + MSYMBOL_TYPE (msymbol) == ourtype3 || + MSYMBOL_TYPE (msymbol) == ourtype4) + { + if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) + { + /* Functions: Look up by address. */ + if (kind != FUNCTIONS_NAMESPACE || + (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))) + { + /* Variables/Absolutes: Look up by name */ + if (lookup_symbol (SYMBOL_NAME (msymbol), + (struct block *) NULL, VAR_NAMESPACE, + 0, (struct symtab **) NULL) == NULL) + { + /* match */ + psr = (struct symbol_search *) xmalloc (sizeof (struct symbol_search)); + psr->block = i; + psr->msymbol = msymbol; + psr->symtab = NULL; + psr->symbol = NULL; + psr->next = NULL; + if (tail == NULL) + { + sr = psr; + old_chain = make_cleanup_free_search_symbols (sr); + } + else + tail->next = psr; + tail = psr; + } + } + } + } + } } *matches = sr; @@ -3720,14 +2769,10 @@ search_symbols (regexp, kind, nfiles, files, matches) /* Helper function for symtab_symbol_info, this function uses the data returned from search_symbols() to print information regarding the match to gdb_stdout. -*/ + */ static void -print_symbol_info (kind, s, sym, block, last) - namespace_enum kind; - struct symtab *s; - struct symbol *sym; - int block; - char *last; +print_symbol_info (namespace_enum kind, struct symtab *s, struct symbol *sym, + int block, char *last) { if (last == NULL || strcmp (last, s->filename) != 0) { @@ -3738,74 +2783,79 @@ print_symbol_info (kind, s, sym, block, last) if (kind != TYPES_NAMESPACE && block == STATIC_BLOCK) printf_filtered ("static "); - + /* Typedef that is not a C++ class */ if (kind == TYPES_NAMESPACE && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE) - c_typedef_print (SYMBOL_TYPE(sym), sym, gdb_stdout); + typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout); /* variable, func, or typedef-that-is-c++-class */ - else if (kind < TYPES_NAMESPACE || - (kind == TYPES_NAMESPACE && - SYMBOL_NAMESPACE(sym) == STRUCT_NAMESPACE)) + else if (kind < TYPES_NAMESPACE || + (kind == TYPES_NAMESPACE && + SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE)) { type_print (SYMBOL_TYPE (sym), - (SYMBOL_CLASS (sym) == LOC_TYPEDEF - ? "" : SYMBOL_SOURCE_NAME (sym)), - gdb_stdout, 0); + (SYMBOL_CLASS (sym) == LOC_TYPEDEF + ? "" : SYMBOL_SOURCE_NAME (sym)), + gdb_stdout, 0); printf_filtered (";\n"); } else { -# if 0 +#if 0 /* Tiemann says: "info methods was never implemented." */ char *demangled_name; - c_type_print_base (TYPE_FN_FIELD_TYPE(t, block), - gdb_stdout, 0, 0); - c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, block), - gdb_stdout, 0); + c_type_print_base (TYPE_FN_FIELD_TYPE (t, block), + gdb_stdout, 0, 0); + c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (t, block), + gdb_stdout, 0); if (TYPE_FN_FIELD_STUB (t, block)) - check_stub_method (TYPE_DOMAIN_TYPE (type), j, block); + check_stub_method (TYPE_DOMAIN_TYPE (type), j, block); demangled_name = - cplus_demangle (TYPE_FN_FIELD_PHYSNAME (t, block), - DMGL_ANSI | DMGL_PARAMS); + cplus_demangle (TYPE_FN_FIELD_PHYSNAME (t, block), + DMGL_ANSI | DMGL_PARAMS); if (demangled_name == NULL) - fprintf_filtered (stream, "<badly mangled name %s>", - TYPE_FN_FIELD_PHYSNAME (t, block)); + fprintf_filtered (stream, "<badly mangled name %s>", + TYPE_FN_FIELD_PHYSNAME (t, block)); else - { - fputs_filtered (demangled_name, stream); - free (demangled_name); - } -# endif + { + fputs_filtered (demangled_name, stream); + xfree (demangled_name); + } +#endif } } /* This help function for symtab_symbol_info() prints information for non-debugging symbols to gdb_stdout. -*/ + */ static void -print_msymbol_info (msymbol) - struct minimal_symbol *msymbol; +print_msymbol_info (struct minimal_symbol *msymbol) { - printf_filtered (" %08lx %s\n", - (unsigned long) SYMBOL_VALUE_ADDRESS (msymbol), - SYMBOL_SOURCE_NAME (msymbol)); + char *tmp; + + if (TARGET_ADDR_BIT <= 32) + tmp = longest_local_hex_string_custom (SYMBOL_VALUE_ADDRESS (msymbol) + & (CORE_ADDR) 0xffffffff, + "08l"); + else + tmp = longest_local_hex_string_custom (SYMBOL_VALUE_ADDRESS (msymbol), + "016l"); + printf_filtered ("%s %s\n", + tmp, SYMBOL_SOURCE_NAME (msymbol)); } /* This is the guts of the commands "info functions", "info types", and "info variables". It calls search_symbols to find all matches and then print_[m]symbol_info to print out some useful information about the matches. -*/ + */ static void -symtab_symbol_info (regexp, kind, from_tty) - char *regexp; - namespace_enum kind; - int from_tty; +symtab_symbol_info (char *regexp, namespace_enum kind, int from_tty) { static char *classnames[] - = {"variable", "function", "type", "method"}; + = + {"variable", "function", "type", "method"}; struct symbol_search *symbols; struct symbol_search *p; struct cleanup *old_chain; @@ -3814,60 +2864,55 @@ symtab_symbol_info (regexp, kind, from_tty) /* must make sure that if we're interrupted, symbols gets freed */ search_symbols (regexp, kind, 0, (char **) NULL, &symbols); - old_chain = make_cleanup ((make_cleanup_func) free_search_symbols, symbols); + old_chain = make_cleanup_free_search_symbols (symbols); printf_filtered (regexp - ? "All %ss matching regular expression \"%s\":\n" - : "All defined %ss:\n", - classnames[(int) (kind - LABEL_NAMESPACE - 1)], regexp); + ? "All %ss matching regular expression \"%s\":\n" + : "All defined %ss:\n", + classnames[(int) (kind - VARIABLES_NAMESPACE)], regexp); for (p = symbols; p != NULL; p = p->next) { QUIT; if (p->msymbol != NULL) - { - if (first) - { - printf_filtered ("\nNon-debugging symbols:\n"); - first = 0; - } - print_msymbol_info (p->msymbol); - } + { + if (first) + { + printf_filtered ("\nNon-debugging symbols:\n"); + first = 0; + } + print_msymbol_info (p->msymbol); + } else - { - print_symbol_info (kind, - p->symtab, - p->symbol, - p->block, - last_filename); - last_filename = p->symtab->filename; - } + { + print_symbol_info (kind, + p->symtab, + p->symbol, + p->block, + last_filename); + last_filename = p->symtab->filename; + } } do_cleanups (old_chain); } static void -variables_info (regexp, from_tty) - char *regexp; - int from_tty; +variables_info (char *regexp, int from_tty) { symtab_symbol_info (regexp, VARIABLES_NAMESPACE, from_tty); } static void -functions_info (regexp, from_tty) - char *regexp; - int from_tty; +functions_info (char *regexp, int from_tty) { symtab_symbol_info (regexp, FUNCTIONS_NAMESPACE, from_tty); } + static void -types_info (regexp, from_tty) - char *regexp; - int from_tty; +types_info (char *regexp, int from_tty) { symtab_symbol_info (regexp, TYPES_NAMESPACE, from_tty); } @@ -3875,70 +2920,73 @@ types_info (regexp, from_tty) #if 0 /* Tiemann says: "info methods was never implemented." */ static void -methods_info (regexp) - char *regexp; +methods_info (char *regexp) { symtab_symbol_info (regexp, METHODS_NAMESPACE, 0, from_tty); } #endif /* 0 */ /* Breakpoint all functions matching regular expression. */ + +void +rbreak_command_wrapper (char *regexp, int from_tty) +{ + rbreak_command (regexp, from_tty); +} + static void -rbreak_command (regexp, from_tty) - char *regexp; - int from_tty; +rbreak_command (char *regexp, int from_tty) { struct symbol_search *ss; struct symbol_search *p; struct cleanup *old_chain; search_symbols (regexp, FUNCTIONS_NAMESPACE, 0, (char **) NULL, &ss); - old_chain = make_cleanup ((make_cleanup_func) free_search_symbols, ss); + old_chain = make_cleanup_free_search_symbols (ss); for (p = ss; p != NULL; p = p->next) { if (p->msymbol == NULL) - { - char *string = (char *) alloca (strlen (p->symtab->filename) - + strlen (SYMBOL_NAME (p->symbol)) - + 4); - strcpy (string, p->symtab->filename); - strcat (string, ":'"); - strcat (string, SYMBOL_NAME (p->symbol)); - strcat (string, "'"); - break_command (string, from_tty); - print_symbol_info (FUNCTIONS_NAMESPACE, - p->symtab, - p->symbol, - p->block, - p->symtab->filename); - } + { + char *string = (char *) alloca (strlen (p->symtab->filename) + + strlen (SYMBOL_NAME (p->symbol)) + + 4); + strcpy (string, p->symtab->filename); + strcat (string, ":'"); + strcat (string, SYMBOL_NAME (p->symbol)); + strcat (string, "'"); + break_command (string, from_tty); + print_symbol_info (FUNCTIONS_NAMESPACE, + p->symtab, + p->symbol, + p->block, + p->symtab->filename); + } else - { - break_command (SYMBOL_NAME (p->msymbol), from_tty); - printf_filtered ("<function, no debug info> %s;\n", - SYMBOL_SOURCE_NAME (p->msymbol)); - } + { + break_command (SYMBOL_NAME (p->msymbol), from_tty); + printf_filtered ("<function, no debug info> %s;\n", + SYMBOL_SOURCE_NAME (p->msymbol)); + } } do_cleanups (old_chain); } - + /* Return Nonzero if block a is lexically nested within block b, or if a and b have the same pc range. Return zero otherwise. */ int -contained_in (a, b) - struct block *a, *b; +contained_in (struct block *a, struct block *b) { if (!a || !b) return 0; return BLOCK_START (a) >= BLOCK_START (b) - && BLOCK_END (a) <= BLOCK_END (b); + && BLOCK_END (a) <= BLOCK_END (b); } - + /* Helper routine for make_symbol_completion_list. */ static int return_val_size; @@ -3959,16 +3007,12 @@ static char **return_val; } while (0) /* Test to see if the symbol specified by SYMNAME (which is already - demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN - characters. If so, add it to the current completion list. */ + demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN + characters. If so, add it to the current completion list. */ static void -completion_list_add_name (symname, sym_text, sym_text_len, text, word) - char *symname; - char *sym_text; - int sym_text_len; - char *text; - char *word; +completion_list_add_name (char *symname, char *sym_text, int sym_text_len, + char *text, char *word) { int newsize; int i; @@ -3980,17 +3024,6 @@ completion_list_add_name (symname, sym_text, sym_text_len, text, word) return; } - /* Clip any symbol names that we've already considered. (This is a - time optimization) */ - - for (i = 0; i < return_val_index; ++i) - { - if (STREQ (symname, return_val[i])) - { - return; - } - } - /* We have a match for a completion, so add SYMNAME to the current list of matches. Note that the name is moved to freshly malloc'd space. */ @@ -4016,19 +3049,6 @@ completion_list_add_name (symname, sym_text, sym_text_len, text, word) strcat (new, symname); } - /* Recheck for duplicates if we intend to add a modified symbol. */ - if (word != sym_text) - { - for (i = 0; i < return_val_index; ++i) - { - if (STREQ (new, return_val[i])) - { - free (new); - return; - } - } - } - if (return_val_index + 3 > return_val_size) { newsize = (return_val_size *= 2) * sizeof (char *); @@ -4039,17 +3059,15 @@ completion_list_add_name (symname, sym_text, sym_text_len, text, word) } } -/* Return a NULL terminated array of all symbols (regardless of class) which - begin by matching TEXT. If the answer is no symbols, then the return value - is an array which contains only a NULL pointer. +/* Return a NULL terminated array of all symbols (regardless of class) + which begin by matching TEXT. If the answer is no symbols, then + the return value is an array which contains only a NULL pointer. Problem: All of the symbols have to be copied because readline frees them. I'm not going to worry about this; hopefully there won't be that many. */ char ** -make_symbol_completion_list (text, word) - char *text; - char *word; +make_symbol_completion_list (char *text, char *word) { register struct symbol *sym; register struct symtab *s; @@ -4082,7 +3100,7 @@ make_symbol_completion_list (text, word) quote_found = '\0'; else if (*p == '\\' && p[1] == quote_found) /* A backslash followed by the quote character - doesn't end the string. */ + doesn't end the string. */ ++p; } else if (*p == '\'' || *p == '"') @@ -4096,8 +3114,12 @@ make_symbol_completion_list (text, word) sym_text = quote_pos + 1; else if (quote_found == '"') /* A double-quoted string is never a symbol, nor does it make sense - to complete it any other way. */ - return NULL; + to complete it any other way. */ + { + return_val = (char **) xmalloc (sizeof (char *)); + return_val[0] = NULL; + return return_val; + } else { /* It is not a quoted string. Break it based on the characters @@ -4124,30 +3146,31 @@ make_symbol_completion_list (text, word) by matching SYM_TEXT. Add each one that you find to the list. */ ALL_PSYMTABS (objfile, ps) - { - /* If the psymtab's been read in we'll get it when we search - through the blockvector. */ - if (ps->readin) continue; - - for (psym = objfile->global_psymbols.list + ps->globals_offset; - psym < (objfile->global_psymbols.list + ps->globals_offset - + ps->n_global_syms); - psym++) - { - /* If interrupted, then quit. */ - QUIT; - COMPLETION_LIST_ADD_SYMBOL (*psym, sym_text, sym_text_len, text, word); - } - - for (psym = objfile->static_psymbols.list + ps->statics_offset; - psym < (objfile->static_psymbols.list + ps->statics_offset - + ps->n_static_syms); - psym++) - { - QUIT; - COMPLETION_LIST_ADD_SYMBOL (*psym, sym_text, sym_text_len, text, word); - } - } + { + /* If the psymtab's been read in we'll get it when we search + through the blockvector. */ + if (ps->readin) + continue; + + for (psym = objfile->global_psymbols.list + ps->globals_offset; + psym < (objfile->global_psymbols.list + ps->globals_offset + + ps->n_global_syms); + psym++) + { + /* If interrupted, then quit. */ + QUIT; + COMPLETION_LIST_ADD_SYMBOL (*psym, sym_text, sym_text_len, text, word); + } + + for (psym = objfile->static_psymbols.list + ps->statics_offset; + psym < (objfile->static_psymbols.list + ps->statics_offset + + ps->n_static_syms); + psym++) + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (*psym, sym_text, sym_text_len, text, word); + } + } /* At this point scan through the misc symbol vectors and add each symbol you find to the list. Eventually we want to ignore @@ -4155,10 +3178,10 @@ make_symbol_completion_list (text, word) handled by the psymtab code above). */ ALL_MSYMBOLS (objfile, msymbol) - { - QUIT; - COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word); - } + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word); + } /* Search upwards from currently selected frame (so that we can complete on local vars. */ @@ -4167,15 +3190,14 @@ make_symbol_completion_list (text, word) { if (!BLOCK_SUPERBLOCK (b)) { - surrounding_static_block = b; /* For elmin of dups */ + surrounding_static_block = b; /* For elmin of dups */ } - + /* Also catch fields of types defined in this places which match our - text string. Only complete on types visible from current context. */ + text string. Only complete on types visible from current context. */ - for (i = 0; i < BLOCK_NSYMS (b); i++) + ALL_BLOCK_SYMBOLS (b, i, sym) { - sym = BLOCK_SYM (b, i); COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) { @@ -4189,7 +3211,7 @@ make_symbol_completion_list (text, word) if (TYPE_FIELD_NAME (t, j)) { completion_list_add_name (TYPE_FIELD_NAME (t, j), - sym_text, sym_text_len, text, word); + sym_text, sym_text_len, text, word); } } } @@ -4201,30 +3223,298 @@ make_symbol_completion_list (text, word) symbols which match. */ ALL_SYMTABS (objfile, s) + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + ALL_BLOCK_SYMBOLS (b, i, sym) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + } + + ALL_SYMTABS (objfile, s) + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + /* Don't do this block twice. */ + if (b == surrounding_static_block) + continue; + ALL_BLOCK_SYMBOLS (b, i, sym) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + } + + return (return_val); +} + +/* Like make_symbol_completion_list, but returns a list of symbols + defined in a source file FILE. */ + +char ** +make_file_symbol_completion_list (char *text, char *word, char *srcfile) +{ + register struct symbol *sym; + register struct symtab *s; + register struct block *b; + register int i; + /* The symbol we are completing on. Points in same buffer as text. */ + char *sym_text; + /* Length of sym_text. */ + int sym_text_len; + + /* Now look for the symbol we are supposed to complete on. + FIXME: This should be language-specific. */ + { + char *p; + char quote_found; + char *quote_pos = NULL; + + /* First see if this is a quoted string. */ + quote_found = '\0'; + for (p = text; *p != '\0'; ++p) + { + if (quote_found != '\0') + { + if (*p == quote_found) + /* Found close quote. */ + quote_found = '\0'; + else if (*p == '\\' && p[1] == quote_found) + /* A backslash followed by the quote character + doesn't end the string. */ + ++p; + } + else if (*p == '\'' || *p == '"') + { + quote_found = *p; + quote_pos = p; + } + } + if (quote_found == '\'') + /* A string within single quotes can be a symbol, so complete on it. */ + sym_text = quote_pos + 1; + else if (quote_found == '"') + /* A double-quoted string is never a symbol, nor does it make sense + to complete it any other way. */ + { + return_val = (char **) xmalloc (sizeof (char *)); + return_val[0] = NULL; + return return_val; + } + else + { + /* It is not a quoted string. Break it based on the characters + which are in symbols. */ + while (p > text) + { + if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0') + --p; + else + break; + } + sym_text = p; + } + } + + sym_text_len = strlen (sym_text); + + return_val_size = 10; + return_val_index = 0; + return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *)); + return_val[0] = NULL; + + /* Find the symtab for SRCFILE (this loads it if it was not yet read + in). */ + s = lookup_symtab (srcfile); + if (s == NULL) { - QUIT; - b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); - for (i = 0; i < BLOCK_NSYMS (b); i++) + /* Maybe they typed the file with leading directories, while the + symbol tables record only its basename. */ + const char *tail = lbasename (srcfile); + + if (tail > srcfile) + s = lookup_symtab (tail); + } + + /* If we have no symtab for that file, return an empty list. */ + if (s == NULL) + return (return_val); + + /* Go through this symtab and check the externs and statics for + symbols which match. */ + + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + ALL_BLOCK_SYMBOLS (b, i, sym) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + ALL_BLOCK_SYMBOLS (b, i, sym) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + + return (return_val); +} + +/* A helper function for make_source_files_completion_list. It adds + another file name to a list of possible completions, growing the + list as necessary. */ + +static void +add_filename_to_list (const char *fname, char *text, char *word, + char ***list, int *list_used, int *list_alloced) +{ + char *new; + size_t fnlen = strlen (fname); + + if (*list_used + 1 >= *list_alloced) + { + *list_alloced *= 2; + *list = (char **) xrealloc ((char *) *list, + *list_alloced * sizeof (char *)); + } + + if (word == text) + { + /* Return exactly fname. */ + new = xmalloc (fnlen + 5); + strcpy (new, fname); + } + else if (word > text) + { + /* Return some portion of fname. */ + new = xmalloc (fnlen + 5); + strcpy (new, fname + (word - text)); + } + else + { + /* Return some of TEXT plus fname. */ + new = xmalloc (fnlen + (text - word) + 5); + strncpy (new, word, text - word); + new[text - word] = '\0'; + strcat (new, fname); + } + (*list)[*list_used] = new; + (*list)[++*list_used] = NULL; +} + +static int +not_interesting_fname (const char *fname) +{ + static const char *illegal_aliens[] = { + "_globals_", /* inserted by coff_symtab_read */ + NULL + }; + int i; + + for (i = 0; illegal_aliens[i]; i++) + { + if (strcmp (fname, illegal_aliens[i]) == 0) + return 1; + } + return 0; +} + +/* Return a NULL terminated array of all source files whose names + begin with matching TEXT. The file names are looked up in the + symbol tables of this program. If the answer is no matchess, then + the return value is an array which contains only a NULL pointer. */ + +char ** +make_source_files_completion_list (char *text, char *word) +{ + register struct symtab *s; + register struct partial_symtab *ps; + register struct objfile *objfile; + int first = 1; + int list_alloced = 1; + int list_used = 0; + size_t text_len = strlen (text); + char **list = (char **) xmalloc (list_alloced * sizeof (char *)); + const char *base_name; + + list[0] = NULL; + + if (!have_full_symbols () && !have_partial_symbols ()) + return list; + + ALL_SYMTABS (objfile, s) + { + if (not_interesting_fname (s->filename)) + continue; + if (!filename_seen (s->filename, 1, &first) +#if HAVE_DOS_BASED_FILE_SYSTEM + && strncasecmp (s->filename, text, text_len) == 0 +#else + && strncmp (s->filename, text, text_len) == 0 +#endif + ) { - sym = BLOCK_SYM (b, i); - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + /* This file matches for a completion; add it to the current + list of matches. */ + add_filename_to_list (s->filename, text, word, + &list, &list_used, &list_alloced); + } + else + { + /* NOTE: We allow the user to type a base name when the + debug info records leading directories, but not the other + way around. This is what subroutines of breakpoint + command do when they parse file names. */ + base_name = lbasename (s->filename); + if (base_name != s->filename + && !filename_seen (base_name, 1, &first) +#if HAVE_DOS_BASED_FILE_SYSTEM + && strncasecmp (base_name, text, text_len) == 0 +#else + && strncmp (base_name, text, text_len) == 0 +#endif + ) + add_filename_to_list (base_name, text, word, + &list, &list_used, &list_alloced); } } - ALL_SYMTABS (objfile, s) + ALL_PSYMTABS (objfile, ps) { - QUIT; - b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); - /* Don't do this block twice. */ - if (b == surrounding_static_block) continue; - for (i = 0; i < BLOCK_NSYMS (b); i++) + if (not_interesting_fname (ps->filename)) + continue; + if (!ps->readin) { - sym = BLOCK_SYM (b, i); - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (!filename_seen (ps->filename, 1, &first) +#if HAVE_DOS_BASED_FILE_SYSTEM + && strncasecmp (ps->filename, text, text_len) == 0 +#else + && strncmp (ps->filename, text, text_len) == 0 +#endif + ) + { + /* This file matches for a completion; add it to the + current list of matches. */ + add_filename_to_list (ps->filename, text, word, + &list, &list_used, &list_alloced); + + } + else + { + base_name = lbasename (ps->filename); + if (base_name != ps->filename + && !filename_seen (base_name, 1, &first) +#if HAVE_DOS_BASED_FILE_SYSTEM + && strncasecmp (base_name, text, text_len) == 0 +#else + && strncmp (base_name, text, text_len) == 0 +#endif + ) + add_filename_to_list (base_name, text, word, + &list, &list_used, &list_alloced); + } } } - return (return_val); + return list; } /* Determine if PC is in the prologue of a function. The prologue is the area @@ -4236,51 +3526,69 @@ make_symbol_completion_list (text, word) */ int -in_prologue (pc, func_start) - CORE_ADDR pc; - CORE_ADDR func_start; +in_prologue (CORE_ADDR pc, CORE_ADDR func_start) { -#if 0 struct symtab_and_line sal; CORE_ADDR func_addr, func_end; - if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) - goto nosyms; /* Might be in prologue */ - - sal = find_pc_line (func_addr, 0); - - if (sal.line == 0) - goto nosyms; - - /* sal.end is the address of the first instruction past sal.line. */ - if (sal.end > func_addr - && sal.end <= func_end) /* Is prologue in function? */ - return pc < sal.end; /* Yes, is pc in prologue? */ + /* We have several sources of information we can consult to figure + this out. + - Compilers usually emit line number info that marks the prologue + as its own "source line". So the ending address of that "line" + is the end of the prologue. If available, this is the most + reliable method. + - The minimal symbols and partial symbols, which can usually tell + us the starting and ending addresses of a function. + - If we know the function's start address, we can call the + architecture-defined SKIP_PROLOGUE function to analyze the + instruction stream and guess where the prologue ends. + - Our `func_start' argument; if non-zero, this is the caller's + best guess as to the function's entry point. At the time of + this writing, handle_inferior_event doesn't get this right, so + it should be our last resort. */ - /* The line after the prologue seems to be outside the function. In this - case, tell the caller to find the prologue the hard way. */ + /* Consult the partial symbol table, to find which function + the PC is in. */ + if (! find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + { + CORE_ADDR prologue_end; - return 1; + /* We don't even have minsym information, so fall back to using + func_start, if given. */ + if (! func_start) + return 1; /* We *might* be in a prologue. */ -/* Come here when symtabs don't contain line # info. In this case, it is - likely that the user has stepped into a library function w/o symbols, or - is doing a stepi/nexti through code without symbols. */ + prologue_end = SKIP_PROLOGUE (func_start); - nosyms: -#endif + return func_start <= pc && pc < prologue_end; + } -/* If func_start is zero (meaning unknown) then we don't know whether pc is - in the prologue or not. I.E. it might be. */ + /* If we have line number information for the function, that's + usually pretty reliable. */ + sal = find_pc_line (func_addr, 0); - if (!func_start) return 1; + /* Now sal describes the source line at the function's entry point, + which (by convention) is the prologue. The end of that "line", + sal.end, is the end of the prologue. -/* We need to call the target-specific prologue skipping functions with the - function's start address because PC may be pointing at an instruction that - could be mistakenly considered part of the prologue. */ + Note that, for functions whose source code is all on a single + line, the line number information doesn't always end up this way. + So we must verify that our purported end-of-prologue address is + *within* the function, not at its start or end. */ + if (sal.line == 0 + || sal.end <= func_addr + || func_end <= sal.end) + { + /* We don't have any good line number info, so use the minsym + information, together with the architecture-specific prologue + scanning code. */ + CORE_ADDR prologue_end = SKIP_PROLOGUE (func_addr); - SKIP_PROLOGUE (func_start); + return func_addr <= pc && pc < prologue_end; + } - return pc < func_start; + /* We have line number info, and it looks good. */ + return func_addr <= pc && pc < sal.end; } @@ -4292,19 +3600,17 @@ static int sym_return_val_index; static struct symbol **sym_return_val; /* Test to see if the symbol specified by SYMNAME (which is already - demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN - characters. If so, add it to the current completion list. */ + demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN + characters. If so, add it to the current completion list. */ static void -overload_list_add_symbol (sym, oload_name) - struct symbol * sym; - char * oload_name; +overload_list_add_symbol (struct symbol *sym, char *oload_name) { int newsize; int i; /* Get the demangled name without parameters */ - char * sym_name = cplus_demangle (SYMBOL_NAME (sym), DMGL_ARM | DMGL_ANSI); + char *sym_name = cplus_demangle (SYMBOL_NAME (sym), DMGL_ARM | DMGL_ANSI); if (!sym_name) { sym_name = (char *) xmalloc (strlen (SYMBOL_NAME (sym)) + 1); @@ -4313,7 +3619,10 @@ overload_list_add_symbol (sym, oload_name) /* skip symbols that cannot match */ if (strcmp (sym_name, oload_name) != 0) - return; + { + xfree (sym_name); + return; + } /* If there is no type information, we can't do anything, so skip */ if (SYMBOL_TYPE (sym) == NULL) @@ -4333,8 +3642,8 @@ overload_list_add_symbol (sym, oload_name) } sym_return_val[sym_return_val_index++] = sym; sym_return_val[sym_return_val_index] = NULL; - - free (sym_name); + + xfree (sym_name); } /* Return a null-terminated list of pointers to function symbols that @@ -4344,17 +3653,14 @@ overload_list_add_symbol (sym, oload_name) struct symbol ** -make_symbol_overload_list (fsym) - struct symbol * fsym; +make_symbol_overload_list (struct symbol *fsym) { register struct symbol *sym; register struct symtab *s; register struct partial_symtab *ps; - register struct minimal_symbol *msymbol; register struct objfile *objfile; register struct block *b, *surrounding_static_block = 0; - register int i, j; - struct partial_symbol **psym; + register int i; /* The name we are completing on. */ char *oload_name = NULL; /* Length of name. */ @@ -4377,44 +3683,38 @@ make_symbol_overload_list (fsym) sym_return_val[0] = NULL; /* Look through the partial symtabs for all symbols which begin - by matching OLOAD_NAME. Add each one that you find to the list. */ + by matching OLOAD_NAME. Make sure we read that symbol table in. */ ALL_PSYMTABS (objfile, ps) - { - /* If the psymtab's been read in we'll get it when we search - through the blockvector. */ - if (ps->readin) continue; - - for (psym = objfile->global_psymbols.list + ps->globals_offset; - psym < (objfile->global_psymbols.list + ps->globals_offset - + ps->n_global_syms); - psym++) - { - /* If interrupted, then quit. */ - QUIT; - overload_list_add_symbol (*psym, oload_name); - } - - for (psym = objfile->static_psymbols.list + ps->statics_offset; - psym < (objfile->static_psymbols.list + ps->statics_offset - + ps->n_static_syms); - psym++) - { - QUIT; - overload_list_add_symbol (*psym, oload_name); - } - } + { + struct partial_symbol **psym; - /* At this point scan through the misc symbol vectors and add each - symbol you find to the list. Eventually we want to ignore - anything that isn't a text symbol (everything else will be - handled by the psymtab code above). */ + /* If the psymtab's been read in we'll get it when we search + through the blockvector. */ + if (ps->readin) + continue; - ALL_MSYMBOLS (objfile, msymbol) - { - QUIT; - overload_list_add_symbol (msymbol, oload_name); - } + for (psym = objfile->global_psymbols.list + ps->globals_offset; + psym < (objfile->global_psymbols.list + ps->globals_offset + + ps->n_global_syms); + psym++) + { + /* If interrupted, then quit. */ + QUIT; + /* This will cause the symbol table to be read if it has not yet been */ + s = PSYMTAB_TO_SYMTAB (ps); + } + + for (psym = objfile->static_psymbols.list + ps->statics_offset; + psym < (objfile->static_psymbols.list + ps->statics_offset + + ps->n_static_syms); + psym++) + { + QUIT; + /* This will cause the symbol table to be read if it has not yet been */ + s = PSYMTAB_TO_SYMTAB (ps); + } + } /* Search upwards from currently selected frame (so that we can complete on local vars. */ @@ -4423,15 +3723,14 @@ make_symbol_overload_list (fsym) { if (!BLOCK_SUPERBLOCK (b)) { - surrounding_static_block = b; /* For elimination of dups */ + surrounding_static_block = b; /* For elimination of dups */ } - + /* Also catch fields of types defined in this places which match our - text string. Only complete on types visible from current context. */ + text string. Only complete on types visible from current context. */ - for (i = 0; i < BLOCK_NSYMS (b); i++) + ALL_BLOCK_SYMBOLS (b, i, sym) { - sym = BLOCK_SYM (b, i); overload_list_add_symbol (sym, oload_name); } } @@ -4440,55 +3739,95 @@ make_symbol_overload_list (fsym) symbols which match. */ ALL_SYMTABS (objfile, s) - { - QUIT; - b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); - for (i = 0; i < BLOCK_NSYMS (b); i++) - { - sym = BLOCK_SYM (b, i); - overload_list_add_symbol (sym, oload_name); - } - } + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + ALL_BLOCK_SYMBOLS (b, i, sym) + { + overload_list_add_symbol (sym, oload_name); + } + } ALL_SYMTABS (objfile, s) - { - QUIT; - b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); - /* Don't do this block twice. */ - if (b == surrounding_static_block) continue; - for (i = 0; i < BLOCK_NSYMS (b); i++) - { - sym = BLOCK_SYM (b, i); - overload_list_add_symbol (sym, oload_name); - } - } + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + /* Don't do this block twice. */ + if (b == surrounding_static_block) + continue; + ALL_BLOCK_SYMBOLS (b, i, sym) + { + overload_list_add_symbol (sym, oload_name); + } + } - free (oload_name); + xfree (oload_name); return (sym_return_val); } /* End of overload resolution functions */ - +struct symtabs_and_lines +decode_line_spec (char *string, int funfirstline) +{ + struct symtabs_and_lines sals; + if (string == 0) + error ("Empty line specification."); + sals = decode_line_1 (&string, funfirstline, + current_source_symtab, current_source_line, + (char ***) NULL); + if (*string) + error ("Junk at end of line specification: %s", string); + return sals; +} + +/* Track MAIN */ +static char *name_of_main; + void -_initialize_symtab () +set_main_name (const char *name) +{ + if (name_of_main != NULL) + { + xfree (name_of_main); + name_of_main = NULL; + } + if (name != NULL) + { + name_of_main = xstrdup (name); + } +} + +char * +main_name (void) +{ + if (name_of_main != NULL) + return name_of_main; + else + return "main"; +} + + +void +_initialize_symtab (void) { add_info ("variables", variables_info, - "All global and static variable names, or those matching REGEXP."); + "All global and static variable names, or those matching REGEXP."); if (dbx_commands) - add_com("whereis", class_info, variables_info, - "All global and static variable names, or those matching REGEXP."); + add_com ("whereis", class_info, variables_info, + "All global and static variable names, or those matching REGEXP."); add_info ("functions", functions_info, "All function names, or those matching REGEXP."); + /* FIXME: This command has at least the following problems: 1. It prints builtin types (in a very strange and confusing fashion). 2. It doesn't print right, e.g. with - typedef struct foo *FOO - type_print prints "FOO" when we want to make it (in this situation) - print "struct foo *". + typedef struct foo *FOO + type_print prints "FOO" when we want to make it (in this situation) + print "struct foo *". I also think "ptype" or "whatis" is more likely to be useful (but if there is much disagreement "info types" can be fixed). */ add_info ("types", types_info, @@ -4505,13 +3844,13 @@ are listed."); "Source files in the program."); add_com ("rbreak", class_breakpoint, rbreak_command, - "Set a breakpoint for all functions matching REGEXP."); + "Set a breakpoint for all functions matching REGEXP."); if (xdb_commands) { add_com ("lf", class_info, sources_info, "Source files in the program"); add_com ("lg", class_info, variables_info, - "All global and static variable names, or those matching REGEXP."); + "All global and static variable names, or those matching REGEXP."); } /* Initialize the one built-in type that isn't language dependent... */ diff --git a/contrib/gdb/gdb/thread.c b/contrib/gdb/gdb/thread.c index d07401a..b9c1f02 100644 --- a/contrib/gdb/gdb/thread.c +++ b/contrib/gdb/gdb/thread.c @@ -1,24 +1,26 @@ /* Multi-process/thread control for GDB, the GNU debugger. - Copyright 1986, 1987, 1988, 1993, 1998 + + Copyright 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. - Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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 "symtab.h" @@ -30,190 +32,115 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdbthread.h" #include "command.h" #include "gdbcmd.h" +#include "regcache.h" +#include "gdb.h" #include <ctype.h> #include <sys/types.h> #include <signal.h> +#include "ui-out.h" -/*#include "lynxos-core.h"*/ - -struct thread_info -{ - struct thread_info *next; - int pid; /* Actual process id */ - int num; /* Convenient handle */ - CORE_ADDR prev_pc; /* State from wait_for_inferior */ - CORE_ADDR prev_func_start; - char *prev_func_name; - struct breakpoint *step_resume_breakpoint; - struct breakpoint *through_sigtramp_breakpoint; - CORE_ADDR step_range_start; - CORE_ADDR step_range_end; - CORE_ADDR step_frame_address; - int trap_expected; - int handling_longjmp; - int another_trap; - - /* This is set TRUE when a catchpoint of a shared library event - triggers. Since we don't wish to leave the inferior in the - solib hook when we report the event, we step the inferior - back to user code before stopping and reporting the event. - */ - int stepping_through_solib_after_catch; - - /* When stepping_through_solib_after_catch is TRUE, this is a - list of the catchpoints that should be reported as triggering - when we finally do stop stepping. - */ - bpstat stepping_through_solib_catchpoints; - - /* This is set to TRUE when this thread is in a signal handler - trampoline and we're single-stepping through it */ - int stepping_through_sigtramp; +/*#include "lynxos-core.h" */ -}; +/* Definition of struct thread_info exported to gdbthread.h */ /* Prototypes for exported functions. */ -void _initialize_thread PARAMS ((void)); +void _initialize_thread (void); /* Prototypes for local functions. */ -#if !defined(FIND_NEW_THREADS) -#define FIND_NEW_THREADS target_find_new_threads -#endif - static struct thread_info *thread_list = NULL; static int highest_thread_num; -static struct thread_info * find_thread_id PARAMS ((int num)); +static struct thread_info *find_thread_id (int num); -static void thread_command PARAMS ((char * tidstr, int from_tty)); -static void thread_apply_all_command PARAMS ((char *, int)); -static int thread_alive PARAMS ((struct thread_info *)); -static void info_threads_command PARAMS ((char *, int)); -static void thread_apply_command PARAMS ((char *, int)); -static void restore_current_thread PARAMS ((int)); -static void switch_to_thread PARAMS ((int pid)); -static void prune_threads PARAMS ((void)); +static void thread_command (char *tidstr, int from_tty); +static void thread_apply_all_command (char *, int); +static int thread_alive (struct thread_info *); +static void info_threads_command (char *, int); +static void thread_apply_command (char *, int); +static void restore_current_thread (ptid_t); +static void switch_to_thread (ptid_t ptid); +static void prune_threads (void); -/* If the host has threads, the host machine definition may set this - macro. But, for remote thread debugging, it gets more complex and - setting macros does not bind to the various target dependent - methods well. So, we use the vector target_thread_functions */ - -static struct target_thread_vector *target_thread_functions; - -int -target_find_new_threads () +void +delete_step_resume_breakpoint (void *arg) { - int retval = 0; - if (target_thread_functions && - target_thread_functions->find_new_threads) - retval = (*(target_thread_functions->find_new_threads)) (); - return retval; /* no support */ -} - - -int -target_get_thread_info PARAMS ((gdb_threadref * ref, - int selection, /* FIXME: Selection */ - struct gdb_ext_thread_info * info)); - -int -target_get_thread_info (ref, selection, info) + struct breakpoint **breakpointp = (struct breakpoint **) arg; + struct thread_info *tp; - gdb_threadref *ref; - int selection; - /* FIXME: Selection */ - struct gdb_ext_thread_info *info; + if (*breakpointp != NULL) + { + delete_breakpoint (*breakpointp); + for (tp = thread_list; tp; tp = tp->next) + if (tp->step_resume_breakpoint == *breakpointp) + tp->step_resume_breakpoint = NULL; -{ - int retval = 0; - if (target_thread_functions - && target_thread_functions->get_thread_info) - retval = (*(target_thread_functions->get_thread_info)) (ref, selection, info); - return retval; + *breakpointp = NULL; + } } +static void +free_thread (struct thread_info *tp) +{ + /* NOTE: this will take care of any left-over step_resume breakpoints, + but not any user-specified thread-specific breakpoints. */ + if (tp->step_resume_breakpoint) + delete_breakpoint (tp->step_resume_breakpoint); -/* It is possible that these bind and unbinf functions implement a - stack the interface allows it, but its not implemented that way - */ - + /* FIXME: do I ever need to call the back-end to give it a + chance at this private data before deleting the thread? */ + if (tp->private) + xfree (tp->private); -void -bind_target_thread_vector (vec) - struct target_thread_vector *vec; -{ - target_thread_functions = vec; + xfree (tp); } -struct target_thread_vector * -unbind_target_thread_vector () -{ - struct target_thread_vector *retval; - retval = target_thread_functions; - target_thread_functions = 0; - return retval; -} /* unbind_target_thread-vector */ - void -init_thread_list () +init_thread_list (void) { struct thread_info *tp, *tpnext; + highest_thread_num = 0; if (!thread_list) return; for (tp = thread_list; tp; tp = tpnext) { tpnext = tp->next; - free (tp); + free_thread (tp); } thread_list = NULL; - highest_thread_num = 0; } -void -add_thread (pid) - int pid; +/* add_thread now returns a pointer to the new thread_info, + so that back_ends can initialize their private data. */ + +struct thread_info * +add_thread (ptid_t ptid) { struct thread_info *tp; - tp = (struct thread_info *) xmalloc (sizeof (struct thread_info)); - - tp->pid = pid; + tp = (struct thread_info *) xmalloc (sizeof (*tp)); + memset (tp, 0, sizeof (*tp)); + tp->ptid = ptid; tp->num = ++highest_thread_num; - tp->prev_pc = 0; - tp->prev_func_start = 0; - tp->prev_func_name = NULL; - tp->step_range_start = 0; - tp->step_range_end = 0; - tp->step_frame_address =0; - tp->step_resume_breakpoint = 0; - tp->through_sigtramp_breakpoint = 0; - tp->handling_longjmp = 0; - tp->trap_expected = 0; - tp->another_trap = 0; - tp->stepping_through_solib_after_catch = 0; - tp->stepping_through_solib_catchpoints = NULL; - tp->stepping_through_sigtramp = 0; tp->next = thread_list; thread_list = tp; + return tp; } void -delete_thread (pid) - int pid; +delete_thread (ptid_t ptid) { struct thread_info *tp, *tpprev; tpprev = NULL; for (tp = thread_list; tp; tpprev = tp, tp = tp->next) - if (tp->pid == pid) + if (ptid_equal (tp->ptid, ptid)) break; if (!tp) @@ -224,14 +151,11 @@ delete_thread (pid) else thread_list = tp->next; - free (tp); - - return; + free_thread (tp); } static struct thread_info * -find_thread_id (num) - int num; +find_thread_id (int num) { struct thread_info *tp; @@ -242,9 +166,48 @@ find_thread_id (num) return NULL; } +/* Find a thread_info by matching PTID. */ +struct thread_info * +find_thread_pid (ptid_t ptid) +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (ptid_equal (tp->ptid, ptid)) + return tp; + + return NULL; +} + +/* + * Thread iterator function. + * + * Calls a callback function once for each thread, so long as + * the callback function returns false. If the callback function + * returns true, the iteration will end and the current thread + * will be returned. This can be useful for implementing a + * search for a thread with arbitrary attributes, or for applying + * some operation to every thread. + * + * FIXME: some of the existing functionality, such as + * "Thread apply all", might be rewritten using this functionality. + */ + +struct thread_info * +iterate_over_threads (int (*callback) (struct thread_info *, void *), + void *data) +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if ((*callback) (tp, data)) + return tp; + + return NULL; +} + int -valid_thread_id (num) - int num; +valid_thread_id (int num) { struct thread_info *tp; @@ -256,226 +219,246 @@ valid_thread_id (num) } int -pid_to_thread_id (pid) - int pid; +pid_to_thread_id (ptid_t ptid) { struct thread_info *tp; for (tp = thread_list; tp; tp = tp->next) - if (tp->pid == pid) + if (ptid_equal (tp->ptid, ptid)) return tp->num; return 0; } -int -thread_id_to_pid (num) - int num; +ptid_t +thread_id_to_pid (int num) { struct thread_info *thread = find_thread_id (num); if (thread) - return thread->pid; + return thread->ptid; else - return -1; + return pid_to_ptid (-1); } int -in_thread_list (pid) - int pid; +in_thread_list (ptid_t ptid) { struct thread_info *tp; for (tp = thread_list; tp; tp = tp->next) - if (tp->pid == pid) + if (ptid_equal (tp->ptid, ptid)) return 1; return 0; /* Never heard of 'im */ } +/* Print a list of thread ids currently known, and the total number of + threads. To be used from within catch_errors. */ +static int +do_captured_list_thread_ids (struct ui_out *uiout, + void *arg) +{ + struct thread_info *tp; + int num = 0; + + ui_out_tuple_begin (uiout, "thread-ids"); + + for (tp = thread_list; tp; tp = tp->next) + { + num++; + ui_out_field_int (uiout, "thread-id", tp->num); + } + + ui_out_tuple_end (uiout); + ui_out_field_int (uiout, "number-of-threads", num); + return GDB_RC_OK; +} + +/* Official gdblib interface function to get a list of thread ids and + the total number. */ +enum gdb_rc +gdb_list_thread_ids (struct ui_out *uiout) +{ + return catch_exceptions (uiout, do_captured_list_thread_ids, NULL, + NULL, RETURN_MASK_ALL); +} + /* Load infrun state for the thread PID. */ -void load_infrun_state (pid, prev_pc, prev_func_start, prev_func_name, - trap_expected, step_resume_breakpoint, - through_sigtramp_breakpoint, step_range_start, - step_range_end, step_frame_address, - handling_longjmp, another_trap, - stepping_through_solib_after_catch, - stepping_through_solib_catchpoints, - stepping_through_sigtramp) - int pid; - CORE_ADDR *prev_pc; - CORE_ADDR *prev_func_start; - char **prev_func_name; - int *trap_expected; - struct breakpoint **step_resume_breakpoint; - struct breakpoint **through_sigtramp_breakpoint; - CORE_ADDR *step_range_start; - CORE_ADDR *step_range_end; - CORE_ADDR *step_frame_address; - int *handling_longjmp; - int *another_trap; - int * stepping_through_solib_after_catch; - bpstat * stepping_through_solib_catchpoints; - int * stepping_through_sigtramp; +void +load_infrun_state (ptid_t ptid, + CORE_ADDR *prev_pc, + CORE_ADDR *prev_func_start, + char **prev_func_name, + int *trap_expected, + struct breakpoint **step_resume_breakpoint, + struct breakpoint **through_sigtramp_breakpoint, + CORE_ADDR *step_range_start, + CORE_ADDR *step_range_end, + CORE_ADDR *step_frame_address, + int *handling_longjmp, + int *another_trap, + int *stepping_through_solib_after_catch, + bpstat *stepping_through_solib_catchpoints, + int *stepping_through_sigtramp, + int *current_line, + struct symtab **current_symtab, + CORE_ADDR *step_sp) { struct thread_info *tp; /* If we can't find the thread, then we're debugging a single threaded process. No need to do anything in that case. */ - tp = find_thread_id (pid_to_thread_id (pid)); + tp = find_thread_id (pid_to_thread_id (ptid)); if (tp == NULL) return; *prev_pc = tp->prev_pc; *prev_func_start = tp->prev_func_start; *prev_func_name = tp->prev_func_name; + *trap_expected = tp->trap_expected; *step_resume_breakpoint = tp->step_resume_breakpoint; + *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint; *step_range_start = tp->step_range_start; *step_range_end = tp->step_range_end; *step_frame_address = tp->step_frame_address; - *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint; *handling_longjmp = tp->handling_longjmp; - *trap_expected = tp->trap_expected; *another_trap = tp->another_trap; *stepping_through_solib_after_catch = tp->stepping_through_solib_after_catch; *stepping_through_solib_catchpoints = tp->stepping_through_solib_catchpoints; *stepping_through_sigtramp = tp->stepping_through_sigtramp; + *current_line = tp->current_line; + *current_symtab = tp->current_symtab; + *step_sp = tp->step_sp; } /* Save infrun state for the thread PID. */ -void save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name, - trap_expected, step_resume_breakpoint, - through_sigtramp_breakpoint, step_range_start, - step_range_end, step_frame_address, - handling_longjmp, another_trap, - stepping_through_solib_after_catch, - stepping_through_solib_catchpoints, - stepping_through_sigtramp) - int pid; - CORE_ADDR prev_pc; - CORE_ADDR prev_func_start; - char *prev_func_name; - int trap_expected; - struct breakpoint *step_resume_breakpoint; - struct breakpoint *through_sigtramp_breakpoint; - CORE_ADDR step_range_start; - CORE_ADDR step_range_end; - CORE_ADDR step_frame_address; - int handling_longjmp; - int another_trap; - int stepping_through_solib_after_catch; - bpstat stepping_through_solib_catchpoints; - int stepping_through_sigtramp; +void +save_infrun_state (ptid_t ptid, + CORE_ADDR prev_pc, + CORE_ADDR prev_func_start, + char *prev_func_name, + int trap_expected, + struct breakpoint *step_resume_breakpoint, + struct breakpoint *through_sigtramp_breakpoint, + CORE_ADDR step_range_start, + CORE_ADDR step_range_end, + CORE_ADDR step_frame_address, + int handling_longjmp, + int another_trap, + int stepping_through_solib_after_catch, + bpstat stepping_through_solib_catchpoints, + int stepping_through_sigtramp, + int current_line, + struct symtab *current_symtab, + CORE_ADDR step_sp) { struct thread_info *tp; /* If we can't find the thread, then we're debugging a single-threaded process. Nothing to do in that case. */ - tp = find_thread_id (pid_to_thread_id (pid)); + tp = find_thread_id (pid_to_thread_id (ptid)); if (tp == NULL) return; tp->prev_pc = prev_pc; tp->prev_func_start = prev_func_start; tp->prev_func_name = prev_func_name; + tp->trap_expected = trap_expected; tp->step_resume_breakpoint = step_resume_breakpoint; + tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint; tp->step_range_start = step_range_start; tp->step_range_end = step_range_end; tp->step_frame_address = step_frame_address; - tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint; tp->handling_longjmp = handling_longjmp; - tp->trap_expected = trap_expected; tp->another_trap = another_trap; tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch; tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints; tp->stepping_through_sigtramp = stepping_through_sigtramp; + tp->current_line = current_line; + tp->current_symtab = current_symtab; + tp->step_sp = step_sp; } /* Return true if TP is an active thread. */ static int -thread_alive (tp) - struct thread_info *tp; +thread_alive (struct thread_info *tp) { - if (tp->pid == -1) + if (PIDGET (tp->ptid) == -1) return 0; - if (! target_thread_alive (tp->pid)) + if (!target_thread_alive (tp->ptid)) { - tp->pid = -1; /* Mark it as dead */ + tp->ptid = pid_to_ptid (-1); /* Mark it as dead */ return 0; } return 1; } static void -prune_threads () +prune_threads (void) { - struct thread_info *tp, *tpprev, *next; + struct thread_info *tp, *next; - tpprev = 0; for (tp = thread_list; tp; tp = next) { next = tp->next; if (!thread_alive (tp)) - { - if (tpprev) - tpprev->next = next; - else - thread_list = next; - free (tp); - } - else - tpprev = tp; + delete_thread (tp->ptid); } } /* Print information about currently known threads - * + * Note: this has the drawback that it _really_ switches * threads, which frees the frame cache. A no-side * effects info-threads command would be nicer. */ static void -info_threads_command (arg, from_tty) - char *arg; - int from_tty; +info_threads_command (char *arg, int from_tty) { struct thread_info *tp; - int current_pid; - struct frame_info *cur_frame; - int saved_frame_level = selected_frame_level; - int counter; + ptid_t current_ptid; + struct frame_info *cur_frame; + int saved_frame_level = selected_frame_level; + int counter; + char *extra_info; /* Avoid coredumps which would happen if we tried to access a NULL selected_frame. */ - if (!target_has_stack) error ("No stack."); + if (!target_has_stack) + error ("No stack."); prune_threads (); -#if defined(FIND_NEW_THREADS) - FIND_NEW_THREADS (); -#endif - current_pid = inferior_pid; + target_find_new_threads (); + current_ptid = inferior_ptid; for (tp = thread_list; tp; tp = tp->next) { - if (tp->pid == current_pid) + if (ptid_equal (tp->ptid, current_ptid)) printf_filtered ("* "); else printf_filtered (" "); #ifdef HPUXHPPA - printf_filtered ("%d %s ", tp->num, target_tid_to_str (tp->pid)); + printf_filtered ("%d %s", tp->num, target_tid_to_str (tp->ptid)); #else - printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid)); + printf_filtered ("%d %s", tp->num, target_pid_to_str (tp->ptid)); #endif - switch_to_thread (tp->pid); + + extra_info = target_extra_thread_info (tp); + if (extra_info) + printf_filtered (" (%s)", extra_info); + puts_filtered (" "); + + switch_to_thread (tp->ptid); if (selected_frame) print_only_stack_frame (selected_frame, -1, 0); else printf_filtered ("[No stack.]\n"); } - switch_to_thread (current_pid); + switch_to_thread (current_ptid); /* Code below copied from "up_silently_base" in "stack.c". * It restores the frame set by the user before the "info threads" @@ -483,8 +466,8 @@ info_threads_command (arg, from_tty) * back to the current thread. That switch has put us at the top * of the stack (leaf frame). */ - counter = saved_frame_level; - cur_frame = find_relative_frame(selected_frame, &counter); + counter = saved_frame_level; + cur_frame = find_relative_frame (selected_frame, &counter); if (counter != 0) { /* Ooops, can't restore, tell user where we are. */ @@ -493,99 +476,133 @@ info_threads_command (arg, from_tty) } else { - select_frame(cur_frame, saved_frame_level); + select_frame (cur_frame, saved_frame_level); } /* re-show current frame. */ - show_stack_frame(cur_frame); + show_stack_frame (cur_frame); } /* Switch from one thread to another. */ static void -switch_to_thread (pid) - int pid; +switch_to_thread (ptid_t ptid) { - if (pid == inferior_pid) + if (ptid_equal (ptid, inferior_ptid)) return; - inferior_pid = pid; + inferior_ptid = ptid; flush_cached_frames (); registers_changed (); - stop_pc = read_pc(); + stop_pc = read_pc (); select_frame (get_current_frame (), 0); } static void -restore_current_thread (pid) - int pid; +restore_current_thread (ptid_t ptid) { - if (pid != inferior_pid) + if (! ptid_equal (ptid, inferior_ptid)) { - switch_to_thread (pid); - print_stack_frame( get_current_frame(), 0, -1); + switch_to_thread (ptid); + print_stack_frame (get_current_frame (), 0, -1); } } +struct current_thread_cleanup +{ + ptid_t inferior_ptid; +}; + +static void +do_restore_current_thread_cleanup (void *arg) +{ + struct current_thread_cleanup *old = arg; + restore_current_thread (old->inferior_ptid); + xfree (old); +} + +static struct cleanup * +make_cleanup_restore_current_thread (ptid_t inferior_ptid) +{ + struct current_thread_cleanup *old + = xmalloc (sizeof (struct current_thread_cleanup)); + old->inferior_ptid = inferior_ptid; + return make_cleanup (do_restore_current_thread_cleanup, old); +} + /* Apply a GDB command to a list of threads. List syntax is a whitespace seperated list of numbers, or ranges, or the keyword `all'. Ranges consist of two numbers seperated by a hyphen. Examples: - thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4 - thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9 - thread apply all p x/i $pc Apply x/i $pc cmd to all threads -*/ + thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4 + thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9 + thread apply all p x/i $pc Apply x/i $pc cmd to all threads + */ static void -thread_apply_all_command (cmd, from_tty) - char *cmd; - int from_tty; +thread_apply_all_command (char *cmd, int from_tty) { struct thread_info *tp; struct cleanup *old_chain; + struct cleanup *saved_cmd_cleanup_chain; + char *saved_cmd; if (cmd == NULL || *cmd == '\000') error ("Please specify a command following the thread ID list"); - old_chain = make_cleanup ((make_cleanup_func) restore_current_thread, - (void *)(long) inferior_pid); + old_chain = make_cleanup_restore_current_thread (inferior_ptid); + /* It is safe to update the thread list now, before + traversing it for "thread apply all". MVS */ + target_find_new_threads (); + + /* Save a copy of the command in case it is clobbered by + execute_command */ + saved_cmd = xstrdup (cmd); + saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd); for (tp = thread_list; tp; tp = tp->next) if (thread_alive (tp)) { - switch_to_thread (tp->pid); + switch_to_thread (tp->ptid); #ifdef HPUXHPPA printf_filtered ("\nThread %d (%s):\n", tp->num, - target_tid_to_str (inferior_pid)); + target_tid_to_str (inferior_ptid)); #else printf_filtered ("\nThread %d (%s):\n", tp->num, - target_pid_to_str (inferior_pid)); + target_pid_to_str (inferior_ptid)); #endif execute_command (cmd, from_tty); + strcpy (cmd, saved_cmd); /* Restore exact command used previously */ } + + do_cleanups (saved_cmd_cleanup_chain); + do_cleanups (old_chain); } static void -thread_apply_command (tidlist, from_tty) - char *tidlist; - int from_tty; +thread_apply_command (char *tidlist, int from_tty) { char *cmd; char *p; struct cleanup *old_chain; + struct cleanup *saved_cmd_cleanup_chain; + char *saved_cmd; if (tidlist == NULL || *tidlist == '\000') error ("Please specify a thread ID list"); - for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++); + for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++); if (*cmd == '\000') error ("Please specify a command following the thread ID list"); - old_chain = make_cleanup ((make_cleanup_func) restore_current_thread, - (void *)(long) inferior_pid); + old_chain = make_cleanup_restore_current_thread (inferior_ptid); + /* Save a copy of the command in case it is clobbered by + execute_command */ + saved_cmd = xstrdup (cmd); + saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd); while (tidlist < cmd) { struct thread_info *tp; @@ -601,7 +618,7 @@ thread_apply_command (tidlist, from_tty) if (*tidlist == '-') /* Got a range of IDs? */ { - tidlist++; /* Skip the - */ + tidlist++; /* Skip the - */ end = strtol (tidlist, &p, 10); if (p == tidlist) error ("Error parsing %s", tidlist); @@ -623,82 +640,98 @@ thread_apply_command (tidlist, from_tty) warning ("Thread %d has terminated.", start); else { - switch_to_thread (tp->pid); + switch_to_thread (tp->ptid); #ifdef HPUXHPPA printf_filtered ("\nThread %d (%s):\n", tp->num, - target_tid_to_str (inferior_pid)); + target_tid_to_str (inferior_ptid)); #else printf_filtered ("\nThread %d (%s):\n", tp->num, - target_pid_to_str (inferior_pid)); + target_pid_to_str (inferior_ptid)); #endif execute_command (cmd, from_tty); + strcpy (cmd, saved_cmd); /* Restore exact command used previously */ } } } + + do_cleanups (saved_cmd_cleanup_chain); + do_cleanups (old_chain); } /* Switch to the specified thread. Will dispatch off to thread_apply_command if prefix of arg is `apply'. */ static void -thread_command (tidstr, from_tty) - char *tidstr; - int from_tty; +thread_command (char *tidstr, int from_tty) { - int num; - struct thread_info *tp; - if (!tidstr) { /* Don't generate an error, just say which thread is current. */ if (target_has_stack) printf_filtered ("[Current thread is %d (%s)]\n", - pid_to_thread_id(inferior_pid), + pid_to_thread_id (inferior_ptid), #if defined(HPUXHPPA) - target_tid_to_str(inferior_pid) + target_tid_to_str (inferior_ptid) #else - target_pid_to_str(inferior_pid) + target_pid_to_str (inferior_ptid) #endif - ); + ); else error ("No stack."); return; } - num = atoi (tidstr); + + gdb_thread_select (uiout, tidstr); +} + +static int +do_captured_thread_select (struct ui_out *uiout, + void *tidstr) +{ + int num; + struct thread_info *tp; + + num = value_as_long (parse_and_eval (tidstr)); tp = find_thread_id (num); if (!tp) - error ("Thread ID %d not known. Use the \"info threads\" command to\n\ -see the IDs of currently known threads.", num); + error ("Thread ID %d not known.", num); if (!thread_alive (tp)) error ("Thread ID %d has terminated.\n", num); - switch_to_thread (tp->pid); + switch_to_thread (tp->ptid); - if (context_hook) - context_hook (num); - - printf_filtered ("[Switching to thread %d (%s)]\n", - pid_to_thread_id (inferior_pid), + ui_out_text (uiout, "[Switching to thread "); + ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid)); + ui_out_text (uiout, " ("); #if defined(HPUXHPPA) - target_tid_to_str (inferior_pid) + ui_out_text (uiout, target_tid_to_str (inferior_ptid)); #else - target_pid_to_str (inferior_pid) + ui_out_text (uiout, target_pid_to_str (inferior_ptid)); #endif - ); + ui_out_text (uiout, ")]"); + print_stack_frame (selected_frame, selected_frame_level, 1); + return GDB_RC_OK; +} + +enum gdb_rc +gdb_thread_select (struct ui_out *uiout, + char *tidstr) +{ + return catch_exceptions (uiout, do_captured_thread_select, tidstr, + NULL, RETURN_MASK_ALL); } /* Commands with a prefix of `thread'. */ struct cmd_list_element *thread_cmd_list = NULL; void -_initialize_thread () +_initialize_thread (void) { static struct cmd_list_element *thread_apply_list = NULL; - extern struct cmd_list_element *cmdlist; add_info ("threads", info_threads_command, "IDs of currently known threads."); diff --git a/contrib/gdb/gdb/top.c b/contrib/gdb/gdb/top.c index 90eddb5..972a557 100644 --- a/contrib/gdb/gdb/top.c +++ b/contrib/gdb/gdb/top.c @@ -1,41 +1,49 @@ /* Top level stuff for GDB, the GNU debugger. - Copyright 1986, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 1998 - Free Software Foundation, Inc. -This file is part of GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This file is part of GDB. -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. + 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. -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. */ + 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. -/* $FreeBSD$ */ + 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 "gdbcmd.h" #include "call-cmds.h" +#include "cli/cli-cmds.h" +#include "cli/cli-script.h" +#include "cli/cli-setshow.h" #include "symtab.h" #include "inferior.h" -#include "signals.h" +#include <signal.h> #include "target.h" #include "breakpoint.h" #include "gdbtypes.h" #include "expression.h" #include "value.h" #include "language.h" -#include "terminal.h" /* For job_control. */ +#include "terminal.h" /* For job_control. */ #include "annotate.h" -#include <setjmp.h> +#include "completer.h" #include "top.h" +#include "version.h" +#include "serial.h" +#include "doublest.h" +#include "gdb_assert.h" /* readline include files */ #include <readline/readline.h> @@ -45,114 +53,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #undef savestring #include <sys/types.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif +#include <setjmp.h> + +#include "event-top.h" #include "gdb_string.h" #include "gdb_stat.h" #include <ctype.h> +#include "ui-out.h" +#include "cli-out.h" -extern void initialize_utils PARAMS ((void)); - -/* Prototypes for local functions */ - -static void dont_repeat_command PARAMS ((char *, int)); - -static void source_cleanup_lines PARAMS ((PTR)); - -static void user_defined_command PARAMS ((char *, int)); - -static void init_signals PARAMS ((void)); - -#ifdef STOP_SIGNAL -static void stop_sig PARAMS ((int)); -#endif - -static char * line_completion_function PARAMS ((char *, int, char *, int)); - -static char * readline_line_completion_function PARAMS ((char *, int)); - -static void command_loop_marker PARAMS ((int)); - -static void while_command PARAMS ((char *, int)); - -static void if_command PARAMS ((char *, int)); - -static struct command_line * -build_command_line PARAMS ((enum command_control_type, char *)); - -static struct command_line * -get_command_line PARAMS ((enum command_control_type, char *)); - -static void realloc_body_list PARAMS ((struct command_line *, int)); - -static enum misc_command_type read_next_line PARAMS ((struct command_line **)); - -static enum command_control_type -recurse_read_control_structure PARAMS ((struct command_line *)); - -static struct cleanup * setup_user_args PARAMS ((char *)); - -static char * locate_arg PARAMS ((char *)); - -static char * insert_args PARAMS ((char *)); - -static void arg_cleanup PARAMS ((void)); - -static void init_main PARAMS ((void)); - -static void init_cmd_lists PARAMS ((void)); - -static void float_handler PARAMS ((int)); - -static void init_signals PARAMS ((void)); - -static void set_verbose PARAMS ((char *, int, struct cmd_list_element *)); - -static void show_history PARAMS ((char *, int)); - -static void set_history PARAMS ((char *, int)); +/* Default command line prompt. This is overriden in some configs. */ -static void set_history_size_command PARAMS ((char *, int, - struct cmd_list_element *)); - -static void show_commands PARAMS ((char *, int)); - -static void echo_command PARAMS ((char *, int)); - -static void pwd_command PARAMS ((char *, int)); - -static void show_version PARAMS ((char *, int)); - -static void document_command PARAMS ((char *, int)); - -static void define_command PARAMS ((char *, int)); - -static void validate_comname PARAMS ((char *)); - -static void help_command PARAMS ((char *, int)); - -static void show_command PARAMS ((char *, int)); - -static void info_command PARAMS ((char *, int)); - -static void complete_command PARAMS ((char *, int)); - -static void do_nothing PARAMS ((int)); - -#ifdef SIGHUP -static int quit_cover PARAMS ((PTR)); - -static void disconnect PARAMS ((int)); -#endif - -static void source_cleanup PARAMS ((FILE *)); - -/* If this definition isn't overridden by the header files, assume - that isatty and fileno exist on this system. */ -#ifndef ISATTY -#define ISATTY(FP) (isatty (fileno (FP))) +#ifndef DEFAULT_PROMPT +#define DEFAULT_PROMPT "(gdb) " #endif /* Initialization file name for gdb. This is overridden in some configs. */ @@ -169,107 +83,11 @@ int inhibit_gdbinit = 0; int use_windows = 1; -/* Version number of GDB, as a string. */ - -extern char *version; - -/* Canonical host name as a string. */ - -extern char *host_name; - -/* Canonical target name as a string. */ - -extern char *target_name; - extern char lang_frame_mismatch_warn[]; /* language.c */ /* Flag for whether we want all the "from_tty" gubbish printed. */ -int caution = 1; /* Default is yes, sigh. */ - -/* Define all cmd_list_elements. */ - -/* Chain containing all defined commands. */ - -struct cmd_list_element *cmdlist; - -/* Chain containing all defined info subcommands. */ - -struct cmd_list_element *infolist; - -/* Chain containing all defined enable subcommands. */ - -struct cmd_list_element *enablelist; - -/* Chain containing all defined disable subcommands. */ - -struct cmd_list_element *disablelist; - -/* Chain containing all defined toggle subcommands. */ - -struct cmd_list_element *togglelist; - -/* Chain containing all defined stop subcommands. */ - -struct cmd_list_element *stoplist; - -/* Chain containing all defined delete subcommands. */ - -struct cmd_list_element *deletelist; - -/* Chain containing all defined "enable breakpoint" subcommands. */ - -struct cmd_list_element *enablebreaklist; - -/* Chain containing all defined set subcommands */ - -struct cmd_list_element *setlist; - -/* Chain containing all defined unset subcommands */ - -struct cmd_list_element *unsetlist; - -/* Chain containing all defined show subcommands. */ - -struct cmd_list_element *showlist; - -/* Chain containing all defined \"set history\". */ - -struct cmd_list_element *sethistlist; - -/* Chain containing all defined \"show history\". */ - -struct cmd_list_element *showhistlist; - -/* Chain containing all defined \"unset history\". */ - -struct cmd_list_element *unsethistlist; - -/* Chain containing all defined maintenance subcommands. */ - -#if MAINTENANCE_CMDS -struct cmd_list_element *maintenancelist; -#endif - -/* Chain containing all defined "maintenance info" subcommands. */ - -#if MAINTENANCE_CMDS -struct cmd_list_element *maintenanceinfolist; -#endif - -/* Chain containing all defined "maintenance print" subcommands. */ - -#if MAINTENANCE_CMDS -struct cmd_list_element *maintenanceprintlist; -#endif - -struct cmd_list_element *setprintlist; - -struct cmd_list_element *showprintlist; - -struct cmd_list_element *setchecklist; - -struct cmd_list_element *showchecklist; +int caution = 1; /* Default is yes, sigh. */ /* stdio stream that command input is being read from. Set to stdin normally. Set by source_command to the file we are sourcing. Set to NULL if we are @@ -288,13 +106,13 @@ char gdb_dirbuf[1024]; The function receives two args: an input stream, and a prompt string. */ -void (*window_hook) PARAMS ((FILE *, char *)); +void (*window_hook) (FILE *, char *); int epoch_interface; int xgdb_verbose; /* gdb prints this when reading a command interactively */ -static char *prompt; +static char *gdb_prompt_string; /* the global prompt string */ /* Buffer used for reading command lines, and the size allocated for it so far. */ @@ -303,7 +121,7 @@ char *line; int linesize = 100; /* Nonzero if the current command is modified by "server ". This - affects things like recording into the command history, comamnds + affects things like recording into the command history, commands repeating on RETURN, etc. This is so a user interface (emacs, GUI, whatever) can issue its own commands and also send along commands from the user, and have the user not notice that the user interface @@ -319,90 +137,81 @@ int baud_rate = -1; /* Timeout limit for response from target. */ -int remote_timeout = 1; /* Set default to 1 second */ +/* The default value has been changed many times over the years. It + was originally 5 seconds. But that was thought to be a long time + to sit and wait, so it was changed to 2 seconds. That was thought + to be plenty unless the connection was going through some terminal + server or multiplexer or other form of hairy serial connection. + + In mid-1996, remote_timeout was moved from remote.c to top.c and + it began being used in other remote-* targets. It appears that the + default was changed to 20 seconds at that time, perhaps because the + Hitachi E7000 ICE didn't always respond in a timely manner. + + But if 5 seconds is a long time to sit and wait for retransmissions, + 20 seconds is far worse. This demonstrates the difficulty of using + a single variable for all protocol timeouts. + + As remote.c is used much more than remote-e7000.c, it was changed + back to 2 seconds in 1999. */ + +int remote_timeout = 2; /* Non-zero tells remote* modules to output debugging info. */ int remote_debug = 0; +/* Non-zero means the target is running. Note: this is different from + saying that there is an active target and we are stopped at a + breakpoint, for instance. This is a real indicator whether the + target is off and running, which gdb is doing something else. */ +int target_executing = 0; + /* Level of control structure. */ static int control_level; -/* Structure for arguments to user defined functions. */ -#define MAXUSERARGS 10 -struct user_args -{ - struct user_args *next; - struct - { - char *arg; - int len; - } a[MAXUSERARGS]; - int count; -} *user_args; - /* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */ #ifndef STOP_SIGNAL #ifdef SIGTSTP #define STOP_SIGNAL SIGTSTP -static void stop_sig PARAMS ((int)); -#endif -#endif - -/* Some System V have job control but not sigsetmask(). */ -#if !defined (HAVE_SIGSETMASK) -#if !defined (USG) -#define HAVE_SIGSETMASK 1 -#else -#define HAVE_SIGSETMASK 0 +static void stop_sig (int); #endif #endif -#if 0 == (HAVE_SIGSETMASK) -#define sigsetmask(n) -#endif - /* Hooks for alternate command interfaces. */ /* Called after most modules have been initialized, but before taking users - command file. */ - -void (*init_ui_hook) PARAMS ((char *argv0)); -#ifdef __CYGWIN32__ -void (*ui_loop_hook) PARAMS ((int)); -#endif + command file. -/* Called instead of command_loop at top level. Can be invoked via - return_to_top_level. */ + If the UI fails to initialize and it wants GDB to continue + using the default UI, then it should clear this hook before returning. */ -void (*command_loop_hook) PARAMS ((void)); +void (*init_ui_hook) (char *argv0); +/* This hook is called from within gdb's many mini-event loops which could + steal control from a real user interface's event loop. It returns + non-zero if the user is requesting a detach, zero otherwise. */ -/* Called instead of fputs for all output. */ +int (*ui_loop_hook) (int); -void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, GDB_FILE *stream)); +/* Called instead of command_loop at top level. Can be invoked via + throw_exception(). */ -/* Called when the target says something to the host, which may - want to appear in a different window. */ +void (*command_loop_hook) (void); -void (*target_output_hook) PARAMS ((char *)); /* Called from print_frame_info to list the line we stopped in. */ -void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, int line, - int stopline, int noerror)); +void (*print_frame_info_listing_hook) (struct symtab * s, int line, + int stopline, int noerror); /* Replaces most of query. */ -int (*query_hook) PARAMS ((const char *, va_list)); +int (*query_hook) (const char *, va_list); /* Replaces most of warning. */ -void (*warning_hook) PARAMS ((const char *, va_list)); - -/* Called from gdb_flush to flush output. */ - -void (*flush_hook) PARAMS ((GDB_FILE *stream)); +void (*warning_hook) (const char *, va_list); /* These three functions support getting lines of text from the user. They are used in sequence. First readline_begin_hook is called with a text @@ -415,77 +224,101 @@ void (*flush_hook) PARAMS ((GDB_FILE *stream)); to notify the GUI that we are done with the interaction window and it can close it. */ -void (*readline_begin_hook) PARAMS ((char *, ...)); -char * (*readline_hook) PARAMS ((char *)); -void (*readline_end_hook) PARAMS ((void)); +void (*readline_begin_hook) (char *, ...); +char *(*readline_hook) (char *); +void (*readline_end_hook) (void); /* Called as appropriate to notify the interface of the specified breakpoint conditions. */ -void (*create_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); -void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); -void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); +void (*create_breakpoint_hook) (struct breakpoint * bpt); +void (*delete_breakpoint_hook) (struct breakpoint * bpt); +void (*modify_breakpoint_hook) (struct breakpoint * bpt); + +/* Called as appropriate to notify the interface that we have attached + to or detached from an already running process. */ + +void (*attach_hook) (void); +void (*detach_hook) (void); /* Called during long calculations to allow GUI to repair window damage, and to check for stop buttons, etc... */ -void (*interactive_hook) PARAMS ((void)); +void (*interactive_hook) (void); /* Called when the registers have changed, as a hint to a GUI to minimize window update. */ -void (*registers_changed_hook) PARAMS ((void)); +void (*registers_changed_hook) (void); /* Tell the GUI someone changed the register REGNO. -1 means that the caller does not know which register changed or - that several registers have changed (see value_assign).*/ -void (*register_changed_hook) PARAMS ((int regno)); + that several registers have changed (see value_assign). */ +void (*register_changed_hook) (int regno); /* Tell the GUI someone changed LEN bytes of memory at ADDR */ -void (*memory_changed_hook) PARAMS ((CORE_ADDR addr, int len)); +void (*memory_changed_hook) (CORE_ADDR addr, int len); /* Called when going to wait for the target. Usually allows the GUI to run while waiting for target events. */ -int (*target_wait_hook) PARAMS ((int pid, struct target_waitstatus *status)); +ptid_t (*target_wait_hook) (ptid_t ptid, + struct target_waitstatus * status); /* Used by UI as a wrapper around command execution. May do various things like enabling/disabling buttons, etc... */ -void (*call_command_hook) PARAMS ((struct cmd_list_element *c, char *cmd, - int from_tty)); +void (*call_command_hook) (struct cmd_list_element * c, char *cmd, + int from_tty); + +/* Called after a `set' command has finished. Is only run if the + `set' command succeeded. */ + +void (*set_hook) (struct cmd_list_element * c); /* Called when the current thread changes. Argument is thread id. */ -void (*context_hook) PARAMS ((int id)); +void (*context_hook) (int id); /* Takes control from error (). Typically used to prevent longjmps out of the middle of the GUI. Usually used in conjunction with a catch routine. */ -NORETURN void (*error_hook) PARAMS ((void)) ATTR_NORETURN; - +NORETURN void (*error_hook) (void) ATTR_NORETURN; -/* Where to go for return_to_top_level (RETURN_ERROR). */ -SIGJMP_BUF error_return; -/* Where to go for return_to_top_level (RETURN_QUIT). */ -SIGJMP_BUF quit_return; -/* Return for reason REASON. This generally gets back to the command - loop, but can be caught via catch_errors. */ +/* One should use catch_errors rather than manipulating these + directly. */ +#if defined(HAVE_SIGSETJMP) +#define SIGJMP_BUF sigjmp_buf +#define SIGSETJMP(buf) sigsetjmp((buf), 1) +#define SIGLONGJMP(buf,val) siglongjmp((buf), (val)) +#else +#define SIGJMP_BUF jmp_buf +#define SIGSETJMP(buf) setjmp(buf) +#define SIGLONGJMP(buf,val) longjmp((buf), (val)) +#endif + +/* Where to go for throw_exception(). */ +static SIGJMP_BUF *catch_return; + +/* Return for reason REASON to the nearest containing catch_errors(). */ NORETURN void -return_to_top_level (reason) - enum return_reason reason; +throw_exception (enum return_reason reason) { quit_flag = 0; immediate_quit = 0; /* Perhaps it would be cleaner to do this via the cleanup chain (not sure I can think of a reason why that is vital, though). */ - bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */ + bpstat_clear_actions (stop_bpstat); /* Clear queued breakpoint commands */ disable_current_display (); do_cleanups (ALL_CLEANUPS); + if (event_loop_p && target_can_async_p () && !target_executing) + do_exec_cleanups (ALL_CLEANUPS); + if (event_loop_p && sync_execution) + do_exec_error_cleanups (ALL_CLEANUPS); if (annotation_level > 1) switch (reason) @@ -498,14 +331,18 @@ return_to_top_level (reason) break; } - (NORETURN void) SIGLONGJMP - (reason == RETURN_ERROR ? error_return : quit_return, 1); + /* Jump to the containing catch_errors() call, communicating REASON + to that call via setjmp's return value. Note that REASON can't + be zero, by definition in defs.h. */ + + (NORETURN void) SIGLONGJMP (*catch_return, (int) reason); } -/* Call FUNC with arg ARGS, catching any errors. If there is no - error, return the value returned by FUNC. If there is an error, - print ERRSTRING, print the specific error message, then return - zero. +/* Call FUNC() with args FUNC_UIOUT and FUNC_ARGS, catching any + errors. Set FUNC_CAUGHT to an ``enum return_reason'' if the + function is aborted (using throw_exception() or zero if the + function returns normally. Set FUNC_VAL to the value returned by + the function or 0 if the function was aborted. Must not be called with immediate_quit in effect (bad things might happen, say we got a signal in the middle of a memcpy to quit_return). @@ -521,709 +358,287 @@ return_to_top_level (reason) catch_errors. Note that quit should return to the command line fairly quickly, even if some further processing is being done. */ -int -catch_errors (func, args, errstring, mask) - catch_errors_ftype *func; - PTR args; - char *errstring; - return_mask mask; -{ - SIGJMP_BUF saved_error; - SIGJMP_BUF saved_quit; - SIGJMP_BUF tmp_jmp; - int val; +/* MAYBE: cagney/1999-11-05: catch_errors() in conjunction with + error() et.al. could maintain a set of flags that indicate the the + current state of each of the longjmp buffers. This would give the + longjmp code the chance to detect a longjmp botch (before it gets + to longjmperror()). Prior to 1999-11-05 this wasn't possible as + code also randomly used a SET_TOP_LEVEL macro that directly + initialize the longjmp buffers. */ + +/* MAYBE: cagney/1999-11-05: Should the catch_errors and cleanups code + be consolidated into a single file instead of being distributed + between utils.c and top.c? */ + +static void +catcher (catch_exceptions_ftype *func, + struct ui_out *func_uiout, + void *func_args, + int *func_val, + enum return_reason *func_caught, + char *errstring, + return_mask mask) +{ + SIGJMP_BUF *saved_catch; + SIGJMP_BUF catch; struct cleanup *saved_cleanup_chain; char *saved_error_pre_print; char *saved_quit_pre_print; + struct ui_out *saved_uiout; - saved_cleanup_chain = save_cleanups (); - saved_error_pre_print = error_pre_print; - saved_quit_pre_print = quit_pre_print; + /* Return value from SIGSETJMP(): enum return_reason if error or + quit caught, 0 otherwise. */ + int caught; - if (mask & RETURN_MASK_ERROR) - { - memcpy ((char *)saved_error, (char *)error_return, sizeof (SIGJMP_BUF)); - error_pre_print = errstring; - } - if (mask & RETURN_MASK_QUIT) - { - memcpy (saved_quit, quit_return, sizeof (SIGJMP_BUF)); - quit_pre_print = errstring; - } + /* Return value from FUNC(): Hopefully non-zero. Explicitly set to + zero if an error quit was caught. */ + int val; - if (SIGSETJMP (tmp_jmp) == 0) - { - if (mask & RETURN_MASK_ERROR) - memcpy (error_return, tmp_jmp, sizeof (SIGJMP_BUF)); - if (mask & RETURN_MASK_QUIT) - memcpy (quit_return, tmp_jmp, sizeof (SIGJMP_BUF)); - val = (*func) (args); - } - else - val = 0; + /* Override error/quit messages during FUNC. */ - restore_cleanups (saved_cleanup_chain); + saved_error_pre_print = error_pre_print; + saved_quit_pre_print = quit_pre_print; if (mask & RETURN_MASK_ERROR) - { - memcpy (error_return, saved_error, sizeof (SIGJMP_BUF)); - error_pre_print = saved_error_pre_print; - } + error_pre_print = errstring; if (mask & RETURN_MASK_QUIT) - { - memcpy (quit_return, saved_quit, sizeof (SIGJMP_BUF)); - quit_pre_print = saved_quit_pre_print; - } - return val; -} - -/* Handler for SIGHUP. */ - -#ifdef SIGHUP -static void -disconnect (signo) -int signo; -{ - catch_errors (quit_cover, NULL, - "Could not kill the program being debugged", RETURN_MASK_ALL); - signal (SIGHUP, SIG_DFL); - kill (getpid (), SIGHUP); -} - -/* Just a little helper function for disconnect(). */ - -static int -quit_cover (s) - PTR s; -{ - caution = 0; /* Throw caution to the wind -- we're exiting. - This prevents asking the user dumb questions. */ - quit_command((char *)0, 0); - return 0; -} -#endif /* defined SIGHUP */ - -/* Line number we are currently in in a file which is being sourced. */ -static int source_line_number; + quit_pre_print = errstring; -/* Name of the file we are sourcing. */ -static char *source_file_name; + /* Override the global ``struct ui_out'' builder. */ -/* Buffer containing the error_pre_print used by the source stuff. - Malloc'd. */ -static char *source_error; -static int source_error_allocated; + saved_uiout = uiout; + uiout = func_uiout; -/* Something to glom on to the start of error_pre_print if source_file_name - is set. */ -static char *source_pre_error; + /* Prevent error/quit during FUNC from calling cleanups established + prior to here. */ -/* Clean up on error during a "source" command (or execution of a - user-defined command). */ + saved_cleanup_chain = save_cleanups (); -static void -source_cleanup (stream) - FILE *stream; -{ - /* Restore the previous input stream. */ - instream = stream; -} + /* Call FUNC, catching error/quit events. */ -/* Read commands from STREAM. */ -void -read_command_file (stream) - FILE *stream; -{ - struct cleanup *cleanups; + saved_catch = catch_return; + catch_return = &catch; + caught = SIGSETJMP (catch); + if (!caught) + val = (*func) (func_uiout, func_args); + else + val = 0; + catch_return = saved_catch; - cleanups = make_cleanup ((make_cleanup_func) source_cleanup, instream); - instream = stream; - command_loop (); - do_cleanups (cleanups); -} - -extern void init_proc PARAMS ((void)); + /* FIXME: cagney/1999-11-05: A correct FUNC implementation will + clean things up (restoring the cleanup chain) to the state they + were just prior to the call. Unfortunately, many FUNC's are not + that well behaved. This could be fixed by adding either a + do_cleanups call (to cover the problem) or an assertion check to + detect bad FUNCs code. */ -void (*pre_init_ui_hook) PARAMS ((void)); + /* Restore the cleanup chain, the error/quit messages, and the uiout + builder, to their original states. */ -void -gdb_init (argv0) - char *argv0; -{ - if (pre_init_ui_hook) - pre_init_ui_hook (); + restore_cleanups (saved_cleanup_chain); - /* Run the init function of each source file */ + uiout = saved_uiout; - getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); - current_directory = gdb_dirbuf; + if (mask & RETURN_MASK_QUIT) + quit_pre_print = saved_quit_pre_print; + if (mask & RETURN_MASK_ERROR) + error_pre_print = saved_error_pre_print; - init_cmd_lists (); /* This needs to be done first */ - initialize_targets (); /* Setup target_terminal macros for utils.c */ - initialize_utils (); /* Make errors and warnings possible */ - initialize_all_files (); - init_main (); /* But that omits this file! Do it now */ - init_signals (); + /* Return normally if no error/quit event occurred or this catcher + can handle this exception. The caller analyses the func return + values. */ - init_proc (); + if (!caught || (mask & RETURN_MASK (caught))) + { + *func_val = val; + *func_caught = caught; + return; + } - /* We need a default language for parsing expressions, so simple things like - "set width 0" won't fail if no language is explicitly set in a config file - or implicitly set by reading an executable during startup. */ - set_language (language_c); - expected_language = current_language; /* don't warn about the change. */ + /* The caller didn't request that the event be caught, relay the + event to the next containing catch_errors(). */ - if (init_ui_hook) - init_ui_hook (argv0); + throw_exception (caught); } -/* Allocate, initialize a new command line structure for one of the - control commands (if/while). */ - -static struct command_line * -build_command_line (type, args) - enum command_control_type type; - char *args; +int +catch_exceptions (struct ui_out *uiout, + catch_exceptions_ftype *func, + void *func_args, + char *errstring, + return_mask mask) { - struct command_line *cmd; - - if (args == NULL) - error ("if/while commands require arguments.\n"); - - cmd = (struct command_line *)xmalloc (sizeof (struct command_line)); - cmd->next = NULL; - cmd->control_type = type; - - cmd->body_count = 1; - cmd->body_list - = (struct command_line **)xmalloc (sizeof (struct command_line *) - * cmd->body_count); - memset (cmd->body_list, 0, sizeof (struct command_line *) * cmd->body_count); - cmd->line = savestring (args, strlen (args)); - return cmd; + int val; + enum return_reason caught; + catcher (func, uiout, func_args, &val, &caught, errstring, mask); + gdb_assert (val >= 0); + gdb_assert (caught <= 0); + if (caught < 0) + return caught; + return val; } -/* Build and return a new command structure for the control commands - such as "if" and "while". */ - -static struct command_line * -get_command_line (type, arg) - enum command_control_type type; - char *arg; +struct catch_errors_args { - struct command_line *cmd; - struct cleanup *old_chain = NULL; - - /* Allocate and build a new command line structure. */ - cmd = build_command_line (type, arg); - - old_chain = make_cleanup ((make_cleanup_func) free_command_lines, &cmd); - - /* Read in the body of this command. */ - if (recurse_read_control_structure (cmd) == invalid_control) - { - warning ("error reading in control structure\n"); - do_cleanups (old_chain); - return NULL; - } - - discard_cleanups (old_chain); - return cmd; -} + catch_errors_ftype *func; + void *func_args; +}; -/* Recursively print a command (including full control structures). */ -void -print_command_line (cmd, depth) - struct command_line *cmd; - unsigned int depth; +int +do_catch_errors (struct ui_out *uiout, void *data) { - unsigned int i; - - if (depth) - { - for (i = 0; i < depth; i++) - fputs_filtered (" ", gdb_stdout); - } - - /* A simple command, print it and return. */ - if (cmd->control_type == simple_control) - { - fputs_filtered (cmd->line, gdb_stdout); - fputs_filtered ("\n", gdb_stdout); - return; - } - - /* loop_continue to jump to the start of a while loop, print it - and return. */ - if (cmd->control_type == continue_control) - { - fputs_filtered ("loop_continue\n", gdb_stdout); - return; - } - - /* loop_break to break out of a while loop, print it and return. */ - if (cmd->control_type == break_control) - { - fputs_filtered ("loop_break\n", gdb_stdout); - return; - } - - /* A while command. Recursively print its subcommands before returning. */ - if (cmd->control_type == while_control) - { - struct command_line *list; - fputs_filtered ("while ", gdb_stdout); - fputs_filtered (cmd->line, gdb_stdout); - fputs_filtered ("\n", gdb_stdout); - list = *cmd->body_list; - while (list) - { - print_command_line (list, depth + 1); - list = list->next; - } - } - - /* An if command. Recursively print both arms before returning. */ - if (cmd->control_type == if_control) - { - fputs_filtered ("if ", gdb_stdout); - fputs_filtered (cmd->line, gdb_stdout); - fputs_filtered ("\n", gdb_stdout); - /* The true arm. */ - print_command_line (cmd->body_list[0], depth + 1); - - /* Show the false arm if it exists. */ - if (cmd->body_count == 2) - { - if (depth) - { - for (i = 0; i < depth; i++) - fputs_filtered (" ", gdb_stdout); - } - fputs_filtered ("else\n", gdb_stdout); - print_command_line (cmd->body_list[1], depth + 1); - } - if (depth) - { - for (i = 0; i < depth; i++) - fputs_filtered (" ", gdb_stdout); - } - fputs_filtered ("end\n", gdb_stdout); - } + struct catch_errors_args *args = data; + return args->func (args->func_args); } -/* Execute the command in CMD. */ - -enum command_control_type -execute_control_command (cmd) - struct command_line *cmd; +int +catch_errors (catch_errors_ftype *func, void *func_args, char *errstring, + return_mask mask) { - struct expression *expr; - struct command_line *current; - struct cleanup *old_chain = 0; - value_ptr val; - value_ptr val_mark; - int loop; - enum command_control_type ret; - char *new_line; - - switch (cmd->control_type) - { - case simple_control: - /* A simple command, execute it and return. */ - new_line = insert_args (cmd->line); - if (!new_line) - return invalid_control; - old_chain = make_cleanup ((make_cleanup_func) free_current_contents, - &new_line); - execute_command (new_line, 0); - ret = cmd->control_type; - break; - - case continue_control: - case break_control: - /* Return for "continue", and "break" so we can either - continue the loop at the top, or break out. */ - ret = cmd->control_type; - break; - - case while_control: - { - /* Parse the loop control expression for the while statement. */ - new_line = insert_args (cmd->line); - if (!new_line) - return invalid_control; - old_chain = make_cleanup ((make_cleanup_func) free_current_contents, - &new_line); - expr = parse_expression (new_line); - make_cleanup ((make_cleanup_func) free_current_contents, &expr); - - ret = simple_control; - loop = 1; - - /* Keep iterating so long as the expression is true. */ - while (loop == 1) - { - int cond_result; - - QUIT; - - /* Evaluate the expression. */ - val_mark = value_mark (); - val = evaluate_expression (expr); - cond_result = value_true (val); - value_free_to_mark (val_mark); - - /* If the value is false, then break out of the loop. */ - if (!cond_result) - break; - - /* Execute the body of the while statement. */ - current = *cmd->body_list; - while (current) - { - ret = execute_control_command (current); - - /* If we got an error, or a "break" command, then stop - looping. */ - if (ret == invalid_control || ret == break_control) - { - loop = 0; - break; - } - - /* If we got a "continue" command, then restart the loop - at this point. */ - if (ret == continue_control) - break; - - /* Get the next statement. */ - current = current->next; - } - } - - /* Reset RET so that we don't recurse the break all the way down. */ - if (ret == break_control) - ret = simple_control; - - break; - } - - case if_control: - { - new_line = insert_args (cmd->line); - if (!new_line) - return invalid_control; - old_chain = make_cleanup ((make_cleanup_func) free_current_contents, - &new_line); - /* Parse the conditional for the if statement. */ - expr = parse_expression (new_line); - make_cleanup ((make_cleanup_func) free_current_contents, &expr); - - current = NULL; - ret = simple_control; - - /* Evaluate the conditional. */ - val_mark = value_mark (); - val = evaluate_expression (expr); - - /* Choose which arm to take commands from based on the value of the - conditional expression. */ - if (value_true (val)) - current = *cmd->body_list; - else if (cmd->body_count == 2) - current = *(cmd->body_list + 1); - value_free_to_mark (val_mark); - - /* Execute commands in the given arm. */ - while (current) - { - ret = execute_control_command (current); - - /* If we got an error, get out. */ - if (ret != simple_control) - break; - - /* Get the next statement in the body. */ - current = current->next; - } - - break; - } - - default: - warning ("Invalid control type in command structure."); - return invalid_control; - } + int val; + enum return_reason caught; + struct catch_errors_args args; + args.func = func; + args.func_args = func_args; + catcher (do_catch_errors, uiout, &args, &val, &caught, errstring, mask); + if (caught != 0) + return 0; + return val; +} - if (old_chain) - do_cleanups (old_chain); +struct captured_command_args + { + catch_command_errors_ftype *command; + char *arg; + int from_tty; + }; - return ret; +static int +do_captured_command (void *data) +{ + struct captured_command_args *context = data; + context->command (context->arg, context->from_tty); + /* FIXME: cagney/1999-11-07: Technically this do_cleanups() call + isn't needed. Instead an assertion check could be made that + simply confirmed that the called function correctly cleaned up + after itself. Unfortunately, old code (prior to 1999-11-04) in + main.c was calling SET_TOP_LEVEL(), calling the command function, + and then *always* calling do_cleanups(). For the moment we + remain ``bug compatible'' with that old code.. */ + do_cleanups (ALL_CLEANUPS); + return 1; } -/* "while" command support. Executes a body of statements while the - loop condition is nonzero. */ - -static void -while_command (arg, from_tty) - char *arg; - int from_tty; +int +catch_command_errors (catch_command_errors_ftype * command, + char *arg, int from_tty, return_mask mask) { - struct command_line *command = NULL; - - control_level = 1; - command = get_command_line (while_control, arg); - - if (command == NULL) - return; - - execute_control_command (command); - free_command_lines (&command); + struct captured_command_args args; + args.command = command; + args.arg = arg; + args.from_tty = from_tty; + return catch_errors (do_captured_command, &args, "", mask); } -/* "if" command support. Execute either the true or false arm depending - on the value of the if conditional. */ -static void -if_command (arg, from_tty) - char *arg; - int from_tty; -{ - struct command_line *command = NULL; - - control_level = 1; - command = get_command_line (if_control, arg); +/* Handler for SIGHUP. */ - if (command == NULL) - return; +#ifdef SIGHUP +/* Just a little helper function for disconnect(). */ - execute_control_command (command); - free_command_lines (&command); +/* NOTE 1999-04-29: This function will be static again, once we modify + gdb to use the event loop as the default command loop and we merge + event-top.c into this file, top.c */ +/* static */ int +quit_cover (void *s) +{ + caution = 0; /* Throw caution to the wind -- we're exiting. + This prevents asking the user dumb questions. */ + quit_command ((char *) 0, 0); + return 0; } -/* Cleanup */ static void -arg_cleanup () +disconnect (int signo) { - struct user_args *oargs = user_args; - if (!user_args) - fatal ("Internal error, arg_cleanup called with no user args.\n"); - - user_args = user_args->next; - free (oargs); + catch_errors (quit_cover, NULL, + "Could not kill the program being debugged", RETURN_MASK_ALL); + signal (SIGHUP, SIG_DFL); + kill (getpid (), SIGHUP); } +#endif /* defined SIGHUP */ + +/* Line number we are currently in in a file which is being sourced. */ +/* NOTE 1999-04-29: This variable will be static again, once we modify + gdb to use the event loop as the default command loop and we merge + event-top.c into this file, top.c */ +/* static */ int source_line_number; -/* Bind the incomming arguments for a user defined command to - $arg0, $arg1 ... $argMAXUSERARGS. */ - -static struct cleanup * -setup_user_args (p) - char *p; -{ - struct user_args *args; - struct cleanup *old_chain; - unsigned int arg_count = 0; - - args = (struct user_args *)xmalloc (sizeof (struct user_args)); - memset (args, 0, sizeof (struct user_args)); - - args->next = user_args; - user_args = args; - - old_chain = make_cleanup ((make_cleanup_func) arg_cleanup, 0); - - if (p == NULL) - return old_chain; - - while (*p) - { - char *start_arg; - int squote = 0; - int dquote = 0; - int bsquote = 0; - - if (arg_count >= MAXUSERARGS) - { - error ("user defined function may only have %d arguments.\n", - MAXUSERARGS); - return old_chain; - } - - /* Strip whitespace. */ - while (*p == ' ' || *p == '\t') - p++; - - /* P now points to an argument. */ - start_arg = p; - user_args->a[arg_count].arg = p; +/* Name of the file we are sourcing. */ +/* NOTE 1999-04-29: This variable will be static again, once we modify + gdb to use the event loop as the default command loop and we merge + event-top.c into this file, top.c */ +/* static */ char *source_file_name; - /* Get to the end of this argument. */ - while (*p) - { - if (((*p == ' ' || *p == '\t')) && !squote && !dquote && !bsquote) - break; - else - { - if (bsquote) - bsquote = 0; - else if (*p == '\\') - bsquote = 1; - else if (squote) - { - if (*p == '\'') - squote = 0; - } - else if (dquote) - { - if (*p == '"') - dquote = 0; - } - else - { - if (*p == '\'') - squote = 1; - else if (*p == '"') - dquote = 1; - } - p++; - } - } +/* Buffer containing the error_pre_print used by the source stuff. + Malloc'd. */ +/* NOTE 1999-04-29: This variable will be static again, once we modify + gdb to use the event loop as the default command loop and we merge + event-top.c into this file, top.c */ +/* static */ char *source_error; +static int source_error_allocated; - user_args->a[arg_count].len = p - start_arg; - arg_count++; - user_args->count++; - } - return old_chain; -} +/* Something to glom on to the start of error_pre_print if source_file_name + is set. */ +/* NOTE 1999-04-29: This variable will be static again, once we modify + gdb to use the event loop as the default command loop and we merge + event-top.c into this file, top.c */ +/* static */ char *source_pre_error; -/* Given character string P, return a point to the first argument ($arg), - or NULL if P contains no arguments. */ +/* Clean up on error during a "source" command (or execution of a + user-defined command). */ -static char * -locate_arg (p) - char *p; +void +do_restore_instream_cleanup (void *stream) { - while ((p = strchr (p, '$'))) - { - if (strncmp (p, "$arg", 4) == 0 && isdigit (p[4])) - return p; - p++; - } - return NULL; + /* Restore the previous input stream. */ + instream = stream; } -/* Insert the user defined arguments stored in user_arg into the $arg - arguments found in line, with the updated copy being placed into nline. */ - -static char * -insert_args (line) - char *line; +/* Read commands from STREAM. */ +void +read_command_file (FILE *stream) { - char *p, *save_line, *new_line; - unsigned len, i; - - /* First we need to know how much memory to allocate for the new line. */ - save_line = line; - len = 0; - while ((p = locate_arg (line))) - { - len += p - line; - i = p[4] - '0'; - - if (i >= user_args->count) - { - error ("Missing argument %d in user function.\n", i); - return NULL; - } - len += user_args->a[i].len; - line = p + 5; - } - - /* Don't forget the tail. */ - len += strlen (line); - - /* Allocate space for the new line and fill it in. */ - new_line = (char *)xmalloc (len + 1); - if (new_line == NULL) - return NULL; - - /* Restore pointer to beginning of old line. */ - line = save_line; - - /* Save pointer to beginning of new line. */ - save_line = new_line; - - while ((p = locate_arg (line))) - { - int i, len; - - memcpy (new_line, line, p - line); - new_line += p - line; - i = p[4] - '0'; - - len = user_args->a[i].len; - if (len) - { - memcpy (new_line, user_args->a[i].arg, len); - new_line += len; - } - line = p + 5; - } - /* Don't forget the tail. */ - strcpy (new_line, line); + struct cleanup *cleanups; - /* Return a pointer to the beginning of the new line. */ - return save_line; + cleanups = make_cleanup (do_restore_instream_cleanup, instream); + instream = stream; + command_loop (); + do_cleanups (cleanups); } + +void (*pre_init_ui_hook) (void); +#ifdef __MSDOS__ void -execute_user_command (c, args) - struct cmd_list_element *c; - char *args; +do_chdir_cleanup (void *old_dir) { - register struct command_line *cmdlines; - struct cleanup *old_chain; - enum command_control_type ret; - - old_chain = setup_user_args (args); - - cmdlines = c->user_commands; - if (cmdlines == 0) - /* Null command */ - return; - - /* Set the instream to 0, indicating execution of a - user-defined function. */ - old_chain = make_cleanup ((make_cleanup_func) source_cleanup, instream); - instream = (FILE *) 0; - while (cmdlines) - { - ret = execute_control_command (cmdlines); - if (ret != simple_control && ret != break_control) - { - warning ("Error in control structure.\n"); - break; - } - cmdlines = cmdlines->next; - } - do_cleanups (old_chain); + chdir (old_dir); + xfree (old_dir); } +#endif /* Execute the line P as a command. Pass FROM_TTY as second argument to the defining function. */ void -execute_command (p, from_tty) - char *p; - int from_tty; +execute_command (char *p, int from_tty) { register struct cmd_list_element *c; register enum language flang; static int warned = 0; - /* FIXME: These should really be in an appropriate header file */ - extern void serial_log_command PARAMS ((const char *)); - + char *line; + free_all_values (); /* Force cleanup of any alloca areas if using C alloca instead of @@ -1232,21 +647,44 @@ execute_command (p, from_tty) /* This can happen when command_line_input hits end of file. */ if (p == NULL) - return; + return; serial_log_command (p); - while (*p == ' ' || *p == '\t') p++; + while (*p == ' ' || *p == '\t') + p++; if (*p) { char *arg; + line = p; c = lookup_cmd (&p, cmdlist, "", 0, 1); + + /* If the target is running, we allow only a limited set of + commands. */ + if (event_loop_p && target_can_async_p () && target_executing) + if (!strcmp (c->name, "help") + && !strcmp (c->name, "pwd") + && !strcmp (c->name, "show") + && !strcmp (c->name, "stop")) + error ("Cannot execute this command while the target is running."); + /* Pass null arg rather than an empty one. */ arg = *p ? p : 0; - /* Clear off trailing whitespace, except for set and complete command. */ - if (arg && c->type != set_cmd && c->function.cfunc != complete_command) + /* FIXME: cagney/2002-02-02: The c->type test is pretty dodgy + while the is_complete_command(cfunc) test is just plain + bogus. They should both be replaced by a test of the form + c->strip_trailing_white_space_p. */ + /* NOTE: cagney/2002-02-02: The function.cfunc in the below + can't be replaced with func. This is because it is the + cfunc, and not the func, that has the value that the + is_complete_command hack is testing for. */ + /* Clear off trailing whitespace, except for set and complete + command. */ + if (arg + && c->type != set_cmd + && !is_complete_command (c)) { p = arg + strlen (arg) - 1; while (p >= arg && (*p == ' ' || *p == '\t')) @@ -1254,30 +692,47 @@ execute_command (p, from_tty) *(p + 1) = '\0'; } - /* If this command has been hooked, run the hook first. */ - if (c->hook) - execute_user_command (c->hook, (char *)0); + /* If this command has been pre-hooked, run the hook first. */ + if ((c->hook_pre) && (!c->hook_in)) + { + c->hook_in = 1; /* Prevent recursive hooking */ + execute_user_command (c->hook_pre, (char *) 0); + c->hook_in = 0; /* Allow hook to work again once it is complete */ + } + + if (c->flags & DEPRECATED_WARN_USER) + deprecated_cmd_warning (&line); if (c->class == class_user) execute_user_command (c, arg); else if (c->type == set_cmd || c->type == show_cmd) do_setshow_command (arg, from_tty & caution, c); - else if (c->function.cfunc == NO_FUNCTION) + else if (c->func == NULL) error ("That is not a command, just a help topic."); else if (call_command_hook) call_command_hook (c, arg, from_tty & caution); else - (*c->function.cfunc) (arg, from_tty & caution); - } + (*c->func) (c, arg, from_tty & caution); + + /* If this command has been post-hooked, run the hook last. */ + if ((c->hook_post) && (!c->hook_in)) + { + c->hook_in = 1; /* Prevent recursive hooking */ + execute_user_command (c->hook_post, (char *) 0); + c->hook_in = 0; /* allow hook to work again once it is complete */ + } + + } /* Tell the user if the language has changed (except first time). */ if (current_language != expected_language) - { - if (language_mode == language_mode_auto) { - language_info (1); /* Print what changed. */ + { + if (language_mode == language_mode_auto) + { + language_info (1); /* Print what changed. */ + } + warned = 0; } - warned = 0; - } /* Warn the user if the working language does not match the language of the current frame. Only warn the user if we are @@ -1298,18 +753,11 @@ execute_command (p, from_tty) } } -/* ARGSUSED */ -static void -command_loop_marker (foo) - int foo; -{ -} - /* Read commands from `instream' and execute them until end of file or error reading instream. */ void -command_loop () +command_loop (void) { struct cleanup *old_chain; char *command; @@ -1323,32 +771,18 @@ command_loop () while (instream && !feof (instream)) { -#if defined(TUI) - extern int insert_mode; -#endif if (window_hook && instream == stdin) - (*window_hook) (instream, prompt); + (*window_hook) (instream, get_prompt ()); quit_flag = 0; if (instream == stdin && stdin_is_tty) reinitialize_more_filter (); - old_chain = make_cleanup ((make_cleanup_func) command_loop_marker, 0); - -#if defined(TUI) - /* A bit of paranoia: I want to make sure the "insert_mode" global - * is clear except when it is being used for command-line editing - * (see tuiIO.c, utils.c); otherwise normal output will - * get messed up in the TUI. So clear it before/after - * the command-line-input call. - RT - */ - insert_mode = 0; -#endif + old_chain = make_cleanup (null_cleanup, 0); + /* Get a command-line. This calls the readline package. */ - command = command_line_input (instream == stdin ? prompt : (char *) NULL, + command = command_line_input (instream == stdin ? + get_prompt () : (char *) NULL, instream == stdin, "prompt"); -#if defined(TUI) - insert_mode = 0; -#endif if (command == 0) return; @@ -1393,11 +827,46 @@ command_loop () } } } + +/* Read commands from `instream' and execute them until end of file or + error reading instream. This command loop doesnt care about any + such things as displaying time and space usage. If the user asks + for those, they won't work. */ +void +simplified_command_loop (char *(*read_input_func) (char *), + void (*execute_command_func) (char *, int)) +{ + struct cleanup *old_chain; + char *command; + int stdin_is_tty = ISATTY (stdin); + + while (instream && !feof (instream)) + { + quit_flag = 0; + if (instream == stdin && stdin_is_tty) + reinitialize_more_filter (); + old_chain = make_cleanup (null_cleanup, 0); + + /* Get a command-line. */ + command = (*read_input_func) (instream == stdin ? + get_prompt () : (char *) NULL); + + if (command == 0) + return; + + (*execute_command_func) (command, instream == stdin); + + /* Do any commands attached to breakpoint we stopped at. */ + bpstat_do_actions (&stop_bpstat); + + do_cleanups (old_chain); + } +} /* Commands call this if they do not want to be repeated by null lines. */ void -dont_repeat () +dont_repeat (void) { if (server_command) return; @@ -1411,31 +880,25 @@ dont_repeat () /* Read a line from the stream "instream" without command line editing. - It prints PRROMPT once at the start. + It prints PROMPT_ARG once at the start. Action is compatible with "readline", e.g. space for the result is malloc'd and should be freed by the caller. A NULL return means end of file. */ char * -gdb_readline (prrompt) - char *prrompt; +gdb_readline (char *prompt_arg) { int c; char *result; int input_index = 0; int result_size = 80; - if (prrompt) + if (prompt_arg) { /* Don't use a _filtered function here. It causes the assumed - character position to be off, since the newline we read from - the user is not accounted for. */ - fputs_unfiltered (prrompt, gdb_stdout); -#ifdef MPW - /* Move to a new line so the entered line doesn't have a prompt - on the front of it. */ - fputs_unfiltered ("\n", gdb_stdout); -#endif /* MPW */ + character position to be off, since the newline we read from + the user is not accounted for. */ + fputs_unfiltered (prompt_arg, gdb_stdout); gdb_flush (gdb_stdout); } @@ -1444,7 +907,7 @@ gdb_readline (prrompt) while (1) { /* Read from stdin if we are executing a user defined command. - This is the right thing for prompt_for_continue, at least. */ + This is the right thing for prompt_for_continue, at least. */ c = fgetc (instream ? instream : stdin); if (c == EOF) @@ -1454,7 +917,7 @@ gdb_readline (prrompt) if we are called again fgetc will still return EOF and we'll return NULL then. */ break; - free (result); + xfree (result); return NULL; } @@ -1485,457 +948,37 @@ gdb_readline (prrompt) substitution. These variables are given default values at the end of this file. */ static int command_editing_p; -static int history_expansion_p; +/* NOTE 1999-04-29: This variable will be static again, once we modify + gdb to use the event loop as the default command loop and we merge + event-top.c into this file, top.c */ +/* static */ int history_expansion_p; static int write_history_p; static int history_size; static char *history_filename; -/* readline uses the word breaks for two things: - (1) In figuring out where to point the TEXT parameter to the - rl_completion_entry_function. Since we don't use TEXT for much, - it doesn't matter a lot what the word breaks are for this purpose, but - it does affect how much stuff M-? lists. - (2) If one of the matches contains a word break character, readline - will quote it. That's why we switch between - gdb_completer_word_break_characters and - gdb_completer_command_word_break_characters. I'm not sure when - we need this behavior (perhaps for funky characters in C++ symbols?). */ - -/* Variables which are necessary for fancy command line editing. */ -char *gdb_completer_word_break_characters = - " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-"; - -/* When completing on command names, we remove '-' from the list of - word break characters, since we use it in command names. If the - readline library sees one in any of the current completion strings, - it thinks that the string needs to be quoted and automatically supplies - a leading quote. */ -char *gdb_completer_command_word_break_characters = - " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,"; - -/* Characters that can be used to quote completion strings. Note that we - can't include '"' because the gdb C parser treats such quoted sequences - as strings. */ -char *gdb_completer_quote_characters = - "'"; - -/* Functions that are used as part of the fancy command line editing. */ - -/* This can be used for functions which don't want to complete on symbols - but don't want to complete on anything else either. */ -/* ARGSUSED */ -char ** -noop_completer (text, prefix) - char *text; - char *prefix; -{ - return NULL; -} - -/* Complete on filenames. */ -char ** -filename_completer (text, word) - char *text; - char *word; -{ - int subsequent_name; - char **return_val; - int return_val_used; - int return_val_alloced; - - return_val_used = 0; - /* Small for testing. */ - return_val_alloced = 1; - return_val = (char **) xmalloc (return_val_alloced * sizeof (char *)); - - subsequent_name = 0; - while (1) - { - char *p; - p = filename_completion_function (text, subsequent_name); - if (return_val_used >= return_val_alloced) - { - return_val_alloced *= 2; - return_val = - (char **) xrealloc (return_val, - return_val_alloced * sizeof (char *)); - } - if (p == NULL) - { - return_val[return_val_used++] = p; - break; - } - /* Like emacs, don't complete on old versions. Especially useful - in the "source" command. */ - if (p[strlen (p) - 1] == '~') - continue; - - { - char *q; - if (word == text) - /* Return exactly p. */ - return_val[return_val_used++] = p; - else if (word > text) - { - /* Return some portion of p. */ - q = xmalloc (strlen (p) + 5); - strcpy (q, p + (word - text)); - return_val[return_val_used++] = q; - free (p); - } - else - { - /* Return some of TEXT plus p. */ - q = xmalloc (strlen (p) + (text - word) + 5); - strncpy (q, word, text - word); - q[text - word] = '\0'; - strcat (q, p); - return_val[return_val_used++] = q; - free (p); - } - } - subsequent_name = 1; - } -#if 0 - /* There is no way to do this just long enough to affect quote inserting - without also affecting the next completion. This should be fixed in - readline. FIXME. */ - /* Insure that readline does the right thing - with respect to inserting quotes. */ - rl_completer_word_break_characters = ""; -#endif - return return_val; -} - -/* Here are some useful test cases for completion. FIXME: These should - be put in the test suite. They should be tested with both M-? and TAB. - - "show output-" "radix" - "show output" "-radix" - "p" ambiguous (commands starting with p--path, print, printf, etc.) - "p " ambiguous (all symbols) - "info t foo" no completions - "info t " no completions - "info t" ambiguous ("info target", "info terminal", etc.) - "info ajksdlfk" no completions - "info ajksdlfk " no completions - "info" " " - "info " ambiguous (all info commands) - "p \"a" no completions (string constant) - "p 'a" ambiguous (all symbols starting with a) - "p b-a" ambiguous (all symbols starting with a) - "p b-" ambiguous (all symbols) - "file Make" "file" (word break hard to screw up here) - "file ../gdb.stabs/we" "ird" (needs to not break word at slash) - */ - -/* Generate completions one by one for the completer. Each time we are - called return another potential completion to the caller. - line_completion just completes on commands or passes the buck to the - command's completer function, the stuff specific to symbol completion - is in make_symbol_completion_list. - - TEXT is the caller's idea of the "word" we are looking at. - - MATCHES is the number of matches that have currently been collected from - calling this completion function. When zero, then we need to initialize, - otherwise the initialization has already taken place and we can just - return the next potential completion string. - - LINE_BUFFER is available to be looked at; it contains the entire text - of the line. POINT is the offset in that line of the cursor. You - should pretend that the line ends at POINT. - - Returns NULL if there are no more completions, else a pointer to a string - which is a possible completion, it is the caller's responsibility to - free the string. */ - -static char * -line_completion_function (text, matches, line_buffer, point) - char *text; - int matches; - char *line_buffer; - int point; -{ - static char **list = (char **)NULL; /* Cache of completions */ - static int index; /* Next cached completion */ - char *output = NULL; - char *tmp_command, *p; - /* Pointer within tmp_command which corresponds to text. */ - char *word; - struct cmd_list_element *c, *result_list; - - if (matches == 0) - { - /* The caller is beginning to accumulate a new set of completions, so - we need to find all of them now, and cache them for returning one at - a time on future calls. */ - - if (list) - { - /* Free the storage used by LIST, but not by the strings inside. - This is because rl_complete_internal () frees the strings. */ - free ((PTR)list); - } - list = 0; - index = 0; - - /* Choose the default set of word break characters to break completions. - If we later find out that we are doing completions on command strings - (as opposed to strings supplied by the individual command completer - functions, which can be any string) then we will switch to the - special word break set for command strings, which leaves out the - '-' character used in some commands. */ - - rl_completer_word_break_characters = - gdb_completer_word_break_characters; - - /* Decide whether to complete on a list of gdb commands or on symbols. */ - tmp_command = (char *) alloca (point + 1); - p = tmp_command; - - strncpy (tmp_command, line_buffer, point); - tmp_command[point] = '\0'; - /* Since text always contains some number of characters leading up - to point, we can find the equivalent position in tmp_command - by subtracting that many characters from the end of tmp_command. */ - word = tmp_command + point - strlen (text); - - if (point == 0) - { - /* An empty line we want to consider ambiguous; that is, it - could be any command. */ - c = (struct cmd_list_element *) -1; - result_list = 0; - } - else - { - c = lookup_cmd_1 (&p, cmdlist, &result_list, 1); - } - - /* Move p up to the next interesting thing. */ - while (*p == ' ' || *p == '\t') - { - p++; - } - - if (!c) - { - /* It is an unrecognized command. So there are no - possible completions. */ - list = NULL; - } - else if (c == (struct cmd_list_element *) -1) - { - char *q; - - /* lookup_cmd_1 advances p up to the first ambiguous thing, but - doesn't advance over that thing itself. Do so now. */ - q = p; - while (*q && (isalnum (*q) || *q == '-' || *q == '_')) - ++q; - if (q != tmp_command + point) - { - /* There is something beyond the ambiguous - command, so there are no possible completions. For - example, "info t " or "info t foo" does not complete - to anything, because "info t" can be "info target" or - "info terminal". */ - list = NULL; - } - else - { - /* We're trying to complete on the command which was ambiguous. - This we can deal with. */ - if (result_list) - { - list = complete_on_cmdlist (*result_list->prefixlist, p, - word); - } - else - { - list = complete_on_cmdlist (cmdlist, p, word); - } - /* Insure that readline does the right thing with respect to - inserting quotes. */ - rl_completer_word_break_characters = - gdb_completer_command_word_break_characters; - } - } - else - { - /* We've recognized a full command. */ - - if (p == tmp_command + point) - { - /* There is no non-whitespace in the line beyond the command. */ - - if (p[-1] == ' ' || p[-1] == '\t') - { - /* The command is followed by whitespace; we need to complete - on whatever comes after command. */ - if (c->prefixlist) - { - /* It is a prefix command; what comes after it is - a subcommand (e.g. "info "). */ - list = complete_on_cmdlist (*c->prefixlist, p, word); - - /* Insure that readline does the right thing - with respect to inserting quotes. */ - rl_completer_word_break_characters = - gdb_completer_command_word_break_characters; - } - else if (c->enums) - { - list = complete_on_enum (c->enums, p, word); - rl_completer_word_break_characters = - gdb_completer_command_word_break_characters; - } - else - { - /* It is a normal command; what comes after it is - completed by the command's completer function. */ - list = (*c->completer) (p, word); - } - } - else - { - /* The command is not followed by whitespace; we need to - complete on the command itself. e.g. "p" which is a - command itself but also can complete to "print", "ptype" - etc. */ - char *q; - - /* Find the command we are completing on. */ - q = p; - while (q > tmp_command) - { - if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_') - --q; - else - break; - } - - list = complete_on_cmdlist (result_list, q, word); - - /* Insure that readline does the right thing - with respect to inserting quotes. */ - rl_completer_word_break_characters = - gdb_completer_command_word_break_characters; - } - } - else - { - /* There is non-whitespace beyond the command. */ - - if (c->prefixlist && !c->allow_unknown) - { - /* It is an unrecognized subcommand of a prefix command, - e.g. "info adsfkdj". */ - list = NULL; - } - else if (c->enums) - { - list = complete_on_enum (c->enums, p, word); - } - else - { - /* It is a normal command. */ - list = (*c->completer) (p, word); - } - } - } - } - - /* If we found a list of potential completions during initialization then - dole them out one at a time. The vector of completions is NULL - terminated, so after returning the last one, return NULL (and continue - to do so) each time we are called after that, until a new list is - available. */ - - if (list) - { - output = list[index]; - if (output) - { - index++; - } - } - -#if 0 - /* Can't do this because readline hasn't yet checked the word breaks - for figuring out whether to insert a quote. */ - if (output == NULL) - /* Make sure the word break characters are set back to normal for the - next time that readline tries to complete something. */ - rl_completer_word_break_characters = - gdb_completer_word_break_characters; -#endif - - return (output); -} - -/* Line completion interface function for readline. */ - -static char * -readline_line_completion_function (text, matches) - char *text; - int matches; -{ - return line_completion_function (text, matches, rl_line_buffer, rl_point); -} - -/* Skip over a possibly quoted word (as defined by the quote characters - and word break characters the completer uses). Returns pointer to the - location after the "word". */ - -char * -skip_quoted (str) - char *str; -{ - char quote_char = '\0'; - char *scan; - - for (scan = str; *scan != '\0'; scan++) - { - if (quote_char != '\0') - { - /* Ignore everything until the matching close quote char */ - if (*scan == quote_char) - { - /* Found matching close quote. */ - scan++; - break; - } - } - else if (strchr (gdb_completer_quote_characters, *scan)) - { - /* Found start of a quoted string. */ - quote_char = *scan; - } - else if (strchr (gdb_completer_word_break_characters, *scan)) - { - break; - } - } - return (scan); -} - #ifdef STOP_SIGNAL static void -stop_sig (signo) -int signo; +stop_sig (int signo) { #if STOP_SIGNAL == SIGTSTP signal (SIGTSTP, SIG_DFL); +#if HAVE_SIGPROCMASK + { + sigset_t zero; + + sigemptyset (&zero); + sigprocmask (SIG_SETMASK, &zero, 0); + } +#elif HAVE_SIGSETMASK sigsetmask (0); +#endif kill (getpid (), SIGTSTP); signal (SIGTSTP, stop_sig); #else signal (STOP_SIGNAL, stop_sig); #endif - printf_unfiltered ("%s", prompt); + printf_unfiltered ("%s", get_prompt ()); gdb_flush (gdb_stdout); /* Forget about any previous command -- null line now will do nothing. */ @@ -1945,8 +988,16 @@ int signo; /* Initialize signal handlers. */ static void -do_nothing (signo) -int signo; +float_handler (int signo) +{ + /* This message is based on ANSI C, section 4.7. Note that integer + divide by zero causes this, so "float" is a misnomer. */ + signal (SIGFPE, float_handler); + error ("Erroneous arithmetic operation."); +} + +static void +do_nothing (int signo) { /* Under System V the default disposition of a signal is reinstated after the signal is caught and delivered to an application process. On such @@ -1958,7 +1009,7 @@ int signo; } static void -init_signals () +init_signals (void) { signal (SIGINT, request_quit); @@ -1988,6 +1039,52 @@ init_signals () #endif } +/* The current saved history number from operate-and-get-next. + This is -1 if not valid. */ +static int operate_saved_history = -1; + +/* This is put on the appropriate hook and helps operate-and-get-next + do its work. */ +void +gdb_rl_operate_and_get_next_completion () +{ + int delta = where_history () - operate_saved_history; + /* The `key' argument to rl_get_previous_history is ignored. */ + rl_get_previous_history (delta, 0); + operate_saved_history = -1; + + /* readline doesn't automatically update the display for us. */ + rl_redisplay (); + + after_char_processing_hook = NULL; + rl_pre_input_hook = NULL; +} + +/* This is a gdb-local readline command handler. It accepts the + current command line (like RET does) and, if this command was taken + from the history, arranges for the next command in the history to + appear on the command line when the prompt returns. + We ignore the arguments. */ +static int +gdb_rl_operate_and_get_next (int count, int key) +{ + if (event_loop_p) + { + /* Use the async hook. */ + after_char_processing_hook = gdb_rl_operate_and_get_next_completion; + } + else + { + /* This hook only works correctly when we are using the + synchronous readline. */ + rl_pre_input_hook = (Function *) gdb_rl_operate_and_get_next_completion; + } + + /* Add 1 because we eventually want the next line. */ + operate_saved_history = where_history () + 1; + return rl_newline (1, key); +} + /* Read one line from the command input stream `instream' into the local static buffer `linebuffer' (whose current length is `linelength'). @@ -2004,17 +1101,14 @@ init_signals () simple input as the user has requested. */ char * -command_line_input (prrompt, repeat, annotation_suffix) - char *prrompt; - int repeat; - char *annotation_suffix; +command_line_input (char *prompt_arg, int repeat, char *annotation_suffix) { static char *linebuffer = 0; static unsigned linelength = 0; register char *p; char *p1; char *rl; - char *local_prompt = prrompt; + char *local_prompt = prompt_arg; char *nline; char got_eof = 0; @@ -2024,12 +1118,12 @@ command_line_input (prrompt, repeat, annotation_suffix) if (annotation_level > 1 && instream == stdin) { - local_prompt = alloca ((prrompt == NULL ? 0 : strlen (prrompt)) + local_prompt = alloca ((prompt_arg == NULL ? 0 : strlen (prompt_arg)) + strlen (annotation_suffix) + 40); - if (prrompt == NULL) + if (prompt_arg == NULL) local_prompt[0] = '\0'; else - strcpy (local_prompt, prrompt); + strcpy (local_prompt, prompt_arg); strcat (local_prompt, "\n\032\032"); strcat (local_prompt, annotation_suffix); strcat (local_prompt, "\n"); @@ -2048,13 +1142,18 @@ command_line_input (prrompt, repeat, annotation_suffix) immediate_quit++; #ifdef STOP_SIGNAL if (job_control) - signal (STOP_SIGNAL, stop_sig); + { + if (event_loop_p) + signal (STOP_SIGNAL, handle_stop_sig); + else + signal (STOP_SIGNAL, stop_sig); + } #endif while (1) { /* Make sure that all output has been output. Some machines may let - you get away with leaving out some of the gdb_flush, but not all. */ + you get away with leaving out some of the gdb_flush, but not all. */ wrap_here (""); gdb_flush (gdb_stdout); gdb_flush (gdb_stderr); @@ -2103,9 +1202,9 @@ command_line_input (prrompt, repeat, annotation_suffix) got_eof = 1; break; } - if (strlen(rl) + 1 + (p - linebuffer) > linelength) + if (strlen (rl) + 1 + (p - linebuffer) > linelength) { - linelength = strlen(rl) + 1 + (p - linebuffer); + linelength = strlen (rl) + 1 + (p - linebuffer); nline = (char *) xrealloc (linebuffer, linelength); p += nline - linebuffer; linebuffer = nline; @@ -2116,14 +1215,14 @@ command_line_input (prrompt, repeat, annotation_suffix) while (*p1) *p++ = *p1++; - free (rl); /* Allocated in readline. */ + xfree (rl); /* Allocated in readline. */ if (p == linebuffer || *(p - 1) != '\\') break; p--; /* Put on top of '\'. */ local_prompt = (char *) 0; - } + } #ifdef STOP_SIGNAL if (job_control) @@ -2137,12 +1236,12 @@ command_line_input (prrompt, repeat, annotation_suffix) #define SERVER_COMMAND_LENGTH 7 server_command = (p - linebuffer > SERVER_COMMAND_LENGTH) - && STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH); + && STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH); if (server_command) { /* Note that we don't set `line'. Between this and the check in - dont_repeat, this insures that repeating will still do the - right thing. */ + dont_repeat, this insures that repeating will still do the + right thing. */ *p = '\0'; return linebuffer + SERVER_COMMAND_LENGTH; } @@ -2164,8 +1263,8 @@ command_line_input (prrompt, repeat, annotation_suffix) /* If there was an error, call this function again. */ if (expanded < 0) { - free (history_value); - return command_line_input (prrompt, repeat, annotation_suffix); + xfree (history_value); + return command_line_input (prompt_arg, repeat, annotation_suffix); } if (strlen (history_value) > linelength) { @@ -2173,8 +1272,8 @@ command_line_input (prrompt, repeat, annotation_suffix) linebuffer = (char *) xrealloc (linebuffer, linelength); } strcpy (linebuffer, history_value); - p = linebuffer + strlen(linebuffer); - free (history_value); + p = linebuffer + strlen (linebuffer); + xfree (history_value); } } @@ -2183,7 +1282,7 @@ command_line_input (prrompt, repeat, annotation_suffix) global buffer. */ if (repeat && p == linebuffer) return line; - for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++) ; + for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++); if (repeat && !*p1) return line; @@ -2201,7 +1300,7 @@ command_line_input (prrompt, repeat, annotation_suffix) and remove the '#'. The kill ring is probably better, but some people are in the habit of commenting things out. */ if (*p1 == '#') - *p1 = '\0'; /* Found a comment. */ + *p1 = '\0'; /* Found a comment. */ /* Save into global buffer if appropriate. */ if (repeat) @@ -2218,717 +1317,338 @@ command_line_input (prrompt, repeat, annotation_suffix) return linebuffer; } - -/* Expand the body_list of COMMAND so that it can hold NEW_LENGTH - code bodies. This is typically used when we encounter an "else" - clause for an "if" command. */ - -static void -realloc_body_list (command, new_length) - struct command_line *command; - int new_length; +/* Print the GDB banner. */ +void +print_gdb_version (struct ui_file *stream) { - int n; - struct command_line **body_list; - - n = command->body_count; - - /* Nothing to do? */ - if (new_length <= n) - return; + /* From GNU coding standards, first line is meant to be easy for a + program to parse, and is just canonical program name and version + number, which starts after last space. */ - body_list = (struct command_line **) - xmalloc (sizeof (struct command_line *) * new_length); + fprintf_filtered (stream, "GNU gdb %s\n", version); - memcpy (body_list, command->body_list, sizeof (struct command_line *) * n); + /* Second line is a copyright notice. */ - free (command->body_list); - command->body_list = body_list; - command->body_count = new_length; -} + fprintf_filtered (stream, "Copyright 2002 Free Software Foundation, Inc.\n"); -/* Read one line from the input stream. If the command is an "else" or - "end", return such an indication to the caller. */ + /* Following the copyright is a brief statement that the program is + free software, that users are free to copy and change it on + certain conditions, that it is covered by the GNU GPL, and that + there is no warranty. */ -static enum misc_command_type -read_next_line (command) - struct command_line **command; -{ - char *p, *p1, *prompt_ptr, control_prompt[256]; - int i = 0; + fprintf_filtered (stream, "\ +GDB is free software, covered by the GNU General Public License, and you are\n\ +welcome to change it and/or distribute copies of it under certain conditions.\n\ +Type \"show copying\" to see the conditions.\n\ +There is absolutely no warranty for GDB. Type \"show warranty\" for details.\n"); - if (control_level >= 254) - error ("Control nesting too deep!\n"); + /* After the required info we print the configuration information. */ - /* Set a prompt based on the nesting of the control commands. */ - if (instream == stdin || (instream == 0 && readline_hook != NULL)) + fprintf_filtered (stream, "This GDB was configured as \""); + if (!STREQ (host_name, target_name)) { - for (i = 0; i < control_level; i++) - control_prompt[i] = ' '; - control_prompt[i] = '>'; - control_prompt[i+1] = '\0'; - prompt_ptr = (char *)&control_prompt[0]; + fprintf_filtered (stream, "--host=%s --target=%s", host_name, target_name); } else - prompt_ptr = NULL; - - p = command_line_input (prompt_ptr, instream == stdin, "commands"); - - /* Not sure what to do here. */ - if (p == NULL) - return end_command; - - /* Strip leading and trailing whitespace. */ - while (*p == ' ' || *p == '\t') - p++; - - p1 = p + strlen (p); - while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) - p1--; - - /* Blanks and comments don't really do anything, but we need to - distinguish them from else, end and other commands which can be - executed. */ - if (p1 == p || p[0] == '#') - return nop_command; - - /* Is this the end of a simple, while, or if control structure? */ - if (p1 - p == 3 && !strncmp (p, "end", 3)) - return end_command; - - /* Is the else clause of an if control structure? */ - if (p1 - p == 4 && !strncmp (p, "else", 4)) - return else_command; - - /* Check for while, if, break, continue, etc and build a new command - line structure for them. */ - if (p1 - p > 5 && !strncmp (p, "while", 5)) - *command = build_command_line (while_control, p + 6); - else if (p1 - p > 2 && !strncmp (p, "if", 2)) - *command = build_command_line (if_control, p + 3); - else if (p1 - p == 10 && !strncmp (p, "loop_break", 10)) { - *command = (struct command_line *) - xmalloc (sizeof (struct command_line)); - (*command)->next = NULL; - (*command)->line = NULL; - (*command)->control_type = break_control; - (*command)->body_count = 0; - (*command)->body_list = NULL; - } - else if (p1 - p == 13 && !strncmp (p, "loop_continue", 13)) - { - *command = (struct command_line *) - xmalloc (sizeof (struct command_line)); - (*command)->next = NULL; - (*command)->line = NULL; - (*command)->control_type = continue_control; - (*command)->body_count = 0; - (*command)->body_list = NULL; + fprintf_filtered (stream, "%s", host_name); } - else - { - /* A normal command. */ - *command = (struct command_line *) - xmalloc (sizeof (struct command_line)); - (*command)->next = NULL; - (*command)->line = savestring (p, p1 - p); - (*command)->control_type = simple_control; - (*command)->body_count = 0; - (*command)->body_list = NULL; - } - - /* Nothing special. */ - return ok_command; + fprintf_filtered (stream, "\"."); } + +/* get_prompt: access method for the GDB prompt string. */ + +#define MAX_PROMPT_SIZE 256 + +/* + * int get_prompt_1 (char * buf); + * + * Work-horse for get_prompt (called via catch_errors). + * Argument is buffer to hold the formatted prompt. + * + * Returns: 1 for success (use formatted prompt) + * 0 for failure (use gdb_prompt_string). + */ -/* Recursively read in the control structures and create a command_line - structure from them. - - The parent_control parameter is the control structure in which the - following commands are nested. */ +static int gdb_prompt_escape; -static enum command_control_type -recurse_read_control_structure (current_cmd) - struct command_line *current_cmd; +static int +get_prompt_1 (void *data) { - int current_body, i; - enum misc_command_type val; - enum command_control_type ret; - struct command_line **body_ptr, *child_tail, *next; + char *formatted_prompt = data; + char *local_prompt; - child_tail = NULL; - current_body = 1; + if (event_loop_p) + local_prompt = PROMPT (0); + else + local_prompt = gdb_prompt_string; - /* Sanity checks. */ - if (current_cmd->control_type == simple_control) - { - error ("Recursed on a simple control type\n"); - return invalid_control; - } - if (current_body > current_cmd->body_count) + if (gdb_prompt_escape == 0) { - error ("Allocated body is smaller than this command type needs\n"); - return invalid_control; + return 0; /* do no formatting */ } - - /* Read lines from the input stream and build control structures. */ - while (1) + else + /* formatted prompt */ { - dont_repeat (); + char fmt[40], *promptp, *outp, *tmp; + struct value *arg_val; + DOUBLEST doubleval; + LONGEST longval; + CORE_ADDR addrval; - next = NULL; - val = read_next_line (&next); + int i, len; + struct type *arg_type, *elt_type; - /* Just skip blanks and comments. */ - if (val == nop_command) - continue; + promptp = local_prompt; + outp = formatted_prompt; - if (val == end_command) + while (*promptp != '\0') { - if (current_cmd->control_type == while_control - || current_cmd->control_type == if_control) - { - /* Success reading an entire control structure. */ - ret = simple_control; - break; - } - else - { - ret = invalid_control; - break; - } - } - - /* Not the end of a control structure. */ - if (val == else_command) - { - if (current_cmd->control_type == if_control - && current_body == 1) + int available = MAX_PROMPT_SIZE - (outp - formatted_prompt) - 1; + + if (*promptp != gdb_prompt_escape) { - realloc_body_list (current_cmd, 2); - current_body = 2; - child_tail = NULL; - continue; + if (available >= 1) /* overflow protect */ + *outp++ = *promptp++; } else { - ret = invalid_control; - break; - } - } - - if (child_tail) - { - child_tail->next = next; - } - else - { - body_ptr = current_cmd->body_list; - for (i = 1; i < current_body; i++) - body_ptr++; - - *body_ptr = next; - - } - - child_tail = next; - - /* If the latest line is another control structure, then recurse - on it. */ - if (next->control_type == while_control - || next->control_type == if_control) - { - control_level++; - ret = recurse_read_control_structure (next); - control_level--; - - if (ret != simple_control) - break; - } - } - - dont_repeat (); - - return ret; -} - -/* Read lines from the input stream and accumulate them in a chain of - struct command_line's, which is then returned. For input from a - terminal, the special command "end" is used to mark the end of the - input, and is not included in the returned chain of commands. */ - -#define END_MESSAGE "End with a line saying just \"end\"." - -struct command_line * -read_command_lines (prompt, from_tty) -char *prompt; -int from_tty; -{ - struct command_line *head, *tail, *next; - struct cleanup *old_chain; - enum command_control_type ret; - enum misc_command_type val; - - if (readline_begin_hook) - { - /* Note - intentional to merge messages with no newline */ - (*readline_begin_hook) ("%s %s\n", prompt, END_MESSAGE); - } - else if (from_tty && input_from_terminal_p ()) - { - printf_unfiltered ("%s\n%s\n", prompt, END_MESSAGE); - gdb_flush (gdb_stdout); - } - - head = tail = NULL; - old_chain = NULL; - - while (1) - { - val = read_next_line (&next); - - /* Ignore blank lines or comments. */ - if (val == nop_command) - continue; - - if (val == end_command) - { - ret = simple_control; - break; - } - - if (val != ok_command) - { - ret = invalid_control; - break; - } - - if (next->control_type == while_control - || next->control_type == if_control) - { - control_level++; - ret = recurse_read_control_structure (next); - control_level--; - - if (ret == invalid_control) - break; - } - - if (tail) - { - tail->next = next; - } - else - { - head = next; - old_chain = make_cleanup ((make_cleanup_func) free_command_lines, - &head); - } - tail = next; - } - - dont_repeat (); - - if (head) - { - if (ret != invalid_control) - { - discard_cleanups (old_chain); - } - else - do_cleanups (old_chain); - } - - if (readline_end_hook) - { - (*readline_end_hook) (); - } - return (head); -} - -/* Free a chain of struct command_line's. */ - -void -free_command_lines (lptr) - struct command_line **lptr; -{ - register struct command_line *l = *lptr; - register struct command_line *next; - struct command_line **blist; - int i; - - while (l) - { - if (l->body_count > 0) - { - blist = l->body_list; - for (i = 0; i < l->body_count; i++, blist++) - free_command_lines (blist); - } - next = l->next; - free (l->line); - free ((PTR)l); - l = next; - } -} - -/* Add an element to the list of info subcommands. */ - -void -add_info (name, fun, doc) - char *name; - void (*fun) PARAMS ((char *, int)); - char *doc; -{ - add_cmd (name, no_class, fun, doc, &infolist); -} - -/* Add an alias to the list of info subcommands. */ - -void -add_info_alias (name, oldname, abbrev_flag) - char *name; - char *oldname; - int abbrev_flag; -{ - add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); -} - -/* The "info" command is defined as a prefix, with allow_unknown = 0. - Therefore, its own definition is called only for "info" with no args. */ - -/* ARGSUSED */ -static void -info_command (arg, from_tty) - char *arg; - int from_tty; -{ - printf_unfiltered ("\"info\" must be followed by the name of an info command.\n"); - help_list (infolist, "info ", -1, gdb_stdout); -} - -/* The "complete" command is used by Emacs to implement completion. */ - -/* ARGSUSED */ -static void -complete_command (arg, from_tty) - char *arg; - int from_tty; -{ - int i; - int argpoint; - char *completion; - - dont_repeat (); - - if (arg == NULL) - arg = ""; - argpoint = strlen (arg); - - for (completion = line_completion_function (arg, i = 0, arg, argpoint); - completion; - completion = line_completion_function (arg, ++i, arg, argpoint)) - { - printf_unfiltered ("%s\n", completion); - free (completion); - } -} - -/* The "show" command with no arguments shows all the settings. */ - -/* ARGSUSED */ -static void -show_command (arg, from_tty) - char *arg; - int from_tty; -{ - cmd_show_list (showlist, from_tty, ""); -} - -/* Add an element to the list of commands. */ - -void -add_com (name, class, fun, doc) - char *name; - enum command_class class; - void (*fun) PARAMS ((char *, int)); - char *doc; -{ - add_cmd (name, class, fun, doc, &cmdlist); -} - -/* Add an alias or abbreviation command to the list of commands. */ - -void -add_com_alias (name, oldname, class, abbrev_flag) - char *name; - char *oldname; - enum command_class class; - int abbrev_flag; -{ - add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist); -} - -void -error_no_arg (why) - char *why; -{ - error ("Argument required (%s).", why); -} - -/* ARGSUSED */ -static void -help_command (command, from_tty) - char *command; - int from_tty; /* Ignored */ -{ - help_cmd (command, gdb_stdout); -} - -static void -validate_comname (comname) - char *comname; -{ - register char *p; - - if (comname == 0) - error_no_arg ("name of command to define"); - - p = comname; - while (*p) - { - if (!isalnum(*p) && *p != '-' && *p != '_') - error ("Junk in argument list: \"%s\"", p); - p++; - } -} - -/* This is just a placeholder in the command data structures. */ -static void -user_defined_command (ignore, from_tty) - char *ignore; - int from_tty; -{ -} + /* GDB prompt string contains escape char. Parse for arg. + Two consecutive escape chars followed by arg followed by + a comma means to insert the arg using a default format. + Otherwise a printf format string may be included between + the two escape chars. eg: + %%foo, insert foo using default format + %2.2f%foo, insert foo using "%2.2f" format + A mismatch between the format string and the data type + of "foo" is an error (which we don't know how to protect + against). */ + + fmt[0] = '\0'; /* assume null format string */ + if (promptp[1] == gdb_prompt_escape) /* double esc char */ + { + promptp += 2; /* skip past two escape chars. */ + } + else + { + /* extract format string from between two esc chars */ + i = 0; + do + { + fmt[i++] = *promptp++; /* copy format string */ + } + while (i < sizeof (fmt) - 1 && + *promptp != gdb_prompt_escape && + *promptp != '\0'); -static void -define_command (comname, from_tty) - char *comname; - int from_tty; -{ - register struct command_line *cmds; - register struct cmd_list_element *c, *newc, *hookc = 0; - char *tem = comname; - char tmpbuf[128]; -#define HOOK_STRING "hook-" -#define HOOK_LEN 5 + if (*promptp != gdb_prompt_escape) + error ("Syntax error at prompt position %d", + promptp - local_prompt); + else + { + promptp++; /* skip second escape char */ + fmt[i++] = '\0'; /* terminate the format string */ + } + } - validate_comname (comname); + arg_val = parse_to_comma_and_eval (&promptp); + if (*promptp == ',') + promptp++; /* skip past the comma */ + arg_type = check_typedef (VALUE_TYPE (arg_val)); + switch (TYPE_CODE (arg_type)) + { + case TYPE_CODE_ARRAY: + elt_type = check_typedef (TYPE_TARGET_TYPE (arg_type)); + if (TYPE_LENGTH (arg_type) > 0 && + TYPE_LENGTH (elt_type) == 1 && + TYPE_CODE (elt_type) == TYPE_CODE_INT) + { + int len = TYPE_LENGTH (arg_type); - /* Look it up, and verify that we got an exact match. */ - c = lookup_cmd (&tem, cmdlist, "", -1, 1); - if (c && !STREQ (comname, c->name)) - c = 0; + if (VALUE_LAZY (arg_val)) + value_fetch_lazy (arg_val); + tmp = VALUE_CONTENTS (arg_val); - if (c) - { - if (c->class == class_user || c->class == class_alias) - tem = "Redefine command \"%s\"? "; - else - tem = "Really redefine built-in command \"%s\"? "; - if (!query (tem, c->name)) - error ("Command \"%s\" not redefined.", c->name); - } + if (len > available) + len = available; /* overflow protect */ - /* If this new command is a hook, then mark the command which it - is hooking. Note that we allow hooking `help' commands, so that - we can hook the `stop' pseudo-command. */ + /* FIXME: how to protect GDB from crashing + from bad user-supplied format string? */ + if (fmt[0] != 0) + sprintf (outp, fmt, tmp); + else + strncpy (outp, tmp, len); + outp[len] = '\0'; + } + break; + case TYPE_CODE_PTR: + elt_type = check_typedef (TYPE_TARGET_TYPE (arg_type)); + addrval = value_as_address (arg_val); - if (!strncmp (comname, HOOK_STRING, HOOK_LEN)) - { - /* Look up cmd it hooks, and verify that we got an exact match. */ - tem = comname+HOOK_LEN; - hookc = lookup_cmd (&tem, cmdlist, "", -1, 0); - if (hookc && !STREQ (comname+HOOK_LEN, hookc->name)) - hookc = 0; - if (!hookc) - { - warning ("Your new `%s' command does not hook any existing command.", - comname); - if (!query ("Proceed? ")) - error ("Not confirmed."); + if (TYPE_LENGTH (elt_type) == 1 && + TYPE_CODE (elt_type) == TYPE_CODE_INT && + addrval != 0) + { + /* display it as a string */ + char *default_fmt = "%s"; + char *tmp; + int err = 0; + + /* Limiting the number of bytes that the following call + will read protects us from sprintf overflow later. */ + i = target_read_string (addrval, /* src */ + &tmp, /* dest */ + available, /* len */ + &err); + if (err) /* read failed */ + error ("%s on target_read", safe_strerror (err)); + + tmp[i] = '\0'; /* force-terminate string */ + /* FIXME: how to protect GDB from crashing + from bad user-supplied format string? */ + sprintf (outp, fmt[0] == 0 ? default_fmt : fmt, + tmp); + xfree (tmp); + } + else + { + /* display it as a pointer */ + char *default_fmt = "0x%x"; + + /* FIXME: how to protect GDB from crashing + from bad user-supplied format string? */ + if (available >= 16 /*? */ ) /* overflow protect */ + sprintf (outp, fmt[0] == 0 ? default_fmt : fmt, + (long) addrval); + } + break; + case TYPE_CODE_FLT: + { + char *default_fmt = "%g"; + + doubleval = value_as_double (arg_val); + /* FIXME: how to protect GDB from crashing + from bad user-supplied format string? */ + if (available >= 16 /*? */ ) /* overflow protect */ + sprintf (outp, fmt[0] == 0 ? default_fmt : fmt, + (double) doubleval); + break; + } + case TYPE_CODE_INT: + { + char *default_fmt = "%d"; + + longval = value_as_long (arg_val); + /* FIXME: how to protect GDB from crashing + from bad user-supplied format string? */ + if (available >= 16 /*? */ ) /* overflow protect */ + sprintf (outp, fmt[0] == 0 ? default_fmt : fmt, + (long) longval); + break; + } + case TYPE_CODE_BOOL: + { + /* no default format for bool */ + longval = value_as_long (arg_val); + if (available >= 8 /*? */ ) /* overflow protect */ + { + if (longval) + strcpy (outp, "<true>"); + else + strcpy (outp, "<false>"); + } + break; + } + case TYPE_CODE_ENUM: + { + /* no default format for enum */ + longval = value_as_long (arg_val); + len = TYPE_NFIELDS (arg_type); + /* find enum name if possible */ + for (i = 0; i < len; i++) + if (TYPE_FIELD_BITPOS (arg_type, i) == longval) + break; /* match -- end loop */ + + if (i < len) /* enum name found */ + { + char *name = TYPE_FIELD_NAME (arg_type, i); + + strncpy (outp, name, available); + /* in casel available < strlen (name), */ + outp[available] = '\0'; + } + else + { + if (available >= 16 /*? */ ) /* overflow protect */ + sprintf (outp, "%ld", (long) longval); + } + break; + } + case TYPE_CODE_VOID: + *outp = '\0'; + break; /* void type -- no output */ + default: + error ("bad data type at prompt position %d", + promptp - local_prompt); + break; + } + outp += strlen (outp); + } } - } - - comname = savestring (comname, strlen (comname)); - - /* If the rest of the commands will be case insensitive, this one - should behave in the same manner. */ - for (tem = comname; *tem; tem++) - if (isupper(*tem)) *tem = tolower(*tem); - - control_level = 0; - sprintf (tmpbuf, "Type commands for definition of \"%s\".", comname); - cmds = read_command_lines (tmpbuf, from_tty); - - if (c && c->class == class_user) - free_command_lines (&c->user_commands); - - newc = add_cmd (comname, class_user, user_defined_command, - (c && c->class == class_user) - ? c->doc : savestring ("User-defined.", 13), &cmdlist); - newc->user_commands = cmds; - - /* If this new command is a hook, then mark both commands as being - tied. */ - if (hookc) - { - hookc->hook = newc; /* Target gets hooked. */ - newc->hookee = hookc; /* We are marked as hooking target cmd. */ + *outp++ = '\0'; /* terminate prompt string */ + return 1; } } -static void -document_command (comname, from_tty) - char *comname; - int from_tty; -{ - struct command_line *doclines; - register struct cmd_list_element *c; - char *tem = comname; - char tmpbuf[128]; - - validate_comname (comname); - - c = lookup_cmd (&tem, cmdlist, "", 0, 1); - - if (c->class != class_user) - error ("Command \"%s\" is built-in.", comname); - - sprintf (tmpbuf, "Type documentation for \"%s\".", comname); - doclines = read_command_lines (tmpbuf, from_tty); - - if (c->doc) free (c->doc); - - { - register struct command_line *cl1; - register int len = 0; - - for (cl1 = doclines; cl1; cl1 = cl1->next) - len += strlen (cl1->line) + 1; - - c->doc = (char *) xmalloc (len + 1); - *c->doc = 0; - - for (cl1 = doclines; cl1; cl1 = cl1->next) - { - strcat (c->doc, cl1->line); - if (cl1->next) - strcat (c->doc, "\n"); - } - } - - free_command_lines (&doclines); -} - -/* Print the GDB banner. */ -void -print_gdb_version (stream) - GDB_FILE *stream; +char * +get_prompt (void) { - /* From GNU coding standards, first line is meant to be easy for a - program to parse, and is just canonical program name and version - number, which starts after last space. */ - - fprintf_filtered (stream, "GNU gdb %s\n", version); + static char buf[MAX_PROMPT_SIZE]; - /* Second line is a copyright notice. */ - - fprintf_filtered (stream, "Copyright 1998 Free Software Foundation, Inc.\n"); - - /* Following the copyright is a brief statement that the program is - free software, that users are free to copy and change it on - certain conditions, that it is covered by the GNU GPL, and that - there is no warranty. */ - - fprintf_filtered (stream, "\ -GDB is free software, covered by the GNU General Public License, and you are\n\ -welcome to change it and/or distribute copies of it under certain conditions.\n\ -Type \"show copying\" to see the conditions.\n\ -There is absolutely no warranty for GDB. Type \"show warranty\" for details.\n"); - - /* After the required info we print the configuration information. */ - - fprintf_filtered (stream, "This GDB was configured as \""); - if (!STREQ (host_name, target_name)) + if (catch_errors (get_prompt_1, buf, "bad formatted prompt: ", + RETURN_MASK_ALL)) { - fprintf_filtered (stream, "--host=%s --target=%s", host_name, target_name); + return &buf[0]; /* successful formatted prompt */ } else { - fprintf_filtered (stream, "%s", host_name); + /* Prompt could not be formatted. */ + if (event_loop_p) + return PROMPT (0); + else + return gdb_prompt_string; } - fprintf_filtered (stream, "\"."); -} - -/* ARGSUSED */ -static void -show_version (args, from_tty) - char *args; - int from_tty; -{ - immediate_quit++; - print_gdb_version (gdb_stdout); - printf_filtered ("\n"); - immediate_quit--; } - -/* xgdb calls this to reprint the usual GDB prompt. Obsolete now that xgdb - is obsolete. */ void -print_prompt () -{ - printf_unfiltered ("%s", prompt); - gdb_flush (gdb_stdout); -} - -/* This replaces the above for the frontends: it returns a pointer - to the prompt. */ -char * -get_prompt () -{ - return prompt; -} - -void -set_prompt (s) - char *s; +set_prompt (char *s) { /* ??rehrauer: I don't know why this fails, since it looks as though assignments to prompt are wrapped in calls to savestring... - if (prompt != NULL) - free (prompt); -*/ - prompt = savestring (s, strlen (s)); + if (prompt != NULL) + xfree (prompt); + */ + if (event_loop_p) + PROMPT (0) = savestring (s, strlen (s)); + else + gdb_prompt_string = savestring (s, strlen (s)); } - + /* If necessary, make the user confirm that we should quit. Return non-zero if we should quit, zero if we shouldn't. */ int -quit_confirm () +quit_confirm (void) { - if (inferior_pid != 0 && target_has_execution) + if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution) { char *s; /* This is something of a hack. But there's no reliable way to - see if a GUI is running. The `use_windows' variable doesn't - cut it. */ + see if a GUI is running. The `use_windows' variable doesn't + cut it. */ if (init_ui_hook) s = "A debugging session is active.\nDo you still want to close the debugger?"; else if (attach_flag) @@ -2936,7 +1656,7 @@ quit_confirm () else s = "The program is running. Exit anyway? "; - if (! query (s)) + if (!query (s)) return 0; } @@ -2946,9 +1666,7 @@ quit_confirm () /* Quit without asking for confirmation. */ void -quit_force (args, from_tty) - char *args; - int from_tty; +quit_force (char *args, int from_tty) { int exit_code = 0; @@ -2956,12 +1674,12 @@ quit_force (args, from_tty) value of that expression. */ if (args) { - value_ptr val = parse_and_eval (args); + struct value *val = parse_and_eval (args); exit_code = (int) value_as_long (val); } - if (inferior_pid != 0 && target_has_execution) + if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution) { if (attach_flag) target_detach (args, from_tty); @@ -2976,269 +1694,34 @@ quit_force (args, from_tty) if (write_history_p && history_filename) write_history (history_filename); - do_final_cleanups(ALL_CLEANUPS); /* Do any final cleanups before exiting */ - -#if defined(TUI) - /* tuiDo((TuiOpaqueFuncPtr)tuiCleanUp); */ - /* The above does not need to be inside a tuiDo(), since - * it is not manipulating the curses screen, but rather, - * it is tearing it down. - */ - if (tui_version) - tuiCleanUp(); -#endif + do_final_cleanups (ALL_CLEANUPS); /* Do any final cleanups before exiting */ exit (exit_code); } -/* Handle the quit command. */ - -void -quit_command (args, from_tty) - char *args; - int from_tty; -{ - if (! quit_confirm ()) - error ("Not confirmed."); - quit_force (args, from_tty); -} - /* Returns whether GDB is running on a terminal and whether the user desires that questions be asked of them on that terminal. */ int -input_from_terminal_p () +input_from_terminal_p (void) { return gdb_has_a_terminal () && (instream == stdin) & caution; } /* ARGSUSED */ static void -pwd_command (args, from_tty) - char *args; - int from_tty; +dont_repeat_command (char *ignored, int from_tty) { - if (args) error ("The \"pwd\" command does not take an argument: %s", args); - getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); - - if (!STREQ (gdb_dirbuf, current_directory)) - printf_unfiltered ("Working directory %s\n (canonically %s).\n", - current_directory, gdb_dirbuf); - else - printf_unfiltered ("Working directory %s.\n", current_directory); -} - -void -cd_command (dir, from_tty) - char *dir; - int from_tty; -{ - int len; - /* Found something other than leading repetitions of "/..". */ - int found_real_path; - char *p; - - /* If the new directory is absolute, repeat is a no-op; if relative, - repeat might be useful but is more likely to be a mistake. */ - dont_repeat (); - - if (dir == 0) - error_no_arg ("new working directory"); - - dir = tilde_expand (dir); - make_cleanup (free, dir); - - if (chdir (dir) < 0) - perror_with_name (dir); - - len = strlen (dir); - dir = savestring (dir, len - (len > 1 && SLASH_P(dir[len-1]))); - if (ROOTED_P(dir)) - current_directory = dir; - else - { - if (SLASH_P (current_directory[0]) && current_directory[1] == '\0') - current_directory = concat (current_directory, dir, NULL); - else - current_directory = concat (current_directory, SLASH_STRING, dir, NULL); - free (dir); - } - - /* Now simplify any occurrences of `.' and `..' in the pathname. */ - - found_real_path = 0; - for (p = current_directory; *p;) - { - if (SLASH_P (p[0]) && p[1] == '.' && (p[2] == 0 || SLASH_P (p[2]))) - strcpy (p, p + 2); - else if (SLASH_P (p[0]) && p[1] == '.' && p[2] == '.' - && (p[3] == 0 || SLASH_P (p[3]))) - { - if (found_real_path) - { - /* Search backwards for the directory just before the "/.." - and obliterate it and the "/..". */ - char *q = p; - while (q != current_directory && ! SLASH_P (q[-1])) - --q; - - if (q == current_directory) - /* current_directory is - a relative pathname ("can't happen"--leave it alone). */ - ++p; - else - { - strcpy (q - 1, p + 3); - p = q - 1; - } - } - else - /* We are dealing with leading repetitions of "/..", for example - "/../..", which is the Mach super-root. */ - p += 3; - } - else - { - found_real_path = 1; - ++p; - } - } - - forget_cached_source_info (); - - if (from_tty) - pwd_command ((char *) 0, 1); -} - -struct source_cleanup_lines_args { - int old_line; - char *old_file; - char *old_pre_error; - char *old_error_pre_print; -}; - -static void -source_cleanup_lines (args) - PTR args; -{ - struct source_cleanup_lines_args *p = - (struct source_cleanup_lines_args *)args; - source_line_number = p->old_line; - source_file_name = p->old_file; - source_pre_error = p->old_pre_error; - error_pre_print = p->old_error_pre_print; -} - -/* ARGSUSED */ -void -source_command (args, from_tty) - char *args; - int from_tty; -{ - FILE *stream; - struct cleanup *old_cleanups; - char *file = args; - struct source_cleanup_lines_args old_lines; - int needed_length; - - if (file == NULL) - { - error ("source command requires pathname of file to source."); - } - - file = tilde_expand (file); - old_cleanups = make_cleanup (free, file); - - stream = fopen (file, FOPEN_RT); - if (!stream) - if (from_tty) - perror_with_name (file); - else - return; - - make_cleanup ((make_cleanup_func) fclose, stream); - - old_lines.old_line = source_line_number; - old_lines.old_file = source_file_name; - old_lines.old_pre_error = source_pre_error; - old_lines.old_error_pre_print = error_pre_print; - make_cleanup (source_cleanup_lines, &old_lines); - source_line_number = 0; - source_file_name = file; - source_pre_error = error_pre_print == NULL ? "" : error_pre_print; - source_pre_error = savestring (source_pre_error, strlen (source_pre_error)); - make_cleanup (free, source_pre_error); - /* This will get set every time we read a line. So it won't stay "" for - long. */ - error_pre_print = ""; - - needed_length = strlen (source_file_name) + strlen (source_pre_error) + 80; - if (source_error_allocated < needed_length) - { - source_error_allocated *= 2; - if (source_error_allocated < needed_length) - source_error_allocated = needed_length; - if (source_error == NULL) - source_error = xmalloc (source_error_allocated); - else - source_error = xrealloc (source_error, source_error_allocated); - } - - read_command_file (stream); - - do_cleanups (old_cleanups); -} - -/* ARGSUSED */ -static void -echo_command (text, from_tty) - char *text; - int from_tty; -{ - char *p = text; - register int c; - - if (text) - while ((c = *p++) != '\0') - { - if (c == '\\') - { - /* \ at end of argument is used after spaces - so they won't be lost. */ - if (*p == 0) - return; - - c = parse_escape (&p); - if (c >= 0) - printf_filtered ("%c", c); - } - else - printf_filtered ("%c", c); - } - - /* Force this output to appear now. */ - wrap_here (""); - gdb_flush (gdb_stdout); -} - -/* ARGSUSED */ -static void -dont_repeat_command (ignored, from_tty) - char *ignored; - int from_tty; -{ - *line = 0; /* Can't call dont_repeat here because we're not - necessarily reading from stdin. */ + *line = 0; /* Can't call dont_repeat here because we're not + necessarily reading from stdin. */ } /* Functions to manipulate command line editing control variables. */ /* Number of commands to print in each call to show_commands. */ #define Hist_print 10 -static void -show_commands (args, from_tty) - char *args; - int from_tty; +void +show_commands (char *args, int from_tty) { /* Index for history commands. Relative to history_base. */ int offset; @@ -3251,8 +1734,6 @@ show_commands (args, from_tty) than the number of the last command). Relative to history_base. */ int hist_len; - extern HIST_ENTRY *history_get PARAMS ((int)); - /* Print out some of the commands from the command history. */ /* First determine the length of the history list. */ hist_len = history_size; @@ -3272,7 +1753,7 @@ show_commands (args, from_tty) ; else /* "info editing <exp>" should print around command number <exp>. */ - num = (parse_and_eval_address (args) - history_base) - Hist_print / 2; + num = (parse_and_eval_long (args) - history_base) - Hist_print / 2; } /* "show commands" means print the last Hist_print commands. */ else @@ -3295,7 +1776,7 @@ show_commands (args, from_tty) for (offset = num; offset < num + Hist_print && offset < hist_len; offset++) { printf_filtered ("%5d %s\n", history_base + offset, - (history_get (history_base + offset))->line); + (history_get (history_base + offset))->line); } /* The next command we want to display is the next one that we haven't @@ -3315,10 +1796,7 @@ show_commands (args, from_tty) /* Called by do_setshow_command. */ /* ARGSUSED */ static void -set_history_size_command (args, from_tty, c) - char *args; - int from_tty; - struct cmd_list_element *c; +set_history_size_command (char *args, int from_tty, struct cmd_list_element *c) { if (history_size == INT_MAX) unstifle_history (); @@ -3332,20 +1810,16 @@ set_history_size_command (args, from_tty, c) } /* ARGSUSED */ -static void -set_history (args, from_tty) - char *args; - int from_tty; +void +set_history (char *args, int from_tty) { printf_unfiltered ("\"set history\" must be followed by the name of a history subcommand.\n"); help_list (sethistlist, "set history ", -1, gdb_stdout); } /* ARGSUSED */ -static void -show_history (args, from_tty) - char *args; - int from_tty; +void +show_history (char *args, int from_tty) { cmd_show_list (showhistlist, from_tty, ""); } @@ -3354,11 +1828,8 @@ int info_verbose = 0; /* Default verbose msgs off */ /* Called by do_setshow_command. An elaborate joke. */ /* ARGSUSED */ -static void -set_verbose (args, from_tty, c) - char *args; - int from_tty; - struct cmd_list_element *c; +void +set_verbose (char *args, int from_tty, struct cmd_list_element *c) { char *cmdname = "verbose"; struct cmd_list_element *showcmd; @@ -3377,45 +1848,6 @@ set_verbose (args, from_tty, c) } } -static void -float_handler (signo) -int signo; -{ - /* This message is based on ANSI C, section 4.7. Note that integer - divide by zero causes this, so "float" is a misnomer. */ - signal (SIGFPE, float_handler); - error ("Erroneous arithmetic operation."); -} - - -static void -init_cmd_lists () -{ - cmdlist = NULL; - infolist = NULL; - enablelist = NULL; - disablelist = NULL; - togglelist = NULL; - stoplist = NULL; - deletelist = NULL; - enablebreaklist = NULL; - setlist = NULL; - unsetlist = NULL; - showlist = NULL; - sethistlist = NULL; - showhistlist = NULL; - unsethistlist = NULL; -#if MAINTENANCE_CMDS - maintenancelist = NULL; - maintenanceinfolist = NULL; - maintenanceprintlist = NULL; -#endif - setprintlist = NULL; - showprintlist = NULL; - setchecklist = NULL; - showchecklist = NULL; -} - /* Init the history buffer. Note that we are called after the init file(s) * have been read so that the user can change the history file via his * .gdbinit file (for instance). The GDBHISTFILE environment variable @@ -3423,7 +1855,7 @@ init_cmd_lists () */ void -init_history() +init_history (void) { char *tmpenv; @@ -3437,26 +1869,54 @@ init_history() tmpenv = getenv ("GDBHISTFILE"); if (tmpenv) - history_filename = savestring (tmpenv, strlen(tmpenv)); - else if (!history_filename) { - /* We include the current directory so that if the user changes - directories the file written will be the same as the one - that was read. */ - history_filename = concat (current_directory, "/.gdb_history", NULL); - } + history_filename = savestring (tmpenv, strlen (tmpenv)); + else if (!history_filename) + { + /* We include the current directory so that if the user changes + directories the file written will be the same as the one + that was read. */ +#ifdef __MSDOS__ + /* No leading dots in file names are allowed on MSDOS. */ + history_filename = concat (current_directory, "/_gdb_history", NULL); +#else + history_filename = concat (current_directory, "/.gdb_history", NULL); +#endif + } read_history (history_filename); } static void -init_main () +init_main (void) { struct cmd_list_element *c; -#ifdef DEFAULT_PROMPT - prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); -#else - prompt = savestring ("(gdb) ", 6); -#endif + /* If we are running the asynchronous version, + we initialize the prompts differently. */ + if (!event_loop_p) + { + gdb_prompt_string = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT)); + } + else + { + /* initialize the prompt stack to a simple "(gdb) " prompt or to + whatever the DEFAULT_PROMPT is. */ + the_prompts.top = 0; + PREFIX (0) = ""; + PROMPT (0) = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT)); + SUFFIX (0) = ""; + /* Set things up for annotation_level > 1, if the user ever decides + to use it. */ + async_annotation_suffix = "prompt"; + /* Set the variable associated with the setshow prompt command. */ + new_async_prompt = savestring (PROMPT (0), strlen (PROMPT (0))); + + /* If gdb was started with --annotate=2, this is equivalent to + the user entering the command 'set annotate 2' at the gdb + prompt, so we need to do extra processing. */ + if (annotation_level > 1) + set_async_annotation_level (NULL, 0, NULL); + } + gdb_prompt_escape = 0; /* default to none. */ /* Set the important stuff up for command editing. */ command_editing_p = 1; @@ -3465,213 +1925,189 @@ init_main () /* Setup important stuff for command line editing. */ rl_completion_entry_function = (int (*)()) readline_line_completion_function; - rl_completer_word_break_characters = gdb_completer_word_break_characters; - rl_completer_quote_characters = gdb_completer_quote_characters; + rl_completer_word_break_characters = + get_gdb_completer_word_break_characters (); + rl_completer_quote_characters = get_gdb_completer_quote_characters (); rl_readline_name = "gdb"; - /* Define the classes of commands. - They will appear in the help list in the reverse of this order. */ - - add_cmd ("internals", class_maintenance, NO_FUNCTION, - "Maintenance commands.\n\ -Some gdb commands are provided just for use by gdb maintainers.\n\ -These commands are subject to frequent change, and may not be as\n\ -well documented as user commands.", - &cmdlist); - add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist); - add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist); - add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\ -The commands in this class are those defined by the user.\n\ -Use the \"define\" command to define a command.", &cmdlist); - add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist); - if (!dbx_commands) - add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist); - add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist); - add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist); - add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist); - add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\ -The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ -counting from zero for the innermost (currently executing) frame.\n\n\ -At any time gdb identifies one frame as the \"selected\" frame.\n\ -Variable lookups are done with respect to the selected frame.\n\ -When the program being debugged stops, gdb selects the innermost frame.\n\ -The commands below can be used to select other frames by number or address.", - &cmdlist); - add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist); - - add_com ("pwd", class_files, pwd_command, - "Print working directory. This is used for your program as well."); - c = add_cmd ("cd", class_files, cd_command, - "Set working directory to DIR for debugger and program being debugged.\n\ -The change does not take effect for the program being debugged\n\ -until the next time it is started.", &cmdlist); - c->completer = filename_completer; + /* The name for this defun comes from Bash, where it originated. + 15 is Control-o, the same binding this function has in Bash. */ + rl_add_defun ("operate-and-get-next", gdb_rl_operate_and_get_next, 15); + + /* The set prompt command is different depending whether or not the + async version is run. NOTE: this difference is going to + disappear as we make the event loop be the default engine of + gdb. */ + if (!event_loop_p) + { + add_show_from_set + (add_set_cmd ("prompt", class_support, var_string, + (char *) &gdb_prompt_string, "Set gdb's prompt", + &setlist), + &showlist); + } + else + { + c = add_set_cmd ("prompt", class_support, var_string, + (char *) &new_async_prompt, "Set gdb's prompt", + &setlist); + add_show_from_set (c, &showlist); + set_cmd_sfunc (c, set_async_prompt); + } add_show_from_set - (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt, - "Set gdb's prompt", - &setlist), + (add_set_cmd ("prompt-escape-char", class_support, var_zinteger, + (char *) &gdb_prompt_escape, + "Set escape character for formatting of gdb's prompt", + &setlist), &showlist); - add_com ("echo", class_support, echo_command, - "Print a constant string. Give string as argument.\n\ -C escape sequences may be used in the argument.\n\ -No newline is added at the end of the argument;\n\ -use \"\\n\" if you want a newline to be printed.\n\ -Since leading and trailing whitespace are ignored in command arguments,\n\ -if you want to print some you must use \"\\\" before leading whitespace\n\ -to be printed or after trailing whitespace."); - add_com ("document", class_support, document_command, - "Document a user-defined command.\n\ -Give command name as argument. Give documentation on following lines.\n\ -End with a line of just \"end\"."); - add_com ("define", class_support, define_command, - "Define a new command name. Command name is argument.\n\ -Definition appears on following lines, one command per line.\n\ -End with a line of just \"end\".\n\ -Use the \"document\" command to give documentation for the new command.\n\ -Commands defined in this way may have up to ten arguments."); - -#ifdef __STDC__ - c = add_cmd ("source", class_support, source_command, - "Read commands from a file named FILE.\n\ -Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\ -when gdb is started.", &cmdlist); -#else - /* Punt file name, we can't help it easily. */ - c = add_cmd ("source", class_support, source_command, - "Read commands from a file named FILE.\n\ -Note that the file \".gdbinit\" is read automatically in this way\n\ -when gdb is started.", &cmdlist); -#endif - c->completer = filename_completer; - - add_com ("quit", class_support, quit_command, "Exit gdb."); - add_com ("help", class_support, help_command, "Print list of commands."); - add_com_alias ("q", "quit", class_support, 1); - add_com_alias ("h", "help", class_support, 1); - add_com ("dont-repeat", class_support, dont_repeat_command, "Don't repeat this command.\n\ Primarily used inside of user-defined commands that should not be repeated when\n\ hitting return."); - c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose, - "Set ", - &setlist), - add_show_from_set (c, &showlist); - c->function.sfunc = set_verbose; - set_verbose (NULL, 0, c); - - add_show_from_set - (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p, - "Set editing of command lines as they are typed.\n\ + /* The set editing command is different depending whether or not the + async version is run. NOTE: this difference is going to disappear + as we make the event loop be the default engine of gdb. */ + if (!event_loop_p) + { + add_show_from_set + (add_set_cmd ("editing", class_support, var_boolean, (char *) &command_editing_p, + "Set editing of command lines as they are typed.\n\ Use \"on\" to enable the editing, and \"off\" to disable it.\n\ Without an argument, command line editing is enabled. To edit, use\n\ EMACS-like or VI-like commands like control-P or ESC.", &setlist), - &showlist); - - add_prefix_cmd ("history", class_support, set_history, - "Generic command for setting command history parameters.", - &sethistlist, "set history ", 0, &setlist); - add_prefix_cmd ("history", class_support, show_history, - "Generic command for showing command history parameters.", - &showhistlist, "show history ", 0, &showlist); + &showlist); + } + else + { + c = add_set_cmd ("editing", class_support, var_boolean, (char *) &async_command_editing_p, + "Set editing of command lines as they are typed.\n\ +Use \"on\" to enable the editing, and \"off\" to disable it.\n\ +Without an argument, command line editing is enabled. To edit, use\n\ +EMACS-like or VI-like commands like control-P or ESC.", &setlist); - add_show_from_set - (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p, - "Set history expansion on command input.\n\ -Without an argument, history expansion is enabled.", &sethistlist), - &showhistlist); + add_show_from_set (c, &showlist); + set_cmd_sfunc (c, set_async_editing_command); + } add_show_from_set - (add_set_cmd ("save", no_class, var_boolean, (char *)&write_history_p, - "Set saving of the history record on exit.\n\ + (add_set_cmd ("save", no_class, var_boolean, (char *) &write_history_p, + "Set saving of the history record on exit.\n\ Use \"on\" to enable the saving, and \"off\" to disable it.\n\ Without an argument, saving is enabled.", &sethistlist), &showhistlist); - c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size, + c = add_set_cmd ("size", no_class, var_integer, (char *) &history_size, "Set the size of the command history, \n\ ie. the number of previous commands to keep a record of.", &sethistlist); add_show_from_set (c, &showhistlist); - c->function.sfunc = set_history_size_command; + set_cmd_sfunc (c, set_history_size_command); - add_show_from_set - (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename, - "Set the filename in which to record the command history\n\ - (the list of previous commands of which a record is kept).", &sethistlist), - &showhistlist); + c = add_set_cmd ("filename", no_class, var_filename, + (char *) &history_filename, + "Set the filename in which to record the command history\n\ + (the list of previous commands of which a record is kept).", &sethistlist); + c->completer = filename_completer; + add_show_from_set (c, &showhistlist); add_show_from_set (add_set_cmd ("confirm", class_support, var_boolean, - (char *)&caution, + (char *) &caution, "Set whether to confirm potentially dangerous operations.", &setlist), &showlist); - add_prefix_cmd ("info", class_info, info_command, - "Generic command for showing things about the program being debugged.", - &infolist, "info ", 0, &cmdlist); - add_com_alias ("i", "info", class_info, 1); - - add_com ("complete", class_obscure, complete_command, - "List the completions for the rest of the line as a command."); - - add_prefix_cmd ("show", class_info, show_command, - "Generic command for showing things about the debugger.", - &showlist, "show ", 0, &cmdlist); - /* Another way to get at the same thing. */ - add_info ("set", show_command, "Show all GDB settings."); - - add_cmd ("commands", no_class, show_commands, - "Show the history of commands you typed.\n\ -You can supply a command number to start with, or a `+' to start after\n\ -the previous command number shown.", - &showlist); - - add_cmd ("version", no_class, show_version, - "Show what version of GDB this is.", &showlist); - - add_com ("while", class_support, while_command, -"Execute nested commands WHILE the conditional expression is non zero.\n\ -The conditional expression must follow the word `while' and must in turn be\n\ -followed by a new line. The nested commands must be entered one per line,\n\ -and should be terminated by the word `end'."); - - add_com ("if", class_support, if_command, -"Execute nested commands once IF the conditional expression is non zero.\n\ -The conditional expression must follow the word `if' and must in turn be\n\ -followed by a new line. The nested commands must be entered one per line,\n\ -and should be terminated by the word 'else' or `end'. If an else clause\n\ -is used, the same rules apply to its nested commands as to the first ones."); - - /* If target is open when baud changes, it doesn't take effect until the - next open (I think, not sure). */ - add_show_from_set (add_set_cmd ("remotebaud", no_class, - var_zinteger, (char *)&baud_rate, - "Set baud rate for remote serial I/O.\n\ -This value is used to set the speed of the serial port when debugging\n\ -using remote targets.", &setlist), - &showlist); - - add_show_from_set ( - add_set_cmd ("remotedebug", no_class, var_zinteger, (char *)&remote_debug, - "Set debugging of remote protocol.\n\ -When enabled, each packet sent or received with the remote target\n\ -is displayed.", &setlist), - &showlist); - - add_show_from_set ( - add_set_cmd ("remotetimeout", no_class, var_integer, (char *)&remote_timeout, - "Set timeout limit to wait for target to respond.\n\ -This value is used to set the time limit for gdb to wait for a response\n\ -from the target.", &setlist), - &showlist); - - c = add_set_cmd ("annotate", class_obscure, var_zinteger, - (char *)&annotation_level, "Set annotation_level.\n\ + /* The set annotate command is different depending whether or not + the async version is run. NOTE: this difference is going to + disappear as we make the event loop be the default engine of + gdb. */ + if (!event_loop_p) + { + c = add_set_cmd ("annotate", class_obscure, var_zinteger, + (char *) &annotation_level, "Set annotation_level.\n\ 0 == normal; 1 == fullname (for use when running under emacs)\n\ 2 == output annotated suitably for use by programs that control GDB.", - &setlist); - c = add_show_from_set (c, &showlist); + &setlist); + c = add_show_from_set (c, &showlist); + } + else + { + c = add_set_cmd ("annotate", class_obscure, var_zinteger, + (char *) &annotation_level, "Set annotation_level.\n\ +0 == normal; 1 == fullname (for use when running under emacs)\n\ +2 == output annotated suitably for use by programs that control GDB.", + &setlist); + add_show_from_set (c, &showlist); + set_cmd_sfunc (c, set_async_annotation_level); + } + if (event_loop_p) + { + add_show_from_set + (add_set_cmd ("exec-done-display", class_support, var_boolean, (char *) &exec_done_display_p, + "Set notification of completion for asynchronous execution commands.\n\ +Use \"on\" to enable the notification, and \"off\" to disable it.", &setlist), + &showlist); + } +} + +void +gdb_init (char *argv0) +{ + if (pre_init_ui_hook) + pre_init_ui_hook (); + + /* Run the init function of each source file */ + + getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); + current_directory = gdb_dirbuf; + +#ifdef __MSDOS__ + /* Make sure we return to the original directory upon exit, come + what may, since the OS doesn't do that for us. */ + make_final_cleanup (do_chdir_cleanup, xstrdup (current_directory)); +#endif + + init_cmd_lists (); /* This needs to be done first */ + initialize_targets (); /* Setup target_terminal macros for utils.c */ + initialize_utils (); /* Make errors and warnings possible */ + initialize_all_files (); + initialize_current_architecture (); + init_cli_cmds(); + init_main (); /* But that omits this file! Do it now */ + + /* The signal handling mechanism is different depending whether or + not the async version is run. NOTE: in the future we plan to make + the event loop be the default engine of gdb, and this difference + will disappear. */ + if (event_loop_p) + async_init_signals (); + else + init_signals (); + + /* We need a default language for parsing expressions, so simple things like + "set width 0" won't fail if no language is explicitly set in a config file + or implicitly set by reading an executable during startup. */ + set_language (language_c); + expected_language = current_language; /* don't warn about the change. */ + + /* Allow another UI to initialize. If the UI fails to initialize, and + it wants GDB to revert to the CLI, it should clear init_ui_hook. */ + if (init_ui_hook) + init_ui_hook (argv0); + + /* Install the default UI */ + if (!init_ui_hook) + { + uiout = cli_out_new (gdb_stdout); + + /* All the interpreters should have had a look at things by now. + Initialize the selected interpreter. */ + if (interpreter_p) + { + fprintf_unfiltered (gdb_stderr, "Interpreter `%s' unrecognized.\n", + interpreter_p); + exit (1); + } + } } diff --git a/contrib/gdb/gdb/utils.c b/contrib/gdb/gdb/utils.c index ef8f405..75f65e1 100644 --- a/contrib/gdb/gdb/utils.c +++ b/contrib/gdb/gdb/utils.c @@ -1,30 +1,34 @@ /* General utility routines for GDB, the GNU debugger. - Copyright 1986, 89, 90, 91, 92, 95, 96, 1998 Free Software Foundation, Inc. + Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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. */ + 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. */ -/* $FreeBSD$ */ +/* FIXME: cagney/2002-02-28: The GDB coding standard indicates that + "defs.h" should be included first. Unfortunatly some systems + (currently Debian GNU/Linux) include the <stdbool.h> via <curses.h> + and they clash with "bfd.h"'s definiton of true/false. The correct + fix is to remove true/false from "bfd.h", however, until that + happens, hack around it by including "config.h" and <curses.h> + first. */ -#include "defs.h" -#include <ctype.h> -#include "gdb_string.h" -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif +#include "config.h" #ifdef HAVE_CURSES_H #include <curses.h> @@ -33,12 +37,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <term.h> #endif +#include "defs.h" +#include "gdb_assert.h" +#include <ctype.h> +#include "gdb_string.h" +#include "event-top.h" + +#ifdef __GO32__ +#include <pc.h> +#endif + /* SunOS's curses.h has a '#define reg register' in it. Thank you Sun. */ #ifdef reg #undef reg #endif -#include "signals.h" +#include <signal.h> #include "gdbcmd.h" #include "serial.h" #include "bfd.h" @@ -48,52 +62,76 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "language.h" #include "annotate.h" +#include "inferior.h" /* for signed_pointer_to_address */ + +#include <sys/param.h> /* For MAXPATHLEN */ + #include <readline/readline.h> +#ifdef USE_MMALLOC +#include "mmalloc.h" +#endif + +#ifdef NEED_DECLARATION_MALLOC +extern PTR malloc (); +#endif +#ifdef NEED_DECLARATION_REALLOC +extern PTR realloc (); +#endif +#ifdef NEED_DECLARATION_FREE +extern void free (); +#endif +/* Actually, we'll never have the decl, since we don't define _GNU_SOURCE. */ +#if defined(HAVE_CANONICALIZE_FILE_NAME) \ + && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) +extern char *canonicalize_file_name (const char *); +#endif + +#undef XMALLOC +#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) + /* readline defines this. */ #undef savestring -void (*error_begin_hook) PARAMS ((void)); +void (*error_begin_hook) (void); + +/* Holds the last error message issued by gdb */ + +static struct ui_file *gdb_lasterr; /* Prototypes for local functions */ -static void vfprintf_maybe_filtered PARAMS ((GDB_FILE *, const char *, - va_list, int)); +static void vfprintf_maybe_filtered (struct ui_file *, const char *, + va_list, int); -static void fputs_maybe_filtered PARAMS ((const char *, GDB_FILE *, int)); +static void fputs_maybe_filtered (const char *, struct ui_file *, int); #if defined (USE_MMALLOC) && !defined (NO_MMCHECK) -static void malloc_botch PARAMS ((void)); +static void malloc_botch (void); #endif -static void -fatal_dump_core PARAMS((char *, ...)); - -static void -prompt_for_continue PARAMS ((void)); +static void prompt_for_continue (void); -static void -set_width_command PARAMS ((char *, int, struct cmd_list_element *)); +static void set_width_command (char *, int, struct cmd_list_element *); -static void -set_width PARAMS ((void)); - -/* If this definition isn't overridden by the header files, assume - that isatty and fileno exist on this system. */ -#ifndef ISATTY -#define ISATTY(FP) (isatty (fileno (FP))) -#endif - -#ifndef GDB_FILE_ISATTY -#define GDB_FILE_ISATTY(GDB_FILE_PTR) (gdb_file_isatty(GDB_FILE_PTR)) -#endif +static void set_width (void); /* Chain of cleanup actions established with make_cleanup, to be executed if an error happens. */ -static struct cleanup *cleanup_chain; /* cleaned up after a failed command */ -static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */ -static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */ +static struct cleanup *cleanup_chain; /* cleaned up after a failed command */ +static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */ +static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */ +static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */ +/* cleaned up on each error from within an execution command */ +static struct cleanup *exec_error_cleanup_chain; + +/* Pointer to what is left to do for an execution command after the + target stops. Used only in asynchronous mode, by targets that + support async execution. The finish and until commands use it. So + does the target extended-remote command. */ +struct continuation *cmd_continuation; +struct continuation *intermediate_continuation; /* Nonzero if we have job control. */ @@ -146,43 +184,101 @@ char *quit_pre_print; char *warning_pre_print = "\nwarning: "; int pagination_enabled = 1; - + /* Add a new cleanup to the cleanup_chain, and return the previous chain pointer to be passed later to do_cleanups or discard_cleanups. Args are FUNCTION to clean up with, and ARG to pass to it. */ struct cleanup * -make_cleanup (function, arg) - void (*function) PARAMS ((PTR)); - PTR arg; +make_cleanup (make_cleanup_ftype *function, void *arg) { - return make_my_cleanup (&cleanup_chain, function, arg); + return make_my_cleanup (&cleanup_chain, function, arg); } struct cleanup * -make_final_cleanup (function, arg) - void (*function) PARAMS ((PTR)); - PTR arg; +make_final_cleanup (make_cleanup_ftype *function, void *arg) { - return make_my_cleanup (&final_cleanup_chain, function, arg); + return make_my_cleanup (&final_cleanup_chain, function, arg); } + +struct cleanup * +make_run_cleanup (make_cleanup_ftype *function, void *arg) +{ + return make_my_cleanup (&run_cleanup_chain, function, arg); +} + struct cleanup * -make_run_cleanup (function, arg) - void (*function) PARAMS ((PTR)); - PTR arg; +make_exec_cleanup (make_cleanup_ftype *function, void *arg) { - return make_my_cleanup (&run_cleanup_chain, function, arg); + return make_my_cleanup (&exec_cleanup_chain, function, arg); } + struct cleanup * -make_my_cleanup (pmy_chain, function, arg) - struct cleanup **pmy_chain; - void (*function) PARAMS ((PTR)); - PTR arg; +make_exec_error_cleanup (make_cleanup_ftype *function, void *arg) +{ + return make_my_cleanup (&exec_error_cleanup_chain, function, arg); +} + +static void +do_freeargv (void *arg) +{ + freeargv ((char **) arg); +} + +struct cleanup * +make_cleanup_freeargv (char **arg) +{ + return make_my_cleanup (&cleanup_chain, do_freeargv, arg); +} + +static void +do_bfd_close_cleanup (void *arg) +{ + bfd_close (arg); +} + +struct cleanup * +make_cleanup_bfd_close (bfd *abfd) +{ + return make_cleanup (do_bfd_close_cleanup, abfd); +} + +static void +do_close_cleanup (void *arg) +{ + int *fd = arg; + close (*fd); + xfree (fd); +} + +struct cleanup * +make_cleanup_close (int fd) +{ + int *saved_fd = xmalloc (sizeof (fd)); + *saved_fd = fd; + return make_cleanup (do_close_cleanup, saved_fd); +} + +static void +do_ui_file_delete (void *arg) +{ + ui_file_delete (arg); +} + +struct cleanup * +make_cleanup_ui_file_delete (struct ui_file *arg) +{ + return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg); +} + +struct cleanup * +make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg) { register struct cleanup *new - = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); register struct cleanup *old_chain = *pmy_chain; new->next = *pmy_chain; @@ -197,37 +293,45 @@ make_my_cleanup (pmy_chain, function, arg) until we get back to the point OLD_CHAIN in the cleanup_chain. */ void -do_cleanups (old_chain) - register struct cleanup *old_chain; +do_cleanups (register struct cleanup *old_chain) { - do_my_cleanups (&cleanup_chain, old_chain); + do_my_cleanups (&cleanup_chain, old_chain); } void -do_final_cleanups (old_chain) - register struct cleanup *old_chain; +do_final_cleanups (register struct cleanup *old_chain) { - do_my_cleanups (&final_cleanup_chain, old_chain); + do_my_cleanups (&final_cleanup_chain, old_chain); } void -do_run_cleanups (old_chain) - register struct cleanup *old_chain; +do_run_cleanups (register struct cleanup *old_chain) { - do_my_cleanups (&run_cleanup_chain, old_chain); + do_my_cleanups (&run_cleanup_chain, old_chain); } void -do_my_cleanups (pmy_chain, old_chain) - register struct cleanup **pmy_chain; - register struct cleanup *old_chain; +do_exec_cleanups (register struct cleanup *old_chain) +{ + do_my_cleanups (&exec_cleanup_chain, old_chain); +} + +void +do_exec_error_cleanups (register struct cleanup *old_chain) +{ + do_my_cleanups (&exec_error_cleanup_chain, old_chain); +} + +void +do_my_cleanups (register struct cleanup **pmy_chain, + register struct cleanup *old_chain) { register struct cleanup *ptr; while ((ptr = *pmy_chain) != old_chain) { *pmy_chain = ptr->next; /* Do this first incase recursion */ (*ptr->function) (ptr->arg); - free (ptr); + xfree (ptr); } } @@ -235,48 +339,50 @@ do_my_cleanups (pmy_chain, old_chain) until we get back to the point OLD_CHAIN in the cleanup_chain. */ void -discard_cleanups (old_chain) - register struct cleanup *old_chain; +discard_cleanups (register struct cleanup *old_chain) +{ + discard_my_cleanups (&cleanup_chain, old_chain); +} + +void +discard_final_cleanups (register struct cleanup *old_chain) { - discard_my_cleanups (&cleanup_chain, old_chain); + discard_my_cleanups (&final_cleanup_chain, old_chain); } void -discard_final_cleanups (old_chain) - register struct cleanup *old_chain; +discard_exec_error_cleanups (register struct cleanup *old_chain) { - discard_my_cleanups (&final_cleanup_chain, old_chain); + discard_my_cleanups (&exec_error_cleanup_chain, old_chain); } void -discard_my_cleanups (pmy_chain, old_chain) - register struct cleanup **pmy_chain; - register struct cleanup *old_chain; +discard_my_cleanups (register struct cleanup **pmy_chain, + register struct cleanup *old_chain) { register struct cleanup *ptr; while ((ptr = *pmy_chain) != old_chain) { *pmy_chain = ptr->next; - free ((PTR)ptr); + xfree (ptr); } } /* Set the cleanup_chain to 0, and return the old cleanup chain. */ struct cleanup * -save_cleanups () +save_cleanups (void) { - return save_my_cleanups (&cleanup_chain); + return save_my_cleanups (&cleanup_chain); } struct cleanup * -save_final_cleanups () +save_final_cleanups (void) { - return save_my_cleanups (&final_cleanup_chain); + return save_my_cleanups (&final_cleanup_chain); } struct cleanup * -save_my_cleanups (pmy_chain) - struct cleanup **pmy_chain; +save_my_cleanups (struct cleanup **pmy_chain) { struct cleanup *old_chain = *pmy_chain; @@ -286,23 +392,19 @@ save_my_cleanups (pmy_chain) /* Restore the cleanup chain from a previously saved chain. */ void -restore_cleanups (chain) - struct cleanup *chain; +restore_cleanups (struct cleanup *chain) { - restore_my_cleanups (&cleanup_chain, chain); + restore_my_cleanups (&cleanup_chain, chain); } void -restore_final_cleanups (chain) - struct cleanup *chain; +restore_final_cleanups (struct cleanup *chain) { - restore_my_cleanups (&final_cleanup_chain, chain); + restore_my_cleanups (&final_cleanup_chain, chain); } void -restore_my_cleanups (pmy_chain, chain) - struct cleanup **pmy_chain; - struct cleanup *chain; +restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain) { *pmy_chain = chain; } @@ -310,16 +412,23 @@ restore_my_cleanups (pmy_chain, chain) /* This function is useful for cleanups. Do - foo = xmalloc (...); - old_chain = make_cleanup (free_current_contents, &foo); + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); to arrange to free the object thus allocated. */ void -free_current_contents (location) - char **location; +free_current_contents (void *ptr) { - free (*location); + void **location = ptr; + if (location == NULL) + internal_error (__FILE__, __LINE__, + "free_current_contents: NULL pointer"); + if (*location != NULL) + { + xfree (*location); + *location = NULL; + } } /* Provide a known function that does nothing, to use as a base for @@ -331,29 +440,157 @@ free_current_contents (location) /* ARGSUSED */ void -null_cleanup (arg) - PTR arg; +null_cleanup (void *arg) +{ +} + +/* Add a continuation to the continuation list, the global list + cmd_continuation. The new continuation will be added at the front.*/ +void +add_continuation (void (*continuation_hook) (struct continuation_arg *), + struct continuation_arg *arg_list) +{ + struct continuation *continuation_ptr; + + continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation)); + continuation_ptr->continuation_hook = continuation_hook; + continuation_ptr->arg_list = arg_list; + continuation_ptr->next = cmd_continuation; + cmd_continuation = continuation_ptr; +} + +/* Walk down the cmd_continuation list, and execute all the + continuations. There is a problem though. In some cases new + continuations may be added while we are in the middle of this + loop. If this happens they will be added in the front, and done + before we have a chance of exhausting those that were already + there. We need to then save the beginning of the list in a pointer + and do the continuations from there on, instead of using the + global beginning of list as our iteration pointer.*/ +void +do_all_continuations (void) +{ + struct continuation *continuation_ptr; + struct continuation *saved_continuation; + + /* Copy the list header into another pointer, and set the global + list header to null, so that the global list can change as a side + effect of invoking the continuations and the processing of + the preexisting continuations will not be affected. */ + continuation_ptr = cmd_continuation; + cmd_continuation = NULL; + + /* Work now on the list we have set aside. */ + while (continuation_ptr) + { + (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); + saved_continuation = continuation_ptr; + continuation_ptr = continuation_ptr->next; + xfree (saved_continuation); + } +} + +/* Walk down the cmd_continuation list, and get rid of all the + continuations. */ +void +discard_all_continuations (void) +{ + struct continuation *continuation_ptr; + + while (cmd_continuation) + { + continuation_ptr = cmd_continuation; + cmd_continuation = continuation_ptr->next; + xfree (continuation_ptr); + } +} + +/* Add a continuation to the continuation list, the global list + intermediate_continuation. The new continuation will be added at the front.*/ +void +add_intermediate_continuation (void (*continuation_hook) + (struct continuation_arg *), + struct continuation_arg *arg_list) +{ + struct continuation *continuation_ptr; + + continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation)); + continuation_ptr->continuation_hook = continuation_hook; + continuation_ptr->arg_list = arg_list; + continuation_ptr->next = intermediate_continuation; + intermediate_continuation = continuation_ptr; +} + +/* Walk down the cmd_continuation list, and execute all the + continuations. There is a problem though. In some cases new + continuations may be added while we are in the middle of this + loop. If this happens they will be added in the front, and done + before we have a chance of exhausting those that were already + there. We need to then save the beginning of the list in a pointer + and do the continuations from there on, instead of using the + global beginning of list as our iteration pointer.*/ +void +do_all_intermediate_continuations (void) +{ + struct continuation *continuation_ptr; + struct continuation *saved_continuation; + + /* Copy the list header into another pointer, and set the global + list header to null, so that the global list can change as a side + effect of invoking the continuations and the processing of + the preexisting continuations will not be affected. */ + continuation_ptr = intermediate_continuation; + intermediate_continuation = NULL; + + /* Work now on the list we have set aside. */ + while (continuation_ptr) + { + (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); + saved_continuation = continuation_ptr; + continuation_ptr = continuation_ptr->next; + xfree (saved_continuation); + } +} + +/* Walk down the cmd_continuation list, and get rid of all the + continuations. */ +void +discard_all_intermediate_continuations (void) { + struct continuation *continuation_ptr; + + while (intermediate_continuation) + { + continuation_ptr = intermediate_continuation; + intermediate_continuation = continuation_ptr->next; + xfree (continuation_ptr); + } } -/* Print a warning message. Way to use this is to call warning_begin, - output the warning message (use unfiltered output to gdb_stderr), - ending in a newline. There is not currently a warning_end that you - call afterwards, but such a thing might be added if it is useful - for a GUI to separate warning messages from other output. - FIXME: Why do warnings use unfiltered output and errors filtered? - Is this anything other than a historical accident? */ +/* Print a warning message. The first argument STRING is the warning + message, used as an fprintf format string, the second is the + va_list of arguments for that string. A warning is unfiltered (not + paginated) so that the user does not need to page through each + screen full of warnings when there are lots of them. */ void -warning_begin () +vwarning (const char *string, va_list args) { - target_terminal_ours (); - wrap_here(""); /* Force out any buffered output */ - gdb_flush (gdb_stdout); - if (warning_pre_print) - fprintf_unfiltered (gdb_stderr, warning_pre_print); + if (warning_hook) + (*warning_hook) (string, args); + else + { + target_terminal_ours (); + wrap_here (""); /* Force out any buffered output */ + gdb_flush (gdb_stdout); + if (warning_pre_print) + fprintf_unfiltered (gdb_stderr, warning_pre_print); + vfprintf_unfiltered (gdb_stderr, string, args); + fprintf_unfiltered (gdb_stderr, "\n"); + va_end (args); + } } /* Print a warning message. @@ -362,210 +599,183 @@ warning_begin () The primary difference between warnings and errors is that a warning does not force the return to command level. */ -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -warning (const char *string, ...) -#else -warning (va_alist) - va_dcl -#endif +warning (const char *string,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, string); -#else - char *string; - - va_start (args); - string = va_arg (args, char *); -#endif - if (warning_hook) - (*warning_hook) (string, args); - else - { - warning_begin (); - vfprintf_unfiltered (gdb_stderr, string, args); - fprintf_unfiltered (gdb_stderr, "\n"); - va_end (args); - } -} - -/* Start the printing of an error message. Way to use this is to call - this, output the error message (use filtered output to gdb_stderr - (FIXME: Some callers, like memory_error, use gdb_stdout)), ending - in a newline, and then call return_to_top_level (RETURN_ERROR). - error() provides a convenient way to do this for the special case - that the error message can be formatted with a single printf call, - but this is more general. */ -void -error_begin () -{ - if (error_begin_hook) - error_begin_hook (); - - target_terminal_ours (); - wrap_here (""); /* Force out any buffered output */ - gdb_flush (gdb_stdout); - - annotate_error_begin (); - - if (error_pre_print) - fprintf_filtered (gdb_stderr, error_pre_print); + vwarning (string, args); + va_end (args); } /* Print an error message and return to command level. The first argument STRING is the error message, used as a fprintf string, and the remaining args are passed as arguments to it. */ -/* VARARGS */ NORETURN void -#ifdef ANSI_PROTOTYPES -error (const char *string, ...) -#else -error (va_alist) - va_dcl -#endif +verror (const char *string, va_list args) { - va_list args; -#ifdef ANSI_PROTOTYPES - va_start (args, string); -#else - va_start (args); -#endif - if (error_hook) - (*error_hook) (); - else - { - error_begin (); -#ifdef ANSI_PROTOTYPES - vfprintf_filtered (gdb_stderr, string, args); -#else - { - char *string1; - - string1 = va_arg (args, char *); - vfprintf_filtered (gdb_stderr, string1, args); - } -#endif - fprintf_filtered (gdb_stderr, "\n"); - va_end (args); - return_to_top_level (RETURN_ERROR); - } + struct ui_file *tmp_stream = mem_fileopen (); + make_cleanup_ui_file_delete (tmp_stream); + vfprintf_unfiltered (tmp_stream, string, args); + error_stream (tmp_stream); } - -/* Print an error message and exit reporting failure. - This is for a error that we cannot continue from. - The arguments are printed a la printf. - - This function cannot be declared volatile (NORETURN) in an - ANSI environment because exit() is not declared volatile. */ - -/* VARARGS */ NORETURN void -#ifdef ANSI_PROTOTYPES -fatal (char *string, ...) -#else -fatal (va_alist) - va_dcl -#endif +error (const char *string,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, string); -#else - char *string; - va_start (args); - string = va_arg (args, char *); -#endif - fprintf_unfiltered (gdb_stderr, "\ngdb: "); - vfprintf_unfiltered (gdb_stderr, string, args); - fprintf_unfiltered (gdb_stderr, "\n"); + verror (string, args); va_end (args); - exit (1); } -/* Print an error message and exit, dumping core. - The arguments are printed a la printf (). */ - -/* VARARGS */ static void -#ifdef ANSI_PROTOTYPES -fatal_dump_core (char *string, ...) -#else -fatal_dump_core (va_alist) - va_dcl -#endif +do_write (void *data, const char *buffer, long length_buffer) { - va_list args; -#ifdef ANSI_PROTOTYPES - va_start (args, string); -#else - char *string; + ui_file_write (data, buffer, length_buffer); +} - va_start (args); - string = va_arg (args, char *); -#endif - /* "internal error" is always correct, since GDB should never dump - core, no matter what the input. */ - fprintf_unfiltered (gdb_stderr, "\ngdb internal error: "); - vfprintf_unfiltered (gdb_stderr, string, args); - fprintf_unfiltered (gdb_stderr, "\n"); - va_end (args); +NORETURN void +error_stream (struct ui_file *stream) +{ + if (error_begin_hook) + error_begin_hook (); + + /* Copy the stream into the GDB_LASTERR buffer. */ + ui_file_rewind (gdb_lasterr); + ui_file_put (stream, do_write, gdb_lasterr); + + /* Write the message plus any error_pre_print to gdb_stderr. */ + target_terminal_ours (); + wrap_here (""); /* Force out any buffered output */ + gdb_flush (gdb_stdout); + annotate_error_begin (); + if (error_pre_print) + fprintf_filtered (gdb_stderr, error_pre_print); + ui_file_put (stream, do_write, gdb_stderr); + fprintf_filtered (gdb_stderr, "\n"); - signal (SIGQUIT, SIG_DFL); - kill (getpid (), SIGQUIT); - /* We should never get here, but just in case... */ - exit (1); + throw_exception (RETURN_ERROR); } -/* The strerror() function can return NULL for errno values that are - out of range. Provide a "safe" version that always returns a - printable string. */ +/* Get the last error message issued by gdb */ char * -safe_strerror (errnum) - int errnum; +error_last_message (void) { - char *msg; - static char buf[32]; + long len; + return ui_file_xstrdup (gdb_lasterr, &len); +} + +/* This is to be called by main() at the very beginning */ - if ((msg = strerror (errnum)) == NULL) +void +error_init (void) +{ + gdb_lasterr = mem_fileopen (); +} + +/* Print a message reporting an internal error. Ask the user if they + want to continue, dump core, or just exit. */ + +NORETURN void +internal_verror (const char *file, int line, + const char *fmt, va_list ap) +{ + static char msg[] = "Internal GDB error: recursive internal error.\n"; + static int dejavu = 0; + int quit_p; + int dump_core_p; + + /* don't allow infinite error recursion. */ + switch (dejavu) { - sprintf (buf, "(undocumented errno %d)", errnum); - msg = buf; + case 0: + dejavu = 1; + break; + case 1: + dejavu = 2; + fputs_unfiltered (msg, gdb_stderr); + abort (); /* NOTE: GDB has only three calls to abort(). */ + default: + dejavu = 3; + write (STDERR_FILENO, msg, sizeof (msg)); + exit (1); } - return (msg); + + /* Try to get the message out */ + target_terminal_ours (); + fprintf_unfiltered (gdb_stderr, "%s:%d: gdb-internal-error: ", file, line); + vfprintf_unfiltered (gdb_stderr, fmt, ap); + fputs_unfiltered ("\n", gdb_stderr); + + /* Default (yes/batch case) is to quit GDB. When in batch mode this + lessens the likelhood of GDB going into an infinate loop. */ + quit_p = query ("\ +An internal GDB error was detected. This may make further\n\ +debugging unreliable. Quit this debugging session? "); + + /* Default (yes/batch case) is to dump core. This leaves a GDB + dropping so that it is easier to see that something went wrong to + GDB. */ + dump_core_p = query ("\ +Create a core file containing the current state of GDB? "); + + if (quit_p) + { + if (dump_core_p) + abort (); /* NOTE: GDB has only three calls to abort(). */ + else + exit (1); + } + else + { + if (dump_core_p) + { + if (fork () == 0) + abort (); /* NOTE: GDB has only three calls to abort(). */ + } + } + + dejavu = 0; + throw_exception (RETURN_ERROR); } -/* The strsignal() function can return NULL for signal values that are +NORETURN void +internal_error (const char *file, int line, const char *string, ...) +{ + va_list ap; + va_start (ap, string); + + internal_verror (file, line, string, ap); + va_end (ap); +} + +/* The strerror() function can return NULL for errno values that are out of range. Provide a "safe" version that always returns a printable string. */ char * -safe_strsignal (signo) - int signo; +safe_strerror (int errnum) { char *msg; static char buf[32]; - if ((msg = strsignal (signo)) == NULL) + if ((msg = strerror (errnum)) == NULL) { - sprintf (buf, "(undocumented signal %d)", signo); + sprintf (buf, "(undocumented errno %d)", errnum); msg = buf; } return (msg); } - /* Print the system error message for errno, and also mention STRING as the file name for which the error was encountered. Then return to command level. */ NORETURN void -perror_with_name (string) - char *string; +perror_with_name (const char *string) { char *err; char *combined; @@ -582,16 +792,14 @@ perror_with_name (string) bfd_set_error (bfd_error_no_error); errno = 0; - error ("%s.", combined); + error ("%s.", combined); } /* Print the system error message for ERRCODE, and also mention STRING as the file name for which the error was encountered. */ void -print_sys_errmsg (string, errcode) - char *string; - int errcode; +print_sys_errmsg (const char *string, int errcode) { char *err; char *combined; @@ -611,9 +819,9 @@ print_sys_errmsg (string, errcode) /* Control C eventually causes this to be called, at a convenient time. */ void -quit () +quit (void) { - serial_t gdb_stdout_serial = serial_fdopen (1); + struct serial *gdb_stdout_serial = serial_fdopen (1); target_terminal_ours (); @@ -623,15 +831,15 @@ quit () too): */ /* 1. The _filtered buffer. */ - wrap_here ((char *)0); + wrap_here ((char *) 0); /* 2. The stdio buffer. */ gdb_flush (gdb_stdout); gdb_flush (gdb_stderr); /* 3. The system-level buffer. */ - SERIAL_DRAIN_OUTPUT (gdb_stdout_serial); - SERIAL_UN_FDOPEN (gdb_stdout_serial); + serial_drain_output (gdb_stdout_serial); + serial_un_fdopen (gdb_stdout_serial); annotate_error_begin (); @@ -639,82 +847,26 @@ quit () if (quit_pre_print) fprintf_unfiltered (gdb_stderr, quit_pre_print); +#ifdef __MSDOS__ + /* No steenking SIGINT will ever be coming our way when the + program is resumed. Don't lie. */ + fprintf_unfiltered (gdb_stderr, "Quit\n"); +#else if (job_control - /* If there is no terminal switching for this target, then we can't - possibly get screwed by the lack of job control. */ + /* If there is no terminal switching for this target, then we can't + possibly get screwed by the lack of job control. */ || current_target.to_terminal_ours == NULL) fprintf_unfiltered (gdb_stderr, "Quit\n"); else fprintf_unfiltered (gdb_stderr, - "Quit (expect signal SIGINT when the program is resumed)\n"); - return_to_top_level (RETURN_QUIT); -} - - -#if defined(__GO32__) - -/* In the absence of signals, poll keyboard for a quit. - Called from #define QUIT pollquit() in xm-go32.h. */ - -void -notice_quit() -{ - if (kbhit ()) - switch (getkey ()) - { - case 1: - quit_flag = 1; - break; - case 2: - immediate_quit = 2; - break; - default: - /* We just ignore it */ - /* FIXME!! Don't think this actually works! */ - fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n"); - break; - } -} - -#elif defined(_MSC_VER) /* should test for wingdb instead? */ - -/* - * Windows translates all keyboard and mouse events - * into a message which is appended to the message - * queue for the process. - */ - -void notice_quit() -{ - int k = win32pollquit(); - if (k == 1) - quit_flag = 1; - else if (k == 2) - immediate_quit = 1; -} - -#else /* !defined(__GO32__) && !defined(_MSC_VER) */ - -void notice_quit() -{ - /* Done by signals */ -} - -#endif /* !defined(__GO32__) && !defined(_MSC_VER) */ - -void -pollquit() -{ - notice_quit (); - if (quit_flag || immediate_quit) - quit (); + "Quit (expect signal SIGINT when the program is resumed)\n"); +#endif + throw_exception (RETURN_QUIT); } /* Control C comes here */ - void -request_quit (signo) - int signo; +request_quit (int signo) { quit_flag = 1; /* Restore the signal handler. Harmless with BSD-style signals, needed @@ -725,68 +877,61 @@ request_quit (signo) #ifdef REQUEST_QUIT REQUEST_QUIT; #else - if (immediate_quit) + if (immediate_quit) quit (); #endif } - /* Memory management stuff (malloc friends). */ -/* Make a substitute size_t for non-ANSI compilers. */ - -#ifndef HAVE_STDDEF_H -#ifndef size_t -#define size_t unsigned int -#endif -#endif - #if !defined (USE_MMALLOC) -PTR -mmalloc (md, size) - PTR md; - size_t size; +/* NOTE: These must use PTR so that their definition matches the + declaration found in "mmalloc.h". */ + +static void * +mmalloc (void *md, size_t size) { - return malloc (size); + return malloc (size); /* NOTE: GDB's only call to malloc() */ } -PTR -mrealloc (md, ptr, size) - PTR md; - PTR ptr; - size_t size; +static void * +mrealloc (void *md, void *ptr, size_t size) { - if (ptr == 0) /* Guard against old realloc's */ - return malloc (size); + if (ptr == 0) /* Guard against old realloc's */ + return mmalloc (md, size); else - return realloc (ptr, size); + return realloc (ptr, size); /* NOTE: GDB's only call to ralloc() */ } -void -mfree (md, ptr) - PTR md; - PTR ptr; +static void * +mcalloc (void *md, size_t number, size_t size) { - free (ptr); + return calloc (number, size); /* NOTE: GDB's only call to calloc() */ } -#endif /* USE_MMALLOC */ +static void +mfree (void *md, void *ptr) +{ + free (ptr); /* NOTE: GDB's only call to free() */ +} + +#endif /* USE_MMALLOC */ #if !defined (USE_MMALLOC) || defined (NO_MMCHECK) void -init_malloc (md) - PTR md; +init_malloc (void *md) { } #else /* Have mmalloc and want corruption checking */ static void -malloc_botch () +malloc_botch (void) { - fatal_dump_core ("Memory corruption"); + fprintf_unfiltered (gdb_stderr, "Memory corruption\n"); + internal_error (__FILE__, __LINE__, "failed internal consistency check"); } /* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified @@ -808,14 +953,13 @@ malloc_botch () #endif void -init_malloc (md) - PTR md; +init_malloc (void *md) { if (!mmcheckf (md, malloc_botch, MMCHECK_FORCE)) { /* Don't use warning(), which relies on current_target being set - to something other than dummy_target, until after - initialize_all_files(). */ + to something other than dummy_target, until after + initialize_all_files(). */ fprintf_unfiltered (gdb_stderr, "warning: failed to install memory consistency checks; "); @@ -832,96 +976,171 @@ init_malloc (md) memory requested in SIZE. */ NORETURN void -nomem (size) - long size; +nomem (long size) { if (size > 0) { - fatal ("virtual memory exhausted: can't allocate %ld bytes.", size); + internal_error (__FILE__, __LINE__, + "virtual memory exhausted: can't allocate %ld bytes.", size); } else { - fatal ("virtual memory exhausted."); + internal_error (__FILE__, __LINE__, + "virtual memory exhausted."); } } -/* Like mmalloc but get error if no storage available, and protect against - the caller wanting to allocate zero bytes. Whether to return NULL for - a zero byte request, or translate the request into a request for one - byte of zero'd storage, is a religious issue. */ +/* The xmmalloc() family of memory management routines. -PTR -xmmalloc (md, size) - PTR md; - long size; + These are are like the mmalloc() family except that they implement + consistent semantics and guard against typical memory management + problems: if a malloc fails, an internal error is thrown; if + free(NULL) is called, it is ignored; if *alloc(0) is called, NULL + is returned. + + All these routines are implemented using the mmalloc() family. */ + +void * +xmmalloc (void *md, size_t size) { - register PTR val; + void *val; if (size == 0) { val = NULL; } - else if ((val = mmalloc (md, size)) == NULL) + else { - nomem (size); + val = mmalloc (md, size); + if (val == NULL) + nomem (size); } return (val); } -/* Like mrealloc but get error if no storage available. */ - -PTR -xmrealloc (md, ptr, size) - PTR md; - PTR ptr; - long size; +void * +xmrealloc (void *md, void *ptr, size_t size) { - register PTR val; + void *val; - if (ptr != NULL) + if (size == 0) { - val = mrealloc (md, ptr, size); + if (ptr != NULL) + mfree (md, ptr); + val = NULL; } else { - val = mmalloc (md, size); + if (ptr != NULL) + { + val = mrealloc (md, ptr, size); + } + else + { + val = mmalloc (md, size); + } + if (val == NULL) + { + nomem (size); + } } - if (val == NULL) + return (val); +} + +void * +xmcalloc (void *md, size_t number, size_t size) +{ + void *mem; + if (number == 0 || size == 0) + mem = NULL; + else { - nomem (size); + mem = mcalloc (md, number, size); + if (mem == NULL) + nomem (number * size); } - return (val); + return mem; +} + +void +xmfree (void *md, void *ptr) +{ + if (ptr != NULL) + mfree (md, ptr); } -/* Like malloc but get error if no storage available, and protect against - the caller wanting to allocate zero bytes. */ +/* The xmalloc() (libiberty.h) family of memory management routines. + + These are like the ISO-C malloc() family except that they implement + consistent semantics and guard against typical memory management + problems. See xmmalloc() above for further information. + + All these routines are wrappers to the xmmalloc() family. */ + +/* NOTE: These are declared using PTR to ensure consistency with + "libiberty.h". xfree() is GDB local. */ PTR -USE_FROM_LIBIBERTY_NOW_xmalloc (size) - size_t size; +xmalloc (size_t size) { - return (xmmalloc ((PTR) NULL, size)); + return xmmalloc (NULL, size); } -/* Like mrealloc but get error if no storage available. */ +PTR +xrealloc (PTR ptr, size_t size) +{ + return xmrealloc (NULL, ptr, size); +} PTR -USE_FROM_LIBIBERTY_NOW_xrealloc (ptr, size) - PTR ptr; - size_t size; +xcalloc (size_t number, size_t size) { - return (xmrealloc ((PTR) NULL, ptr, size)); + return xmcalloc (NULL, number, size); } +void +xfree (void *ptr) +{ + xmfree (NULL, ptr); +} + +/* Like asprintf/vasprintf but get an internal_error if the call + fails. */ + +void +xasprintf (char **ret, const char *format, ...) +{ + va_list args; + va_start (args, format); + xvasprintf (ret, format, args); + va_end (args); +} + +void +xvasprintf (char **ret, const char *format, va_list ap) +{ + int status = vasprintf (ret, format, ap); + /* NULL could be returned due to a memory allocation problem; a + badly format string; or something else. */ + if ((*ret) == NULL) + internal_error (__FILE__, __LINE__, + "vasprintf returned NULL buffer (errno %d)", + errno); + /* A negative status with a non-NULL buffer shouldn't never + happen. But to be sure. */ + if (status < 0) + internal_error (__FILE__, __LINE__, + "vasprintf call failed (errno %d)", + errno); +} + + /* My replacement for the read system call. Used like `read' but keeps going if `read' returns too soon. */ int -myread (desc, addr, len) - int desc; - char *addr; - int len; +myread (int desc, char *addr, int len) { register int val; int orglen = len; @@ -944,9 +1163,7 @@ myread (desc, addr, len) Uses malloc to get the space. Returns the address of the copy. */ char * -savestring (ptr, size) - const char *ptr; - int size; +savestring (const char *ptr, size_t size) { register char *p = (char *) xmalloc (size + 1); memcpy (p, ptr, size); @@ -955,10 +1172,7 @@ savestring (ptr, size) } char * -msavestring (md, ptr, size) - PTR md; - const char *ptr; - int size; +msavestring (void *md, const char *ptr, size_t size) { register char *p = (char *) xmmalloc (md, size + 1); memcpy (p, ptr, size); @@ -966,59 +1180,29 @@ msavestring (md, ptr, size) return p; } -/* The "const" is so it compiles under DGUX (which prototypes strsave - in <string.h>. FIXME: This should be named "xstrsave", shouldn't it? - Doesn't real strsave return NULL if out of memory? */ char * -strsave (ptr) - const char *ptr; -{ - return savestring (ptr, strlen (ptr)); -} - -char * -mstrsave (md, ptr) - PTR md; - const char *ptr; +mstrsave (void *md, const char *ptr) { return (msavestring (md, ptr, strlen (ptr))); } void -print_spaces (n, file) - register int n; - register GDB_FILE *file; +print_spaces (register int n, register struct ui_file *file) { - if (file->ts_streamtype == astring) - { - char *p; - - gdb_file_adjust_strbuf (n, file); - p = file->ts_strbuf + strlen (file->ts_strbuf); - - memset (p, ' ', n); - p[n] = '\000'; - } - else - { - while (n-- > 0) - fputc (' ', file->ts_filestream); - } + fputs_unfiltered (n_spaces (n), file); } /* Print a host address. */ void -gdb_print_address (addr, stream) - PTR addr; - GDB_FILE *stream; +gdb_print_host_address (void *addr, struct ui_file *stream) { /* We could use the %p conversion specifier to fprintf if we had any way of knowing whether this host supports it. But the following should work on the Alpha and on 32 bit machines. */ - fprintf_filtered (stream, "0x%lx", (unsigned long)addr); + fprintf_filtered (stream, "0x%lx", (unsigned long) addr); } /* Ask user a y-or-n question and return 1 iff answer is yes. @@ -1028,25 +1212,14 @@ gdb_print_address (addr, stream) /* VARARGS */ int -#ifdef ANSI_PROTOTYPES -query (char *ctlstr, ...) -#else -query (va_alist) - va_dcl -#endif +query (const char *ctlstr,...) { va_list args; register int answer; register int ans2; int retval; -#ifdef ANSI_PROTOTYPES va_start (args, ctlstr); -#else - char *ctlstr; - va_start (args); - ctlstr = va_arg (args, char *); -#endif if (query_hook) { @@ -1056,11 +1229,6 @@ query (va_alist) /* Automatically answer "yes" if input is not from a terminal. */ if (!input_from_terminal_p ()) return 1; -#ifdef MPW - /* FIXME Automatically answer "yes" if called from MacGDB. */ - if (mac_app) - return 1; -#endif /* MPW */ while (1) { @@ -1076,49 +1244,24 @@ query (va_alist) if (annotation_level > 1) printf_filtered ("\n\032\032query\n"); -#ifdef MPW - /* If not in MacGDB, move to a new line so the entered line doesn't - have a prompt on the front of it. */ - if (!mac_app) - fputs_unfiltered ("\n", gdb_stdout); -#endif /* MPW */ - - wrap_here(""); + wrap_here (""); gdb_flush (gdb_stdout); -#if defined(TUI) - if (!tui_version || cmdWin == tuiWinWithFocus()) -#endif - answer = fgetc (stdin); -#if defined(TUI) - else - - answer = (unsigned char)tuiBufferGetc(); - -#endif + answer = fgetc (stdin); clearerr (stdin); /* in case of C-d */ if (answer == EOF) /* C-d */ - { + { retval = 1; break; } /* Eat rest of input line, to EOF or newline */ - if ((answer != '\n') || (tui_version && answer != '\r')) - do + if (answer != '\n') + do { -#if defined(TUI) - if (!tui_version || cmdWin == tuiWinWithFocus()) -#endif - ans2 = fgetc (stdin); -#if defined(TUI) - else - - ans2 = (unsigned char)tuiBufferGetc(); -#endif + ans2 = fgetc (stdin); clearerr (stdin); } - while (ans2 != EOF && ans2 != '\n' && ans2 != '\r'); - TUIDO(((TuiOpaqueFuncPtr)tui_vStartNewLines, 1)); + while (ans2 != EOF && ans2 != '\n' && ans2 != '\r'); if (answer >= 'a') answer -= 040; @@ -1139,8 +1282,8 @@ query (va_alist) printf_filtered ("\n\032\032post-query\n"); return retval; } - + /* Parse a C escape sequence. STRING_PTR points to a variable containing a pointer to the string to parse. That pointer should point to the character after the \. That pointer @@ -1157,8 +1300,7 @@ query (va_alist) after the zeros. A value of 0 does not mean end of string. */ int -parse_escape (string_ptr) - char **string_ptr; +parse_escape (char **string_ptr) { register int c = *(*string_ptr)++; switch (c) @@ -1191,7 +1333,7 @@ parse_escape (string_ptr) if (c == '?') return 0177; return (c & 0200) | (c & 037); - + case '0': case '1': case '2': @@ -1228,86 +1370,86 @@ parse_escape (string_ptr) be call for printing things which are independent of the language of the program being debugged. */ -void -gdb_printchar (c, stream, quoter) - register int c; - GDB_FILE *stream; - int quoter; +static void +printchar (int c, void (*do_fputs) (const char *, struct ui_file *), + void (*do_fprintf) (struct ui_file *, const char *, ...), + struct ui_file *stream, int quoter) { c &= 0xFF; /* Avoid sign bit follies */ - if ( c < 0x20 || /* Low control chars */ - (c >= 0x7F && c < 0xA0) || /* DEL, High controls */ - (sevenbit_strings && c >= 0x80)) { /* high order bit set */ - switch (c) - { - case '\n': - fputs_filtered ("\\n", stream); - break; - case '\b': - fputs_filtered ("\\b", stream); - break; - case '\t': - fputs_filtered ("\\t", stream); - break; - case '\f': - fputs_filtered ("\\f", stream); - break; - case '\r': - fputs_filtered ("\\r", stream); - break; - case '\033': - fputs_filtered ("\\e", stream); - break; - case '\007': - fputs_filtered ("\\a", stream); - break; - default: - fprintf_filtered (stream, "\\%.3o", (unsigned int) c); - break; - } - } else { - if (c == '\\' || c == quoter) - fputs_filtered ("\\", stream); - fprintf_filtered (stream, "%c", c); - } + if (c < 0x20 || /* Low control chars */ + (c >= 0x7F && c < 0xA0) || /* DEL, High controls */ + (sevenbit_strings && c >= 0x80)) + { /* high order bit set */ + switch (c) + { + case '\n': + do_fputs ("\\n", stream); + break; + case '\b': + do_fputs ("\\b", stream); + break; + case '\t': + do_fputs ("\\t", stream); + break; + case '\f': + do_fputs ("\\f", stream); + break; + case '\r': + do_fputs ("\\r", stream); + break; + case '\033': + do_fputs ("\\e", stream); + break; + case '\007': + do_fputs ("\\a", stream); + break; + default: + do_fprintf (stream, "\\%.3o", (unsigned int) c); + break; + } + } + else + { + if (c == '\\' || c == quoter) + do_fputs ("\\", stream); + do_fprintf (stream, "%c", c); + } } +/* Print the character C on STREAM as part of the contents of a + literal string whose delimiter is QUOTER. Note that these routines + should only be call for printing things which are independent of + the language of the program being debugged. */ +void +fputstr_filtered (const char *str, int quoter, struct ui_file *stream) +{ + while (*str) + printchar (*str++, fputs_filtered, fprintf_filtered, stream, quoter); +} - -static char * hexlate = "0123456789abcdef" ; -int fmthex(inbuf,outbuff,length,linelength) - unsigned char * inbuf ; - unsigned char * outbuff; - int length; - int linelength; +void +fputstr_unfiltered (const char *str, int quoter, struct ui_file *stream) { - unsigned char byte , nib ; - int outlength = 0 ; + while (*str) + printchar (*str++, fputs_unfiltered, fprintf_unfiltered, stream, quoter); +} - while (length) - { - if (outlength >= linelength) break ; - byte = *inbuf ; - inbuf++ ; - nib = byte >> 4 ; - *outbuff++ = hexlate[nib] ; - nib = byte &0x0f ; - *outbuff++ = hexlate[nib] ; - *outbuff++ = ' ' ; - length-- ; - outlength += 3 ; - } - *outbuff = '\0' ; /* null terminate our output line */ - return outlength ; +void +fputstrn_unfiltered (const char *str, int n, int quoter, struct ui_file *stream) +{ + int i; + for (i = 0; i < n; i++) + printchar (str[i], fputs_unfiltered, fprintf_unfiltered, stream, quoter); } + /* Number of lines per page or UINT_MAX if paging is disabled. */ static unsigned int lines_per_page; -/* Number of chars per line or UNIT_MAX is line folding is disabled. */ +/* Number of chars per line or UINT_MAX if line folding is disabled. */ static unsigned int chars_per_line; /* Current count of lines printed on this page, chars on this line. */ static unsigned int lines_printed, chars_printed; @@ -1335,67 +1477,62 @@ static char *wrap_indent; /* Column number on the screen where wrap_buffer begins, or 0 if wrapping is not in effect. */ static int wrap_column; - + /* Inialize the lines and chars per page */ void -init_page_info() +init_page_info (void) { #if defined(TUI) - if (tui_version && m_winPtrNotNull(cmdWin)) - { - lines_per_page = cmdWin->generic.height; - chars_per_line = cmdWin->generic.width; - } - else + if (!tui_get_command_dimension (&chars_per_line, &lines_per_page)) #endif { /* These defaults will be used if we are unable to get the correct values from termcap. */ #if defined(__GO32__) - lines_per_page = ScreenRows(); - chars_per_line = ScreenCols(); -#else + lines_per_page = ScreenRows (); + chars_per_line = ScreenCols (); +#else lines_per_page = 24; chars_per_line = 80; -#if !defined (MPW) && !defined (_WIN32) +#if !defined (_WIN32) /* No termcap under MPW, although might be cool to do something by looking at worksheet or console window sizes. */ /* Initialize the screen height and width from termcap. */ { - char *termtype = getenv ("TERM"); + char *termtype = getenv ("TERM"); - /* Positive means success, nonpositive means failure. */ - int status; + /* Positive means success, nonpositive means failure. */ + int status; - /* 2048 is large enough for all known terminals, according to the - GNU termcap manual. */ - char term_buffer[2048]; + /* 2048 is large enough for all known terminals, according to the + GNU termcap manual. */ + char term_buffer[2048]; - if (termtype) - { + if (termtype) + { status = tgetent (term_buffer, termtype); if (status > 0) { - int val; + int val; int running_in_emacs = getenv ("EMACS") != NULL; - - val = tgetnum ("li"); - if (val >= 0 && !running_in_emacs) - lines_per_page = val; - else - /* The number of lines per page is not mentioned + + val = tgetnum ("li"); + if (val >= 0 && !running_in_emacs) + lines_per_page = val; + else + /* The number of lines per page is not mentioned in the terminal description. This probably means that paging is not useful (e.g. emacs shell window), so disable paging. */ - lines_per_page = UINT_MAX; - - val = tgetnum ("co"); - if (val >= 0) - chars_per_line = val; + lines_per_page = UINT_MAX; + + val = tgetnum ("co"); + if (val >= 0) + chars_per_line = val; } - } + } } #endif /* MPW */ @@ -1406,17 +1543,17 @@ init_page_info() #endif #endif /* If the output is not a terminal, don't paginate it. */ - if (!GDB_FILE_ISATTY (gdb_stdout)) - lines_per_page = UINT_MAX; - } /* the command_line_version */ - set_width(); + if (!ui_file_isatty (gdb_stdout)) + lines_per_page = UINT_MAX; + } /* the command_line_version */ + set_width (); } static void -set_width() +set_width (void) { if (chars_per_line == 0) - init_page_info(); + init_page_info (); if (!wrap_buffer) { @@ -1425,15 +1562,12 @@ set_width() } else wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2); - wrap_pointer = wrap_buffer; /* Start it at the beginning */ + wrap_pointer = wrap_buffer; /* Start it at the beginning */ } /* ARGSUSED */ -static void -set_width_command (args, from_tty, c) - char *args; - int from_tty; - struct cmd_list_element *c; +static void +set_width_command (char *args, int from_tty, struct cmd_list_element *c) { set_width (); } @@ -1442,7 +1576,7 @@ set_width_command (args, from_tty, c) to continue by pressing RETURN. */ static void -prompt_for_continue () +prompt_for_continue (void) { char *ignore; char cont_prompt[120]; @@ -1482,8 +1616,13 @@ prompt_for_continue () while (*p == ' ' || *p == '\t') ++p; if (p[0] == 'q') - request_quit (SIGINT); - free (ignore); + { + if (!event_loop_p) + request_quit (SIGINT); + else + async_request_quit (0); + } + xfree (ignore); } immediate_quit--; @@ -1497,7 +1636,7 @@ prompt_for_continue () /* Reinitialize filter; ie. tell it to reset to original values. */ void -reinitialize_more_filter () +reinitialize_more_filter (void) { lines_printed = 0; chars_printed = 0; @@ -1525,12 +1664,11 @@ reinitialize_more_filter () used to force out output from the wrap_buffer. */ void -wrap_here(indent) - char *indent; +wrap_here (char *indent) { /* This should have been allocated, but be paranoid anyway. */ if (!wrap_buffer) - abort (); + internal_error (__FILE__, __LINE__, "failed internal consistency check"); if (wrap_buffer[0]) { @@ -1539,7 +1677,7 @@ wrap_here(indent) } wrap_pointer = wrap_buffer; wrap_buffer[0] = '\0'; - if (chars_per_line == UINT_MAX) /* No line overflow checking */ + if (chars_per_line == UINT_MAX) /* No line overflow checking */ { wrap_column = 0; } @@ -1566,7 +1704,7 @@ wrap_here(indent) line. Otherwise do nothing. */ void -begin_line () +begin_line (void) { if (chars_printed > 0) { @@ -1574,122 +1712,6 @@ begin_line () } } -int -gdb_file_isatty (stream) - GDB_FILE *stream; -{ - - if (stream->ts_streamtype == afile) - return (isatty(fileno(stream->ts_filestream))); - else return 0; -} - -GDB_FILE * -gdb_file_init_astring (n) - int n; -{ - GDB_FILE *tmpstream; - - tmpstream = xmalloc (sizeof(GDB_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 - tmpstream->ts_strbuf = NULL; - tmpstream->ts_buflen = n; - - return tmpstream; -} - -void -gdb_file_deallocate (streamptr) - GDB_FILE **streamptr; -{ - GDB_FILE *tmpstream; - - tmpstream = *streamptr; - if ((tmpstream->ts_streamtype == astring) && - (tmpstream->ts_strbuf != NULL)) - { - free (tmpstream->ts_strbuf); - } - - free (tmpstream); - *streamptr = NULL; -} - -char * -gdb_file_get_strbuf (stream) - GDB_FILE *stream; -{ - 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 -gdb_file_adjust_strbuf (n, stream) - int n; - GDB_FILE *stream; -{ - int non_null_chars; - - 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); - } -} - -GDB_FILE * -gdb_fopen (name, mode) - char * name; - char * mode; -{ - int gdb_file_size; - GDB_FILE *tmp; - - gdb_file_size = sizeof(GDB_FILE); - tmp = (GDB_FILE *) xmalloc (gdb_file_size); - tmp->ts_streamtype = afile; - tmp->ts_filestream = fopen (name, mode); - tmp->ts_strbuf = NULL; - tmp->ts_buflen = 0; - - return tmp; -} - -void -gdb_flush (stream) - GDB_FILE *stream; -{ - if (flush_hook - && (stream == gdb_stdout - || stream == gdb_stderr)) - { - flush_hook (stream); - return; - } - - fflush (stream->ts_filestream); -} - -void -gdb_fclose(streamptr) - GDB_FILE **streamptr; -{ - GDB_FILE *tmpstream; - - tmpstream = *streamptr; - fclose (tmpstream->ts_filestream); - gdb_file_deallocate (streamptr); -} /* Like fputs but if FILTER is true, pause after every screenful. @@ -1705,10 +1727,8 @@ gdb_fclose(streamptr) routine should not be called when cleanups are not in place. */ static void -fputs_maybe_filtered (linebuffer, stream, filter) - const char *linebuffer; - GDB_FILE *stream; - int filter; +fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream, + int filter) { const char *lineptr; @@ -1716,8 +1736,8 @@ fputs_maybe_filtered (linebuffer, stream, filter) return; /* Don't do any filtering if it is disabled. */ - if (stream != gdb_stdout - || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)) + if ((stream != gdb_stdout) || !pagination_enabled + || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)) { fputs_unfiltered (linebuffer, stream); return; @@ -1726,7 +1746,7 @@ fputs_maybe_filtered (linebuffer, stream, filter) /* Go through and output each character. Show line extension when this is necessary; prompt user for new page when this is necessary. */ - + lineptr = linebuffer; while (*lineptr) { @@ -1746,7 +1766,7 @@ fputs_maybe_filtered (linebuffer, stream, filter) fputc_unfiltered ('\t', stream); /* Shifting right by 3 produces the number of tab stops we have already passed, and then adding one and - shifting left 3 advances to the next tab stop. */ + shifting left 3 advances to the next tab stop. */ chars_printed = ((chars_printed >> 3) + 1) << 3; lineptr++; } @@ -1755,11 +1775,11 @@ fputs_maybe_filtered (linebuffer, stream, filter) if (wrap_column) *wrap_pointer++ = *lineptr; else - fputc_unfiltered (*lineptr, stream); + fputc_unfiltered (*lineptr, stream); chars_printed++; lineptr++; } - + if (chars_printed >= chars_per_line) { unsigned int save_chars = chars_printed; @@ -1767,8 +1787,8 @@ fputs_maybe_filtered (linebuffer, stream, filter) chars_printed = 0; lines_printed++; /* If we aren't actually wrapping, don't output newline -- - if chars_per_line is right, we probably just overflowed - anyway; if it's wrong, let us keep going. */ + if chars_per_line is right, we probably just overflowed + anyway; if it's wrong, let us keep going. */ if (wrap_column) fputc_unfiltered ('\n', stream); @@ -1780,8 +1800,8 @@ fputs_maybe_filtered (linebuffer, stream, filter) if (wrap_column) { fputs_unfiltered (wrap_indent, stream); - *wrap_pointer = '\0'; /* Null-terminate saved stuff */ - fputs_unfiltered (wrap_buffer, stream); /* and eject it */ + *wrap_pointer = '\0'; /* Null-terminate saved stuff */ + fputs_unfiltered (wrap_buffer, stream); /* and eject it */ /* FIXME, this strlen is what prevents wrap_indent from containing tabs. However, if we recurse to print it and count its chars, we risk trouble if wrap_indent is @@ -1789,18 +1809,18 @@ fputs_maybe_filtered (linebuffer, stream, filter) Note also that this can set chars_printed > chars_per_line if we are printing a long string. */ chars_printed = strlen (wrap_indent) - + (save_chars - wrap_column); + + (save_chars - wrap_column); wrap_pointer = wrap_buffer; /* Reset buffer */ wrap_buffer[0] = '\0'; - wrap_column = 0; /* And disable fancy wrap */ - } + wrap_column = 0; /* And disable fancy wrap */ + } } } if (*lineptr == '\n') { chars_printed = 0; - wrap_here ((char *)0); /* Spit out chars, cancel further wraps */ + wrap_here ((char *) 0); /* Spit out chars, cancel further wraps */ lines_printed++; fputc_unfiltered ('\n', stream); lineptr++; @@ -1809,42 +1829,38 @@ fputs_maybe_filtered (linebuffer, stream, filter) } void -fputs_filtered (linebuffer, stream) - const char *linebuffer; - GDB_FILE *stream; +fputs_filtered (const char *linebuffer, struct ui_file *stream) { fputs_maybe_filtered (linebuffer, stream, 1); } int -putchar_unfiltered (c) - int c; +putchar_unfiltered (int c) { - char buf[2]; - - buf[0] = c; - buf[1] = 0; - fputs_unfiltered (buf, gdb_stdout); + char buf = c; + ui_file_write (gdb_stdout, &buf, 1); return c; } +/* Write character C to gdb_stdout using GDB's paging mechanism and return C. + May return nonlocally. */ + int -fputc_unfiltered (c, stream) - int c; - GDB_FILE * stream; +putchar_filtered (int c) { - char buf[2]; + return fputc_filtered (c, gdb_stdout); +} - buf[0] = c; - buf[1] = 0; - fputs_unfiltered (buf, stream); +int +fputc_unfiltered (int c, struct ui_file *stream) +{ + char buf = c; + ui_file_write (stream, &buf, 1); return c; } int -fputc_filtered (c, stream) - int c; - GDB_FILE * stream; +fputc_filtered (int c, struct ui_file *stream) { char buf[2]; @@ -1858,10 +1874,7 @@ fputc_filtered (c, stream) characters in printable fashion. */ void -puts_debug (prefix, string, suffix) - char *prefix; - char *string; - char *suffix; +puts_debug (char *prefix, char *string, char *suffix) { int ch; @@ -1876,18 +1889,18 @@ puts_debug (prefix, string, suffix) /* If the prefix is changing, print the previous suffix, a new line, and the new prefix. */ - if ((return_p || (strcmp(prev_prefix, prefix) != 0)) && !new_line) + if ((return_p || (strcmp (prev_prefix, prefix) != 0)) && !new_line) { - fputs_unfiltered (prev_suffix, gdb_stderr); - fputs_unfiltered ("\n", gdb_stderr); - fputs_unfiltered (prefix, gdb_stderr); + fputs_unfiltered (prev_suffix, gdb_stdlog); + fputs_unfiltered ("\n", gdb_stdlog); + fputs_unfiltered (prefix, gdb_stdlog); } /* Print prefix if we printed a newline during the previous call. */ if (new_line) { new_line = 0; - fputs_unfiltered (prefix, gdb_stderr); + fputs_unfiltered (prefix, gdb_stdlog); } prev_prefix = prefix; @@ -1897,24 +1910,38 @@ puts_debug (prefix, string, suffix) while ((ch = *string++) != '\0') { switch (ch) - { + { default: if (isprint (ch)) - fputc_unfiltered (ch, gdb_stderr); + fputc_unfiltered (ch, gdb_stdlog); else - fprintf_unfiltered (gdb_stderr, "\\x%02x", ch & 0xff); + fprintf_unfiltered (gdb_stdlog, "\\x%02x", ch & 0xff); break; - case '\\': fputs_unfiltered ("\\\\", gdb_stderr); break; - case '\b': fputs_unfiltered ("\\b", gdb_stderr); break; - case '\f': fputs_unfiltered ("\\f", gdb_stderr); break; - case '\n': new_line = 1; - fputs_unfiltered ("\\n", gdb_stderr); break; - case '\r': fputs_unfiltered ("\\r", gdb_stderr); break; - case '\t': fputs_unfiltered ("\\t", gdb_stderr); break; - case '\v': fputs_unfiltered ("\\v", gdb_stderr); break; - } + case '\\': + fputs_unfiltered ("\\\\", gdb_stdlog); + break; + case '\b': + fputs_unfiltered ("\\b", gdb_stdlog); + break; + case '\f': + fputs_unfiltered ("\\f", gdb_stdlog); + break; + case '\n': + new_line = 1; + fputs_unfiltered ("\\n", gdb_stdlog); + break; + case '\r': + fputs_unfiltered ("\\r", gdb_stdlog); + break; + case '\t': + fputs_unfiltered ("\\t", gdb_stdlog); + break; + case '\v': + fputs_unfiltered ("\\v", gdb_stdlog); + break; + } return_p = ch == '\r'; } @@ -1922,8 +1949,8 @@ puts_debug (prefix, string, suffix) /* Print suffix if we printed a newline. */ if (new_line) { - fputs_unfiltered (suffix, gdb_stderr); - fputs_unfiltered ("\n", gdb_stderr); + fputs_unfiltered (suffix, gdb_stdlog); + fputs_unfiltered ("\n", gdb_stdlog); } } @@ -1943,116 +1970,63 @@ puts_debug (prefix, string, suffix) called when cleanups are not in place. */ static void -vfprintf_maybe_filtered (stream, format, args, filter) - GDB_FILE *stream; - const char *format; - va_list args; - int filter; +vfprintf_maybe_filtered (struct ui_file *stream, const char *format, + va_list args, int filter) { char *linebuffer; struct cleanup *old_cleanups; - vasprintf (&linebuffer, format, args); - if (linebuffer == NULL) - { - fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr); - exit (1); - } - old_cleanups = make_cleanup (free, linebuffer); + xvasprintf (&linebuffer, format, args); + old_cleanups = make_cleanup (xfree, linebuffer); fputs_maybe_filtered (linebuffer, stream, filter); do_cleanups (old_cleanups); } void -vfprintf_filtered (stream, format, args) - GDB_FILE *stream; - const char *format; - va_list args; +vfprintf_filtered (struct ui_file *stream, const char *format, va_list args) { vfprintf_maybe_filtered (stream, format, args, 1); } void -vfprintf_unfiltered (stream, format, args) - GDB_FILE *stream; - const char *format; - va_list args; +vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args) { char *linebuffer; struct cleanup *old_cleanups; - vasprintf (&linebuffer, format, args); - if (linebuffer == NULL) - { - fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr); - exit (1); - } - old_cleanups = make_cleanup (free, linebuffer); + xvasprintf (&linebuffer, format, args); + old_cleanups = make_cleanup (xfree, linebuffer); fputs_unfiltered (linebuffer, stream); do_cleanups (old_cleanups); } void -vprintf_filtered (format, args) - const char *format; - va_list args; +vprintf_filtered (const char *format, va_list args) { vfprintf_maybe_filtered (gdb_stdout, format, args, 1); } void -vprintf_unfiltered (format, args) - const char *format; - va_list args; +vprintf_unfiltered (const char *format, va_list args) { vfprintf_unfiltered (gdb_stdout, format, args); } -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -fprintf_filtered (GDB_FILE *stream, const char *format, ...) -#else -fprintf_filtered (va_alist) - va_dcl -#endif +fprintf_filtered (struct ui_file * stream, const char *format,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - GDB_FILE *stream; - char *format; - - va_start (args); - stream = va_arg (args, GDB_FILE *); - format = va_arg (args, char *); -#endif vfprintf_filtered (stream, format, args); va_end (args); } -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -fprintf_unfiltered (GDB_FILE *stream, const char *format, ...) -#else -fprintf_unfiltered (va_alist) - va_dcl -#endif +fprintf_unfiltered (struct ui_file * stream, const char *format,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - GDB_FILE *stream; - char *format; - - va_start (args); - stream = va_arg (args, GDB_FILE *); - format = va_arg (args, char *); -#endif vfprintf_unfiltered (stream, format, args); va_end (args); } @@ -2060,28 +2034,11 @@ fprintf_unfiltered (va_alist) /* Like fprintf_filtered, but prints its result indented. Called as fprintfi_filtered (spaces, stream, format, ...); */ -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -fprintfi_filtered (int spaces, GDB_FILE *stream, const char *format, ...) -#else -fprintfi_filtered (va_alist) - va_dcl -#endif +fprintfi_filtered (int spaces, struct ui_file * stream, const char *format,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - int spaces; - GDB_FILE *stream; - char *format; - - va_start (args); - spaces = va_arg (args, int); - stream = va_arg (args, GDB_FILE *); - format = va_arg (args, char *); -#endif print_spaces_filtered (spaces, stream); vfprintf_filtered (stream, format, args); @@ -2089,47 +2046,21 @@ fprintfi_filtered (va_alist) } -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -printf_filtered (const char *format, ...) -#else -printf_filtered (va_alist) - va_dcl -#endif +printf_filtered (const char *format,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - char *format; - - va_start (args); - format = va_arg (args, char *); -#endif vfprintf_filtered (gdb_stdout, format, args); va_end (args); } -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -printf_unfiltered (const char *format, ...) -#else -printf_unfiltered (va_alist) - va_dcl -#endif +printf_unfiltered (const char *format,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - char *format; - - va_start (args); - format = va_arg (args, char *); -#endif vfprintf_unfiltered (gdb_stdout, format, args); va_end (args); } @@ -2137,26 +2068,11 @@ printf_unfiltered (va_alist) /* Like printf_filtered, but prints it's result indented. Called as printfi_filtered (spaces, format, ...); */ -/* VARARGS */ void -#ifdef ANSI_PROTOTYPES -printfi_filtered (int spaces, const char *format, ...) -#else -printfi_filtered (va_alist) - va_dcl -#endif +printfi_filtered (int spaces, const char *format,...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - int spaces; - char *format; - - va_start (args); - spaces = va_arg (args, int); - format = va_arg (args, char *); -#endif print_spaces_filtered (spaces, gdb_stdout); vfprintf_filtered (gdb_stdout, format, args); va_end (args); @@ -2168,15 +2084,13 @@ printfi_filtered (va_alist) This one doesn't, and had better not! */ void -puts_filtered (string) - const char *string; +puts_filtered (const char *string) { fputs_filtered (string, gdb_stdout); } void -puts_unfiltered (string) - const char *string; +puts_unfiltered (const char *string) { fputs_unfiltered (string, gdb_stdout); } @@ -2184,19 +2098,18 @@ puts_unfiltered (string) /* Return a pointer to N spaces and a null. The pointer is good until the next call to here. */ char * -n_spaces (n) - int n; +n_spaces (int n) { - register char *t; - static char *spaces; - static int max_spaces; + char *t; + static char *spaces = 0; + static int max_spaces = -1; if (n > max_spaces) { if (spaces) - free (spaces); - spaces = (char *) xmalloc (n+1); - for (t = spaces+n; t != spaces;) + xfree (spaces); + spaces = (char *) xmalloc (n + 1); + for (t = spaces + n; t != spaces;) *--t = ' '; spaces[n] = '\0'; max_spaces = n; @@ -2207,9 +2120,7 @@ n_spaces (n) /* Print N spaces. */ void -print_spaces_filtered (n, stream) - int n; - GDB_FILE *stream; +print_spaces_filtered (int n, struct ui_file *stream) { fputs_filtered (n_spaces (n), stream); } @@ -2222,11 +2133,8 @@ print_spaces_filtered (n, stream) demangling is off, the name is printed in its "raw" form. */ void -fprintf_symbol_filtered (stream, name, lang, arg_mode) - GDB_FILE *stream; - char *name; - enum language lang; - int arg_mode; +fprintf_symbol_filtered (struct ui_file *stream, char *name, enum language lang, + int arg_mode) { char *demangled; @@ -2257,7 +2165,7 @@ fprintf_symbol_filtered (stream, name, lang, arg_mode) fputs_filtered (demangled ? demangled : name, stream); if (demangled != NULL) { - free (demangled); + xfree (demangled); } } } @@ -2266,16 +2174,14 @@ fprintf_symbol_filtered (stream, name, lang, arg_mode) /* Do a strcmp() type operation on STRING1 and STRING2, ignoring any differences in whitespace. Returns 0 if they match, non-zero if they don't (slightly different than strcmp()'s range of return values). - + As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO". This "feature" is useful when searching for matching C++ function names (such as if the user types 'break FOO', where FOO is a mangled C++ function). */ int -strcmp_iw (string1, string2) - const char *string1; - const char *string2; +strcmp_iw (const char *string1, const char *string2) { while ((*string1 != '\0') && (*string2 != '\0')) { @@ -2299,109 +2205,102 @@ strcmp_iw (string1, string2) } return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0'); } - + /* -** subsetCompare() -** Answer whether stringToCompare is a full or partial match to -** templateString. The partial match must be in sequence starting -** at index 0. -*/ + ** subset_compare() + ** Answer whether string_to_compare is a full or partial match to + ** template_string. The partial match must be in sequence starting + ** at index 0. + */ int -#ifdef _STDC__ -subsetCompare( - char *stringToCompare, - char *templateString) -#else -subsetCompare(stringToCompare, templateString) - char *stringToCompare; - char *templateString; -#endif -{ - int match = 0; - - if (templateString != (char *)NULL && stringToCompare != (char *)NULL && - strlen(stringToCompare) <= strlen(templateString)) - match = (strncmp(templateString, - stringToCompare, - strlen(stringToCompare)) == 0); - - return match; -} /* subsetCompare */ +subset_compare (char *string_to_compare, char *template_string) +{ + int match; + if (template_string != (char *) NULL && string_to_compare != (char *) NULL && + strlen (string_to_compare) <= strlen (template_string)) + match = (strncmp (template_string, + string_to_compare, + strlen (string_to_compare)) == 0); + else + match = 0; + return match; +} -void pagination_on_command(arg, from_tty) - char *arg; - int from_tty; +static void pagination_on_command (char *arg, int from_tty); +static void +pagination_on_command (char *arg, int from_tty) { pagination_enabled = 1; } -void pagination_off_command(arg, from_tty) - char *arg; - int from_tty; +static void pagination_on_command (char *arg, int from_tty); +static void +pagination_off_command (char *arg, int from_tty) { pagination_enabled = 0; } - + void -initialize_utils () +initialize_utils (void) { struct cmd_list_element *c; - c = add_set_cmd ("width", class_support, var_uinteger, - (char *)&chars_per_line, - "Set number of characters gdb thinks are in a line.", - &setlist); + c = add_set_cmd ("width", class_support, var_uinteger, + (char *) &chars_per_line, + "Set number of characters gdb thinks are in a line.", + &setlist); add_show_from_set (c, &showlist); - c->function.sfunc = set_width_command; + set_cmd_sfunc (c, set_width_command); add_show_from_set (add_set_cmd ("height", class_support, - var_uinteger, (char *)&lines_per_page, + var_uinteger, (char *) &lines_per_page, "Set number of lines gdb thinks are in a page.", &setlist), &showlist); - + init_page_info (); /* If the output is not a terminal, don't paginate it. */ - if (!GDB_FILE_ISATTY (gdb_stdout)) + if (!ui_file_isatty (gdb_stdout)) lines_per_page = UINT_MAX; - set_width_command ((char *)NULL, 0, c); + set_width_command ((char *) NULL, 0, c); add_show_from_set - (add_set_cmd ("demangle", class_support, var_boolean, - (char *)&demangle, - "Set demangling of encoded C++ names when displaying symbols.", + (add_set_cmd ("demangle", class_support, var_boolean, + (char *) &demangle, + "Set demangling of encoded C++ names when displaying symbols.", &setprintlist), &showprintlist); add_show_from_set (add_set_cmd ("pagination", class_support, - var_boolean, (char *)&pagination_enabled, + var_boolean, (char *) &pagination_enabled, "Set state of pagination.", &setlist), &showlist); + if (xdb_commands) { - add_com("am", class_support, pagination_on_command, - "Enable pagination"); - add_com("sm", class_support, pagination_off_command, - "Disable pagination"); + add_com ("am", class_support, pagination_on_command, + "Enable pagination"); + add_com ("sm", class_support, pagination_off_command, + "Disable pagination"); } add_show_from_set - (add_set_cmd ("sevenbit-strings", class_support, var_boolean, - (char *)&sevenbit_strings, - "Set printing of 8-bit characters in strings as \\nnn.", + (add_set_cmd ("sevenbit-strings", class_support, var_boolean, + (char *) &sevenbit_strings, + "Set printing of 8-bit characters in strings as \\nnn.", &setprintlist), &showprintlist); add_show_from_set - (add_set_cmd ("asm-demangle", class_support, var_boolean, - (char *)&asm_demangle, - "Set demangling of C++ names in disassembly listings.", + (add_set_cmd ("asm-demangle", class_support, var_boolean, + (char *) &asm_demangle, + "Set demangling of C++ names in disassembly listings.", &setprintlist), &showprintlist); } @@ -2409,526 +2308,258 @@ initialize_utils () /* Machine specific function to handle SIGWINCH signal. */ #ifdef SIGWINCH_HANDLER_BODY - SIGWINCH_HANDLER_BODY +SIGWINCH_HANDLER_BODY #endif - -/* Support for converting target fp numbers into host DOUBLEST format. */ - -/* XXX - This code should really be in libiberty/floatformat.c, however - configuration issues with libiberty made this very difficult to do in the - available time. */ - -#include "floatformat.h" -#include <math.h> /* ldexp */ - -/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not - going to bother with trying to muck around with whether it is defined in - a system header, what we do if not, etc. */ -#define FLOATFORMAT_CHAR_BIT 8 - -static unsigned long get_field PARAMS ((unsigned char *, - enum floatformat_byteorders, - unsigned int, - unsigned int, - unsigned int)); - -/* Extract a field which starts at START and is LEN bytes long. DATA and - TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ -static unsigned long -get_field (data, order, total_len, start, len) - unsigned char *data; - enum floatformat_byteorders order; - unsigned int total_len; - unsigned int start; - unsigned int len; -{ - unsigned long result; - unsigned int cur_byte; - int cur_bitshift; - - /* Start at the least significant part of the field. */ - cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; - cur_bitshift = - ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; - result = *(data + cur_byte) >> (-cur_bitshift); - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; - /* Move towards the most significant part of the field. */ - while (cur_bitshift < len) - { - if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) - /* This is the last byte; zero out the bits which are not part of - this field. */ - result |= - (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) - << cur_bitshift; - else - result |= *(data + cur_byte) << cur_bitshift; - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; - } - return result; -} - -/* Convert from FMT to a DOUBLEST. - FROM is the address of the extended float. - Store the DOUBLEST in *TO. */ - -void -floatformat_to_doublest (fmt, from, to) - const struct floatformat *fmt; - char *from; - DOUBLEST *to; -{ - unsigned char *ufrom = (unsigned char *)from; - DOUBLEST dto; - long exponent; - unsigned long mant; - unsigned int mant_bits, mant_off; - int mant_bits_left; - int special_exponent; /* It's a NaN, denorm or zero */ - - /* If the mantissa bits are not contiguous from one end of the - mantissa to the other, we need to make a private copy of the - source bytes that is in the right order since the unpacking - algorithm assumes that the bits are contiguous. - - Swap the bytes individually rather than accessing them through - "long *" since we have no guarantee that they start on a long - alignment, and also sizeof(long) for the host could be different - than sizeof(long) for the target. FIXME: Assumes sizeof(long) - for the target is 4. */ - - if (fmt -> byteorder == floatformat_littlebyte_bigword) - { - static unsigned char *newfrom; - unsigned char *swapin, *swapout; - int longswaps; - - longswaps = fmt -> totalsize / FLOATFORMAT_CHAR_BIT; - longswaps >>= 3; - - if (newfrom == NULL) - { - newfrom = (unsigned char *) xmalloc (fmt -> totalsize); - } - swapout = newfrom; - swapin = ufrom; - ufrom = newfrom; - while (longswaps-- > 0) - { - /* This is ugly, but efficient */ - *swapout++ = swapin[4]; - *swapout++ = swapin[5]; - *swapout++ = swapin[6]; - *swapout++ = swapin[7]; - *swapout++ = swapin[0]; - *swapout++ = swapin[1]; - *swapout++ = swapin[2]; - *swapout++ = swapin[3]; - swapin += 8; - } - } +/* print routines to handle variable size regs, etc. */ - exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, - fmt->exp_start, fmt->exp_len); - /* Note that if exponent indicates a NaN, we can't really do anything useful - (not knowing if the host has NaN's, or how to build one). So it will - end up as an infinity or something close; that is OK. */ - - mant_bits_left = fmt->man_len; - mant_off = fmt->man_start; - dto = 0.0; - - special_exponent = exponent == 0 || exponent == fmt->exp_nan; - -/* Don't bias zero's, denorms or NaNs. */ - if (!special_exponent) - exponent -= fmt->exp_bias; +/* temporary storage using circular buffer */ +#define NUMCELLS 16 +#define CELLSIZE 32 +static char * +get_cell (void) +{ + static char buf[NUMCELLS][CELLSIZE]; + static int cell = 0; + if (++cell >= NUMCELLS) + cell = 0; + return buf[cell]; +} - /* Build the result algebraically. Might go infinite, underflow, etc; - who cares. */ +int +strlen_paddr (void) +{ + return (TARGET_ADDR_BIT / 8 * 2); +} -/* If this format uses a hidden bit, explicitly add it in now. Otherwise, - increment the exponent by one to account for the integer bit. */ +char * +paddr (CORE_ADDR addr) +{ + return phex (addr, TARGET_ADDR_BIT / 8); +} - if (!special_exponent) - if (fmt->intbit == floatformat_intbit_no) - dto = ldexp (1.0, exponent); - else - exponent++; +char * +paddr_nz (CORE_ADDR addr) +{ + return phex_nz (addr, TARGET_ADDR_BIT / 8); +} - while (mant_bits_left > 0) +static void +decimal2str (char *paddr_str, char *sign, ULONGEST addr) +{ + /* steal code from valprint.c:print_decimal(). Should this worry + about the real size of addr as the above does? */ + unsigned long temp[3]; + int i = 0; + do { - mant_bits = min (mant_bits_left, 32); - - mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, - mant_off, mant_bits); - - dto += ldexp ((double)mant, exponent - mant_bits); - exponent -= mant_bits; - mant_off += mant_bits; - mant_bits_left -= mant_bits; + temp[i] = addr % (1000 * 1000 * 1000); + addr /= (1000 * 1000 * 1000); + i++; } - - /* Negate it if negative. */ - if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) - dto = -dto; - *to = dto; -} - -static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders, - unsigned int, - unsigned int, - unsigned int, - unsigned long)); - -/* Set a field which starts at START and is LEN bytes long. DATA and - TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ -static void -put_field (data, order, total_len, start, len, stuff_to_put) - unsigned char *data; - enum floatformat_byteorders order; - unsigned int total_len; - unsigned int start; - unsigned int len; - unsigned long stuff_to_put; -{ - unsigned int cur_byte; - int cur_bitshift; - - /* Start at the least significant part of the field. */ - cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; - cur_bitshift = - ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; - *(data + cur_byte) &= - ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); - *(data + cur_byte) |= - (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; - - /* Move towards the most significant part of the field. */ - while (cur_bitshift < len) + while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); + switch (i) { - if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) - { - /* This is the last byte. */ - *(data + cur_byte) &= - ~((1 << (len - cur_bitshift)) - 1); - *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); - } - else - *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) - & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; + case 1: + sprintf (paddr_str, "%s%lu", + sign, temp[0]); + break; + case 2: + sprintf (paddr_str, "%s%lu%09lu", + sign, temp[1], temp[0]); + break; + case 3: + sprintf (paddr_str, "%s%lu%09lu%09lu", + sign, temp[2], temp[1], temp[0]); + break; + default: + internal_error (__FILE__, __LINE__, "failed internal consistency check"); } } -#ifdef HAVE_LONG_DOUBLE -/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR. - The range of the returned value is >= 0.5 and < 1.0. This is equivalent to - frexp, but operates on the long double data type. */ - -static long double ldfrexp PARAMS ((long double value, int *eptr)); - -static long double -ldfrexp (value, eptr) - long double value; - int *eptr; +char * +paddr_u (CORE_ADDR addr) { - long double tmp; - int exp; - - /* Unfortunately, there are no portable functions for extracting the exponent - of a long double, so we have to do it iteratively by multiplying or dividing - by two until the fraction is between 0.5 and 1.0. */ - - if (value < 0.0l) - value = -value; - - tmp = 1.0l; - exp = 0; - - if (value >= tmp) /* Value >= 1.0 */ - while (value >= tmp) - { - tmp *= 2.0l; - exp++; - } - else if (value != 0.0l) /* Value < 1.0 and > 0.0 */ - { - while (value < tmp) - { - tmp /= 2.0l; - exp--; - } - tmp *= 2.0l; - exp++; - } - - *eptr = exp; - return value/tmp; + char *paddr_str = get_cell (); + decimal2str (paddr_str, "", addr); + return paddr_str; } -#endif /* HAVE_LONG_DOUBLE */ - -/* The converse: convert the DOUBLEST *FROM to an extended float - and store where TO points. Neither FROM nor TO have any alignment - restrictions. */ +char * +paddr_d (LONGEST addr) +{ + char *paddr_str = get_cell (); + if (addr < 0) + decimal2str (paddr_str, "-", -addr); + else + decimal2str (paddr_str, "", addr); + return paddr_str; +} -void -floatformat_from_doublest (fmt, from, to) - CONST struct floatformat *fmt; - DOUBLEST *from; - char *to; -{ - DOUBLEST dfrom; - int exponent; - DOUBLEST mant; - unsigned int mant_bits, mant_off; - int mant_bits_left; - unsigned char *uto = (unsigned char *)to; - - memcpy (&dfrom, from, sizeof (dfrom)); - memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); - if (dfrom == 0) - return; /* Result is zero */ - if (dfrom != dfrom) /* Result is NaN */ - { - /* From is NaN */ - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, - fmt->exp_len, fmt->exp_nan); - /* Be sure it's not infinity, but NaN value is irrel */ - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, - 32, 1); - return; - } +/* eliminate warning from compiler on 32-bit systems */ +static int thirty_two = 32; - /* If negative, set the sign bit. */ - if (dfrom < 0) +char * +phex (ULONGEST l, int sizeof_l) +{ + char *str; + switch (sizeof_l) { - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); - dfrom = -dfrom; + case 8: + str = get_cell (); + sprintf (str, "%08lx%08lx", + (unsigned long) (l >> thirty_two), + (unsigned long) (l & 0xffffffff)); + break; + case 4: + str = get_cell (); + sprintf (str, "%08lx", (unsigned long) l); + break; + case 2: + str = get_cell (); + sprintf (str, "%04x", (unsigned short) (l & 0xffff)); + break; + default: + str = phex (l, sizeof (l)); + break; } + return str; +} - if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity */ +char * +phex_nz (ULONGEST l, int sizeof_l) +{ + char *str; + switch (sizeof_l) { - /* Infinity exponent is same as NaN's. */ - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, - fmt->exp_len, fmt->exp_nan); - /* Infinity mantissa is all zeroes. */ - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, - fmt->man_len, 0); - return; + case 8: + { + unsigned long high = (unsigned long) (l >> thirty_two); + str = get_cell (); + if (high == 0) + sprintf (str, "%lx", (unsigned long) (l & 0xffffffff)); + else + sprintf (str, "%lx%08lx", + high, (unsigned long) (l & 0xffffffff)); + break; + } + case 4: + str = get_cell (); + sprintf (str, "%lx", (unsigned long) l); + break; + case 2: + str = get_cell (); + sprintf (str, "%x", (unsigned short) (l & 0xffff)); + break; + default: + str = phex_nz (l, sizeof (l)); + break; } + return str; +} -#ifdef HAVE_LONG_DOUBLE - mant = ldfrexp (dfrom, &exponent); -#else - mant = frexp (dfrom, &exponent); -#endif - - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, - exponent + fmt->exp_bias - 1); - - mant_bits_left = fmt->man_len; - mant_off = fmt->man_start; - while (mant_bits_left > 0) - { - unsigned long mant_long; - mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; - - mant *= 4294967296.0; - mant_long = (unsigned long)mant; - mant -= mant_long; - - /* If the integer bit is implicit, then we need to discard it. - If we are discarding a zero, we should be (but are not) creating - a denormalized number which means adjusting the exponent - (I think). */ - if (mant_bits_left == fmt->man_len - && fmt->intbit == floatformat_intbit_no) - { - mant_long <<= 1; - mant_bits -= 1; - } - - if (mant_bits < 32) - { - /* The bits we want are in the most significant MANT_BITS bits of - mant_long. Move them to the least significant. */ - mant_long >>= 32 - mant_bits; - } - - put_field (uto, fmt->byteorder, fmt->totalsize, - mant_off, mant_bits, mant_long); - mant_off += mant_bits; - mant_bits_left -= mant_bits; - } - if (fmt -> byteorder == floatformat_littlebyte_bigword) - { - int count; - unsigned char *swaplow = uto; - unsigned char *swaphigh = uto + 4; - unsigned char tmp; - for (count = 0; count < 4; count++) - { - tmp = *swaplow; - *swaplow++ = *swaphigh; - *swaphigh++ = tmp; - } - } +/* Convert to / from the hosts pointer to GDB's internal CORE_ADDR + using the target's conversion routines. */ +CORE_ADDR +host_pointer_to_address (void *ptr) +{ + if (sizeof (ptr) != TYPE_LENGTH (builtin_type_void_data_ptr)) + internal_error (__FILE__, __LINE__, + "core_addr_to_void_ptr: bad cast"); + return POINTER_TO_ADDRESS (builtin_type_void_data_ptr, &ptr); } -/* temporary storage using circular buffer */ -#define NUMCELLS 16 -#define CELLSIZE 32 -static char* -get_cell() +void * +address_to_host_pointer (CORE_ADDR addr) { - static char buf[NUMCELLS][CELLSIZE]; - static int cell=0; - if (++cell>=NUMCELLS) cell=0; - return buf[cell]; + void *ptr; + if (sizeof (ptr) != TYPE_LENGTH (builtin_type_void_data_ptr)) + internal_error (__FILE__, __LINE__, + "core_addr_to_void_ptr: bad cast"); + ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr); + return ptr; } -/* print routines to handle variable size regs, etc. - - FIXME: Note that t_addr is a bfd_vma, which is currently either an - unsigned long or unsigned long long, determined at configure time. - If t_addr is an unsigned long long and sizeof (unsigned long long) - is greater than sizeof (unsigned long), then I believe this code will - probably lose, at least for little endian machines. I believe that - it would also be better to eliminate the switch on the absolute size - of t_addr and replace it with a sequence of if statements that compare - sizeof t_addr with sizeof the various types and do the right thing, - which includes knowing whether or not the host supports long long. - -fnf - - */ - -static int thirty_two = 32; /* eliminate warning from compiler on 32-bit systems */ - -char* -paddr(addr) - t_addr addr; +/* Convert a CORE_ADDR into a string. */ +const char * +core_addr_to_string (const CORE_ADDR addr) { - char *paddr_str=get_cell(); - switch (sizeof(t_addr)) - { - case 8: - sprintf (paddr_str, "%08lx%08lx", - (unsigned long) (addr >> thirty_two), (unsigned long) (addr & 0xffffffff)); - break; - case 4: - sprintf (paddr_str, "%08lx", (unsigned long) addr); - break; - case 2: - sprintf (paddr_str, "%04x", (unsigned short) (addr & 0xffff)); - break; - default: - sprintf (paddr_str, "%lx", (unsigned long) addr); - } - return paddr_str; + char *str = get_cell (); + strcpy (str, "0x"); + strcat (str, phex (addr, sizeof (addr))); + return str; } -char* -preg(reg) - t_reg reg; +const char * +core_addr_to_string_nz (const CORE_ADDR addr) { - char *preg_str=get_cell(); - switch (sizeof(t_reg)) - { - case 8: - sprintf (preg_str, "%08lx%08lx", - (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff)); - break; - case 4: - sprintf (preg_str, "%08lx", (unsigned long) reg); - break; - case 2: - sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff)); - break; - default: - sprintf (preg_str, "%lx", (unsigned long) reg); - } - return preg_str; + char *str = get_cell (); + strcpy (str, "0x"); + strcat (str, phex_nz (addr, sizeof (addr))); + return str; } -char* -paddr_nz(addr) - t_addr addr; +/* Convert a string back into a CORE_ADDR. */ +CORE_ADDR +string_to_core_addr (const char *my_string) { - char *paddr_str=get_cell(); - switch (sizeof(t_addr)) + CORE_ADDR addr = 0; + if (my_string[0] == '0' && tolower (my_string[1]) == 'x') { - case 8: + /* Assume that it is in decimal. */ + int i; + for (i = 2; my_string[i] != '\0'; i++) { - unsigned long high = (unsigned long) (addr >> thirty_two); - if (high == 0) - sprintf (paddr_str, "%lx", (unsigned long) (addr & 0xffffffff)); + if (isdigit (my_string[i])) + addr = (my_string[i] - '0') + (addr * 16); + else if (isxdigit (my_string[i])) + addr = (tolower (my_string[i]) - 'a' + 0xa) + (addr * 16); else - sprintf (paddr_str, "%lx%08lx", - high, (unsigned long) (addr & 0xffffffff)); - break; + internal_error (__FILE__, __LINE__, "invalid hex"); } - case 4: - sprintf (paddr_str, "%lx", (unsigned long) addr); - break; - case 2: - sprintf (paddr_str, "%x", (unsigned short) (addr & 0xffff)); - break; - default: - sprintf (paddr_str,"%lx", (unsigned long) addr); } - return paddr_str; -} - -char* -preg_nz(reg) - t_reg reg; -{ - char *preg_str=get_cell(); - switch (sizeof(t_reg)) + else { - case 8: + /* Assume that it is in decimal. */ + int i; + for (i = 0; my_string[i] != '\0'; i++) { - unsigned long high = (unsigned long) (reg >> thirty_two); - if (high == 0) - sprintf (preg_str, "%lx", (unsigned long) (reg & 0xffffffff)); + if (isdigit (my_string[i])) + addr = (my_string[i] - '0') + (addr * 10); else - sprintf (preg_str, "%lx%08lx", - high, (unsigned long) (reg & 0xffffffff)); - break; + internal_error (__FILE__, __LINE__, "invalid decimal"); } - case 4: - sprintf (preg_str, "%lx", (unsigned long) reg); - break; - case 2: - sprintf (preg_str, "%x", (unsigned short) (reg & 0xffff)); - break; - default: - sprintf (preg_str, "%lx", (unsigned long) reg); } - return preg_str; + return addr; +} + +char * +gdb_realpath (const char *filename) +{ +#if defined(HAVE_REALPATH) +# if defined (PATH_MAX) + char buf[PATH_MAX]; +# define USE_REALPATH +# elif defined (MAXPATHLEN) + char buf[MAXPATHLEN]; +# define USE_REALPATH +# elif defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA) + char *buf = alloca ((size_t)pathconf ("/", _PC_PATH_MAX)); +# define USE_REALPATH +# endif +#endif /* HAVE_REALPATH */ + +#if defined(USE_REALPATH) + char *rp = realpath (filename, buf); + return xstrdup (rp ? rp : filename); +#elif defined(HAVE_CANONICALIZE_FILE_NAME) + char *rp = canonicalize_file_name (filename); + if (rp == NULL) + return xstrdup (filename); + else + return rp; +#else + return xstrdup (filename); +#endif } |