From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3601 invoked by alias); 5 Jun 2009 19:41:00 -0000 Received: (qmail 3579 invoked by uid 22791); 5 Jun 2009 19:40:50 -0000 X-SWARE-Spam-Status: No, hits=-1.0 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_35,J_CHICKENPOX_42,J_CHICKENPOX_43,J_CHICKENPOX_63,J_CHICKENPOX_65,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS,ZMIde_GENERICSPAM1 X-Spam-Check-By: sourceware.org Received: from main.gmane.org (HELO ciao.gmane.org) (80.91.229.2) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 05 Jun 2009 19:40:40 +0000 Received: from list by ciao.gmane.org with local (Exim 4.43) id 1MCfHG-0004zm-JX for gdb@sources.redhat.com; Fri, 05 Jun 2009 19:40:35 +0000 Received: from entropy.qnx.com ([209.226.137.107]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 05 Jun 2009 19:40:34 +0000 Received: from aristovski by entropy.qnx.com with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 05 Jun 2009 19:40:34 +0000 To: gdb@sources.redhat.com From: Aleksandar Ristovski Subject: Re: corelow and threads question Date: Fri, 05 Jun 2009 19:41:00 -0000 Message-ID: References: <200906052025.10264.pedro@codesourcery.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------030708060204000908000405" User-Agent: Thunderbird 2.0.0.21 (Windows/20090302) In-Reply-To: <200906052025.10264.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2009-06/txt/msg00055.txt.bz2 This is a multi-part message in MIME format. --------------030708060204000908000405 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1708 Pedro Alves wrote: > On Friday 05 June 2009 19:54:54, Aleksandar Ristovski wrote: > >> With corelow.c patched as proposed, on Neutrino I could do this: >> >> For NTO, I "hijack" core_ops: >> static void >> init_nto_core_ops () >> { >> struct target_ops *core_ops; >> >> core_ops = find_core_target (); >> gdb_assert (core_ops && core_ops->to_shortname != NULL >> && !!"core_ops must be initialized first!"); >> original_core_ops = *core_ops; >> core_ops->to_extra_thread_info = >> nto_target_extra_thread_info; >> core_ops->to_open = nto_core_open; >> core_ops->to_xfer_partial = nto_core_xfer_partial; >> core_ops->to_pid_to_str = nto_pid_to_str; >> } > > As I mentioned in the other threads, this is fine as a local change, > but not so to have in GDB proper, so it does go against > your goal of pushing all your local changes. :-/ > > This is depending on the order of which the _initialize > routines are called, hence the gdb_assert. I just cleaned > up the only left over target that was doing a similar hack > (sol-threads.c) a couple of months ago, to not do so. > > Again, it's hard to come up with a better alternative > without knowing what you're doing in those overrides. Maybe > what you need is a thread_stratum target sitting on top of > nto-procfs.c or corelow.c. Maybe we need new gdbarch > callbacks. > Ok, I attached my nto-diff (work-in-progress) that compile with current gdb HEAD sources (with some tweaks in configure scripts). You will see all my hacks there. I am inclined to think that core_ops is the right way to go; at which point should I do a "push_target" in that case? -- Aleksandar Ristovski QNX Software Systems --------------030708060204000908000405 Content-Type: text/x-patch; name="nto.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="nto.diff" Content-length: 46511 Index: gdb/corelow.c =================================================================== RCS file: /cvs/src/src/gdb/corelow.c,v retrieving revision 1.86 diff -u -p -r1.86 corelow.c --- gdb/corelow.c 5 Jun 2009 18:08:53 -0000 1.86 +++ gdb/corelow.c 5 Jun 2009 19:37:14 -0000 @@ -395,12 +395,6 @@ core_open (char *filename, int from_tty) previous session, and the frame cache being stale. */ registers_changed (); - /* Build up thread list from BFD sections, and possibly set the - current thread to the .reg/NN section matching the .reg - section. */ - bfd_map_over_sections (core_bfd, add_to_thread_list, - bfd_get_section_by_name (core_bfd, ".reg")); - post_create_inferior (&core_ops, from_tty); /* Now go through the target stack looking for threads since there @@ -748,6 +742,13 @@ core_pid_to_str (struct target_ops *ops, return buf; } +static void +core_find_new_threads (struct target_ops *ops) +{ + if (core_bfd) + bfd_map_over_sections (core_bfd, add_to_thread_list, NULL); +} + /* Fill in core_ops with its defined operations and properties. */ static void @@ -775,6 +776,7 @@ init_core_ops (void) core_ops.to_has_stack = 1; core_ops.to_has_registers = 1; core_ops.to_magic = OPS_MAGIC; + core_ops.to_find_new_threads = core_find_new_threads; } void Index: gdb/i386-nto-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/i386-nto-tdep.c,v retrieving revision 1.32 diff -u -p -r1.32 i386-nto-tdep.c --- gdb/i386-nto-tdep.c 22 Feb 2009 01:02:17 -0000 1.32 +++ gdb/i386-nto-tdep.c 5 Jun 2009 19:37:14 -0000 @@ -33,9 +33,7 @@ #include "nto-tdep.h" #include "solib.h" #include "solib-svr4.h" - -/* Target vector for QNX NTO x86. */ -static struct nto_target_ops i386_nto_target; +#include "elf-bfd.h" #ifndef X86_CPU_FXSR #define X86_CPU_FXSR (1L << 12) @@ -126,6 +124,8 @@ i386nto_regset_id (int regno) return NTO_REG_GENERAL; else if (regno < I386_NUM_GREGS + I386_NUM_FREGS) return NTO_REG_FLOAT; + else if (regno < I386_SSE_NUM_REGS) + return NTO_REG_FLOAT; /* We store xmm registers in fxsave_area. */ return -1; /* Error. */ } @@ -134,6 +134,7 @@ static int i386nto_register_area (struct gdbarch *gdbarch, int regno, int regset, unsigned *off) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); int len; *off = 0; @@ -149,30 +150,98 @@ i386nto_register_area (struct gdbarch *g } else if (regset == NTO_REG_FLOAT) { - unsigned off_adjust, regsize, regset_size; + unsigned off_adjust, regsize, regset_size, regno_base; + /* The following are flags indicating number in our fxsave_area. */ + int first_four = (regno >= I387_FCTRL_REGNUM (tdep) + && regno <= I387_FISEG_REGNUM (tdep)); + int second_four = (regno > I387_FISEG_REGNUM (tdep) + && regno <= I387_FOP_REGNUM (tdep)); + int st_reg = (regno >= I387_ST0_REGNUM (tdep) + && regno < I387_ST0_REGNUM (tdep) + 8); + int xmm_reg = (regno >= I387_XMM0_REGNUM (tdep) + && regno < I387_MXCSR_REGNUM (tdep)); if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) { - off_adjust = 32; - regsize = 16; regset_size = 512; + /* fxsave_area structure. */ + if (first_four) + { + /* fpu_control_word, fpu_status_word, fpu_tag_word, fpu_operand + registers. */ + regsize = 2; /* Two bytes each. */ + off_adjust = 0; + regno_base = I387_FCTRL_REGNUM (tdep); + } + else if (second_four) + { + /* fpu_ip, fpu_cs, fpu_op, fpu_ds registers. */ + regsize = 4; + off_adjust = 8; + regno_base = I387_FISEG_REGNUM (tdep) + 1; + } + else if (st_reg) + { + /* ST registers. */ + regsize = 16; + off_adjust = 32; + regno_base = I387_ST0_REGNUM (tdep); + } + else if (xmm_reg) + { + /* XMM registers. */ + regsize = 16; + off_adjust = 160; + regno_base = I387_XMM0_REGNUM (tdep); + } + else if (regno == I387_MXCSR_REGNUM (tdep)) + { + regsize = 4; + off_adjust = 24; + regno_base = I387_MXCSR_REGNUM (tdep); + } + else + { + /* Whole regset. */ + gdb_assert (regno == -1); + off_adjust = 0; + regno_base = 0; + regsize = regset_size; + } } else { - off_adjust = 28; - regsize = 10; - regset_size = 128; + regset_size = 108; + /* fsave_area structure. */ + if (first_four || second_four) + { + /* fpu_control_word, ... , fpu_ds registers. */ + regsize = 4; + off_adjust = 0; + regno_base = I387_FCTRL_REGNUM (tdep); + } + else if (st_reg) + { + /* One of ST registers. */ + regsize = 10; + off_adjust = 7 * 4; + regno_base = I387_ST0_REGNUM (tdep); + } + else + { + /* Whole regset. */ + gdb_assert (regno == -1); + off_adjust = 0; + regno_base = 0; + regsize = regset_size; + } } - if (regno == -1) - return regset_size; - - *off = (regno - gdbarch_fp0_regnum (gdbarch)) * regsize + off_adjust; - return 10; - /* Why 10 instead of regsize? 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. */ + if (regno != -1) + *off = off_adjust + (regno - regno_base) * regsize; + else + *off = 0; + return regsize; } return -1; } @@ -217,8 +286,6 @@ i386nto_sigtramp_p (struct frame_info *t return name && strcmp ("__signalstub", name) == 0; } -#define I386_NTO_SIGCONTEXT_OFFSET 136 - /* Assuming THIS_FRAME is a QNX Neutrino sigtramp routine, return the address of the associated sigcontext structure. */ @@ -226,33 +293,34 @@ static CORE_ADDR i386nto_sigcontext_addr (struct frame_info *this_frame) { char buf[4]; - CORE_ADDR sp; + CORE_ADDR ptrctx; - get_frame_register (this_frame, I386_ESP_REGNUM, buf); - sp = extract_unsigned_integer (buf, 4); + /* We store __ucontext_t addr in EDI register. */ + get_frame_register (this_frame, I386_EDI_REGNUM, buf); + ptrctx = extract_unsigned_integer (buf, 4); + ptrctx += 24 /* Context pointer is at this offset. */; - return sp + I386_NTO_SIGCONTEXT_OFFSET; + return ptrctx; } static void init_i386nto_ops (void) { - i386_nto_target.regset_id = i386nto_regset_id; - i386_nto_target.supply_gregset = i386nto_supply_gregset; - i386_nto_target.supply_fpregset = i386nto_supply_fpregset; - i386_nto_target.supply_altregset = nto_dummy_supply_regset; - i386_nto_target.supply_regset = i386nto_supply_regset; - i386_nto_target.register_area = i386nto_register_area; - i386_nto_target.regset_fill = i386nto_regset_fill; - i386_nto_target.fetch_link_map_offsets = - svr4_ilp32_fetch_link_map_offsets; + nto_regset_id = i386nto_regset_id; + nto_supply_gregset = i386nto_supply_gregset; + nto_supply_fpregset = i386nto_supply_fpregset; + nto_supply_altregset = nto_dummy_supply_regset; + nto_supply_regset = i386nto_supply_regset; + nto_register_area = i386nto_register_area; + nto_regset_fill = i386nto_regset_fill; + nto_fetch_link_map_offsets = svr4_ilp32_fetch_link_map_offsets; } + static void i386nto_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - static struct target_so_ops nto_svr4_so_ops; /* Deal with our strange signals. */ nto_initialize_signals (); @@ -270,8 +338,8 @@ i386nto_init_abi (struct gdbarch_info in tdep->sigtramp_p = i386nto_sigtramp_p; tdep->sigcontext_addr = i386nto_sigcontext_addr; - tdep->sc_pc_offset = 56; - tdep->sc_sp_offset = 68; + tdep->sc_reg_offset = i386nto_gregset_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (i386nto_gregset_reg_offset); /* Setjmp()'s return PC saved in EDX (5). */ tdep->jb_pc_offset = 20; /* 5x32 bit ints in. */ @@ -279,31 +347,17 @@ i386nto_init_abi (struct gdbarch_info in set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); - /* Initialize this lazily, to avoid an initialization order - dependency on solib-svr4.c's _initialize routine. */ - if (nto_svr4_so_ops.in_dynsym_resolve_code == NULL) - { - nto_svr4_so_ops = svr4_so_ops; + /* Our loader handles solib relocations differently than svr4. */ + svr4_so_ops.relocate_section_addresses = nto_relocate_section_addresses; - /* Our loader handles solib relocations differently than svr4. */ - nto_svr4_so_ops.relocate_section_addresses - = nto_relocate_section_addresses; - - /* Supply a nice function to find our solibs. */ - nto_svr4_so_ops.find_and_open_solib - = nto_find_and_open_solib; - - /* Our linker code is in libc. */ - nto_svr4_so_ops.in_dynsym_resolve_code - = nto_in_dynsym_resolve_code; - } - set_solib_ops (gdbarch, &nto_svr4_so_ops); + /* Supply a nice function to find our solibs. */ + svr4_so_ops.find_and_open_solib = nto_find_and_open_solib; - nto_set_target (&i386_nto_target); -} + /* Our linker code is in libc. */ + svr4_so_ops.in_dynsym_resolve_code = nto_in_dynsym_resolve_code; -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_i386nto_tdep; + set_solib_ops (gdbarch, &svr4_so_ops); +} void _initialize_i386nto_tdep (void) Index: gdb/nto-procfs.c =================================================================== RCS file: /cvs/src/src/gdb/nto-procfs.c,v retrieving revision 1.44 diff -u -p -r1.44 nto-procfs.c --- gdb/nto-procfs.c 27 May 2009 18:28:31 -0000 1.44 +++ gdb/nto-procfs.c 5 Jun 2009 19:37:14 -0000 @@ -47,10 +47,19 @@ #define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\ _DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY) +/* Typedefs, we use gdb specific type names... to be consistent, + we use them here too. */ +typedef debug_thread_t nto_procfs_status; +typedef debug_process_t nto_procfs_info; + +extern int nto_stopped_by_watchpoint (void); + static struct target_ops procfs_ops; int ctl_fd; +extern unsigned int nto_inferior_stopped_flags; + static void (*ofunc) (); static procfs_run run; @@ -63,8 +72,6 @@ static int procfs_xfer_memory (CORE_ADDR struct mem_attrib *attrib, struct target_ops *); -static void notice_signals (void); - static void init_procfs_ops (void); static ptid_t do_attach (ptid_t ptid); @@ -75,7 +82,7 @@ static int procfs_insert_hw_watchpoint ( static int procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type); -static int procfs_stopped_by_watchpoint (void); +static void procfs_notice_signals (ptid_t ptid); /* These two globals are only ever set in procfs_open(), but are referenced elsewhere. 'nto_procfs_node' is a flag used to say @@ -103,12 +110,6 @@ nto_node (void) return (node); } -static enum gdb_osabi -procfs_is_nto_target (bfd *abfd) -{ - return GDB_OSABI_QNXNTO; -} - /* 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 @@ -123,8 +124,6 @@ procfs_open (char *arg, int from_tty) procfs_sysinfo *sysinfo; struct cleanup *cleanups; - nto_is_nto_target = procfs_is_nto_target; - /* Set the default node used for spawning to this one, and only override it if there is a valid arg. */ @@ -220,11 +219,94 @@ static int procfs_thread_alive (struct target_ops *ops, ptid_t ptid) { pid_t tid; + pid_t pid; + procfs_status status; + int err; tid = ptid_get_tid (ptid); - if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK) - return 1; - return 0; + pid = ptid_get_pid (ptid); + + if (kill (pid, 0) == -1) + return 0; + + status.tid = tid; + if ((err = devctl (ctl_fd, DCMD_PROC_TIDSTATUS, + &status, sizeof (status), 0)) != EOK) + return 0; + + /* Thread is alive or dead but not yet joined, + or dead and there is an alive (or dead unjoined) thread with + higher tid. We return tidinfo. + + Client should check if the tid is the same as + requested; if not, requested tid is dead. */ + return (status.tid == tid) && (status.state != STATE_DEAD); +} + +static void +update_thread_private_data_name (struct thread_info *new_thread, + const char *newname) +{ + int newnamelen; + struct private_thread_info *pti; + gdb_assert (newname != NULL); + gdb_assert (new_thread != NULL); + + newnamelen = strlen (newname); + + if (!new_thread->private) + { + new_thread->private = xmalloc (sizeof (struct private_thread_info) + + newnamelen + 1); + memcpy (new_thread->private->name, newname, newnamelen + 1); + } + else if (strcmp (newname, new_thread->private->name) != 0) + { + /* Reallocate if neccessary. */ + int oldnamelen = strlen (new_thread->private->name); + if (oldnamelen < newnamelen) + new_thread->private = xrealloc (new_thread->private, + sizeof (struct private_thread_info) + + newnamelen + 1); + memcpy (new_thread->private->name, newname, newnamelen + 1); + } +} + +static void +update_thread_private_data (struct thread_info *new_thread, + pthread_t tid, int state, int flags) +{ + struct private_thread_info *pti; + procfs_info pidinfo; + struct _thread_name *tn; + procfs_threadctl tctl; +#if _NTO_VERSION > 630 + gdb_assert (new_thread != NULL); + + if (devctl (ctl_fd, DCMD_PROC_INFO, &pidinfo, + sizeof(pidinfo), 0) != EOK) + return; + + memset (&tctl, 0, sizeof (tctl)); + tctl.cmd = _NTO_TCTL_NAME; + tn = (struct _thread_name *) (&tctl.data); + + /* Fetch name for the given thread. */ + tctl.tid = tid; + tn->name_buf_len = sizeof (tctl.data) - sizeof (*tn); + tn->new_name_len = -1; /* Getting, not setting. */ + if (devctl (ctl_fd, DCMD_PROC_THREADCTL, &tctl, sizeof (tctl), NULL) != EOK) + tn->name_buf[0] = '\0'; + + tn->name_buf[_NTO_THREAD_NAME_MAX] = '\0'; + + update_thread_private_data_name (new_thread, tn->name_buf); + + pti = (struct private_thread_info *) new_thread->private; + pti->tid = tid; + pti->state = state; + pti->flags = flags; +#endif /* _NTO_VERSION */ } void @@ -233,20 +315,37 @@ procfs_find_new_threads (struct target_o procfs_status status; pid_t pid; ptid_t ptid; + pthread_t tid; + struct thread_info *new_thread; if (ctl_fd == -1) return; pid = ptid_get_pid (inferior_ptid); - for (status.tid = 1;; ++status.tid) + status.tid = 1; + + for (tid = 1;; ++tid) { - if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0) - != EOK && status.tid != 0) + if (status.tid == tid + && (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0) + != EOK)) break; - ptid = ptid_build (pid, 0, status.tid); - if (!in_thread_list (ptid)) - add_thread (ptid); + if (status.tid != tid) + { + /* The reason why this would not be equal is that devctl might have + returned different tid, meaning the requested tid no longer exists + (e.g. thread exited). */ + /* if (in_thread_list (ptid)) + delete_thread (ptid); */ + continue; + } + ptid = ptid_build (pid, 0, tid); + new_thread = find_thread_ptid (ptid); + if (!new_thread) + new_thread = add_thread (ptid); + update_thread_private_data (new_thread, tid, status.state, 0); + status.tid++; } return; } @@ -626,11 +725,11 @@ procfs_wait (struct target_ops *ops, ptid_t ptid, struct target_waitstatus *ourstatus, int options) { sigset_t set; - siginfo_t info; procfs_status status; static int exit_signo = 0; /* To track signals that cause termination. */ ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + nto_inferior_stopped_flags = 0; if (ptid_equal (inferior_ptid, null_ptid)) { @@ -646,12 +745,19 @@ procfs_wait (struct target_ops *ops, devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); while (!(status.flags & _DEBUG_FLAG_ISTOP)) { + siginfo_t info; + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGUSR1); ofunc = (void (*)()) signal (SIGINT, nto_interrupt); sigwaitinfo (&set, &info); signal (SIGINT, ofunc); devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); } + nto_inferior_stopped_flags = status.flags; + if (status.flags & _DEBUG_FLAG_SSTEP) { ourstatus->kind = TARGET_WAITKIND_STOPPED; @@ -690,9 +796,6 @@ procfs_wait (struct target_ops *ops, case _DEBUG_WHY_TERMINATED: { - int waitval = 0; - - waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG); if (exit_signo) { /* Abnormal death. */ @@ -703,7 +806,7 @@ procfs_wait (struct target_ops *ops, { /* Normal death. */ ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = WEXITSTATUS (waitval); + ourstatus->value.integer = status.what; } exit_signo = 0; break; @@ -774,6 +877,39 @@ procfs_xfer_memory (CORE_ADDR memaddr, g return (nbytes); } +static LONGEST +procfs_xfer_partial (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +{ + if (object == TARGET_OBJECT_AUXV + && readbuf) + { + int err; + CORE_ADDR initial_stack; + nto_procfs_info procinfo; + + if (offset > 0) + return 0; + + err = devctl (ctl_fd, DCMD_PROC_INFO, &procinfo, sizeof procinfo, 0); + if (err != EOK) + return -1; + + /* Similar as in the case of a core file, we read auxv from + initial_stack. */ + initial_stack = procinfo.initial_stack; + + /* procfs is always 'self-hosted', no byte-order manipulation. */ + return nto_read_auxv_from_initial_stack (initial_stack, readbuf, len); + } + + if (ops->beneath && ops->beneath->to_xfer_partial) + return ops->beneath->to_xfer_partial (ops, object, annex, readbuf, + writebuf, offset, len); + return -1; +} + /* 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 @@ -882,14 +1018,17 @@ procfs_resume (struct target_ops *ops, run.flags |= _DEBUG_RUN_ARM; sigemptyset (&run.trace); - notice_signals (); + procfs_notice_signals (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid : + ptid); 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 ((status.why == _DEBUG_WHY_REQUESTED) + || (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))) { if (signal_to_pass != status.info.si_signo) { @@ -897,7 +1036,7 @@ procfs_resume (struct target_ops *ops, signal_to_pass, 0, 0); run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG; } - else /* Let it kill the program without telling us. */ + else /* Let it kill the program without telling us. */ sigdelset (&run.trace, signal_to_pass); } } @@ -1230,7 +1369,7 @@ procfs_store_registers (struct target_op } static void -notice_signals (void) +procfs_notice_signals (ptid_t ptid) { int signo; @@ -1245,18 +1384,6 @@ notice_signals (void) } } -/* 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. */ -static void -procfs_notice_signals (ptid_t ptid) -{ - sigemptyset (&run.trace); - notice_signals (); -} - static struct tidinfo * procfs_thread_info (pid_t pid, short tid) { @@ -1303,6 +1430,7 @@ init_procfs_ops (void) procfs_ops.to_store_registers = procfs_store_registers; procfs_ops.to_prepare_to_store = procfs_prepare_to_store; procfs_ops.deprecated_xfer_memory = procfs_xfer_memory; + procfs_ops.to_xfer_partial = procfs_xfer_partial; procfs_ops.to_files_info = procfs_files_info; procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint; procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint; @@ -1311,7 +1439,7 @@ init_procfs_ops (void) 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_stopped_by_watchpoint = nto_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; @@ -1334,6 +1462,7 @@ init_procfs_ops (void) procfs_ops.to_has_execution = 1; procfs_ops.to_magic = OPS_MAGIC; procfs_ops.to_have_continuable_watchpoint = 1; + procfs_ops.to_extra_thread_info = nto_target_extra_thread_info; } #define OSTYPE_NTO 1 @@ -1361,8 +1490,6 @@ _initialize_procfs (void) add_info ("pidlist", procfs_pidlist, _("pidlist")); add_info ("meminfo", procfs_meminfo, _("memory information")); - - nto_is_nto_target = procfs_is_nto_target; } Index: gdb/nto-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/nto-tdep.c,v retrieving revision 1.32 diff -u -p -r1.32 nto-tdep.c --- gdb/nto-tdep.c 22 May 2009 23:49:13 -0000 1.32 +++ gdb/nto-tdep.c 5 Jun 2009 19:37:15 -0000 @@ -34,22 +34,38 @@ #include "gdbcore.h" #include "objfiles.h" -#include +#include "gdbcmd.h" +#include "safe-ctype.h" +#include "gdb_assert.h" + +#include "observer.h" + + +#include +#include +#define __ELF_H_INCLUDED /* Needed for our link.h to avoid including elf.h. */ +#include +typedef debug_thread_t nto_procfs_status; +typedef debug_process_t nto_procfs_info; + +#define QNX_NOTE_NAME "QNX" #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 + +/* The following define does a cast to const gdb_byte * type. */ + +#define EXTRACT_SIGNED_INTEGER(ptr, len) extract_signed_integer ((const gdb_byte *)(ptr), len) +#define EXTRACT_UNSIGNED_INTEGER(ptr, len) extract_unsigned_integer ((const gdb_byte *)(ptr), len) + static char default_nto_target[] = ""; -#endif struct nto_target_ops current_nto_target; +unsigned int nto_inferior_stopped_flags; + static char * nto_target (void) { @@ -67,19 +83,6 @@ nto_target (void) #endif } -void -nto_set_target (struct nto_target_ops *targ) -{ - nto_regset_id = targ->regset_id; - nto_supply_gregset = targ->supply_gregset; - nto_supply_fpregset = targ->supply_fpregset; - nto_supply_altregset = targ->supply_altregset; - nto_supply_regset = targ->supply_regset; - nto_register_area = targ->register_area; - nto_regset_fill = targ->regset_fill; - nto_fetch_link_map_offsets = targ->fetch_link_map_offsets; -} - /* 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 @@ -98,13 +101,16 @@ nto_map_arch_to_cputype (const char *arc return CPUTYPE_UNKNOWN; } -int -nto_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname) +/* Helper function, calculates architecture path, e.g. + /opt/qnx640/target/qnx6/ppcbe + It allocates string, callers must free the string using free. */ + +static char * +nto_build_arch_path () { - char *buf, *arch_path, *nto_root, *endian, *base; - const char *arch; - int ret; -#define PATH_FMT "%s/lib:%s/usr/lib:%s/usr/photon/lib:%s/usr/photon/dll:%s/lib/dll" + const char *nto_root, *arch, *endian; + char *arch_path; + const char *variant_suffix = ""; nto_root = nto_target (); if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name, "i386") == 0) @@ -127,16 +133,39 @@ nto_find_and_open_solib (char *solib, un == BFD_ENDIAN_BIG ? "be" : "le"; } + if (strcmp (arch, "ppc") == 0) + { + struct bfd_arch_info const *info = + gdbarch_bfd_arch_info (current_gdbarch); + + if (info->mach == bfd_mach_ppc_e500) + variant_suffix = "-spe"; + } + /* In case nto_root is short, add strlen(solib) so we can reuse arch_path below. */ arch_path = - alloca (strlen (nto_root) + strlen (arch) + strlen (endian) + 2 + - strlen (solib)); - sprintf (arch_path, "%s/%s%s", nto_root, arch, endian); + malloc (strlen (nto_root) + strlen (arch) + strlen (endian) + + strlen (variant_suffix) + 2); + sprintf (arch_path, "%s/%s%s%s", nto_root, arch, endian, variant_suffix); + return arch_path; +} +int +nto_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname) +{ + char *buf, *arch_path, *base; + const char *arch; + int ret; +#define PATH_FMT "%s/lib%c%s/usr/lib%c%s/usr/photon/lib%c" \ + "%s/usr/photon/dll%c%s/lib/dll" + + arch_path = nto_build_arch_path (); buf = alloca (strlen (PATH_FMT) + strlen (arch_path) * 5 + 1); - sprintf (buf, PATH_FMT, arch_path, arch_path, arch_path, arch_path, - arch_path); + sprintf (buf, PATH_FMT, arch_path, DIRNAME_SEPARATOR, + arch_path, DIRNAME_SEPARATOR, arch_path, DIRNAME_SEPARATOR, + arch_path, DIRNAME_SEPARATOR, arch_path); + free (arch_path); /* Don't assume basename() isn't destructive. */ base = strrchr (solib, '/'); @@ -148,51 +177,54 @@ nto_find_and_open_solib (char *solib, un ret = openp (buf, 1, base, o_flags, temp_pathname); if (ret < 0 && base != solib) { - sprintf (arch_path, "/%s", solib); - ret = open (arch_path, o_flags, 0); + sprintf (buf, "/%s", solib); + ret = open (buf, o_flags, 0); if (temp_pathname) { if (ret >= 0) - *temp_pathname = gdb_realpath (arch_path); + *temp_pathname = gdb_realpath (buf); else - **temp_pathname = '\0'; + *temp_pathname = NULL; } } return ret; } +/* The following two variables are defined in solib.c. */ +extern char *gdb_sysroot; /* a.k.a solib-absolute-prefix */ + void nto_init_solib_absolute_prefix (void) { - char buf[PATH_MAX * 2], arch_path[PATH_MAX]; - char *nto_root, *endian; - const char *arch; - - nto_root = nto_target (); - if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name, "i386") == 0) - { - arch = "x86"; - endian = ""; - } - else if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name, - "rs6000") == 0 - || strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name, - "powerpc") == 0) - { - arch = "ppc"; - endian = "be"; - } - else + /* If it was nto_init_solib_absolute_prefix that set the path, + the following variable will be set to 1. */ + static int nto_set_gdb_sysroot; + + char *buf, *arch_path; + + arch_path = nto_build_arch_path (); + + /* Do not change it if already set. */ + if ((!gdb_sysroot + || strlen (gdb_sysroot) == 0) + || nto_set_gdb_sysroot) { - arch = gdbarch_bfd_arch_info (target_gdbarch)->arch_name; - endian = gdbarch_byte_order (target_gdbarch) - == BFD_ENDIAN_BIG ? "be" : "le"; + buf = alloca (26 /* set solib-absolute-prefix */ + + strlen (arch_path) + 1); + if (gdb_sysroot == NULL || gdb_sysroot[0] == '\0') + { + /* Initially, only set the string. We don't want any side effects. */ + xfree (gdb_sysroot); + gdb_sysroot = xstrdup (arch_path); + } + else + { + sprintf (buf, "set solib-absolute-prefix %s", arch_path); + execute_command (buf, 0); + } + nto_set_gdb_sysroot = 1; } - - sprintf (arch_path, "%s/%s%s", nto_root, arch, endian); - - sprintf (buf, "set solib-absolute-prefix %s", arch_path); - execute_command (buf, 0); + free (arch_path); } char ** @@ -268,22 +300,20 @@ struct lm_info address changes, we may need a different offset, we want to warn about the difference and compute it only once. */ CORE_ADDR l_addr; - - /* The target location of lm. */ - CORE_ADDR lm_addr; }; - static CORE_ADDR -LM_ADDR (struct so_list *so) +LM_ADDR_FROM_LINK_MAP (struct so_list *so) { + struct link_map_offsets *lmo = nto_fetch_link_map_offsets (); + if (so->lm_info->l_addr == (CORE_ADDR)-1) { - struct link_map_offsets *lmo = nto_fetch_link_map_offsets (); struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; - so->lm_info->l_addr = - extract_typed_address (so->lm_info->lm + lmo->l_addr_offset, ptr_type); + so->lm_info->l_addr = extract_typed_address (so->lm_info->lm + + lmo->l_addr_offset, + ptr_type); } return so->lm_info->l_addr; } @@ -326,8 +356,16 @@ nto_relocate_section_addresses (struct s 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); + sec->addr = nto_truncate_ptr (sec->addr + + LM_ADDR_FROM_LINK_MAP (so) + - vaddr); + sec->endaddr = nto_truncate_ptr (sec->endaddr + + LM_ADDR_FROM_LINK_MAP (so) + - vaddr); + if (so->addr_low == 0) + so->addr_low = LM_ADDR_FROM_LINK_MAP (so); + if (so->addr_high < sec->endaddr) + so->addr_high = sec->endaddr; } /* This is cheating a bit because our linker code is in libc.so. If we @@ -341,38 +379,95 @@ nto_in_dynsym_resolve_code (CORE_ADDR pc } void -nto_generic_supply_gpregset (const struct regset *regset, - struct regcache *regcache, int regnum, - const void *gregs, size_t len) +nto_dummy_supply_regset (struct regcache *regcache, char *regs) { } -void -nto_generic_supply_fpregset (const struct regset *regset, - struct regcache *regcache, int regnum, - const void *fpregs, size_t len) +static void +nto_sniff_abi_note_section (bfd *abfd, asection *sect, void *obj) { -} + const char *sectname; + unsigned int sectsize; + char *note; // buffer holding the section contents + unsigned int namelen, type; + const char *name; + + sectname = bfd_get_section_name (abfd, sect); + sectsize = bfd_section_size (abfd, sect); + + /* TODO: limit the note size here, for now limit is 128 bytes + (enough to check the name and type). */ + if (sectsize > 128) + sectsize = 128; -void -nto_generic_supply_altregset (const struct regset *regset, - struct regcache *regcache, int regnum, - const void *altregs, size_t len) -{ -} + if (sectname == strstr(sectname, "note")) + { + note = alloca (sectsize); + bfd_get_section_contents (abfd, sect, note, 0, sectsize); + namelen = (unsigned int) bfd_h_get_32 (abfd, note); + name = note + 12; + + if (namelen != strlen (QNX_NOTE_NAME) + 1 + || 0 != strcmp (name, QNX_NOTE_NAME)) + goto not_ours; + + type = (unsigned int) bfd_h_get_32 (abfd, note + 8); + + switch (type) + { + case QNT_NULL: + gdb_assert (0); + break; + case QNT_CORE_SYSINFO: + *(enum gdb_osabi *) obj = GDB_OSABI_QNXNTO; + break; + case QNT_CORE_INFO: + break; + } -void -nto_dummy_supply_regset (struct regcache *regcache, char *regs) -{ - /* Do nothing. */ +not_ours: + { /* We do nothing here. */ } + } } enum gdb_osabi nto_elf_osabi_sniffer (bfd *abfd) { - if (nto_is_nto_target) - return nto_is_nto_target (abfd); - return GDB_OSABI_UNKNOWN; + unsigned int elfosabi; + unsigned int elftype; + enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; + + /* Note: if we ever get to sign our binaries, we should + really check if the OSABI matches. But untill then, just + hope the user knows what they are doing and are really opening + QNXNTO binary. */ + + elftype = elf_elfheader (abfd)->e_type; + + if (elftype == ET_CORE) + /* We do properly mark our core files, get the OSABI from + core note section. */ + bfd_map_over_sections (abfd, + nto_sniff_abi_note_section, + &osabi); + else + /* Note: if we ever get to sign our binaries, we should + really check if the OSABI matches. But untill then, just + hope the user knows what they are doing and are really opening + QNXNTO binary. */ + osabi = GDB_OSABI_QNXNTO; + + if (nto_internal_debugging) + gdb_assert (osabi == GDB_OSABI_QNXNTO); + return osabi; +} + +char * +nto_target_extra_thread_info (struct thread_info *ti) +{ + if (ti && ti->private && ti->private->name[0]) + return ti->private->name; + return ""; } void @@ -398,12 +493,361 @@ nto_initialize_signals (void) #endif } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_nto_tdep; +static void +show_nto_debug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("QNX NTO debug level is %d.\n"), nto_internal_debugging); +} + +static int +nto_print_tidinfo_callback (struct thread_info *tp, void *data) +{ + char star = ' '; + int tid = 0; + int state = 0; + int flags = 0; + + if (tp) + { + if (ptid_equal (tp->ptid, inferior_ptid)) + star = '*'; + + if (tp->private) + { + tid = tp->private->tid; + state = tp->private->state; + flags = tp->private->flags; + } + else + tid = ptid_get_tid (tp->ptid); + + printf_filtered ("%c%d\t%d\t%d\n", star, tid, state, flags); + } + + return 0; +} + +static void +nto_info_tidinfo_command (char *args, int from_tty) +{ + char *execfile = get_exec_file (0); + + target_find_new_threads (); + printf_filtered("Threads for pid %d (%s)\nTid:\tState:\tFlags:\n", + ptid_get_pid (inferior_ptid), execfile ? execfile : ""); + + iterate_over_threads (nto_print_tidinfo_callback, NULL); +} + + +char * +nto_pid_to_str (struct target_ops *ops, 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 thread %d", pid, tid); + + return buf; +} + + +/* NTO Core handling. */ + +extern struct gdbarch *core_gdbarch; + +/* Add thread status for the given gdb_thread_id. */ + +static void +nto_core_add_thread_status_info (pid_t core_pid, int gdb_thread_id, const nto_procfs_status *ps) +{ + struct thread_info *ti; + ptid_t ptid; + struct private_thread_info *priv; + struct gdbarch *curr_gdbarch = current_gdbarch; + + /* See corelow, function add_to_thread_list for details on pid. */ + ptid = ptid_build (core_pid, 0, gdb_thread_id); + ti = find_thread_ptid (ptid); + if (!ti) + ti = add_thread (ptid); + if(!ti) + { + warning ("Thread with gdb id %d not found.\n", gdb_thread_id); + return; + } + priv = malloc (sizeof (*priv)); + if (priv == NULL) + { + warning ("Out of memory.\n"); + return; + } + memset (priv, 0, sizeof (*priv)); + ti->private = priv; + if (core_gdbarch != current_gdbarch) + /* Dirty hack - current_gdbarch is not the same, and we need + core_gdbarch for endiannes. */ + current_gdbarch = core_gdbarch; + priv->tid = EXTRACT_UNSIGNED_INTEGER (&ps->tid, sizeof (ps->tid)); + priv->state = EXTRACT_UNSIGNED_INTEGER (&ps->state, sizeof (ps->state)); + priv->flags = EXTRACT_UNSIGNED_INTEGER (&ps->flags, sizeof (ps->flags)); + if (curr_gdbarch != current_gdbarch) + current_gdbarch = curr_gdbarch; +} + +/* Add thread statuses read from qnx notes. */ +static void +nto_core_add_thread_private_data (bfd *abfd, asection *sect, void *notused) +{ + const char *sectname; + unsigned int sectsize; + const char qnx_core_status[] = ".qnx_core_status/"; + const unsigned int qnx_sectnamelen = 17;/* strlen (qnx_core_status). */ + const char warning_msg[] = "Unable to read %s section from core.\n"; + int gdb_thread_id; + int data_ofs; + nto_procfs_status status; + int len; + + sectname = bfd_get_section_name (abfd, sect); + sectsize = bfd_section_size (abfd, sect); + if (sectsize > sizeof (status)) + sectsize = sizeof (status); + + if (strncmp (sectname, qnx_core_status, qnx_sectnamelen) != 0) + return; + + if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0) + { + warning (warning_msg, sectname); + return; + } + len = bfd_bread ((gdb_byte *)&status, sectsize, abfd); + if (len != sectsize) + { + warning (warning_msg, sectname); + return; + } + gdb_thread_id = atoi (sectname + qnx_sectnamelen); + nto_core_add_thread_status_info (elf_tdata (abfd)->core_pid, gdb_thread_id, &status); +} + +struct target_ops original_core_ops; + +static void +nto_core_solib_create_inferior_hook (void) +{ + /* Do nothing. */ +} + +struct auxv_buf +{ + LONGEST len; + LONGEST len_read; /* For passing result. Can be len, 0, or -1 */ + gdb_byte *readbuf; +}; + +/* Read AUXV from initial_stack. */ +LONGEST +nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack, gdb_byte *readbuf, + LONGEST len) +{ + int data_ofs = 0; + int anint32; + LONGEST len_read = 0; + gdb_byte *panint32 = (gdb_byte*)&anint32; + gdb_byte *buff; + + /* Skip over argc, argv and envp... (see comment in ldd.c) */ + if (target_read_memory (initial_stack + data_ofs, panint32, 4) != 0) + return 0; + + anint32 = EXTRACT_UNSIGNED_INTEGER (panint32, sizeof (anint32)); + + /* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */ + data_ofs += (anint32 + 2) * 4; /* + 2 comes from argc itself and + NULL terminating pointer in argv */ + + /* Now loop over env table: */ + while (target_read_memory (initial_stack + data_ofs, panint32, 4) == 0) + { + anint32 = EXTRACT_SIGNED_INTEGER (panint32, sizeof (anint32)); + data_ofs += 4; + if (anint32 == 0) + break; + } + initial_stack += data_ofs; + + memset (readbuf, 0, len); + buff = readbuf; + while (len_read <= len-8) + { + /* For 32-bit architecture, size of auxv_t is 8 bytes. */ + + /* Search backwards until we have read AT_PHDR (num. 3), + AT_PHENT (num 4), AT_PHNUM (num 5) */ + if (target_read_memory (initial_stack, buff, 8) + == 0) + { + int a_type = EXTRACT_SIGNED_INTEGER (buff, sizeof (a_type)); + if (a_type != AT_NULL) + { + buff += 8; + len_read += 8; + } + if (a_type == AT_PHNUM) /* That's all we need. */ + break; + initial_stack += 8; + } + else + break; + } + return len_read; +} + +/* Read AUXV from note. */ +static void +nto_core_read_auxv_from_note (bfd *abfd, asection *sect, void *pauxv_buf) +{ + struct auxv_buf *auxv_buf = (struct auxv_buf *)pauxv_buf; + const char *sectname; + unsigned int sectsize; + const char qnx_core_info[] = ".qnx_core_info/"; + const unsigned int qnx_sectnamelen = 14;/* strlen (qnx_core_status). */ + const char warning_msg[] = "Unable to read %s section from core.\n"; + int data_ofs; + nto_procfs_info info; + int len; + gdb_byte *buff; /* For skipping over argc, argv and envp-s */ + int anint32; + CORE_ADDR initial_stack, base_address; + + sectname = bfd_get_section_name (abfd, sect); + sectsize = bfd_section_size (abfd, sect); + if (sectsize > sizeof (info)) + sectsize = sizeof (info); + + if (strncmp (sectname, qnx_core_info, qnx_sectnamelen) != 0) + return; + + if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0) + { + warning (warning_msg, sectname); + return; + } + len = bfd_bread ((gdb_byte *)&info, sectsize, abfd); + if (len != sectsize) + { + warning (warning_msg, sectname); + return; + } + initial_stack = EXTRACT_UNSIGNED_INTEGER + (&info.initial_stack, sizeof (info.initial_stack)); + base_address = EXTRACT_UNSIGNED_INTEGER + (&info.base_address, sizeof (info.base_address)); + buff = auxv_buf->readbuf; + + auxv_buf->len_read = nto_read_auxv_from_initial_stack + (initial_stack, auxv_buf->readbuf, auxv_buf->len); +} + +static LONGEST +nto_core_xfer_partial (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +{ + if (object == TARGET_OBJECT_AUXV + && readbuf) + { + struct auxv_buf auxv_buf; + + auxv_buf.len = len; + auxv_buf.len_read = 0; + auxv_buf.readbuf = readbuf; + + if (offset > 0) + return 0; + + bfd_map_over_sections (core_bfd, nto_core_read_auxv_from_note, &auxv_buf); + if (auxv_buf.len_read > 0) + return auxv_buf.len_read; + } + + /* In any other case, try default code. */ + return original_core_ops.to_xfer_partial (ops, object, annex, readbuf, + writebuf, offset, len); +} + +static void +nto_core_open (char *filename, int from_tty) +{ + original_core_ops.to_open (filename, from_tty); +} + + +static void +nto_find_new_threads_in_core (struct target_ops *ops) +{ + if (core_bfd) + bfd_map_over_sections (core_bfd, nto_core_add_thread_private_data, NULL); +} + + +static void +init_nto_core_ops () +{ + struct target_ops *core_ops; + + core_ops = find_core_target (); + gdb_assert (core_ops && core_ops->to_shortname != NULL + && !!"core_ops must be initialized first!"); + original_core_ops = *core_ops; + core_ops->to_extra_thread_info = nto_target_extra_thread_info; + core_ops->to_open = nto_core_open; + core_ops->to_xfer_partial = nto_core_xfer_partial; + core_ops->to_pid_to_str = nto_pid_to_str; + core_ops->to_find_new_threads = nto_find_new_threads_in_core; +} + +int +nto_stopped_by_watchpoint (void) +{ + /* NOTE: nto_stopped_by_watchpoint will be called ONLY while we are + stopped due to a SIGTRAP. This assumes gdb works in 'all-stop' mode; + future gdb versions will likely run in 'non-stop' mode in which case + we will have to store/examine statuses per thread in question. + Until then, this will work fine. */ + + return nto_inferior_stopped_flags + & (_DEBUG_FLAG_TRACE_RD + | _DEBUG_FLAG_TRACE_WR + | _DEBUG_FLAG_TRACE_MODIFY); +} + + +static void +nto_architecture_changed_listener (struct gdbarch *newarch) +{ + nto_init_solib_absolute_prefix (); +} + + +/* Prevent corelow.c from adding core_ops target. We will do it + after overriding some of the default functions. See comment in + corelow.c for details. */ +int coreops_suppress_target = 1; + void _initialize_nto_tdep (void) { + init_nto_core_ops (); + add_setshow_zinteger_cmd ("nto-debug", class_maintenance, &nto_internal_debugging, _("\ Set QNX NTO internal debugging."), _("\ @@ -412,6 +856,13 @@ When non-zero, nto specific debug info i displayed. Different information is displayed\n\ for different positive values."), NULL, - NULL, /* FIXME: i18n: QNX NTO internal debugging is %s. */ - &setdebuglist, &showdebuglist); + show_nto_debug, + &setdebuglist, + &showdebuglist); + + add_info ("tidinfo", nto_info_tidinfo_command, "List threads for current process." ); + nto_fetch_link_map_offsets = svr4_ilp32_fetch_link_map_offsets; + nto_is_nto_target = nto_elf_osabi_sniffer; + + observer_attach_architecture_changed (nto_architecture_changed_listener); } Index: gdb/nto-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/nto-tdep.h,v retrieving revision 1.13 diff -u -p -r1.13 nto-tdep.h --- gdb/nto-tdep.h 22 May 2009 23:49:13 -0000 1.13 +++ gdb/nto-tdep.h 5 Jun 2009 19:37:15 -0000 @@ -25,6 +25,7 @@ #include "solist.h" #include "osabi.h" #include "regset.h" +#include "gdbthread.h" /* Target operations defined for Neutrino targets (-nto-tdep.c). */ @@ -103,6 +104,10 @@ extern struct nto_target_ops current_nto #define nto_is_nto_target (current_nto_target.is_nto_target) +#define NTO_ALL_REGS (-1) +#define RAW_SUPPLY_IF_NEEDED(regcache, whichreg, dataptr) \ + {if (!(NTO_ALL_REGS == regno || regno == (whichreg))) {} \ + else regcache_raw_supply (regcache, whichreg, dataptr); } /* Keep this consistant with neutrino syspage.h. */ enum { @@ -138,12 +143,18 @@ typedef struct _debug_regs qnx_reg64 padding[1024]; } nto_regset_t; +/* Used by gdbthread.h. Same as struct tidinfo in pdebug protocol */ +struct private_thread_info { + short tid; + unsigned char state; + unsigned char flags; + char name[1]; +}; + /* Generic functions in nto-tdep.c. */ void nto_init_solib_absolute_prefix (void); -void nto_set_target(struct nto_target_ops *); - char **nto_parse_redirection (char *start_argv[], const char **in, const char **out, const char **err); @@ -160,19 +171,28 @@ enum gdb_osabi nto_elf_osabi_sniffer (bf void nto_initialize_signals (void); -void nto_generic_supply_gpregset (const struct regset *, struct regcache *, - int, const void *, size_t); - -void nto_generic_supply_fpregset (const struct regset *, struct regcache *, - int, const void *, size_t); - -void nto_generic_supply_altregset (const struct regset *, struct regcache *, - int, const void *, size_t); - /* Dummy function for initializing nto_target_ops on targets which do not define a particular regset. */ void nto_dummy_supply_regset (struct regcache *regcache, char *regs); int nto_in_dynsym_resolve_code (CORE_ADDR pc); +char *nto_target_extra_thread_info (struct thread_info *); + +struct link_map_offsets* nto_generic_svr4_fetch_link_map_offsets (void); + +/* needed for remote protocol and for core files */ +enum target_signal target_signal_from_nto (struct gdbarch *, int sig); +int target_signal_to_nto(struct gdbarch *, enum target_signal sig); + +int qnx_filename_cmp (const char *s1, const char *s2); + +LONGEST nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack, + gdb_byte *readbuf, + LONGEST len); + +char *nto_pid_to_str (struct target_ops *, ptid_t); + + + #endif --------------030708060204000908000405--