Move code to disable ASR to nat/
[deliverable/binutils-gdb.git] / gdb / ia64-hpux-tdep.c
CommitLineData
92c9a463
JB
1/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
2
32d0add0 3 Copyright (C) 2010-2015 Free Software Foundation, Inc.
92c9a463
JB
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"
77ca787b
JB
26#include "target.h"
27#include "frame.h"
c4de7027
JB
28#include "regcache.h"
29#include "gdbcore.h"
30#include "inferior.h"
31
32/* A sequence of instructions pushed on the stack when we want to perform
33 an inferior function call. The main purpose of this code is to save
34 the output region of the register frame belonging to the function
35 from which we are making the call. Normally, all registers are saved
36 prior to the call, but this does not include stacked registers because
37 they are seen by GDB as pseudo registers.
38
a9df6b22
JB
39 With Linux kernels, these stacked registers can be saved by simply
40 creating a new register frame, or in other words by moving the BSP.
41 But the HP/UX kernel does not allow this. So we rely on this code
42 instead, that makes functions calls whose only purpose is to create
43 new register frames.
c4de7027
JB
44
45 The array below is the result obtained after assembling the code
46 shown below. It's an array of bytes in order to make it independent
47 of the host endianess, in case it ends up being used on more than
48 one target.
49
50 start:
51 // Save b0 before using it (into preserved reg: r4).
52 mov r4 = b0
53 ;;
54
55 br.call.dptk.few b0 = stub#
56 ;;
57
58 // Add a nop bundle where we can insert our dummy breakpoint.
59 nop.m 0
60 nop.i 0
61 nop.i 0
62 ;;
63
64 stub:
65 // Alloc a new register stack frame. Here, we set the size
66 // of all regions to zero. Eventually, GDB will manually
67 // change the instruction to set the size of the local region
68 // to match size of the output region of the function from
69 // which we are making the function call. This is to protect
70 // the value of the output registers of the function from
71 // which we are making the call.
72 alloc r6 = ar.pfs, 0, 0, 0, 0
73
74 // Save b0 before using it again (into preserved reg: r5).
75 mov r5 = b0
76 ;;
77
78 // Now that we have protected the entire output region of the
79 // register stack frame, we can call our function that will
80 // setup the arguments, and call our target function.
81 br.call.dptk.few b0 = call_dummy#
82 ;;
83
84 // Restore b0, ar.pfs, and return
85 mov b0 = r5
86 mov.i ar.pfs = r6
87 ;;
88 br.ret.dptk.few b0
89 ;;
90
91 call_dummy:
92 // Alloc a new frame, with 2 local registers, and 8 output registers
93 // (8 output registers for the maximum of 8 slots passed by register).
94 alloc r32 = ar.pfs, 2, 0, 8, 0
95
96 // Save b0 before using it to call our target function.
97 mov r33 = b0
98
99 // Load the argument values placed by GDB inside r14-r21 in their
100 // proper registers.
101 or r34 = r14, r0
102 or r35 = r15, r0
103 or r36 = r16, r0
104 or r37 = r17, r0
105 or r38 = r18, r0
106 or r39 = r19, r0
107 or r40 = r20, r0
108 or r41 = r21, r0
109 ;;
110
111 // actual call
112 br.call.dptk.few b0 = b1
113 ;;
114
115 mov.i ar.pfs=r32
116 mov b0=r33
117 ;;
118
119 br.ret.dptk.few b0
120 ;;
121
122*/
123
124static const gdb_byte ia64_hpux_dummy_code[] =
125{
126 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00,
127 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
128 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
129 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x52,
130 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
131 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
132 0x02, 0x30, 0x00, 0x00, 0x80, 0x05, 0x50, 0x00,
133 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
134 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
135 0x00, 0x02, 0x00, 0x00, 0x30, 0x00, 0x00, 0x52,
136 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28,
137 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0xaa, 0x00,
138 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
139 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02,
140 0x00, 0x00, 0x29, 0x04, 0x80, 0x05, 0x10, 0x02,
141 0x00, 0x62, 0x00, 0x40, 0xe4, 0x00, 0x38, 0x80,
142 0x00, 0x18, 0x3d, 0x00, 0x0e, 0x20, 0x40, 0x82,
143 0x00, 0x1c, 0x40, 0xa0, 0x14, 0x01, 0x38, 0x80,
144 0x00, 0x30, 0x49, 0x00, 0x0e, 0x20, 0x70, 0x9a,
145 0x00, 0x1c, 0x40, 0x00, 0x45, 0x01, 0x38, 0x80,
146 0x0a, 0x48, 0x55, 0x00, 0x0e, 0x20, 0x00, 0x00,
147 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
148 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
149 0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x12,
150 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
151 0x01, 0x55, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x07,
152 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
153 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02
154};
77ca787b
JB
155
156/* The offset to be used in order to get the __reason pseudo-register
157 when using one of the *UREGS ttrace requests (see system header file
158 /usr/include/ia64/sys/uregs.h for more details).
159
160 The documentation for this pseudo-register says that a nonzero value
161 indicates that the thread stopped due to a fault, trap, or interrupt.
162 A null value indicates a stop inside a syscall. */
163#define IA64_HPUX_UREG_REASON 0x00070000
92c9a463
JB
164
165/* Return nonzero if the value of the register identified by REGNUM
166 can be modified. */
167
168static int
169ia64_hpux_can_store_ar_register (int regnum)
170{
171 switch (regnum)
172 {
173 case IA64_RSC_REGNUM:
174 case IA64_RNAT_REGNUM:
175 case IA64_CSD_REGNUM:
176 case IA64_SSD_REGNUM:
177 case IA64_CCV_REGNUM:
178 case IA64_UNAT_REGNUM:
179 case IA64_FPSR_REGNUM:
180 case IA64_PFS_REGNUM:
181 case IA64_LC_REGNUM:
182 case IA64_EC_REGNUM:
183 return 1;
184 break;
185
186 default:
187 return 0;
188 break;
189 }
190}
191
192/* The "cannot_store_register" target_ops method. */
193
194static int
195ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
196{
197 /* General registers. */
198
199 if (regnum == IA64_GR0_REGNUM)
200 return 1;
201
202 /* FP register. */
203
204 if (regnum == IA64_FR0_REGNUM || regnum == IA64_FR1_REGNUM)
205 return 1;
206
207 /* Application registers. */
208 if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_AR0_REGNUM + 127)
209 return (!ia64_hpux_can_store_ar_register (regnum));
210
211 /* We can store all other registers. */
212 return 0;
213}
214
77ca787b
JB
215/* Return nonzero if the inferior is stopped inside a system call. */
216
217static int
218ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch)
219{
220 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
221 struct target_ops *ops = &current_target;
222 gdb_byte buf[8];
223 int len;
224
225 len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL,
226 buf, IA64_HPUX_UREG_REASON, sizeof (buf));
227 if (len == -1)
228 /* The target wasn't able to tell us. Assume we are not stopped
229 in a system call, which is the normal situation. */
230 return 0;
231 gdb_assert (len == 8);
232
233 return (extract_unsigned_integer (buf, len, byte_order) == 0);
234}
235
236/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux. */
237
238static int
239ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
240 ULONGEST cfm)
241{
242 int sof;
243
244 if (frame_relative_level (this_frame) == 0
245 && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame)))
246 /* If the inferior stopped in a system call, the base address
247 of the register frame is at BSP - SOL instead of BSP - SOF.
248 This is an HP-UX exception. */
249 sof = (cfm & 0x3f80) >> 7;
250 else
251 sof = (cfm & 0x7f);
252
253 return sof;
254}
255
c4de7027
JB
256/* Implement the push_dummy_code gdbarch method.
257
258 This function assumes that the SP is already 16-byte-aligned. */
259
260static CORE_ADDR
261ia64_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
262 CORE_ADDR funaddr, struct value **args, int nargs,
263 struct type *value_type, CORE_ADDR *real_pc,
264 CORE_ADDR *bp_addr, struct regcache *regcache)
265{
266 ULONGEST cfm;
267 int sof, sol, sor, soo;
e362b510 268 gdb_byte buf[16];
c4de7027
JB
269
270 regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
271 sof = cfm & 0x7f;
272 sol = (cfm >> 7) & 0x7f;
273 sor = (cfm >> 14) & 0xf;
274 soo = sof - sol - sor;
275
276 /* Reserve some space on the stack to hold the dummy code. */
277 sp = sp - sizeof (ia64_hpux_dummy_code);
278
279 /* Set the breakpoint address at the first instruction of the bundle
280 in the dummy code that has only nops. This is where the dummy code
281 expects us to break. */
282 *bp_addr = sp + 0x20;
283
284 /* Start the inferior function call from the dummy code. The dummy
285 code will then call our function. */
286 *real_pc = sp;
287
288 /* Transfer the dummy code to the inferior. */
289 write_memory (sp, ia64_hpux_dummy_code, sizeof (ia64_hpux_dummy_code));
290
291 /* Update the size of the local portion of the register frame allocated
292 by ``stub'' to match the size of the output region of the current
293 register frame. This allows us to save the stacked registers.
294
295 The "alloc" instruction is located at slot 0 of the bundle at +0x30.
296 Update the "sof" and "sol" portion of that instruction which are
297 respectively at bits 18-24 and 25-31 of the bundle. */
298 memcpy (buf, ia64_hpux_dummy_code + 0x30, sizeof (buf));
299
300 buf[2] |= ((soo & 0x3f) << 2);
301 buf[3] |= (soo << 1);
302 if (soo > 63)
303 buf[3] |= 1;
304
305 write_memory (sp + 0x30, buf, sizeof (buf));
306
307 /* Return the new (already properly aligned) SP. */
308 return sp;
309}
310
311/* The "allocate_new_rse_frame" ia64_infcall_ops routine for ia64-hpux. */
312
313static void
314ia64_hpux_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp,
315 int sof)
316{
317 /* We cannot change the value of the BSP register on HP-UX,
318 so we can't allocate a new RSE frame. */
319}
320
321/* The "store_argument_in_slot" ia64_infcall_ops routine for ia64-hpux. */
322
323static void
324ia64_hpux_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
325 int slotnum, gdb_byte *buf)
326{
327 /* The call sequence on this target expects us to place the arguments
328 inside r14 - r21. */
329 regcache_cooked_write (regcache, IA64_GR0_REGNUM + 14 + slotnum, buf);
330}
331
332/* The "set_function_addr" ia64_infcall_ops routine for ia64-hpux. */
333
334static void
335ia64_hpux_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
336{
337 /* The calling sequence calls the function whose address is placed
338 in register b1. */
339 regcache_cooked_write_unsigned (regcache, IA64_BR1_REGNUM, func_addr);
340}
341
342/* The ia64_infcall_ops structure for ia64-hpux. */
343
344static const struct ia64_infcall_ops ia64_hpux_infcall_ops =
345{
346 ia64_hpux_allocate_new_rse_frame,
347 ia64_hpux_store_argument_in_slot,
348 ia64_hpux_set_function_addr
349};
350
351/* The "dummy_id" gdbarch routine for ia64-hpux. */
352
353static struct frame_id
354ia64_hpux_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
355{
356 CORE_ADDR sp, pc, bp_addr, bsp;
357
358 sp = get_frame_register_unsigned (this_frame, IA64_GR12_REGNUM);
359
360 /* Just double-check that the frame PC is within a certain region
361 of the stack that would be plausible for our dummy code (the dummy
362 code was pushed at SP + 16). If not, then return a null frame ID.
363 This is necessary in our case, because it is possible to produce
364 the same frame ID for a normal frame, if that frame corresponds
365 to the function called by our dummy code, and the function has not
366 modified the registers that we use to build the dummy frame ID. */
367 pc = get_frame_pc (this_frame);
368 if (pc < sp + 16 || pc >= sp + 16 + sizeof (ia64_hpux_dummy_code))
369 return null_frame_id;
370
371 /* The call sequence is such that the address of the dummy breakpoint
372 we inserted is stored in r5. */
373 bp_addr = get_frame_register_unsigned (this_frame, IA64_GR5_REGNUM);
374
375 bsp = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM);
376
377 return frame_id_build_special (sp, bp_addr, bsp);
378}
379
92c9a463
JB
380/* Should be set to non-NULL if the ia64-hpux solib module is linked in.
381 This may not be the case because the shared library support code can
382 only be compiled on ia64-hpux. */
383
384struct target_so_ops *ia64_hpux_so_ops = NULL;
385
c4de7027
JB
386/* The "find_global_pointer_from_solib" gdbarch_tdep routine for
387 ia64-hpux. */
388
389static CORE_ADDR
390ia64_hpux_find_global_pointer_from_solib (struct gdbarch *gdbarch,
391 CORE_ADDR faddr)
392{
393 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
394 struct target_ops *ops = &current_target;
395 gdb_byte buf[8];
396 LONGEST len;
397
398 len = target_read (ops, TARGET_OBJECT_HPUX_SOLIB_GOT,
399 paddress (gdbarch, faddr), buf, 0, sizeof (buf));
400
401 return extract_unsigned_integer (buf, len, byte_order);
402}
403
92c9a463
JB
404static void
405ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
406{
77ca787b
JB
407 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
408
409 tdep->size_of_register_frame = ia64_hpux_size_of_register_frame;
410
92c9a463
JB
411 set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
412 set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
413
c4de7027
JB
414 /* Inferior functions must be called from stack. */
415 set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
416 set_gdbarch_push_dummy_code (gdbarch, ia64_hpux_push_dummy_code);
417 tdep->infcall_ops = ia64_hpux_infcall_ops;
418 tdep->find_global_pointer_from_solib
419 = ia64_hpux_find_global_pointer_from_solib;
420 set_gdbarch_dummy_id (gdbarch, ia64_hpux_dummy_id);
421
92c9a463
JB
422 if (ia64_hpux_so_ops)
423 set_solib_ops (gdbarch, ia64_hpux_so_ops);
424}
425
426/* Provide a prototype to silence -Wmissing-prototypes. */
427extern initialize_file_ftype _initialize_ia64_hpux_tdep;
428
429void
430_initialize_ia64_hpux_tdep (void)
431{
432 gdbarch_register_osabi (bfd_arch_ia64, 0, GDB_OSABI_HPUX_ELF,
433 ia64_hpux_init_abi);
434}
This page took 0.615583 seconds and 4 git commands to generate.