1130803Smarcel/* nto-tdep.c - general QNX Neutrino target functionality.
2130803Smarcel
3130803Smarcel   Copyright 2003 Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   Contributed by QNX Software Systems Ltd.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
22130803Smarcel   Boston, MA 02111-1307, USA.  */
23130803Smarcel
24130803Smarcel#include "gdb_stat.h"
25130803Smarcel#include "gdb_string.h"
26130803Smarcel#include "nto-tdep.h"
27130803Smarcel#include "top.h"
28130803Smarcel#include "cli/cli-decode.h"
29130803Smarcel#include "cli/cli-cmds.h"
30130803Smarcel#include "inferior.h"
31130803Smarcel#include "gdbarch.h"
32130803Smarcel#include "bfd.h"
33130803Smarcel#include "elf-bfd.h"
34130803Smarcel#include "solib-svr4.h"
35130803Smarcel#include "gdbcore.h"
36130803Smarcel
37130803Smarcel#ifdef __CYGWIN__
38130803Smarcel#include <sys/cygwin.h>
39130803Smarcel#endif
40130803Smarcel
41130803Smarcel#ifdef __CYGWIN__
42130803Smarcelstatic char default_nto_target[] = "C:\\QNXsdk\\target\\qnx6";
43130803Smarcel#elif defined(__sun__) || defined(linux)
44130803Smarcelstatic char default_nto_target[] = "/opt/QNXsdk/target/qnx6";
45130803Smarcel#else
46130803Smarcelstatic char default_nto_target[] = "";
47130803Smarcel#endif
48130803Smarcel
49130803Smarcelstruct nto_target_ops current_nto_target;
50130803Smarcel
51130803Smarcelstatic char *
52130803Smarcelnto_target (void)
53130803Smarcel{
54130803Smarcel  char *p = getenv ("QNX_TARGET");
55130803Smarcel
56130803Smarcel#ifdef __CYGWIN__
57130803Smarcel  static char buf[PATH_MAX];
58130803Smarcel  if (p)
59130803Smarcel    cygwin_conv_to_posix_path (p, buf);
60130803Smarcel  else
61130803Smarcel    cygwin_conv_to_posix_path (default_nto_target, buf);
62130803Smarcel  return buf;
63130803Smarcel#else
64130803Smarcel  return p ? p : default_nto_target;
65130803Smarcel#endif
66130803Smarcel}
67130803Smarcel
68130803Smarcel/* Take a string such as i386, rs6000, etc. and map it onto CPUTYPE_X86,
69130803Smarcel   CPUTYPE_PPC, etc. as defined in nto-share/dsmsgs.h.  */
70130803Smarcelint
71130803Smarcelnto_map_arch_to_cputype (const char *arch)
72130803Smarcel{
73130803Smarcel  if (!strcmp (arch, "i386") || !strcmp (arch, "x86"))
74130803Smarcel    return CPUTYPE_X86;
75130803Smarcel  if (!strcmp (arch, "rs6000") || !strcmp (arch, "powerpc"))
76130803Smarcel    return CPUTYPE_PPC;
77130803Smarcel  if (!strcmp (arch, "mips"))
78130803Smarcel    return CPUTYPE_MIPS;
79130803Smarcel  if (!strcmp (arch, "arm"))
80130803Smarcel    return CPUTYPE_ARM;
81130803Smarcel  if (!strcmp (arch, "sh"))
82130803Smarcel    return CPUTYPE_SH;
83130803Smarcel  return CPUTYPE_UNKNOWN;
84130803Smarcel}
85130803Smarcel
86130803Smarcelint
87130803Smarcelnto_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname)
88130803Smarcel{
89130803Smarcel  char *buf, arch_path[PATH_MAX], *nto_root, *endian;
90130803Smarcel  const char *arch;
91130803Smarcel  char *path_fmt = "%s/lib:%s/usr/lib:%s/usr/photon/lib\
92130803Smarcel:%s/usr/photon/dll:%s/lib/dll";
93130803Smarcel
94130803Smarcel  nto_root = nto_target ();
95130803Smarcel  if (strcmp (TARGET_ARCHITECTURE->arch_name, "i386") == 0)
96130803Smarcel    {
97130803Smarcel      arch = "x86";
98130803Smarcel      endian = "";
99130803Smarcel    }
100130803Smarcel  else if (strcmp (TARGET_ARCHITECTURE->arch_name, "rs6000") == 0
101130803Smarcel	   || strcmp (TARGET_ARCHITECTURE->arch_name, "powerpc") == 0)
102130803Smarcel    {
103130803Smarcel      arch = "ppc";
104130803Smarcel      endian = "be";
105130803Smarcel    }
106130803Smarcel  else
107130803Smarcel    {
108130803Smarcel      arch = TARGET_ARCHITECTURE->arch_name;
109130803Smarcel      endian = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "be" : "le";
110130803Smarcel    }
111130803Smarcel
112130803Smarcel  sprintf (arch_path, "%s/%s%s", nto_root, arch, endian);
113130803Smarcel
114130803Smarcel  buf = alloca (strlen (path_fmt) + strlen (arch_path) * 5 + 1);
115130803Smarcel  sprintf (buf, path_fmt, arch_path, arch_path, arch_path, arch_path,
116130803Smarcel	   arch_path);
117130803Smarcel
118130803Smarcel  return openp (buf, 1, solib, o_flags, 0, temp_pathname);
119130803Smarcel}
120130803Smarcel
121130803Smarcelvoid
122130803Smarcelnto_init_solib_absolute_prefix (void)
123130803Smarcel{
124130803Smarcel  char buf[PATH_MAX * 2], arch_path[PATH_MAX];
125130803Smarcel  char *nto_root, *endian;
126130803Smarcel  const char *arch;
127130803Smarcel
128130803Smarcel  nto_root = nto_target ();
129130803Smarcel  if (strcmp (TARGET_ARCHITECTURE->arch_name, "i386") == 0)
130130803Smarcel    {
131130803Smarcel      arch = "x86";
132130803Smarcel      endian = "";
133130803Smarcel    }
134130803Smarcel  else if (strcmp (TARGET_ARCHITECTURE->arch_name, "rs6000") == 0
135130803Smarcel	   || strcmp (TARGET_ARCHITECTURE->arch_name, "powerpc") == 0)
136130803Smarcel    {
137130803Smarcel      arch = "ppc";
138130803Smarcel      endian = "be";
139130803Smarcel    }
140130803Smarcel  else
141130803Smarcel    {
142130803Smarcel      arch = TARGET_ARCHITECTURE->arch_name;
143130803Smarcel      endian = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "be" : "le";
144130803Smarcel    }
145130803Smarcel
146130803Smarcel  sprintf (arch_path, "%s/%s%s", nto_root, arch, endian);
147130803Smarcel
148130803Smarcel  sprintf (buf, "set solib-absolute-prefix %s", arch_path);
149130803Smarcel  execute_command (buf, 0);
150130803Smarcel}
151130803Smarcel
152130803Smarcelchar **
153130803Smarcelnto_parse_redirection (char *pargv[], char **pin, char **pout, char **perr)
154130803Smarcel{
155130803Smarcel  char **argv;
156130803Smarcel  char *in, *out, *err, *p;
157130803Smarcel  int argc, i, n;
158130803Smarcel
159130803Smarcel  for (n = 0; pargv[n]; n++);
160130803Smarcel  if (n == 0)
161130803Smarcel    return NULL;
162130803Smarcel  in = "";
163130803Smarcel  out = "";
164130803Smarcel  err = "";
165130803Smarcel
166130803Smarcel  argv = xcalloc (n + 1, sizeof argv[0]);
167130803Smarcel  argc = n;
168130803Smarcel  for (i = 0, n = 0; n < argc; n++)
169130803Smarcel    {
170130803Smarcel      p = pargv[n];
171130803Smarcel      if (*p == '>')
172130803Smarcel	{
173130803Smarcel	  p++;
174130803Smarcel	  if (*p)
175130803Smarcel	    out = p;
176130803Smarcel	  else
177130803Smarcel	    out = pargv[++n];
178130803Smarcel	}
179130803Smarcel      else if (*p == '<')
180130803Smarcel	{
181130803Smarcel	  p++;
182130803Smarcel	  if (*p)
183130803Smarcel	    in = p;
184130803Smarcel	  else
185130803Smarcel	    in = pargv[++n];
186130803Smarcel	}
187130803Smarcel      else if (*p++ == '2' && *p++ == '>')
188130803Smarcel	{
189130803Smarcel	  if (*p == '&' && *(p + 1) == '1')
190130803Smarcel	    err = out;
191130803Smarcel	  else if (*p)
192130803Smarcel	    err = p;
193130803Smarcel	  else
194130803Smarcel	    err = pargv[++n];
195130803Smarcel	}
196130803Smarcel      else
197130803Smarcel	argv[i++] = pargv[n];
198130803Smarcel    }
199130803Smarcel  *pin = in;
200130803Smarcel  *pout = out;
201130803Smarcel  *perr = err;
202130803Smarcel  return argv;
203130803Smarcel}
204130803Smarcel
205130803Smarcel/* The struct lm_info, LM_ADDR, and nto_truncate_ptr are copied from
206130803Smarcel   solib-svr4.c to support nto_relocate_section_addresses
207130803Smarcel   which is different from the svr4 version.  */
208130803Smarcel
209130803Smarcelstruct lm_info
210130803Smarcel{
211130803Smarcel  /* Pointer to copy of link map from inferior.  The type is char *
212130803Smarcel     rather than void *, so that we may use byte offsets to find the
213130803Smarcel     various fields without the need for a cast.  */
214130803Smarcel  char *lm;
215130803Smarcel};
216130803Smarcel
217130803Smarcelstatic CORE_ADDR
218130803SmarcelLM_ADDR (struct so_list *so)
219130803Smarcel{
220130803Smarcel  struct link_map_offsets *lmo = nto_fetch_link_map_offsets ();
221130803Smarcel
222130803Smarcel  return (CORE_ADDR) extract_signed_integer (so->lm_info->lm +
223130803Smarcel					     lmo->l_addr_offset,
224130803Smarcel					     lmo->l_addr_size);
225130803Smarcel}
226130803Smarcel
227130803Smarcelstatic CORE_ADDR
228130803Smarcelnto_truncate_ptr (CORE_ADDR addr)
229130803Smarcel{
230130803Smarcel  if (TARGET_PTR_BIT == sizeof (CORE_ADDR) * 8)
231130803Smarcel    /* We don't need to truncate anything, and the bit twiddling below
232130803Smarcel       will fail due to overflow problems.  */
233130803Smarcel    return addr;
234130803Smarcel  else
235130803Smarcel    return addr & (((CORE_ADDR) 1 << TARGET_PTR_BIT) - 1);
236130803Smarcel}
237130803Smarcel
238130803SmarcelElf_Internal_Phdr *
239130803Smarcelfind_load_phdr (bfd *abfd)
240130803Smarcel{
241130803Smarcel  Elf_Internal_Phdr *phdr;
242130803Smarcel  unsigned int i;
243130803Smarcel
244130803Smarcel  if (!elf_tdata (abfd))
245130803Smarcel    return NULL;
246130803Smarcel
247130803Smarcel  phdr = elf_tdata (abfd)->phdr;
248130803Smarcel  for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
249130803Smarcel    {
250130803Smarcel      if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
251130803Smarcel	return phdr;
252130803Smarcel    }
253130803Smarcel  return NULL;
254130803Smarcel}
255130803Smarcel
256130803Smarcelvoid
257130803Smarcelnto_relocate_section_addresses (struct so_list *so, struct section_table *sec)
258130803Smarcel{
259130803Smarcel  /* Neutrino treats the l_addr base address field in link.h as different than
260130803Smarcel     the base address in the System V ABI and so the offset needs to be
261130803Smarcel     calculated and applied to relocations.  */
262130803Smarcel  Elf_Internal_Phdr *phdr = find_load_phdr (sec->bfd);
263130803Smarcel  unsigned vaddr = phdr ? phdr->p_vaddr : 0;
264130803Smarcel
265130803Smarcel  sec->addr = nto_truncate_ptr (sec->addr + LM_ADDR (so) - vaddr);
266130803Smarcel  sec->endaddr = nto_truncate_ptr (sec->endaddr + LM_ADDR (so) - vaddr);
267130803Smarcel}
268130803Smarcel
269130803Smarcelstatic void
270130803Smarcelfetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
271130803Smarcel		      int which, CORE_ADDR reg_addr)
272130803Smarcel{
273130803Smarcel  nto_regset_t regset;
274130803Smarcel
275130803Smarcel/* See corelow.c:get_core_registers for values of WHICH.  */
276130803Smarcel  if (which == 0)
277130803Smarcel    {
278130803Smarcel      memcpy ((char *) &regset, core_reg_sect,
279130803Smarcel	      min (core_reg_size, sizeof (regset)));
280130803Smarcel      nto_supply_gregset ((char *) &regset);
281130803Smarcel    }
282130803Smarcel  else if (which == 2)
283130803Smarcel    {
284130803Smarcel      memcpy ((char *) &regset, core_reg_sect,
285130803Smarcel	      min (core_reg_size, sizeof (regset)));
286130803Smarcel      nto_supply_fpregset ((char *) &regset);
287130803Smarcel    }
288130803Smarcel}
289130803Smarcel
290130803Smarcelvoid
291130803Smarcelnto_dummy_supply_regset (char *regs)
292130803Smarcel{
293130803Smarcel  /* Do nothing.  */
294130803Smarcel}
295130803Smarcel
296130803Smarcel/* Register that we are able to handle ELF file formats using standard
297130803Smarcel   procfs "regset" structures.  */
298130803Smarcelstatic struct core_fns regset_core_fns = {
299130803Smarcel  bfd_target_elf_flavour,	/* core_flavour */
300130803Smarcel  default_check_format,		/* check_format */
301130803Smarcel  default_core_sniffer,		/* core_sniffer */
302130803Smarcel  fetch_core_registers,		/* core_read_registers */
303130803Smarcel  NULL				/* next */
304130803Smarcel};
305130803Smarcel
306130803Smarcelvoid
307130803Smarcel_initialize_nto_tdep (void)
308130803Smarcel{
309130803Smarcel  add_setshow_cmd ("nto-debug", class_maintenance, var_zinteger,
310130803Smarcel		   &nto_internal_debugging, "Set QNX NTO internal debugging.\n\
311130803SmarcelWhen non-zero, nto specific debug info is\n\
312130803Smarceldisplayed. Different information is displayed\n\
313130803Smarcelfor different positive values.", "Show QNX NTO internal debugging.\n",
314130803Smarcel		   NULL, NULL, &setdebuglist, &showdebuglist);
315130803Smarcel
316130803Smarcel  /* We use SIG45 for pulses, or something, so nostop, noprint
317130803Smarcel     and pass them.  */
318130803Smarcel  signal_stop_update (target_signal_from_name ("SIG45"), 0);
319130803Smarcel  signal_print_update (target_signal_from_name ("SIG45"), 0);
320130803Smarcel  signal_pass_update (target_signal_from_name ("SIG45"), 1);
321130803Smarcel
322130803Smarcel  /* By default we don't want to stop on these two, but we do want to pass.  */
323130803Smarcel#if defined(SIGSELECT)
324130803Smarcel  signal_stop_update (SIGSELECT, 0);
325130803Smarcel  signal_print_update (SIGSELECT, 0);
326130803Smarcel  signal_pass_update (SIGSELECT, 1);
327130803Smarcel#endif
328130803Smarcel
329130803Smarcel#if defined(SIGPHOTON)
330130803Smarcel  signal_stop_update (SIGPHOTON, 0);
331130803Smarcel  signal_print_update (SIGPHOTON, 0);
332130803Smarcel  signal_pass_update (SIGPHOTON, 1);
333130803Smarcel#endif
334130803Smarcel
335130803Smarcel  /* Register core file support.  */
336130803Smarcel  add_core_fns (&regset_core_fns);
337130803Smarcel}
338