From: nobody <> Date: Mon, 9 Feb 2004 10:55:25 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'drow-cplus- X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=3e8231d1e8fb374255409496f05fc18bf0d3b706;p=thirdparty%2Fbinutils-gdb.git This commit was manufactured by cvs2svn to create branch 'drow-cplus- branch'. Cherrypick from master 2004-02-09 10:55:24 UTC Michael Chastain '2004-02-09 Michael Chastain ': gdb/auxv.c gdb/auxv.h gdb/config/sparc/obsd.mt gdb/config/sparc/obsd64.mt gdb/sparc64obsd-tdep.c gdb/sparcobsd-tdep.c gdb/testsuite/gdb.asm/openbsd.inc gdb/testsuite/gdb.base/chng-syms.c gdb/testsuite/gdb.base/chng-syms.exp gdb/testsuite/gdb.base/pending.c gdb/testsuite/gdb.base/pending.exp gdb/testsuite/gdb.base/pendshr.c gdb/testsuite/gdb.threads/thread-specific.c gdb/testsuite/gdb.threads/thread-specific.exp gdb/tui/tui-command.c gdb/tui/tui-command.h gdb/tui/tui-data.c gdb/tui/tui-data.h gdb/tui/tui-disasm.c gdb/tui/tui-disasm.h gdb/tui/tui-io.c gdb/tui/tui-io.h gdb/tui/tui-layout.c gdb/tui/tui-layout.h gdb/tui/tui-regs.c gdb/tui/tui-regs.h gdb/tui/tui-source.c gdb/tui/tui-source.h gdb/tui/tui-stack.c gdb/tui/tui-stack.h gdb/tui/tui-win.c gdb/tui/tui-win.h gdb/tui/tui-windata.c gdb/tui/tui-windata.h gdb/tui/tui-wingeneral.c gdb/tui/tui-wingeneral.h gdb/tui/tui-winsource.c gdb/tui/tui-winsource.h sim/testsuite/sim/mips/ChangeLog sim/testsuite/sim/mips/basic.exp sim/testsuite/sim/mips/sanity.s sim/testsuite/sim/mips/testutils.inc --- diff --git a/gdb/auxv.c b/gdb/auxv.c new file mode 100644 index 00000000000..c28014c4a9e --- /dev/null +++ b/gdb/auxv.c @@ -0,0 +1,301 @@ +/* Auxiliary vector support for GDB, the GNU debugger. + + Copyright 2004 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "target.h" +#include "gdbtypes.h" +#include "command.h" +#include "inferior.h" +#include "valprint.h" +#include "gdb_assert.h" + +#include "auxv.h" +#include "elf/common.h" + +#include +#include + + +/* This function is called like a to_xfer_partial hook, + but must be called with TARGET_OBJECT_AUXV. + It handles access via /proc/PID/auxv, which is the common method. + This function is appropriate for doing: + #define NATIVE_XFER_AUXV procfs_xfer_auxv + for a native target that uses inftarg.c's child_xfer_partial hook. */ + +LONGEST +procfs_xfer_auxv (struct target_ops *ops, + int /* enum target_object */ object, + const char *annex, + void *readbuf, + const void *writebuf, + ULONGEST offset, + LONGEST len) +{ + char *pathname; + int fd; + LONGEST n; + + gdb_assert (object == TARGET_OBJECT_AUXV); + gdb_assert (readbuf || writebuf); + + pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid)); + fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY); + xfree (pathname); + if (fd < 0) + return -1; + + if (offset != (ULONGEST) 0 + && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset) + n = -1; + else if (readbuf != NULL) + n = read (fd, readbuf, len); + else + n = write (fd, writebuf, len); + + (void) close (fd); + + return n; +} + +/* Read all the auxv data into a contiguous xmalloc'd buffer, + stored in *DATA. Return the size in bytes of this data. + If zero, there is no data and *DATA is null. + if < 0, there was an error and *DATA is null. */ +LONGEST +target_auxv_read (struct target_ops *ops, char **data) +{ + size_t auxv_alloc = 512, auxv_pos = 0; + char *auxv = xmalloc (auxv_alloc); + int n; + + while (1) + { + n = target_read_partial (ops, TARGET_OBJECT_AUXV, + NULL, &auxv[auxv_pos], 0, + auxv_alloc - auxv_pos); + if (n <= 0) + break; + auxv_pos += n; + if (auxv_pos < auxv_alloc) /* Read all there was. */ + break; + gdb_assert (auxv_pos == auxv_alloc); + auxv_alloc *= 2; + auxv = xrealloc (auxv, auxv_alloc); + } + + if (auxv_pos == 0) + { + xfree (auxv); + *data = NULL; + return n; + } + + *data = auxv; + return auxv_pos; +} + +/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. + Return 0 if *READPTR is already at the end of the buffer. + Return -1 if there is insufficient buffer for a whole entry. + Return 1 if an entry was read into *TYPEP and *VALP. */ +int +target_auxv_parse (struct target_ops *ops, char **readptr, char *endptr, + CORE_ADDR *typep, CORE_ADDR *valp) +{ + const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr); + char *ptr = *readptr; + + if (endptr == ptr) + return 0; + + if (endptr - ptr < sizeof_auxv_field * 2) + return -1; + + *typep = extract_unsigned_integer (ptr, sizeof_auxv_field); + ptr += sizeof_auxv_field; + *valp = extract_unsigned_integer (ptr, sizeof_auxv_field); + ptr += sizeof_auxv_field; + + *readptr = ptr; + return 1; +} + +/* Extract the auxiliary vector entry with a_type matching MATCH. + Return zero if no such entry was found, or -1 if there was + an error getting the information. On success, return 1 after + storing the entry's value field in *VALP. */ +int +target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) +{ + CORE_ADDR type, val; + char *data; + int n = target_auxv_read (ops, &data); + char *ptr = data; + int ents = 0; + + if (n <= 0) + return n; + + while (1) + switch (target_auxv_parse (ops, &ptr, data + n, &type, &val)) + { + case 1: /* Here's an entry, check it. */ + if (type == match) + { + xfree (data); + *valp = val; + return 1; + } + break; + case 0: /* End of the vector. */ + xfree (data); + return 0; + default: /* Bogosity. */ + xfree (data); + return -1; + } + + /*NOTREACHED*/ +} + + +/* Print the contents of the target's AUXV on the specified file. */ +int +fprint_target_auxv (struct ui_file *file, struct target_ops *ops) +{ + CORE_ADDR type, val; + char *data; + int len = target_auxv_read (ops, &data); + char *ptr = data; + int ents = 0; + + if (len <= 0) + return len; + + while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0) + { + extern int addressprint; + const char *name = "???"; + const char *description = ""; + enum { dec, hex, str } flavor = hex; + + switch (type) + { +#define TAG(tag, text, kind) \ + case tag: name = #tag; description = text; flavor = kind; break + TAG (AT_NULL, "End of vector", hex); + TAG (AT_IGNORE, "Entry should be ignored", hex); + TAG (AT_EXECFD, "File descriptor of program", dec); + TAG (AT_PHDR, "Program headers for program", hex); + TAG (AT_PHENT, "Size of program header entry", dec); + TAG (AT_PHNUM, "Number of program headers", dec); + TAG (AT_PAGESZ, "System page size", dec); + TAG (AT_BASE, "Base address of interpreter", hex); + TAG (AT_FLAGS, "Flags", hex); + TAG (AT_ENTRY, "Entry point of program", hex); + TAG (AT_NOTELF, "Program is not ELF", dec); + TAG (AT_UID, "Real user ID", dec); + TAG (AT_EUID, "Effective user ID", dec); + TAG (AT_GID, "Real group ID", dec); + TAG (AT_EGID, "Effective group ID", dec); + TAG (AT_CLKTCK, "Frequency of times()", dec); + TAG (AT_PLATFORM, "String identifying platform", str); + TAG (AT_HWCAP, "Machine-dependent CPU capability hints", hex); + TAG (AT_FPUCW, "Used FPU control word", dec); + TAG (AT_DCACHEBSIZE, "Data cache block size", dec); + TAG (AT_ICACHEBSIZE, "Instruction cache block size", dec); + TAG (AT_UCACHEBSIZE, "Unified cache block size", dec); + TAG (AT_IGNOREPPC, "Entry should be ignored", dec); + TAG (AT_SYSINFO, "Special system info/entry points", hex); + TAG (AT_SYSINFO_EHDR, "System-supplied DSO's ELF header", hex); + TAG (AT_SECURE, "Boolean, was exec setuid-like?", dec); + TAG (AT_SUN_UID, "Effective user ID", dec); + TAG (AT_SUN_RUID, "Real user ID", dec); + TAG (AT_SUN_GID, "Effective group ID", dec); + TAG (AT_SUN_RGID, "Real group ID", dec); + TAG (AT_SUN_LDELF, "Dynamic linker's ELF header", hex); + TAG (AT_SUN_LDSHDR, "Dynamic linker's section headers", hex); + TAG (AT_SUN_LDNAME, "String giving name of dynamic linker", str); + TAG (AT_SUN_LPAGESZ, "Large pagesize", dec); + TAG (AT_SUN_PLATFORM, "Platform name string", str); + TAG (AT_SUN_HWCAP, "Machine-dependent CPU capability hints", hex); + TAG (AT_SUN_IFLUSH, "Should flush icache?", dec); + TAG (AT_SUN_CPU, "CPU name string", str); + TAG (AT_SUN_EMUL_ENTRY, "COFF entry point address", hex); + TAG (AT_SUN_EMUL_EXECFD, "COFF executable file descriptor", dec); + TAG (AT_SUN_EXECNAME, + "Canonicalized file name given to execve", str); + TAG (AT_SUN_MMU, "String for name of MMU module", str); + TAG (AT_SUN_LDDATA, "Dynamic linker's data segment address", hex); + } + + fprintf_filtered (file, "%-4s %-20s %-30s ", + paddr_d (type), name, description); + switch (flavor) + { + case dec: + fprintf_filtered (file, "%s\n", paddr_d (val)); + break; + case hex: + fprintf_filtered (file, "0x%s\n", paddr_nz (val)); + break; + case str: + if (addressprint) + fprintf_filtered (file, "0x%s", paddr_nz (val)); + val_print_string (val, -1, 1, file); + fprintf_filtered (file, "\n"); + break; + } + ++ents; + } + + xfree (data); + + return ents; +} + +static void +info_auxv_command (char *cmd, int from_tty) +{ + + if (! target_has_stack) + error ("The program has no auxiliary information now."); + else + { + int ents = fprint_target_auxv (gdb_stdout, ¤t_target); + if (ents < 0) + error ("No auxilary vector found, or failed reading it."); + else if (ents == 0) + error ("Auxilary vector is empty."); + } +} + + +extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */ + +void +_initialize_auxv (void) +{ + add_info ("auxv", info_auxv_command, + "Display the inferior's auxiliary vector.\n\ +This is information provided by the operating system at program startup."); +} diff --git a/gdb/auxv.h b/gdb/auxv.h new file mode 100644 index 00000000000..4ce0569a591 --- /dev/null +++ b/gdb/auxv.h @@ -0,0 +1,75 @@ +/* Auxiliary vector support for GDB, the GNU debugger. + + Copyright 2004 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef AUXV_H +#define AUXV_H + +/* See "include/elf/common.h" for the definition of valid AT_* values. */ + + +/* Avoid miscellaneous includes in this file, so that it can be + included by nm-*.h for the procfs_xfer_auxv decl if that is + used in NATIVE_XFER_AUXV. */ +struct target_ops; /* Forward declaration. */ + + +/* Read all the auxv data into a contiguous xmalloc'd buffer, + stored in *DATA. Return the size in bytes of this data. + If zero, there is no data and *DATA is null. + if < 0, there was an error and *DATA is null. */ +extern LONGEST target_auxv_read (struct target_ops *ops, char **data); + +/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. + Return 0 if *READPTR is already at the end of the buffer. + Return -1 if there is insufficient buffer for a whole entry. + Return 1 if an entry was read into *TYPEP and *VALP. */ +extern int target_auxv_parse (struct target_ops *ops, + char **readptr, char *endptr, + CORE_ADDR *typep, CORE_ADDR *valp); + +/* Extract the auxiliary vector entry with a_type matching MATCH. + Return zero if no such entry was found, or -1 if there was + an error getting the information. On success, return 1 after + storing the entry's value field in *VALP. */ +extern int target_auxv_search (struct target_ops *ops, + CORE_ADDR match, CORE_ADDR *valp); + +/* Print the contents of the target's AUXV on the specified file. */ +extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops); + + +/* This function is called like a to_xfer_partial hook, + but must be called with TARGET_OBJECT_AUXV. + It handles access via /proc/PID/auxv, which is the common method. + This function is appropriate for doing: + #define NATIVE_XFER_AUXV procfs_xfer_auxv + for a native target that uses inftarg.c's child_xfer_partial hook. */ + +extern LONGEST procfs_xfer_auxv (struct target_ops *ops, + int /* enum target_object */ object, + const char *annex, + void *readbuf, + const void *writebuf, + ULONGEST offset, + LONGEST len); + + +#endif diff --git a/gdb/config/sparc/obsd.mt b/gdb/config/sparc/obsd.mt new file mode 100644 index 00000000000..800cb048eac --- /dev/null +++ b/gdb/config/sparc/obsd.mt @@ -0,0 +1,4 @@ +# Target: OpenBSD/sparc +TDEPFILES= sparc-tdep.o sparcnbsd-tdep.o sparcobsd-tdep.o nbsd-tdep.o \ + corelow.o solib.o solib-svr4.o +TM_FILE= tm-nbsd.h diff --git a/gdb/config/sparc/obsd64.mt b/gdb/config/sparc/obsd64.mt new file mode 100644 index 00000000000..a69281754c4 --- /dev/null +++ b/gdb/config/sparc/obsd64.mt @@ -0,0 +1,5 @@ +# Target: OpenBSD/sparc64 +TDEPFILES= sparc64-tdep.o sparc64nbsd-tdep.o sparc64obsd-tdep.o \ + sparc-tdep.o sparcnbsd-tdep.o nbsd-tdep.o \ + corelow.o solib.o solib-svr4.o +TM_FILE= tm-nbsd.h diff --git a/gdb/sparc64obsd-tdep.c b/gdb/sparc64obsd-tdep.c new file mode 100644 index 00000000000..190a46be1fa --- /dev/null +++ b/gdb/sparc64obsd-tdep.c @@ -0,0 +1,210 @@ +/* Target-dependent code for OpenBSD/sparc64. + + Copyright 2004 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "osabi.h" +#include "regset.h" +#include "symtab.h" +#include "solib-svr4.h" +#include "trad-frame.h" + +#include "gdb_assert.h" + +#include "sparc64-tdep.h" +#include "nbsd-tdep.h" + +/* OpenBSD uses the traditional NetBSD core file format, even for + ports that use ELF. The core files don't use multiple register + sets. Instead, the general-purpose and floating-point registers + are lumped together in a single section. Unlike on NetBSD, OpenBSD + uses a different layout for its general-purpose registers than the + layout used for ptrace(2). */ + +/* From . */ +const struct sparc_gregset sparc64obsd_core_gregset = +{ + 0 * 8, /* "tstate" */ + 1 * 8, /* %pc */ + 2 * 8, /* %npc */ + 3 * 8, /* %y */ + -1, /* %fprs */ + -1, + 7 * 8, /* %g1 */ + 22 * 8, /* %l0 */ + 4 /* sizeof (%y) */ +}; + +static void +sparc64obsd_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + const char *regs = gregs; + + sparc64_supply_gregset (regset->descr, regcache, regnum, regs); + sparc64_supply_fpregset (regcache, regnum, regs + 288); +} + + +/* Signal trampolines. */ + +/* The OpenBSD kernel maps the signal trampoline at some random + location in user space, which means that the traditional BSD way of + detecting it won't work. + + The signal trampoline will be mapped at an address that is page + aligned. We recognize the signal trampoline by the looking for the + sigreturn system call. */ + +static const int sparc64obsd_page_size = 8192; + +static int +sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name) +{ + CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1)); + unsigned long insn; + + if (name) + return 0; + + /* Check for "restore %g0, SYS_sigreturn, %g1". */ + insn = sparc_fetch_instruction (start_pc + 0xe8); + if (insn != 0x83e82067) + return 0; + + /* Check for "t ST_SYSCALL". */ + insn = sparc_fetch_instruction (start_pc + 0xf0); + if (insn != 0x91d02000) + return 0; + + return 1; +} + +static struct sparc_frame_cache * +sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + struct sparc_frame_cache *cache; + CORE_ADDR addr; + + if (*this_cache) + return *this_cache; + + cache = sparc_frame_cache (next_frame, this_cache); + gdb_assert (cache == *this_cache); + + /* If we couldn't find the frame's function, we're probably dealing + with an on-stack signal trampoline. */ + if (cache->pc == 0) + { + cache->pc = frame_pc_unwind (next_frame); + cache->pc &= ~(sparc64obsd_page_size - 1); + + /* Since we couldn't find the frame's function, the cache was + initialized under the assumption that we're frameless. */ + cache->frameless_p = 0; + addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM); + cache->base = addr; + } + + /* We find the appropriate instance of `struct sigcontext' at a + fixed offset in the signal frame. */ + addr = cache->base + BIAS + 128 + 16; + cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame); + + return cache; +} + +static void +sparc64obsd_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct sparc_frame_cache *cache = + sparc64obsd_frame_cache (next_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, cache->pc); +} + +static void +sparc64obsd_frame_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct sparc_frame_cache *cache = + sparc64obsd_frame_cache (next_frame, this_cache); + + trad_frame_prev_register (next_frame, cache->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind sparc64obsd_frame_unwind = +{ + SIGTRAMP_FRAME, + sparc64obsd_frame_this_id, + sparc64obsd_frame_prev_register +}; + +static const struct frame_unwind * +sparc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (sparc64obsd_pc_in_sigtramp (pc, name)) + return &sparc64obsd_frame_unwind; + + return NULL; +} + + +static void +sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->gregset = XMALLOC (struct regset); + tdep->gregset->descr = &sparc64obsd_core_gregset; + tdep->gregset->supply_regset = sparc64obsd_supply_gregset; + tdep->sizeof_gregset = 832; + + set_gdbarch_pc_in_sigtramp (gdbarch, sparc64obsd_pc_in_sigtramp); + frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer); + + sparc64_init_abi (info, gdbarch); + + set_solib_svr4_fetch_link_map_offsets + (gdbarch, nbsd_lp64_solib_svr4_fetch_link_map_offsets); +} + + +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_sparc64obsd_tdep (void); + +void +_initialize_sparc64obsd_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9, + GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi); +} diff --git a/gdb/sparcobsd-tdep.c b/gdb/sparcobsd-tdep.c new file mode 100644 index 00000000000..108e255ed13 --- /dev/null +++ b/gdb/sparcobsd-tdep.c @@ -0,0 +1,171 @@ +/* Target-dependent code for OpenBSD/sparc. + + Copyright 2004 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "floatformat.h" +#include "frame.h" +#include "frame-unwind.h" +#include "osabi.h" +#include "solib-svr4.h" +#include "symtab.h" +#include "trad-frame.h" + +#include "gdb_assert.h" + +#include "sparc-tdep.h" +#include "nbsd-tdep.h" + +/* Signal trampolines. */ + +/* The OpenBSD kernel maps the signal trampoline at some random + location in user space, which means that the traditional BSD way of + detecting it won't work. + + The signal trampoline will be mapped at an address that is page + aligned. We recognize the signal trampoline by the looking for the + sigreturn system call. */ + +static const int sparc32obsd_page_size = 4096; + +static int +sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, char *name) +{ + CORE_ADDR start_pc = (pc & ~(sparc32obsd_page_size - 1)); + unsigned long insn; + + if (name) + return 0; + + /* Check for "restore %g0, SYS_sigreturn, %g1". */ + insn = sparc_fetch_instruction (start_pc + 0xec); + if (insn != 0x83e82067) + return 0; + + /* Check for "t ST_SYSCALL". */ + insn = sparc_fetch_instruction (start_pc + 0xf4); + if (insn != 0x91d02000) + return 0; + + return 1; +} + +static struct sparc_frame_cache * +sparc32obsd_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + struct sparc_frame_cache *cache; + CORE_ADDR addr; + + if (*this_cache) + return *this_cache; + + cache = sparc_frame_cache (next_frame, this_cache); + gdb_assert (cache == *this_cache); + + /* If we couldn't find the frame's function, we're probably dealing + with an on-stack signal trampoline. */ + if (cache->pc == 0) + { + cache->pc = frame_pc_unwind (next_frame); + cache->pc &= ~(sparc32obsd_page_size - 1); + + /* Since we couldn't find the frame's function, the cache was + initialized under the assumption that we're frameless. */ + cache->frameless_p = 0; + addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM); + cache->base = addr; + } + + cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (next_frame); + + return cache; +} + +static void +sparc32obsd_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct sparc_frame_cache *cache = + sparc32obsd_frame_cache (next_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, cache->pc); +} + +static void +sparc32obsd_frame_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct sparc_frame_cache *cache = + sparc32obsd_frame_cache (next_frame, this_cache); + + trad_frame_prev_register (next_frame, cache->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind sparc32obsd_frame_unwind = +{ + SIGTRAMP_FRAME, + sparc32obsd_frame_this_id, + sparc32obsd_frame_prev_register +}; + +static const struct frame_unwind * +sparc32obsd_sigtramp_frame_sniffer (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (sparc32obsd_pc_in_sigtramp (pc, name)) + return &sparc32obsd_frame_unwind; + + return NULL; +} + + +static void +sparc32obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */ + set_gdbarch_long_double_bit (gdbarch, 64); + set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big); + + set_gdbarch_pc_in_sigtramp (gdbarch, sparc32obsd_pc_in_sigtramp); + frame_unwind_append_sniffer (gdbarch, sparc32obsd_sigtramp_frame_sniffer); + + set_solib_svr4_fetch_link_map_offsets + (gdbarch, nbsd_ilp32_solib_svr4_fetch_link_map_offsets); +} + + +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_sparc32obsd_tdep (void); + +void +_initialize_sparc32obsd_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_OPENBSD_ELF, + sparc32obsd_init_abi); +} diff --git a/gdb/testsuite/gdb.asm/openbsd.inc b/gdb/testsuite/gdb.asm/openbsd.inc new file mode 100644 index 00000000000..90e3dbd0d25 --- /dev/null +++ b/gdb/testsuite/gdb.asm/openbsd.inc @@ -0,0 +1,12 @@ + comment "openbsd .note" + +.section ".note.openbsdbsd.ident", "a" + .p2align 2 + + .long 8 + .long 4 + .long 1 + .ascii "OpenBSD\0\0" + .long 200311 + + .p2align 2 diff --git a/gdb/testsuite/gdb.base/chng-syms.c b/gdb/testsuite/gdb.base/chng-syms.c new file mode 100644 index 00000000000..3394f5c3897 --- /dev/null +++ b/gdb/testsuite/gdb.base/chng-syms.c @@ -0,0 +1,22 @@ +/* + * Test that GDB cleans up properly after errors that result when a + * breakpoint is reset. + */ + +/* VARIABLE is a macro defined on the compiler command line. */ + +#include + +int VARIABLE = 42; + +void stop_here () +{ + VARIABLE *= 2; +} + +int main () +{ + stop_here (); + exit (0); +} + diff --git a/gdb/testsuite/gdb.base/chng-syms.exp b/gdb/testsuite/gdb.base/chng-syms.exp new file mode 100644 index 00000000000..18f847f937d --- /dev/null +++ b/gdb/testsuite/gdb.base/chng-syms.exp @@ -0,0 +1,120 @@ +# Copyright 2004 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 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. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# Author: Paul N. Hilfinger (Hilfinger@gnat.com) + +# Test that GDB cleans up properly after errors that result when a +# breakpoint is reset. + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +# IDT/SIM apparently doesn't have enough file descriptors to allow the +# problem checked by this test to occur. +if [istarget "mips-idt-*"] { + return 0; +} + +set testfile "chng-syms" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DVARIABLE=var1}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +set oldtimeout $timeout +set timeout 10 +verbose "Timeout is now 10 seconds" 2 + +proc expect_to_stop_here { ident } { + global gdb_prompt + global decimal + + # the "at foo.c:36" output we get with -g. + # the "in func" output we get without -g. + gdb_expect { + -re "Breakpoint \[0-9\]*, stop_here .*$gdb_prompt $" { + return 1 + } + -re "$gdb_prompt $" { + fail "running to stop_here $ident" + return 0 + } + timeout { + fail "running to stop_here $ident (timeout)" + return 0 + } + } + return 1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test "break stop_here if (var1 == 42)" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "setting conditional breakpoint on function" +gdb_run_cmd + +expect_to_stop_here "first time" + +gdb_continue_to_end "breakpoint first time through" + +# Now we recompile the executable, but without a variable named "var1", first +# waiting to insure that even on fast machines, the file modification times +# are distinct. This will force GDB to reload the file on the +# next "run" command, causing an error when GDB tries to tries to reset +# the breakpoint. + +sleep 2 +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DVARIABLE=var2}] != "" } { + +# Complication: Since GDB generally holds an open file descriptor on the +# executable at this point, there are some systems in which the +# re-compilation will fail. In such cases, we'll consider the test +# (vacuously) passed providing that re-running it succeeds as before. + + gdb_run_cmd + expect_to_stop_here "after re-compile fails" + gdb_continue_to_end "after re-compile fails" + +} else { + + gdb_run_cmd + gdb_expect { + -re "Error in re-setting .*No symbol .var1..*Program exited normally.*" { + pass "running with invalidated bpt condition after executable changes" + } + timeout { + fail "(timeout) running with invalidated bpt condition after executable changes" + } + } + +} + +set timeout $oldtimeout +verbose "Timeout is now $timeout seconds" 2 +return 0 diff --git a/gdb/testsuite/gdb.base/pending.c b/gdb/testsuite/gdb.base/pending.c new file mode 100644 index 00000000000..a83a451b94e --- /dev/null +++ b/gdb/testsuite/gdb.base/pending.c @@ -0,0 +1,35 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004 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 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. + + Please email any bugs, comments, and/or additions to this file to: + bug-gdb@prep.ai.mit.edu */ + +#include + +int k = 0; + +extern void pendfunc (int x); + +int main() +{ + pendfunc (3); /* break main here */ + pendfunc (4); + k = 1; + pendfunc (3); + return 0; +} diff --git a/gdb/testsuite/gdb.base/pending.exp b/gdb/testsuite/gdb.base/pending.exp new file mode 100644 index 00000000000..2cef30af5bf --- /dev/null +++ b/gdb/testsuite/gdb.base/pending.exp @@ -0,0 +1,266 @@ +# Copyright 2003, 2004 +# 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 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. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was created by Jeff Johnston. (jjohnstn@redhat.com) +# The shared library compilation portion was copied from shlib-call.exp which was +# written by Elena Zannoni (ezannoni@redhat.com). + +if $tracelevel then { + strace $tracelevel +} + +# +# test running programs +# +set prms_id 0 +set bug_id 0 + +# are we on a target board? +if ![isnative] then { + return 0 +} + +set testfile "pending" +set libfile "pendshr" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if [get_compiler_info ${binfile}] { + return -1 +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}.o" object {debug}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +# Build the shared libraries this test case needs. +# + +if {$gcc_compiled == 0} { + if [istarget "hppa*-hp-hpux*"] then { + set additional_flags "additional_flags=+z" + } elseif { [istarget "mips-sgi-irix*"] } { + # Disable SGI compiler's implicit -Dsgi + set additional_flags "additional_flags=-Usgi" + } else { + # don't know what the compiler is... + set additional_flags "" + } +} else { + if { ([istarget "powerpc*-*-aix*"] + || [istarget "rs6000*-*-aix*"]) } { + set additional_flags "" + } else { + set additional_flags "additional_flags=-fpic" + } +} + +if {[gdb_compile "${srcdir}/${subdir}/${libfile}.c" "${objdir}/${subdir}/${libfile}.o" object [list debug $additional_flags]] != ""} { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +if [istarget "hppa*-*-hpux*"] { + remote_exec build "ld -b ${objdir}/${subdir}/${libfile}.o -o ${objdir}/${subdir}/${libfile}.sl" +} else { + set additional_flags "additional_flags=-shared" + if {[gdb_compile "${objdir}/${subdir}/${libfile}.o" "${objdir}/${subdir}/${libfile}.sl" executable [list debug $additional_flags]] != ""} { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." + } +} + +if { ($gcc_compiled + && ([istarget "powerpc*-*-aix*"] + || [istarget "rs6000*-*-aix*"] )) } { + set additional_flags "additional_flags=-L${objdir}/${subdir}" +} elseif { [istarget "mips-sgi-irix*"] } { + set additional_flags "additional_flags=-rpath ${objdir}/${subdir}" +} else { + set additional_flags "" +} +if {[gdb_compile "${objdir}/${subdir}/${testfile}.o ${objdir}/${subdir}/${libfile}.sl" "${binfile}" executable [list debug $additional_flags]] != ""} { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if [target_info exists gdb_stub] { + gdb_step_for_stub; +} +# +# Test setting, querying, and modifying pending breakpoints +# + +gdb_test_multiple "break pendfunc1" "set pending breakpoint" { + -re ".*Make breakpoint pending.*y or n. $" { + gdb_test "y" "Breakpoint.*pendfunc1.*pending." "set pending breakpoint" + } +} + +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep y.*PENDING.*pendfunc1.*" \ +"single pending breakpoint info" + +# +# Test breaking at existing function +# + +set mainline [gdb_get_line_number "break main here"] + +gdb_test "break main" \ + "Breakpoint.*at.* file .*$srcfile, line $mainline.*" \ + "breakpoint function" + +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep y.*PENDING.*pendfunc1.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$mainline" \ +"pending plus real breakpoint info" + + +# +# Test not setting a pending breakpoint +# +gdb_test_multiple "break pendfunc2" "Don't set pending breakpoint" { + -re ".*Make breakpoint pending.*y or n. $" { + gdb_test "n" "" "Don't set pending breakpoint" + } +} + +# +# Add condition to pending breakpoint +# + +gdb_test "condition 1 k == 1" "" + +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep y.*PENDING.*pendfunc1.* +\[\t \]+stop only if k == 1.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$mainline" \ +"pending plus condition" + +# +# Disable pending breakpoint +# + +gdb_test "disable 1" "" + +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep n.*PENDING.*pendfunc1.* +\[\t \]+stop only if k == 1.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$mainline" \ +"pending disabled" + +# +# Add commands to pending breakpoint +# +gdb_test "commands 1\nprint k\nend" "" \ + "Set commands for pending breakpoint" + +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep n.*PENDING.*pendfunc1.* +\[\t \]+stop only if k == 1.* +\[\t \]+print k.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$mainline" \ +"pending disabled plus commands" + +# +# Try a pending break for a line in a source file with a condition +# + +gdb_test_multiple "break pendshr.c:26 if x > 3" "Set pending breakpoint 2" { + -re ".*Make breakpoint pending.*y or n. $" { + gdb_test "y" "Breakpoint.*pendshr.c:26.*pending." \ + "Set pending breakpoint 2" + } +} + +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep n.*PENDING.*pendfunc1.* +\[\t \]+stop only if k == 1.* +\[\t \]+print k.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$mainline.* +\[0-9\]+\[\t \]+breakpoint keep y.*PENDING.*pendshr.c:26 if x > 3.*" \ +"multiple pending breakpoints" + +# +# Run to main which should resolve a pending breakpoint +# + +gdb_test "run" \ +"Breakpoint.*at.* +Pending breakpoint \"pendshr.c:26 if x > 3\" resolved.* +Breakpoint.*, main.*$mainline.*" \ +"running to main" + +# +# Re-enable the first pending breakpoint which should resolve +# + +gdb_test "enable 1" \ +"Breakpoint.*at.* +Pending breakpoint \"pendfunc1.* resolved.*" \ +"re-enabling pending breakpoint that can resolve instantly" + +# +# Continue to verify conditionals and commands for breakpoints are honored +# + +gdb_test "continue" \ +".*Breakpoint.*pendfunc1.*at.*pendshr.c:26.*4;" \ +"continue to resolved breakpoint 2" + +gdb_test "continue" \ +".*Breakpoint.*pendfunc1.*at.*pendshr.c:26.* +\[$\]1 = 1." \ +"continue to resolved breakpoint 1" + +delete_breakpoints + +gdb_breakpoint "main" + +# +# Set non-existent pending breakpoint +# +gdb_test_multiple "break imaginary" "set imaginary pending breakpoint" { + -re ".*Make breakpoint pending.*y or n. $" { + gdb_test "y" "Breakpoint.*imaginary.*pending." \ + "set imaginary pending breakpoint" + } +} + +# +# rerun program and make sure that any pending breakpoint remains and no +# error messages are issued for the missing function +# + +rerun_to_main +gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$mainline.* +\[0-9\]+\[\t \]+breakpoint keep y.*PENDING.*imaginary.*" \ +"verify pending breakpoint after restart" diff --git a/gdb/testsuite/gdb.base/pendshr.c b/gdb/testsuite/gdb.base/pendshr.c new file mode 100644 index 00000000000..672fe8ab7ee --- /dev/null +++ b/gdb/testsuite/gdb.base/pendshr.c @@ -0,0 +1,33 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004 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 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. + + Please email any bugs, comments, and/or additions to this file to: + bug-gdb@prep.ai.mit.edu */ + +#include + +void pendfunc1 (int x) +{ + int y = x + 4; + printf ("in pendfunc1, x is %d\n", x); +} + +void pendfunc (int x) +{ + pendfunc1 (x); +} diff --git a/gdb/testsuite/gdb.threads/thread-specific.c b/gdb/testsuite/gdb.threads/thread-specific.c new file mode 100644 index 00000000000..88a462dac29 --- /dev/null +++ b/gdb/testsuite/gdb.threads/thread-specific.c @@ -0,0 +1,66 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004 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 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 +#include +#include +#include + +void *thread_function(void *arg); + +unsigned int args[1]; + +int main() { + int res; + pthread_t threads[2]; + void *thread_result; + long i = 1; + + args[0] = 1; + res = pthread_create(&threads[0], + NULL, + thread_function, + (void *) 0); + + /* thread-specific.exp: last thread start. */ + args[1] = 1; + + /* Don't run forever. Run just short of it :) */ + while (i > 0) + { + /* thread-specific.exp: main loop. */ + (i) ++; + } + + exit(EXIT_SUCCESS); +} + +void *thread_function(void *arg) { + int my_number = (long) arg; + int *myp = &args[my_number]; + + /* Don't run forever. Run just short of it :) */ + while (*myp > 0) + { + /* thread-specific.exp: thread loop. */ + (*myp) ++; + } + + pthread_exit(NULL); +} diff --git a/gdb/testsuite/gdb.threads/thread-specific.exp b/gdb/testsuite/gdb.threads/thread-specific.exp new file mode 100644 index 00000000000..ffcaaad1762 --- /dev/null +++ b/gdb/testsuite/gdb.threads/thread-specific.exp @@ -0,0 +1,110 @@ +# Copyright 2004 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 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. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was written by Daniel Jacobowitz . +# It tests that the correct breakpoint is reported when we hit a +# thread-specific breakpoint inserted for several threads. + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile "thread-specific" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } { + return -1 +} + +# Return a list of the valid thread IDs, with the initial thread first. +proc get_thread_list { } { + global gdb_prompt + global expect_out + + set thr_list "" + + gdb_test_multiple "info threads" "get threads list" { + -re "info threads\r\n" { + exp_continue + } + -re "^\\* *(\[0-9\]*) Thread \[^\n\]*main\[^\n\]*\n" { + set thr_list "$expect_out(1,string) $thr_list" + exp_continue + } + -re "^ *(\[0-9\]*) Thread \[^\n\]*\n" { + lappend thr_list $expect_out(1,string) + exp_continue + } + -re ".*$gdb_prompt $" { + if { [llength $thr_list] != 0 } { + pass "get threads list" + } else { + fail "get threads list (no threads)" + } + } + } + + return $thr_list +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_load ${binfile} + +gdb_test "set print sevenbit-strings" "" +gdb_test "set width 0" "" + +runto_main + +gdb_breakpoint [gdb_get_line_number "thread-specific.exp: last thread start"] +gdb_continue_to_breakpoint "all threads started" + +set line [gdb_get_line_number "thread-specific.exp: thread loop"] +set threads [get_thread_list] + +gdb_test_multiple "break $line thread [lindex $threads 0]" \ + "breakpoint $line main thread" { + -re "Breakpoint (\[0-9\]*) at.* file .*$srcfile, line.*$gdb_prompt $" { + set main_breakpoint $expect_out(1,string) + pass "breakpoint $line main thread" + } +} + +foreach thread [lrange $threads 1 end] { + gdb_breakpoint "$line thread $thread" +} + +gdb_test_multiple "continue" "continue to thread-specific breakpoint" { + -re "Breakpoint $main_breakpoint, .* at .*\r\n$gdb_prompt $" { + fail "continue to thread-specific breakpoint (wrong breakpoint)" + } + -re "Breakpoint .* at .*\r\n$gdb_prompt $" { + pass "continue to thread-specific breakpoint" + } +} + +return 0 diff --git a/gdb/tui/tui-command.c b/gdb/tui/tui-command.c new file mode 100644 index 00000000000..a182b4ce8e6 --- /dev/null +++ b/gdb/tui/tui-command.c @@ -0,0 +1,136 @@ +/* Specific command window processing. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-win.h" +#include "tui/tui-io.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + + +/***************************************** +** STATIC LOCAL FUNCTIONS FORWARD DECLS ** +******************************************/ + + + +/***************************************** +** PUBLIC FUNCTIONS ** +******************************************/ + +/* Dispatch the correct tui function based upon the control character. */ +unsigned int +tui_dispatch_ctrl_char (unsigned int ch) +{ + struct tui_win_info *win_info = tui_win_with_focus (); + WINDOW *w = TUI_CMD_WIN->generic.handle; + + /* + ** If the command window has the logical focus, or no-one does + ** assume it is the command window; in this case, pass the + ** character on through and do nothing here. + */ + if (win_info == NULL || win_info == TUI_CMD_WIN) + return ch; + else + { + unsigned int c = 0, ch_copy = ch; + int i; + char *term; + + /* If this is an xterm, page next/prev keys aren't returned + ** by keypad as a single char, so we must handle them here. + ** Seems like a bug in the curses library? + */ + term = (char *) getenv ("TERM"); + for (i = 0; (term && term[i]); i++) + term[i] = toupper (term[i]); + if ((strcmp (term, "XTERM") == 0) && key_is_start_sequence (ch)) + { + unsigned int page_ch = 0; + unsigned int tmp_char; + + tmp_char = 0; + while (!key_is_end_sequence (tmp_char)) + { + tmp_char = (int) wgetch (w); + if (tmp_char == ERR) + { + return ch; + } + if (!tmp_char) + break; + if (tmp_char == 53) + page_ch = KEY_PPAGE; + else if (tmp_char == 54) + page_ch = KEY_NPAGE; + else + { + return 0; + } + } + ch_copy = page_ch; + } + + switch (ch_copy) + { + case KEY_NPAGE: + tui_scroll_forward (win_info, 0); + break; + case KEY_PPAGE: + tui_scroll_backward (win_info, 0); + break; + case KEY_DOWN: + case KEY_SF: + tui_scroll_forward (win_info, 1); + break; + case KEY_UP: + case KEY_SR: + tui_scroll_backward (win_info, 1); + break; + case KEY_RIGHT: + tui_scroll_left (win_info, 1); + break; + case KEY_LEFT: + tui_scroll_right (win_info, 1); + break; + case '\f': + tui_refresh_all_win (); + break; + default: + c = ch_copy; + break; + } + return c; + } +} diff --git a/gdb/tui/tui-command.h b/gdb/tui/tui-command.h new file mode 100644 index 00000000000..9653bf07ee5 --- /dev/null +++ b/gdb/tui/tui-command.h @@ -0,0 +1,30 @@ +/* Specific command window processing. + + Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation, + Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_COMMAND_H +#define TUI_COMMAND_H + +extern unsigned int tui_dispatch_ctrl_char (unsigned int); + +#endif diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c new file mode 100644 index 00000000000..1f41023a265 --- /dev/null +++ b/gdb/tui/tui-data.c @@ -0,0 +1,928 @@ +/* TUI data manipulation routines. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-wingeneral.h" + +#include "gdb_string.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/**************************** +** GLOBAL DECLARATIONS +****************************/ +struct tui_win_info *(tui_win_list[MAX_MAJOR_WINDOWS]); + +/*************************** +** Private data +****************************/ +static enum tui_layout_type current_layout = UNDEFINED_LAYOUT; +static int term_height, term_width; +static struct tui_gen_win_info _locator; +static struct tui_gen_win_info exec_info[2]; +static struct tui_win_info * src_win_list[2]; +static struct tui_list source_windows = {(void **) src_win_list, 0}; +static int default_tab_len = DEFAULT_TAB_LEN; +static struct tui_win_info * win_with_focus = (struct tui_win_info *) NULL; +static struct tui_layout_def layout_def = +{SRC_WIN, /* DISPLAY_MODE */ + FALSE, /* SPLIT */ + TUI_UNDEFINED_REGS, /* REGS_DISPLAY_TYPE */ + TUI_SFLOAT_REGS}; /* FLOAT_REGS_DISPLAY_TYPE */ +static int win_resized = FALSE; + + +/********************************* +** Static function forward decls +**********************************/ +static void free_content (tui_win_content, int, enum tui_win_type); +static void free_content_elements (tui_win_content, int, enum tui_win_type); + + + +/********************************* +** PUBLIC FUNCTIONS +**********************************/ + +int +tui_win_is_source_type (enum tui_win_type win_type) +{ + return (win_type == SRC_WIN || win_type == DISASSEM_WIN); +} + +int +tui_win_is_auxillary (enum tui_win_type win_type) +{ + return (win_type > MAX_MAJOR_WINDOWS); +} + +int +tui_win_has_locator (struct tui_win_info *win_info) +{ + return (win_info != NULL \ + && win_info->detail.source_info.has_locator); +} + +void +tui_set_win_highlight (struct tui_win_info *win_info, int highlight) +{ + if (win_info != NULL) + win_info->is_highlighted = highlight; +} + +/****************************************** +** ACCESSORS & MUTATORS FOR PRIVATE DATA +******************************************/ + +/* Answer a whether the terminal window has been resized or not. */ +int +tui_win_resized (void) +{ + return win_resized; +} + + +/* Set a whether the terminal window has been resized or not. */ +void +tui_set_win_resized_to (int resized) +{ + win_resized = resized; +} + + +/* Answer a pointer to the current layout definition. */ +struct tui_layout_def * +tui_layout_def (void) +{ + return &layout_def; +} + + +/* Answer the window with the logical focus. */ +struct tui_win_info * +tui_win_with_focus (void) +{ + return win_with_focus; +} + + +/* Set the window that has the logical focus. */ +void +tui_set_win_with_focus (struct tui_win_info * win_info) +{ + win_with_focus = win_info; +} + + +/* Answer the length in chars, of tabs. */ +int +tui_default_tab_len (void) +{ + return default_tab_len; +} + + +/* Set the length in chars, of tabs. */ +void +tui_set_default_tab_len (int len) +{ + default_tab_len = len; +} + + +/* Accessor for the current source window. Usually there is only one + source window (either source or disassembly), but both can be + displayed at the same time. */ +struct tui_list * +tui_source_windows (void) +{ + return &source_windows; +} + + +/* Clear the list of source windows. Usually there is only one source + window (either source or disassembly), but both can be displayed at + the same time. */ +void +tui_clear_source_windows (void) +{ + source_windows.list[0] = NULL; + source_windows.list[1] = NULL; + source_windows.count = 0; +} + + +/* Clear the pertinant detail in the source windows. */ +void +tui_clear_source_windows_detail (void) +{ + int i; + + for (i = 0; i < (tui_source_windows ())->count; i++) + tui_clear_win_detail ((struct tui_win_info *) (tui_source_windows ())->list[i]); +} + + +/* Add a window to the list of source windows. Usually there is only + one source window (either source or disassembly), but both can be + displayed at the same time. */ +void +tui_add_to_source_windows (struct tui_win_info * win_info) +{ + if (source_windows.count < 2) + source_windows.list[source_windows.count++] = (void *) win_info; +} + + +/* Clear the pertinant detail in the windows. */ +void +tui_clear_win_detail (struct tui_win_info * win_info) +{ + if (win_info != NULL) + { + switch (win_info->generic.type) + { + case SRC_WIN: + case DISASSEM_WIN: + win_info->detail.source_info.start_line_or_addr.addr = 0; + win_info->detail.source_info.horizontal_offset = 0; + break; + case CMD_WIN: + win_info->detail.command_info.cur_line = + win_info->detail.command_info.curch = 0; + break; + case DATA_WIN: + win_info->detail.data_display_info.data_content = + (tui_win_content) NULL; + win_info->detail.data_display_info.data_content_count = 0; + win_info->detail.data_display_info.regs_content = + (tui_win_content) NULL; + win_info->detail.data_display_info.regs_content_count = 0; + win_info->detail.data_display_info.regs_display_type = + TUI_UNDEFINED_REGS; + win_info->detail.data_display_info.regs_column_count = 1; + win_info->detail.data_display_info.display_regs = FALSE; + break; + default: + break; + } + } +} + + +/* Accessor for the source execution info ptr. */ +struct tui_gen_win_info * +tui_source_exec_info_win_ptr (void) +{ + return &exec_info[0]; +} + + +/* Accessor for the disassem execution info ptr. */ +struct tui_gen_win_info * +tui_disassem_exec_info_win_ptr (void) +{ + return &exec_info[1]; +} + + +/* Accessor for the locator win info. Answers a pointer to the static + locator win info struct. */ +struct tui_gen_win_info * +tui_locator_win_info_ptr (void) +{ + return &_locator; +} + + +/* Accessor for the term_height. */ +int +tui_term_height (void) +{ + return term_height; +} + + +/* Mutator for the term height. */ +void +tui_set_term_height_to (int h) +{ + term_height = h; +} + + +/* Accessor for the term_width. */ +int +tui_term_width (void) +{ + return term_width; +} + + +/* Mutator for the term_width. */ +void +tui_set_term_width_to (int w) +{ + term_width = w; +} + + +/* Accessor for the current layout. */ +enum tui_layout_type +tui_current_layout (void) +{ + return current_layout; +} + + +/* Mutator for the current layout. */ +void +tui_set_current_layout_to (enum tui_layout_type new_layout) +{ + current_layout = new_layout; +} + + +/* Set the origin of the window. */ +void +set_gen_win_origin (struct tui_gen_win_info * win_info, int x, int y) +{ + win_info->origin.x = x; + win_info->origin.y = y; +} + + +/***************************** +** OTHER PUBLIC FUNCTIONS +*****************************/ + + +/* Answer the next window in the list, cycling back to the top if + necessary. */ +struct tui_win_info * +tui_next_win (struct tui_win_info * cur_win) +{ + enum tui_win_type type = cur_win->generic.type; + struct tui_win_info * next_win = (struct tui_win_info *) NULL; + + if (cur_win->generic.type == CMD_WIN) + type = SRC_WIN; + else + type = cur_win->generic.type + 1; + while (type != cur_win->generic.type && (next_win == NULL)) + { + if (tui_win_list[type] && tui_win_list[type]->generic.is_visible) + next_win = tui_win_list[type]; + else + { + if (type == CMD_WIN) + type = SRC_WIN; + else + type++; + } + } + + return next_win; +} + + +/* Answer the prev window in the list, cycling back to the bottom if + necessary. */ +struct tui_win_info * +tui_prev_win (struct tui_win_info * cur_win) +{ + enum tui_win_type type = cur_win->generic.type; + struct tui_win_info * prev = (struct tui_win_info *) NULL; + + if (cur_win->generic.type == SRC_WIN) + type = CMD_WIN; + else + type = cur_win->generic.type - 1; + while (type != cur_win->generic.type && (prev == NULL)) + { + if (tui_win_list[type]->generic.is_visible) + prev = tui_win_list[type]; + else + { + if (type == SRC_WIN) + type = CMD_WIN; + else + type--; + } + } + + return prev; +} + + +/* Answer the window represented by name. */ +struct tui_win_info * +tui_partial_win_by_name (char *name) +{ + struct tui_win_info * win_info = (struct tui_win_info *) NULL; + + if (name != (char *) NULL) + { + int i = 0; + + while (i < MAX_MAJOR_WINDOWS && win_info == NULL) + { + if (tui_win_list[i] != 0) + { + char *cur_name = tui_win_name (&tui_win_list[i]->generic); + if (strlen (name) <= strlen (cur_name) && + strncmp (name, cur_name, strlen (name)) == 0) + win_info = tui_win_list[i]; + } + i++; + } + } + + return win_info; +} + + +/* Answer the name of the window. */ +char * +tui_win_name (struct tui_gen_win_info * win_info) +{ + char *name = (char *) NULL; + + switch (win_info->type) + { + case SRC_WIN: + name = SRC_NAME; + break; + case CMD_WIN: + name = CMD_NAME; + break; + case DISASSEM_WIN: + name = DISASSEM_NAME; + break; + case DATA_WIN: + name = DATA_NAME; + break; + default: + name = ""; + break; + } + + return name; +} + + +void +tui_initialize_static_data (void) +{ + tui_init_generic_part (tui_source_exec_info_win_ptr ()); + tui_init_generic_part (tui_disassem_exec_info_win_ptr ()); + tui_init_generic_part (tui_locator_win_info_ptr ()); +} + + +struct tui_gen_win_info * +tui_alloc_generic_win_info (void) +{ + struct tui_gen_win_info * win; + + if ((win = (struct tui_gen_win_info *) xmalloc ( + sizeof (struct tui_gen_win_info *))) != (struct tui_gen_win_info *) NULL) + tui_init_generic_part (win); + + return win; +} + + +void +tui_init_generic_part (struct tui_gen_win_info * win) +{ + win->width = + win->height = + win->origin.x = + win->origin.y = + win->viewport_height = + win->content_size = + win->last_visible_line = 0; + win->handle = (WINDOW *) NULL; + win->content = NULL; + win->content_in_use = + win->is_visible = FALSE; + win->title = 0; +} + + +/* + ** init_content_element(). + */ +void +init_content_element (struct tui_win_element * element, enum tui_win_type type) +{ + element->highlight = FALSE; + switch (type) + { + case SRC_WIN: + case DISASSEM_WIN: + element->which_element.source.line = (char *) NULL; + element->which_element.source.line_or_addr.line_no = 0; + element->which_element.source.is_exec_point = FALSE; + element->which_element.source.has_break = FALSE; + break; + case DATA_WIN: + tui_init_generic_part (&element->which_element.data_window); + element->which_element.data_window.type = DATA_ITEM_WIN; + ((struct tui_gen_win_info *) & element->which_element.data_window)->content = + (void **) tui_alloc_content (1, DATA_ITEM_WIN); + ((struct tui_gen_win_info *) + & element->which_element.data_window)->content_size = 1; + break; + case CMD_WIN: + element->which_element.command.line = (char *) NULL; + break; + case DATA_ITEM_WIN: + element->which_element.data.name = (char *) NULL; + element->which_element.data.type = TUI_REGISTER; + element->which_element.data.item_no = UNDEFINED_ITEM; + element->which_element.data.value = NULL; + element->which_element.data.highlight = FALSE; + break; + case LOCATOR_WIN: + element->which_element.locator.file_name[0] = + element->which_element.locator.proc_name[0] = (char) 0; + element->which_element.locator.line_no = 0; + element->which_element.locator.addr = 0; + break; + case EXEC_INFO_WIN: + memset(element->which_element.simple_string, ' ', + sizeof(element->which_element.simple_string)); + break; + default: + break; + } +} + +void +init_win_info (struct tui_win_info * win_info) +{ + tui_init_generic_part (&win_info->generic); + win_info->can_highlight = + win_info->is_highlighted = FALSE; + switch (win_info->generic.type) + { + case SRC_WIN: + case DISASSEM_WIN: + win_info->detail.source_info.execution_info = (struct tui_gen_win_info *) NULL; + win_info->detail.source_info.has_locator = FALSE; + win_info->detail.source_info.horizontal_offset = 0; + win_info->detail.source_info.start_line_or_addr.addr = 0; + win_info->detail.source_info.filename = 0; + break; + case DATA_WIN: + win_info->detail.data_display_info.data_content = (tui_win_content) NULL; + win_info->detail.data_display_info.data_content_count = 0; + win_info->detail.data_display_info.regs_content = (tui_win_content) NULL; + win_info->detail.data_display_info.regs_content_count = 0; + win_info->detail.data_display_info.regs_display_type = + TUI_UNDEFINED_REGS; + win_info->detail.data_display_info.regs_column_count = 1; + win_info->detail.data_display_info.display_regs = FALSE; + break; + case CMD_WIN: + win_info->detail.command_info.cur_line = 0; + win_info->detail.command_info.curch = 0; + break; + default: + win_info->detail.opaque = NULL; + break; + } +} + + +struct tui_win_info * +tui_alloc_win_info (enum tui_win_type type) +{ + struct tui_win_info * win_info = (struct tui_win_info *) NULL; + + win_info = (struct tui_win_info *) xmalloc (sizeof (struct tui_win_info)); + if ((win_info != NULL)) + { + win_info->generic.type = type; + init_win_info (win_info); + } + + return win_info; +} + + +/* Allocates the content and elements in a block. */ +tui_win_content +tui_alloc_content (int num_elements, enum tui_win_type type) +{ + tui_win_content content = (tui_win_content) NULL; + char *element_block_ptr = (char *) NULL; + int i; + + if ((content = (tui_win_content) + xmalloc (sizeof (struct tui_win_element *) * num_elements)) != (tui_win_content) NULL) + { /* + ** All windows, except the data window, can allocate the elements + ** in a chunk. The data window cannot because items can be + ** added/removed from the data display by the user at any time. + */ + if (type != DATA_WIN) + { + if ((element_block_ptr = (char *) + xmalloc (sizeof (struct tui_win_element) * num_elements)) != (char *) NULL) + { + for (i = 0; i < num_elements; i++) + { + content[i] = (struct tui_win_element *) element_block_ptr; + init_content_element (content[i], type); + element_block_ptr += sizeof (struct tui_win_element); + } + } + else + { + xfree (content); + content = (tui_win_content) NULL; + } + } + } + + return content; +} + + +/* Adds the input number of elements to the windows's content. If no + content has been allocated yet, alloc_content() is called to do + this. The index of the first element added is returned, unless + there is a memory allocation error, in which case, (-1) is + returned. */ +int +tui_add_content_elements (struct tui_gen_win_info * win_info, int num_elements) +{ + struct tui_win_element * element_ptr; + int i, index_start; + + if (win_info->content == NULL) + { + win_info->content = (void **) tui_alloc_content (num_elements, win_info->type); + index_start = 0; + } + else + index_start = win_info->content_size; + if (win_info->content != NULL) + { + for (i = index_start; (i < num_elements + index_start); i++) + { + if ((element_ptr = (struct tui_win_element *) + xmalloc (sizeof (struct tui_win_element))) != (struct tui_win_element *) NULL) + { + win_info->content[i] = (void *) element_ptr; + init_content_element (element_ptr, win_info->type); + win_info->content_size++; + } + else /* things must be really hosed now! We ran out of memory!? */ + return (-1); + } + } + + return index_start; +} + + +/* Delete all curses windows associated with win_info, leaving everything + else intact. */ +void +tui_del_window (struct tui_win_info * win_info) +{ + struct tui_gen_win_info * generic_win; + + switch (win_info->generic.type) + { + case SRC_WIN: + case DISASSEM_WIN: + generic_win = tui_locator_win_info_ptr (); + if (generic_win != (struct tui_gen_win_info *) NULL) + { + tui_delete_win (generic_win->handle); + generic_win->handle = (WINDOW *) NULL; + generic_win->is_visible = FALSE; + } + if (win_info->detail.source_info.filename) + { + xfree (win_info->detail.source_info.filename); + win_info->detail.source_info.filename = 0; + } + generic_win = win_info->detail.source_info.execution_info; + if (generic_win != (struct tui_gen_win_info *) NULL) + { + tui_delete_win (generic_win->handle); + generic_win->handle = (WINDOW *) NULL; + generic_win->is_visible = FALSE; + } + break; + case DATA_WIN: + if (win_info->generic.content != NULL) + { + tui_del_data_windows (win_info->detail.data_display_info.regs_content, + win_info->detail.data_display_info.regs_content_count); + tui_del_data_windows (win_info->detail.data_display_info.data_content, + win_info->detail.data_display_info.data_content_count); + } + break; + default: + break; + } + if (win_info->generic.handle != (WINDOW *) NULL) + { + tui_delete_win (win_info->generic.handle); + win_info->generic.handle = (WINDOW *) NULL; + win_info->generic.is_visible = FALSE; + } +} + + +void +tui_free_window (struct tui_win_info * win_info) +{ + struct tui_gen_win_info * generic_win; + + switch (win_info->generic.type) + { + case SRC_WIN: + case DISASSEM_WIN: + generic_win = tui_locator_win_info_ptr (); + if (generic_win != (struct tui_gen_win_info *) NULL) + { + tui_delete_win (generic_win->handle); + generic_win->handle = (WINDOW *) NULL; + } + tui_free_win_content (generic_win); + if (win_info->detail.source_info.filename) + { + xfree (win_info->detail.source_info.filename); + win_info->detail.source_info.filename = 0; + } + generic_win = win_info->detail.source_info.execution_info; + if (generic_win != (struct tui_gen_win_info *) NULL) + { + tui_delete_win (generic_win->handle); + generic_win->handle = (WINDOW *) NULL; + tui_free_win_content (generic_win); + } + break; + case DATA_WIN: + if (win_info->generic.content != NULL) + { + tui_free_data_content (win_info->detail.data_display_info.regs_content, + win_info->detail.data_display_info.regs_content_count); + win_info->detail.data_display_info.regs_content = + (tui_win_content) NULL; + win_info->detail.data_display_info.regs_content_count = 0; + tui_free_data_content (win_info->detail.data_display_info.data_content, + win_info->detail.data_display_info.data_content_count); + win_info->detail.data_display_info.data_content = + (tui_win_content) NULL; + win_info->detail.data_display_info.data_content_count = 0; + win_info->detail.data_display_info.regs_display_type = + TUI_UNDEFINED_REGS; + win_info->detail.data_display_info.regs_column_count = 1; + win_info->detail.data_display_info.display_regs = FALSE; + win_info->generic.content = NULL; + win_info->generic.content_size = 0; + } + break; + default: + break; + } + if (win_info->generic.handle != (WINDOW *) NULL) + { + tui_delete_win (win_info->generic.handle); + win_info->generic.handle = (WINDOW *) NULL; + tui_free_win_content (&win_info->generic); + } + if (win_info->generic.title) + xfree (win_info->generic.title); + xfree (win_info); +} + + +void +tui_free_all_source_wins_content (void) +{ + int i; + + for (i = 0; i < (tui_source_windows ())->count; i++) + { + struct tui_win_info * win_info = (struct tui_win_info *) (tui_source_windows ())->list[i]; + + if (win_info != NULL) + { + tui_free_win_content (&(win_info->generic)); + tui_free_win_content (win_info->detail.source_info.execution_info); + } + } +} + + +void +tui_free_win_content (struct tui_gen_win_info * win_info) +{ + if (win_info->content != NULL) + { + free_content ((tui_win_content) win_info->content, + win_info->content_size, + win_info->type); + win_info->content = NULL; + } + win_info->content_size = 0; +} + + +void +tui_del_data_windows (tui_win_content content, int content_size) +{ + int i; + + /* + ** Remember that data window content elements are of type struct tui_gen_win_info *, + ** each of which whose single element is a data element. + */ + for (i = 0; i < content_size; i++) + { + struct tui_gen_win_info * generic_win = &content[i]->which_element.data_window; + + if (generic_win != (struct tui_gen_win_info *) NULL) + { + tui_delete_win (generic_win->handle); + generic_win->handle = (WINDOW *) NULL; + generic_win->is_visible = FALSE; + } + } +} + + +void +tui_free_data_content (tui_win_content content, int content_size) +{ + int i; + + /* + ** Remember that data window content elements are of type struct tui_gen_win_info *, + ** each of which whose single element is a data element. + */ + for (i = 0; i < content_size; i++) + { + struct tui_gen_win_info * generic_win = &content[i]->which_element.data_window; + + if (generic_win != (struct tui_gen_win_info *) NULL) + { + tui_delete_win (generic_win->handle); + generic_win->handle = (WINDOW *) NULL; + tui_free_win_content (generic_win); + } + } + free_content (content, + content_size, + DATA_WIN); +} + + +/********************************** +** LOCAL STATIC FUNCTIONS ** +**********************************/ + + +static void +free_content (tui_win_content content, int content_size, enum tui_win_type win_type) +{ + if (content != (tui_win_content) NULL) + { + free_content_elements (content, content_size, win_type); + xfree (content); + } +} + + +/* + ** free_content_elements(). + */ +static void +free_content_elements (tui_win_content content, int content_size, enum tui_win_type type) +{ + if (content != (tui_win_content) NULL) + { + int i; + + if (type == SRC_WIN || type == DISASSEM_WIN) + { + /* free whole source block */ + xfree (content[0]->which_element.source.line); + } + else + { + for (i = 0; i < content_size; i++) + { + struct tui_win_element * element; + + element = content[i]; + if (element != (struct tui_win_element *) NULL) + { + switch (type) + { + case DATA_WIN: + xfree (element); + break; + case DATA_ITEM_WIN: + /* + ** Note that data elements are not allocated + ** in a single block, but individually, as needed. + */ + if (element->which_element.data.type != TUI_REGISTER) + xfree ((void *)element->which_element.data.name); + xfree (element->which_element.data.value); + xfree (element); + break; + case CMD_WIN: + xfree (element->which_element.command.line); + break; + default: + break; + } + } + } + } + if (type != DATA_WIN && type != DATA_ITEM_WIN) + xfree (content[0]); /* free the element block */ + } +} diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h new file mode 100644 index 00000000000..8628172ff3b --- /dev/null +++ b/gdb/tui/tui-data.h @@ -0,0 +1,346 @@ +/* TUI data manipulation routines. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_DATA_H +#define TUI_DATA_H + +#if defined (HAVE_NCURSES_H) +#include +#elif defined (HAVE_CURSES_H) +#include +#endif + +/* Generic window information */ +struct tui_gen_win_info +{ + WINDOW *handle; /* window handle */ + enum tui_win_type type; /* type of window */ + int width; /* window width */ + int height; /* window height */ + struct tui_point origin; /* origin of window */ + void **content; /* content of window */ + int content_size; /* Size of content (# of elements) */ + int content_in_use; /* Can it be used, or is it already used? */ + int viewport_height; /* viewport height */ + int last_visible_line; /* index of last visible line */ + int is_visible; /* whether the window is visible or not */ + char *title; /* Window title to display. */ +}; + +/* Constant definitions */ +#define DEFAULT_TAB_LEN 8 +#define NO_SRC_STRING "[ No Source Available ]" +#define NO_DISASSEM_STRING "[ No Assembly Available ]" +#define NO_REGS_STRING "[ Register Values Unavailable ]" +#define NO_DATA_STRING "[ No Data Values Displayed ]" +#define MAX_CONTENT_COUNT 100 +#define SRC_NAME "SRC" +#define CMD_NAME "CMD" +#define DATA_NAME "REGS" +#define DISASSEM_NAME "ASM" +#define TUI_NULL_STR "" +#define DEFAULT_HISTORY_COUNT 25 +#define BOX_WINDOW TRUE +#define DONT_BOX_WINDOW FALSE +#define HILITE TRUE +#define NO_HILITE FALSE +#define WITH_LOCATOR TRUE +#define NO_LOCATOR FALSE +#define EMPTY_SOURCE_PROMPT TRUE +#define NO_EMPTY_SOURCE_PROMPT FALSE +#define UNDEFINED_ITEM -1 +#define MIN_WIN_HEIGHT 3 +#define MIN_CMD_WIN_HEIGHT 3 + +/* Strings to display in the TUI status line. */ +#define PROC_PREFIX "In: " +#define LINE_PREFIX "Line: " +#define PC_PREFIX "PC: " +#define SINGLE_KEY "(SingleKey)" + +/* Minimum/Maximum length of some fields displayed in the TUI status line. */ +#define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line numbers. */ +#define MIN_PROC_WIDTH 12 +#define MAX_TARGET_WIDTH 10 +#define MAX_PID_WIDTH 14 + +#define TUI_FLOAT_REGS_NAME "$FREGS" +#define TUI_FLOAT_REGS_NAME_LOWER "$fregs" +#define TUI_GENERAL_REGS_NAME "$GREGS" +#define TUI_GENERAL_REGS_NAME_LOWER "$gregs" +#define TUI_SPECIAL_REGS_NAME "$SREGS" +#define TUI_SPECIAL_REGS_NAME_LOWER "$sregs" +#define TUI_GENERAL_SPECIAL_REGS_NAME "$REGS" +#define TUI_GENERAL_SPECIAL_REGS_NAME_LOWER "$regs" + +/* Scroll direction enum. */ +enum tui_scroll_direction +{ + FORWARD_SCROLL, + BACKWARD_SCROLL, + LEFT_SCROLL, + RIGHT_SCROLL +}; + + +/* General list struct. */ +struct tui_list +{ + void **list; + int count; +}; + + +/* The kinds of layouts available */ +enum tui_layout_type +{ + SRC_COMMAND, + DISASSEM_COMMAND, + SRC_DISASSEM_COMMAND, + SRC_DATA_COMMAND, + DISASSEM_DATA_COMMAND, + UNDEFINED_LAYOUT +}; + +/* Basic data types that can be displayed in the data window. */ +enum tui_data_type +{ + TUI_REGISTER, + TUI_SCALAR, + TUI_COMPLEX, + TUI_STRUCT +}; + +/* Types of register displays */ +enum tui_register_display_type +{ + TUI_UNDEFINED_REGS, + TUI_GENERAL_REGS, + TUI_SFLOAT_REGS, + TUI_DFLOAT_REGS, + TUI_SPECIAL_REGS, + TUI_GENERAL_AND_SPECIAL_REGS +}; + +/* Structure describing source line or line address */ +union tui_line_or_address +{ + int line_no; + CORE_ADDR addr; +}; + +/* Current Layout definition */ +struct tui_layout_def +{ + enum tui_win_type display_mode; + int split; + enum tui_register_display_type regs_display_type; + enum tui_register_display_type float_regs_display_type; +}; + +/* Elements in the Source/Disassembly Window */ +struct tui_source_element +{ + char *line; + union tui_line_or_address line_or_addr; + int is_exec_point; + int has_break; +}; + + +/* Elements in the data display window content */ +struct tui_data_element +{ + const char *name; + int item_no; /* the register number, or data display number */ + enum tui_data_type type; + void *value; + int highlight; +}; + + +/* Elements in the command window content */ +struct tui_command_element +{ + char *line; +}; + + +#define MAX_LOCATOR_ELEMENT_LEN 100 + +/* Elements in the locator window content */ +struct tui_locator_element +{ + char file_name[MAX_LOCATOR_ELEMENT_LEN]; + char proc_name[MAX_LOCATOR_ELEMENT_LEN]; + int line_no; + CORE_ADDR addr; +}; + +/* Flags to tell what kind of breakpoint is at current line. */ +#define TUI_BP_ENABLED 0x01 +#define TUI_BP_DISABLED 0x02 +#define TUI_BP_HIT 0x04 +#define TUI_BP_CONDITIONAL 0x08 +#define TUI_BP_HARDWARE 0x10 + +/* Position of breakpoint markers in the exec info string. */ +#define TUI_BP_HIT_POS 0 +#define TUI_BP_BREAK_POS 1 +#define TUI_EXEC_POS 2 +#define TUI_EXECINFO_SIZE 4 + +typedef char tui_exec_info_content[TUI_EXECINFO_SIZE]; + +/* An content element in a window */ +union tui_which_element +{ + struct tui_source_element source; /* the source elements */ + struct tui_gen_win_info data_window; /* data display elements */ + struct tui_data_element data; /* elements of data_window */ + struct tui_command_element command; /* command elements */ + struct tui_locator_element locator; /* locator elements */ + tui_exec_info_content simple_string; /* simple char based elements */ +}; + +struct tui_win_element +{ + int highlight; + union tui_which_element which_element; +}; + + +/* This describes the content of the window. */ +typedef struct tui_win_element **tui_win_content; + + +/* This struct defines the specific information about a data display window */ +struct tui_data_info +{ + tui_win_content data_content; /* start of data display content */ + int data_content_count; + tui_win_content regs_content; /* start of regs display content */ + int regs_content_count; + enum tui_register_display_type regs_display_type; + int regs_column_count; + int display_regs; /* Should regs be displayed at all? */ +}; + + +struct tui_source_info +{ + int has_locator; /* Does locator belongs to this window? */ + /* Execution information window. */ + struct tui_gen_win_info *execution_info; + int horizontal_offset; /* used for horizontal scroll */ + union tui_line_or_address start_line_or_addr; + char* filename; +}; + + +struct tui_command_info +{ + int cur_line; /* The current line position */ + int curch; /* The current cursor position */ + int start_line; +}; + + +/* This defines information about each logical window */ +struct tui_win_info +{ + struct tui_gen_win_info generic; /* general window information */ + union + { + struct tui_source_info source_info; + struct tui_data_info data_display_info; + struct tui_command_info command_info; + void *opaque; + } + detail; + int can_highlight; /* Can this window ever be highlighted? */ + int is_highlighted; /* Is this window highlighted? */ +}; + +extern int tui_win_is_source_type (enum tui_win_type win_type); +extern int tui_win_is_auxillary (enum tui_win_type win_type); +extern int tui_win_has_locator (struct tui_win_info *win_info); +extern void tui_set_win_highlight (struct tui_win_info *win_info, + int highlight); + + +/* Global Data */ +extern struct tui_win_info *(tui_win_list[MAX_MAJOR_WINDOWS]); + +#define TUI_SRC_WIN tui_win_list[SRC_WIN] +#define TUI_DISASM_WIN tui_win_list[DISASSEM_WIN] +#define TUI_DATA_WIN tui_win_list[DATA_WIN] +#define TUI_CMD_WIN tui_win_list[CMD_WIN] + +/* Data Manipulation Functions */ +extern void tui_initialize_static_data (void); +extern struct tui_gen_win_info *tui_alloc_generic_win_info (void); +extern struct tui_win_info *tui_alloc_win_info (enum tui_win_type); +extern void tui_init_generic_part (struct tui_gen_win_info *); +extern void tui_init_win_info (struct tui_win_info *); +extern tui_win_content tui_alloc_content (int, enum tui_win_type); +extern int tui_add_content_elements (struct tui_gen_win_info *, int); +extern void tui_init_content_element (struct tui_win_element *, enum tui_win_type); +extern void tui_free_window (struct tui_win_info *); +extern void tui_free_win_content (struct tui_gen_win_info *); +extern void tui_free_data_content (tui_win_content, int); +extern void tui_free_all_source_wins_content (void); +extern void tui_del_window (struct tui_win_info *); +extern void tui_del_data_windows (tui_win_content, int); +extern struct tui_win_info *tui_partial_win_by_name (char *); +extern char *tui_win_name (struct tui_gen_win_info *); +extern enum tui_layout_type tui_current_layout (void); +extern void tui_set_current_layout_to (enum tui_layout_type); +extern int tui_term_height (void); +extern void tui_set_term_height_to (int); +extern int tui_term_width (void); +extern void tui_set_term_width_to (int); +extern void tui_set_gen_win_origin (struct tui_gen_win_info *, int, int); +extern struct tui_gen_win_info *tui_locator_win_info_ptr (void); +extern struct tui_gen_win_info *tui_source_exec_info_win_ptr (void); +extern struct tui_gen_win_info *tui_disassem_exec_info_win_ptr (void); +extern struct tui_list * tui_source_windows (void); +extern void tui_clear_source_windows (void); +extern void tui_clear_source_windows_detail (void); +extern void tui_clear_win_detail (struct tui_win_info * win_info); +extern void tui_add_to_source_windows (struct tui_win_info *); +extern int tui_default_tab_len (void); +extern void tui_set_default_tab_len (int); +extern struct tui_win_info *tui_win_with_focus (void); +extern void tui_set_win_with_focus (struct tui_win_info *); +extern struct tui_layout_def * tui_layout_def (void); +extern int tui_win_resized (void); +extern void tui_set_win_resized_to (int); + +extern struct tui_win_info *tui_next_win (struct tui_win_info *); +extern struct tui_win_info *tui_prev_win (struct tui_win_info *); + +extern void tui_add_to_source_windows (struct tui_win_info * win_info); + +#endif /* TUI_DATA_H */ diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c new file mode 100644 index 00000000000..a4311218dcc --- /dev/null +++ b/gdb/tui/tui-disasm.c @@ -0,0 +1,403 @@ +/* Disassembly display. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "breakpoint.h" +#include "frame.h" +#include "value.h" +#include "source.h" +#include "disasm.h" +#include "gdb_string.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-win.h" +#include "tui/tui-layout.h" +#include "tui/tui-winsource.h" +#include "tui/tui-stack.h" +#include "tui/tui-file.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +struct tui_asm_line +{ + CORE_ADDR addr; + char* addr_string; + char* insn; +}; + +/* Function to set the disassembly window's content. + Disassemble count lines starting at pc. + Return address of the count'th instruction after pc. */ +static CORE_ADDR +tui_disassemble (struct tui_asm_line* lines, CORE_ADDR pc, int count) +{ + struct ui_file *gdb_dis_out; + + /* now init the ui_file structure */ + gdb_dis_out = tui_sfileopen (256); + + /* Now construct each line */ + for (; count > 0; count--, lines++) + { + if (lines->addr_string) + xfree (lines->addr_string); + if (lines->insn) + xfree (lines->insn); + + print_address (pc, gdb_dis_out); + lines->addr = pc; + lines->addr_string = xstrdup (tui_file_get_strbuf (gdb_dis_out)); + + ui_file_rewind (gdb_dis_out); + + pc = pc + gdb_print_insn (pc, gdb_dis_out); + + lines->insn = xstrdup (tui_file_get_strbuf (gdb_dis_out)); + + /* reset the buffer to empty */ + ui_file_rewind (gdb_dis_out); + } + ui_file_delete (gdb_dis_out); + return pc; +} + +/* Find the disassembly address that corresponds to FROM lines + above or below the PC. Variable sized instructions are taken + into account by the algorithm. */ +static CORE_ADDR +tui_find_disassembly_address (CORE_ADDR pc, int from) +{ + CORE_ADDR new_low; + int max_lines; + int i; + struct tui_asm_line* lines; + + max_lines = (from > 0) ? from : - from; + if (max_lines <= 1) + return pc; + + lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line) + * max_lines); + memset (lines, 0, sizeof (struct tui_asm_line) * max_lines); + + new_low = pc; + if (from > 0) + { + tui_disassemble (lines, pc, max_lines); + new_low = lines[max_lines - 1].addr; + } + else + { + CORE_ADDR last_addr; + int pos; + struct minimal_symbol* msymbol; + + /* Find backward an address which is a symbol + and for which disassembling from that address will fill + completely the window. */ + pos = max_lines - 1; + do { + new_low -= 1 * max_lines; + msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0); + + if (msymbol) + new_low = SYMBOL_VALUE_ADDRESS (msymbol); + else + new_low += 1 * max_lines; + + tui_disassemble (lines, new_low, max_lines); + last_addr = lines[pos].addr; + } while (last_addr > pc && msymbol); + + /* Scan forward disassembling one instruction at a time + until the last visible instruction of the window + matches the pc. We keep the disassembled instructions + in the 'lines' window and shift it downward (increasing + its addresses). */ + if (last_addr < pc) + do + { + CORE_ADDR next_addr; + + pos++; + if (pos >= max_lines) + pos = 0; + + next_addr = tui_disassemble (&lines[pos], last_addr, 1); + + /* If there are some problems while disassembling exit. */ + if (next_addr <= last_addr) + break; + last_addr = next_addr; + } while (last_addr <= pc); + pos++; + if (pos >= max_lines) + pos = 0; + new_low = lines[pos].addr; + } + for (i = 0; i < max_lines; i++) + { + xfree (lines[i].addr_string); + xfree (lines[i].insn); + } + return new_low; +} + +/* Function to set the disassembly window's content. */ +enum tui_status +tui_set_disassem_content (CORE_ADDR pc) +{ + enum tui_status ret = TUI_FAILURE; + int i; + int offset = TUI_DISASM_WIN->detail.source_info.horizontal_offset; + int line_width, max_lines; + CORE_ADDR cur_pc; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + int tab_len = tui_default_tab_len (); + struct tui_asm_line* lines; + int insn_pos; + int addr_size, max_size; + char* line; + + if (pc == 0) + return TUI_FAILURE; + + ret = tui_alloc_source_buffer (TUI_DISASM_WIN); + if (ret != TUI_SUCCESS) + return ret; + + TUI_DISASM_WIN->detail.source_info.start_line_or_addr.addr = pc; + cur_pc = (CORE_ADDR) + (((struct tui_win_element *) locator->content[0])->which_element.locator.addr); + + max_lines = TUI_DISASM_WIN->generic.height - 2; /* account for hilite */ + + /* Get temporary table that will hold all strings (addr & insn). */ + lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line) + * max_lines); + memset (lines, 0, sizeof (struct tui_asm_line) * max_lines); + + line_width = TUI_DISASM_WIN->generic.width - 1; + + tui_disassemble (lines, pc, max_lines); + + /* See what is the maximum length of an address and of a line. */ + addr_size = 0; + max_size = 0; + for (i = 0; i < max_lines; i++) + { + size_t len = strlen (lines[i].addr_string); + if (len > addr_size) + addr_size = len; + + len = strlen (lines[i].insn) + tab_len; + if (len > max_size) + max_size = len; + } + max_size += addr_size + tab_len; + + /* Allocate memory to create each line. */ + line = (char*) alloca (max_size); + insn_pos = (1 + (addr_size / tab_len)) * tab_len; + + /* Now construct each line */ + for (i = 0; i < max_lines; i++) + { + struct tui_win_element * element; + struct tui_source_element* src; + int cur_len; + + element = (struct tui_win_element *) TUI_DISASM_WIN->generic.content[i]; + src = &element->which_element.source; + strcpy (line, lines[i].addr_string); + cur_len = strlen (line); + + /* Add spaces to make the instructions start on the same column */ + while (cur_len < insn_pos) + { + strcat (line, " "); + cur_len++; + } + + strcat (line, lines[i].insn); + + /* Now copy the line taking the offset into account */ + if (strlen (line) > offset) + strcpy (src->line, &line[offset]); + else + src->line[0] = '\0'; + + src->line_or_addr.addr = lines[i].addr; + src->is_exec_point = lines[i].addr == cur_pc; + + /* See whether there is a breakpoint installed. */ + src->has_break = (!src->is_exec_point + && breakpoint_here_p (pc) != no_breakpoint_here); + + xfree (lines[i].addr_string); + xfree (lines[i].insn); + } + TUI_DISASM_WIN->generic.content_size = i; + return TUI_SUCCESS; +} + + +/* Function to display the disassembly window with disassembled code. */ +void +tui_show_disassem (CORE_ADDR start_addr) +{ + struct symtab *s = find_pc_symtab (start_addr); + struct tui_win_info * win_with_focus = tui_win_with_focus (); + union tui_line_or_address val; + + val.addr = start_addr; + tui_add_win_to_layout (DISASSEM_WIN); + tui_update_source_window (TUI_DISASM_WIN, s, val, FALSE); + /* + ** if the focus was in the src win, put it in the asm win, if the + ** source view isn't split + */ + if (tui_current_layout () != SRC_DISASSEM_COMMAND && win_with_focus == TUI_SRC_WIN) + tui_set_win_focus_to (TUI_DISASM_WIN); + + return; +} + + +/* Function to display the disassembly window. */ +void +tui_show_disassem_and_update_source (CORE_ADDR start_addr) +{ + struct symtab_and_line sal; + + tui_show_disassem (start_addr); + if (tui_current_layout () == SRC_DISASSEM_COMMAND) + { + union tui_line_or_address val; + + /* + ** Update what is in the source window if it is displayed too, + ** note that it follows what is in the disassembly window and visa-versa + */ + sal = find_pc_line (start_addr, 0); + val.line_no = sal.line; + tui_update_source_window (TUI_SRC_WIN, sal.symtab, val, TRUE); + if (sal.symtab) + { + set_current_source_symtab_and_line (&sal); + tui_update_locator_filename (sal.symtab->filename); + } + else + tui_update_locator_filename ("?"); + } + + return; +} + +CORE_ADDR +tui_get_begin_asm_address (void) +{ + struct tui_gen_win_info * locator; + struct tui_locator_element * element; + CORE_ADDR addr; + + locator = tui_locator_win_info_ptr (); + element = &((struct tui_win_element *) locator->content[0])->which_element.locator; + + if (element->addr == 0) + { + struct minimal_symbol *main_symbol; + + /* Find address of the start of program. + Note: this should be language specific. */ + main_symbol = lookup_minimal_symbol ("main", NULL, NULL); + if (main_symbol == 0) + main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL); + if (main_symbol == 0) + main_symbol = lookup_minimal_symbol ("_start", NULL, NULL); + if (main_symbol) + addr = SYMBOL_VALUE_ADDRESS (main_symbol); + else + addr = 0; + } + else /* the target is executing */ + addr = element->addr; + + return addr; +} + +/* Determine what the low address will be to display in the TUI's + disassembly window. This may or may not be the same as the + low address input. */ +CORE_ADDR +tui_get_low_disassembly_address (CORE_ADDR low, CORE_ADDR pc) +{ + int pos; + + /* Determine where to start the disassembly so that the pc is about in the + middle of the viewport. */ + pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2; + pc = tui_find_disassembly_address (pc, -pos); + + if (pc < low) + pc = low; + return pc; +} + +/* Scroll the disassembly forward or backward vertically. */ +void +tui_vertical_disassem_scroll (enum tui_scroll_direction scroll_direction, + int num_to_scroll) +{ + if (TUI_DISASM_WIN->generic.content != NULL) + { + CORE_ADDR pc; + tui_win_content content; + struct symtab *s; + union tui_line_or_address val; + int max_lines, dir; + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + + content = (tui_win_content) TUI_DISASM_WIN->generic.content; + if (cursal.symtab == (struct symtab *) NULL) + s = find_pc_symtab (get_frame_pc (deprecated_selected_frame)); + else + s = cursal.symtab; + + /* account for hilite */ + max_lines = TUI_DISASM_WIN->generic.height - 2; + pc = content[0]->which_element.source.line_or_addr.addr; + dir = (scroll_direction == FORWARD_SCROLL) ? max_lines : - max_lines; + + val.addr = tui_find_disassembly_address (pc, dir); + tui_update_source_window_as_is (TUI_DISASM_WIN, s, val, FALSE); + } +} diff --git a/gdb/tui/tui-disasm.h b/gdb/tui/tui-disasm.h new file mode 100644 index 00000000000..e72aba1f3f1 --- /dev/null +++ b/gdb/tui/tui-disasm.h @@ -0,0 +1,37 @@ +/* Disassembly display. + + Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation, + Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_DISASM_H +#define TUI_DISASM_H + +#include "tui/tui.h" /* For enum tui_status. */ +#include "tui/tui-data.h" /* For enum tui_scroll_direction. */ + +extern enum tui_status tui_set_disassem_content (CORE_ADDR); +extern void tui_show_disassem (CORE_ADDR); +extern void tui_show_disassem_and_update_source (CORE_ADDR); +extern void tui_vertical_disassem_scroll (enum tui_scroll_direction, int); +extern CORE_ADDR tui_get_begin_asm_address (void); + +#endif diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c new file mode 100644 index 00000000000..6ca2beeb85e --- /dev/null +++ b/gdb/tui/tui-io.c @@ -0,0 +1,714 @@ +/* TUI support I/O functions. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "terminal.h" +#include "target.h" +#include "event-loop.h" +#include "event-top.h" +#include "command.h" +#include "top.h" +#include "readline/readline.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-io.h" +#include "tui/tui-command.h" +#include "tui/tui-win.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-file.h" +#include "ui-out.h" +#include "cli-out.h" +#include +#include +#include + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +int +key_is_start_sequence (int ch) +{ + return (ch == 27); +} + +int +key_is_end_sequence (int ch) +{ + return (ch == 126); +} + +int +key_is_backspace (int ch) +{ + return (ch == 8); +} + +int +key_is_command_char (int ch) +{ + return ((ch == KEY_NPAGE) || (ch == KEY_PPAGE) + || (ch == KEY_LEFT) || (ch == KEY_RIGHT) + || (ch == KEY_UP) || (ch == KEY_DOWN) + || (ch == KEY_SF) || (ch == KEY_SR) + || (ch == (int)'\f') || key_is_start_sequence (ch)); +} + +/* Use definition from readline 4.3. */ +#undef CTRL_CHAR +#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0)) + +/* This file controls the IO interactions between gdb and curses. + When the TUI is enabled, gdb has two modes a curses and a standard + mode. + + In curses mode, the gdb outputs are made in a curses command window. + For this, the gdb_stdout and gdb_stderr are redirected to the specific + ui_file implemented by TUI. The output is handled by tui_puts(). + The input is also controlled by curses with tui_getc(). The readline + library uses this function to get its input. Several readline hooks + are installed to redirect readline output to the TUI (see also the + note below). + + In normal mode, the gdb outputs are restored to their origin, that + is as if TUI is not used. Readline also uses its original getc() + function with stdin. + + Note SCz/2001-07-21: the current readline is not clean in its management of + the output. Even if we install a redisplay handler, it sometimes writes on + a stdout file. It is important to redirect every output produced by + readline, otherwise the curses window will be garbled. This is implemented + with a pipe that TUI reads and readline writes to. A gdb input handler + is created so that reading the pipe is handled automatically. + This will probably not work on non-Unix platforms. The best fix is + to make readline clean enougth so that is never write on stdout. + + Note SCz/2002-09-01: we now use more readline hooks and it seems that + with them we don't need the pipe anymore (verified by creating the pipe + and closing its end so that write causes a SIGPIPE). The old pipe code + is still there and can be conditionally removed by + #undef TUI_USE_PIPE_FOR_READLINE. */ + +/* For gdb 5.3, prefer to continue the pipe hack as a backup wheel. */ +#define TUI_USE_PIPE_FOR_READLINE +/*#undef TUI_USE_PIPE_FOR_READLINE*/ + +/* TUI output files. */ +static struct ui_file *tui_stdout; +static struct ui_file *tui_stderr; +struct ui_out *tui_out; + +/* GDB output files in non-curses mode. */ +static struct ui_file *tui_old_stdout; +static struct ui_file *tui_old_stderr; +struct ui_out *tui_old_uiout; + +/* Readline previous hooks. */ +static Function *tui_old_rl_getc_function; +static VFunction *tui_old_rl_redisplay_function; +static VFunction *tui_old_rl_prep_terminal; +static VFunction *tui_old_rl_deprep_terminal; +static int tui_old_readline_echoing_p; + +/* Readline output stream. + Should be removed when readline is clean. */ +static FILE *tui_rl_outstream; +static FILE *tui_old_rl_outstream; +#ifdef TUI_USE_PIPE_FOR_READLINE +static int tui_readline_pipe[2]; +#endif + +/* The last gdb prompt that was registered in readline. + This may be the main gdb prompt or a secondary prompt. */ +static char *tui_rl_saved_prompt; + +static unsigned int tui_handle_resize_during_io (unsigned int); + +static void +tui_putc (char c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = 0; + tui_puts (buf); +} + +/* Print the string in the curses command window. */ +void +tui_puts (const char *string) +{ + static int tui_skip_line = -1; + char c; + WINDOW *w; + + w = TUI_CMD_WIN->generic.handle; + while ((c = *string++) != 0) + { + /* Catch annotation and discard them. We need two \032 and + discard until a \n is seen. */ + if (c == '\032') + { + tui_skip_line++; + } + else if (tui_skip_line != 1) + { + tui_skip_line = -1; + waddch (w, c); + } + else if (c == '\n') + tui_skip_line = -1; + } + getyx (w, TUI_CMD_WIN->detail.command_info.cur_line, + TUI_CMD_WIN->detail.command_info.curch); + TUI_CMD_WIN->detail.command_info.start_line = TUI_CMD_WIN->detail.command_info.cur_line; + + /* We could defer the following. */ + wrefresh (w); + fflush (stdout); +} + +/* Readline callback. + Redisplay the command line with its prompt after readline has + changed the edited text. */ +void +tui_redisplay_readline (void) +{ + int prev_col; + int height; + int col, line; + int c_pos; + int c_line; + int in; + WINDOW *w; + char *prompt; + int start_line; + + /* Detect when we temporarily left SingleKey and now the readline + edit buffer is empty, automatically restore the SingleKey mode. */ + if (tui_current_key_mode == TUI_ONE_COMMAND_MODE && rl_end == 0) + tui_set_key_mode (TUI_SINGLE_KEY_MODE); + + if (tui_current_key_mode == TUI_SINGLE_KEY_MODE) + prompt = ""; + else + prompt = tui_rl_saved_prompt; + + c_pos = -1; + c_line = -1; + w = TUI_CMD_WIN->generic.handle; + start_line = TUI_CMD_WIN->detail.command_info.start_line; + wmove (w, start_line, 0); + prev_col = 0; + height = 1; + for (in = 0; prompt && prompt[in]; in++) + { + waddch (w, prompt[in]); + getyx (w, line, col); + if (col < prev_col) + height++; + prev_col = col; + } + for (in = 0; in < rl_end; in++) + { + unsigned char c; + + c = (unsigned char) rl_line_buffer[in]; + if (in == rl_point) + { + getyx (w, c_line, c_pos); + } + + if (CTRL_CHAR (c) || c == RUBOUT) + { + waddch (w, '^'); + waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?'); + } + else + { + waddch (w, c); + } + if (c == '\n') + { + getyx (w, TUI_CMD_WIN->detail.command_info.start_line, + TUI_CMD_WIN->detail.command_info.curch); + } + getyx (w, line, col); + if (col < prev_col) + height++; + prev_col = col; + } + wclrtobot (w); + getyx (w, TUI_CMD_WIN->detail.command_info.start_line, + TUI_CMD_WIN->detail.command_info.curch); + if (c_line >= 0) + { + wmove (w, c_line, c_pos); + TUI_CMD_WIN->detail.command_info.cur_line = c_line; + TUI_CMD_WIN->detail.command_info.curch = c_pos; + } + TUI_CMD_WIN->detail.command_info.start_line -= height - 1; + + wrefresh (w); + fflush(stdout); +} + +/* Readline callback to prepare the terminal. It is called once + each time we enter readline. Terminal is already setup in curses mode. */ +static void +tui_prep_terminal (int notused1) +{ + /* Save the prompt registered in readline to correctly display it. + (we can't use gdb_prompt() due to secondary prompts and can't use + rl_prompt because it points to an alloca buffer). */ + xfree (tui_rl_saved_prompt); + tui_rl_saved_prompt = xstrdup (rl_prompt); +} + +/* Readline callback to restore the terminal. It is called once + each time we leave readline. There is nothing to do in curses mode. */ +static void +tui_deprep_terminal (void) +{ +} + +#ifdef TUI_USE_PIPE_FOR_READLINE +/* Read readline output pipe and feed the command window with it. + Should be removed when readline is clean. */ +static void +tui_readline_output (int code, gdb_client_data data) +{ + int size; + char buf[256]; + + size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1); + if (size > 0 && tui_active) + { + buf[size] = 0; + tui_puts (buf); + } +} +#endif + +/* Return the portion of PATHNAME that should be output when listing + possible completions. If we are hacking filename completion, we + are only interested in the basename, the portion following the + final slash. Otherwise, we return what we were passed. + + Comes from readline/complete.c */ +static char * +printable_part (char *pathname) +{ + char *temp; + + temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL; +#if defined (__MSDOS__) + if (rl_filename_completion_desired && temp == 0 && isalpha (pathname[0]) && pathname[1] == ':') + temp = pathname + 1; +#endif + return (temp ? ++temp : pathname); +} + +/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we + are using it, check for and output a single character for `special' + filenames. Return the number of characters we output. */ + +#define PUTX(c) \ + do { \ + if (CTRL_CHAR (c)) \ + { \ + tui_puts ("^"); \ + tui_putc (UNCTRL (c)); \ + printed_len += 2; \ + } \ + else if (c == RUBOUT) \ + { \ + tui_puts ("^?"); \ + printed_len += 2; \ + } \ + else \ + { \ + tui_putc (c); \ + printed_len++; \ + } \ + } while (0) + +static int +print_filename (char *to_print, char *full_pathname) +{ + int printed_len = 0; + char *s; + + for (s = to_print; *s; s++) + { + PUTX (*s); + } + return printed_len; +} + +/* The user must press "y" or "n". Non-zero return means "y" pressed. + Comes from readline/complete.c */ +static int +get_y_or_n (void) +{ + extern int _rl_abort_internal (); + int c; + + for (;;) + { + c = rl_read_key (); + if (c == 'y' || c == 'Y' || c == ' ') + return (1); + if (c == 'n' || c == 'N' || c == RUBOUT) + return (0); + if (c == ABORT_CHAR) + _rl_abort_internal (); + beep (); + } +} + +/* A convenience function for displaying a list of strings in + columnar format on readline's output stream. MATCHES is the list + of strings, in argv format, LEN is the number of strings in MATCHES, + and MAX is the length of the longest string in MATCHES. + + Comes from readline/complete.c and modified to write in + the TUI command window using tui_putc/tui_puts. */ +static void +tui_rl_display_match_list (char **matches, int len, int max) +{ + typedef int QSFUNC (const void *, const void *); + extern int _rl_qsort_string_compare (const void*, const void*); + extern int _rl_print_completions_horizontally; + + int count, limit, printed_len; + int i, j, k, l; + char *temp; + + /* Screen dimension correspond to the TUI command window. */ + int screenwidth = TUI_CMD_WIN->generic.width; + + /* If there are many items, then ask the user if she really wants to + see them all. */ + if (len >= rl_completion_query_items) + { + char msg[256]; + + sprintf (msg, "\nDisplay all %d possibilities? (y or n)", len); + tui_puts (msg); + if (get_y_or_n () == 0) + { + tui_puts ("\n"); + return; + } + } + + /* How many items of MAX length can we fit in the screen window? */ + max += 2; + limit = screenwidth / max; + if (limit != 1 && (limit * max == screenwidth)) + limit--; + + /* Avoid a possible floating exception. If max > screenwidth, + limit will be 0 and a divide-by-zero fault will result. */ + if (limit == 0) + limit = 1; + + /* How many iterations of the printing loop? */ + count = (len + (limit - 1)) / limit; + + /* Watch out for special case. If LEN is less than LIMIT, then + just do the inner printing loop. + 0 < len <= limit implies count = 1. */ + + /* Sort the items if they are not already sorted. */ + if (rl_ignore_completion_duplicates == 0) + qsort (matches + 1, len, sizeof (char *), + (QSFUNC *)_rl_qsort_string_compare); + + tui_putc ('\n'); + + if (_rl_print_completions_horizontally == 0) + { + /* Print the sorted items, up-and-down alphabetically, like ls. */ + for (i = 1; i <= count; i++) + { + for (j = 0, l = i; j < limit; j++) + { + if (l > len || matches[l] == 0) + break; + else + { + temp = printable_part (matches[l]); + printed_len = print_filename (temp, matches[l]); + + if (j + 1 < limit) + for (k = 0; k < max - printed_len; k++) + tui_putc (' '); + } + l += count; + } + tui_putc ('\n'); + } + } + else + { + /* Print the sorted items, across alphabetically, like ls -x. */ + for (i = 1; matches[i]; i++) + { + temp = printable_part (matches[i]); + printed_len = print_filename (temp, matches[i]); + /* Have we reached the end of this line? */ + if (matches[i+1]) + { + if (i && (limit > 1) && (i % limit) == 0) + tui_putc ('\n'); + else + for (k = 0; k < max - printed_len; k++) + tui_putc (' '); + } + } + tui_putc ('\n'); + } +} + +/* Setup the IO for curses or non-curses mode. + - In non-curses mode, readline and gdb use the standard input and + standard output/error directly. + - In curses mode, the standard output/error is controlled by TUI + with the tui_stdout and tui_stderr. The output is redirected in + the curses command window. Several readline callbacks are installed + so that readline asks for its input to the curses command window + with wgetch(). */ +void +tui_setup_io (int mode) +{ + extern int readline_echoing_p; + + if (mode) + { + /* Redirect readline to TUI. */ + tui_old_rl_redisplay_function = rl_redisplay_function; + tui_old_rl_deprep_terminal = rl_deprep_term_function; + tui_old_rl_prep_terminal = rl_prep_term_function; + tui_old_rl_getc_function = rl_getc_function; + tui_old_rl_outstream = rl_outstream; + tui_old_readline_echoing_p = readline_echoing_p; + rl_redisplay_function = tui_redisplay_readline; + rl_deprep_term_function = tui_deprep_terminal; + rl_prep_term_function = tui_prep_terminal; + rl_getc_function = tui_getc; + readline_echoing_p = 0; + rl_outstream = tui_rl_outstream; + rl_prompt = 0; + rl_completion_display_matches_hook = tui_rl_display_match_list; + rl_already_prompted = 0; + + /* Keep track of previous gdb output. */ + tui_old_stdout = gdb_stdout; + tui_old_stderr = gdb_stderr; + tui_old_uiout = uiout; + + /* Reconfigure gdb output. */ + gdb_stdout = tui_stdout; + gdb_stderr = tui_stderr; + gdb_stdlog = gdb_stdout; /* for moment */ + gdb_stdtarg = gdb_stderr; /* for moment */ + uiout = tui_out; + + /* Save tty for SIGCONT. */ + savetty (); + } + else + { + /* Restore gdb output. */ + gdb_stdout = tui_old_stdout; + gdb_stderr = tui_old_stderr; + gdb_stdlog = gdb_stdout; /* for moment */ + gdb_stdtarg = gdb_stderr; /* for moment */ + uiout = tui_old_uiout; + + /* Restore readline. */ + rl_redisplay_function = tui_old_rl_redisplay_function; + rl_deprep_term_function = tui_old_rl_deprep_terminal; + rl_prep_term_function = tui_old_rl_prep_terminal; + rl_getc_function = tui_old_rl_getc_function; + rl_outstream = tui_old_rl_outstream; + rl_completion_display_matches_hook = 0; + readline_echoing_p = tui_old_readline_echoing_p; + rl_already_prompted = 0; + + /* Save tty for SIGCONT. */ + savetty (); + } +} + +#ifdef SIGCONT +/* Catch SIGCONT to restore the terminal and refresh the screen. */ +static void +tui_cont_sig (int sig) +{ + if (tui_active) + { + /* Restore the terminal setting because another process (shell) + might have changed it. */ + resetty (); + + /* Force a refresh of the screen. */ + tui_refresh_all_win (); + + /* Update cursor position on the screen. */ + wmove (TUI_CMD_WIN->generic.handle, + TUI_CMD_WIN->detail.command_info.start_line, + TUI_CMD_WIN->detail.command_info.curch); + wrefresh (TUI_CMD_WIN->generic.handle); + } + signal (sig, tui_cont_sig); +} +#endif + +/* Initialize the IO for gdb in curses mode. */ +void +tui_initialize_io (void) +{ +#ifdef SIGCONT + signal (SIGCONT, tui_cont_sig); +#endif + + /* Create tui output streams. */ + tui_stdout = tui_fileopen (stdout); + tui_stderr = tui_fileopen (stderr); + tui_out = tui_out_new (tui_stdout); + + /* Create the default UI. It is not created because we installed + a init_ui_hook. */ + tui_old_uiout = uiout = cli_out_new (gdb_stdout); + +#ifdef TUI_USE_PIPE_FOR_READLINE + /* Temporary solution for readline writing to stdout: + redirect readline output in a pipe, read that pipe and + output the content in the curses command window. */ + if (pipe (tui_readline_pipe) != 0) + { + fprintf_unfiltered (gdb_stderr, "Cannot create pipe for readline"); + exit (1); + } + tui_rl_outstream = fdopen (tui_readline_pipe[1], "w"); + if (tui_rl_outstream == 0) + { + fprintf_unfiltered (gdb_stderr, "Cannot redirect readline output"); + exit (1); + } + setvbuf (tui_rl_outstream, (char*) NULL, _IOLBF, 0); + +#ifdef O_NONBLOCK + (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK); +#else +#ifdef O_NDELAY + (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY); +#endif +#endif + add_file_handler (tui_readline_pipe[0], tui_readline_output, 0); +#else + tui_rl_outstream = stdout; +#endif +} + +/* Get a character from the command window. This is called from the readline + package. */ +int +tui_getc (FILE *fp) +{ + int ch; + WINDOW *w; + + w = TUI_CMD_WIN->generic.handle; + +#ifdef TUI_USE_PIPE_FOR_READLINE + /* Flush readline output. */ + tui_readline_output (GDB_READABLE, 0); +#endif + + ch = wgetch (w); + ch = tui_handle_resize_during_io (ch); + + /* The \n must be echoed because it will not be printed by readline. */ + if (ch == '\n') + { + /* When hitting return with an empty input, gdb executes the last + command. If we emit a newline, this fills up the command window + with empty lines with gdb prompt at beginning. Instead of that, + stay on the same line but provide a visual effect to show the + user we recognized the command. */ + if (rl_end == 0) + { + wmove (w, TUI_CMD_WIN->detail.command_info.cur_line, 0); + + /* Clear the line. This will blink the gdb prompt since + it will be redrawn at the same line. */ + wclrtoeol (w); + wrefresh (w); + napms (20); + } + else + { + wmove (w, TUI_CMD_WIN->detail.command_info.cur_line, + TUI_CMD_WIN->detail.command_info.curch); + waddch (w, ch); + } + } + + if (key_is_command_char (ch)) + { /* Handle prev/next/up/down here */ + ch = tui_dispatch_ctrl_char (ch); + } + + if (ch == '\n' || ch == '\r' || ch == '\f') + TUI_CMD_WIN->detail.command_info.curch = 0; + if (ch == KEY_BACKSPACE) + return '\b'; + + return ch; +} + + +/* Cleanup when a resize has occured. + Returns the character that must be processed. */ +static unsigned int +tui_handle_resize_during_io (unsigned int original_ch) +{ + if (tui_win_resized ()) + { + tui_refresh_all_win (); + dont_repeat (); + tui_set_win_resized_to (FALSE); + return '\n'; + } + else + return original_ch; +} diff --git a/gdb/tui/tui-io.h b/gdb/tui/tui-io.h new file mode 100644 index 00000000000..06d085de93f --- /dev/null +++ b/gdb/tui/tui-io.h @@ -0,0 +1,55 @@ +/* TUI support I/O functions. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_IO_H +#define TUI_IO_H + +struct ui_out; + +/* Print the string in the curses command window. */ +extern void tui_puts (const char *); + +/* Setup the IO for curses or non-curses mode. */ +extern void tui_setup_io (int mode); + +/* Initialize the IO for gdb in curses mode. */ +extern void tui_initialize_io (void); + +/* Get a character from the command window. */ +extern int tui_getc (FILE *); + +/* Readline callback. + Redisplay the command line with its prompt after readline has + changed the edited text. */ +extern void tui_redisplay_readline (void); + +extern struct ui_out *tui_out; +extern struct ui_out *tui_old_uiout; + +extern int key_is_start_sequence (int ch); +extern int key_is_end_sequence (int ch); +extern int key_is_backspace (int ch); +extern int key_is_command_char (int ch); + +#endif diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c new file mode 100644 index 00000000000..341d3cd3e14 --- /dev/null +++ b/gdb/tui/tui-layout.c @@ -0,0 +1,1080 @@ +/* TUI layout window management. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "command.h" +#include "symtab.h" +#include "frame.h" +#include "source.h" +#include + +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-windata.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-stack.h" +#include "tui/tui-regs.h" +#include "tui/tui-win.h" +#include "tui/tui-winsource.h" +#include "tui/tui-disasm.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/******************************* +** Static Local Decls +********************************/ +static void show_layout (enum tui_layout_type); +static void init_gen_win_info (struct tui_gen_win_info *, enum tui_win_type, int, int, int, int); +static void init_and_make_win (void **, enum tui_win_type, int, int, int, int, int); +static void show_source_or_disasm_and_command (enum tui_layout_type); +static void make_source_or_disasm_window (struct tui_win_info * *, enum tui_win_type, int, int); +static void make_command_window (struct tui_win_info * *, int, int); +static void make_source_window (struct tui_win_info * *, int, int); +static void make_disasm_window (struct tui_win_info * *, int, int); +static void make_data_window (struct tui_win_info * *, int, int); +static void show_source_command (void); +static void show_disasm_command (void); +static void show_source_disasm_command (void); +static void show_data (enum tui_layout_type); +static enum tui_layout_type next_layout (void); +static enum tui_layout_type prev_layout (void); +static void tui_layout_command (char *, int); +static void tui_toggle_layout_command (char *, int); +static void tui_toggle_split_layout_command (char *, int); +static CORE_ADDR extract_display_start_addr (void); +static void tui_handle_xdb_layout (struct tui_layout_def *); + + +/*************************************** +** DEFINITIONS +***************************************/ + +#define LAYOUT_USAGE "Usage: layout prev | next | \n" + +/* Show the screen layout defined. */ +static void +show_layout (enum tui_layout_type layout) +{ + enum tui_layout_type cur_layout = tui_current_layout (); + + if (layout != cur_layout) + { + /* + ** Since the new layout may cause changes in window size, we + ** should free the content and reallocate on next display of + ** source/asm + */ + tui_free_all_source_wins_content (); + tui_clear_source_windows (); + if (layout == SRC_DATA_COMMAND || layout == DISASSEM_DATA_COMMAND) + { + show_data (layout); + tui_refresh_all (tui_win_list); + } + else + { + /* First make the current layout be invisible */ + tui_make_all_invisible (); + tui_make_invisible (tui_locator_win_info_ptr ()); + + switch (layout) + { + /* Now show the new layout */ + case SRC_COMMAND: + show_source_command (); + tui_add_to_source_windows (TUI_SRC_WIN); + break; + case DISASSEM_COMMAND: + show_disasm_command (); + tui_add_to_source_windows (TUI_DISASM_WIN); + break; + case SRC_DISASSEM_COMMAND: + show_source_disasm_command (); + tui_add_to_source_windows (TUI_SRC_WIN); + tui_add_to_source_windows (TUI_DISASM_WIN); + break; + default: + break; + } + } + } +} + + +/* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND, + SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. + If the layout is SRC_DATA_COMMAND, DISASSEM_DATA_COMMAND, or + UNDEFINED_LAYOUT, then the data window is populated according to + regs_display_type. */ +enum tui_status +tui_set_layout (enum tui_layout_type layout_type, + enum tui_register_display_type regs_display_type) +{ + enum tui_status status = TUI_SUCCESS; + + if (layout_type != UNDEFINED_LAYOUT || regs_display_type != TUI_UNDEFINED_REGS) + { + enum tui_layout_type cur_layout = tui_current_layout (), new_layout = UNDEFINED_LAYOUT; + int regs_populate = FALSE; + CORE_ADDR addr = extract_display_start_addr (); + struct tui_win_info * new_win_with_focus = (struct tui_win_info *) NULL; + struct tui_win_info * win_with_focus = tui_win_with_focus (); + struct tui_layout_def * layout_def = tui_layout_def (); + + + if (layout_type == UNDEFINED_LAYOUT && + regs_display_type != TUI_UNDEFINED_REGS) + { + if (cur_layout == SRC_DISASSEM_COMMAND) + new_layout = DISASSEM_DATA_COMMAND; + else if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND) + new_layout = SRC_DATA_COMMAND; + else if (cur_layout == DISASSEM_COMMAND || + cur_layout == DISASSEM_DATA_COMMAND) + new_layout = DISASSEM_DATA_COMMAND; + } + else + new_layout = layout_type; + + regs_populate = (new_layout == SRC_DATA_COMMAND || + new_layout == DISASSEM_DATA_COMMAND || + regs_display_type != TUI_UNDEFINED_REGS); + if (new_layout != cur_layout || regs_display_type != TUI_UNDEFINED_REGS) + { + if (new_layout != cur_layout) + { + show_layout (new_layout); + /* + ** Now determine where focus should be + */ + if (win_with_focus != TUI_CMD_WIN) + { + switch (new_layout) + { + case SRC_COMMAND: + tui_set_win_focus_to (TUI_SRC_WIN); + layout_def->display_mode = SRC_WIN; + layout_def->split = FALSE; + break; + case DISASSEM_COMMAND: + /* the previous layout was not showing + ** code. this can happen if there is no + ** source available: + ** 1. if the source file is in another dir OR + ** 2. if target was compiled without -g + ** We still want to show the assembly though! + */ + addr = tui_get_begin_asm_address (); + tui_set_win_focus_to (TUI_DISASM_WIN); + layout_def->display_mode = DISASSEM_WIN; + layout_def->split = FALSE; + break; + case SRC_DISASSEM_COMMAND: + /* the previous layout was not showing + ** code. this can happen if there is no + ** source available: + ** 1. if the source file is in another dir OR + ** 2. if target was compiled without -g + ** We still want to show the assembly though! + */ + addr = tui_get_begin_asm_address (); + if (win_with_focus == TUI_SRC_WIN) + tui_set_win_focus_to (TUI_SRC_WIN); + else + tui_set_win_focus_to (TUI_DISASM_WIN); + layout_def->split = TRUE; + break; + case SRC_DATA_COMMAND: + if (win_with_focus != TUI_DATA_WIN) + tui_set_win_focus_to (TUI_SRC_WIN); + else + tui_set_win_focus_to (TUI_DATA_WIN); + layout_def->display_mode = SRC_WIN; + layout_def->split = FALSE; + break; + case DISASSEM_DATA_COMMAND: + /* the previous layout was not showing + ** code. this can happen if there is no + ** source available: + ** 1. if the source file is in another dir OR + ** 2. if target was compiled without -g + ** We still want to show the assembly though! + */ + addr = tui_get_begin_asm_address (); + if (win_with_focus != TUI_DATA_WIN) + tui_set_win_focus_to (TUI_DISASM_WIN); + else + tui_set_win_focus_to (TUI_DATA_WIN); + layout_def->display_mode = DISASSEM_WIN; + layout_def->split = FALSE; + break; + default: + break; + } + } + if (new_win_with_focus != (struct tui_win_info *) NULL) + tui_set_win_focus_to (new_win_with_focus); + /* + ** Now update the window content + */ + if (!regs_populate && + (new_layout == SRC_DATA_COMMAND || + new_layout == DISASSEM_DATA_COMMAND)) + tui_display_all_data (); + + tui_update_source_windows_with_addr (addr); + } + if (regs_populate) + { + layout_def->regs_display_type = + (regs_display_type == TUI_UNDEFINED_REGS ? + TUI_GENERAL_REGS : regs_display_type); + tui_show_registers (layout_def->regs_display_type); + } + } + } + else + status = TUI_FAILURE; + + return status; +} + +/* Add the specified window to the layout in a logical way. This + means setting up the most logical layout given the window to be + added. */ +void +tui_add_win_to_layout (enum tui_win_type type) +{ + enum tui_layout_type cur_layout = tui_current_layout (); + + switch (type) + { + case SRC_WIN: + if (cur_layout != SRC_COMMAND && + cur_layout != SRC_DISASSEM_COMMAND && + cur_layout != SRC_DATA_COMMAND) + { + tui_clear_source_windows_detail (); + if (cur_layout == DISASSEM_DATA_COMMAND) + show_layout (SRC_DATA_COMMAND); + else + show_layout (SRC_COMMAND); + } + break; + case DISASSEM_WIN: + if (cur_layout != DISASSEM_COMMAND && + cur_layout != SRC_DISASSEM_COMMAND && + cur_layout != DISASSEM_DATA_COMMAND) + { + tui_clear_source_windows_detail (); + if (cur_layout == SRC_DATA_COMMAND) + show_layout (DISASSEM_DATA_COMMAND); + else + show_layout (DISASSEM_COMMAND); + } + break; + case DATA_WIN: + if (cur_layout != SRC_DATA_COMMAND && + cur_layout != DISASSEM_DATA_COMMAND) + { + if (cur_layout == DISASSEM_COMMAND) + show_layout (DISASSEM_DATA_COMMAND); + else + show_layout (SRC_DATA_COMMAND); + } + break; + default: + break; + } +} + + +/* Answer the height of a window. If it hasn't been created yet, + answer what the height of a window would be based upon its type and + the layout. */ +int +tui_default_win_height (enum tui_win_type type, enum tui_layout_type layout) +{ + int h; + + if (tui_win_list[type] != (struct tui_win_info *) NULL) + h = tui_win_list[type]->generic.height; + else + { + switch (layout) + { + case SRC_COMMAND: + case DISASSEM_COMMAND: + if (TUI_CMD_WIN == NULL) + h = tui_term_height () / 2; + else + h = tui_term_height () - TUI_CMD_WIN->generic.height; + break; + case SRC_DISASSEM_COMMAND: + case SRC_DATA_COMMAND: + case DISASSEM_DATA_COMMAND: + if (TUI_CMD_WIN == NULL) + h = tui_term_height () / 3; + else + h = (tui_term_height () - TUI_CMD_WIN->generic.height) / 2; + break; + default: + h = 0; + break; + } + } + + return h; +} + + +/* Answer the height of a window. If it hasn't been created yet, + answer what the height of a window would be based upon its type and + the layout. */ +int +tui_default_win_viewport_height (enum tui_win_type type, + enum tui_layout_type layout) +{ + int h; + + h = tui_default_win_height (type, layout); + + if (tui_win_list[type] == TUI_CMD_WIN) + h -= 1; + else + h -= 2; + + return h; +} + + +/* Function to initialize gdb commands, for tui window layout + manipulation. */ +void +_initialize_tui_layout (void) +{ + add_com ("layout", class_tui, tui_layout_command, + "Change the layout of windows.\n\ +Usage: layout prev | next | \n\ +Layout names are:\n\ + src : Displays source and command windows.\n\ + asm : Displays disassembly and command windows.\n\ + split : Displays source, disassembly and command windows.\n\ + regs : Displays register window. If existing layout\n\ + is source/command or assembly/command, the \n\ + register window is displayed. If the\n\ + source/assembly/command (split) is displayed, \n\ + the register window is displayed with \n\ + the window that has current logical focus.\n"); + if (xdb_commands) + { + add_com ("td", class_tui, tui_toggle_layout_command, + "Toggle between Source/Command and Disassembly/Command layouts.\n"); + add_com ("ts", class_tui, tui_toggle_split_layout_command, + "Toggle between Source/Command or Disassembly/Command and \n\ +Source/Disassembly/Command layouts.\n"); + } +} + + +/************************* +** STATIC LOCAL FUNCTIONS +**************************/ + + +/* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, + REGS, $REGS, $GREGS, $FREGS, $SREGS. */ +enum tui_status +tui_set_layout_for_display_command (const char *layout_name) +{ + enum tui_status status = TUI_SUCCESS; + + if (layout_name != (char *) NULL) + { + int i; + char *buf_ptr; + enum tui_layout_type new_layout = UNDEFINED_LAYOUT; + enum tui_register_display_type dpy_type = TUI_UNDEFINED_REGS; + enum tui_layout_type cur_layout = tui_current_layout (); + + buf_ptr = (char *) xstrdup (layout_name); + for (i = 0; (i < strlen (layout_name)); i++) + buf_ptr[i] = toupper (buf_ptr[i]); + + /* First check for ambiguous input */ + if (strlen (buf_ptr) <= 1 && (*buf_ptr == 'S' || *buf_ptr == '$')) + { + warning ("Ambiguous command input.\n"); + status = TUI_FAILURE; + } + else + { + if (subset_compare (buf_ptr, "SRC")) + new_layout = SRC_COMMAND; + else if (subset_compare (buf_ptr, "ASM")) + new_layout = DISASSEM_COMMAND; + else if (subset_compare (buf_ptr, "SPLIT")) + new_layout = SRC_DISASSEM_COMMAND; + else if (subset_compare (buf_ptr, "REGS") || + subset_compare (buf_ptr, TUI_GENERAL_SPECIAL_REGS_NAME) || + subset_compare (buf_ptr, TUI_GENERAL_REGS_NAME) || + subset_compare (buf_ptr, TUI_FLOAT_REGS_NAME) || + subset_compare (buf_ptr, TUI_SPECIAL_REGS_NAME)) + { + if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND) + new_layout = SRC_DATA_COMMAND; + else + new_layout = DISASSEM_DATA_COMMAND; + +/* could ifdef out the following code. when compile with -z, there are null + pointer references that cause a core dump if 'layout regs' is the first + layout command issued by the user. HP has asked us to hook up this code + - edie epstein + */ + if (subset_compare (buf_ptr, TUI_FLOAT_REGS_NAME)) + { + if (TUI_DATA_WIN->detail.data_display_info.regs_display_type != + TUI_SFLOAT_REGS && + TUI_DATA_WIN->detail.data_display_info.regs_display_type != + TUI_DFLOAT_REGS) + dpy_type = TUI_SFLOAT_REGS; + else + dpy_type = + TUI_DATA_WIN->detail.data_display_info.regs_display_type; + } + else if (subset_compare (buf_ptr, + TUI_GENERAL_SPECIAL_REGS_NAME)) + dpy_type = TUI_GENERAL_AND_SPECIAL_REGS; + else if (subset_compare (buf_ptr, TUI_GENERAL_REGS_NAME)) + dpy_type = TUI_GENERAL_REGS; + else if (subset_compare (buf_ptr, TUI_SPECIAL_REGS_NAME)) + dpy_type = TUI_SPECIAL_REGS; + else if (TUI_DATA_WIN) + { + if (TUI_DATA_WIN->detail.data_display_info.regs_display_type != + TUI_UNDEFINED_REGS) + dpy_type = + TUI_DATA_WIN->detail.data_display_info.regs_display_type; + else + dpy_type = TUI_GENERAL_REGS; + } + +/* end of potential ifdef + */ + +/* if ifdefed out code above, then assume that the user wishes to display the + general purpose registers + */ + +/* dpy_type = TUI_GENERAL_REGS; + */ + } + else if (subset_compare (buf_ptr, "NEXT")) + new_layout = next_layout (); + else if (subset_compare (buf_ptr, "PREV")) + new_layout = prev_layout (); + else + status = TUI_FAILURE; + xfree (buf_ptr); + + tui_set_layout (new_layout, dpy_type); + } + } + else + status = TUI_FAILURE; + + return status; +} + + +static CORE_ADDR +extract_display_start_addr (void) +{ + enum tui_layout_type cur_layout = tui_current_layout (); + CORE_ADDR addr; + CORE_ADDR pc; + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + + switch (cur_layout) + { + case SRC_COMMAND: + case SRC_DATA_COMMAND: + find_line_pc (cursal.symtab, + TUI_SRC_WIN->detail.source_info.start_line_or_addr.line_no, + &pc); + addr = pc; + break; + case DISASSEM_COMMAND: + case SRC_DISASSEM_COMMAND: + case DISASSEM_DATA_COMMAND: + addr = TUI_DISASM_WIN->detail.source_info.start_line_or_addr.addr; + break; + default: + addr = 0; + break; + } + + return addr; +} + + +static void +tui_handle_xdb_layout (struct tui_layout_def * layout_def) +{ + if (layout_def->split) + { + tui_set_layout (SRC_DISASSEM_COMMAND, TUI_UNDEFINED_REGS); + tui_set_win_focus_to (tui_win_list[layout_def->display_mode]); + } + else + { + if (layout_def->display_mode == SRC_WIN) + tui_set_layout (SRC_COMMAND, TUI_UNDEFINED_REGS); + else + tui_set_layout (DISASSEM_DATA_COMMAND, layout_def->regs_display_type); + } +} + + +static void +tui_toggle_layout_command (char *arg, int from_tty) +{ + struct tui_layout_def * layout_def = tui_layout_def (); + + /* Make sure the curses mode is enabled. */ + tui_enable (); + if (layout_def->display_mode == SRC_WIN) + layout_def->display_mode = DISASSEM_WIN; + else + layout_def->display_mode = SRC_WIN; + + if (!layout_def->split) + tui_handle_xdb_layout (layout_def); +} + + +static void +tui_toggle_split_layout_command (char *arg, int from_tty) +{ + struct tui_layout_def * layout_def = tui_layout_def (); + + /* Make sure the curses mode is enabled. */ + tui_enable (); + layout_def->split = (!layout_def->split); + tui_handle_xdb_layout (layout_def); +} + + +static void +tui_layout_command (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + + /* Switch to the selected layout. */ + if (tui_set_layout_for_display_command (arg) != TUI_SUCCESS) + warning ("Invalid layout specified.\n%s", LAYOUT_USAGE); + +} + +/* Answer the previous layout to cycle to. */ +static enum tui_layout_type +next_layout (void) +{ + enum tui_layout_type new_layout; + + new_layout = tui_current_layout (); + if (new_layout == UNDEFINED_LAYOUT) + new_layout = SRC_COMMAND; + else + { + new_layout++; + if (new_layout == UNDEFINED_LAYOUT) + new_layout = SRC_COMMAND; + } + + return new_layout; +} + + +/* Answer the next layout to cycle to. */ +static enum tui_layout_type +prev_layout (void) +{ + enum tui_layout_type new_layout; + + new_layout = tui_current_layout (); + if (new_layout == SRC_COMMAND) + new_layout = DISASSEM_DATA_COMMAND; + else + { + new_layout--; + if (new_layout == UNDEFINED_LAYOUT) + new_layout = DISASSEM_DATA_COMMAND; + } + + return new_layout; +} + + + +static void +make_command_window (struct tui_win_info * * win_info_ptr, int height, int origin_y) +{ + init_and_make_win ((void **) win_info_ptr, + CMD_WIN, + height, + tui_term_width (), + 0, + origin_y, + DONT_BOX_WINDOW); + + (*win_info_ptr)->can_highlight = FALSE; +} + + +/* + ** make_source_window(). + */ +static void +make_source_window (struct tui_win_info * * win_info_ptr, int height, int origin_y) +{ + make_source_or_disasm_window (win_info_ptr, SRC_WIN, height, origin_y); + + return; +} /* make_source_window */ + + +/* + ** make_disasm_window(). + */ +static void +make_disasm_window (struct tui_win_info * * win_info_ptr, int height, int origin_y) +{ + make_source_or_disasm_window (win_info_ptr, DISASSEM_WIN, height, origin_y); + + return; +} /* make_disasm_window */ + + +static void +make_data_window (struct tui_win_info * * win_info_ptr, int height, int origin_y) +{ + init_and_make_win ((void **) win_info_ptr, + DATA_WIN, + height, + tui_term_width (), + 0, + origin_y, + BOX_WINDOW); +} + + + +/* Show the Source/Command layout. */ +static void +show_source_command (void) +{ + show_source_or_disasm_and_command (SRC_COMMAND); +} + + +/* Show the Dissassem/Command layout. */ +static void +show_disasm_command (void) +{ + show_source_or_disasm_and_command (DISASSEM_COMMAND); +} + + +/* Show the Source/Disassem/Command layout. */ +static void +show_source_disasm_command (void) +{ + if (tui_current_layout () != SRC_DISASSEM_COMMAND) + { + int cmd_height, src_height, asm_height; + + if (TUI_CMD_WIN != NULL) + cmd_height = TUI_CMD_WIN->generic.height; + else + cmd_height = tui_term_height () / 3; + + src_height = (tui_term_height () - cmd_height) / 2; + asm_height = tui_term_height () - (src_height + cmd_height); + + if (TUI_SRC_WIN == NULL) + make_source_window (&TUI_SRC_WIN, src_height, 0); + else + { + init_gen_win_info (&TUI_SRC_WIN->generic, + TUI_SRC_WIN->generic.type, + src_height, + TUI_SRC_WIN->generic.width, + TUI_SRC_WIN->detail.source_info.execution_info->width, + 0); + TUI_SRC_WIN->can_highlight = TRUE; + init_gen_win_info (TUI_SRC_WIN->detail.source_info.execution_info, + EXEC_INFO_WIN, + src_height, + 3, + 0, + 0); + tui_make_visible (&TUI_SRC_WIN->generic); + tui_make_visible (TUI_SRC_WIN->detail.source_info.execution_info); + TUI_SRC_WIN->detail.source_info.has_locator = FALSE;; + } + if (TUI_SRC_WIN != NULL) + { + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + + tui_show_source_content (TUI_SRC_WIN); + if (TUI_DISASM_WIN == NULL) + { + make_disasm_window (&TUI_DISASM_WIN, asm_height, src_height - 1); + init_and_make_win ((void **) & locator, + LOCATOR_WIN, + 2 /* 1 */ , + tui_term_width (), + 0, + (src_height + asm_height) - 1, + DONT_BOX_WINDOW); + } + else + { + init_gen_win_info (locator, + LOCATOR_WIN, + 2 /* 1 */ , + tui_term_width (), + 0, + (src_height + asm_height) - 1); + TUI_DISASM_WIN->detail.source_info.has_locator = TRUE; + init_gen_win_info ( + &TUI_DISASM_WIN->generic, + TUI_DISASM_WIN->generic.type, + asm_height, + TUI_DISASM_WIN->generic.width, + TUI_DISASM_WIN->detail.source_info.execution_info->width, + src_height - 1); + init_gen_win_info (TUI_DISASM_WIN->detail.source_info.execution_info, + EXEC_INFO_WIN, + asm_height, + 3, + 0, + src_height - 1); + TUI_DISASM_WIN->can_highlight = TRUE; + tui_make_visible (&TUI_DISASM_WIN->generic); + tui_make_visible (TUI_DISASM_WIN->detail.source_info.execution_info); + } + if (TUI_DISASM_WIN != NULL) + { + TUI_SRC_WIN->detail.source_info.has_locator = FALSE; + TUI_DISASM_WIN->detail.source_info.has_locator = TRUE; + tui_make_visible (locator); + tui_show_locator_content (); + tui_show_source_content (TUI_DISASM_WIN); + + if (TUI_CMD_WIN == NULL) + make_command_window (&TUI_CMD_WIN, + cmd_height, + tui_term_height () - cmd_height); + else + { + init_gen_win_info (&TUI_CMD_WIN->generic, + TUI_CMD_WIN->generic.type, + TUI_CMD_WIN->generic.height, + TUI_CMD_WIN->generic.width, + 0, + TUI_CMD_WIN->generic.origin.y); + TUI_CMD_WIN->can_highlight = FALSE; + tui_make_visible (&TUI_CMD_WIN->generic); + } + if (TUI_CMD_WIN != NULL) + tui_refresh_win (&TUI_CMD_WIN->generic); + } + } + tui_set_current_layout_to (SRC_DISASSEM_COMMAND); + } +} + + +/* Show the Source/Data/Command or the Dissassembly/Data/Command + layout. */ +static void +show_data (enum tui_layout_type new_layout) +{ + int total_height = (tui_term_height () - TUI_CMD_WIN->generic.height); + int src_height, data_height; + enum tui_win_type win_type; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + + + data_height = total_height / 2; + src_height = total_height - data_height; + tui_make_all_invisible (); + tui_make_invisible (locator); + make_data_window (&TUI_DATA_WIN, data_height, 0); + TUI_DATA_WIN->can_highlight = TRUE; + if (new_layout == SRC_DATA_COMMAND) + win_type = SRC_WIN; + else + win_type = DISASSEM_WIN; + if (tui_win_list[win_type] == NULL) + { + if (win_type == SRC_WIN) + make_source_window (&tui_win_list[win_type], src_height, data_height - 1); + else + make_disasm_window (&tui_win_list[win_type], src_height, data_height - 1); + init_and_make_win ((void **) & locator, + LOCATOR_WIN, + 2 /* 1 */ , + tui_term_width (), + 0, + total_height - 1, + DONT_BOX_WINDOW); + } + else + { + init_gen_win_info (&tui_win_list[win_type]->generic, + tui_win_list[win_type]->generic.type, + src_height, + tui_win_list[win_type]->generic.width, + tui_win_list[win_type]->detail.source_info.execution_info->width, + data_height - 1); + init_gen_win_info (tui_win_list[win_type]->detail.source_info.execution_info, + EXEC_INFO_WIN, + src_height, + 3, + 0, + data_height - 1); + tui_make_visible (&tui_win_list[win_type]->generic); + tui_make_visible (tui_win_list[win_type]->detail.source_info.execution_info); + init_gen_win_info (locator, + LOCATOR_WIN, + 2 /* 1 */ , + tui_term_width (), + 0, + total_height - 1); + } + tui_win_list[win_type]->detail.source_info.has_locator = TRUE; + tui_make_visible (locator); + tui_show_locator_content (); + tui_add_to_source_windows (tui_win_list[win_type]); + tui_set_current_layout_to (new_layout); +} + +/* + ** init_gen_win_info(). + */ +static void +init_gen_win_info (struct tui_gen_win_info * win_info, enum tui_win_type type, + int height, int width, int origin_x, int origin_y) +{ + int h = height; + + win_info->type = type; + win_info->width = width; + win_info->height = h; + if (h > 1) + { + win_info->viewport_height = h - 1; + if (win_info->type != CMD_WIN) + win_info->viewport_height--; + } + else + win_info->viewport_height = 1; + win_info->origin.x = origin_x; + win_info->origin.y = origin_y; + + return; +} /* init_gen_win_info */ + +/* + ** init_and_make_win(). + */ +static void +init_and_make_win (void ** win_info_ptr, enum tui_win_type win_type, + int height, int width, int origin_x, int origin_y, int box_it) +{ + void *opaque_win_info = *win_info_ptr; + struct tui_gen_win_info * generic; + + if (opaque_win_info == NULL) + { + if (tui_win_is_auxillary (win_type)) + opaque_win_info = (void *) tui_alloc_generic_win_info (); + else + opaque_win_info = (void *) tui_alloc_win_info (win_type); + } + if (tui_win_is_auxillary (win_type)) + generic = (struct tui_gen_win_info *) opaque_win_info; + else + generic = &((struct tui_win_info *) opaque_win_info)->generic; + + if (opaque_win_info != NULL) + { + init_gen_win_info (generic, win_type, height, width, origin_x, origin_y); + if (!tui_win_is_auxillary (win_type)) + { + if (generic->type == CMD_WIN) + ((struct tui_win_info *) opaque_win_info)->can_highlight = FALSE; + else + ((struct tui_win_info *) opaque_win_info)->can_highlight = TRUE; + } + tui_make_window (generic, box_it); + } + *win_info_ptr = opaque_win_info; +} + + +static void +make_source_or_disasm_window (struct tui_win_info * * win_info_ptr, enum tui_win_type type, + int height, int origin_y) +{ + struct tui_gen_win_info * execution_info = (struct tui_gen_win_info *) NULL; + + /* + ** Create the exeuction info window. + */ + if (type == SRC_WIN) + execution_info = tui_source_exec_info_win_ptr (); + else + execution_info = tui_disassem_exec_info_win_ptr (); + init_and_make_win ((void **) & execution_info, + EXEC_INFO_WIN, + height, + 3, + 0, + origin_y, + DONT_BOX_WINDOW); + /* + ** Now create the source window. + */ + init_and_make_win ((void **) win_info_ptr, + type, + height, + tui_term_width () - execution_info->width, + execution_info->width, + origin_y, + BOX_WINDOW); + + (*win_info_ptr)->detail.source_info.execution_info = execution_info; +} + + +/* Show the Source/Command or the Disassem layout. */ +static void +show_source_or_disasm_and_command (enum tui_layout_type layout_type) +{ + if (tui_current_layout () != layout_type) + { + struct tui_win_info * *win_info_ptr; + int src_height, cmd_height; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + + if (TUI_CMD_WIN != NULL) + cmd_height = TUI_CMD_WIN->generic.height; + else + cmd_height = tui_term_height () / 3; + src_height = tui_term_height () - cmd_height; + + + if (layout_type == SRC_COMMAND) + win_info_ptr = &TUI_SRC_WIN; + else + win_info_ptr = &TUI_DISASM_WIN; + + if ((*win_info_ptr) == NULL) + { + if (layout_type == SRC_COMMAND) + make_source_window (win_info_ptr, src_height - 1, 0); + else + make_disasm_window (win_info_ptr, src_height - 1, 0); + init_and_make_win ((void **) & locator, + LOCATOR_WIN, + 2 /* 1 */ , + tui_term_width (), + 0, + src_height - 1, + DONT_BOX_WINDOW); + } + else + { + init_gen_win_info (locator, + LOCATOR_WIN, + 2 /* 1 */ , + tui_term_width (), + 0, + src_height - 1); + (*win_info_ptr)->detail.source_info.has_locator = TRUE; + init_gen_win_info ( + &(*win_info_ptr)->generic, + (*win_info_ptr)->generic.type, + src_height - 1, + (*win_info_ptr)->generic.width, + (*win_info_ptr)->detail.source_info.execution_info->width, + 0); + init_gen_win_info ((*win_info_ptr)->detail.source_info.execution_info, + EXEC_INFO_WIN, + src_height - 1, + 3, + 0, + 0); + (*win_info_ptr)->can_highlight = TRUE; + tui_make_visible (&(*win_info_ptr)->generic); + tui_make_visible ((*win_info_ptr)->detail.source_info.execution_info); + } + if ((*win_info_ptr) != NULL) + { + (*win_info_ptr)->detail.source_info.has_locator = TRUE; + tui_make_visible (locator); + tui_show_locator_content (); + tui_show_source_content (*win_info_ptr); + + if (TUI_CMD_WIN == NULL) + { + make_command_window (&TUI_CMD_WIN, cmd_height, src_height); + tui_refresh_win (&TUI_CMD_WIN->generic); + } + else + { + init_gen_win_info (&TUI_CMD_WIN->generic, + TUI_CMD_WIN->generic.type, + TUI_CMD_WIN->generic.height, + TUI_CMD_WIN->generic.width, + TUI_CMD_WIN->generic.origin.x, + TUI_CMD_WIN->generic.origin.y); + TUI_CMD_WIN->can_highlight = FALSE; + tui_make_visible (&TUI_CMD_WIN->generic); + } + } + tui_set_current_layout_to (layout_type); + } +} diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h new file mode 100644 index 00000000000..5df1f0be9f1 --- /dev/null +++ b/gdb/tui/tui-layout.h @@ -0,0 +1,38 @@ +/* TUI layout window management. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_LAYOUT_H +#define TUI_LAYOUT_H + +#include "tui/tui.h" +#include "tui/tui-data.h" + +extern void tui_add_win_to_layout (enum tui_win_type); +extern int tui_default_win_height (enum tui_win_type, enum tui_layout_type); +extern int tui_default_win_viewport_height (enum tui_win_type, + enum tui_layout_type); +extern enum tui_status tui_set_layout (enum tui_layout_type, + enum tui_register_display_type); + +#endif /*TUI_LAYOUT_H */ diff --git a/gdb/tui/tui-regs.c b/gdb/tui/tui-regs.c new file mode 100644 index 00000000000..d3ff1ebb648 --- /dev/null +++ b/gdb/tui/tui-regs.c @@ -0,0 +1,984 @@ +/* TUI display registers in window. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "frame.h" +#include "regcache.h" +#include "inferior.h" +#include "target.h" +#include "gdb_string.h" +#include "tui/tui-layout.h" +#include "tui/tui-win.h" +#include "tui/tui-windata.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-file.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/***************************************** +** LOCAL DEFINITIONS ** +******************************************/ +#define DOUBLE_FLOAT_LABEL_WIDTH 6 +#define DOUBLE_FLOAT_LABEL_FMT "%6.6s: " +#define DOUBLE_FLOAT_VALUE_WIDTH 30 /*min of 16 but may be in sci notation */ + +#define SINGLE_FLOAT_LABEL_WIDTH 6 +#define SINGLE_FLOAT_LABEL_FMT "%6.6s: " +#define SINGLE_FLOAT_VALUE_WIDTH 25 /* min of 8 but may be in sci notation */ + +#define SINGLE_LABEL_WIDTH 16 +#define SINGLE_LABEL_FMT "%10.10s: " +#define SINGLE_VALUE_WIDTH 20 /* minimum of 8 but may be in sci notation */ + +/* In the code HP gave Cygnus, this was actually a function call to a + PA-specific function, which was supposed to determine whether the + target was a 64-bit or 32-bit processor. However, the 64-bit + support wasn't complete, so we didn't merge that in, so we leave + this here as a stub. */ +#define IS_64BIT 0 + +/***************************************** +** STATIC DATA ** +******************************************/ + + +/***************************************** +** STATIC LOCAL FUNCTIONS FORWARD DECLS ** +******************************************/ +static enum tui_status tui_set_regs_content + (int, int, struct frame_info *, enum tui_register_display_type, int); +static const char *tui_register_name (int); +static enum tui_status tui_get_register_raw_value (int, char *, struct frame_info *); +static void tui_set_register_element + (int, struct frame_info *, struct tui_data_element *, int); +static void tui_display_register (int, struct tui_gen_win_info *, enum precision_type); +static void tui_register_format + (char *, int, int, struct tui_data_element *, enum precision_type); +static enum tui_status tui_set_general_regs_content (int); +static enum tui_status tui_set_special_regs_content (int); +static enum tui_status tui_set_general_and_special_regs_content (int); +static enum tui_status tui_set_float_regs_content (enum tui_register_display_type, int); +static int tui_reg_value_has_changed + (struct tui_data_element *, struct frame_info *, char *); +static void tui_show_float_command (char *, int); +static void tui_show_general_command (char *, int); +static void tui_show_special_command (char *, int); +static void tui_v_show_registers_command_support (enum tui_register_display_type); +static void _tui_toggle_float_regs_command (char *, int); +static void tui_scroll_regs_forward_command (char *, int); +static void tui_scroll_regs_backward_command (char *, int); + + + +/***************************************** +** PUBLIC FUNCTIONS ** +******************************************/ + +/* Answer the number of the last line in the regs display. If there + are no registers (-1) is returned. */ +int +tui_last_regs_line_no (void) +{ + int num_lines = (-1); + + if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0) + { + num_lines = (TUI_DATA_WIN->detail.data_display_info.regs_content_count / + TUI_DATA_WIN->detail.data_display_info.regs_column_count); + if (TUI_DATA_WIN->detail.data_display_info.regs_content_count % + TUI_DATA_WIN->detail.data_display_info.regs_column_count) + num_lines++; + } + return num_lines; +} + + +/* Answer the line number that the register element at element_no is + on. If element_no is greater than the number of register elements + there are, -1 is returned. */ +int +tui_line_from_reg_element_no (int element_no) +{ + if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count) + { + int i, line = (-1); + + i = 1; + while (line == (-1)) + { + if (element_no < + (TUI_DATA_WIN->detail.data_display_info.regs_column_count * i)) + line = i - 1; + else + i++; + } + + return line; + } + else + return (-1); +} + + +/* Answer the index of the first element in line_no. If line_no is past + the register area (-1) is returned. */ +int +tui_first_reg_element_no_inline (int line_no) +{ + if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count) + <= TUI_DATA_WIN->detail.data_display_info.regs_content_count) + return ((line_no + 1) * + TUI_DATA_WIN->detail.data_display_info.regs_column_count) - + TUI_DATA_WIN->detail.data_display_info.regs_column_count; + else + return (-1); +} + + +/* Answer the index of the last element in line_no. If line_no is + past the register area (-1) is returned. */ +int +tui_last_reg_element_no_in_line (int line_no) +{ + if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count) <= + TUI_DATA_WIN->detail.data_display_info.regs_content_count) + return ((line_no + 1) * + TUI_DATA_WIN->detail.data_display_info.regs_column_count) - 1; + else + return (-1); +} + + +/* Calculate the number of columns that should be used to display the + registers. */ +int +tui_calculate_regs_column_count (enum tui_register_display_type dpy_type) +{ + int col_count, col_width; + + if (IS_64BIT || dpy_type == TUI_DFLOAT_REGS) + col_width = DOUBLE_FLOAT_VALUE_WIDTH + DOUBLE_FLOAT_LABEL_WIDTH; + else + { + if (dpy_type == TUI_SFLOAT_REGS) + col_width = SINGLE_FLOAT_VALUE_WIDTH + SINGLE_FLOAT_LABEL_WIDTH; + else + col_width = SINGLE_VALUE_WIDTH + SINGLE_LABEL_WIDTH; + } + col_count = (TUI_DATA_WIN->generic.width - 2) / col_width; + + return col_count; +} + + +/* Show the registers int the data window as indicated by dpy_type. If + there is any other registers being displayed, then they are + cleared. What registers are displayed is dependent upon dpy_type. */ +void +tui_show_registers (enum tui_register_display_type dpy_type) +{ + enum tui_status ret = TUI_FAILURE; + int refresh_values_only = FALSE; + + /* Say that registers should be displayed, even if there is a problem */ + TUI_DATA_WIN->detail.data_display_info.display_regs = TRUE; + + if (target_has_registers) + { + refresh_values_only = + (dpy_type == TUI_DATA_WIN->detail.data_display_info.regs_display_type); + switch (dpy_type) + { + case TUI_GENERAL_REGS: + ret = tui_set_general_regs_content (refresh_values_only); + break; + case TUI_SFLOAT_REGS: + case TUI_DFLOAT_REGS: + ret = tui_set_float_regs_content (dpy_type, refresh_values_only); + break; + +/* could ifdef out */ + + case TUI_SPECIAL_REGS: + ret = tui_set_special_regs_content (refresh_values_only); + break; + case TUI_GENERAL_AND_SPECIAL_REGS: + ret = tui_set_general_and_special_regs_content (refresh_values_only); + break; + +/* end of potential if def */ + + default: + break; + } + } + if (ret == TUI_FAILURE) + { + TUI_DATA_WIN->detail.data_display_info.regs_display_type = TUI_UNDEFINED_REGS; + tui_erase_data_content (NO_REGS_STRING); + } + else + { + int i; + + /* Clear all notation of changed values */ + for (i = 0; (i < TUI_DATA_WIN->detail.data_display_info.regs_content_count); i++) + { + struct tui_gen_win_info * data_item_win; + + data_item_win = &TUI_DATA_WIN->detail.data_display_info. + regs_content[i]->which_element.data_window; + (&((struct tui_win_element *) + data_item_win->content[0])->which_element.data)->highlight = FALSE; + } + TUI_DATA_WIN->detail.data_display_info.regs_display_type = dpy_type; + tui_display_all_data (); + } + (tui_layout_def ())->regs_display_type = dpy_type; + + return; +} + + +/* Function to display the registers in the content from + 'start_element_no' until the end of the register content or the end + of the display height. No checking for displaying past the end of + the registers is done here. */ +void +tui_display_registers_from (int start_element_no) +{ + if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL && + TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0) + { + int i = start_element_no; + int j, value_chars_wide, item_win_width, cur_y, label_width; + enum precision_type precision; + + precision = (TUI_DATA_WIN->detail.data_display_info.regs_display_type + == TUI_DFLOAT_REGS) ? + double_precision : unspecified_precision; + if (IS_64BIT || + TUI_DATA_WIN->detail.data_display_info.regs_display_type == TUI_DFLOAT_REGS) + { + value_chars_wide = DOUBLE_FLOAT_VALUE_WIDTH; + label_width = DOUBLE_FLOAT_LABEL_WIDTH; + } + else + { + if (TUI_DATA_WIN->detail.data_display_info.regs_display_type == + TUI_SFLOAT_REGS) + { + value_chars_wide = SINGLE_FLOAT_VALUE_WIDTH; + label_width = SINGLE_FLOAT_LABEL_WIDTH; + } + else + { + value_chars_wide = SINGLE_VALUE_WIDTH; + label_width = SINGLE_LABEL_WIDTH; + } + } + item_win_width = value_chars_wide + label_width; + /* + ** Now create each data "sub" window, and write the display into it. + */ + cur_y = 1; + while (i < TUI_DATA_WIN->detail.data_display_info.regs_content_count && + cur_y <= TUI_DATA_WIN->generic.viewport_height) + { + for (j = 0; + (j < TUI_DATA_WIN->detail.data_display_info.regs_column_count && + i < TUI_DATA_WIN->detail.data_display_info.regs_content_count); j++) + { + struct tui_gen_win_info * data_item_win; + struct tui_data_element * data_element_ptr; + + /* create the window if necessary */ + data_item_win = &TUI_DATA_WIN->detail.data_display_info. + regs_content[i]->which_element.data_window; + data_element_ptr = &((struct tui_win_element *) + data_item_win->content[0])->which_element.data; + if (data_item_win->handle == (WINDOW *) NULL) + { + data_item_win->height = 1; + data_item_win->width = (precision == double_precision) ? + item_win_width + 2 : item_win_width + 1; + data_item_win->origin.x = (item_win_width * j) + 1; + data_item_win->origin.y = cur_y; + tui_make_window (data_item_win, DONT_BOX_WINDOW); + scrollok (data_item_win->handle, FALSE); + } + touchwin (data_item_win->handle); + + /* + ** Get the printable representation of the register + ** and display it + */ + tui_display_register ( + data_element_ptr->item_no, data_item_win, precision); + i++; /* next register */ + } + cur_y++; /* next row; */ + } + } + + return; +} + + +/* Function to display the registers in the content from + 'start_element_no' on 'start_line_no' until the end of the register + content or the end of the display height. This function checks + that we won't display off the end of the register display. */ +void +tui_display_reg_element_at_line (int start_element_no, int start_line_no) +{ + if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL && + TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0) + { + int element_no = start_element_no; + + if (start_element_no != 0 && start_line_no != 0) + { + int last_line_no, first_line_on_last_page; + + last_line_no = tui_last_regs_line_no (); + first_line_on_last_page = last_line_no - (TUI_DATA_WIN->generic.height - 2); + if (first_line_on_last_page < 0) + first_line_on_last_page = 0; + /* + ** If there is no other data displayed except registers, + ** and the element_no causes us to scroll past the end of the + ** registers, adjust what element to really start the display at. + */ + if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0 && + start_line_no > first_line_on_last_page) + element_no = tui_first_reg_element_no_inline (first_line_on_last_page); + } + tui_display_registers_from (element_no); + } +} + + + +/* Function to display the registers starting at line line_no in the + data window. Answers the line number that the display actually + started from. If nothing is displayed (-1) is returned. */ +int +tui_display_registers_from_line (int line_no, int force_display) +{ + if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0) + { + int line, element_no; + + if (line_no < 0) + line = 0; + else if (force_display) + { /* + ** If we must display regs (force_display is true), then make + ** sure that we don't display off the end of the registers. + */ + if (line_no >= tui_last_regs_line_no ()) + { + if ((line = tui_line_from_reg_element_no ( + TUI_DATA_WIN->detail.data_display_info.regs_content_count - 1)) < 0) + line = 0; + } + else + line = line_no; + } + else + line = line_no; + + element_no = tui_first_reg_element_no_inline (line); + if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count) + tui_display_reg_element_at_line (element_no, line); + else + line = (-1); + + return line; + } + + return (-1); /* nothing was displayed */ +} + + +/* This function check all displayed registers for changes in values, + given a particular frame. If the values have changed, they are + updated with the new value and highlighted. */ +void +tui_check_register_values (struct frame_info *frame) +{ + if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible) + { + if (TUI_DATA_WIN->detail.data_display_info.regs_content_count <= 0 && + TUI_DATA_WIN->detail.data_display_info.display_regs) + tui_show_registers ((tui_layout_def ())->regs_display_type); + else + { + int i, j; + char raw_buf[MAX_REGISTER_SIZE]; + + for (i = 0; + (i < TUI_DATA_WIN->detail.data_display_info.regs_content_count); i++) + { + struct tui_data_element * data_element_ptr; + struct tui_gen_win_info * data_item_win_ptr; + int was_hilighted; + + data_item_win_ptr = &TUI_DATA_WIN->detail.data_display_info. + regs_content[i]->which_element.data_window; + data_element_ptr = &((struct tui_win_element *) + data_item_win_ptr->content[0])->which_element.data; + was_hilighted = data_element_ptr->highlight; + data_element_ptr->highlight = + tui_reg_value_has_changed (data_element_ptr, frame, &raw_buf[0]); + if (data_element_ptr->highlight) + { + int size; + + size = DEPRECATED_REGISTER_RAW_SIZE (data_element_ptr->item_no); + for (j = 0; j < size; j++) + ((char *) data_element_ptr->value)[j] = raw_buf[j]; + tui_display_register ( + data_element_ptr->item_no, + data_item_win_ptr, + ((TUI_DATA_WIN->detail.data_display_info.regs_display_type == + TUI_DFLOAT_REGS) ? + double_precision : unspecified_precision)); + } + else if (was_hilighted) + { + data_element_ptr->highlight = FALSE; + tui_display_register ( + data_element_ptr->item_no, + data_item_win_ptr, + ((TUI_DATA_WIN->detail.data_display_info.regs_display_type == + TUI_DFLOAT_REGS) ? + double_precision : unspecified_precision)); + } + } + } + } + return; +} + + +/* + ** tui_toggle_float_regs(). + */ +void +tui_toggle_float_regs (void) +{ + struct tui_layout_def * layout_def = tui_layout_def (); + + if (layout_def->float_regs_display_type == TUI_SFLOAT_REGS) + layout_def->float_regs_display_type = TUI_DFLOAT_REGS; + else + layout_def->float_regs_display_type = TUI_SFLOAT_REGS; + + if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible && + (TUI_DATA_WIN->detail.data_display_info.regs_display_type == TUI_SFLOAT_REGS || + TUI_DATA_WIN->detail.data_display_info.regs_display_type == TUI_DFLOAT_REGS)) + tui_show_registers (layout_def->float_regs_display_type); + + return; +} /* tui_toggle_float_regs */ + + +void +_initialize_tui_regs (void) +{ + if (xdb_commands) + { + add_com ("fr", class_tui, tui_show_float_command, + "Display only floating point registers\n"); + add_com ("gr", class_tui, tui_show_general_command, + "Display only general registers\n"); + add_com ("sr", class_tui, tui_show_special_command, + "Display only special registers\n"); + add_com ("+r", class_tui, tui_scroll_regs_forward_command, + "Scroll the registers window forward\n"); + add_com ("-r", class_tui, tui_scroll_regs_backward_command, + "Scroll the register window backward\n"); + add_com ("tf", class_tui, _tui_toggle_float_regs_command, + "Toggle between single and double precision floating point registers.\n"); + add_cmd (TUI_FLOAT_REGS_NAME_LOWER, + class_tui, + _tui_toggle_float_regs_command, + "Toggle between single and double precision floating point \ +registers.\n", + &togglelist); + } +} + + +/***************************************** +** STATIC LOCAL FUNCTIONS ** +******************************************/ + + +/* + ** tui_register_name(). + ** Return the register name. + */ +static const char * +tui_register_name (int reg_num) +{ + return REGISTER_NAME (reg_num); +} +extern int pagination_enabled; + +static void +tui_restore_gdbout (void *ui) +{ + ui_file_delete (gdb_stdout); + gdb_stdout = (struct ui_file*) ui; + pagination_enabled = 1; +} + +/* + ** tui_register_format + ** Function to format the register name and value into a buffer, + ** suitable for printing or display + */ +static void +tui_register_format (char *buf, int buf_len, int reg_num, + struct tui_data_element * data_element, + enum precision_type precision) +{ + struct ui_file *stream; + struct ui_file *old_stdout; + const char *name; + struct cleanup *cleanups; + char *p; + int pos; + + name = REGISTER_NAME (reg_num); + if (name == 0) + { + strcpy (buf, ""); + return; + } + + pagination_enabled = 0; + old_stdout = gdb_stdout; + stream = tui_sfileopen (buf_len); + gdb_stdout = stream; + cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout); + gdbarch_print_registers_info (current_gdbarch, stream, deprecated_selected_frame, + reg_num, 1); + + /* Save formatted output in the buffer. */ + p = tui_file_get_strbuf (stream); + pos = 0; + while (*p && *p == *name++ && buf_len) + { + *buf++ = *p++; + buf_len--; + pos++; + } + while (*p == ' ') + p++; + while (pos < 8 && buf_len) + { + *buf++ = ' '; + buf_len--; + pos++; + } + strncpy (buf, p, buf_len); + + /* Remove the possible \n. */ + p = strchr (buf, '\n'); + if (p) + *p = 0; + + do_cleanups (cleanups); +} + + +#define NUM_GENERAL_REGS 32 +/* Set the content of the data window to consist of the general + registers. */ +static enum tui_status +tui_set_general_regs_content (int refresh_values_only) +{ + return (tui_set_regs_content (0, + NUM_GENERAL_REGS - 1, + deprecated_selected_frame, + TUI_GENERAL_REGS, + refresh_values_only)); + +} + + +#ifndef PCOQ_HEAD_REGNUM +#define START_SPECIAL_REGS 0 +#else +#define START_SPECIAL_REGS PCOQ_HEAD_REGNUM +#endif + +/* Set the content of the data window to consist of the special + registers. */ +static enum tui_status +tui_set_special_regs_content (int refresh_values_only) +{ + enum tui_status ret = TUI_FAILURE; + int end_reg_num; + + end_reg_num = FP0_REGNUM - 1; + ret = tui_set_regs_content (START_SPECIAL_REGS, + end_reg_num, + deprecated_selected_frame, + TUI_SPECIAL_REGS, + refresh_values_only); + + return ret; +} + + +/* Set the content of the data window to consist of the special + registers. */ +static enum tui_status +tui_set_general_and_special_regs_content (int refresh_values_only) +{ + enum tui_status ret = TUI_FAILURE; + int end_reg_num = (-1); + + end_reg_num = FP0_REGNUM - 1; + ret = tui_set_regs_content ( + 0, end_reg_num, deprecated_selected_frame, TUI_SPECIAL_REGS, refresh_values_only); + + return ret; +} + +/* Set the content of the data window to consist of the float + registers. */ +static enum tui_status +tui_set_float_regs_content (enum tui_register_display_type dpy_type, + int refresh_values_only) +{ + enum tui_status ret = TUI_FAILURE; + int start_reg_num; + + start_reg_num = FP0_REGNUM; + ret = tui_set_regs_content (start_reg_num, + NUM_REGS - 1, + deprecated_selected_frame, + dpy_type, + refresh_values_only); + + return ret; +} + + +/* Answer TRUE if the register's value has changed, FALSE otherwise. + If TRUE, new_value is filled in with the new value. */ +static int +tui_reg_value_has_changed (struct tui_data_element * data_element, + struct frame_info *frame, char *new_value) +{ + int has_changed = FALSE; + + if (data_element->item_no != UNDEFINED_ITEM && + tui_register_name (data_element->item_no) != (char *) NULL) + { + char raw_buf[MAX_REGISTER_SIZE]; + int i; + + if (tui_get_register_raw_value (data_element->item_no, raw_buf, frame) == TUI_SUCCESS) + { + int size = DEPRECATED_REGISTER_RAW_SIZE (data_element->item_no); + + for (i = 0; (i < size && !has_changed); i++) + has_changed = (((char *) data_element->value)[i] != raw_buf[i]); + if (has_changed && new_value != (char *) NULL) + { + for (i = 0; i < size; i++) + new_value[i] = raw_buf[i]; + } + } + } + return has_changed; +} + + + +/* Get the register raw value. The raw value is returned in reg_value. */ +static enum tui_status +tui_get_register_raw_value (int reg_num, char *reg_value, struct frame_info *frame) +{ + enum tui_status ret = TUI_FAILURE; + + if (target_has_registers) + { + get_frame_register (frame, reg_num, reg_value); + /* NOTE: cagney/2003-03-13: This is bogus. It is refering to + the register cache and not the frame which could have pulled + the register value off the stack. */ + if (register_cached (reg_num) >= 0) + ret = TUI_SUCCESS; + } + return ret; +} + + + +/* Function to initialize a data element with the input and the + register value. */ +static void +tui_set_register_element (int reg_num, struct frame_info *frame, + struct tui_data_element * data_element, + int refresh_value_only) +{ + if (data_element != (struct tui_data_element *) NULL) + { + if (!refresh_value_only) + { + data_element->item_no = reg_num; + data_element->name = tui_register_name (reg_num); + data_element->highlight = FALSE; + } + if (data_element->value == NULL) + data_element->value = xmalloc (MAX_REGISTER_SIZE); + if (data_element->value != NULL) + tui_get_register_raw_value (reg_num, data_element->value, frame); + } +} + + +/* Set the content of the data window to consist of the registers + numbered from start_reg_num to end_reg_num. Note that if + refresh_values_only is TRUE, start_reg_num and end_reg_num are + ignored. */ +static enum tui_status +tui_set_regs_content (int start_reg_num, int end_reg_num, + struct frame_info *frame, + enum tui_register_display_type dpy_type, + int refresh_values_only) +{ + enum tui_status ret = TUI_FAILURE; + int num_regs = end_reg_num - start_reg_num + 1; + int allocated_here = FALSE; + + if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0 && + !refresh_values_only) + { + tui_free_data_content (TUI_DATA_WIN->detail.data_display_info.regs_content, + TUI_DATA_WIN->detail.data_display_info.regs_content_count); + TUI_DATA_WIN->detail.data_display_info.regs_content_count = 0; + } + if (TUI_DATA_WIN->detail.data_display_info.regs_content_count <= 0) + { + TUI_DATA_WIN->detail.data_display_info.regs_content = + tui_alloc_content (num_regs, DATA_WIN); + allocated_here = TRUE; + } + + if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL) + { + int i; + + if (!refresh_values_only || allocated_here) + { + TUI_DATA_WIN->generic.content = NULL; + TUI_DATA_WIN->generic.content_size = 0; + tui_add_content_elements (&TUI_DATA_WIN->generic, num_regs); + TUI_DATA_WIN->detail.data_display_info.regs_content = + (tui_win_content) TUI_DATA_WIN->generic.content; + TUI_DATA_WIN->detail.data_display_info.regs_content_count = num_regs; + } + /* + ** Now set the register names and values + */ + for (i = start_reg_num; (i <= end_reg_num); i++) + { + struct tui_gen_win_info * data_item_win; + + data_item_win = &TUI_DATA_WIN->detail.data_display_info. + regs_content[i - start_reg_num]->which_element.data_window; + tui_set_register_element ( + i, + frame, + &((struct tui_win_element *) data_item_win->content[0])->which_element.data, + !allocated_here && refresh_values_only); + } + TUI_DATA_WIN->detail.data_display_info.regs_column_count = + tui_calculate_regs_column_count (dpy_type); +#ifdef LATER + if (TUI_DATA_WIN->detail.data_display_info.data_content_count > 0) + { + /* delete all the windows? */ + /* realloc content equal to data_content_count + regs_content_count */ + /* append TUI_DATA_WIN->detail.data_display_info.data_content to content */ + } +#endif + TUI_DATA_WIN->generic.content_size = + TUI_DATA_WIN->detail.data_display_info.regs_content_count + + TUI_DATA_WIN->detail.data_display_info.data_content_count; + ret = TUI_SUCCESS; + } + + return ret; +} + + +/* Function to display a register in a window. If hilite is TRUE, + than the value will be displayed in reverse video. */ +static void +tui_display_register (int reg_num, + struct tui_gen_win_info * win_info, /* the data item window */ + enum precision_type precision) +{ + if (win_info->handle != (WINDOW *) NULL) + { + int i; + char buf[40]; + int value_chars_wide, label_width; + struct tui_data_element * data_element_ptr = &((tui_win_content) + win_info->content)[0]->which_element.data; + + if (IS_64BIT || + TUI_DATA_WIN->detail.data_display_info.regs_display_type == TUI_DFLOAT_REGS) + { + value_chars_wide = DOUBLE_FLOAT_VALUE_WIDTH; + label_width = DOUBLE_FLOAT_LABEL_WIDTH; + } + else + { + if (TUI_DATA_WIN->detail.data_display_info.regs_display_type == + TUI_SFLOAT_REGS) + { + value_chars_wide = SINGLE_FLOAT_VALUE_WIDTH; + label_width = SINGLE_FLOAT_LABEL_WIDTH; + } + else + { + value_chars_wide = SINGLE_VALUE_WIDTH; + label_width = SINGLE_LABEL_WIDTH; + } + } + + buf[0] = (char) 0; + tui_register_format (buf, + value_chars_wide + label_width, + reg_num, + data_element_ptr, + precision); + + if (data_element_ptr->highlight) + wstandout (win_info->handle); + + wmove (win_info->handle, 0, 0); + for (i = 1; i < win_info->width; i++) + waddch (win_info->handle, ' '); + wmove (win_info->handle, 0, 0); + waddstr (win_info->handle, buf); + + if (data_element_ptr->highlight) + wstandend (win_info->handle); + tui_refresh_win (win_info); + } +} + + +static void +tui_v_show_registers_command_support (enum tui_register_display_type dpy_type) +{ + + if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible) + { /* Data window already displayed, show the registers */ + if (TUI_DATA_WIN->detail.data_display_info.regs_display_type != dpy_type) + tui_show_registers (dpy_type); + } + else + (tui_layout_def ())->regs_display_type = dpy_type; + + return; +} + + +static void +tui_show_float_command (char *arg, int from_tty) +{ + if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->generic.is_visible || + (TUI_DATA_WIN->detail.data_display_info.regs_display_type != TUI_SFLOAT_REGS && + TUI_DATA_WIN->detail.data_display_info.regs_display_type != TUI_DFLOAT_REGS)) + tui_v_show_registers_command_support ((tui_layout_def ())->float_regs_display_type); +} + + +static void +tui_show_general_command (char *arg, int from_tty) +{ + tui_v_show_registers_command_support (TUI_GENERAL_REGS); +} + + +static void +tui_show_special_command (char *arg, int from_tty) +{ + tui_v_show_registers_command_support (TUI_SPECIAL_REGS); +} + + +static void +_tui_toggle_float_regs_command (char *arg, int from_tty) +{ + if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible) + tui_toggle_float_regs (); + else + { + struct tui_layout_def * layout_def = tui_layout_def (); + + if (layout_def->float_regs_display_type == TUI_SFLOAT_REGS) + layout_def->float_regs_display_type = TUI_DFLOAT_REGS; + else + layout_def->float_regs_display_type = TUI_SFLOAT_REGS; + } +} + + +static void +tui_scroll_regs_forward_command (char *arg, int from_tty) +{ + tui_scroll (FORWARD_SCROLL, TUI_DATA_WIN, 1); +} + + +static void +tui_scroll_regs_backward_command (char *arg, int from_tty) +{ + tui_scroll (BACKWARD_SCROLL, TUI_DATA_WIN, 1); +} diff --git a/gdb/tui/tui-regs.h b/gdb/tui/tui-regs.h new file mode 100644 index 00000000000..c4de1239c05 --- /dev/null +++ b/gdb/tui/tui-regs.h @@ -0,0 +1,41 @@ +/* TUI display registers in window. + + Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation, + Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_REGS_H +#define TUI_REGS_H + +#include "tui/tui-data.h" /* For struct tui_register_display_type. */ + +extern void tui_check_register_values (struct frame_info *); +extern void tui_show_registers (enum tui_register_display_type); +extern void tui_display_registers_from (int); +extern int tui_display_registers_from_line (int, int); +extern int tui_last_regs_line_no (void); +extern int tui_first_reg_element_inline (int); +extern int tui_line_from_reg_element_no (int); +extern void tui_toggle_float_regs (void); +extern int tui_calculate_regs_column_count (enum tui_register_display_type); +extern int tui_first_reg_element_no_inline (int lineno); + +#endif diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c new file mode 100644 index 00000000000..f97de2f49e3 --- /dev/null +++ b/gdb/tui/tui-source.c @@ -0,0 +1,357 @@ +/* TUI display source window. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "symtab.h" +#include "frame.h" +#include "breakpoint.h" +#include "source.h" +#include "symtab.h" + +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-stack.h" +#include "tui/tui-winsource.h" +#include "tui/tui-source.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/* Function to display source in the source window. */ +enum tui_status +tui_set_source_content (struct symtab *s, int line_no, int noerror) +{ + enum tui_status ret = TUI_FAILURE; + + if (s != (struct symtab *) NULL && s->filename != (char *) NULL) + { + FILE *stream; + int i, desc, c, line_width, nlines; + char *src_line = 0; + + if ((ret = tui_alloc_source_buffer (TUI_SRC_WIN)) == TUI_SUCCESS) + { + line_width = TUI_SRC_WIN->generic.width - 1; + /* Take hilite (window border) into account, when calculating + the number of lines */ + nlines = (line_no + (TUI_SRC_WIN->generic.height - 2)) - line_no; + desc = open_source_file (s); + if (desc < 0) + { + if (!noerror) + { + char *name = alloca (strlen (s->filename) + 100); + sprintf (name, "%s:%d", s->filename, line_no); + print_sys_errmsg (name, errno); + } + ret = TUI_FAILURE; + } + else + { + if (s->line_charpos == 0) + find_source_lines (s, desc); + + if (line_no < 1 || line_no > s->nlines) + { + close (desc); + printf_unfiltered ( + "Line number %d out of range; %s has %d lines.\n", + line_no, s->filename, s->nlines); + } + else if (lseek (desc, s->line_charpos[line_no - 1], 0) < 0) + { + close (desc); + perror_with_name (s->filename); + } + else + { + int offset, cur_line_no, cur_line, cur_len, threshold; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + struct tui_source_info * src = &TUI_SRC_WIN->detail.source_info; + + if (TUI_SRC_WIN->generic.title) + xfree (TUI_SRC_WIN->generic.title); + TUI_SRC_WIN->generic.title = xstrdup (s->filename); + + if (src->filename) + xfree (src->filename); + src->filename = xstrdup (s->filename); + + /* Determine the threshold for the length of the line + and the offset to start the display. */ + offset = src->horizontal_offset; + threshold = (line_width - 1) + offset; + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + cur_line = 0; + cur_line_no = src->start_line_or_addr.line_no = line_no; + if (offset > 0) + src_line = (char *) xmalloc ( + (threshold + 1) * sizeof (char)); + while (cur_line < nlines) + { + struct tui_win_element * element = (struct tui_win_element *) + TUI_SRC_WIN->generic.content[cur_line]; + + /* get the first character in the line */ + c = fgetc (stream); + + if (offset == 0) + src_line = ((struct tui_win_element *) + TUI_SRC_WIN->generic.content[ + cur_line])->which_element.source.line; + /* Init the line with the line number */ + sprintf (src_line, "%-6d", cur_line_no); + cur_len = strlen (src_line); + i = cur_len - + ((cur_len / tui_default_tab_len ()) * tui_default_tab_len ()); + while (i < tui_default_tab_len ()) + { + src_line[cur_len] = ' '; + i++; + cur_len++; + } + src_line[cur_len] = (char) 0; + + /* Set whether element is the execution point and + whether there is a break point on it. */ + element->which_element.source.line_or_addr.line_no = + cur_line_no; + element->which_element.source.is_exec_point = + (strcmp (((struct tui_win_element *) + locator->content[0])->which_element.locator.file_name, + s->filename) == 0 + && cur_line_no == ((struct tui_win_element *) + locator->content[0])->which_element.locator.line_no); + if (c != EOF) + { + i = strlen (src_line) - 1; + do + { + if ((c != '\n') && + (c != '\r') && (++i < threshold)) + { + if (c < 040 && c != '\t') + { + src_line[i++] = '^'; + src_line[i] = c + 0100; + } + else if (c == 0177) + { + src_line[i++] = '^'; + src_line[i] = '?'; + } + else + { /* Store the charcter in the line + buffer. If it is a tab, then + translate to the correct number of + chars so we don't overwrite our + buffer. */ + if (c == '\t') + { + int j, max_tab_len = tui_default_tab_len (); + + for (j = i - ( + (i / max_tab_len) * max_tab_len); + ((j < max_tab_len) && + i < threshold); + i++, j++) + src_line[i] = ' '; + i--; + } + else + src_line[i] = c; + } + src_line[i + 1] = 0; + } + else + { /* If we have not reached EOL, then eat + chars until we do */ + while (c != EOF && c != '\n' && c != '\r') + c = fgetc (stream); + } + } + while (c != EOF && c != '\n' && c != '\r' && + i < threshold && (c = fgetc (stream))); + } + /* Now copy the line taking the offset into account */ + if (strlen (src_line) > offset) + strcpy (((struct tui_win_element *) TUI_SRC_WIN->generic.content[ + cur_line])->which_element.source.line, + &src_line[offset]); + else + ((struct tui_win_element *) + TUI_SRC_WIN->generic.content[ + cur_line])->which_element.source.line[0] = (char) 0; + cur_line++; + cur_line_no++; + } + if (offset > 0) + xfree (src_line); + fclose (stream); + TUI_SRC_WIN->generic.content_size = nlines; + ret = TUI_SUCCESS; + } + } + } + } + return ret; +} + + +/* elz: this function sets the contents of the source window to empty + except for a line in the middle with a warning message about the + source not being available. This function is called by + tui_erase_source_contents(), which in turn is invoked when the + source files cannot be accessed. */ + +void +tui_set_source_content_nil (struct tui_win_info * win_info, char *warning_string) +{ + int line_width; + int n_lines; + int curr_line = 0; + + line_width = win_info->generic.width - 1; + n_lines = win_info->generic.height - 2; + + /* set to empty each line in the window, except for the one + which contains the message */ + while (curr_line < win_info->generic.content_size) + { + /* set the information related to each displayed line + to null: i.e. the line number is 0, there is no bp, + it is not where the program is stopped */ + + struct tui_win_element * element = + (struct tui_win_element *) win_info->generic.content[curr_line]; + element->which_element.source.line_or_addr.line_no = 0; + element->which_element.source.is_exec_point = FALSE; + element->which_element.source.has_break = FALSE; + + /* set the contents of the line to blank */ + element->which_element.source.line[0] = (char) 0; + + /* if the current line is in the middle of the screen, then we + want to display the 'no source available' message in it. + Note: the 'weird' arithmetic with the line width and height + comes from the function tui_erase_source_content(). We need + to keep the screen and the window's actual contents in synch. */ + + if (curr_line == (n_lines / 2 + 1)) + { + int i; + int xpos; + int warning_length = strlen (warning_string); + char *src_line; + + src_line = element->which_element.source.line; + + if (warning_length >= ((line_width - 1) / 2)) + xpos = 1; + else + xpos = (line_width - 1) / 2 - warning_length; + + for (i = 0; i < xpos; i++) + src_line[i] = ' '; + + sprintf (src_line + i, "%s", warning_string); + + for (i = xpos + warning_length; i < line_width; i++) + src_line[i] = ' '; + + src_line[i] = '\n'; + + } /* end if */ + + curr_line++; + + } /* end while */ +} + + +/* Function to display source in the source window. This function + initializes the horizontal scroll to 0. */ +void +tui_show_symtab_source (struct symtab *s, union tui_line_or_address line, int noerror) +{ + TUI_SRC_WIN->detail.source_info.horizontal_offset = 0; + tui_update_source_window_as_is (TUI_SRC_WIN, s, line, noerror); +} + + +/* Answer whether the source is currently displayed in the source + window. */ +int +tui_source_is_displayed (char *fname) +{ + return (TUI_SRC_WIN->generic.content_in_use && + (strcmp (((struct tui_win_element *) (tui_locator_win_info_ptr ())-> + content[0])->which_element.locator.file_name, fname) == 0)); +} + + +/* Scroll the source forward or backward vertically. */ +void +tui_vertical_source_scroll (enum tui_scroll_direction scroll_direction, + int num_to_scroll) +{ + if (TUI_SRC_WIN->generic.content != NULL) + { + union tui_line_or_address l; + struct symtab *s; + tui_win_content content = (tui_win_content) TUI_SRC_WIN->generic.content; + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + + if (cursal.symtab == (struct symtab *) NULL) + s = find_pc_symtab (get_frame_pc (deprecated_selected_frame)); + else + s = cursal.symtab; + + if (scroll_direction == FORWARD_SCROLL) + { + l.line_no = content[0]->which_element.source.line_or_addr.line_no + + num_to_scroll; + if (l.line_no > s->nlines) + /*line = s->nlines - win_info->generic.content_size + 1; */ + /*elz: fix for dts 23398 */ + l.line_no = content[0]->which_element.source.line_or_addr.line_no; + } + else + { + l.line_no = content[0]->which_element.source.line_or_addr.line_no - + num_to_scroll; + if (l.line_no <= 0) + l.line_no = 1; + } + + print_source_lines (s, l.line_no, l.line_no + 1, 0); + } +} diff --git a/gdb/tui/tui-source.h b/gdb/tui/tui-source.h new file mode 100644 index 00000000000..3b61ca4374d --- /dev/null +++ b/gdb/tui/tui-source.h @@ -0,0 +1,40 @@ +/* TUI display source window. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_SOURCE_H +#define TUI_SOURCE_H + +#include "tui/tui-data.h" + +struct symtab; +struct tui_win_info; + +extern void tui_set_source_content_nil (struct tui_win_info *, char *); + +extern enum tui_status tui_set_source_content (struct symtab *, int, int); +extern void tui_show_symtab_source (struct symtab *, union tui_line_or_address, int); +extern int tui_source_is_displayed (char *); +extern void tui_vertical_source_scroll (enum tui_scroll_direction, int); + +#endif diff --git a/gdb/tui/tui-stack.c b/gdb/tui/tui-stack.c new file mode 100644 index 00000000000..7285dab9140 --- /dev/null +++ b/gdb/tui/tui-stack.c @@ -0,0 +1,433 @@ +/* TUI display locator. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "breakpoint.h" +#include "frame.h" +#include "command.h" +#include "inferior.h" +#include "target.h" +#include "top.h" +#include "gdb_string.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-stack.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-source.h" +#include "tui/tui-winsource.h" +#include "tui/tui-file.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/* Get a printable name for the function at the address. + The symbol name is demangled if demangling is turned on. + Returns a pointer to a static area holding the result. */ +static char* tui_get_function_from_frame (struct frame_info *fi); + +/* Set the filename portion of the locator. */ +static void tui_set_locator_filename (const char *filename); + +/* Update the locator, with the provided arguments. */ +static void tui_set_locator_info (const char *filename, const char *procname, + int lineno, CORE_ADDR addr); + +static void tui_update_command (char *, int); + + +/* Create the status line to display as much information as we + can on this single line: target name, process number, current + function, current line, current PC, SingleKey mode. */ +static char* +tui_make_status_line (struct tui_locator_element* loc) +{ + char* string; + char line_buf[50], *pname; + char* buf; + int status_size; + int i, proc_width; + const char* pid_name; + const char* pc_buf; + int target_width; + int pid_width; + int line_width; + int pc_width; + struct ui_file *pc_out; + + if (ptid_equal (inferior_ptid, null_ptid)) + pid_name = "No process"; + else + pid_name = target_pid_to_str (inferior_ptid); + + target_width = strlen (target_shortname); + if (target_width > MAX_TARGET_WIDTH) + target_width = MAX_TARGET_WIDTH; + + pid_width = strlen (pid_name); + if (pid_width > MAX_PID_WIDTH) + pid_width = MAX_PID_WIDTH; + + status_size = tui_term_width (); + string = (char *) xmalloc (status_size + 1); + buf = (char*) alloca (status_size + 1); + + /* Translate line number and obtain its size. */ + if (loc->line_no > 0) + sprintf (line_buf, "%d", loc->line_no); + else + strcpy (line_buf, "??"); + line_width = strlen (line_buf); + if (line_width < MIN_LINE_WIDTH) + line_width = MIN_LINE_WIDTH; + + /* Translate PC address. */ + pc_out = tui_sfileopen (128); + print_address_numeric (loc->addr, 1, pc_out); + pc_buf = tui_file_get_strbuf (pc_out); + pc_width = strlen (pc_buf); + + /* First determine the amount of proc name width we have available. + The +1 are for a space separator between fields. + The -1 are to take into account the \0 counted by sizeof. */ + proc_width = (status_size + - (target_width + 1) + - (pid_width + 1) + - (sizeof (PROC_PREFIX) - 1 + 1) + - (sizeof (LINE_PREFIX) - 1 + line_width + 1) + - (sizeof (PC_PREFIX) - 1 + pc_width + 1) + - (tui_current_key_mode == TUI_SINGLE_KEY_MODE + ? (sizeof (SINGLE_KEY) - 1 + 1) + : 0)); + + /* If there is no room to print the function name, try by removing + some fields. */ + if (proc_width < MIN_PROC_WIDTH) + { + proc_width += target_width + 1; + target_width = 0; + if (proc_width < MIN_PROC_WIDTH) + { + proc_width += pid_width + 1; + pid_width = 0; + if (proc_width <= MIN_PROC_WIDTH) + { + proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1; + pc_width = 0; + if (proc_width < 0) + { + proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1; + line_width = 0; + if (proc_width < 0) + proc_width = 0; + } + } + } + } + + /* Now convert elements to string form */ + pname = loc->proc_name; + + /* Now create the locator line from the string version + of the elements. We could use sprintf() here but + that wouldn't ensure that we don't overrun the size + of the allocated buffer. strcat_to_buf() will. */ + *string = (char) 0; + + if (target_width > 0) + { + sprintf (buf, "%*.*s ", + -target_width, target_width, target_shortname); + strcat_to_buf (string, status_size, buf); + } + if (pid_width > 0) + { + sprintf (buf, "%*.*s ", + -pid_width, pid_width, pid_name); + strcat_to_buf (string, status_size, buf); + } + + /* Show whether we are in SingleKey mode. */ + if (tui_current_key_mode == TUI_SINGLE_KEY_MODE) + { + strcat_to_buf (string, status_size, SINGLE_KEY); + strcat_to_buf (string, status_size, " "); + } + + /* procedure/class name */ + if (proc_width > 0) + { + if (strlen (pname) > proc_width) + sprintf (buf, "%s%*.*s* ", PROC_PREFIX, + 1 - proc_width, proc_width - 1, pname); + else + sprintf (buf, "%s%*.*s ", PROC_PREFIX, + -proc_width, proc_width, pname); + strcat_to_buf (string, status_size, buf); + } + + if (line_width > 0) + { + sprintf (buf, "%s%*.*s ", LINE_PREFIX, + -line_width, line_width, line_buf); + strcat_to_buf (string, status_size, buf); + } + if (pc_width > 0) + { + strcat_to_buf (string, status_size, PC_PREFIX); + strcat_to_buf (string, status_size, pc_buf); + } + + + for (i = strlen (string); i < status_size; i++) + string[i] = ' '; + string[status_size] = (char) 0; + + ui_file_delete (pc_out); + return string; +} + +/* Get a printable name for the function at the address. + The symbol name is demangled if demangling is turned on. + Returns a pointer to a static area holding the result. */ +static char* +tui_get_function_from_frame (struct frame_info *fi) +{ + static char name[256]; + struct ui_file *stream = tui_sfileopen (256); + char *p; + + print_address_symbolic (get_frame_pc (fi), stream, demangle, ""); + p = tui_file_get_strbuf (stream); + + /* Use simple heuristics to isolate the function name. The symbol can + be demangled and we can have function parameters. Remove them because + the status line is too short to display them. */ + if (*p == '<') + p++; + strncpy (name, p, sizeof (name)); + p = strchr (name, '('); + if (!p) + p = strchr (name, '>'); + if (p) + *p = 0; + p = strchr (name, '+'); + if (p) + *p = 0; + ui_file_delete (stream); + return name; +} + +void +tui_show_locator_content (void) +{ + char *string; + struct tui_gen_win_info * locator; + + locator = tui_locator_win_info_ptr (); + + if (locator != NULL && locator->handle != (WINDOW *) NULL) + { + struct tui_win_element * element; + + element = (struct tui_win_element *) locator->content[0]; + + string = tui_make_status_line (&element->which_element.locator); + wmove (locator->handle, 0, 0); + wstandout (locator->handle); + waddstr (locator->handle, string); + wclrtoeol (locator->handle); + wstandend (locator->handle); + tui_refresh_win (locator); + wmove (locator->handle, 0, 0); + xfree (string); + locator->content_in_use = TRUE; + } +} + + +/* Set the filename portion of the locator. */ +static void +tui_set_locator_filename (const char *filename) +{ + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + struct tui_locator_element * element; + + if (locator->content[0] == NULL) + { + tui_set_locator_info (filename, NULL, 0, 0); + return; + } + + element = &((struct tui_win_element *) locator->content[0])->which_element.locator; + element->file_name[0] = 0; + strcat_to_buf (element->file_name, MAX_LOCATOR_ELEMENT_LEN, filename); +} + +/* Update the locator, with the provided arguments. */ +static void +tui_set_locator_info (const char *filename, const char *procname, int lineno, + CORE_ADDR addr) +{ + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + struct tui_locator_element * element; + + /* Allocate the locator content if necessary. */ + if (locator->content_size <= 0) + { + locator->content = (void **) tui_alloc_content (1, locator->type); + locator->content_size = 1; + } + + element = &((struct tui_win_element *) locator->content[0])->which_element.locator; + element->proc_name[0] = (char) 0; + strcat_to_buf (element->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname); + element->line_no = lineno; + element->addr = addr; + tui_set_locator_filename (filename); +} + +/* Update only the filename portion of the locator. */ +void +tui_update_locator_filename (const char *filename) +{ + tui_set_locator_filename (filename); + tui_show_locator_content (); +} + +/* Function to print the frame information for the TUI. */ +void +tui_show_frame_info (struct frame_info *fi) +{ + struct tui_win_info * win_info; + int i; + + if (fi) + { + int start_line, i; + CORE_ADDR low; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + int source_already_displayed; + struct symtab_and_line sal; + + find_frame_sal (fi, &sal); + + source_already_displayed = sal.symtab != 0 + && tui_source_is_displayed (sal.symtab->filename); + tui_set_locator_info (sal.symtab == 0 ? "??" : sal.symtab->filename, + tui_get_function_from_frame (fi), + sal.line, + get_frame_pc (fi)); + tui_show_locator_content (); + start_line = 0; + for (i = 0; i < (tui_source_windows ())->count; i++) + { + union tui_which_element *item; + win_info = (struct tui_win_info *) (tui_source_windows ())->list[i]; + + item = &((struct tui_win_element *) locator->content[0])->which_element; + if (win_info == TUI_SRC_WIN) + { + start_line = (item->locator.line_no - + (win_info->generic.viewport_height / 2)) + 1; + if (start_line <= 0) + start_line = 1; + } + else + { + if (find_pc_partial_function (get_frame_pc (fi), (char **) NULL, + &low, (CORE_ADDR) NULL) == 0) + error ("No function contains program counter for selected frame.\n"); + else + low = tui_get_low_disassembly_address (low, get_frame_pc (fi)); + } + + if (win_info == TUI_SRC_WIN) + { + union tui_line_or_address l; + l.line_no = start_line; + if (!(source_already_displayed + && tui_line_is_displayed (item->locator.line_no, win_info, TRUE))) + tui_update_source_window (win_info, sal.symtab, l, TRUE); + else + { + l.line_no = item->locator.line_no; + tui_set_is_exec_point_at (l, win_info); + } + } + else + { + if (win_info == TUI_DISASM_WIN) + { + union tui_line_or_address a; + a.addr = low; + if (!tui_addr_is_displayed (item->locator.addr, win_info, TRUE)) + tui_update_source_window (win_info, sal.symtab, a, TRUE); + else + { + a.addr = item->locator.addr; + tui_set_is_exec_point_at (a, win_info); + } + } + } + tui_update_exec_info (win_info); + } + } + else + { + tui_set_locator_info (NULL, NULL, 0, (CORE_ADDR) 0); + tui_show_locator_content (); + for (i = 0; i < (tui_source_windows ())->count; i++) + { + win_info = (struct tui_win_info *) (tui_source_windows ())->list[i]; + tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT); + tui_update_exec_info (win_info); + } + } +} + +/* Function to initialize gdb commands, for tui window stack + manipulation. */ +void +_initialize_tui_stack (void) +{ + add_com ("update", class_tui, tui_update_command, + "Update the source window and locator to display the current " + "execution point.\n"); +} + +/* Command to update the display with the current execution point. */ +static void +tui_update_command (char *arg, int from_tty) +{ + char cmd[sizeof("frame 0")]; + + strcpy (cmd, "frame 0"); + execute_command (cmd, from_tty); +} diff --git a/gdb/tui/tui-stack.h b/gdb/tui/tui-stack.h new file mode 100644 index 00000000000..65725b3fd2f --- /dev/null +++ b/gdb/tui/tui-stack.h @@ -0,0 +1,34 @@ +/* TUI display locator. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_STACK_H +#define TUI_STACK_H + +struct frame_info; + +extern void tui_update_locator_filename (const char *); +extern void tui_show_locator_content (void); +extern void tui_show_frame_info (struct frame_info *); + +#endif diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c new file mode 100644 index 00000000000..3950a7ca4ce --- /dev/null +++ b/gdb/tui/tui-win.c @@ -0,0 +1,1511 @@ +/* TUI window generic functions. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + 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. */ + +/* This module contains procedures for handling tui window functions + like resize, scrolling, scrolling, changing focus, etc. + + Author: Susan B. Macchia */ + +#include "defs.h" +#include "command.h" +#include "symtab.h" +#include "breakpoint.h" +#include "frame.h" +#include "cli/cli-cmds.h" +#include "top.h" +#include "source.h" + +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-stack.h" +#include "tui/tui-regs.h" +#include "tui/tui-disasm.h" +#include "tui/tui-source.h" +#include "tui/tui-winsource.h" +#include "tui/tui-windata.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +#include "gdb_string.h" +#include +#include + +/******************************* +** Static Local Decls +********************************/ +static void make_visible_with_new_height (struct tui_win_info *); +static void make_invisible_and_set_new_height (struct tui_win_info *, int); +static enum tui_status tui_adjust_win_heights (struct tui_win_info *, int); +static int new_height_ok (struct tui_win_info *, int); +static void tui_set_tab_width_command (char *, int); +static void tui_refresh_all_command (char *, int); +static void tui_set_win_height_command (char *, int); +static void tui_xdb_set_win_height_command (char *, int); +static void tui_all_windows_info (char *, int); +static void tui_set_focus_command (char *, int); +static void tui_scroll_forward_command (char *, int); +static void tui_scroll_backward_command (char *, int); +static void tui_scroll_left_command (char *, int); +static void tui_scroll_right_command (char *, int); +static void parse_scrolling_args (char *, struct tui_win_info * *, int *); + + +/*************************************** +** DEFINITIONS +***************************************/ +#define WIN_HEIGHT_USAGE "Usage: winheight [+ | -] <#lines>\n" +#define XDBWIN_HEIGHT_USAGE "Usage: w <#lines>\n" +#define FOCUS_USAGE "Usage: focus { | next | prev}\n" + +/*************************************** +** PUBLIC FUNCTIONS +***************************************/ + +#ifndef ACS_LRCORNER +# define ACS_LRCORNER '+' +#endif +#ifndef ACS_LLCORNER +# define ACS_LLCORNER '+' +#endif +#ifndef ACS_ULCORNER +# define ACS_ULCORNER '+' +#endif +#ifndef ACS_URCORNER +# define ACS_URCORNER '+' +#endif +#ifndef ACS_HLINE +# define ACS_HLINE '-' +#endif +#ifndef ACS_VLINE +# define ACS_VLINE '|' +#endif + +/* Possible values for tui-border-kind variable. */ +static const char *tui_border_kind_enums[] = { + "space", + "ascii", + "acs", + NULL +}; + +/* Possible values for tui-border-mode and tui-active-border-mode. */ +static const char *tui_border_mode_enums[] = { + "normal", + "standout", + "reverse", + "half", + "half-standout", + "bold", + "bold-standout", + NULL +}; + +struct tui_translate +{ + const char *name; + int value; +}; + +/* Translation table for border-mode variables. + The list of values must be terminated by a NULL. + After the NULL value, an entry defines the default. */ +struct tui_translate tui_border_mode_translate[] = { + { "normal", A_NORMAL }, + { "standout", A_STANDOUT }, + { "reverse", A_REVERSE }, + { "half", A_DIM }, + { "half-standout", A_DIM | A_STANDOUT }, + { "bold", A_BOLD }, + { "bold-standout", A_BOLD | A_STANDOUT }, + { 0, 0 }, + { "normal", A_NORMAL } +}; + +/* Translation tables for border-kind, one for each border + character (see wborder, border curses operations). + -1 is used to indicate the ACS because ACS characters + are determined at run time by curses (depends on terminal). */ +struct tui_translate tui_border_kind_translate_vline[] = { + { "space", ' ' }, + { "ascii", '|' }, + { "acs", -1 }, + { 0, 0 }, + { "ascii", '|' } +}; + +struct tui_translate tui_border_kind_translate_hline[] = { + { "space", ' ' }, + { "ascii", '-' }, + { "acs", -1 }, + { 0, 0 }, + { "ascii", '-' } +}; + +struct tui_translate tui_border_kind_translate_ulcorner[] = { + { "space", ' ' }, + { "ascii", '+' }, + { "acs", -1 }, + { 0, 0 }, + { "ascii", '+' } +}; + +struct tui_translate tui_border_kind_translate_urcorner[] = { + { "space", ' ' }, + { "ascii", '+' }, + { "acs", -1 }, + { 0, 0 }, + { "ascii", '+' } +}; + +struct tui_translate tui_border_kind_translate_llcorner[] = { + { "space", ' ' }, + { "ascii", '+' }, + { "acs", -1 }, + { 0, 0 }, + { "ascii", '+' } +}; + +struct tui_translate tui_border_kind_translate_lrcorner[] = { + { "space", ' ' }, + { "ascii", '+' }, + { "acs", -1 }, + { 0, 0 }, + { "ascii", '+' } +}; + + +/* Tui configuration variables controlled with set/show command. */ +const char *tui_active_border_mode = "bold-standout"; +const char *tui_border_mode = "normal"; +const char *tui_border_kind = "acs"; + +/* Tui internal configuration variables. These variables are + updated by tui_update_variables to reflect the tui configuration + variables. */ +chtype tui_border_vline; +chtype tui_border_hline; +chtype tui_border_ulcorner; +chtype tui_border_urcorner; +chtype tui_border_llcorner; +chtype tui_border_lrcorner; + +int tui_border_attrs; +int tui_active_border_attrs; + +/* Identify the item in the translation table. + When the item is not recognized, use the default entry. */ +static struct tui_translate * +translate (const char *name, struct tui_translate *table) +{ + while (table->name) + { + if (name && strcmp (table->name, name) == 0) + return table; + table++; + } + + /* Not found, return default entry. */ + table++; + return table; +} + +/* Update the tui internal configuration according to gdb settings. + Returns 1 if the configuration has changed and the screen should + be redrawn. */ +int +tui_update_variables (void) +{ + int need_redraw = 0; + struct tui_translate *entry; + + entry = translate (tui_border_mode, tui_border_mode_translate); + if (tui_border_attrs != entry->value) + { + tui_border_attrs = entry->value; + need_redraw = 1; + } + entry = translate (tui_active_border_mode, tui_border_mode_translate); + if (tui_active_border_attrs != entry->value) + { + tui_active_border_attrs = entry->value; + need_redraw = 1; + } + + /* If one corner changes, all characters are changed. + Only check the first one. The ACS characters are determined at + run time by curses terminal management. */ + entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner); + if (tui_border_lrcorner != (chtype) entry->value) + { + tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value; + need_redraw = 1; + } + entry = translate (tui_border_kind, tui_border_kind_translate_llcorner); + tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value; + + entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner); + tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value; + + entry = translate (tui_border_kind, tui_border_kind_translate_urcorner); + tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value; + + entry = translate (tui_border_kind, tui_border_kind_translate_hline); + tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value; + + entry = translate (tui_border_kind, tui_border_kind_translate_vline); + tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value; + + return need_redraw; +} + +static void +set_tui_cmd (char *args, int from_tty) +{ +} + +static void +show_tui_cmd (char *args, int from_tty) +{ +} + +/* Function to initialize gdb commands, for tui window manipulation. */ +void +_initialize_tui_win (void) +{ + struct cmd_list_element *c; + static struct cmd_list_element *tui_setlist; + static struct cmd_list_element *tui_showlist; + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + add_cmd ("tui", class_tui, NULL, + "Text User Interface commands.", + &cmdlist); + + add_prefix_cmd ("tui", class_tui, set_tui_cmd, + "TUI configuration variables", + &tui_setlist, "set tui ", + 0/*allow-unknown*/, &setlist); + add_prefix_cmd ("tui", class_tui, show_tui_cmd, + "TUI configuration variables", + &tui_showlist, "show tui ", + 0/*allow-unknown*/, &showlist); + + add_com ("refresh", class_tui, tui_refresh_all_command, + "Refresh the terminal display.\n"); + if (xdb_commands) + add_com_alias ("U", "refresh", class_tui, 0); + add_com ("tabset", class_tui, tui_set_tab_width_command, + "Set the width (in characters) of tab stops.\n\ +Usage: tabset \n"); + add_com ("winheight", class_tui, tui_set_win_height_command, + "Set the height of a specified window.\n\ +Usage: winheight [+ | -] <#lines>\n\ +Window names are:\n\ +src : the source window\n\ +cmd : the command window\n\ +asm : the disassembly window\n\ +regs : the register display\n"); + add_com_alias ("wh", "winheight", class_tui, 0); + add_info ("win", tui_all_windows_info, + "List of all displayed windows.\n"); + add_com ("focus", class_tui, tui_set_focus_command, + "Set focus to named window or next/prev window.\n\ +Usage: focus { | next | prev}\n\ +Valid Window names are:\n\ +src : the source window\n\ +asm : the disassembly window\n\ +regs : the register display\n\ +cmd : the command window\n"); + add_com_alias ("fs", "focus", class_tui, 0); + add_com ("+", class_tui, tui_scroll_forward_command, + "Scroll window forward.\nUsage: + [win] [n]\n"); + add_com ("-", class_tui, tui_scroll_backward_command, + "Scroll window backward.\nUsage: - [win] [n]\n"); + add_com ("<", class_tui, tui_scroll_left_command, + "Scroll window forward.\nUsage: < [win] [n]\n"); + add_com (">", class_tui, tui_scroll_right_command, + "Scroll window backward.\nUsage: > [win] [n]\n"); + if (xdb_commands) + add_com ("w", class_xdb, tui_xdb_set_win_height_command, + "XDB compatibility command for setting the height of a command window.\n\ +Usage: w <#lines>\n"); + + /* Define the tui control variables. */ + c = add_set_enum_cmd + ("border-kind", no_class, + tui_border_kind_enums, &tui_border_kind, + "Set the kind of border for TUI windows.\n" + "This variable controls the border of TUI windows:\n" + "space use a white space\n" + "ascii use ascii characters + - | for the border\n" + "acs use the Alternate Character Set\n", + &tui_setlist); + add_show_from_set (c, &tui_showlist); + + c = add_set_enum_cmd + ("border-mode", no_class, + tui_border_mode_enums, &tui_border_mode, + "Set the attribute mode to use for the TUI window borders.\n" + "This variable controls the attributes to use for the window borders:\n" + "normal normal display\n" + "standout use highlight mode of terminal\n" + "reverse use reverse video mode\n" + "half use half bright\n" + "half-standout use half bright and standout mode\n" + "bold use extra bright or bold\n" + "bold-standout use extra bright or bold with standout mode\n", + &tui_setlist); + add_show_from_set (c, &tui_showlist); + + c = add_set_enum_cmd + ("active-border-mode", no_class, + tui_border_mode_enums, &tui_active_border_mode, + "Set the attribute mode to use for the active TUI window border.\n" + "This variable controls the attributes to use for the active window border:\n" + "normal normal display\n" + "standout use highlight mode of terminal\n" + "reverse use reverse video mode\n" + "half use half bright\n" + "half-standout use half bright and standout mode\n" + "bold use extra bright or bold\n" + "bold-standout use extra bright or bold with standout mode\n", + &tui_setlist); + add_show_from_set (c, &tui_showlist); +} + +/* Update gdb's knowledge of the terminal size. */ +void +tui_update_gdb_sizes (void) +{ + char cmd[50]; + int screenheight, screenwidth; + + rl_get_screen_size (&screenheight, &screenwidth); + /* Set to TUI command window dimension or use readline values. */ + sprintf (cmd, "set width %d", + tui_active ? TUI_CMD_WIN->generic.width : screenwidth); + execute_command (cmd, 0); + sprintf (cmd, "set height %d", + tui_active ? TUI_CMD_WIN->generic.height : screenheight); + execute_command (cmd, 0); +} + + +/* Set the logical focus to win_info. */ +void +tui_set_win_focus_to (struct tui_win_info * win_info) +{ + if (win_info != NULL) + { + struct tui_win_info * win_with_focus = tui_win_with_focus (); + + if (win_with_focus != NULL + && win_with_focus->generic.type != CMD_WIN) + tui_unhighlight_win (win_with_focus); + tui_set_win_with_focus (win_info); + if (win_info->generic.type != CMD_WIN) + tui_highlight_win (win_info); + } +} + + +void +tui_scroll_forward (struct tui_win_info * win_to_scroll, int num_to_scroll) +{ + if (win_to_scroll != TUI_CMD_WIN) + { + int _num_to_scroll = num_to_scroll; + + if (num_to_scroll == 0) + _num_to_scroll = win_to_scroll->generic.height - 3; + /* + ** If we are scrolling the source or disassembly window, do a + ** "psuedo" scroll since not all of the source is in memory, + ** only what is in the viewport. If win_to_scroll is the + ** command window do nothing since the term should handle it. + */ + if (win_to_scroll == TUI_SRC_WIN) + tui_vertical_source_scroll (FORWARD_SCROLL, _num_to_scroll); + else if (win_to_scroll == TUI_DISASM_WIN) + tui_vertical_disassem_scroll (FORWARD_SCROLL, _num_to_scroll); + else if (win_to_scroll == TUI_DATA_WIN) + tui_vertical_data_scroll (FORWARD_SCROLL, _num_to_scroll); + } +} + +void +tui_scroll_backward (struct tui_win_info * win_to_scroll, int num_to_scroll) +{ + if (win_to_scroll != TUI_CMD_WIN) + { + int _num_to_scroll = num_to_scroll; + + if (num_to_scroll == 0) + _num_to_scroll = win_to_scroll->generic.height - 3; + /* + ** If we are scrolling the source or disassembly window, do a + ** "psuedo" scroll since not all of the source is in memory, + ** only what is in the viewport. If win_to_scroll is the + ** command window do nothing since the term should handle it. + */ + if (win_to_scroll == TUI_SRC_WIN) + tui_vertical_source_scroll (BACKWARD_SCROLL, _num_to_scroll); + else if (win_to_scroll == TUI_DISASM_WIN) + tui_vertical_disassem_scroll (BACKWARD_SCROLL, _num_to_scroll); + else if (win_to_scroll == TUI_DATA_WIN) + tui_vertical_data_scroll (BACKWARD_SCROLL, _num_to_scroll); + } +} + + +void +tui_scroll_left (struct tui_win_info * win_to_scroll, int num_to_scroll) +{ + if (win_to_scroll != TUI_CMD_WIN) + { + int _num_to_scroll = num_to_scroll; + + if (_num_to_scroll == 0) + _num_to_scroll = 1; + /* + ** If we are scrolling the source or disassembly window, do a + ** "psuedo" scroll since not all of the source is in memory, + ** only what is in the viewport. If win_to_scroll is the + ** command window do nothing since the term should handle it. + */ + if (win_to_scroll == TUI_SRC_WIN || win_to_scroll == TUI_DISASM_WIN) + tui_horizontal_source_scroll (win_to_scroll, LEFT_SCROLL, _num_to_scroll); + } +} + + +void +tui_scroll_right (struct tui_win_info * win_to_scroll, int num_to_scroll) +{ + if (win_to_scroll != TUI_CMD_WIN) + { + int _num_to_scroll = num_to_scroll; + + if (_num_to_scroll == 0) + _num_to_scroll = 1; + /* + ** If we are scrolling the source or disassembly window, do a + ** "psuedo" scroll since not all of the source is in memory, + ** only what is in the viewport. If win_to_scroll is the + ** command window do nothing since the term should handle it. + */ + if (win_to_scroll == TUI_SRC_WIN || win_to_scroll == TUI_DISASM_WIN) + tui_horizontal_source_scroll (win_to_scroll, RIGHT_SCROLL, _num_to_scroll); + } +} + + +/* Scroll a window. Arguments are passed through a va_list. */ +void +tui_scroll (enum tui_scroll_direction direction, + struct tui_win_info * win_to_scroll, + int num_to_scroll) +{ + switch (direction) + { + case FORWARD_SCROLL: + tui_scroll_forward (win_to_scroll, num_to_scroll); + break; + case BACKWARD_SCROLL: + tui_scroll_backward (win_to_scroll, num_to_scroll); + break; + case LEFT_SCROLL: + tui_scroll_left (win_to_scroll, num_to_scroll); + break; + case RIGHT_SCROLL: + tui_scroll_right (win_to_scroll, num_to_scroll); + break; + default: + break; + } +} + + +void +tui_refresh_all_win (void) +{ + enum tui_win_type type; + + clearok (curscr, TRUE); + tui_refresh_all (tui_win_list); + for (type = SRC_WIN; type < MAX_MAJOR_WINDOWS; type++) + { + if (tui_win_list[type] && tui_win_list[type]->generic.is_visible) + { + switch (type) + { + case SRC_WIN: + case DISASSEM_WIN: + tui_show_source_content (tui_win_list[type]); + tui_check_and_display_highlight_if_needed (tui_win_list[type]); + tui_erase_exec_info_content (tui_win_list[type]); + tui_update_exec_info (tui_win_list[type]); + break; + case DATA_WIN: + tui_refresh_data_win (); + break; + default: + break; + } + } + } + tui_show_locator_content (); +} + + +/* Resize all the windows based on the the terminal size. This + function gets called from within the readline sinwinch handler. */ +void +tui_resize_all (void) +{ + int height_diff, width_diff; + int screenheight, screenwidth; + + rl_get_screen_size (&screenheight, &screenwidth); + width_diff = screenwidth - tui_term_width (); + height_diff = screenheight - tui_term_height (); + if (height_diff || width_diff) + { + enum tui_layout_type cur_layout = tui_current_layout (); + struct tui_win_info * win_with_focus = tui_win_with_focus (); + struct tui_win_info *first_win; + struct tui_win_info *second_win; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + enum tui_win_type win_type; + int new_height, split_diff, cmd_split_diff, num_wins_displayed = 2; + + /* turn keypad off while we resize */ + if (win_with_focus != TUI_CMD_WIN) + keypad (TUI_CMD_WIN->generic.handle, FALSE); + tui_update_gdb_sizes (); + tui_set_term_height_to (screenheight); + tui_set_term_width_to (screenwidth); + if (cur_layout == SRC_DISASSEM_COMMAND || + cur_layout == SRC_DATA_COMMAND || cur_layout == DISASSEM_DATA_COMMAND) + num_wins_displayed++; + split_diff = height_diff / num_wins_displayed; + cmd_split_diff = split_diff; + if (height_diff % num_wins_displayed) + { + if (height_diff < 0) + cmd_split_diff--; + else + cmd_split_diff++; + } + /* now adjust each window */ + clear (); + refresh (); + switch (cur_layout) + { + case SRC_COMMAND: + case DISASSEM_COMMAND: + first_win = (struct tui_win_info *) (tui_source_windows ())->list[0]; + first_win->generic.width += width_diff; + locator->width += width_diff; + /* check for invalid heights */ + if (height_diff == 0) + new_height = first_win->generic.height; + else if ((first_win->generic.height + split_diff) >= + (screenheight - MIN_CMD_WIN_HEIGHT - 1)) + new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1; + else if ((first_win->generic.height + split_diff) <= 0) + new_height = MIN_WIN_HEIGHT; + else + new_height = first_win->generic.height + split_diff; + + make_invisible_and_set_new_height (first_win, new_height); + TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1; + TUI_CMD_WIN->generic.width += width_diff; + new_height = screenheight - TUI_CMD_WIN->generic.origin.y; + make_invisible_and_set_new_height (TUI_CMD_WIN, new_height); + make_visible_with_new_height (first_win); + make_visible_with_new_height (TUI_CMD_WIN); + if (first_win->generic.content_size <= 0) + tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT); + break; + default: + if (cur_layout == SRC_DISASSEM_COMMAND) + { + first_win = TUI_SRC_WIN; + first_win->generic.width += width_diff; + second_win = TUI_DISASM_WIN; + second_win->generic.width += width_diff; + } + else + { + first_win = TUI_DATA_WIN; + first_win->generic.width += width_diff; + second_win = (struct tui_win_info *) (tui_source_windows ())->list[0]; + second_win->generic.width += width_diff; + } + /* Change the first window's height/width */ + /* check for invalid heights */ + if (height_diff == 0) + new_height = first_win->generic.height; + else if ((first_win->generic.height + + second_win->generic.height + (split_diff * 2)) >= + (screenheight - MIN_CMD_WIN_HEIGHT - 1)) + new_height = (screenheight - MIN_CMD_WIN_HEIGHT - 1) / 2; + else if ((first_win->generic.height + split_diff) <= 0) + new_height = MIN_WIN_HEIGHT; + else + new_height = first_win->generic.height + split_diff; + make_invisible_and_set_new_height (first_win, new_height); + + if (first_win == TUI_DATA_WIN && width_diff != 0) + first_win->detail.data_display_info.regs_column_count = + tui_calculate_regs_column_count ( + first_win->detail.data_display_info.regs_display_type); + locator->width += width_diff; + + /* Change the second window's height/width */ + /* check for invalid heights */ + if (height_diff == 0) + new_height = second_win->generic.height; + else if ((first_win->generic.height + + second_win->generic.height + (split_diff * 2)) >= + (screenheight - MIN_CMD_WIN_HEIGHT - 1)) + { + new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1; + if (new_height % 2) + new_height = (new_height / 2) + 1; + else + new_height /= 2; + } + else if ((second_win->generic.height + split_diff) <= 0) + new_height = MIN_WIN_HEIGHT; + else + new_height = second_win->generic.height + split_diff; + second_win->generic.origin.y = first_win->generic.height - 1; + make_invisible_and_set_new_height (second_win, new_height); + + /* Change the command window's height/width */ + TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1; + make_invisible_and_set_new_height ( + TUI_CMD_WIN, TUI_CMD_WIN->generic.height + cmd_split_diff); + make_visible_with_new_height (first_win); + make_visible_with_new_height (second_win); + make_visible_with_new_height (TUI_CMD_WIN); + if (first_win->generic.content_size <= 0) + tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT); + if (second_win->generic.content_size <= 0) + tui_erase_source_content (second_win, EMPTY_SOURCE_PROMPT); + break; + } + /* + ** Now remove all invisible windows, and their content so that they get + ** created again when called for with the new size + */ + for (win_type = SRC_WIN; (win_type < MAX_MAJOR_WINDOWS); win_type++) + { + if (win_type != CMD_WIN && (tui_win_list[win_type] != NULL) + && !tui_win_list[win_type]->generic.is_visible) + { + tui_free_window (tui_win_list[win_type]); + tui_win_list[win_type] = (struct tui_win_info *) NULL; + } + } + tui_set_win_resized_to (TRUE); + /* turn keypad back on, unless focus is in the command window */ + if (win_with_focus != TUI_CMD_WIN) + keypad (TUI_CMD_WIN->generic.handle, TRUE); + } +} + + +/* SIGWINCH signal handler for the tui. This signal handler is always + called, even when the readline package clears signals because it is + set as the old_sigwinch() (TUI only). */ +void +tui_sigwinch_handler (int signal) +{ + /* + ** Say that a resize was done so that the readline can do it + ** later when appropriate. + */ + tui_set_win_resized_to (TRUE); +} + + + +/************************* +** STATIC LOCAL FUNCTIONS +**************************/ + + +static void +tui_scroll_forward_command (char *arg, int from_tty) +{ + int num_to_scroll = 1; + struct tui_win_info * win_to_scroll; + + /* Make sure the curses mode is enabled. */ + tui_enable (); + if (arg == (char *) NULL) + parse_scrolling_args (arg, &win_to_scroll, (int *) NULL); + else + parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll); + tui_scroll (FORWARD_SCROLL, win_to_scroll, num_to_scroll); +} + + +static void +tui_scroll_backward_command (char *arg, int from_tty) +{ + int num_to_scroll = 1; + struct tui_win_info * win_to_scroll; + + /* Make sure the curses mode is enabled. */ + tui_enable (); + if (arg == (char *) NULL) + parse_scrolling_args (arg, &win_to_scroll, (int *) NULL); + else + parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll); + tui_scroll (BACKWARD_SCROLL, win_to_scroll, num_to_scroll); +} + + +static void +tui_scroll_left_command (char *arg, int from_tty) +{ + int num_to_scroll; + struct tui_win_info * win_to_scroll; + + /* Make sure the curses mode is enabled. */ + tui_enable (); + parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll); + tui_scroll (LEFT_SCROLL, win_to_scroll, num_to_scroll); +} + + +static void +tui_scroll_right_command (char *arg, int from_tty) +{ + int num_to_scroll; + struct tui_win_info * win_to_scroll; + + /* Make sure the curses mode is enabled. */ + tui_enable (); + parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll); + tui_scroll (RIGHT_SCROLL, win_to_scroll, num_to_scroll); +} + + +/* Set focus to the window named by 'arg'. */ +static void +tui_set_focus (char *arg, int from_tty) +{ + if (arg != (char *) NULL) + { + char *buf_ptr = (char *) xstrdup (arg); + int i; + struct tui_win_info * win_info = (struct tui_win_info *) NULL; + + for (i = 0; (i < strlen (buf_ptr)); i++) + buf_ptr[i] = toupper (arg[i]); + + if (subset_compare (buf_ptr, "NEXT")) + win_info = tui_next_win (tui_win_with_focus ()); + else if (subset_compare (buf_ptr, "PREV")) + win_info = tui_prev_win (tui_win_with_focus ()); + else + win_info = tui_partial_win_by_name (buf_ptr); + + if (win_info == (struct tui_win_info *) NULL || !win_info->generic.is_visible) + warning ("Invalid window specified. \n\ +The window name specified must be valid and visible.\n"); + else + { + tui_set_win_focus_to (win_info); + keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN)); + } + + if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible) + tui_refresh_data_win (); + xfree (buf_ptr); + printf_filtered ("Focus set to %s window.\n", + tui_win_name ((struct tui_gen_win_info *) tui_win_with_focus ())); + } + else + warning ("Incorrect Number of Arguments.\n%s", FOCUS_USAGE); +} + +static void +tui_set_focus_command (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + tui_set_focus (arg, from_tty); +} + + +static void +tui_all_windows_info (char *arg, int from_tty) +{ + enum tui_win_type type; + struct tui_win_info * win_with_focus = tui_win_with_focus (); + + for (type = SRC_WIN; (type < MAX_MAJOR_WINDOWS); type++) + if (tui_win_list[type] && tui_win_list[type]->generic.is_visible) + { + if (win_with_focus == tui_win_list[type]) + printf_filtered (" %s\t(%d lines) \n", + tui_win_name (&tui_win_list[type]->generic), + tui_win_list[type]->generic.height); + else + printf_filtered (" %s\t(%d lines)\n", + tui_win_name (&tui_win_list[type]->generic), + tui_win_list[type]->generic.height); + } +} + + +static void +tui_refresh_all_command (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + + tui_refresh_all_win (); +} + + +/* Set the height of the specified window. */ +static void +tui_set_tab_width_command (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + if (arg != (char *) NULL) + { + int ts; + + ts = atoi (arg); + if (ts > 0) + tui_set_default_tab_len (ts); + else + warning ("Tab widths greater than 0 must be specified.\n"); + } +} + + +/* Set the height of the specified window. */ +static void +tui_set_win_height (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + if (arg != (char *) NULL) + { + char *buf = xstrdup (arg); + char *buf_ptr = buf; + char *wname = (char *) NULL; + int new_height, i; + struct tui_win_info * win_info; + + wname = buf_ptr; + buf_ptr = strchr (buf_ptr, ' '); + if (buf_ptr != (char *) NULL) + { + *buf_ptr = (char) 0; + + /* + ** Validate the window name + */ + for (i = 0; i < strlen (wname); i++) + wname[i] = toupper (wname[i]); + win_info = tui_partial_win_by_name (wname); + + if (win_info == (struct tui_win_info *) NULL || !win_info->generic.is_visible) + warning ("Invalid window specified. \n\ +The window name specified must be valid and visible.\n"); + else + { + /* Process the size */ + while (*(++buf_ptr) == ' ') + ; + + if (*buf_ptr != (char) 0) + { + int negate = FALSE; + int fixed_size = TRUE; + int input_no;; + + if (*buf_ptr == '+' || *buf_ptr == '-') + { + if (*buf_ptr == '-') + negate = TRUE; + fixed_size = FALSE; + buf_ptr++; + } + input_no = atoi (buf_ptr); + if (input_no > 0) + { + if (negate) + input_no *= (-1); + if (fixed_size) + new_height = input_no; + else + new_height = win_info->generic.height + input_no; + /* + ** Now change the window's height, and adjust all + ** other windows around it + */ + if (tui_adjust_win_heights (win_info, + new_height) == TUI_FAILURE) + warning ("Invalid window height specified.\n%s", + WIN_HEIGHT_USAGE); + else + tui_update_gdb_sizes (); + } + else + warning ("Invalid window height specified.\n%s", + WIN_HEIGHT_USAGE); + } + } + } + else + printf_filtered (WIN_HEIGHT_USAGE); + + if (buf != (char *) NULL) + xfree (buf); + } + else + printf_filtered (WIN_HEIGHT_USAGE); +} + +/* Set the height of the specified window, with va_list. */ +static void +tui_set_win_height_command (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + tui_set_win_height (arg, from_tty); +} + + +/* XDB Compatibility command for setting the window height. This will + increase or decrease the command window by the specified amount. */ +static void +tui_xdb_set_win_height (char *arg, int from_tty) +{ + /* Make sure the curses mode is enabled. */ + tui_enable (); + if (arg != (char *) NULL) + { + int input_no = atoi (arg); + + if (input_no > 0) + { /* Add 1 for the locator */ + int new_height = tui_term_height () - (input_no + 1); + + if (!new_height_ok (tui_win_list[CMD_WIN], new_height) || + tui_adjust_win_heights (tui_win_list[CMD_WIN], + new_height) == TUI_FAILURE) + warning ("Invalid window height specified.\n%s", + XDBWIN_HEIGHT_USAGE); + } + else + warning ("Invalid window height specified.\n%s", + XDBWIN_HEIGHT_USAGE); + } + else + warning ("Invalid window height specified.\n%s", XDBWIN_HEIGHT_USAGE); +} + +/* Set the height of the specified window, with va_list. */ +static void +tui_xdb_set_win_height_command (char *arg, int from_tty) +{ + tui_xdb_set_win_height (arg, from_tty); +} + + +/* Function to adjust all window heights around the primary. */ +static enum tui_status +tui_adjust_win_heights (struct tui_win_info * primary_win_info, int new_height) +{ + enum tui_status status = TUI_FAILURE; + + if (new_height_ok (primary_win_info, new_height)) + { + status = TUI_SUCCESS; + if (new_height != primary_win_info->generic.height) + { + int diff; + struct tui_win_info * win_info; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + enum tui_layout_type cur_layout = tui_current_layout (); + + diff = (new_height - primary_win_info->generic.height) * (-1); + if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND) + { + struct tui_win_info * src_win_info; + + make_invisible_and_set_new_height (primary_win_info, new_height); + if (primary_win_info->generic.type == CMD_WIN) + { + win_info = (struct tui_win_info *) (tui_source_windows ())->list[0]; + src_win_info = win_info; + } + else + { + win_info = tui_win_list[CMD_WIN]; + src_win_info = primary_win_info; + } + make_invisible_and_set_new_height (win_info, + win_info->generic.height + diff); + TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1; + make_visible_with_new_height (win_info); + make_visible_with_new_height (primary_win_info); + if (src_win_info->generic.content_size <= 0) + tui_erase_source_content (src_win_info, EMPTY_SOURCE_PROMPT); + } + else + { + struct tui_win_info *first_win; + struct tui_win_info *second_win; + + if (cur_layout == SRC_DISASSEM_COMMAND) + { + first_win = TUI_SRC_WIN; + second_win = TUI_DISASM_WIN; + } + else + { + first_win = TUI_DATA_WIN; + second_win = (struct tui_win_info *) (tui_source_windows ())->list[0]; + } + if (primary_win_info == TUI_CMD_WIN) + { /* + ** Split the change in height accross the 1st & 2nd windows + ** adjusting them as well. + */ + int first_split_diff = diff / 2; /* subtract the locator */ + int second_split_diff = first_split_diff; + + if (diff % 2) + { + if (first_win->generic.height > + second_win->generic.height) + if (diff < 0) + first_split_diff--; + else + first_split_diff++; + else + { + if (diff < 0) + second_split_diff--; + else + second_split_diff++; + } + } + /* make sure that the minimum hieghts are honored */ + while ((first_win->generic.height + first_split_diff) < 3) + { + first_split_diff++; + second_split_diff--; + } + while ((second_win->generic.height + second_split_diff) < 3) + { + second_split_diff++; + first_split_diff--; + } + make_invisible_and_set_new_height ( + first_win, + first_win->generic.height + first_split_diff); + second_win->generic.origin.y = first_win->generic.height - 1; + make_invisible_and_set_new_height ( + second_win, second_win->generic.height + second_split_diff); + TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1; + make_invisible_and_set_new_height (TUI_CMD_WIN, new_height); + } + else + { + if ((TUI_CMD_WIN->generic.height + diff) < 1) + { /* + ** If there is no way to increase the command window + ** take real estate from the 1st or 2nd window. + */ + if ((TUI_CMD_WIN->generic.height + diff) < 1) + { + int i; + for (i = TUI_CMD_WIN->generic.height + diff; + (i < 1); i++) + if (primary_win_info == first_win) + second_win->generic.height--; + else + first_win->generic.height--; + } + } + if (primary_win_info == first_win) + make_invisible_and_set_new_height (first_win, new_height); + else + make_invisible_and_set_new_height ( + first_win, + first_win->generic.height); + second_win->generic.origin.y = first_win->generic.height - 1; + if (primary_win_info == second_win) + make_invisible_and_set_new_height (second_win, new_height); + else + make_invisible_and_set_new_height ( + second_win, second_win->generic.height); + TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1; + if ((TUI_CMD_WIN->generic.height + diff) < 1) + make_invisible_and_set_new_height (TUI_CMD_WIN, 1); + else + make_invisible_and_set_new_height ( + TUI_CMD_WIN, TUI_CMD_WIN->generic.height + diff); + } + make_visible_with_new_height (TUI_CMD_WIN); + make_visible_with_new_height (second_win); + make_visible_with_new_height (first_win); + if (first_win->generic.content_size <= 0) + tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT); + if (second_win->generic.content_size <= 0) + tui_erase_source_content (second_win, EMPTY_SOURCE_PROMPT); + } + } + } + + return status; +} + + +/* Function make the target window (and auxillary windows associated + with the targer) invisible, and set the new height and location. */ +static void +make_invisible_and_set_new_height (struct tui_win_info * win_info, int height) +{ + int i; + struct tui_gen_win_info * gen_win_info; + + tui_make_invisible (&win_info->generic); + win_info->generic.height = height; + if (height > 1) + win_info->generic.viewport_height = height - 1; + else + win_info->generic.viewport_height = height; + if (win_info != TUI_CMD_WIN) + win_info->generic.viewport_height--; + + /* Now deal with the auxillary windows associated with win_info */ + switch (win_info->generic.type) + { + case SRC_WIN: + case DISASSEM_WIN: + gen_win_info = win_info->detail.source_info.execution_info; + tui_make_invisible (gen_win_info); + gen_win_info->height = height; + gen_win_info->origin.y = win_info->generic.origin.y; + if (height > 1) + gen_win_info->viewport_height = height - 1; + else + gen_win_info->viewport_height = height; + if (win_info != TUI_CMD_WIN) + gen_win_info->viewport_height--; + + if (tui_win_has_locator (win_info)) + { + gen_win_info = tui_locator_win_info_ptr (); + tui_make_invisible (gen_win_info); + gen_win_info->origin.y = win_info->generic.origin.y + height; + } + break; + case DATA_WIN: + /* delete all data item windows */ + for (i = 0; i < win_info->generic.content_size; i++) + { + gen_win_info = (struct tui_gen_win_info *) & ((struct tui_win_element *) + win_info->generic.content[i])->which_element.data_window; + tui_delete_win (gen_win_info->handle); + gen_win_info->handle = (WINDOW *) NULL; + } + break; + default: + break; + } +} + + +/* Function to make the windows with new heights visible. This means + re-creating the windows' content since the window had to be + destroyed to be made invisible. */ +static void +make_visible_with_new_height (struct tui_win_info * win_info) +{ + struct symtab *s; + + tui_make_visible (&win_info->generic); + tui_check_and_display_highlight_if_needed (win_info); + switch (win_info->generic.type) + { + case SRC_WIN: + case DISASSEM_WIN: + tui_free_win_content (win_info->detail.source_info.execution_info); + tui_make_visible (win_info->detail.source_info.execution_info); + if (win_info->generic.content != NULL) + { + union tui_line_or_address line_or_addr; + struct symtab_and_line cursal + = get_current_source_symtab_and_line (); + + if (win_info->generic.type == SRC_WIN) + line_or_addr.line_no = + win_info->detail.source_info.start_line_or_addr.line_no; + else + line_or_addr.addr = + win_info->detail.source_info.start_line_or_addr.addr; + tui_free_win_content (&win_info->generic); + tui_update_source_window (win_info, cursal.symtab, line_or_addr, TRUE); + } + else if (deprecated_selected_frame != (struct frame_info *) NULL) + { + union tui_line_or_address line; + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + + + s = find_pc_symtab (get_frame_pc (deprecated_selected_frame)); + if (win_info->generic.type == SRC_WIN) + line.line_no = cursal.line; + else + { + find_line_pc (s, cursal.line, &line.addr); + } + tui_update_source_window (win_info, s, line, TRUE); + } + if (tui_win_has_locator (win_info)) + { + tui_make_visible (tui_locator_win_info_ptr ()); + tui_show_locator_content (); + } + break; + case DATA_WIN: + tui_display_all_data (); + break; + case CMD_WIN: + win_info->detail.command_info.cur_line = 0; + win_info->detail.command_info.curch = 0; + wmove (win_info->generic.handle, + win_info->detail.command_info.cur_line, + win_info->detail.command_info.curch); + break; + default: + break; + } +} + + +static int +new_height_ok (struct tui_win_info * primary_win_info, int new_height) +{ + int ok = (new_height < tui_term_height ()); + + if (ok) + { + int diff; + enum tui_layout_type cur_layout = tui_current_layout (); + + diff = (new_height - primary_win_info->generic.height) * (-1); + if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND) + { + ok = ((primary_win_info->generic.type == CMD_WIN && + new_height <= (tui_term_height () - 4) && + new_height >= MIN_CMD_WIN_HEIGHT) || + (primary_win_info->generic.type != CMD_WIN && + new_height <= (tui_term_height () - 2) && + new_height >= MIN_WIN_HEIGHT)); + if (ok) + { /* check the total height */ + struct tui_win_info * win_info; + + if (primary_win_info == TUI_CMD_WIN) + win_info = (struct tui_win_info *) (tui_source_windows ())->list[0]; + else + win_info = TUI_CMD_WIN; + ok = ((new_height + + (win_info->generic.height + diff)) <= tui_term_height ()); + } + } + else + { + int cur_total_height, total_height, min_height = 0; + struct tui_win_info *first_win; + struct tui_win_info *second_win; + + if (cur_layout == SRC_DISASSEM_COMMAND) + { + first_win = TUI_SRC_WIN; + second_win = TUI_DISASM_WIN; + } + else + { + first_win = TUI_DATA_WIN; + second_win = (struct tui_win_info *) (tui_source_windows ())->list[0]; + } + /* + ** We could simply add all the heights to obtain the same result + ** but below is more explicit since we subtract 1 for the + ** line that the first and second windows share, and add one + ** for the locator. + */ + total_height = cur_total_height = + (first_win->generic.height + second_win->generic.height - 1) + + TUI_CMD_WIN->generic.height + 1 /*locator */ ; + if (primary_win_info == TUI_CMD_WIN) + { + /* locator included since first & second win share a line */ + ok = ((first_win->generic.height + + second_win->generic.height + diff) >= + (MIN_WIN_HEIGHT * 2) && + new_height >= MIN_CMD_WIN_HEIGHT); + if (ok) + { + total_height = new_height + (first_win->generic.height + + second_win->generic.height + diff); + min_height = MIN_CMD_WIN_HEIGHT; + } + } + else + { + min_height = MIN_WIN_HEIGHT; + /* + ** First see if we can increase/decrease the command + ** window. And make sure that the command window is + ** at least 1 line + */ + ok = ((TUI_CMD_WIN->generic.height + diff) > 0); + if (!ok) + { /* + ** Looks like we have to increase/decrease one of + ** the other windows + */ + if (primary_win_info == first_win) + ok = (second_win->generic.height + diff) >= min_height; + else + ok = (first_win->generic.height + diff) >= min_height; + } + if (ok) + { + if (primary_win_info == first_win) + total_height = new_height + + second_win->generic.height + + TUI_CMD_WIN->generic.height + diff; + else + total_height = new_height + + first_win->generic.height + + TUI_CMD_WIN->generic.height + diff; + } + } + /* + ** Now make sure that the proposed total height doesn't exceed + ** the old total height. + */ + if (ok) + ok = (new_height >= min_height && total_height <= cur_total_height); + } + } + + return ok; +} + + +static void +parse_scrolling_args (char *arg, struct tui_win_info * * win_to_scroll, + int *num_to_scroll) +{ + if (num_to_scroll) + *num_to_scroll = 0; + *win_to_scroll = tui_win_with_focus (); + + /* + ** First set up the default window to scroll, in case there is no + ** window name arg + */ + if (arg != (char *) NULL) + { + char *buf, *buf_ptr; + + /* process the number of lines to scroll */ + buf = buf_ptr = xstrdup (arg); + if (isdigit (*buf_ptr)) + { + char *num_str; + + num_str = buf_ptr; + buf_ptr = strchr (buf_ptr, ' '); + if (buf_ptr != (char *) NULL) + { + *buf_ptr = (char) 0; + if (num_to_scroll) + *num_to_scroll = atoi (num_str); + buf_ptr++; + } + else if (num_to_scroll) + *num_to_scroll = atoi (num_str); + } + + /* process the window name if one is specified */ + if (buf_ptr != (char *) NULL) + { + char *wname; + int i; + + if (*buf_ptr == ' ') + while (*(++buf_ptr) == ' ') + ; + + if (*buf_ptr != (char) 0) + wname = buf_ptr; + else + wname = "?"; + + /* Validate the window name */ + for (i = 0; i < strlen (wname); i++) + wname[i] = toupper (wname[i]); + *win_to_scroll = tui_partial_win_by_name (wname); + + if (*win_to_scroll == (struct tui_win_info *) NULL || + !(*win_to_scroll)->generic.is_visible) + warning ("Invalid window specified. \n\ +The window name specified must be valid and visible.\n"); + else if (*win_to_scroll == TUI_CMD_WIN) + *win_to_scroll = (struct tui_win_info *) (tui_source_windows ())->list[0]; + } + xfree (buf); + } +} diff --git a/gdb/tui/tui-win.h b/gdb/tui/tui-win.h new file mode 100644 index 00000000000..b76998ca03d --- /dev/null +++ b/gdb/tui/tui-win.h @@ -0,0 +1,56 @@ +/* TUI window generic functions. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_WIN_H +#define TUI_WIN_H + +#include "tui/tui-data.h" + +struct tui_win_info; + +extern void tui_scroll_forward (struct tui_win_info *, int); +extern void tui_scroll_backward (struct tui_win_info *, int); +extern void tui_scroll_left (struct tui_win_info *, int); +extern void tui_scroll_right (struct tui_win_info *, int); +extern void tui_scroll (enum tui_scroll_direction, struct tui_win_info *, int); +extern void tui_set_win_focus_to (struct tui_win_info *); +extern void tui_resize_all (void); +extern void tui_refresh_all_win (void); +extern void tui_sigwinch_handler (int); + +extern chtype tui_border_ulcorner; +extern chtype tui_border_urcorner; +extern chtype tui_border_lrcorner; +extern chtype tui_border_llcorner; +extern chtype tui_border_vline; +extern chtype tui_border_hline; +extern int tui_border_attrs; +extern int tui_active_border_attrs; + +extern int tui_update_variables (void); + +/* Update gdb's knowledge of the terminal size. */ +extern void tui_update_gdb_sizes (void); + +#endif diff --git a/gdb/tui/tui-windata.c b/gdb/tui/tui-windata.c new file mode 100644 index 00000000000..6f22d0c0dbe --- /dev/null +++ b/gdb/tui/tui-windata.c @@ -0,0 +1,309 @@ +/* Data/register window display. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-regs.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + + +/***************************************** +** STATIC LOCAL FUNCTIONS FORWARD DECLS ** +******************************************/ + + + +/***************************************** +** PUBLIC FUNCTIONS ** +******************************************/ + + +/* Answer the index first element displayed. If none are displayed, + then return (-1). */ +int +tui_first_data_item_displayed (void) +{ + int element_no = (-1); + int i; + + for (i = 0; (i < TUI_DATA_WIN->generic.content_size && element_no < 0); i++) + { + struct tui_gen_win_info * data_item_win; + + data_item_win = &((tui_win_content) + TUI_DATA_WIN->generic.content)[i]->which_element.data_window; + if (data_item_win->handle != (WINDOW *) NULL && data_item_win->is_visible) + element_no = i; + } + + return element_no; +} + + +/* Answer the index of the first element in line_no. If line_no is + past the data area (-1) is returned. */ +int +tui_first_data_element_no_in_line (int line_no) +{ + int first_element_no = (-1); + + /* + ** First see if there is a register on line_no, and if so, set the + ** first element number + */ + if ((first_element_no = tui_first_reg_element_no_inline (line_no)) == -1) + { /* + ** Looking at the general data, the 1st element on line_no + */ + } + + return first_element_no; +} + + +/* Function to delete all the item windows in the data window. This + is usually done when the data window is scrolled. */ +void +tui_delete_data_content_windows (void) +{ + int i; + struct tui_gen_win_info * data_item_win_ptr; + + for (i = 0; (i < TUI_DATA_WIN->generic.content_size); i++) + { + data_item_win_ptr = &((tui_win_content) + TUI_DATA_WIN->generic.content)[i]->which_element.data_window; + tui_delete_win (data_item_win_ptr->handle); + data_item_win_ptr->handle = (WINDOW *) NULL; + data_item_win_ptr->is_visible = FALSE; + } +} + + +void +tui_erase_data_content (char *prompt) +{ + werase (TUI_DATA_WIN->generic.handle); + tui_check_and_display_highlight_if_needed (TUI_DATA_WIN); + if (prompt != (char *) NULL) + { + int half_width = (TUI_DATA_WIN->generic.width - 2) / 2; + int x_pos; + + if (strlen (prompt) >= half_width) + x_pos = 1; + else + x_pos = half_width - strlen (prompt); + mvwaddstr (TUI_DATA_WIN->generic.handle, + (TUI_DATA_WIN->generic.height / 2), + x_pos, + prompt); + } + wrefresh (TUI_DATA_WIN->generic.handle); +} + + +/* This function displays the data that is in the data window's + content. It does not set the content. */ +void +tui_display_all_data (void) +{ + if (TUI_DATA_WIN->generic.content_size <= 0) + tui_erase_data_content (NO_DATA_STRING); + else + { + tui_erase_data_content ((char *) NULL); + tui_delete_data_content_windows (); + tui_check_and_display_highlight_if_needed (TUI_DATA_WIN); + tui_display_registers_from (0); + /* + ** Then display the other data + */ + if (TUI_DATA_WIN->detail.data_display_info.data_content != + (tui_win_content) NULL && + TUI_DATA_WIN->detail.data_display_info.data_content_count > 0) + { + } + } +} + + +/* Function to display the data starting at line, line_no, in the data + window. */ +void +tui_display_data_from_line (int line_no) +{ + int _line_no = line_no; + + if (line_no < 0) + _line_no = 0; + + tui_check_and_display_highlight_if_needed (TUI_DATA_WIN); + + /* there is no general data, force regs to display (if there are any) */ + if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0) + tui_display_registers_from_line (_line_no, TRUE); + else + { + int element_no, start_line_no; + int regs_last_line = tui_last_regs_line_no (); + + + /* display regs if we can */ + if (tui_display_registers_from_line (_line_no, FALSE) < 0) + { /* + ** _line_no is past the regs display, so calc where the + ** start data element is + */ + if (regs_last_line < _line_no) + { /* figure out how many lines each element is to obtain + the start element_no */ + } + } + else + { /* + ** calculate the starting element of the data display, given + ** regs_last_line and how many lines each element is, up to + ** _line_no + */ + } + /* Now display the data , starting at element_no */ + } +} + + +/* Display data starting at element element_no. */ +void +tui_display_data_from (int element_no, int reuse_windows) +{ + int first_line = (-1); + + if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count) + first_line = tui_line_from_reg_element_no (element_no); + else + { /* calculate the first_line from the element number */ + } + + if (first_line >= 0) + { + tui_erase_data_content ((char *) NULL); + if (!reuse_windows) + tui_delete_data_content_windows (); + tui_display_data_from_line (first_line); + } +} + + +/* Function to redisplay the contents of the data window. */ +void +tui_refresh_data_win (void) +{ + tui_erase_data_content ((char *) NULL); + if (TUI_DATA_WIN->generic.content_size > 0) + { + int first_element = tui_first_data_item_displayed (); + + if (first_element >= 0) /* re-use existing windows */ + tui_display_data_from (first_element, TRUE); + } +} + + +/* Function to check the data values and hilite any that have changed. */ +void +tui_check_data_values (struct frame_info *frame) +{ + tui_check_register_values (frame); + + /* Now check any other data values that there are */ + if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible) + { + int i; + + for (i = 0; TUI_DATA_WIN->detail.data_display_info.data_content_count; i++) + { +#ifdef LATER + tui_data_element_ptr data_element_ptr; + struct tui_gen_win_info * data_item_win_ptr; + Opaque new_value; + + data_item_ptr = &TUI_DATA_WIN->detail.data_display_info. + data_content[i]->which_element.data_window; + data_element_ptr = &((tui_win_content) + data_item_win_ptr->content)[0]->which_element.data; + if value + has changed (data_element_ptr, frame, &new_value) + { + data_element_ptr->value = new_value; + update the display with the new value, hiliting it. + } +#endif + } + } +} + + +/* Scroll the data window vertically forward or backward. */ +void +tui_vertical_data_scroll (enum tui_scroll_direction scroll_direction, int num_to_scroll) +{ + int first_element_no; + int first_line = (-1); + + first_element_no = tui_first_data_item_displayed (); + if (first_element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count) + first_line = tui_line_from_reg_element_no (first_element_no); + else + { /* calculate the first line from the element number which is in + ** the general data content + */ + } + + if (first_line >= 0) + { + int last_element_no, last_line; + + if (scroll_direction == FORWARD_SCROLL) + first_line += num_to_scroll; + else + first_line -= num_to_scroll; + tui_erase_data_content ((char *) NULL); + tui_delete_data_content_windows (); + tui_display_data_from_line (first_line); + } +} + + +/***************************************** +** STATIC LOCAL FUNCTIONS ** +******************************************/ diff --git a/gdb/tui/tui-windata.h b/gdb/tui/tui-windata.h new file mode 100644 index 00000000000..10123a3fad9 --- /dev/null +++ b/gdb/tui/tui-windata.h @@ -0,0 +1,41 @@ +/* Data/register window display. + + Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation, + Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_WINDATA_H +#define TUI_WINDATA_H + +#include "tui/tui-data.h" + +extern void tui_erase_data_content (char *); +extern void tui_display_all_data (void); +extern void tui_check_data_values (struct frame_info *); +extern void tui_display_data_from_line (int); +extern int tui_first_data_item_displayed (void); +extern int tui_first_data_element_no_in_line (int); +extern void tui_delete_data_content_windows (void); +extern void tui_refresh_data_win (void); +extern void tui_display_data_from (int, int); +extern void tui_vertical_data_scroll (enum tui_scroll_direction, int); + +#endif diff --git a/gdb/tui/tui-wingeneral.c b/gdb/tui/tui-wingeneral.c new file mode 100644 index 00000000000..1bd946089e2 --- /dev/null +++ b/gdb/tui/tui-wingeneral.c @@ -0,0 +1,282 @@ +/* General window behavior. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, + Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-win.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/*********************** +** PUBLIC FUNCTIONS +***********************/ + +/* Refresh the window. */ +void +tui_refresh_win (struct tui_gen_win_info * win_info) +{ + if (win_info->type == DATA_WIN && win_info->content_size > 0) + { + int i; + + for (i = 0; (i < win_info->content_size); i++) + { + struct tui_gen_win_info * data_item_win_ptr; + + data_item_win_ptr = &((tui_win_content) + win_info->content)[i]->which_element.data_window; + if (data_item_win_ptr != NULL + && data_item_win_ptr->handle != (WINDOW *) NULL) + wrefresh (data_item_win_ptr->handle); + } + } + else if (win_info->type == CMD_WIN) + { + /* Do nothing */ + } + else + { + if (win_info->handle != (WINDOW *) NULL) + wrefresh (win_info->handle); + } + + return; +} + + +/* Function to delete the curses window, checking for NULL. */ +void +tui_delete_win (WINDOW * window) +{ + if (window != (WINDOW *) NULL) + delwin (window); + + return; +} + + +/* Draw a border arround the window. */ +void +box_win (struct tui_gen_win_info * win_info, int highlight_flag) +{ + if (win_info && win_info->handle) + { + WINDOW *win; + int attrs; + + win = win_info->handle; + if (highlight_flag == HILITE) + attrs = tui_active_border_attrs; + else + attrs = tui_border_attrs; + + wattron (win, attrs); + wborder (win, tui_border_vline, tui_border_vline, + tui_border_hline, tui_border_hline, + tui_border_ulcorner, tui_border_urcorner, + tui_border_llcorner, tui_border_lrcorner); + if (win_info->title) + mvwaddstr (win, 0, 3, win_info->title); + wattroff (win, attrs); + } +} + + +void +tui_unhighlight_win (struct tui_win_info * win_info) +{ + if (win_info != NULL && win_info->generic.handle != (WINDOW *) NULL) + { + box_win ((struct tui_gen_win_info *) win_info, NO_HILITE); + wrefresh (win_info->generic.handle); + tui_set_win_highlight (win_info, 0); + } +} + + +void +tui_highlight_win (struct tui_win_info * win_info) +{ + if (win_info != NULL + && win_info->can_highlight + && win_info->generic.handle != (WINDOW *) NULL) + { + box_win ((struct tui_gen_win_info *) win_info, HILITE); + wrefresh (win_info->generic.handle); + tui_set_win_highlight (win_info, 1); + } +} + +void +tui_check_and_display_highlight_if_needed (struct tui_win_info * win_info) +{ + if (win_info != NULL && win_info->generic.type != CMD_WIN) + { + if (win_info->is_highlighted) + tui_highlight_win (win_info); + else + tui_unhighlight_win (win_info); + + } + return; +} + + +void +tui_make_window (struct tui_gen_win_info * win_info, int box_it) +{ + WINDOW *handle; + + handle = newwin (win_info->height, + win_info->width, + win_info->origin.y, + win_info->origin.x); + win_info->handle = handle; + if (handle != (WINDOW *) NULL) + { + if (box_it == BOX_WINDOW) + box_win (win_info, NO_HILITE); + win_info->is_visible = TRUE; + scrollok (handle, TRUE); + } +} + + +/* We can't really make windows visible, or invisible. So we have to + delete the entire window when making it visible, and create it + again when making it visible. */ +static void +make_visible (struct tui_gen_win_info *win_info, int visible) +{ + /* Don't tear down/recreate command window */ + if (win_info->type == CMD_WIN) + return; + + if (visible) + { + if (!win_info->is_visible) + { + tui_make_window (win_info, + (win_info->type != CMD_WIN + && !tui_win_is_auxillary (win_info->type))); + win_info->is_visible = TRUE; + } + } + else if (!visible && + win_info->is_visible && win_info->handle != (WINDOW *) NULL) + { + win_info->is_visible = FALSE; + tui_delete_win (win_info->handle); + win_info->handle = (WINDOW *) NULL; + } + + return; +} + +void +tui_make_visible (struct tui_gen_win_info *win_info) +{ + make_visible (win_info, 1); +} + +void +tui_make_invisible (struct tui_gen_win_info *win_info) +{ + make_visible (win_info, 0); +} + + +/* Makes all windows invisible (except the command and locator windows). */ +static void +make_all_visible (int visible) +{ + int i; + + for (i = 0; i < MAX_MAJOR_WINDOWS; i++) + { + if (tui_win_list[i] != NULL + && ((tui_win_list[i])->generic.type) != CMD_WIN) + { + if (tui_win_is_source_type ((tui_win_list[i])->generic.type)) + make_visible ((tui_win_list[i])->detail.source_info.execution_info, + visible); + make_visible ((struct tui_gen_win_info *) tui_win_list[i], visible); + } + } + + return; +} + +void +tui_make_all_visible (void) +{ + make_all_visible (1); +} + +void +tui_make_all_invisible (void) +{ + make_all_visible (0); +} + +/* Function to refresh all the windows currently displayed. */ + +void +tui_refresh_all (struct tui_win_info * * list) +{ + enum tui_win_type type; + struct tui_gen_win_info * locator = tui_locator_win_info_ptr (); + + for (type = SRC_WIN; (type < MAX_MAJOR_WINDOWS); type++) + { + if (list[type] && list[type]->generic.is_visible) + { + if (type == SRC_WIN || type == DISASSEM_WIN) + { + touchwin (list[type]->detail.source_info.execution_info->handle); + tui_refresh_win (list[type]->detail.source_info.execution_info); + } + touchwin (list[type]->generic.handle); + tui_refresh_win (&list[type]->generic); + } + } + if (locator->is_visible) + { + touchwin (locator->handle); + tui_refresh_win (locator); + } +} + + +/********************************* +** Local Static Functions +*********************************/ diff --git a/gdb/tui/tui-wingeneral.h b/gdb/tui/tui-wingeneral.h new file mode 100644 index 00000000000..306d79402c0 --- /dev/null +++ b/gdb/tui/tui-wingeneral.h @@ -0,0 +1,45 @@ +/* General window behavior. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_WINGENERAL_H +#define TUI_WINGENERAL_H + +struct tui_win_info; +struct tui_gen_win_info; + +extern void tui_unhighlight_win (struct tui_win_info *); +extern void tui_make_visible (struct tui_gen_win_info *); +extern void tui_make_invisible (struct tui_gen_win_info *); +extern void tui_make_all_visible (void); +extern void tui_make_all_invisible (void); +extern void tui_make_window (struct tui_gen_win_info *, int); +extern struct tui_win_info *tui_copy_win (struct tui_win_info *); +extern void tui_box_win (struct tui_gen_win_info *, int); +extern void tui_highlight_win (struct tui_win_info *); +extern void tui_check_and_display_highlight_if_needed (struct tui_win_info *); +extern void tui_refresh_all (struct tui_win_info **); +extern void tui_delete_win (WINDOW * window); +extern void tui_refresh_win (struct tui_gen_win_info *); + +#endif diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c new file mode 100644 index 00000000000..6b77c4010ce --- /dev/null +++ b/gdb/tui/tui-winsource.c @@ -0,0 +1,659 @@ +/* TUI display source/assembly window. + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "symtab.h" +#include "frame.h" +#include "breakpoint.h" +#include "value.h" +#include "source.h" + +#include "tui/tui.h" +#include "tui/tui-data.h" +#include "tui/tui-stack.h" +#include "tui/tui-win.h" +#include "tui/tui-wingeneral.h" +#include "tui/tui-winsource.h" +#include "tui/tui-source.h" +#include "tui/tui-disasm.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#ifdef HAVE_CURSES_H +#include +#endif +#endif + +/* Function to display the "main" routine. */ +void +tui_display_main (void) +{ + if ((tui_source_windows ())->count > 0) + { + CORE_ADDR addr; + + addr = tui_get_begin_asm_address (); + if (addr != (CORE_ADDR) 0) + { + struct symtab_and_line sal; + + tui_update_source_windows_with_addr (addr); + sal = find_pc_line (addr, 0); + if (sal.symtab) + tui_update_locator_filename (sal.symtab->filename); + else + tui_update_locator_filename ("??"); + } + } +} + + + +/* Function to display source in the source window. This function + initializes the horizontal scroll to 0. */ +void +tui_update_source_window (struct tui_win_info * win_info, struct symtab *s, + union tui_line_or_address line_or_addr, int noerror) +{ + win_info->detail.source_info.horizontal_offset = 0; + tui_update_source_window_as_is (win_info, s, line_or_addr, noerror); + + return; +} + + +/* Function to display source in the source/asm window. This function + shows the source as specified by the horizontal offset. */ +void +tui_update_source_window_as_is (struct tui_win_info * win_info, struct symtab *s, + union tui_line_or_address line_or_addr, int noerror) +{ + enum tui_status ret; + + if (win_info->generic.type == SRC_WIN) + ret = tui_set_source_content (s, line_or_addr.line_no, noerror); + else + ret = tui_set_disassem_content (line_or_addr.addr); + + if (ret == TUI_FAILURE) + { + tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT); + tui_clear_exec_info_content (win_info); + } + else + { + tui_update_breakpoint_info (win_info, 0); + tui_show_source_content (win_info); + tui_update_exec_info (win_info); + if (win_info->generic.type == SRC_WIN) + { + struct symtab_and_line sal; + + sal.line = line_or_addr.line_no + + (win_info->generic.content_size - 2); + sal.symtab = s; + set_current_source_symtab_and_line (&sal); + /* + ** If the focus was in the asm win, put it in the src + ** win if we don't have a split layout + */ + if (tui_win_with_focus () == TUI_DISASM_WIN && + tui_current_layout () != SRC_DISASSEM_COMMAND) + tui_set_win_focus_to (TUI_SRC_WIN); + } + } + + + return; +} + + +/* Function to ensure that the source and/or disassemly windows + reflect the input address. */ +void +tui_update_source_windows_with_addr (CORE_ADDR addr) +{ + if (addr != 0) + { + struct symtab_and_line sal; + union tui_line_or_address l; + + switch (tui_current_layout ()) + { + case DISASSEM_COMMAND: + case DISASSEM_DATA_COMMAND: + tui_show_disassem (addr); + break; + case SRC_DISASSEM_COMMAND: + tui_show_disassem_and_update_source (addr); + break; + default: + sal = find_pc_line (addr, 0); + l.line_no = sal.line; + tui_show_symtab_source (sal.symtab, l, FALSE); + break; + } + } + else + { + int i; + + for (i = 0; i < (tui_source_windows ())->count; i++) + { + struct tui_win_info * win_info = (struct tui_win_info *) (tui_source_windows ())->list[i]; + + tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT); + tui_clear_exec_info_content (win_info); + } + } +} + +/* Function to ensure that the source and/or disassemly windows + reflect the input address. */ +void +tui_update_source_windows_with_line (struct symtab *s, int line) +{ + CORE_ADDR pc; + union tui_line_or_address l; + + switch (tui_current_layout ()) + { + case DISASSEM_COMMAND: + case DISASSEM_DATA_COMMAND: + find_line_pc (s, line, &pc); + tui_update_source_windows_with_addr (pc); + break; + default: + l.line_no = line; + tui_show_symtab_source (s, l, FALSE); + if (tui_current_layout () == SRC_DISASSEM_COMMAND) + { + find_line_pc (s, line, &pc); + tui_show_disassem (pc); + } + break; + } + + return; +} + +void +tui_clear_source_content (struct tui_win_info * win_info, int display_prompt) +{ + if (win_info != NULL) + { + int i; + + win_info->generic.content_in_use = FALSE; + tui_erase_source_content (win_info, display_prompt); + for (i = 0; i < win_info->generic.content_size; i++) + { + struct tui_win_element * element = + (struct tui_win_element *) win_info->generic.content[i]; + element->which_element.source.has_break = FALSE; + element->which_element.source.is_exec_point = FALSE; + } + } +} + + +void +tui_erase_source_content (struct tui_win_info * win_info, int display_prompt) +{ + int x_pos; + int half_width = (win_info->generic.width - 2) / 2; + + if (win_info->generic.handle != (WINDOW *) NULL) + { + werase (win_info->generic.handle); + tui_check_and_display_highlight_if_needed (win_info); + if (display_prompt == EMPTY_SOURCE_PROMPT) + { + char *no_src_str; + + if (win_info->generic.type == SRC_WIN) + no_src_str = NO_SRC_STRING; + else + no_src_str = NO_DISASSEM_STRING; + if (strlen (no_src_str) >= half_width) + x_pos = 1; + else + x_pos = half_width - strlen (no_src_str); + mvwaddstr (win_info->generic.handle, + (win_info->generic.height / 2), + x_pos, + no_src_str); + + /* elz: added this function call to set the real contents of + the window to what is on the screen, so that later calls + to refresh, do display + the correct stuff, and not the old image */ + + tui_set_source_content_nil (win_info, no_src_str); + } + tui_refresh_win (&win_info->generic); + } +} + + +/* Redraw the complete line of a source or disassembly window. */ +static void +tui_show_source_line (struct tui_win_info * win_info, int lineno) +{ + struct tui_win_element * line; + int x, y; + + line = (struct tui_win_element *) win_info->generic.content[lineno - 1]; + if (line->which_element.source.is_exec_point) + wattron (win_info->generic.handle, A_STANDOUT); + + mvwaddstr (win_info->generic.handle, lineno, 1, + line->which_element.source.line); + if (line->which_element.source.is_exec_point) + wattroff (win_info->generic.handle, A_STANDOUT); + + /* Clear to end of line but stop before the border. */ + getyx (win_info->generic.handle, y, x); + while (x + 1 < win_info->generic.width) + { + waddch (win_info->generic.handle, ' '); + getyx (win_info->generic.handle, y, x); + } +} + +void +tui_show_source_content (struct tui_win_info * win_info) +{ + if (win_info->generic.content_size > 0) + { + int lineno; + + for (lineno = 1; lineno <= win_info->generic.content_size; lineno++) + tui_show_source_line (win_info, lineno); + } + else + tui_erase_source_content (win_info, TRUE); + + tui_check_and_display_highlight_if_needed (win_info); + tui_refresh_win (&win_info->generic); + win_info->generic.content_in_use = TRUE; +} + + +/* Scroll the source forward or backward horizontally. */ +void +tui_horizontal_source_scroll (struct tui_win_info * win_info, + enum tui_scroll_direction direction, + int num_to_scroll) +{ + if (win_info->generic.content != NULL) + { + int offset; + struct symtab *s; + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + + if (cursal.symtab == (struct symtab *) NULL) + s = find_pc_symtab (get_frame_pc (deprecated_selected_frame)); + else + s = cursal.symtab; + + if (direction == LEFT_SCROLL) + offset = win_info->detail.source_info.horizontal_offset + num_to_scroll; + else + { + if ((offset = + win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0) + offset = 0; + } + win_info->detail.source_info.horizontal_offset = offset; + tui_update_source_window_as_is (win_info, s, + ((struct tui_win_element *) + win_info->generic.content[0])->which_element.source.line_or_addr, + FALSE); + } + + return; +} + + +/* Set or clear the has_break flag in the line whose line is line_no. */ +void +tui_set_is_exec_point_at (union tui_line_or_address l, struct tui_win_info * win_info) +{ + int changed = 0; + int i; + tui_win_content content = (tui_win_content) win_info->generic.content; + + i = 0; + while (i < win_info->generic.content_size) + { + int new_state; + + if (content[i]->which_element.source.line_or_addr.addr == l.addr) + new_state = TRUE; + else + new_state = FALSE; + if (new_state != content[i]->which_element.source.is_exec_point) + { + changed++; + content[i]->which_element.source.is_exec_point = new_state; + tui_show_source_line (win_info, i + 1); + } + i++; + } + if (changed) + tui_refresh_win (&win_info->generic); +} + +/* Update the execution windows to show the active breakpoints. + This is called whenever a breakpoint is inserted, removed or + has its state changed. */ +void +tui_update_all_breakpoint_info (void) +{ + struct tui_list *list = tui_source_windows (); + int i; + + for (i = 0; i < list->count; i++) + { + struct tui_win_info * win = (struct tui_win_info *) list->list[i]; + + if (tui_update_breakpoint_info (win, FALSE)) + { + tui_update_exec_info (win); + } + } +} + + +/* Scan the source window and the breakpoints to update the + has_break information for each line. + Returns 1 if something changed and the execution window + must be refreshed. */ +int +tui_update_breakpoint_info (struct tui_win_info * win, int current_only) +{ + int i; + int need_refresh = 0; + struct tui_source_info * src = &win->detail.source_info; + + for (i = 0; i < win->generic.content_size; i++) + { + struct breakpoint *bp; + extern struct breakpoint *breakpoint_chain; + int mode; + struct tui_source_element* line; + + line = &((struct tui_win_element *) win->generic.content[i])->which_element.source; + if (current_only && !line->is_exec_point) + continue; + + /* Scan each breakpoint to see if the current line has something to + do with it. Identify enable/disabled breakpoints as well as + those that we already hit. */ + mode = 0; + for (bp = breakpoint_chain; + bp != (struct breakpoint *) NULL; + bp = bp->next) + { + if ((win == TUI_SRC_WIN + && bp->source_file + && (strcmp (src->filename, bp->source_file) == 0) + && bp->line_number == line->line_or_addr.line_no) + || (win == TUI_DISASM_WIN + && bp->loc->address == line->line_or_addr.addr)) + { + if (bp->enable_state == bp_disabled) + mode |= TUI_BP_DISABLED; + else + mode |= TUI_BP_ENABLED; + if (bp->hit_count) + mode |= TUI_BP_HIT; + if (bp->cond) + mode |= TUI_BP_CONDITIONAL; + if (bp->type == bp_hardware_breakpoint) + mode |= TUI_BP_HARDWARE; + } + } + if (line->has_break != mode) + { + line->has_break = mode; + need_refresh = 1; + } + } + return need_refresh; +} + + +/* Function to initialize the content of the execution info window, + based upon the input window which is either the source or + disassembly window. */ +enum tui_status +tui_set_exec_info_content (struct tui_win_info * win_info) +{ + enum tui_status ret = TUI_SUCCESS; + + if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL) + { + struct tui_gen_win_info * exec_info_ptr = win_info->detail.source_info.execution_info; + + if (exec_info_ptr->content == NULL) + exec_info_ptr->content = + (void **) tui_alloc_content (win_info->generic.height, + exec_info_ptr->type); + if (exec_info_ptr->content != NULL) + { + int i; + + tui_update_breakpoint_info (win_info, 1); + for (i = 0; i < win_info->generic.content_size; i++) + { + struct tui_win_element * element; + struct tui_win_element * src_element; + int mode; + + element = (struct tui_win_element *) exec_info_ptr->content[i]; + src_element = (struct tui_win_element *) win_info->generic.content[i]; + + memset(element->which_element.simple_string, ' ', + sizeof(element->which_element.simple_string)); + element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0; + + /* Now update the exec info content based upon the state + of each line as indicated by the source content. */ + mode = src_element->which_element.source.has_break; + if (mode & TUI_BP_HIT) + element->which_element.simple_string[TUI_BP_HIT_POS] = + (mode & TUI_BP_HARDWARE) ? 'H' : 'B'; + else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED)) + element->which_element.simple_string[TUI_BP_HIT_POS] = + (mode & TUI_BP_HARDWARE) ? 'h' : 'b'; + + if (mode & TUI_BP_ENABLED) + element->which_element.simple_string[TUI_BP_BREAK_POS] = '+'; + else if (mode & TUI_BP_DISABLED) + element->which_element.simple_string[TUI_BP_BREAK_POS] = '-'; + + if (src_element->which_element.source.is_exec_point) + element->which_element.simple_string[TUI_EXEC_POS] = '>'; + } + exec_info_ptr->content_size = win_info->generic.content_size; + } + else + ret = TUI_FAILURE; + } + + return ret; +} + + +void +tui_show_exec_info_content (struct tui_win_info * win_info) +{ + struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info; + int cur_line; + + werase (exec_info->handle); + tui_refresh_win (exec_info); + for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++) + mvwaddstr (exec_info->handle, + cur_line, + 0, + ((struct tui_win_element *) + exec_info->content[cur_line - 1])->which_element.simple_string); + tui_refresh_win (exec_info); + exec_info->content_in_use = TRUE; +} + + +void +tui_erase_exec_info_content (struct tui_win_info * win_info) +{ + struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info; + + werase (exec_info->handle); + tui_refresh_win (exec_info); +} + +void +tui_clear_exec_info_content (struct tui_win_info * win_info) +{ + win_info->detail.source_info.execution_info->content_in_use = FALSE; + tui_erase_exec_info_content (win_info); + + return; +} + +/* Function to update the execution info window. */ +void +tui_update_exec_info (struct tui_win_info * win_info) +{ + tui_set_exec_info_content (win_info); + tui_show_exec_info_content (win_info); +} + +enum tui_status +tui_alloc_source_buffer (struct tui_win_info *win_info) +{ + char *src_line_buf; + int i, line_width, max_lines; + enum tui_status ret = TUI_FAILURE; + + max_lines = win_info->generic.height; /* less the highlight box */ + line_width = win_info->generic.width - 1; + /* + ** Allocate the buffer for the source lines. Do this only once since they + ** will be re-used for all source displays. The only other time this will + ** be done is when a window's size changes. + */ + if (win_info->generic.content == NULL) + { + src_line_buf = (char *) xmalloc ((max_lines * line_width) * sizeof (char)); + if (src_line_buf == (char *) NULL) + fputs_unfiltered ( + "Unable to Allocate Memory for Source or Disassembly Display.\n", + gdb_stderr); + else + { + /* allocate the content list */ + if ((win_info->generic.content = + (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL) + { + xfree (src_line_buf); + src_line_buf = (char *) NULL; + fputs_unfiltered ( + "Unable to Allocate Memory for Source or Disassembly Display.\n", + gdb_stderr); + } + } + for (i = 0; i < max_lines; i++) + ((struct tui_win_element *) + win_info->generic.content[i])->which_element.source.line = + src_line_buf + (line_width * i); + ret = TUI_SUCCESS; + } + else + ret = TUI_SUCCESS; + + return ret; +} + + +/* Answer whether the a particular line number or address is displayed + in the current source window. */ +int +tui_line_is_displayed (int line, struct tui_win_info * win_info, + int check_threshold) +{ + int is_displayed = FALSE; + int i, threshold; + + if (check_threshold) + threshold = SCROLL_THRESHOLD; + else + threshold = 0; + i = 0; + while (i < win_info->generic.content_size - threshold && !is_displayed) + { + is_displayed = (((struct tui_win_element *) + win_info->generic.content[i])->which_element.source.line_or_addr.line_no + == (int) line); + i++; + } + + return is_displayed; +} + + +/* Answer whether the a particular line number or address is displayed + in the current source window. */ +int +tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info * win_info, + int check_threshold) +{ + int is_displayed = FALSE; + int i, threshold; + + if (check_threshold) + threshold = SCROLL_THRESHOLD; + else + threshold = 0; + i = 0; + while (i < win_info->generic.content_size - threshold && !is_displayed) + { + is_displayed = (((struct tui_win_element *) + win_info->generic.content[i])->which_element.source.line_or_addr.addr + == addr); + i++; + } + + return is_displayed; +} + + +/***************************************** +** STATIC LOCAL FUNCTIONS ** +******************************************/ diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h new file mode 100644 index 00000000000..e64589ba5f2 --- /dev/null +++ b/gdb/tui/tui-winsource.h @@ -0,0 +1,73 @@ +/* TUI display source/assembly window. + + Copyright 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + Contributed by Hewlett-Packard Company. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TUI_SOURCEWIN_H +#define TUI_SOURCEWIN_H + +#include "tui/tui-data.h" + +struct tui_win_info; + +/* Update the execution windows to show the active breakpoints. This + is called whenever a breakpoint is inserted, removed or has its + state changed. */ +extern void tui_update_all_breakpoint_info (void); + +/* Scan the source window and the breakpoints to update the hasBreak + information for each line. Returns 1 if something changed and the + execution window must be refreshed. */ +extern int tui_update_breakpoint_info (struct tui_win_info * win, + int current_only); + +/* Function to display the "main" routine. */ +extern void tui_display_main (void); +extern void tui_update_source_window (struct tui_win_info *, struct symtab *, + union tui_line_or_address, int); +extern void tui_update_source_window_as_is (struct tui_win_info *, + struct symtab *, + union tui_line_or_address, int); +extern void tui_update_source_windows_with_addr (CORE_ADDR); +extern void tui_update_source_windows_with_line (struct symtab *, int); +extern void tui_clear_source_content (struct tui_win_info *, int); +extern void tui_erase_source_content (struct tui_win_info *, int); +extern void tui_show_source_content (struct tui_win_info *); +extern void tui_horizontal_source_scroll (struct tui_win_info *, + enum tui_scroll_direction, int); +extern enum tui_status tui_set_exec_info_content (struct tui_win_info *); +extern void tui_show_exec_info_content (struct tui_win_info *); +extern void tui_erase_exec_info_content (struct tui_win_info *); +extern void tui_clear_exec_info_content (struct tui_win_info *); +extern void tui_update_exec_info (struct tui_win_info *); + +extern void tui_set_is_exec_point_at (union tui_line_or_address, + struct tui_win_info *); +extern enum tui_status tui_alloc_source_buffer (struct tui_win_info *); +extern int tui_line_is_displayed (int, struct tui_win_info *, int); +extern int tui_addr_is_displayed (CORE_ADDR, struct tui_win_info *, int); + + +/* Constant definitions. */ +#define SCROLL_THRESHOLD 2 /* threshold for lazy scroll */ + +#endif diff --git a/sim/testsuite/sim/mips/ChangeLog b/sim/testsuite/sim/mips/ChangeLog new file mode 100644 index 00000000000..67e7bfa2fe2 --- /dev/null +++ b/sim/testsuite/sim/mips/ChangeLog @@ -0,0 +1,5 @@ +2004-01-26 Chris Demetriou + + * basic.exp: New file. + * testutils.inc: New file. + * sanity.s: New file. diff --git a/sim/testsuite/sim/mips/basic.exp b/sim/testsuite/sim/mips/basic.exp new file mode 100644 index 00000000000..63dc086f525 --- /dev/null +++ b/sim/testsuite/sim/mips/basic.exp @@ -0,0 +1,26 @@ +# MIPS simulator instruction tests + +# As gross as it is, we unset the linker script specifid by the target +# board. The MIPS libgloss linker scripts include libgcc (and possibly +# other libraries), which the linker (used to link these tests rather +# than the compiler) can't necessarily find. +unset_currtarget_info ldscript + +# Only test mips*-elf (e.g., no mips-linux), and only test if the target +# board really is a simulator (sim tests don't work on real HW). +if {[istarget mips*-elf] && [board_info target exists is_simulator]} { + + if {[istarget mipsisa64*-elf]} { + set models "mips1 mips2 mips3 mips4 mips32 mips64" + } elseif {[istarget mipsisa32*-elf]} { + set models "mips1 mips2 mips32" + } elseif {[istarget mips64*-elf]} { + set models "mips1 mips2 mips3" + } else { + # fall back to just testing mips1 code. + set models "mips1" + } + set cpu_option -march + + run_sim_test sanity.s $models +} diff --git a/sim/testsuite/sim/mips/sanity.s b/sim/testsuite/sim/mips/sanity.s new file mode 100644 index 00000000000..74551edd404 --- /dev/null +++ b/sim/testsuite/sim/mips/sanity.s @@ -0,0 +1,20 @@ +# mips test sanity, expected to pass. +# mach: all +# as: -mabi=eabi +# ld: -N -Ttext=0x80010000 +# output: *\\npass\\n + + .include "testutils.inc" + + setup + + .set noreorder + + .ent DIAG +DIAG: + + writemsg "Sanity is good!" + + pass + + .end DIAG diff --git a/sim/testsuite/sim/mips/testutils.inc b/sim/testsuite/sim/mips/testutils.inc new file mode 100644 index 00000000000..f111f793140 --- /dev/null +++ b/sim/testsuite/sim/mips/testutils.inc @@ -0,0 +1,149 @@ +# MIPS simulator testsuite utility functions. +# Copyright (C) 2004 Free Software Foundation, Inc. +# Contributed by Chris Demetriou of Broadcom Corporation. +# +# This file is part of the GNU simulators. +# +# 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, 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. */ + + +# $1, $4, $5, %6, are used as temps by the macros defined here. + + .macro writemsg msg + .data +901: .ascii "\msg\n" +902: + .previous + la $5, 901b + li $6, 902b - 901b + .set push + .set noreorder + jal _dowrite + li $4, 0 + .set pop + .endm + + + # The MIPS simulator uses "break 0x3ff" as the code to exit, + # with the return value in $4 (a0). + .macro exit rc + li $4, \rc + break 0x3ff + .endm + + + .macro setup + + .global _start + .ent _start +_start: + .set push + .set noreorder + j DIAG + nop + .set pop + .end _start + + .global _fail + .ent _fail +_fail: + writemsg "fail" + exit 1 + .end _fail + + .global _pass + .ent _pass +_pass: + writemsg "pass" + exit 0 + .end _pass + + # The MIPS simulator can use multiple different monitor types, + # so we hard-code the simulator "write" reserved instruction opcode, + # rather than jumping to a vector that invokes it. The operation + # expects RA to point to the location at which to continue + # after writing. + .global _dowrite + .ent _dowrite +_dowrite: + # Write opcode (reserved instruction). See sim_monitor and its + # callers in sim/mips/interp.c. + .word 0x00000005 | ((8 << 1) << 6) + .end _dowrite + + .endm # setup + + + .macro pass + .set push + .set noreorder + j _pass + nop + .set pop + .endm + + + .macro fail + .set push + .set noreorder + j _fail + nop + .set pop + .endm + + + .macro load32 reg, val + li \reg, \val + .endm + + + .macro load64 reg, val + dli \reg, \val + .endm + + + .macro loadaddr reg, addr + la \reg, \addr + .endm + + + .macro checkreg reg, expreg + .set push + .set noat + .set noreorder + beq \expreg, \reg, 901f + nop + fail +901: + .set pop + .endm + + + .macro check32 reg, val + .set push + .set noat + load32 $1, \val + checkreg \reg, $1 + .set pop + .endm + + + .macro check64 reg, val + .set push + .set noat + load64 $1, \val + checkreg \reg, $1 + .set pop + .endm