1 /* nto-tdep.c - general QNX Neutrino target functionality.
3 Copyright (C) 2003-2016 Free Software Foundation, Inc.
5 Contributed by QNX Software Systems Ltd.
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
31 #include "solib-svr4.h"
35 #define QNX_NOTE_NAME "QNX"
36 #define QNX_INFO_SECT_NAME "QNX_info"
39 #include <sys/cygwin.h>
43 static char default_nto_target[] = "C:\\QNXsdk\\target\\qnx6";
44 #elif defined(__sun__) || defined(linux)
45 static char default_nto_target[] = "/opt/QNXsdk/target/qnx6";
47 static char default_nto_target[] = "";
50 struct nto_target_ops current_nto_target;
52 static const struct inferior_data *nto_inferior_data_reg;
57 char *p = getenv ("QNX_TARGET");
60 static char buf[PATH_MAX];
62 cygwin_conv_path (CCP_WIN_A_TO_POSIX, p, buf, PATH_MAX);
64 cygwin_conv_path (CCP_WIN_A_TO_POSIX, default_nto_target, buf, PATH_MAX);
67 return p ? p : default_nto_target;
71 /* Take a string such as i386, rs6000, etc. and map it onto CPUTYPE_X86,
72 CPUTYPE_PPC, etc. as defined in nto-share/dsmsgs.h. */
74 nto_map_arch_to_cputype (const char *arch)
76 if (!strcmp (arch, "i386") || !strcmp (arch, "x86"))
78 if (!strcmp (arch, "rs6000") || !strcmp (arch, "powerpc"))
80 if (!strcmp (arch, "mips"))
82 if (!strcmp (arch, "arm"))
84 if (!strcmp (arch, "sh"))
86 return CPUTYPE_UNKNOWN;
90 nto_find_and_open_solib (const char *solib, unsigned o_flags,
93 char *buf, *arch_path, *nto_root;
97 int arch_len, len, ret;
99 "%s/lib:%s/usr/lib:%s/usr/photon/lib:%s/usr/photon/dll:%s/lib/dll"
101 nto_root = nto_target ();
102 if (strcmp (gdbarch_bfd_arch_info (target_gdbarch ())->arch_name, "i386") == 0)
107 else if (strcmp (gdbarch_bfd_arch_info (target_gdbarch ())->arch_name,
109 || strcmp (gdbarch_bfd_arch_info (target_gdbarch ())->arch_name,
117 arch = gdbarch_bfd_arch_info (target_gdbarch ())->arch_name;
118 endian = gdbarch_byte_order (target_gdbarch ())
119 == BFD_ENDIAN_BIG ? "be" : "le";
122 /* In case nto_root is short, add strlen(solib)
123 so we can reuse arch_path below. */
125 arch_len = (strlen (nto_root) + strlen (arch) + strlen (endian) + 2
127 arch_path = (char *) alloca (arch_len);
128 xsnprintf (arch_path, arch_len, "%s/%s%s", nto_root, arch, endian);
130 len = strlen (PATH_FMT) + strlen (arch_path) * 5 + 1;
131 buf = (char *) alloca (len);
132 xsnprintf (buf, len, PATH_FMT, arch_path, arch_path, arch_path, arch_path,
135 base = lbasename (solib);
136 ret = openp (buf, OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH, base, o_flags,
138 if (ret < 0 && base != solib)
140 xsnprintf (arch_path, arch_len, "/%s", solib);
141 ret = open (arch_path, o_flags, 0);
145 *temp_pathname = gdb_realpath (arch_path);
147 *temp_pathname = NULL;
154 nto_init_solib_absolute_prefix (void)
156 char buf[PATH_MAX * 2], arch_path[PATH_MAX];
161 nto_root = nto_target ();
162 if (strcmp (gdbarch_bfd_arch_info (target_gdbarch ())->arch_name, "i386") == 0)
167 else if (strcmp (gdbarch_bfd_arch_info (target_gdbarch ())->arch_name,
169 || strcmp (gdbarch_bfd_arch_info (target_gdbarch ())->arch_name,
177 arch = gdbarch_bfd_arch_info (target_gdbarch ())->arch_name;
178 endian = gdbarch_byte_order (target_gdbarch ())
179 == BFD_ENDIAN_BIG ? "be" : "le";
182 xsnprintf (arch_path, sizeof (arch_path), "%s/%s%s", nto_root, arch, endian);
184 xsnprintf (buf, sizeof (buf), "set solib-absolute-prefix %s", arch_path);
185 execute_command (buf, 0);
189 nto_parse_redirection (char *pargv[], const char **pin, const char **pout,
193 char *in, *out, *err, *p;
196 for (n = 0; pargv[n]; n++);
203 argv = XCNEWVEC (char *, n + 1);
205 for (i = 0, n = 0; n < argc; n++)
224 else if (*p++ == '2' && *p++ == '>')
226 if (*p == '&' && *(p + 1) == '1')
234 argv[i++] = pargv[n];
242 /* The struct lm_info, lm_addr, and nto_truncate_ptr are copied from
243 solib-svr4.c to support nto_relocate_section_addresses
244 which is different from the svr4 version. */
246 /* Link map info to include in an allocated so_list entry */
250 /* Pointer to copy of link map from inferior. The type is char *
251 rather than void *, so that we may use byte offsets to find the
252 various fields without the need for a cast. */
255 /* Amount by which addresses in the binary should be relocated to
256 match the inferior. This could most often be taken directly
257 from lm, but when prelinking is involved and the prelink base
258 address changes, we may need a different offset, we want to
259 warn about the difference and compute it only once. */
262 /* The target location of lm. */
268 lm_addr (struct so_list *so)
270 if (so->lm_info->l_addr == (CORE_ADDR)-1)
272 struct link_map_offsets *lmo = nto_fetch_link_map_offsets ();
273 struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
275 so->lm_info->l_addr =
276 extract_typed_address (so->lm_info->lm + lmo->l_addr_offset, ptr_type);
278 return so->lm_info->l_addr;
282 nto_truncate_ptr (CORE_ADDR addr)
284 if (gdbarch_ptr_bit (target_gdbarch ()) == sizeof (CORE_ADDR) * 8)
285 /* We don't need to truncate anything, and the bit twiddling below
286 will fail due to overflow problems. */
289 return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch ())) - 1);
292 static Elf_Internal_Phdr *
293 find_load_phdr (bfd *abfd)
295 Elf_Internal_Phdr *phdr;
298 if (!elf_tdata (abfd))
301 phdr = elf_tdata (abfd)->phdr;
302 for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
304 if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
311 nto_relocate_section_addresses (struct so_list *so, struct target_section *sec)
313 /* Neutrino treats the l_addr base address field in link.h as different than
314 the base address in the System V ABI and so the offset needs to be
315 calculated and applied to relocations. */
316 Elf_Internal_Phdr *phdr = find_load_phdr (sec->the_bfd_section->owner);
317 unsigned vaddr = phdr ? phdr->p_vaddr : 0;
319 sec->addr = nto_truncate_ptr (sec->addr + lm_addr (so) - vaddr);
320 sec->endaddr = nto_truncate_ptr (sec->endaddr + lm_addr (so) - vaddr);
323 /* This is cheating a bit because our linker code is in libc.so. If we
324 ever implement lazy linking, this may need to be re-examined. */
326 nto_in_dynsym_resolve_code (CORE_ADDR pc)
328 if (in_plt_section (pc))
334 nto_dummy_supply_regset (struct regcache *regcache, char *regs)
340 nto_sniff_abi_note_section (bfd *abfd, asection *sect, void *obj)
342 const char *sectname;
343 unsigned int sectsize;
344 /* Buffer holding the section contents. */
346 unsigned int namelen;
348 const unsigned sizeof_Elf_Nhdr = 12;
350 sectname = bfd_get_section_name (abfd, sect);
351 sectsize = bfd_section_size (abfd, sect);
356 if (sectname != NULL && strstr (sectname, QNX_INFO_SECT_NAME) != NULL)
357 *(enum gdb_osabi *) obj = GDB_OSABI_QNXNTO;
358 else if (sectname != NULL && strstr (sectname, "note") != NULL
359 && sectsize > sizeof_Elf_Nhdr)
361 note = XNEWVEC (char, sectsize);
362 bfd_get_section_contents (abfd, sect, note, 0, sectsize);
363 namelen = (unsigned int) bfd_h_get_32 (abfd, note);
364 name = note + sizeof_Elf_Nhdr;
365 if (sectsize >= namelen + sizeof_Elf_Nhdr
366 && namelen == sizeof (QNX_NOTE_NAME)
367 && 0 == strcmp (name, QNX_NOTE_NAME))
368 *(enum gdb_osabi *) obj = GDB_OSABI_QNXNTO;
375 nto_elf_osabi_sniffer (bfd *abfd)
377 enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
379 bfd_map_over_sections (abfd,
380 nto_sniff_abi_note_section,
386 static const char *nto_thread_state_str[] =
389 "RUNNING", /* 1 0x01 */
390 "READY", /* 2 0x02 */
391 "STOPPED", /* 3 0x03 */
393 "RECEIVE", /* 5 0x05 */
394 "REPLY", /* 6 0x06 */
395 "STACK", /* 7 0x07 */
396 "WAITTHREAD", /* 8 0x08 */
397 "WAITPAGE", /* 9 0x09 */
398 "SIGSUSPEND", /* 10 0x0a */
399 "SIGWAITINFO", /* 11 0x0b */
400 "NANOSLEEP", /* 12 0x0c */
401 "MUTEX", /* 13 0x0d */
402 "CONDVAR", /* 14 0x0e */
403 "JOIN", /* 15 0x0f */
404 "INTR", /* 16 0x10 */
406 "WAITCTX", /* 18 0x12 */
407 "NET_SEND", /* 19 0x13 */
408 "NET_REPLY" /* 20 0x14 */
412 nto_extra_thread_info (struct target_ops *self, struct thread_info *ti)
415 && ti->priv->state < ARRAY_SIZE (nto_thread_state_str))
416 return (char *)nto_thread_state_str [ti->priv->state];
421 nto_initialize_signals (void)
423 /* We use SIG45 for pulses, or something, so nostop, noprint
425 signal_stop_update (gdb_signal_from_name ("SIG45"), 0);
426 signal_print_update (gdb_signal_from_name ("SIG45"), 0);
427 signal_pass_update (gdb_signal_from_name ("SIG45"), 1);
429 /* By default we don't want to stop on these two, but we do want to pass. */
430 #if defined(SIGSELECT)
431 signal_stop_update (SIGSELECT, 0);
432 signal_print_update (SIGSELECT, 0);
433 signal_pass_update (SIGSELECT, 1);
436 #if defined(SIGPHOTON)
437 signal_stop_update (SIGPHOTON, 0);
438 signal_print_update (SIGPHOTON, 0);
439 signal_pass_update (SIGPHOTON, 1);
443 /* Read AUXV from initial_stack. */
445 nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack, gdb_byte *readbuf,
446 LONGEST len, size_t sizeof_auxv_t)
448 gdb_byte targ32[4]; /* For 32 bit target values. */
449 gdb_byte targ64[8]; /* For 64 bit target values. */
450 CORE_ADDR data_ofs = 0;
452 LONGEST len_read = 0;
454 enum bfd_endian byte_order;
457 if (sizeof_auxv_t == 16)
462 /* Skip over argc, argv and envp... Comment from ldd.c:
464 The startup frame is set-up so that we have:
469 envp1 <----- void *frame + (argc + 2) * sizeof(char *)
474 argc <------ void * frame
476 On entry to ldd, frame gives the address of argc on the stack. */
477 /* Read argc. 4 bytes on both 64 and 32 bit arches and luckily little
478 * endian. So we just read first 4 bytes. */
479 if (target_read_memory (initial_stack + data_ofs, targ32, 4) != 0)
482 byte_order = gdbarch_byte_order (target_gdbarch ());
484 anint = extract_unsigned_integer (targ32, sizeof (targ32), byte_order);
486 /* Size of pointer is assumed to be 4 bytes (32 bit arch.) */
487 data_ofs += (anint + 2) * ptr_size; /* + 2 comes from argc itself and
488 NULL terminating pointer in
491 /* Now loop over env table: */
493 while (target_read_memory (initial_stack + data_ofs, targ64, ptr_size)
496 if (extract_unsigned_integer (targ64, ptr_size, byte_order) == 0)
497 anint = 1; /* Keep looping until non-null entry is found. */
500 data_ofs += ptr_size;
502 initial_stack += data_ofs;
504 memset (readbuf, 0, len);
506 while (len_read <= len-sizeof_auxv_t)
508 if (target_read_memory (initial_stack + len_read, buff, sizeof_auxv_t)
511 /* Both 32 and 64 bit structures have int as the first field. */
512 const ULONGEST a_type
513 = extract_unsigned_integer (buff, sizeof (targ32), byte_order);
515 if (a_type == AT_NULL)
517 buff += sizeof_auxv_t;
518 len_read += sizeof_auxv_t;
526 /* Allocate new nto_inferior_data object. */
528 static struct nto_inferior_data *
529 nto_new_inferior_data (void)
531 struct nto_inferior_data *const inf_data
532 = XCNEW (struct nto_inferior_data);
537 /* Free inferior data. */
540 nto_inferior_data_cleanup (struct inferior *const inf, void *const dat)
545 /* Return nto_inferior_data for the given INFERIOR. If not yet created,
548 struct nto_inferior_data *
549 nto_inferior_data (struct inferior *const inferior)
551 struct inferior *const inf = inferior ? inferior : current_inferior ();
552 struct nto_inferior_data *inf_data;
554 gdb_assert (inf != NULL);
557 = (struct nto_inferior_data *) inferior_data (inf, nto_inferior_data_reg);
558 if (inf_data == NULL)
560 set_inferior_data (inf, nto_inferior_data_reg,
561 (inf_data = nto_new_inferior_data ()));
567 /* Provide a prototype to silence -Wmissing-prototypes. */
568 extern initialize_file_ftype _initialize_nto_tdep;
571 _initialize_nto_tdep (void)
573 nto_inferior_data_reg
574 = register_inferior_data_with_cleanup (NULL, nto_inferior_data_cleanup);