]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/nto-tdep.c
gdb/
[thirdparty/binutils-gdb.git] / gdb / nto-tdep.c
CommitLineData
1b883d35
KW
1/* nto-tdep.c - general QNX Neutrino target functionality.
2
7b6bb8da 3 Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010, 2011
4c38e0a4 4 Free Software Foundation, Inc.
1b883d35
KW
5
6 Contributed by QNX Software Systems Ltd.
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
a9762ec7 12 the Free Software Foundation; either version 3 of the License, or
1b883d35
KW
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
a9762ec7 21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1b883d35 22
b4d5ed91 23#include "defs.h"
47979a4b 24#include "gdb_stat.h"
1b883d35
KW
25#include "gdb_string.h"
26#include "nto-tdep.h"
27#include "top.h"
28#include "cli/cli-decode.h"
29#include "cli/cli-cmds.h"
30#include "inferior.h"
31#include "gdbarch.h"
32#include "bfd.h"
33#include "elf-bfd.h"
34#include "solib-svr4.h"
35#include "gdbcore.h"
238ae9af
UW
36#include "objfiles.h"
37
38#include <string.h>
1b883d35
KW
39
40#ifdef __CYGWIN__
41#include <sys/cygwin.h>
42#endif
43
44#ifdef __CYGWIN__
45static char default_nto_target[] = "C:\\QNXsdk\\target\\qnx6";
46#elif defined(__sun__) || defined(linux)
47static char default_nto_target[] = "/opt/QNXsdk/target/qnx6";
48#else
49static char default_nto_target[] = "";
50#endif
51
52struct nto_target_ops current_nto_target;
53
54static char *
55nto_target (void)
56{
57 char *p = getenv ("QNX_TARGET");
58
59#ifdef __CYGWIN__
60 static char buf[PATH_MAX];
61 if (p)
62 cygwin_conv_to_posix_path (p, buf);
63 else
64 cygwin_conv_to_posix_path (default_nto_target, buf);
65 return buf;
66#else
67 return p ? p : default_nto_target;
68#endif
69}
70
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. */
73int
74nto_map_arch_to_cputype (const char *arch)
75{
76 if (!strcmp (arch, "i386") || !strcmp (arch, "x86"))
77 return CPUTYPE_X86;
192cdb19 78 if (!strcmp (arch, "rs6000") || !strcmp (arch, "powerpc"))
1b883d35
KW
79 return CPUTYPE_PPC;
80 if (!strcmp (arch, "mips"))
81 return CPUTYPE_MIPS;
82 if (!strcmp (arch, "arm"))
83 return CPUTYPE_ARM;
84 if (!strcmp (arch, "sh"))
85 return CPUTYPE_SH;
86 return CPUTYPE_UNKNOWN;
87}
88
89int
90nto_find_and_open_solib (char *solib, unsigned o_flags, char **temp_pathname)
91{
d737fd7f 92 char *buf, *arch_path, *nto_root, *endian, *base;
1b883d35 93 const char *arch;
d737fd7f 94 int ret;
0df8b418
MS
95#define PATH_FMT \
96 "%s/lib:%s/usr/lib:%s/usr/photon/lib:%s/usr/photon/dll:%s/lib/dll"
1b883d35
KW
97
98 nto_root = nto_target ();
1cf3db46 99 if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name, "i386") == 0)
1b883d35
KW
100 {
101 arch = "x86";
102 endian = "";
103 }
1cf3db46 104 else if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name,
1143fffb 105 "rs6000") == 0
1cf3db46 106 || strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name,
1143fffb 107 "powerpc") == 0)
1b883d35
KW
108 {
109 arch = "ppc";
110 endian = "be";
111 }
112 else
113 {
1cf3db46
UW
114 arch = gdbarch_bfd_arch_info (target_gdbarch)->arch_name;
115 endian = gdbarch_byte_order (target_gdbarch)
4c6b5505 116 == BFD_ENDIAN_BIG ? "be" : "le";
1b883d35
KW
117 }
118
d737fd7f
KW
119 /* In case nto_root is short, add strlen(solib)
120 so we can reuse arch_path below. */
121 arch_path =
122 alloca (strlen (nto_root) + strlen (arch) + strlen (endian) + 2 +
123 strlen (solib));
1b883d35
KW
124 sprintf (arch_path, "%s/%s%s", nto_root, arch, endian);
125
d737fd7f
KW
126 buf = alloca (strlen (PATH_FMT) + strlen (arch_path) * 5 + 1);
127 sprintf (buf, PATH_FMT, arch_path, arch_path, arch_path, arch_path,
1b883d35
KW
128 arch_path);
129
d737fd7f
KW
130 /* Don't assume basename() isn't destructive. */
131 base = strrchr (solib, '/');
132 if (!base)
133 base = solib;
134 else
135 base++; /* Skip over '/'. */
136
fbdebf46 137 ret = openp (buf, 1, base, o_flags, temp_pathname);
d737fd7f
KW
138 if (ret < 0 && base != solib)
139 {
140 sprintf (arch_path, "/%s", solib);
141 ret = open (arch_path, o_flags, 0);
142 if (temp_pathname)
143 {
144 if (ret >= 0)
145 *temp_pathname = gdb_realpath (arch_path);
146 else
147 **temp_pathname = '\0';
148 }
149 }
150 return ret;
1b883d35
KW
151}
152
153void
154nto_init_solib_absolute_prefix (void)
155{
156 char buf[PATH_MAX * 2], arch_path[PATH_MAX];
157 char *nto_root, *endian;
158 const char *arch;
159
160 nto_root = nto_target ();
1cf3db46 161 if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name, "i386") == 0)
1b883d35
KW
162 {
163 arch = "x86";
164 endian = "";
165 }
1cf3db46 166 else if (strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name,
1143fffb 167 "rs6000") == 0
1cf3db46 168 || strcmp (gdbarch_bfd_arch_info (target_gdbarch)->arch_name,
1143fffb 169 "powerpc") == 0)
1b883d35
KW
170 {
171 arch = "ppc";
172 endian = "be";
173 }
174 else
175 {
1cf3db46
UW
176 arch = gdbarch_bfd_arch_info (target_gdbarch)->arch_name;
177 endian = gdbarch_byte_order (target_gdbarch)
4c6b5505 178 == BFD_ENDIAN_BIG ? "be" : "le";
1b883d35
KW
179 }
180
181 sprintf (arch_path, "%s/%s%s", nto_root, arch, endian);
182
183 sprintf (buf, "set solib-absolute-prefix %s", arch_path);
184 execute_command (buf, 0);
185}
186
187char **
14ef7606
AR
188nto_parse_redirection (char *pargv[], const char **pin, const char **pout,
189 const char **perr)
1b883d35
KW
190{
191 char **argv;
192 char *in, *out, *err, *p;
193 int argc, i, n;
194
195 for (n = 0; pargv[n]; n++);
196 if (n == 0)
197 return NULL;
198 in = "";
199 out = "";
200 err = "";
201
202 argv = xcalloc (n + 1, sizeof argv[0]);
203 argc = n;
204 for (i = 0, n = 0; n < argc; n++)
205 {
206 p = pargv[n];
207 if (*p == '>')
208 {
209 p++;
210 if (*p)
211 out = p;
212 else
213 out = pargv[++n];
214 }
215 else if (*p == '<')
216 {
217 p++;
218 if (*p)
219 in = p;
220 else
221 in = pargv[++n];
222 }
223 else if (*p++ == '2' && *p++ == '>')
224 {
225 if (*p == '&' && *(p + 1) == '1')
226 err = out;
227 else if (*p)
228 err = p;
229 else
230 err = pargv[++n];
231 }
232 else
233 argv[i++] = pargv[n];
234 }
235 *pin = in;
236 *pout = out;
237 *perr = err;
238 return argv;
239}
240
241/* The struct lm_info, LM_ADDR, and nto_truncate_ptr are copied from
242 solib-svr4.c to support nto_relocate_section_addresses
243 which is different from the svr4 version. */
244
ebd67d87
AR
245/* Link map info to include in an allocated so_list entry */
246
1b883d35 247struct lm_info
ebd67d87
AR
248 {
249 /* Pointer to copy of link map from inferior. The type is char *
250 rather than void *, so that we may use byte offsets to find the
251 various fields without the need for a cast. */
252 gdb_byte *lm;
253
254 /* Amount by which addresses in the binary should be relocated to
255 match the inferior. This could most often be taken directly
256 from lm, but when prelinking is involved and the prelink base
257 address changes, we may need a different offset, we want to
258 warn about the difference and compute it only once. */
259 CORE_ADDR l_addr;
260
261 /* The target location of lm. */
262 CORE_ADDR lm_addr;
263 };
264
1b883d35
KW
265
266static CORE_ADDR
267LM_ADDR (struct so_list *so)
268{
ebd67d87
AR
269 if (so->lm_info->l_addr == (CORE_ADDR)-1)
270 {
271 struct link_map_offsets *lmo = nto_fetch_link_map_offsets ();
b6da22b0 272 struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
1b883d35 273
ebd67d87 274 so->lm_info->l_addr =
b6da22b0 275 extract_typed_address (so->lm_info->lm + lmo->l_addr_offset, ptr_type);
ebd67d87
AR
276 }
277 return so->lm_info->l_addr;
1b883d35
KW
278}
279
280static CORE_ADDR
281nto_truncate_ptr (CORE_ADDR addr)
282{
1cf3db46 283 if (gdbarch_ptr_bit (target_gdbarch) == sizeof (CORE_ADDR) * 8)
1b883d35
KW
284 /* We don't need to truncate anything, and the bit twiddling below
285 will fail due to overflow problems. */
286 return addr;
287 else
1cf3db46 288 return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch)) - 1);
1b883d35
KW
289}
290
63807e1d 291static Elf_Internal_Phdr *
1b883d35
KW
292find_load_phdr (bfd *abfd)
293{
294 Elf_Internal_Phdr *phdr;
295 unsigned int i;
296
297 if (!elf_tdata (abfd))
298 return NULL;
299
300 phdr = elf_tdata (abfd)->phdr;
301 for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
302 {
303 if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
304 return phdr;
305 }
306 return NULL;
307}
308
309void
0542c86d 310nto_relocate_section_addresses (struct so_list *so, struct target_section *sec)
1b883d35
KW
311{
312 /* Neutrino treats the l_addr base address field in link.h as different than
313 the base address in the System V ABI and so the offset needs to be
314 calculated and applied to relocations. */
315 Elf_Internal_Phdr *phdr = find_load_phdr (sec->bfd);
316 unsigned vaddr = phdr ? phdr->p_vaddr : 0;
317
318 sec->addr = nto_truncate_ptr (sec->addr + LM_ADDR (so) - vaddr);
319 sec->endaddr = nto_truncate_ptr (sec->endaddr + LM_ADDR (so) - vaddr);
320}
321
d737fd7f
KW
322/* This is cheating a bit because our linker code is in libc.so. If we
323 ever implement lazy linking, this may need to be re-examined. */
324int
325nto_in_dynsym_resolve_code (CORE_ADDR pc)
326{
327 if (in_plt_section (pc, NULL))
328 return 1;
329 return 0;
330}
331
d737fd7f 332void
468e3d51 333nto_dummy_supply_regset (struct regcache *regcache, char *regs)
d737fd7f
KW
334{
335 /* Do nothing. */
336}
337
338enum gdb_osabi
339nto_elf_osabi_sniffer (bfd *abfd)
340{
341 if (nto_is_nto_target)
3d171c85 342 return nto_is_nto_target (abfd);
d737fd7f
KW
343 return GDB_OSABI_UNKNOWN;
344}
345
745a434e
AR
346static const char *nto_thread_state_str[] =
347{
348 "DEAD", /* 0 0x00 */
349 "RUNNING", /* 1 0x01 */
350 "READY", /* 2 0x02 */
351 "STOPPED", /* 3 0x03 */
352 "SEND", /* 4 0x04 */
353 "RECEIVE", /* 5 0x05 */
354 "REPLY", /* 6 0x06 */
355 "STACK", /* 7 0x07 */
356 "WAITTHREAD", /* 8 0x08 */
357 "WAITPAGE", /* 9 0x09 */
358 "SIGSUSPEND", /* 10 0x0a */
359 "SIGWAITINFO", /* 11 0x0b */
360 "NANOSLEEP", /* 12 0x0c */
361 "MUTEX", /* 13 0x0d */
362 "CONDVAR", /* 14 0x0e */
363 "JOIN", /* 15 0x0f */
364 "INTR", /* 16 0x10 */
365 "SEM", /* 17 0x11 */
366 "WAITCTX", /* 18 0x12 */
367 "NET_SEND", /* 19 0x13 */
368 "NET_REPLY" /* 20 0x14 */
369};
370
371char *
372nto_extra_thread_info (struct thread_info *ti)
373{
374 if (ti && ti->private
375 && ti->private->state < ARRAY_SIZE (nto_thread_state_str))
376 return (char *)nto_thread_state_str [ti->private->state];
377 return "";
378}
379
1b883d35 380void
d737fd7f 381nto_initialize_signals (void)
1b883d35 382{
1b883d35
KW
383 /* We use SIG45 for pulses, or something, so nostop, noprint
384 and pass them. */
385 signal_stop_update (target_signal_from_name ("SIG45"), 0);
386 signal_print_update (target_signal_from_name ("SIG45"), 0);
387 signal_pass_update (target_signal_from_name ("SIG45"), 1);
388
389 /* By default we don't want to stop on these two, but we do want to pass. */
390#if defined(SIGSELECT)
391 signal_stop_update (SIGSELECT, 0);
392 signal_print_update (SIGSELECT, 0);
393 signal_pass_update (SIGSELECT, 1);
394#endif
395
396#if defined(SIGPHOTON)
397 signal_stop_update (SIGPHOTON, 0);
398 signal_print_update (SIGPHOTON, 0);
399 signal_pass_update (SIGPHOTON, 1);
400#endif
d737fd7f 401}
1b883d35 402
63807e1d
PA
403/* Provide a prototype to silence -Wmissing-prototypes. */
404extern initialize_file_ftype _initialize_nto_tdep;
405
d737fd7f
KW
406void
407_initialize_nto_tdep (void)
408{
409 add_setshow_zinteger_cmd ("nto-debug", class_maintenance,
7915a72c
AC
410 &nto_internal_debugging, _("\
411Set QNX NTO internal debugging."), _("\
412Show QNX NTO internal debugging."), _("\
d737fd7f
KW
413When non-zero, nto specific debug info is\n\
414displayed. Different information is displayed\n\
7915a72c 415for different positive values."),
2c5b56ce 416 NULL,
0df8b418
MS
417 NULL, /* FIXME: i18n: QNX NTO internal
418 debugging is %s. */
2c5b56ce 419 &setdebuglist, &showdebuglist);
1b883d35 420}