[ia64-hpux] unwinding bsp value from system call
[deliverable/binutils-gdb.git] / gdb / ia64-hpux-tdep.c
1 /* Target-dependent code for the IA-64 for GDB, the GNU debugger.
2
3 Copyright (C) 2010 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "defs.h"
21 #include "ia64-tdep.h"
22 #include "ia64-hpux-tdep.h"
23 #include "osabi.h"
24 #include "gdbtypes.h"
25 #include "solib.h"
26 #include "target.h"
27 #include "frame.h"
28
29 /* The offset to be used in order to get the __reason pseudo-register
30 when using one of the *UREGS ttrace requests (see system header file
31 /usr/include/ia64/sys/uregs.h for more details).
32
33 The documentation for this pseudo-register says that a nonzero value
34 indicates that the thread stopped due to a fault, trap, or interrupt.
35 A null value indicates a stop inside a syscall. */
36 #define IA64_HPUX_UREG_REASON 0x00070000
37
38 /* Return nonzero if the value of the register identified by REGNUM
39 can be modified. */
40
41 static int
42 ia64_hpux_can_store_ar_register (int regnum)
43 {
44 switch (regnum)
45 {
46 case IA64_RSC_REGNUM:
47 case IA64_RNAT_REGNUM:
48 case IA64_CSD_REGNUM:
49 case IA64_SSD_REGNUM:
50 case IA64_CCV_REGNUM:
51 case IA64_UNAT_REGNUM:
52 case IA64_FPSR_REGNUM:
53 case IA64_PFS_REGNUM:
54 case IA64_LC_REGNUM:
55 case IA64_EC_REGNUM:
56 return 1;
57 break;
58
59 default:
60 return 0;
61 break;
62 }
63 }
64
65 /* The "cannot_store_register" target_ops method. */
66
67 static int
68 ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
69 {
70 /* General registers. */
71
72 if (regnum == IA64_GR0_REGNUM)
73 return 1;
74
75 /* FP register. */
76
77 if (regnum == IA64_FR0_REGNUM || regnum == IA64_FR1_REGNUM)
78 return 1;
79
80 /* Application registers. */
81 if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_AR0_REGNUM + 127)
82 return (!ia64_hpux_can_store_ar_register (regnum));
83
84 /* We can store all other registers. */
85 return 0;
86 }
87
88 /* Return nonzero if the inferior is stopped inside a system call. */
89
90 static int
91 ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch)
92 {
93 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
94 struct target_ops *ops = &current_target;
95 gdb_byte buf[8];
96 int len;
97
98 len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL,
99 buf, IA64_HPUX_UREG_REASON, sizeof (buf));
100 if (len == -1)
101 /* The target wasn't able to tell us. Assume we are not stopped
102 in a system call, which is the normal situation. */
103 return 0;
104 gdb_assert (len == 8);
105
106 return (extract_unsigned_integer (buf, len, byte_order) == 0);
107 }
108
109 /* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux. */
110
111 static int
112 ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
113 ULONGEST cfm)
114 {
115 int sof;
116
117 if (frame_relative_level (this_frame) == 0
118 && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame)))
119 /* If the inferior stopped in a system call, the base address
120 of the register frame is at BSP - SOL instead of BSP - SOF.
121 This is an HP-UX exception. */
122 sof = (cfm & 0x3f80) >> 7;
123 else
124 sof = (cfm & 0x7f);
125
126 return sof;
127 }
128
129 /* Should be set to non-NULL if the ia64-hpux solib module is linked in.
130 This may not be the case because the shared library support code can
131 only be compiled on ia64-hpux. */
132
133 struct target_so_ops *ia64_hpux_so_ops = NULL;
134
135 static void
136 ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
137 {
138 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
139
140 tdep->size_of_register_frame = ia64_hpux_size_of_register_frame;
141
142 set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
143 set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
144
145 if (ia64_hpux_so_ops)
146 set_solib_ops (gdbarch, ia64_hpux_so_ops);
147 }
148
149 /* Provide a prototype to silence -Wmissing-prototypes. */
150 extern initialize_file_ftype _initialize_ia64_hpux_tdep;
151
152 void
153 _initialize_ia64_hpux_tdep (void)
154 {
155 gdbarch_register_osabi (bfd_arch_ia64, 0, GDB_OSABI_HPUX_ELF,
156 ia64_hpux_init_abi);
157 }
This page took 0.041794 seconds and 5 git commands to generate.