diff -rc3p -N -x '.#*' -x CVS -x'*.cache' -xMakefile.in -x configure src.orig/gdb/i386-nto-tdep.c src/gdb/i386-nto-tdep.c *** src.orig/gdb/i386-nto-tdep.c Wed Dec 31 19:00:00 1969 --- src/gdb/i386-nto-tdep.c Mon Feb 24 16:58:16 2003 *************** *** 0 **** --- 1,422 ---- + /* i386-nto-tdep.c - i386 specific functionality for QNX Neutrino */ + + /* Copyright 2003 Free Software Foundation */ + + /* This code was donated by QNX Software Systems Ltd. */ + + #include "defs.h" + #include "gdb_string.h" + #include + #include "frame.h" + #include "inferior.h" + #include "bfd.h" + #include "symfile.h" + #include "target.h" + #include "gdb_wait.h" + #include "gdbcmd.h" + #include "objfiles.h" + #include "gdb-stabs.h" + #include "gdbthread.h" + #include "regcache.h" + #include "solib-svr4.h" + #include "dcache.h" + #include "i386-tdep.h" + #include "nto-tdep.h" + #include "osabi.h" + + #ifdef USG + #include + #endif + + #include + #include "serial.h" + + #include "nto-share/debug.h" + + /* Prototypes for i387_supply_fsave etc. */ + #include "i387-tdep.h" + + #ifndef FPC_REGNUM + #define FPC_REGNUM (FP0_REGNUM + 8) + #endif + + #define NUM_GPREGS 13 + static int gdb_to_nto[NUM_GPREGS] = + { 7, 6, 5, 4, 11, 2, 1, 0, 8, 10, 9, 12, -1 }; + + #define GDB_TO_OS(x) ((x >= 0 && x < NUM_GPREGS) ? gdb_to_nto[x] : -1) + + #ifndef X86_CPU_FXSR + #define X86_CPU_FXSR (1L << 12) + #endif + + extern unsigned nto_cpuinfo_flags; + extern int nto_cpuinfo_valid; + extern int nto_ostype, nto_cputype; + /* + Given a register return an id that represents the Neutrino regset it came from + if reg == -1 update all regsets + $MJC + */ + + enum QNX_REGS + { + QNX_REGS_GP = 0, + QNX_REGS_FP = 1, + QNX_REGS_END = 2 + }; + + unsigned + nto_get_regset_id (int regno) + { + unsigned regset; + if (regno == -1) + { /* return size so we can enumerate */ + regset = 2; + } + else if (regno < FP0_REGNUM) + { + regset = 0; + } + else if (regno < FPC_REGNUM) + { + regset = 1; + } + else + { + regset = -1; /* error */ + } + return regset; + } + + /* Tell GDB about the regset contained in the 'data' buffer */ + static void + gp_regset_fetch (char *data) + { + unsigned first_regno; + for (first_regno = 0; first_regno < FP0_REGNUM; first_regno++) + { + int regno = GDB_TO_OS (first_regno); + int const minusone = -1; + + if (data == NULL || regno == -1) + { + supply_register (first_regno, (char *) &minusone); + } + else + { + supply_register (first_regno, &data[regno * 4]); + } + } + } + + /* get 8087 data */ + static void + fp_regset_fetch (char *data) + { + if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) + i387_supply_fxsave (data); + else + i387_supply_fsave (data); + } + + void + nto_cpu_regset_fetch (int endian, int regset, void *data) + { + endian = endian; /* x86, don't care about endian */ + + switch (regset) + { + case QNX_REGS_GP: /* QNX has different ordering of GP regs GDB */ + gp_regset_fetch ((char *) data); + break; + case QNX_REGS_FP: + fp_regset_fetch ((char *) data); + break; + } + } + + /* get regset characteristics */ + unsigned + nto_get_regset_area (unsigned regset, char *subcmd) + { + unsigned length = 0; + switch (regset) + { + case QNX_REGS_GP: + *subcmd = NTO_REG_GENERAL; + length = NUM_GPREGS * sizeof (unsigned); + break; + case QNX_REGS_FP: + *subcmd = NTO_REG_FLOAT; + /* FIXME: should we calculate based on fxsave/fsave? */ + length = 512; + break; + default: + length = 0; + } + return length; + } + + /*- + Given the first and last register number, figure out the size/len + of the Neutrino register save area to ask for/tell about. Also set + the register set that's being dealt with in *subcmd. Watch out for + the range crossing a register set boundry. + */ + + unsigned + nto_cpu_register_area (first_regno, last_regno, subcmd, off, len) + unsigned first_regno; + unsigned last_regno; + unsigned char *subcmd; + unsigned *off; + unsigned *len; + { + int regno = -1; + + if (first_regno < FP0_REGNUM) + { + if (last_regno >= FP0_REGNUM) + last_regno = FP0_REGNUM - 1; + *subcmd = NTO_REG_GENERAL; + regno = GDB_TO_OS (first_regno); + *off = regno * sizeof (unsigned); + if (regno == -1) + *len = 0; + else + *len = (last_regno - first_regno + 1) * sizeof (unsigned); + } + else if (first_regno == FP_REGNUM) + { + /* Frame Pointer Psuedo-register */ + *off = SP_REGNUM * sizeof (unsigned); + *len = sizeof (unsigned); + return FP_REGNUM; + } + else if (first_regno >= FP0_REGNUM && first_regno < FPC_REGNUM) + { + unsigned off_adjust, regsize; + + if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) + { + off_adjust = 32; + regsize = 16; + } + else + { + off_adjust = 28; + regsize = 10; + } + + if (last_regno >= FPC_REGNUM) + last_regno = FPC_REGNUM - 1; + *subcmd = NTO_REG_FLOAT; + *off = (first_regno - FP0_REGNUM) * regsize + off_adjust; + *len = (last_regno - first_regno + 1) * 10; + /* Why 10? GDB only stores 10 bytes per FP register so if we're + * sending a register back to the target, we only want pdebug to write + * 10 bytes so as not to clobber the reserved 6 bytes in the fxsave + * structure. The astute reader will note that this will fail if we + * try to send a range of fpregs rather than 1 at a time but, as far + * as I know, there is no way to send more than one fpreg at a time + * anyway. If this turns out to be wrong, we may need to put more code + * in pdebug to deal with this - perhaps by masking off part of the + * register when it writes it in.*/ + } + else + { + *len = 0; + return last_regno; + } + return last_regno; + } + + /* Tell GDB about the registers contained in the 'data' buffer */ + + void + nto_cpu_register_fetch (endian, first_regno, last_regno, data) + int endian; + unsigned first_regno; + unsigned last_regno; + void *data; + { + fprintf_unfiltered (gdb_stderr, "warning: nto_cpu_register_fetch called \ + in remote-nto-i386.c. This shouldn't happen\n"); + /* If remote-nto-i386.c calls nto_supply_register in remote-nto.c, + * then remote-nto.c calls nto_cpu_register_fetch. Since this never + * happens, this function is left unimplemented. */ + } + + /* Build the Neutrino register set info into the 'data' buffer */ + + int + nto_cpu_register_store (endian, first_regno, last_regno, data) + int endian; + unsigned first_regno; + unsigned last_regno; + void *data; + { + /* Mostly (always?) you're only storing one at a time */ + if (first_regno == last_regno) + { + regcache_collect (first_regno, data); + return 1; + } + /* Floating point is the same for gdb and target */ + if (first_regno >= FP0_REGNUM) + { + for (; first_regno <= last_regno; first_regno++) + { + regcache_collect (first_regno, data); + (char *) data += REGISTER_RAW_SIZE (first_regno); + } + return 1; + } + /* GP registers are mapped differently for NTO than GDB */ + for (; first_regno <= last_regno; first_regno++) + { + int regnum = GDB_TO_OS (first_regno); + if (regnum == -1) + continue; + regcache_collect (first_regno, + (char *) data + sizeof (unsigned) * regnum); + } + return 1; + } + + /* nto_supply_* are used by nto_procfs.c and nto_core-regset.c */ + void + nto_supply_gregset (gregsetp) + nto_gregset_t *gregsetp; + { + register int regi, i = 0; + register unsigned *regp = (unsigned *) gregsetp; + + for (regi = 0; regi < (NUM_REGS - FP0_REGNUM); regi++) + { + i = GDB_TO_OS (regi); + supply_register (regi, (char *) ®p[i]); + } + } + + void + nto_supply_fpregset (fpregsetp) + nto_fpregset_t *fpregsetp; + { + if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) + i387_supply_fxsave ((char *) fpregsetp); + else + i387_supply_fsave ((char *) fpregsetp); + } + + /* Fetch (and possibly build) an appropriate link_map_offsets + structure for native x86 targets using the struct offsets + defined in link.h (but without actual reference to that file). + + This makes it possible to access x86 shared libraries from a GDB + that was not built on an x86 host (for cross debugging). */ + + static struct link_map_offsets * + i386_nto_svr4_fetch_link_map_offsets (void) + { + static struct link_map_offsets lmo; + static struct link_map_offsets *lmp = NULL; + + if (lmp == NULL) + { + lmp = &lmo; + + lmo.r_debug_size = 8; /* The actual size is 20 bytes, but + this is all we need. */ + lmo.r_map_offset = 4; + lmo.r_map_size = 4; + + lmo.link_map_size = 20; /* The actual size is 552 bytes, but + this is all we need. */ + lmo.l_addr_offset = 0; + lmo.l_addr_size = 4; + + lmo.l_name_offset = 4; + lmo.l_name_size = 4; + + lmo.l_next_offset = 12; + lmo.l_next_size = 4; + + lmo.l_prev_offset = 16; + lmo.l_prev_size = 4; + } + + return lmp; + } + + struct link_map_offsets * + nto_fetch_link_map_offsets (void) + { + return i386_nto_svr4_fetch_link_map_offsets (); + } + + static int + i386_nto_pc_in_sigtramp (CORE_ADDR pc, char *name) + { + return name && strcmp ("__signalstub", name) == 0; + } + + static CORE_ADDR + i386_nto_sigcontext_addr (struct frame_info *frame) + { + int sigcontext_offset = 136; + + if (get_next_frame (frame)) + return get_frame_base (get_next_frame (frame)) + sigcontext_offset; + + return read_register (SP_REGNUM) + sigcontext_offset; + } + + static void + i386_nto_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* NTO uses ELF. */ + i386_elf_init_abi (info, gdbarch); + + /* neutrino rewinds to look more normal */ + set_gdbarch_decr_pc_after_break (gdbarch, 0); + + /* NTO has shared libraries. */ + set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section); + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + + set_gdbarch_pc_in_sigtramp (gdbarch, i386_nto_pc_in_sigtramp); + tdep->sigcontext_addr = i386_nto_sigcontext_addr; + tdep->sc_pc_offset = 56; + tdep->sc_sp_offset = 68; + + /* setjmp()'s return PC saved in EDX (5) */ + tdep->jb_pc_offset = 5 * sizeof (int); + + set_solib_svr4_fetch_link_map_offsets (gdbarch, + i386_nto_svr4_fetch_link_map_offsets); + + /* Our loader handles solib relocations slightly differently than svr4 */ + TARGET_SO_RELOCATE_SECTION_ADDRESSES = nto_relocate_section_addresses; + + /* Supply a nice function to find our solibs */ + TARGET_SO_FIND_AND_OPEN_SOLIB = nto_find_and_open_solib; + + /* After a watchpoint trap, the PC points to the instruction after + the one that caused the trap. Therefore we don't need to step over it. + But we do need to reset the status register to avoid another trap. */ + HAVE_CONTINUABLE_WATCHPOINT = 1; + } + + void + _initialize_i386_nto_tdep (void) + { + gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_QNXNTO, + i386_nto_init_abi); + + /* read our extra gdbinit file */ + nto_source_extra_gdbinit (".ntox86-gdbinit"); + } diff -rc3p -N -x '.#*' -x CVS -x'*.cache' -xMakefile.in -x configure src.orig/gdb/nto-procfs.c src/gdb/nto-procfs.c *** src.orig/gdb/nto-procfs.c Wed Dec 31 19:00:00 1969 --- src/gdb/nto-procfs.c Wed Feb 26 16:41:07 2003 *************** *** 0 **** --- 1,1506 ---- + /* Copyright 2003 Free Software Foundation */ + + /* This code was donated by QNX Software Systems Ltd. */ + + /* Machine independent support for QNX Neutrino /proc (process file system) + for GDB. Written by Colin Burgess at QNX Software Systems Limited. */ + + #include "defs.h" + + #include + #include + #include + #include + #include + #include "nto-share/debug.h" + #include + #include + #include + #include + #include + #include + #include + #include + + #include "defs.h" + #include "gdb_string.h" + #include "gdbcore.h" + #include "frame.h" + #include "inferior.h" + #include "bfd.h" + #include "symfile.h" + #include "target.h" + #include "gdb_wait.h" + #include "gdbcmd.h" + #include "objfiles.h" + #include "gdb-stabs.h" + #include "gdbthread.h" + #include "nto-tdep.h" + #include "dcache.h" + #include "gdb_stat.h" + #include "command.h" + + #define NULL_PID 0 + #define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|_DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY) + + static struct target_ops procfs_ops; + + int ctl_fd; + + static void (*ofunc) (); + + static procfs_run run; + + static void procfs_open PARAMS ((char *, int)); + + static int procfs_can_run PARAMS ((void)); + + static ptid_t procfs_wait PARAMS ((ptid_t, struct target_waitstatus *)); + + static int procfs_xfer_memory + PARAMS ((CORE_ADDR, char *, int, int, struct mem_attrib * attrib, + struct target_ops *)); + + static void procfs_fetch_registers PARAMS ((int)); + + static void notice_signals (void); + + static void init_procfs_ops PARAMS ((void)); + + static ptid_t do_attach PARAMS ((ptid_t ptid)); + + static int procfs_can_use_hw_breakpoint PARAMS ((int, int, int)); + + static int procfs_insert_hw_breakpoint PARAMS ((CORE_ADDR, char *)); + + static int procfs_remove_hw_breakpoint PARAMS ((CORE_ADDR addr, char *)); + + static int procfs_insert_hw_watchpoint + PARAMS ((CORE_ADDR addr, int len, int type)); + + static int procfs_remove_hw_watchpoint + PARAMS ((CORE_ADDR addr, int len, int type)); + + static int procfs_stopped_by_watchpoint PARAMS ((void)); + + /* + These two globals are only ever set in procfs_open(), but are + referenced elsewhere. 'nto_procfs_node' is a flag used to say + whether we are local, or we should get the current node descriptor + for the remote QNX node. + */ + static char nto_procfs_path[PATH_MAX] = { "/proc" }; + static unsigned nto_procfs_node = ND_LOCAL_NODE; + + /* + This is a simple wrapper for the netmgr_strtond() function. It is + only called from the QNX_NODE macro declared below. The reason for + the macro and function are because QNX node descriptors are transient, + so we have to re-acquire them every time. + */ + static unsigned + procfs_nto_node (unsigned node) + { + if (node == -1) + { + error ("Lost the QNX node. Debug session probably over."); + /* NOTREACHED */ + } + return (node); + } + + /* + This define returns the current QNX Node, or -1 on error. It calls the above + function which is a simple wrapper for the error() call. + */ + #define QNX_NODE (ND_NODE_CMP(nto_procfs_node, ND_LOCAL_NODE) == 0 ? ND_LOCAL_NODE : \ + procfs_nto_node(netmgr_strtond(nto_procfs_path, 0))) + + /* + This is called when we call 'target procfs ' from the (gdb) prompt. + For QNX6 (nto), the only valid arg will be a QNX node string, + eg: "/net/some_node". If arg is not a valid QNX node, we will + default to local. + */ + static void + procfs_open (arg, from_tty) + char *arg; + int from_tty; + { + char *nodestr; + char *endstr; + char buffer[50]; + int fd, total_size; + procfs_sysinfo *sysinfo; + + /* Set the default node used for spawning to this one, + and only override it if there is a valid arg. */ + + nto_procfs_node = ND_LOCAL_NODE; + nodestr = arg ? strdup (arg) : arg; + + init_thread_list (); + + if (nodestr) + { + nto_procfs_node = netmgr_strtond (nodestr, &endstr); + if (nto_procfs_node == -1) + { + if (errno == ENOTSUP) + printf_filtered ("QNX Net Manager not found.\n"); + printf_filtered ("Invalid QNX node %s: error %d (%s).\n", nodestr, + errno, strerror (errno)); + xfree (nodestr); + nodestr = NULL; + nto_procfs_node = ND_LOCAL_NODE; + } + else if (*endstr) + { + if (*(endstr - 1) == '/') + *(endstr - 1) = 0; + else + *endstr = 0; + } + } + sprintf (nto_procfs_path, "%s%s", nodestr ? nodestr : "", "/proc"); + if (nodestr) + xfree (nodestr); + + fd = open (nto_procfs_path, O_RDONLY); + if (fd == -1) + { + printf_filtered ("Error opening %s : %d (%s)\n", nto_procfs_path, errno, + strerror (errno)); + error ("Invalid procfs arg"); + /* NOTREACHED */ + } + + sysinfo = (void *) buffer; + if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK) + { + printf_filtered ("Error getting size: %d (%s)\n", errno, + strerror (errno)); + close (fd); + error ("Devctl failed."); + /* NOTREACHED */ + } + else + { + total_size = sysinfo->total_size; + if (!(sysinfo = alloca (total_size))) + { + printf_filtered ("Memory error: %d (%s)\n", errno, + strerror (errno)); + close (fd); + error ("alloca failed."); + /* NOTREACHED */ + } + else + { + if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, total_size, 0) != EOK) + { + printf_filtered ("Error getting sysinfo: %d (%s)\n", errno, + strerror (errno)); + close (fd); + error ("Devctl failed."); + /* NOTREACHED */ + } + else + { + if (sysinfo->type != nto_map_arch_to_cputype(TARGET_ARCHITECTURE->arch_name)) + { + close (fd); + error ("Invalid target CPU."); + /* NOTREACHED */ + } + } + } + } + close (fd); + printf_filtered ("Debugging using %s\n", nto_procfs_path); + + } + + static void + procfs_set_thread (ptid) + ptid_t ptid; + { + pid_t tid; + + tid = ptid_get_tid (inferior_ptid); + devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0); + } + + /* Return nonzero if the thread TH is still alive. */ + static int + procfs_thread_alive (ptid_t ptid) + { + pid_t tid; + + tid = ptid_get_tid (ptid); + if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK) + return 1; + return 0; + } + + + void + procfs_find_new_threads (void) + { + procfs_status status; + pid_t pid; + ptid_t ptid; + + if (ctl_fd == -1) + return; + + pid = ptid_get_pid (inferior_ptid); + + for (status.tid = 1;; ++status.tid) + { + if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0) != + EOK && status.tid != 0) + { + break; + } + ptid = ptid_build (pid, 0, status.tid); + if (!in_thread_list (ptid)) + add_thread (ptid); + } + return; + } + + void + procfs_pidlist (char *args, int from_tty) + { + static DIR *dp = NULL; + struct dirent *dirp = NULL; + int fd = -1; + char buf[512]; + procfs_info *pidinfo = NULL; + procfs_debuginfo *info = NULL; + procfs_status *status = NULL; + pid_t num_threads = 0; + pid_t pid; + char name[512]; + + dp = opendir (nto_procfs_path); + if (dp == NULL) + { + printf ("failed to opendir \"%s\" - %d (%s)", nto_procfs_path, errno, + strerror (errno)); + return; + } + + /* start scan at first pid */ + rewinddir (dp); + + do + { + /* Get the right pid and procfs path for the pid */ + do + { + if ((dirp = readdir (dp)) == NULL) + { + closedir (dp); + return; + } + strcat (strcat + (strcat (strcpy (buf, nto_procfs_path), "/"), dirp->d_name), + "/as"); + } + while ((pid = atoi (dirp->d_name)) == 0); + + /* open the procfs path */ + if ((fd = open (buf, O_RDONLY)) == -1) + { + printf ("failed to open %s - %d (%s)\n", buf, errno, + strerror (errno)); + closedir (dp); + return; + } + + pidinfo = (procfs_info *) buf; + if (devctl (fd, DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK) + { + printf ("devctl DCMD_PROC_INFO failed - %d (%s)\n", errno, + strerror (errno)); + break; + } + num_threads = pidinfo->num_threads; + + info = (procfs_debuginfo *) buf; + if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0) != EOK) + strcpy (name, "unavailable"); + else + strcpy (name, info->path); + + /* Collect state info on all the threads. */ + status = (procfs_status *) buf; + for (status->tid = 1; status->tid <= num_threads; status->tid++) + { + if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK + && status->tid != 0) + break; + if (status->tid != 0) + printf_filtered ("%s - %d/%d\n", name, pid, status->tid); + } + close (fd); + } + while (dirp != NULL); + + close (fd); + closedir (dp); + return; + } + + + void + procfs_meminfo (char *args, int from_tty) + { + procfs_mapinfo *mapinfos = NULL; + static int num_mapinfos = 0; + procfs_mapinfo *mapinfo_p, *mapinfo_p2; + int flags = ~0, err, num, i, j; + + struct + { + procfs_debuginfo info; + char buff[_POSIX_PATH_MAX]; + } map; + + struct info + { + unsigned addr; + unsigned size; + unsigned flags; + unsigned debug_vaddr; + unsigned long long offset; + }; + + struct printinfo + { + unsigned long long ino; + unsigned dev; + struct info text; + struct info data; + char name[256]; + } printme; + + + /* Get the number of map entrys */ + if ((err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num)) != EOK) + { + printf ("failed devctl num mapinfos - %d (%s)\n", err, strerror (err)); + return; + } + + mapinfos = xmalloc (num * sizeof (procfs_mapinfo)); + + num_mapinfos = num; + mapinfo_p = mapinfos; + + /* fill the map entrys */ + if ((err = + devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, + num * sizeof (procfs_mapinfo), &num)) != EOK) + { + printf ("failed devctl mapinfos - %d (%s)\n", err, strerror (err)); + xfree (mapinfos); + return; + } + + num = min (num, num_mapinfos); + + /* Run through the list of mapinfo's, and store the data and text info + so we can print it at the bottom of the loop. */ + for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++) + { + if (!(mapinfo_p->flags & flags)) + mapinfo_p->ino = 0; + + if (mapinfo_p->ino == 0) /* already visited */ + continue; + + map.info.vaddr = mapinfo_p->vaddr; + + if ((err = + devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0)) != EOK) + continue; + + memset (&printme, 0, sizeof printme); + printme.dev = mapinfo_p->dev; + printme.ino = mapinfo_p->ino; + printme.text.addr = mapinfo_p->vaddr; + printme.text.size = mapinfo_p->size; + printme.text.flags = mapinfo_p->flags; + printme.text.offset = mapinfo_p->offset; + printme.text.debug_vaddr = map.info.vaddr; + strcpy (printme.name, map.info.path); + + /* check for matching data */ + for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++) + { + if (mapinfo_p2->vaddr != mapinfo_p->vaddr && + mapinfo_p2->ino == mapinfo_p->ino + && mapinfo_p2->dev == mapinfo_p->dev) + { + map.info.vaddr = mapinfo_p2->vaddr; + if ((err = + devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), + 0)) != EOK) + continue; + + if (strcmp (map.info.path, printme.name)) + { + continue; + } + + /* + * lower debug_vaddr is always text, if nessessary, swap + */ + if ((int) map.info.vaddr < (int) printme.text.debug_vaddr) + { + memcpy (&(printme.data), &(printme.text), + sizeof (printme.data)); + printme.text.addr = mapinfo_p2->vaddr; + printme.text.size = mapinfo_p2->size; + printme.text.flags = mapinfo_p2->flags; + printme.text.offset = mapinfo_p2->offset; + printme.text.debug_vaddr = map.info.vaddr; + } + else + { + printme.data.addr = mapinfo_p2->vaddr; + printme.data.size = mapinfo_p2->size; + printme.data.flags = mapinfo_p2->flags; + printme.data.offset = mapinfo_p2->offset; + printme.data.debug_vaddr = map.info.vaddr; + } + mapinfo_p2->ino = 0; + } + } + mapinfo_p->ino = 0; + + printf_filtered ("%s\n", printme.name); + printf_filtered ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size, + printme.text.addr); + printf_filtered ("\t\tflags=%08x\n", printme.text.flags); + printf_filtered ("\t\tdebug=%08x\n", printme.text.debug_vaddr); + printf_filtered ("\t\toffset=%016llx\n", printme.text.offset); + if (printme.data.size) + { + printf_filtered ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size, + printme.data.addr); + printf_filtered ("\t\tflags=%08x\n", printme.data.flags); + printf_filtered ("\t\tdebug=%08x\n", printme.data.debug_vaddr); + printf_filtered ("\t\toffset=%016llx\n", printme.data.offset); + } + printf_filtered ("\tdev=0x%x\n", printme.dev); + printf_filtered ("\tino=0x%x\n", (unsigned int) printme.ino); + } + xfree (mapinfos); + return; + } + + /* Print status information about what we're accessing. */ + + static void + procfs_files_info (ignore) + struct target_ops *ignore; + { + printf_unfiltered ("\tUsing the running image of %s %s via %s.\n", + attach_flag ? "attached" : "child", + target_pid_to_str (inferior_ptid), nto_procfs_path); + } + + /* Mark our target-struct as eligible for stray "run" and "attach" commands. */ + static int + procfs_can_run () + { + return 1; + } + + /* Attach to process PID, then initialize for debugging it */ + static void + procfs_attach (args, from_tty) + char *args; + int from_tty; + { + char *exec_file; + int pid; + + if (!args) + error_no_arg ("process-id to attach"); + + pid = atoi (args); + + if (pid == getpid ()) + error ("Attaching GDB to itself is not a good idea..."); + + if (from_tty) + { + exec_file = (char *) get_exec_file (0); + + if (exec_file) + printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, + target_pid_to_str (pid_to_ptid (pid))); + else + printf_unfiltered ("Attaching to %s\n", + target_pid_to_str (pid_to_ptid (pid))); + + gdb_flush (gdb_stdout); + } + inferior_ptid = do_attach (pid_to_ptid (pid)); + push_target (&procfs_ops); + } + + static ptid_t + do_attach (ptid_t ptid) + { + procfs_status status; + struct sigevent event; + char path[100]; + + sprintf (path, "%s/%d/as", nto_procfs_path, PIDGET (ptid)); + ctl_fd = open (path, O_RDWR); + if (ctl_fd == -1) + { + error ("Couldn't open proc file %s, error %d (%s)", path, errno, + strerror (errno)); + /* NOTREACHED */ + } + if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK) + { + error ("Couldn't stop process"); + /* NOTREACHED */ + } + + /* Define a sigevent for process stopped notification. */ + event.sigev_notify = SIGEV_SIGNAL_THREAD; + event.sigev_signo = SIGUSR1; + event.sigev_code = 0; + event.sigev_value.sival_ptr = NULL; + event.sigev_priority = -1; + devctl (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0); + + if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK) + { + if (status.flags & _DEBUG_FLAG_STOPPED) + { + SignalKill (QNX_NODE, PIDGET (ptid), 0, SIGCONT, 0, 0); + } + } + attach_flag = 1; + nto_init_solib_search_path (); + return ptid; + } + + /* Ask the user what to do when an interrupt is received. */ + + static void + interrupt_query () + { + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ + Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + throw_exception (RETURN_QUIT); + } + + target_terminal_inferior (); + } + + /* The user typed ^C twice. */ + static void + nto_interrupt_twice (signo) + int signo; + { + signal (signo, ofunc); + interrupt_query (); + signal (signo, nto_interrupt_twice); + } + + static void + nto_interrupt (int signo) + { + /* If this doesn't work, try more severe steps. */ + signal (signo, nto_interrupt_twice); + + target_stop (); + } + + static ptid_t + procfs_wait (ptid, ourstatus) + ptid_t ptid; + struct target_waitstatus *ourstatus; + { + sigset_t set; + siginfo_t info; + procfs_status status; + static int exit_signo = 0; /* used to track signals that cause termination */ + + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + + if (ptid_equal (inferior_ptid, null_ptid)) + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_SIGNAL_0; + exit_signo = 0; + return null_ptid; + } + + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + + devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); + while (!(status.flags & _DEBUG_FLAG_ISTOP)) + { + ofunc = (void (*)()) signal (SIGINT, nto_interrupt); + sigwaitinfo (&set, &info); + signal (SIGINT, ofunc); + devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); + } + + if (status.flags & _DEBUG_FLAG_SSTEP) + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_SIGNAL_TRAP; + } + /* Was it a breakpoint? */ + else if (status.flags & _DEBUG_FLAG_TRACE) + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_SIGNAL_TRAP; + } + else if (status.flags & _DEBUG_FLAG_ISTOP) + { + switch (status.why) + { + case _DEBUG_WHY_SIGNALLED: + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = + target_signal_from_host (status.info.si_signo); + exit_signo = 0; + break; + case _DEBUG_WHY_FAULTED: + ourstatus->kind = TARGET_WAITKIND_STOPPED; + if (status.info.si_signo == SIGTRAP) + { + ourstatus->value.sig = 0; + exit_signo = 0; + } + else + { + ourstatus->value.sig = + target_signal_from_host (status.info.si_signo); + exit_signo = ourstatus->value.sig; + } + break; + + case _DEBUG_WHY_TERMINATED: + { + int waitval = 0; + + waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG); + if (exit_signo) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; /* abnormal death */ + ourstatus->value.sig = exit_signo; + } + else + { + ourstatus->kind = TARGET_WAITKIND_EXITED; /* normal death */ + ourstatus->value.integer = WEXITSTATUS (waitval); + } + exit_signo = 0; + break; + } + + case _DEBUG_WHY_REQUESTED: + /* we are assuming a requested stop is due to a SIGINT */ + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_SIGNAL_INT; + exit_signo = 0; + break; + } + } + + return inferior_ptid; + } + + /* + + LOCAL FUNCTION + + procfs_fetch_registers -- fetch current registers from inferior + + SYNOPSIS + + void procfs_fetch_registers (int regno) + + DESCRIPTION + + Read the current values of the inferior's registers, both the + general register set and floating point registers (if supported) + and update gdb's idea of their current values. + + */ + + static void + procfs_fetch_registers (regno) + int regno; + { + union + { + procfs_greg greg; + procfs_fpreg fpreg; + } + reg; + int regsize; + + procfs_set_thread (inferior_ptid); + if (devctl (ctl_fd, DCMD_PROC_GETGREG, ®, sizeof (reg), ®size) == EOK) + { + nto_supply_gregset (®.greg); + } + if (devctl (ctl_fd, DCMD_PROC_GETFPREG, ®, sizeof (reg), ®size) == + EOK) + { + nto_supply_fpregset (®.fpreg); + } + } + + /* + + LOCAL FUNCTION + + procfs_xfer_memory -- copy data to or from inferior memory space + + SYNOPSIS + + int procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, + int dowrite, struct target_ops target) + + DESCRIPTION + + Copy LEN bytes to/from inferior's memory starting at MEMADDR + from/to debugger memory starting at MYADDR. Copy from inferior + if DOWRITE is zero or to inferior if DOWRITE is nonzero. + + Returns the length copied, which is either the LEN argument or + zero. This xfer function does not do partial moves, since procfs_ops + doesn't allow memory operations to cross below us in the target stack + anyway. + + NOTES + + The /proc interface makes this an almost trivial task. + */ + + static int + procfs_xfer_memory (memaddr, myaddr, len, dowrite, attrib, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int dowrite; + struct mem_attrib *attrib; /* ignored */ + struct target_ops *target; /* ignored */ + { + int nbytes = 0; + + if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr) + { + if (dowrite) + { + nbytes = write (ctl_fd, myaddr, len); + } + else + { + nbytes = read (ctl_fd, myaddr, len); + } + if (nbytes < 0) + { + nbytes = 0; + } + } + return (nbytes); + } + + /* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + + static void + procfs_detach (args, from_tty) + char *args; + int from_tty; + { + int siggnal = 0; + + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == 0) + exec_file = ""; + printf_unfiltered ("Detaching from program: %s %s\n", + exec_file, target_pid_to_str (inferior_ptid)); + gdb_flush (gdb_stdout); + } + if (args) + siggnal = atoi (args); + + if (siggnal) + SignalKill (QNX_NODE, PIDGET (inferior_ptid), 0, siggnal, 0, 0); + + close (ctl_fd); + ctl_fd = -1; + init_thread_list (); + inferior_ptid = null_ptid; + attach_flag = 0; + unpush_target (&procfs_ops); /* Pop out of handling an inferior */ + } + + static int + procfs_breakpoint (addr, type, size) + CORE_ADDR addr; + int type; + int size; + { + procfs_break brk; + + brk.type = type; + brk.addr = addr; + brk.size = size; + if ((errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)) != + EOK) + { + return 1; + } + return 0; + } + + static int + procfs_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; + { + return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, 0); + } + + static int + procfs_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; + { + return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, -1); + } + + static int + procfs_insert_hw_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; + { + return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0); + } + + static int + procfs_remove_hw_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; + { + return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1); + } + + static void + procfs_resume (ptid_t ptid, int step, enum target_signal signo) + { + int signal_to_pass; + procfs_status status; + + if (ptid_equal (inferior_ptid, null_ptid)) + return; + + procfs_set_thread (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid : + ptid); + + + run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE; + if (step) + run.flags |= _DEBUG_RUN_STEP; + + sigemptyset ((sigset_t *) & run.fault); + sigaddset ((sigset_t *) & run.fault, FLTBPT); + sigaddset ((sigset_t *) & run.fault, FLTTRACE); + sigaddset ((sigset_t *) & run.fault, FLTILL); + sigaddset ((sigset_t *) & run.fault, FLTPRIV); + sigaddset ((sigset_t *) & run.fault, FLTBOUNDS); + sigaddset ((sigset_t *) & run.fault, FLTIOVF); + sigaddset ((sigset_t *) & run.fault, FLTIZDIV); + sigaddset ((sigset_t *) & run.fault, FLTFPE); + /* Peter V will be changing this at some point... */ + sigaddset ((sigset_t *) & run.fault, FLTPAGE); + + run.flags |= _DEBUG_RUN_ARM; + + sigemptyset (&run.trace); + notice_signals (); + signal_to_pass = target_signal_to_host (signo); + + if (signal_to_pass) + { + devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); + signal_to_pass = target_signal_to_host (signo); + if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED)) + { + if (signal_to_pass != status.info.si_signo) + { + SignalKill (QNX_NODE, PIDGET (inferior_ptid), 0, signal_to_pass, + 0, 0); + run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG; + } + else + { + /* let it kill the program without telling us */ + sigdelset (&run.trace, signal_to_pass); + } + } + } + else + { + run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT; + } + if ((errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0)) != EOK) + { + perror ("run error!\n"); + return; + } + } + + static void + procfs_mourn_inferior () + { + if (!ptid_equal (inferior_ptid, null_ptid)) + { + SignalKill (QNX_NODE, PIDGET (inferior_ptid), 0, SIGKILL, 0, 0); + close (ctl_fd); + } + inferior_ptid = null_ptid; + init_thread_list (); + unpush_target (&procfs_ops); + generic_mourn_inferior (); + attach_flag = 0; + } + + /* This function breaks up an argument string into an argument + * vector suitable for passing to execvp(). + * E.g., on "run a b c d" this routine would get as input + * the string "a b c d", and as output it would fill in argv with + * the four arguments "a", "b", "c", "d". The only additional + * functionality is simple quoting. The gdb command: + * run a "b c d" f + * will fill in argv with the three args "a", "b c d", "e". + */ + static void + breakup_args (scratch, argv) + char *scratch; + char **argv; + { + char *pp, *cp = scratch; + char quoting = 0; + + for (;;) + { + + /* Scan past leading separators */ + quoting = 0; + while (*cp == ' ' || *cp == '\t' || *cp == '\n') + { + cp++; + } + + /* Break if at end of string */ + if (*cp == '\0') + break; + + /* Take an arg */ + if (*cp == '"') + { + cp++; + quoting = strchr (cp, '"') ? 1 : 0; + } + + *argv++ = cp; + + /* Scan for next arg separator */ + pp = cp; + if (quoting) + cp = strchr (pp, '"'); + if ((cp == NULL) || (!quoting)) + cp = strchr (pp, ' '); + if (cp == NULL) + cp = strchr (pp, '\t'); + if (cp == NULL) + cp = strchr (pp, '\n'); + + /* No separators => end of string => break */ + if (cp == NULL) + { + pp = cp; + break; + } + + /* Replace the separator with a terminator */ + *cp++ = '\0'; + } + + /* execv requires a null-terminated arg vector */ + *argv = NULL; + + } + + static void + procfs_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; + { + struct inheritance inherit; + pid_t pid; + int flags, errn; + char **argv, *args; + char *in = "", *out = "", *err = ""; + int fd, fds[3]; + sigset_t set; + + argv = + (char **) xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) * + sizeof (*argv)); + argv[0] = get_exec_file (1); + if (!argv[0]) + { + if (exec_file) + argv[0] = exec_file; + else + return; + } + + args = strdup (allargs); + breakup_args (args, exec_file ? &argv[1] : &argv[0]); + + argv = nto_parse_redirection (argv, &in, &out, &err); + + fds[0] = STDIN_FILENO; + fds[1] = STDOUT_FILENO; + fds[2] = STDERR_FILENO; + + /* If the user specified I/O via gdb's --tty= arg, use it, but only + if the i/o is not also being specified via redirection. */ + if (inferior_io_terminal) + { + if (!in[0]) + in = inferior_io_terminal; + if (!out[0]) + out = inferior_io_terminal; + if (!err[0]) + err = inferior_io_terminal; + } + + if (in[0]) + { + if ((fd = open (in, O_RDONLY)) == -1) + { + perror (in); + } + else + fds[0] = fd; + } + if (out[0]) + { + if ((fd = open (out, O_WRONLY)) == -1) + { + perror (out); + } + else + fds[1] = fd; + } + if (err[0]) + { + if ((fd = open (err, O_WRONLY)) == -1) + { + perror (err); + } + else + fds[2] = fd; + } + + /* Clear any pending SIGUSR1's but keep the behavior the same. */ + signal (SIGUSR1, signal (SIGUSR1, SIG_IGN)); + + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + sigprocmask (SIG_UNBLOCK, &set, NULL); + + memset (&inherit, 0, sizeof (inherit)); + + if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0) + { + inherit.nd = QNX_NODE; + inherit.flags |= SPAWN_SETND; + inherit.flags &= ~SPAWN_EXEC; + } + inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD; + inherit.pgroup = SPAWN_NEWPGROUP; + pid = + spawnp (argv[0], 3, fds, &inherit, argv, + ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0); + xfree (args); + + sigprocmask (SIG_BLOCK, &set, NULL); + + if (pid == -1) + error ("Error spawning %s: %d (%s)", argv[0], errno, strerror (errno)); + + if (fds[0] != STDIN_FILENO) + close (fds[0]); + if (fds[1] != STDOUT_FILENO) + close (fds[1]); + if (fds[2] != STDERR_FILENO) + close (fds[2]); + + inferior_ptid = do_attach (pid_to_ptid (pid)); + + attach_flag = 0; + flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag */ + if ((errn = + devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0)) != EOK) + { + /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n", errn, strerror(errn) ); */ + } + push_target (&procfs_ops); + target_terminal_init (); + + #ifdef SOLIB_CREATE_INFERIOR_HOOK + if (exec_bfd != NULL + || (symfile_objfile != NULL && symfile_objfile->obfd != NULL)) + SOLIB_CREATE_INFERIOR_HOOK (pid); + #endif + } + + static void + procfs_stop () + { + devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0); + } + + static void + procfs_kill_inferior () + { + target_mourn_inferior (); + } + + /* Store register REGNO, or all registers if REGNO == -1, from the contents + of REGISTERS. */ + + static void + procfs_prepare_to_store () + { + } + + void + procfs_store_registers (regno) + int regno; + { + union + { + procfs_greg greg; + procfs_fpreg fpreg; + } + reg; + unsigned first; + unsigned last; + unsigned end; + unsigned off; + unsigned len; + unsigned char subcmd; + char *data; + + if (ptid_equal (inferior_ptid, null_ptid)) + return; + procfs_set_thread (inferior_ptid); + + if (regno == -1) + { + first = 0; + last = NUM_REGS - 1; + } + else + { + first = regno; + last = regno; + } + while (first <= last) + { + end = nto_cpu_register_area (first, last, &subcmd, &off, &len); + switch (subcmd) + { + case NTO_REG_GENERAL: + if (devctl + (ctl_fd, DCMD_PROC_GETGREG, ®.greg, sizeof (reg.greg), + 0) != EOK) + { + printf ("error fetching general registers\n"); + break; + } + data = (char *) ®.greg + off; + if (nto_cpu_register_store (0, first, end, data)) + { + devctl (ctl_fd, DCMD_PROC_SETGREG, ®.greg, + sizeof (reg.greg), 0); + } + break; + case NTO_REG_FLOAT: + if (devctl + (ctl_fd, DCMD_PROC_GETFPREG, ®.fpreg, + sizeof (reg.fpreg), 0) != EOK) + { + /* Do not print a warning. Not all inferiors + have fpregs. */ + break; + } + data = (char *) ®.fpreg + off; + if (nto_cpu_register_store (0, first, end, data)) + { + devctl (ctl_fd, DCMD_PROC_SETFPREG, ®.fpreg, + sizeof (reg.fpreg), 0); + } + break; + case NTO_REG_SYSTEM: + break; + default: + break; + } + first = end + 1; + } + } + + static void + notice_signals (void) + { + int signo; + + for (signo = 1; signo < NSIG; signo++) + { + if (signal_stop_state (target_signal_from_host (signo)) == 0 && + signal_print_state (target_signal_from_host (signo)) == 0 && + signal_pass_state (target_signal_from_host (signo)) == 1) + { + sigdelset (&run.trace, signo); + } + else + { + sigaddset (&run.trace, signo); + } + } + } + + /* + + GLOBAL FUNCTION + + procfs_notice_signals + + SYNOPSIS + + static void procfs_notice_signals (int pid); + + DESCRIPTION + + When the user changes the state of gdb's signal handling via the + "handle" command, this function gets called to see if any change + in the /proc interface is required. It is also called internally + by other /proc interface functions to initialize the state of + the traced signal set. + + One thing it does is that signals for which the state is "nostop", + "noprint", and "pass", have their trace bits reset in the pr_trace + field, so that they are no longer traced. This allows them to be + delivered directly to the inferior without the debugger ever being + involved. + */ + + static void + procfs_notice_signals (pid) + int pid; + { + sigemptyset (&run.trace); + notice_signals (); + } + + static struct tidinfo * + procfs_thread_info (pid_t pid, short tid) + { + /* NYI */ + return NULL; + } + + char * + procfs_pid_to_str (ptid_t ptid) + { + static char buf[1024]; + int pid, tid, n; + struct tidinfo *tip; + + pid = ptid_get_pid (ptid); + tid = ptid_get_tid (ptid); + + n = sprintf (buf, "process %d", pid); + + #if 0 /* NYI */ + tip = procfs_thread_info (pid, tid); + if (tip != NULL) + sprintf (&buf[n], " (state = 0x%02x)", tip->state); + #endif + + return buf; + } + + static void + init_procfs_ops () + { + procfs_ops.to_shortname = "procfs"; + procfs_ops.to_longname = "QNX Neutrino procfs child process"; + procfs_ops.to_doc = + "QNX Neutrino procfs child process (started by the \"run\" command).\n\ + target procfs "; + procfs_ops.to_open = procfs_open; + procfs_ops.to_attach = procfs_attach; + procfs_ops.to_detach = procfs_detach; + procfs_ops.to_resume = procfs_resume; + procfs_ops.to_wait = procfs_wait; + procfs_ops.to_fetch_registers = procfs_fetch_registers; + procfs_ops.to_store_registers = procfs_store_registers; + procfs_ops.to_prepare_to_store = procfs_prepare_to_store; + procfs_ops.to_xfer_memory = procfs_xfer_memory; + procfs_ops.to_files_info = procfs_files_info; + procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint; + procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint; + procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint; + procfs_ops.to_insert_hw_breakpoint = procfs_insert_hw_breakpoint; + procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint; + procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint; + procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint; + procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint; + procfs_ops.to_terminal_init = terminal_init_inferior; + procfs_ops.to_terminal_inferior = terminal_inferior; + procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output; + procfs_ops.to_terminal_ours = terminal_ours; + procfs_ops.to_terminal_info = child_terminal_info; + procfs_ops.to_kill = procfs_kill_inferior; + procfs_ops.to_create_inferior = procfs_create_inferior; + procfs_ops.to_mourn_inferior = procfs_mourn_inferior; + procfs_ops.to_can_run = procfs_can_run; + procfs_ops.to_notice_signals = procfs_notice_signals; + procfs_ops.to_thread_alive = procfs_thread_alive; + procfs_ops.to_find_new_threads = procfs_find_new_threads; + procfs_ops.to_pid_to_str = procfs_pid_to_str; + procfs_ops.to_stop = procfs_stop; + procfs_ops.to_stratum = process_stratum; + procfs_ops.to_has_all_memory = 1; + procfs_ops.to_has_memory = 1; + procfs_ops.to_has_stack = 1; + procfs_ops.to_has_registers = 1; + procfs_ops.to_has_execution = 1; + procfs_ops.to_magic = OPS_MAGIC; + } + + #define OSTYPE_NTO 1 + + void + _initialize_procfs () + { + sigset_t set; + + init_procfs_ops (); + add_target (&procfs_ops); + nto_ostype = OSTYPE_NTO; + + /* We use SIGUSR1 to gain control after we block waiting for a process. + We use sigwaitevent to wait. */ + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + sigprocmask (SIG_BLOCK, &set, NULL); + + /* Set up trace and fault sets, as gdb expects them. */ + sigemptyset (&run.trace); + notice_signals (); + + /* Stuff some information */ + nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags; + nto_cpuinfo_valid = 1; + + add_info ("pidlist", procfs_pidlist, "pidlist"); + add_info ("meminfo", procfs_meminfo, "memory information"); + } + + + static int + procfs_hw_watchpoint (int addr, int len, int type) + { + procfs_break brk; + int err; + + switch (type) + { + case 1: /* Read */ + brk.type = _DEBUG_BREAK_RD; + break; + case 2: /* Read/Write */ + brk.type = _DEBUG_BREAK_RW; + break; + default: /* Modify */ + /* brk.type = _DEBUG_BREAK_RWM; This should work, shouldn't it? I get EINVAL */ + brk.type = _DEBUG_BREAK_RW; + } + brk.type |= _DEBUG_BREAK_HW; /* always ask for HW */ + brk.addr = addr; + brk.size = len; + + if ((err = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)) != EOK) + { + errno = err; + perror ("Failed to set hardware watchpoint"); + return -1; + } + return 0; + } + + static int + procfs_can_use_hw_breakpoint (int type, int cnt, int othertype) + { + return 1; + } + + static int + procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type) + { + return procfs_hw_watchpoint (addr, -1, type); + } + + static int + procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type) + { + return procfs_hw_watchpoint (addr, len, type); + } + + static int + procfs_stopped_by_watchpoint (void) + { + return 0; + } diff -rc3p -N -x '.#*' -x CVS -x'*.cache' -xMakefile.in -x configure src.orig/gdb/nto-share/debug.h src/gdb/nto-share/debug.h *** src.orig/gdb/nto-share/debug.h Wed Dec 31 19:00:00 1969 --- src/gdb/nto-share/debug.h Wed Feb 26 16:36:02 2003 *************** *** 0 **** --- 1,465 ---- + #ifndef _DEBUG_H + #define _DEBUG_H + + /* __DEBUG_H_INCLUDED is Neutrino's native debug.h header. We don't want + these duplicate definitions if we're compiling natively and have already + included it. */ + #ifndef __DEBUG_H_INCLUDED + #define __DEBUG_H_INCLUDED + + #include + #include + #include + + #define QNX_NOTE_NAME "QNX" + + enum Elf_nto_note_types + { + QNT_NULL = 0, + QNT_DEBUG_FULLPATH, + QNT_DEBUG_RELOC, + QNT_STACK, + QNT_GENERATOR, + QNT_DEFAULT_LIB, + QNT_CORE_SYSINFO, + QNT_CORE_INFO, + QNT_CORE_STATUS, + QNT_CORE_GREG, + QNT_CORE_FPREG, + QNT_NUM + }; + + typedef struct + { + long bits[2]; + } nto_sigset_t; + + union nto_sigval + { + int sival_int; + void *sival_ptr; + }; + + typedef struct nto_siginfo + { + int si_signo; + int si_code; /* if SI_NOINFO, only si_signo is valid */ + void (*si_handler) (); + union + { + int _pad[6]; + struct + { + pid_t _pid; + union + { + struct + { + union nto_sigval _value; + uid_t _uid; + } _kill; /* si_code <= 0 SI_FROMUSER */ + struct + { + int _status; /* CLD_EXITED status, else signo */ + clock_t _utime; + clock_t _stime; + } _chld; /* si_signo=SIGCHLD si_code=CLD_* */ + } _pdata; + } _proc; + struct + { + int _fltno; + void *_addr; + void *_fltip; + } _fault; /* si_signo=SIGSEGV,ILL,FPE,TRAP,BUS */ + } _data; + } nto_siginfo_t; + + typedef struct arm_cpu_registers + { + unsigned gpr[16]; + unsigned spsr; + } ARM_CPU_REGISTERS; + + typedef struct arm_fpu_registers + { + /* + * There is no architecturally defined FPU + */ + unsigned __dummy; + } ARM_FPU_REGISTERS; + + typedef struct arm_alt_registers + { + union + { + struct xscale_cp0 + { + unsigned acc0_lo; + unsigned acc0_hi; + } xscale; + } un; + } ARM_ALT_REGISTERS; + + typedef union + { + unsigned long long u64; + double f; + } mipsfloat; + + typedef struct mips_cpu_registers + { + unsigned regs[74]; + unsigned long long regs_alignment; + } MIPS_CPU_REGISTERS; + + typedef struct mips_fpu_registers + { + mipsfloat fpr[32]; + unsigned fpcr31; + } MIPS_FPU_REGISTERS; + + typedef struct mips_alt_registers + { + union + { + struct mips_tx79 + { + unsigned long long gpr_hi[32]; + unsigned long long lo1; + unsigned long long hi1; + unsigned sa; + } tx79; + } un; + } MIPS_ALT_REGISTERS; + + #ifdef __BIGREGS__ + typedef unsigned long long ppcint; + #else + typedef unsigned ppcint; + #endif + + typedef union + { + unsigned long long u64; + double f; + } ppcfloat; + + typedef union + { + unsigned long long u64[2]; + unsigned u32[4]; + unsigned char u8[16]; + float f32[4]; + } ppcvmx; + + typedef struct ppc_cpu_registers + { + ppcint gpr[32]; + ppcint ctr; + ppcint lr; + ppcint msr; + ppcint iar; + unsigned cr; + unsigned xer; + unsigned ear; /* not present on all chips */ + unsigned mq; /* only on the 601 */ + unsigned vrsave; /* on Altivec CPU's, SPR256 */ + } PPC_CPU_REGISTERS; + + typedef struct ppc_fpu_registers + { + ppcfloat fpr[32]; + unsigned fpscr; + unsigned fpscr_val; + /* load/store of fpscr is done through fprs, the real value is in [32,63] of a fpr. + fpscr is the address for lfd, stfd. fpscr_val is the real value of fpscr */ + } PPC_FPU_REGISTERS; + + typedef struct ppc_vmx_registers + { + ppcvmx vmxr[32]; + ppcvmx vscr; + } PPC_VMX_REGISTERS; + + typedef struct ppc_alt_registers + { + PPC_VMX_REGISTERS vmx; + } PPC_ALT_REGISTERS; + + typedef unsigned shint; + + typedef unsigned shfloat; + + typedef struct sh_cpu_registers + { + shint gr[16]; + shint sr; + shint pc; + /* shint dbr; */ + shint gbr; + shint mach; + shint macl; + shint pr; + } SH_CPU_REGISTERS; + + typedef struct sh_fpu_registers + { + shfloat fpr_bank0[16]; + shfloat fpr_bank1[16]; + unsigned fpul; + unsigned fpscr; + } SH_FPU_REGISTERS; + + typedef struct sh_alt_registers + { + /* + * There are no architecturally defined alt regs + */ + unsigned __dummy; + } SH_ALT_REGISTERS; + + typedef struct x86_cpu_registers + { + #ifdef __SEGMENTS__ + unsigned gs, fs; + unsigned es, ds; + #endif + unsigned edi, esi, ebp, exx, ebx, edx, ecx, eax; + unsigned eip, cs, efl; + unsigned esp, ss; + } X86_CPU_REGISTERS; + + typedef struct fsave_area + { + unsigned fpu_control_word; + unsigned fpu_status_word; + unsigned fpu_tag_word; + unsigned fpu_ip; + unsigned fpu_cs; + unsigned fpu_op; + unsigned fpu_ds; + unsigned char st_regs[80]; /* each register is 10 bytes! */ + } X86_FSAVE_REGISTERS; + + typedef struct fxsave_area + { + unsigned short fpu_control_word; + unsigned short fpu_status_word; + unsigned short fpu_tag_word; + unsigned short fpu_operand; + unsigned fpu_ip; + unsigned fpu_cs; + unsigned fpu_op; + unsigned fpu_ds; + unsigned mxcsr; + unsigned reserved; + unsigned char st_regs[128]; + unsigned char xmm_regs[128]; + unsigned char reserved2[224]; + } X86_FXSAVE_REGISTERS; + + typedef union x86_fpu_registers + { + X86_FSAVE_REGISTERS fsave_area; + X86_FXSAVE_REGISTERS fxsave_area; + unsigned char data[512]; /* Needs to be this big for the emulator. */ + } X86_FPU_REGISTERS; + + #ifdef __QNX__ + __BEGIN_DECLS + #include <_pack64.h> + #endif + #define _DEBUG_FLAG_STOPPED 0x00000001 /* Thread is not running */ + #define DEBUG_FLAG_ISTOP 0x00000002 /* Stopped at point of interest */ + #define _DEBUG_FLAG_IPINVAL 0x00000010 /* IP is not valid */ + #define _DEBUG_FLAG_ISSYS 0x00000020 /* System process */ + #define _DEBUG_FLAG_SSTEP 0x00000040 /* Stopped because of single step */ + #define _DEBUG_FLAG_CURTID 0x00000080 /* Thread is current thread */ + #define DEBUG_FLAG_TRACE_EXEC 0x00000100 /* Stopped because of breakpoint */ + #define _DEBUG_FLAG_TRACE_RD 0x00000200 /* Stopped because of read access */ + #define _DEBUG_FLAG_TRACE_WR 0x00000400 /* Stopped because of write access */ + #define _DEBUG_FLAG_TRACE_MODIFY 0x00000800 /* Stopped because of modified memory */ + #define _DEBUG_FLAG_RLC 0x00010000 /* Run-on-Last-Close flag is set */ + #define _DEBUG_FLAG_KLC 0x00020000 /* Kill-on-Last-Close flag is set */ + #define _DEBUG_FLAG_FORK 0x00040000 /* Child inherits flags (Stop on fork/spawn) */ + #define _DEBUG_FLAG_MASK 0x000f0000 /* Flags that can be changed */ + enum + { + _DEBUG_WHY_REQUESTED, + _DEBUG_WHY_SIGNALLED, + _DEBUG_WHY_FAULTED, + _DEBUG_WHY_JOBCONTROL, + _DEBUG_WHY_TERMINATED, + _DEBUG_WHY_CHILD, + _DEBUG_WHY_EXEC + }; + + #define _DEBUG_RUN_CLRSIG 0x00000001 /* Clear pending signal */ + #define _DEBUG_RUN_CLRFLT 0x00000002 /* Clear pending fault */ + #define DEBUG_RUN_TRACE 0x00000004 /* Trace mask flags interesting signals */ + #define DEBUG_RUN_HOLD 0x00000008 /* Hold mask flags interesting signals */ + #define DEBUG_RUN_FAULT 0x00000010 /* Fault mask flags interesting faults */ + #define _DEBUG_RUN_VADDR 0x00000020 /* Change ip before running */ + #define _DEBUG_RUN_STEP 0x00000040 /* Single step only one thread */ + #define _DEBUG_RUN_STEP_ALL 0x00000080 /* Single step one thread, other threads run */ + #define _DEBUG_RUN_CURTID 0x00000100 /* Change current thread (target thread) */ + #define DEBUG_RUN_ARM 0x00000200 /* Deliver event at point of interest */ + + typedef struct _debug_process_info + { + pid_t pid; + pid_t parent; + unsigned flags; + unsigned umask; + pid_t child; + pid_t sibling; + pid_t pgrp; + pid_t sid; + int base_address; + int initial_stack; + uid_t uid; + gid_t gid; + uid_t euid; + gid_t egid; + uid_t suid; + gid_t sgid; + nto_sigset_t sig_ignore; + nto_sigset_t sig_queue; + nto_sigset_t sig_pending; + unsigned num_chancons; + unsigned num_fdcons; + unsigned num_threads; + unsigned num_timers; + unsigned long long reserved[20]; + } nto_procfs_info; + + typedef struct _debug_thread_info + { + pid_t pid; + unsigned tid; + unsigned flags; + unsigned short why; + unsigned short what; + int ip; + int sp; + int stkbase; + int tls; + unsigned stksize; + unsigned tid_flags; + unsigned char priority; + unsigned char real_priority; + unsigned char policy; + unsigned char state; + short syscall; + unsigned short last_cpu; + unsigned timeout; + int last_chid; + nto_sigset_t sig_blocked; + nto_sigset_t sig_pending; + nto_siginfo_t info; + unsigned reserved1; + union + { + struct + { + unsigned tid; + } join; + struct + { + int id; + int sync; + } sync; + struct + { + unsigned nid; + pid_t pid; + int coid; + int chid; + int scoid; + } connect; + struct + { + int chid; + } channel; + struct + { + pid_t pid; + int vaddr; + unsigned flags; + } waitpage; + struct + { + unsigned size; + } stack; + unsigned long long filler[4]; + } blocked; + unsigned long long reserved2[8]; + } nto_procfs_status; + + typedef union _debug_gregs + { + ARM_CPU_REGISTERS arm; + MIPS_CPU_REGISTERS mips; + PPC_CPU_REGISTERS ppc; + SH_CPU_REGISTERS sh; + X86_CPU_REGISTERS x86; + unsigned long long padding[1024]; + } nto_gregset_t; + + typedef union _debug_fpregs + { + /* ARM_FPU_REGISTERS arm; */ + MIPS_FPU_REGISTERS mips; + PPC_FPU_REGISTERS ppc; + SH_FPU_REGISTERS sh; + X86_FPU_REGISTERS x86; + unsigned long long padding[1024]; + } nto_fpregset_t; + + typedef union _debug_altregs + { + ARM_ALT_REGISTERS arm; + MIPS_ALT_REGISTERS mips; + PPC_ALT_REGISTERS ppc; + /* SH_ALT_REGISTERS sh; */ + /* X86_ALT_REGISTERS x86; */ + unsigned long long padding[1024]; + } debug_altreg_t; + + /* Keep this consistant with neutrino syspage.h */ + enum + { + CPUTYPE_X86, + CPUTYPE_PPC, + CPUTYPE_MIPS, + CPUTYPE_SPARE, + CPUTYPE_ARM, + CPUTYPE_SH, + CPUTYPE_UNKNOWN + }; + + enum + { + OSTYPE_QNX4, + OSTYPE_NTO + }; + + #ifdef __QNX__ + #include <_packpop.h> + + __END_DECLS + #endif + + #endif /* __DEBUG_H_INCLUDED */ + + /* these correspond to the DSMSG_* versions in dsmsgs.h */ + enum + { + NTO_REG_GENERAL, + NTO_REG_FLOAT, + NTO_REG_SYSTEM, + NTO_REG_ALT + }; + + #endif /* _DEBUG_H */ diff -rc3p -N -x '.#*' -x CVS -x'*.cache' -xMakefile.in -x configure src.orig/gdb/nto-tdep.c src/gdb/nto-tdep.c *** src.orig/gdb/nto-tdep.c Wed Dec 31 19:00:00 1969 --- src/gdb/nto-tdep.c Wed Feb 26 10:38:28 2003 *************** *** 0 **** --- 1,368 ---- + /* nto-tdep.c - general QNX Neutrino target functionality */ + + /* Copyright 2003 Free Software Foundation */ + + /* This code was donated by QNX Software Systems Ltd. */ + + #include + #include + #include "nto-tdep.h" + #include "top.h" + #include "cli/cli-decode.h" + #include "cli/cli-cmds.h" + #include "inferior.h" + #include "gdbarch.h" + #include "bfd.h" + #include "elf-bfd.h" + #include "solib-svr4.h" + #include "gdbcore.h" + + #ifdef __CYGWIN__ + #include + #endif + + #ifdef __CYGWIN__ + static char default_nto_target[] = "C:\\QNXsdk\\target\\qnx6"; + #elif defined(__sun__) || defined(linux) + static char default_nto_target[] = "/opt/QNXsdk/target/qnx6"; + #else + static char default_nto_target[] = ""; + #endif + + /* Maintenance debugging flag */ + int nto_internal_debugging; + + /* Filled in cpu info structure and flag to indicate its validity. + * This is initialized in procfs_attach or nto_start_remote depending on + * our host/target. It would only be invalid if we were talking to an + * older pdebug which didn't support the cpuinfo message. */ + unsigned nto_cpuinfo_flags; + int nto_cpuinfo_valid; + int nto_ostype = -1; + + static char * + nto_target (void) + { + char *p = getenv ("QNX_TARGET"); + + #ifdef __CYGWIN__ + static char buf[PATH_MAX]; + if (p) + cygwin_conv_to_posix_path (p, buf); + else + cygwin_conv_to_posix_path (default_nto_target, buf); + return buf; + #else + return p ? p : default_nto_target; + #endif + } + + /* Take a string such as i386, rs6000, etc. and map it onto CPUTYPE_X86, + CPUTYPE_PPC, etc. as defined in nto-share/dsmsgs.h */ + int + nto_map_arch_to_cputype(const char *arch) + { + if(!strcmp(arch, "i386") || !strcmp(arch, "x86")) + return CPUTYPE_X86; + if(!strcmp(arch, "rs6000") || !strcmp(arch, "ppc")) + return CPUTYPE_PPC; + if(!strcmp(arch, "mips")) + return CPUTYPE_MIPS; + if(!strcmp(arch, "arm")) + return CPUTYPE_ARM; + if(!strcmp(arch, "sh")) + return CPUTYPE_SH; + return CPUTYPE_UNKNOWN; + } + + int + nto_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname) + { + char *buf, arch_path[PATH_MAX], *nto_root, *endian; + const char *arch; + char *path_fmt = "%s/lib:%s/usr/lib:%s/usr/photon/lib\ + :%s/usr/photon/dll:%s/lib/dll"; + + nto_root = nto_target (); + if (strcmp (TARGET_ARCHITECTURE->arch_name, "i386") == 0) + { + arch = "x86"; + endian = ""; + } + else if (strcmp (TARGET_ARCHITECTURE->arch_name, "rs6000") == 0) + { + arch = "ppc"; + endian = "be"; + } + else + { + arch = TARGET_ARCHITECTURE->arch_name; + endian = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "be" : "le"; + } + + sprintf (arch_path, "%s/%s%s", nto_root, arch, endian); + + buf = alloca (strlen(path_fmt) + strlen(arch_path) * 5 + 1); + sprintf (buf, path_fmt, arch_path, arch_path, arch_path, arch_path, arch_path); + + return openp(buf, 1, solib, o_flags, 0, temp_pathname); + } + + void + nto_init_solib_search_path (void) + { + char buf[PATH_MAX * 2], arch_path[PATH_MAX]; + char *nto_root, *endian; + const char *arch; + char *solib_search_path, *cmd_name = "solib-search-path"; + struct cmd_list_element *c; + + c = lookup_cmd (&cmd_name, setlist, "", 1, 1); + + if (!c || !c->var) + return; + + solib_search_path = *((char **) c->var); + + if (solib_search_path != NULL) + return; + + nto_root = nto_target (); + if (strcmp (TARGET_ARCHITECTURE->arch_name, "i386") == 0) + { + arch = "x86"; + endian = ""; + } + else if (strcmp (TARGET_ARCHITECTURE->arch_name, "rs6000") == 0) + { + arch = "ppc"; + endian = "be"; + } + else + { + arch = TARGET_ARCHITECTURE->arch_name; + endian = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "be" : "le"; + } + + sprintf (arch_path, "%s/%s%s", nto_root, arch, endian); + + sprintf (buf, "set solib-absolute-prefix %s", arch_path); + execute_command (buf, 0); + + #if 0 + sprintf (buf, "%s/lib:%s/usr/lib:%s/usr/photon/lib\ + :%s/usr/photon/dll:%s/lib/dll", arch_path, arch_path, arch_path, arch_path, arch_path); + /* we already looked up the command...might as well use it */ + *((char **) c->var) = xstrdup (buf); + #endif + } + + char ** + nto_parse_redirection (char *pargv[], char **pin, char **pout, char **perr) + { + char **argv; + char *in, *out, *err, *p; + int argc, i, n; + + for (n = 0; pargv[n]; n++); + if (n == 0) + return NULL; + in = ""; + out = ""; + err = ""; + + argv = xcalloc (n + 1, sizeof argv[0]); + argc = n; + for (i = 0, n = 0; n < argc; n++) + { + p = pargv[n]; + if (*p == '>') + { + p++; + if (*p) + out = p; + else + out = pargv[++n]; + } + else if (*p == '<') + { + p++; + if (*p) + in = p; + else + in = pargv[++n]; + } + else if (*p++ == '2' && *p++ == '>') + { + if (*p == '&' && *(p + 1) == '1') + err = out; + else if (*p) + err = p; + else + err = pargv[++n]; + } + else + argv[i++] = pargv[n]; + } + *pin = in; + *pout = out; + *perr = err; + return argv; + } + + void + nto_source_extra_gdbinit (char *file) + { + char *homedir, *homeinit; + struct stat statbuf; + + homedir = getenv ("HOME"); + + if (homedir && !inhibit_gdbinit) + { + homeinit = (char *) alloca (strlen (homedir) + strlen (file) + 10); + sprintf (homeinit, "%s/%s", homedir, file); + if (stat (homeinit, &statbuf) == 0) + catch_command_errors (source_command, homeinit, 0, RETURN_MASK_ALL); + } + } + + /* struct lm_info, LM_ADDR, and nto_truncate_ptr are copied from + solib-svr4.c to support nto_relocate_section_addresses + which is different from the svr4 version. */ + + struct lm_info + { + /* Pointer to copy of link map from inferior. The type is char * + rather than void *, so that we may use byte offsets to find the + various fields without the need for a cast. */ + char *lm; + }; + + static CORE_ADDR + LM_ADDR (struct so_list *so) + { + struct link_map_offsets *lmo = nto_fetch_link_map_offsets (); + + return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + + lmo->l_addr_offset, + lmo->l_addr_size); + } + + static CORE_ADDR + nto_truncate_ptr (CORE_ADDR addr) + { + if (TARGET_PTR_BIT == sizeof (CORE_ADDR) * 8) + /* We don't need to truncate anything, and the bit twiddling below + will fail due to overflow problems. */ + return addr; + else + return addr & (((CORE_ADDR) 1 << TARGET_PTR_BIT) - 1); + } + + Elf_Internal_Phdr * + find_load_phdr (bfd *abfd) + { + Elf_Internal_Phdr *phdr; + unsigned int i; + + if (!elf_tdata (abfd)) + return NULL; + + phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) + { + if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X)) + return phdr; + } + return NULL; + } + + void + nto_relocate_section_addresses (struct so_list *so, struct section_table *sec) + { + /* On some platforms, (ie. QNXnto, NetBSD) LM_ADDR is the assigned + address, not the offset. + The addresses are formed as follows: + LM_ADDR is the target address where the shared library file + is mapped, so the actual section start address is LM_ADDR plus + the section offset within the shared library file. The end + address is that plus the section length. Note that we pay no + attention to the section start address as recorded in the + library header. + */ + Elf_Internal_Phdr *phdr = find_load_phdr (sec->bfd); + unsigned vaddr = phdr ? phdr->p_vaddr : 0; + + sec->addr = nto_truncate_ptr (sec->addr + LM_ADDR (so) - vaddr); + sec->endaddr = nto_truncate_ptr (sec->endaddr + LM_ADDR (so) - vaddr); + } + + static void + fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + CORE_ADDR reg_addr; + { + nto_gregset_t gregset; + nto_fpregset_t fpregset; + + nto_init_solib_search_path (); + + if (which == 0) + { + memcpy ((char *) &gregset, core_reg_sect, + min (core_reg_size, sizeof (gregset))); + nto_supply_gregset (&gregset); + } + else if (which == 2) + { + memcpy ((char *) &fpregset, core_reg_sect, + min (core_reg_size, sizeof (fpregset))); + nto_supply_fpregset (&fpregset); + } + } + + /* Register that we are able to handle ELF file formats using standard + procfs "regset" structures. */ + + static struct core_fns regset_core_fns = { + bfd_target_elf_flavour, /* core_flavour */ + default_check_format, /* check_format */ + default_core_sniffer, /* core_sniffer */ + fetch_core_registers, /* core_read_registers */ + NULL /* next */ + }; + + void + _initialize_nto_tdep () + { + add_show_from_set (add_set_cmd ("nto-debug", class_maintenance, var_zinteger, (char *) &nto_internal_debugging, "Set QNX NTO internal debugging.\n\ + When non-zero, nto specific debug info is\n\ + displayed. Different information is displayed\n\ + for different positive values.", &setdebuglist), + &showdebuglist); + + /* We use SIG45 for pulses, or something, so nostop, noprint + and pass them. */ + signal_stop_update (target_signal_from_name ("SIG45"), 0); + signal_print_update (target_signal_from_name ("SIG45"), 0); + signal_pass_update (target_signal_from_name ("SIG45"), 1); + + /* by default we don't want to stop on these two, but we do want to pass */ + #if defined(SIGSELECT) + signal_stop_update (SIGSELECT, 0); + signal_print_update (SIGSELECT, 0); + signal_pass_update (SIGSELECT, 1); + #endif + + #if defined(SIGPHOTON) + signal_stop_update (SIGPHOTON, 0); + signal_print_update (SIGPHOTON, 0); + signal_pass_update (SIGPHOTON, 1); + #endif + + /* register core file support */ + add_core_fns (®set_core_fns); + } diff -rc3p -N -x '.#*' -x CVS -x'*.cache' -xMakefile.in -x configure src.orig/gdb/nto-tdep.h src/gdb/nto-tdep.h *** src.orig/gdb/nto-tdep.h Wed Dec 31 19:00:00 1969 --- src/gdb/nto-tdep.h Mon Feb 24 17:07:10 2003 *************** *** 0 **** --- 1,63 ---- + /* nto-tdep.h - QNX Neutrino target header */ + + /* Copyright 2003 Free Software Foundation */ + + /* This code was donated by QNX Software Systems Ltd. */ + + #ifndef _NTO_TDEP_H + #define _NTO_TDEP_H + + #include "defs.h" + #include "nto-share/debug.h" + #include "solist.h" + + /* Generic functions in nto-tdep.c */ + + extern void nto_init_solib_search_path PARAMS ((void)); + + char **nto_parse_redirection + PARAMS ((char *start_argv[], char **in, char **out, char **err)); + + int proc_iterate_over_mappings PARAMS ((int (*func) (int, CORE_ADDR))); + + void nto_source_extra_gdbinit PARAMS ((char *)); + + void nto_relocate_section_addresses + PARAMS ((struct so_list *, struct section_table *)); + + int nto_map_arch_to_cputype PARAMS((const char *)); + + int nto_find_and_open_solib PARAMS((char *, unsigned, char **)); + + /* Functions exported from all Neutrino targets (-nto-tdep.c) */ + + unsigned nto_get_regset_id PARAMS ((int regno)); + + void nto_cpu_regset_fetch PARAMS ((int endian, int regset, void *data)); + + unsigned nto_get_regset_area PARAMS ((unsigned regset, char *subcmd)); + + unsigned nto_cpu_register_area + PARAMS ((unsigned first_regno, unsigned last_regno, unsigned char *subcmd, + unsigned *off, unsigned *len)); + + void nto_cpu_register_fetch + PARAMS ((int endian, unsigned first_regno, unsigned last_regno, void *data)); + + int nto_cpu_register_store + PARAMS ((int endian, unsigned first_regno, unsigned last_regno, void *data)); + + void nto_supply_gregset PARAMS ((union _debug_gregs *)); + + void nto_supply_fpregset PARAMS ((union _debug_fpregs *)); + + struct link_map_offsets *nto_fetch_link_map_offsets PARAMS ((void)); + + /* Globals */ + + extern int nto_internal_debugging; + extern unsigned nto_cpuinfo_flags; + extern int nto_cpuinfo_valid; + extern int nto_ostype; + + #endif