]>
Commit | Line | Data |
---|---|---|
1f82754b JB |
1 | /* Native support code for PPC AIX, for GDB the GNU debugger. |
2 | ||
1d506c26 | 3 | Copyright (C) 2006-2024 Free Software Foundation, Inc. |
1f82754b JB |
4 | |
5 | Free Software Foundation, Inc. | |
6 | ||
7 | This file is part of GDB. | |
8 | ||
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 | |
a9762ec7 | 11 | the Free Software Foundation; either version 3 of the License, or |
1f82754b JB |
12 | (at your option) any later version. |
13 | ||
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. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 20 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
1f82754b JB |
21 | |
22 | #include "defs.h" | |
23 | #include "osabi.h" | |
7a61a01c UW |
24 | #include "regcache.h" |
25 | #include "regset.h" | |
4a7622d1 UW |
26 | #include "gdbtypes.h" |
27 | #include "gdbcore.h" | |
28 | #include "target.h" | |
29 | #include "value.h" | |
30 | #include "infcall.h" | |
31 | #include "objfiles.h" | |
32 | #include "breakpoint.h" | |
6f7f3f0d | 33 | #include "ppc-tdep.h" |
356a5233 | 34 | #include "rs6000-aix-tdep.h" |
d5367fe1 | 35 | #include "xcoffread.h" |
4d1eb6b4 JB |
36 | #include "solib.h" |
37 | #include "solib-aix.h" | |
3b2ca824 | 38 | #include "target-float.h" |
268a13a5 | 39 | #include "gdbsupport/xml-utils.h" |
cdcda965 SM |
40 | #include "trad-frame.h" |
41 | #include "frame-unwind.h" | |
4a7622d1 UW |
42 | |
43 | /* If the kernel has to deliver a signal, it pushes a sigcontext | |
44 | structure on the stack and then calls the signal handler, passing | |
0df8b418 | 45 | the address of the sigcontext in an argument register. Usually |
4a7622d1 UW |
46 | the signal handler doesn't save this register, so we have to |
47 | access the sigcontext structure via an offset from the signal handler | |
48 | frame. | |
cdcda965 SM |
49 | The following constants were determined by experimentation on AIX 3.2. |
50 | ||
51 | sigcontext structure have the mstsave saved under the | |
52 | sc_jmpbuf.jmp_context. STKMIN(minimum stack size) is 56 for 32-bit | |
53 | processes, and iar offset under sc_jmpbuf.jmp_context is 40. | |
54 | ie offsetof(struct sigcontext, sc_jmpbuf.jmp_context.iar). | |
55 | so PC offset in this case is STKMIN+iar offset, which is 96. */ | |
56 | ||
4a7622d1 UW |
57 | #define SIG_FRAME_PC_OFFSET 96 |
58 | #define SIG_FRAME_LR_OFFSET 108 | |
cdcda965 | 59 | /* STKMIN+grp1 offset, which is 56+228=284 */ |
4a7622d1 UW |
60 | #define SIG_FRAME_FP_OFFSET 284 |
61 | ||
cdcda965 SM |
62 | /* 64 bit process. |
63 | STKMIN64 is 112 and iar offset is 312. So 112+312=424 */ | |
64 | #define SIG_FRAME_LR_OFFSET64 424 | |
65 | /* STKMIN64+grp1 offset. 112+56=168 */ | |
66 | #define SIG_FRAME_FP_OFFSET64 168 | |
67 | ||
629f88f8 SM |
68 | /* Minimum possible text address in AIX. */ |
69 | #define AIX_TEXT_SEGMENT_BASE 0x10000000 | |
70 | ||
2eb26135 AVK |
71 | struct rs6000_aix_reg_vrreg_offset |
72 | { | |
73 | int vr0_offset; | |
74 | int vscr_offset; | |
75 | int vrsave_offset; | |
76 | }; | |
77 | ||
78 | static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset = | |
79 | { | |
80 | /* AltiVec registers. */ | |
81 | 32, /* vr0_offset */ | |
82 | 544, /* vscr_offset. */ | |
83 | 560 /* vrsave_offset */ | |
84 | }; | |
85 | ||
86 | static int | |
87 | rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep, | |
88 | const struct rs6000_aix_reg_vrreg_offset *offsets, | |
287de656 | 89 | int regnum) |
2eb26135 AVK |
90 | { |
91 | if (regnum >= tdep->ppc_vr0_regnum && | |
92 | regnum < tdep->ppc_vr0_regnum + ppc_num_vrs) | |
93 | return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16; | |
94 | ||
95 | if (regnum == tdep->ppc_vrsave_regnum - 1) | |
96 | return offsets->vscr_offset; | |
97 | ||
98 | if (regnum == tdep->ppc_vrsave_regnum) | |
99 | return offsets->vrsave_offset; | |
100 | ||
101 | return -1; | |
102 | } | |
103 | ||
104 | static void | |
105 | rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache, | |
287de656 | 106 | int regnum, const void *vrregs, size_t len) |
2eb26135 AVK |
107 | { |
108 | struct gdbarch *gdbarch = regcache->arch (); | |
109 | const struct rs6000_aix_reg_vrreg_offset *offsets; | |
110 | size_t offset; | |
111 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); | |
112 | if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0)) | |
113 | return; | |
114 | ||
115 | offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap; | |
116 | if (regnum == -1) | |
117 | { | |
118 | int i; | |
119 | ||
120 | for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; | |
121 | i < tdep->ppc_vr0_regnum + ppc_num_vrs; | |
122 | i++, offset += 16) | |
123 | ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16); | |
124 | ||
125 | ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1), | |
126 | (const gdb_byte *) vrregs, offsets->vscr_offset, 4); | |
127 | ||
128 | ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum, | |
129 | (const gdb_byte *) vrregs, offsets->vrsave_offset, 4); | |
130 | ||
131 | return; | |
132 | } | |
133 | offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum); | |
134 | if (regnum != tdep->ppc_vrsave_regnum && | |
135 | regnum != tdep->ppc_vrsave_regnum - 1) | |
136 | ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16); | |
137 | else | |
138 | ppc_supply_reg (regcache, regnum, | |
139 | (const gdb_byte *) vrregs, offset, 4); | |
140 | ||
141 | } | |
142 | ||
143 | static void | |
144 | rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache, | |
287de656 | 145 | int regnum, const void *vsxregs, size_t len) |
2eb26135 AVK |
146 | { |
147 | struct gdbarch *gdbarch = regcache->arch (); | |
148 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); | |
149 | if (!(tdep->ppc_vsr0_regnum >= 0)) | |
150 | return; | |
151 | ||
152 | if (regnum == -1) | |
153 | { | |
154 | int i, offset = 0; | |
155 | ||
156 | for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum | |
157 | + 32; i++, offset += 8) | |
158 | ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8); | |
159 | ||
160 | return; | |
161 | } | |
162 | else | |
163 | ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8); | |
164 | } | |
165 | ||
166 | static void | |
167 | rs6000_aix_collect_vsxregset (const struct regset *regset, | |
287de656 SM |
168 | const struct regcache *regcache, |
169 | int regnum, void *vsxregs, size_t len) | |
2eb26135 AVK |
170 | { |
171 | struct gdbarch *gdbarch = regcache->arch (); | |
172 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); | |
173 | if (!(tdep->ppc_vsr0_regnum >= 0)) | |
174 | return; | |
175 | ||
176 | if (regnum == -1) | |
177 | { | |
178 | int i; | |
179 | int offset = 0; | |
180 | for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum | |
181 | + 32; i++, offset += 8) | |
182 | ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8); | |
183 | ||
184 | return; | |
185 | } | |
287de656 | 186 | else |
2eb26135 AVK |
187 | ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8); |
188 | } | |
189 | ||
190 | static void | |
191 | rs6000_aix_collect_vrregset (const struct regset *regset, | |
287de656 SM |
192 | const struct regcache *regcache, |
193 | int regnum, void *vrregs, size_t len) | |
2eb26135 AVK |
194 | { |
195 | struct gdbarch *gdbarch = regcache->arch (); | |
196 | const struct rs6000_aix_reg_vrreg_offset *offsets; | |
197 | size_t offset; | |
198 | ||
199 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); | |
200 | if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0)) | |
201 | return; | |
202 | ||
203 | offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap; | |
204 | if (regnum == -1) | |
205 | { | |
206 | int i; | |
207 | ||
208 | for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i < | |
209 | tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16) | |
210 | ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16); | |
211 | ||
212 | ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1), | |
213 | (gdb_byte *) vrregs, offsets->vscr_offset, 4); | |
214 | ||
215 | ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum, | |
216 | (gdb_byte *) vrregs, offsets->vrsave_offset, 4); | |
217 | ||
218 | return; | |
219 | } | |
220 | ||
221 | offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum); | |
222 | if (regnum != tdep->ppc_vrsave_regnum | |
223 | && regnum != tdep->ppc_vrsave_regnum - 1) | |
224 | ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16); | |
225 | else | |
226 | ppc_collect_reg (regcache, regnum, | |
287de656 | 227 | (gdb_byte *) vrregs, offset, 4); |
2eb26135 AVK |
228 | } |
229 | ||
230 | static const struct regset rs6000_aix_vrregset = { | |
231 | &rs6000_aix_vrreg_offset, | |
232 | rs6000_aix_supply_vrregset, | |
233 | rs6000_aix_collect_vrregset | |
234 | }; | |
235 | ||
236 | static const struct regset rs6000_aix_vsxregset = { | |
237 | &rs6000_aix_vrreg_offset, | |
238 | rs6000_aix_supply_vsxregset, | |
239 | rs6000_aix_collect_vsxregset | |
240 | }; | |
241 | ||
cdcda965 | 242 | static struct trad_frame_cache * |
bd2b40ac | 243 | aix_sighandle_frame_cache (frame_info_ptr this_frame, |
cdcda965 SM |
244 | void **this_cache) |
245 | { | |
246 | LONGEST backchain; | |
247 | CORE_ADDR base, base_orig, func; | |
248 | struct gdbarch *gdbarch = get_frame_arch (this_frame); | |
08106042 | 249 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
cdcda965 SM |
250 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
251 | struct trad_frame_cache *this_trad_cache; | |
252 | ||
253 | if ((*this_cache) != NULL) | |
254 | return (struct trad_frame_cache *) (*this_cache); | |
255 | ||
256 | this_trad_cache = trad_frame_cache_zalloc (this_frame); | |
257 | (*this_cache) = this_trad_cache; | |
258 | ||
259 | base = get_frame_register_unsigned (this_frame, | |
dda83cd7 | 260 | gdbarch_sp_regnum (gdbarch)); |
cdcda965 SM |
261 | base_orig = base; |
262 | ||
263 | if (tdep->wordsize == 4) | |
264 | { | |
265 | func = read_memory_unsigned_integer (base_orig + | |
266 | SIG_FRAME_PC_OFFSET + 8, | |
267 | tdep->wordsize, byte_order); | |
268 | safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET + 8, | |
269 | tdep->wordsize, byte_order, &backchain); | |
270 | base = (CORE_ADDR)backchain; | |
271 | } | |
272 | else | |
273 | { | |
274 | func = read_memory_unsigned_integer (base_orig + | |
275 | SIG_FRAME_LR_OFFSET64, | |
276 | tdep->wordsize, byte_order); | |
277 | safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET64, | |
278 | tdep->wordsize, byte_order, &backchain); | |
279 | base = (CORE_ADDR)backchain; | |
280 | } | |
281 | ||
282 | trad_frame_set_reg_value (this_trad_cache, gdbarch_pc_regnum (gdbarch), func); | |
283 | trad_frame_set_reg_value (this_trad_cache, gdbarch_sp_regnum (gdbarch), base); | |
284 | ||
285 | if (tdep->wordsize == 4) | |
286 | trad_frame_set_reg_addr (this_trad_cache, tdep->ppc_lr_regnum, | |
dda83cd7 | 287 | base_orig + 0x38 + 52 + 8); |
cdcda965 SM |
288 | else |
289 | trad_frame_set_reg_addr (this_trad_cache, tdep->ppc_lr_regnum, | |
dda83cd7 | 290 | base_orig + 0x70 + 320); |
cdcda965 SM |
291 | |
292 | trad_frame_set_id (this_trad_cache, frame_id_build (base, func)); | |
293 | trad_frame_set_this_base (this_trad_cache, base); | |
294 | ||
295 | return this_trad_cache; | |
296 | } | |
297 | ||
298 | static void | |
bd2b40ac | 299 | aix_sighandle_frame_this_id (frame_info_ptr this_frame, |
cdcda965 SM |
300 | void **this_prologue_cache, |
301 | struct frame_id *this_id) | |
302 | { | |
303 | struct trad_frame_cache *this_trad_cache | |
304 | = aix_sighandle_frame_cache (this_frame, this_prologue_cache); | |
305 | trad_frame_get_id (this_trad_cache, this_id); | |
306 | } | |
307 | ||
308 | static struct value * | |
bd2b40ac | 309 | aix_sighandle_frame_prev_register (frame_info_ptr this_frame, |
cdcda965 SM |
310 | void **this_prologue_cache, int regnum) |
311 | { | |
312 | struct trad_frame_cache *this_trad_cache | |
313 | = aix_sighandle_frame_cache (this_frame, this_prologue_cache); | |
314 | return trad_frame_get_register (this_trad_cache, this_frame, regnum); | |
315 | } | |
316 | ||
cb8c24b6 | 317 | static int |
cdcda965 | 318 | aix_sighandle_frame_sniffer (const struct frame_unwind *self, |
bd2b40ac | 319 | frame_info_ptr this_frame, |
cdcda965 SM |
320 | void **this_prologue_cache) |
321 | { | |
322 | CORE_ADDR pc = get_frame_pc (this_frame); | |
323 | if (pc && pc < AIX_TEXT_SEGMENT_BASE) | |
324 | return 1; | |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
329 | /* AIX signal handler frame unwinder */ | |
330 | ||
331 | static const struct frame_unwind aix_sighandle_frame_unwind = { | |
a154d838 | 332 | "rs6000 aix sighandle", |
cdcda965 SM |
333 | SIGTRAMP_FRAME, |
334 | default_frame_unwind_stop_reason, | |
335 | aix_sighandle_frame_this_id, | |
336 | aix_sighandle_frame_prev_register, | |
337 | NULL, | |
338 | aix_sighandle_frame_sniffer | |
339 | }; | |
7a61a01c UW |
340 | |
341 | /* Core file support. */ | |
342 | ||
343 | static struct ppc_reg_offsets rs6000_aix32_reg_offsets = | |
344 | { | |
345 | /* General-purpose registers. */ | |
346 | 208, /* r0_offset */ | |
f2db237a AM |
347 | 4, /* gpr_size */ |
348 | 4, /* xr_size */ | |
7a61a01c UW |
349 | 24, /* pc_offset */ |
350 | 28, /* ps_offset */ | |
351 | 32, /* cr_offset */ | |
352 | 36, /* lr_offset */ | |
353 | 40, /* ctr_offset */ | |
354 | 44, /* xer_offset */ | |
355 | 48, /* mq_offset */ | |
356 | ||
357 | /* Floating-point registers. */ | |
358 | 336, /* f0_offset */ | |
359 | 56, /* fpscr_offset */ | |
1d75a658 | 360 | 4 /* fpscr_size */ |
7a61a01c UW |
361 | }; |
362 | ||
363 | static struct ppc_reg_offsets rs6000_aix64_reg_offsets = | |
364 | { | |
365 | /* General-purpose registers. */ | |
366 | 0, /* r0_offset */ | |
f2db237a AM |
367 | 8, /* gpr_size */ |
368 | 4, /* xr_size */ | |
7a61a01c UW |
369 | 264, /* pc_offset */ |
370 | 256, /* ps_offset */ | |
371 | 288, /* cr_offset */ | |
372 | 272, /* lr_offset */ | |
373 | 280, /* ctr_offset */ | |
374 | 292, /* xer_offset */ | |
375 | -1, /* mq_offset */ | |
376 | ||
377 | /* Floating-point registers. */ | |
378 | 312, /* f0_offset */ | |
379 | 296, /* fpscr_offset */ | |
1d75a658 | 380 | 4 /* fpscr_size */ |
7a61a01c UW |
381 | }; |
382 | ||
383 | ||
384 | /* Supply register REGNUM in the general-purpose register set REGSET | |
385 | from the buffer specified by GREGS and LEN to register cache | |
386 | REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ | |
387 | ||
388 | static void | |
389 | rs6000_aix_supply_regset (const struct regset *regset, | |
390 | struct regcache *regcache, int regnum, | |
391 | const void *gregs, size_t len) | |
392 | { | |
393 | ppc_supply_gregset (regset, regcache, regnum, gregs, len); | |
f2db237a | 394 | ppc_supply_fpregset (regset, regcache, regnum, gregs, len); |
7a61a01c UW |
395 | } |
396 | ||
397 | /* Collect register REGNUM in the general-purpose register set | |
0df8b418 | 398 | REGSET, from register cache REGCACHE into the buffer specified by |
7a61a01c UW |
399 | GREGS and LEN. If REGNUM is -1, do this for all registers in |
400 | REGSET. */ | |
401 | ||
402 | static void | |
403 | rs6000_aix_collect_regset (const struct regset *regset, | |
404 | const struct regcache *regcache, int regnum, | |
405 | void *gregs, size_t len) | |
406 | { | |
407 | ppc_collect_gregset (regset, regcache, regnum, gregs, len); | |
f2db237a | 408 | ppc_collect_fpregset (regset, regcache, regnum, gregs, len); |
7a61a01c UW |
409 | } |
410 | ||
411 | /* AIX register set. */ | |
412 | ||
3ca7dae4 | 413 | static const struct regset rs6000_aix32_regset = |
7a61a01c UW |
414 | { |
415 | &rs6000_aix32_reg_offsets, | |
416 | rs6000_aix_supply_regset, | |
417 | rs6000_aix_collect_regset, | |
418 | }; | |
419 | ||
3ca7dae4 | 420 | static const struct regset rs6000_aix64_regset = |
7a61a01c UW |
421 | { |
422 | &rs6000_aix64_reg_offsets, | |
423 | rs6000_aix_supply_regset, | |
424 | rs6000_aix_collect_regset, | |
425 | }; | |
426 | ||
23ea9aeb | 427 | /* Iterate over core file register note sections. */ |
7a61a01c | 428 | |
23ea9aeb AA |
429 | static void |
430 | rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch, | |
431 | iterate_over_regset_sections_cb *cb, | |
432 | void *cb_data, | |
433 | const struct regcache *regcache) | |
7a61a01c | 434 | { |
08106042 | 435 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
2eb26135 AVK |
436 | int have_altivec = tdep->ppc_vr0_regnum != -1; |
437 | int have_vsx = tdep->ppc_vsr0_upper_regnum != -1; | |
438 | ||
345bd07c | 439 | if (tdep->wordsize == 4) |
a616bb94 | 440 | cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data); |
7a61a01c | 441 | else |
a616bb94 | 442 | cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data); |
2eb26135 AVK |
443 | |
444 | if (have_altivec) | |
445 | cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data); | |
446 | ||
447 | if (have_vsx) | |
448 | cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data); | |
449 | ||
7a61a01c UW |
450 | } |
451 | ||
a8ea150e AVK |
452 | /* Read core file description for AIX. */ |
453 | ||
454 | static const struct target_desc * | |
455 | ppc_aix_core_read_description (struct gdbarch *gdbarch, | |
456 | struct target_ops *target, | |
457 | bfd *abfd) | |
458 | { | |
459 | asection *altivec = bfd_get_section_by_name (abfd, ".aix-vmx"); | |
460 | asection *vsx = bfd_get_section_by_name (abfd, ".aix-vsx"); | |
461 | asection *section = bfd_get_section_by_name (abfd, ".reg"); | |
462 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); | |
463 | ||
464 | if (!section) | |
465 | return NULL; | |
466 | ||
467 | int arch64 = 0; | |
468 | if (tdep->wordsize == 8) | |
469 | arch64 = 1; | |
470 | ||
471 | if (vsx && arch64) | |
472 | return tdesc_powerpc_vsx64; | |
473 | else if (vsx && !arch64) | |
474 | return tdesc_powerpc_vsx32; | |
475 | else if (altivec && arch64) | |
476 | return tdesc_powerpc_altivec64; | |
477 | else if (altivec && !arch64) | |
478 | return tdesc_powerpc_altivec32; | |
479 | ||
480 | return NULL; | |
481 | } | |
7a61a01c | 482 | |
0df8b418 | 483 | /* Pass the arguments in either registers, or in the stack. In RS/6000, |
4a7622d1 UW |
484 | the first eight words of the argument list (that might be less than |
485 | eight parameters if some parameters occupy more than one word) are | |
0df8b418 | 486 | passed in r3..r10 registers. Float and double parameters are |
4a7622d1 UW |
487 | passed in fpr's, in addition to that. Rest of the parameters if any |
488 | are passed in user stack. There might be cases in which half of the | |
489 | parameter is copied into registers, the other half is pushed into | |
490 | stack. | |
491 | ||
492 | Stack must be aligned on 64-bit boundaries when synthesizing | |
493 | function calls. | |
494 | ||
495 | If the function is returning a structure, then the return address is passed | |
496 | in r3, then the first 7 words of the parameters can be passed in registers, | |
497 | starting from r4. */ | |
498 | ||
499 | static CORE_ADDR | |
500 | rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function, | |
501 | struct regcache *regcache, CORE_ADDR bp_addr, | |
502 | int nargs, struct value **args, CORE_ADDR sp, | |
cf84fa6b AH |
503 | function_call_return_method return_method, |
504 | CORE_ADDR struct_addr) | |
4a7622d1 | 505 | { |
08106042 | 506 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
e17a4113 | 507 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
4a7622d1 UW |
508 | int ii; |
509 | int len = 0; | |
510 | int argno; /* current argument number */ | |
511 | int argbytes; /* current argument byte */ | |
512 | gdb_byte tmp_buffer[50]; | |
513 | int f_argno = 0; /* current floating point argno */ | |
345bd07c | 514 | int wordsize = tdep->wordsize; |
4a7622d1 UW |
515 | CORE_ADDR func_addr = find_function_addr (function, NULL); |
516 | ||
517 | struct value *arg = 0; | |
518 | struct type *type; | |
519 | ||
520 | ULONGEST saved_sp; | |
521 | ||
522 | /* The calling convention this function implements assumes the | |
523 | processor has floating-point registers. We shouldn't be using it | |
524 | on PPC variants that lack them. */ | |
525 | gdb_assert (ppc_floating_point_unit_p (gdbarch)); | |
526 | ||
527 | /* The first eight words of ther arguments are passed in registers. | |
528 | Copy them appropriately. */ | |
529 | ii = 0; | |
530 | ||
531 | /* If the function is returning a `struct', then the first word | |
532 | (which will be passed in r3) is used for struct return address. | |
533 | In that case we should advance one word and start from r4 | |
534 | register to copy parameters. */ | |
cf84fa6b | 535 | if (return_method == return_method_struct) |
4a7622d1 UW |
536 | { |
537 | regcache_raw_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, | |
538 | struct_addr); | |
539 | ii++; | |
540 | } | |
541 | ||
0df8b418 | 542 | /* effectively indirect call... gcc does... |
4a7622d1 UW |
543 | |
544 | return_val example( float, int); | |
545 | ||
546 | eabi: | |
547 | float in fp0, int in r3 | |
548 | offset of stack on overflow 8/16 | |
549 | for varargs, must go by type. | |
550 | power open: | |
551 | float in r3&r4, int in r5 | |
552 | offset of stack on overflow different | |
553 | both: | |
554 | return in r3 or f0. If no float, must study how gcc emulates floats; | |
0df8b418 | 555 | pay attention to arg promotion. |
4a7622d1 | 556 | User may have to cast\args to handle promotion correctly |
0df8b418 | 557 | since gdb won't know if prototype supplied or not. */ |
4a7622d1 UW |
558 | |
559 | for (argno = 0, argbytes = 0; argno < nargs && ii < 8; ++ii) | |
560 | { | |
561 | int reg_size = register_size (gdbarch, ii + 3); | |
562 | ||
563 | arg = args[argno]; | |
d0c97917 | 564 | type = check_typedef (arg->type ()); |
df86565b | 565 | len = type->length (); |
4a7622d1 | 566 | |
78134374 | 567 | if (type->code () == TYPE_CODE_FLT) |
4a7622d1 | 568 | { |
4a7622d1 | 569 | /* Floating point arguments are passed in fpr's, as well as gpr's. |
0df8b418 | 570 | There are 13 fpr's reserved for passing parameters. At this point |
36d1c68c JB |
571 | there is no way we would run out of them. |
572 | ||
573 | Always store the floating point value using the register's | |
574 | floating-point format. */ | |
575 | const int fp_regnum = tdep->ppc_fp0_regnum + 1 + f_argno; | |
0f068fb5 | 576 | gdb_byte reg_val[PPC_MAX_REGISTER_SIZE]; |
36d1c68c | 577 | struct type *reg_type = register_type (gdbarch, fp_regnum); |
4a7622d1 UW |
578 | |
579 | gdb_assert (len <= 8); | |
580 | ||
efaf1ae0 | 581 | target_float_convert (arg->contents ().data (), type, reg_val, |
50888e42 | 582 | reg_type); |
b66f5587 | 583 | regcache->cooked_write (fp_regnum, reg_val); |
4a7622d1 UW |
584 | ++f_argno; |
585 | } | |
586 | ||
587 | if (len > reg_size) | |
588 | { | |
589 | ||
590 | /* Argument takes more than one register. */ | |
591 | while (argbytes < len) | |
592 | { | |
0f068fb5 | 593 | gdb_byte word[PPC_MAX_REGISTER_SIZE]; |
4a7622d1 UW |
594 | memset (word, 0, reg_size); |
595 | memcpy (word, | |
efaf1ae0 | 596 | ((char *) arg->contents ().data ()) + argbytes, |
4a7622d1 | 597 | (len - argbytes) > reg_size |
dda83cd7 | 598 | ? reg_size : len - argbytes); |
b66f5587 | 599 | regcache->cooked_write (tdep->ppc_gp0_regnum + 3 + ii, word); |
4a7622d1 UW |
600 | ++ii, argbytes += reg_size; |
601 | ||
602 | if (ii >= 8) | |
603 | goto ran_out_of_registers_for_arguments; | |
604 | } | |
605 | argbytes = 0; | |
606 | --ii; | |
607 | } | |
608 | else | |
609 | { | |
610 | /* Argument can fit in one register. No problem. */ | |
0f068fb5 | 611 | gdb_byte word[PPC_MAX_REGISTER_SIZE]; |
4a7622d1 UW |
612 | |
613 | memset (word, 0, reg_size); | |
7aae1a86 AVK |
614 | if (type->code () == TYPE_CODE_INT |
615 | || type->code () == TYPE_CODE_ENUM | |
616 | || type->code () == TYPE_CODE_BOOL | |
617 | || type->code () == TYPE_CODE_CHAR) | |
618 | /* Sign or zero extend the "int" into a "word". */ | |
619 | store_unsigned_integer (word, reg_size, byte_order, | |
efaf1ae0 | 620 | unpack_long (type, arg->contents ().data ())); |
7aae1a86 | 621 | else |
efaf1ae0 | 622 | memcpy (word, arg->contents ().data (), len); |
b66f5587 | 623 | regcache->cooked_write (tdep->ppc_gp0_regnum + 3 +ii, word); |
4a7622d1 UW |
624 | } |
625 | ++argno; | |
626 | } | |
627 | ||
628 | ran_out_of_registers_for_arguments: | |
629 | ||
630 | regcache_cooked_read_unsigned (regcache, | |
631 | gdbarch_sp_regnum (gdbarch), | |
632 | &saved_sp); | |
633 | ||
634 | /* Location for 8 parameters are always reserved. */ | |
635 | sp -= wordsize * 8; | |
636 | ||
637 | /* Another six words for back chain, TOC register, link register, etc. */ | |
638 | sp -= wordsize * 6; | |
639 | ||
640 | /* Stack pointer must be quadword aligned. */ | |
641 | sp &= -16; | |
642 | ||
643 | /* If there are more arguments, allocate space for them in | |
644 | the stack, then push them starting from the ninth one. */ | |
645 | ||
646 | if ((argno < nargs) || argbytes) | |
647 | { | |
648 | int space = 0, jj; | |
649 | ||
650 | if (argbytes) | |
651 | { | |
99dc9709 | 652 | space += ((len - argbytes + wordsize -1) & -wordsize); |
4a7622d1 UW |
653 | jj = argno + 1; |
654 | } | |
655 | else | |
656 | jj = argno; | |
657 | ||
658 | for (; jj < nargs; ++jj) | |
659 | { | |
660 | struct value *val = args[jj]; | |
99dc9709 | 661 | space += ((val->type ()->length () + wordsize -1) & -wordsize); |
4a7622d1 UW |
662 | } |
663 | ||
664 | /* Add location required for the rest of the parameters. */ | |
665 | space = (space + 15) & -16; | |
666 | sp -= space; | |
667 | ||
668 | /* This is another instance we need to be concerned about | |
dda83cd7 SM |
669 | securing our stack space. If we write anything underneath %sp |
670 | (r1), we might conflict with the kernel who thinks he is free | |
671 | to use this area. So, update %sp first before doing anything | |
672 | else. */ | |
4a7622d1 UW |
673 | |
674 | regcache_raw_write_signed (regcache, | |
675 | gdbarch_sp_regnum (gdbarch), sp); | |
676 | ||
677 | /* If the last argument copied into the registers didn't fit there | |
dda83cd7 | 678 | completely, push the rest of it into stack. */ |
4a7622d1 UW |
679 | |
680 | if (argbytes) | |
681 | { | |
99dc9709 | 682 | write_memory (sp + 6 * wordsize + (ii * wordsize), |
efaf1ae0 | 683 | arg->contents ().data () + argbytes, |
4a7622d1 UW |
684 | len - argbytes); |
685 | ++argno; | |
99dc9709 | 686 | ii += ((len - argbytes + wordsize - 1) & -wordsize) / wordsize; |
4a7622d1 UW |
687 | } |
688 | ||
689 | /* Push the rest of the arguments into stack. */ | |
690 | for (; argno < nargs; ++argno) | |
691 | { | |
692 | ||
693 | arg = args[argno]; | |
d0c97917 | 694 | type = check_typedef (arg->type ()); |
df86565b | 695 | len = type->length (); |
4a7622d1 UW |
696 | |
697 | ||
698 | /* Float types should be passed in fpr's, as well as in the | |
dda83cd7 | 699 | stack. */ |
78134374 | 700 | if (type->code () == TYPE_CODE_FLT && f_argno < 13) |
4a7622d1 UW |
701 | { |
702 | ||
703 | gdb_assert (len <= 8); | |
704 | ||
b66f5587 | 705 | regcache->cooked_write (tdep->ppc_fp0_regnum + 1 + f_argno, |
efaf1ae0 | 706 | arg->contents ().data ()); |
4a7622d1 UW |
707 | ++f_argno; |
708 | } | |
709 | ||
99dc9709 AVK |
710 | if (type->code () == TYPE_CODE_INT |
711 | || type->code () == TYPE_CODE_ENUM | |
712 | || type->code () == TYPE_CODE_BOOL | |
713 | || type->code () == TYPE_CODE_CHAR ) | |
714 | { | |
715 | gdb_byte word[PPC_MAX_REGISTER_SIZE]; | |
716 | memset (word, 0, PPC_MAX_REGISTER_SIZE); | |
717 | store_unsigned_integer (word, tdep->wordsize, byte_order, | |
718 | unpack_long (type, arg->contents ().data ())); | |
719 | write_memory (sp + 6 * wordsize + (ii * wordsize), word, PPC_MAX_REGISTER_SIZE); | |
720 | } | |
721 | else | |
722 | write_memory (sp + 6 * wordsize + (ii * wordsize), arg->contents ().data (), len); | |
723 | ii += ((len + wordsize -1) & -wordsize) / wordsize; | |
4a7622d1 UW |
724 | } |
725 | } | |
726 | ||
727 | /* Set the stack pointer. According to the ABI, the SP is meant to | |
728 | be set _before_ the corresponding stack space is used. On AIX, | |
729 | this even applies when the target has been completely stopped! | |
730 | Not doing this can lead to conflicts with the kernel which thinks | |
731 | that it still has control over this not-yet-allocated stack | |
732 | region. */ | |
733 | regcache_raw_write_signed (regcache, gdbarch_sp_regnum (gdbarch), sp); | |
734 | ||
735 | /* Set back chain properly. */ | |
e17a4113 | 736 | store_unsigned_integer (tmp_buffer, wordsize, byte_order, saved_sp); |
4a7622d1 UW |
737 | write_memory (sp, tmp_buffer, wordsize); |
738 | ||
739 | /* Point the inferior function call's return address at the dummy's | |
740 | breakpoint. */ | |
741 | regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); | |
742 | ||
4d1eb6b4 JB |
743 | /* Set the TOC register value. */ |
744 | regcache_raw_write_signed (regcache, tdep->ppc_toc_regnum, | |
745 | solib_aix_get_toc_value (func_addr)); | |
4a7622d1 UW |
746 | |
747 | target_store_registers (regcache, -1); | |
748 | return sp; | |
749 | } | |
750 | ||
751 | static enum return_value_convention | |
6a3a010b | 752 | rs6000_return_value (struct gdbarch *gdbarch, struct value *function, |
4a7622d1 UW |
753 | struct type *valtype, struct regcache *regcache, |
754 | gdb_byte *readbuf, const gdb_byte *writebuf) | |
755 | { | |
08106042 | 756 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
e17a4113 | 757 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
4a7622d1 UW |
758 | |
759 | /* The calling convention this function implements assumes the | |
760 | processor has floating-point registers. We shouldn't be using it | |
761 | on PowerPC variants that lack them. */ | |
762 | gdb_assert (ppc_floating_point_unit_p (gdbarch)); | |
763 | ||
764 | /* AltiVec extension: Functions that declare a vector data type as a | |
765 | return value place that return value in VR2. */ | |
bd63c870 | 766 | if (valtype->code () == TYPE_CODE_ARRAY && valtype->is_vector () |
df86565b | 767 | && valtype->length () == 16) |
4a7622d1 UW |
768 | { |
769 | if (readbuf) | |
dca08e1f | 770 | regcache->cooked_read (tdep->ppc_vr0_regnum + 2, readbuf); |
4a7622d1 | 771 | if (writebuf) |
b66f5587 | 772 | regcache->cooked_write (tdep->ppc_vr0_regnum + 2, writebuf); |
4a7622d1 UW |
773 | |
774 | return RETURN_VALUE_REGISTER_CONVENTION; | |
775 | } | |
776 | ||
777 | /* If the called subprogram returns an aggregate, there exists an | |
778 | implicit first argument, whose value is the address of a caller- | |
779 | allocated buffer into which the callee is assumed to store its | |
0df8b418 | 780 | return value. All explicit parameters are appropriately |
4a7622d1 | 781 | relabeled. */ |
78134374 SM |
782 | if (valtype->code () == TYPE_CODE_STRUCT |
783 | || valtype->code () == TYPE_CODE_UNION | |
784 | || valtype->code () == TYPE_CODE_ARRAY) | |
4a7622d1 UW |
785 | return RETURN_VALUE_STRUCT_CONVENTION; |
786 | ||
787 | /* Scalar floating-point values are returned in FPR1 for float or | |
788 | double, and in FPR1:FPR2 for quadword precision. Fortran | |
789 | complex*8 and complex*16 are returned in FPR1:FPR2, and | |
790 | complex*32 is returned in FPR1:FPR4. */ | |
78134374 | 791 | if (valtype->code () == TYPE_CODE_FLT |
df86565b | 792 | && (valtype->length () == 4 || valtype->length () == 8)) |
4a7622d1 UW |
793 | { |
794 | struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum); | |
795 | gdb_byte regval[8]; | |
796 | ||
797 | /* FIXME: kettenis/2007-01-01: Add support for quadword | |
798 | precision and complex. */ | |
799 | ||
800 | if (readbuf) | |
801 | { | |
dca08e1f | 802 | regcache->cooked_read (tdep->ppc_fp0_regnum + 1, regval); |
3b2ca824 | 803 | target_float_convert (regval, regtype, readbuf, valtype); |
4a7622d1 UW |
804 | } |
805 | if (writebuf) | |
806 | { | |
3b2ca824 | 807 | target_float_convert (writebuf, valtype, regval, regtype); |
b66f5587 | 808 | regcache->cooked_write (tdep->ppc_fp0_regnum + 1, regval); |
4a7622d1 UW |
809 | } |
810 | ||
811 | return RETURN_VALUE_REGISTER_CONVENTION; | |
812 | } | |
813 | ||
814 | /* Values of the types int, long, short, pointer, and char (length | |
815 | is less than or equal to four bytes), as well as bit values of | |
816 | lengths less than or equal to 32 bits, must be returned right | |
817 | justified in GPR3 with signed values sign extended and unsigned | |
818 | values zero extended, as necessary. */ | |
df86565b | 819 | if (valtype->length () <= tdep->wordsize) |
4a7622d1 UW |
820 | { |
821 | if (readbuf) | |
822 | { | |
823 | ULONGEST regval; | |
824 | ||
825 | /* For reading we don't have to worry about sign extension. */ | |
826 | regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3, | |
827 | ®val); | |
df86565b | 828 | store_unsigned_integer (readbuf, valtype->length (), byte_order, |
e17a4113 | 829 | regval); |
4a7622d1 UW |
830 | } |
831 | if (writebuf) | |
832 | { | |
833 | /* For writing, use unpack_long since that should handle any | |
834 | required sign extension. */ | |
835 | regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, | |
836 | unpack_long (valtype, writebuf)); | |
837 | } | |
838 | ||
839 | return RETURN_VALUE_REGISTER_CONVENTION; | |
840 | } | |
841 | ||
842 | /* Eight-byte non-floating-point scalar values must be returned in | |
843 | GPR3:GPR4. */ | |
844 | ||
df86565b | 845 | if (valtype->length () == 8) |
4a7622d1 | 846 | { |
78134374 | 847 | gdb_assert (valtype->code () != TYPE_CODE_FLT); |
4a7622d1 UW |
848 | gdb_assert (tdep->wordsize == 4); |
849 | ||
850 | if (readbuf) | |
851 | { | |
852 | gdb_byte regval[8]; | |
853 | ||
dca08e1f SM |
854 | regcache->cooked_read (tdep->ppc_gp0_regnum + 3, regval); |
855 | regcache->cooked_read (tdep->ppc_gp0_regnum + 4, regval + 4); | |
4a7622d1 UW |
856 | memcpy (readbuf, regval, 8); |
857 | } | |
858 | if (writebuf) | |
859 | { | |
b66f5587 SM |
860 | regcache->cooked_write (tdep->ppc_gp0_regnum + 3, writebuf); |
861 | regcache->cooked_write (tdep->ppc_gp0_regnum + 4, writebuf + 4); | |
4a7622d1 UW |
862 | } |
863 | ||
864 | return RETURN_VALUE_REGISTER_CONVENTION; | |
865 | } | |
866 | ||
867 | return RETURN_VALUE_STRUCT_CONVENTION; | |
868 | } | |
869 | ||
870 | /* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG). | |
871 | ||
872 | Usually a function pointer's representation is simply the address | |
0df8b418 MS |
873 | of the function. On the RS/6000 however, a function pointer is |
874 | represented by a pointer to an OPD entry. This OPD entry contains | |
4a7622d1 UW |
875 | three words, the first word is the address of the function, the |
876 | second word is the TOC pointer (r2), and the third word is the | |
877 | static chain value. Throughout GDB it is currently assumed that a | |
878 | function pointer contains the address of the function, which is not | |
879 | easy to fix. In addition, the conversion of a function address to | |
880 | a function pointer would require allocation of an OPD entry in the | |
881 | inferior's memory space, with all its drawbacks. To be able to | |
882 | call C++ virtual methods in the inferior (which are called via | |
883 | function pointers), find_function_addr uses this function to get the | |
884 | function address from a function pointer. */ | |
885 | ||
886 | /* Return real function address if ADDR (a function pointer) is in the data | |
887 | space and is therefore a special function pointer. */ | |
888 | ||
889 | static CORE_ADDR | |
890 | rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, | |
891 | CORE_ADDR addr, | |
892 | struct target_ops *targ) | |
893 | { | |
08106042 | 894 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
e17a4113 | 895 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
4a7622d1 UW |
896 | struct obj_section *s; |
897 | ||
898 | s = find_pc_section (addr); | |
4a7622d1 | 899 | |
40adab56 JB |
900 | /* Normally, functions live inside a section that is executable. |
901 | So, if ADDR points to a non-executable section, then treat it | |
902 | as a function descriptor and return the target address iff | |
903 | the target address itself points to a section that is executable. */ | |
904 | if (s && (s->the_bfd_section->flags & SEC_CODE) == 0) | |
905 | { | |
57174f31 | 906 | CORE_ADDR pc = 0; |
2971b56b | 907 | struct obj_section *pc_section; |
2971b56b | 908 | |
a70b8144 | 909 | try |
dda83cd7 SM |
910 | { |
911 | pc = read_memory_unsigned_integer (addr, tdep->wordsize, byte_order); | |
912 | } | |
230d2906 | 913 | catch (const gdb_exception_error &e) |
dda83cd7 | 914 | { |
33b5899f | 915 | /* An error occurred during reading. Probably a memory error |
dda83cd7 SM |
916 | due to the section not being loaded yet. This address |
917 | cannot be a function descriptor. */ | |
918 | return addr; | |
919 | } | |
492d29ea | 920 | |
2971b56b | 921 | pc_section = find_pc_section (pc); |
40adab56 JB |
922 | |
923 | if (pc_section && (pc_section->the_bfd_section->flags & SEC_CODE)) | |
dda83cd7 | 924 | return pc; |
40adab56 JB |
925 | } |
926 | ||
927 | return addr; | |
4a7622d1 UW |
928 | } |
929 | ||
930 | ||
931 | /* Calculate the destination of a branch/jump. Return -1 if not a branch. */ | |
932 | ||
933 | static CORE_ADDR | |
41e26ad3 | 934 | branch_dest (struct regcache *regcache, int opcode, int instr, |
4a7622d1 UW |
935 | CORE_ADDR pc, CORE_ADDR safety) |
936 | { | |
ac7936df | 937 | struct gdbarch *gdbarch = regcache->arch (); |
08106042 | 938 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
e17a4113 | 939 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
4a7622d1 UW |
940 | CORE_ADDR dest; |
941 | int immediate; | |
942 | int absolute; | |
943 | int ext_op; | |
944 | ||
945 | absolute = (int) ((instr >> 1) & 1); | |
946 | ||
947 | switch (opcode) | |
948 | { | |
949 | case 18: | |
950 | immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */ | |
951 | if (absolute) | |
952 | dest = immediate; | |
953 | else | |
954 | dest = pc + immediate; | |
955 | break; | |
956 | ||
957 | case 16: | |
958 | immediate = ((instr & ~3) << 16) >> 16; /* br conditional */ | |
959 | if (absolute) | |
960 | dest = immediate; | |
961 | else | |
962 | dest = pc + immediate; | |
963 | break; | |
964 | ||
965 | case 19: | |
966 | ext_op = (instr >> 1) & 0x3ff; | |
967 | ||
968 | if (ext_op == 16) /* br conditional register */ | |
969 | { | |
dda83cd7 | 970 | dest = regcache_raw_get_unsigned (regcache, tdep->ppc_lr_regnum) & ~3; |
4a7622d1 UW |
971 | |
972 | /* If we are about to return from a signal handler, dest is | |
973 | something like 0x3c90. The current frame is a signal handler | |
974 | caller frame, upon completion of the sigreturn system call | |
975 | execution will return to the saved PC in the frame. */ | |
976 | if (dest < AIX_TEXT_SEGMENT_BASE) | |
41e26ad3 | 977 | { |
bd2b40ac | 978 | frame_info_ptr frame = get_current_frame (); |
41e26ad3 YQ |
979 | |
980 | dest = read_memory_unsigned_integer | |
981 | (get_frame_base (frame) + SIG_FRAME_PC_OFFSET, | |
982 | tdep->wordsize, byte_order); | |
983 | } | |
4a7622d1 UW |
984 | } |
985 | ||
986 | else if (ext_op == 528) /* br cond to count reg */ | |
987 | { | |
dda83cd7 | 988 | dest = regcache_raw_get_unsigned (regcache, |
41e26ad3 | 989 | tdep->ppc_ctr_regnum) & ~3; |
4a7622d1 UW |
990 | |
991 | /* If we are about to execute a system call, dest is something | |
992 | like 0x22fc or 0x3b00. Upon completion the system call | |
993 | will return to the address in the link register. */ | |
994 | if (dest < AIX_TEXT_SEGMENT_BASE) | |
dda83cd7 | 995 | dest = regcache_raw_get_unsigned (regcache, |
41e26ad3 | 996 | tdep->ppc_lr_regnum) & ~3; |
4a7622d1 UW |
997 | } |
998 | else | |
999 | return -1; | |
1000 | break; | |
1001 | ||
1002 | default: | |
1003 | return -1; | |
1004 | } | |
1005 | return (dest < AIX_TEXT_SEGMENT_BASE) ? safety : dest; | |
1006 | } | |
1007 | ||
1008 | /* AIX does not support PT_STEP. Simulate it. */ | |
1009 | ||
a0ff9e1a | 1010 | static std::vector<CORE_ADDR> |
f5ea389a | 1011 | rs6000_software_single_step (struct regcache *regcache) |
4a7622d1 | 1012 | { |
ac7936df | 1013 | struct gdbarch *gdbarch = regcache->arch (); |
e17a4113 | 1014 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
4a7622d1 UW |
1015 | int ii, insn; |
1016 | CORE_ADDR loc; | |
1017 | CORE_ADDR breaks[2]; | |
1018 | int opcode; | |
1019 | ||
41e26ad3 | 1020 | loc = regcache_read_pc (regcache); |
4a7622d1 | 1021 | |
e17a4113 | 1022 | insn = read_memory_integer (loc, 4, byte_order); |
4a7622d1 | 1023 | |
a0ff9e1a SM |
1024 | std::vector<CORE_ADDR> next_pcs = ppc_deal_with_atomic_sequence (regcache); |
1025 | if (!next_pcs.empty ()) | |
93f9a11f | 1026 | return next_pcs; |
4a7622d1 | 1027 | |
dd05a5ca AVK |
1028 | /* Here 0xfc000000 is the opcode mask to detect a P10 prefix instruction. */ |
1029 | if ((insn & 0xfc000000) == 1 << 26) | |
1030 | breaks[0] = loc + 2 * PPC_INSN_SIZE; | |
1031 | else | |
1032 | breaks[0] = loc + PPC_INSN_SIZE; | |
4a7622d1 | 1033 | opcode = insn >> 26; |
41e26ad3 | 1034 | breaks[1] = branch_dest (regcache, opcode, insn, loc, breaks[0]); |
4a7622d1 | 1035 | |
0df8b418 | 1036 | /* Don't put two breakpoints on the same address. */ |
4a7622d1 UW |
1037 | if (breaks[1] == breaks[0]) |
1038 | breaks[1] = -1; | |
1039 | ||
1040 | for (ii = 0; ii < 2; ++ii) | |
1041 | { | |
0df8b418 | 1042 | /* ignore invalid breakpoint. */ |
4a7622d1 UW |
1043 | if (breaks[ii] == -1) |
1044 | continue; | |
a0ff9e1a SM |
1045 | |
1046 | next_pcs.push_back (breaks[ii]); | |
4a7622d1 UW |
1047 | } |
1048 | ||
0df8b418 | 1049 | errno = 0; /* FIXME, don't ignore errors! */ |
4a7622d1 | 1050 | /* What errors? {read,write}_memory call error(). */ |
93f9a11f | 1051 | return next_pcs; |
4a7622d1 UW |
1052 | } |
1053 | ||
38a69d0a JB |
1054 | /* Implement the "auto_wide_charset" gdbarch method for this platform. */ |
1055 | ||
1056 | static const char * | |
1057 | rs6000_aix_auto_wide_charset (void) | |
1058 | { | |
1059 | return "UTF-16"; | |
1060 | } | |
1061 | ||
beb4b03c JB |
1062 | /* Implement an osabi sniffer for RS6000/AIX. |
1063 | ||
1064 | This function assumes that ABFD's flavour is XCOFF. In other words, | |
1065 | it should be registered as a sniffer for bfd_target_xcoff_flavour | |
1066 | objfiles only. A failed assertion will be raised if this condition | |
1067 | is not met. */ | |
1068 | ||
1f82754b JB |
1069 | static enum gdb_osabi |
1070 | rs6000_aix_osabi_sniffer (bfd *abfd) | |
1071 | { | |
beb4b03c | 1072 | gdb_assert (bfd_get_flavour (abfd) == bfd_target_xcoff_flavour); |
1f82754b | 1073 | |
d5367fe1 JB |
1074 | /* The only noticeable difference between Lynx178 XCOFF files and |
1075 | AIX XCOFF files comes from the fact that there are no shared | |
1076 | libraries on Lynx178. On AIX, we are betting that an executable | |
1077 | linked with no shared library will never exist. */ | |
1078 | if (xcoff_get_n_import_files (abfd) <= 0) | |
1079 | return GDB_OSABI_UNKNOWN; | |
1080 | ||
beb4b03c | 1081 | return GDB_OSABI_AIX; |
1f82754b JB |
1082 | } |
1083 | ||
356a5233 JB |
1084 | /* A structure encoding the offset and size of a field within |
1085 | a struct. */ | |
1086 | ||
c01e2836 | 1087 | struct ldinfo_field |
356a5233 JB |
1088 | { |
1089 | int offset; | |
1090 | int size; | |
1091 | }; | |
1092 | ||
1093 | /* A structure describing the layout of all the fields of interest | |
1094 | in AIX's struct ld_info. Each field in this struct corresponds | |
1095 | to the field of the same name in struct ld_info. */ | |
1096 | ||
1097 | struct ld_info_desc | |
1098 | { | |
c01e2836 TT |
1099 | struct ldinfo_field ldinfo_next; |
1100 | struct ldinfo_field ldinfo_fd; | |
1101 | struct ldinfo_field ldinfo_textorg; | |
1102 | struct ldinfo_field ldinfo_textsize; | |
1103 | struct ldinfo_field ldinfo_dataorg; | |
1104 | struct ldinfo_field ldinfo_datasize; | |
1105 | struct ldinfo_field ldinfo_filename; | |
356a5233 JB |
1106 | }; |
1107 | ||
1108 | /* The following data has been generated by compiling and running | |
1109 | the following program on AIX 5.3. */ | |
1110 | ||
1111 | #if 0 | |
1c432e72 JB |
1112 | #include <stddef.h> |
1113 | #include <stdio.h> | |
1114 | #define __LDINFO_PTRACE32__ | |
1115 | #define __LDINFO_PTRACE64__ | |
1116 | #include <sys/ldr.h> | |
1117 | ||
1118 | #define pinfo(type,member) \ | |
1119 | { \ | |
1120 | struct type ldi = {0}; \ | |
dda83cd7 | 1121 | \ |
1c432e72 | 1122 | printf (" {%d, %d},\t/* %s */\n", \ |
dda83cd7 SM |
1123 | offsetof (struct type, member), \ |
1124 | sizeof (ldi.member), \ | |
1125 | #member); \ | |
1c432e72 JB |
1126 | } \ |
1127 | while (0) | |
1128 | ||
1129 | int | |
1130 | main (void) | |
1131 | { | |
1132 | printf ("static const struct ld_info_desc ld_info32_desc =\n{\n"); | |
1133 | pinfo (__ld_info32, ldinfo_next); | |
1134 | pinfo (__ld_info32, ldinfo_fd); | |
1135 | pinfo (__ld_info32, ldinfo_textorg); | |
1136 | pinfo (__ld_info32, ldinfo_textsize); | |
1137 | pinfo (__ld_info32, ldinfo_dataorg); | |
1138 | pinfo (__ld_info32, ldinfo_datasize); | |
1139 | pinfo (__ld_info32, ldinfo_filename); | |
1140 | printf ("};\n"); | |
1141 | ||
1142 | printf ("\n"); | |
1143 | ||
1144 | printf ("static const struct ld_info_desc ld_info64_desc =\n{\n"); | |
1145 | pinfo (__ld_info64, ldinfo_next); | |
1146 | pinfo (__ld_info64, ldinfo_fd); | |
1147 | pinfo (__ld_info64, ldinfo_textorg); | |
1148 | pinfo (__ld_info64, ldinfo_textsize); | |
1149 | pinfo (__ld_info64, ldinfo_dataorg); | |
1150 | pinfo (__ld_info64, ldinfo_datasize); | |
1151 | pinfo (__ld_info64, ldinfo_filename); | |
1152 | printf ("};\n"); | |
1153 | ||
1154 | return 0; | |
1155 | } | |
356a5233 JB |
1156 | #endif /* 0 */ |
1157 | ||
1158 | /* Layout of the 32bit version of struct ld_info. */ | |
1159 | ||
1160 | static const struct ld_info_desc ld_info32_desc = | |
1161 | { | |
1162 | {0, 4}, /* ldinfo_next */ | |
1163 | {4, 4}, /* ldinfo_fd */ | |
1164 | {8, 4}, /* ldinfo_textorg */ | |
1165 | {12, 4}, /* ldinfo_textsize */ | |
1166 | {16, 4}, /* ldinfo_dataorg */ | |
1167 | {20, 4}, /* ldinfo_datasize */ | |
1168 | {24, 2}, /* ldinfo_filename */ | |
1169 | }; | |
1170 | ||
1171 | /* Layout of the 64bit version of struct ld_info. */ | |
1172 | ||
1173 | static const struct ld_info_desc ld_info64_desc = | |
1174 | { | |
1175 | {0, 4}, /* ldinfo_next */ | |
1176 | {8, 4}, /* ldinfo_fd */ | |
1177 | {16, 8}, /* ldinfo_textorg */ | |
1178 | {24, 8}, /* ldinfo_textsize */ | |
1179 | {32, 8}, /* ldinfo_dataorg */ | |
1180 | {40, 8}, /* ldinfo_datasize */ | |
1181 | {48, 2}, /* ldinfo_filename */ | |
1182 | }; | |
1183 | ||
1184 | /* A structured representation of one entry read from the ld_info | |
1185 | binary data provided by the AIX loader. */ | |
1186 | ||
1187 | struct ld_info | |
1188 | { | |
1189 | ULONGEST next; | |
1190 | int fd; | |
1191 | CORE_ADDR textorg; | |
1192 | ULONGEST textsize; | |
1193 | CORE_ADDR dataorg; | |
1194 | ULONGEST datasize; | |
1195 | char *filename; | |
1196 | char *member_name; | |
1197 | }; | |
1198 | ||
1199 | /* Return a struct ld_info object corresponding to the entry at | |
1200 | LDI_BUF. | |
1201 | ||
1202 | Note that the filename and member_name strings still point | |
1203 | to the data in LDI_BUF. So LDI_BUF must not be deallocated | |
1204 | while the struct ld_info object returned is in use. */ | |
1205 | ||
1206 | static struct ld_info | |
1207 | rs6000_aix_extract_ld_info (struct gdbarch *gdbarch, | |
1208 | const gdb_byte *ldi_buf) | |
1209 | { | |
08106042 | 1210 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
356a5233 JB |
1211 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
1212 | struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; | |
1213 | const struct ld_info_desc desc | |
1214 | = tdep->wordsize == 8 ? ld_info64_desc : ld_info32_desc; | |
1215 | struct ld_info info; | |
1216 | ||
1217 | info.next = extract_unsigned_integer (ldi_buf + desc.ldinfo_next.offset, | |
1218 | desc.ldinfo_next.size, | |
1219 | byte_order); | |
1220 | info.fd = extract_signed_integer (ldi_buf + desc.ldinfo_fd.offset, | |
1221 | desc.ldinfo_fd.size, | |
1222 | byte_order); | |
1223 | info.textorg = extract_typed_address (ldi_buf + desc.ldinfo_textorg.offset, | |
1224 | ptr_type); | |
1225 | info.textsize | |
1226 | = extract_unsigned_integer (ldi_buf + desc.ldinfo_textsize.offset, | |
1227 | desc.ldinfo_textsize.size, | |
1228 | byte_order); | |
1229 | info.dataorg = extract_typed_address (ldi_buf + desc.ldinfo_dataorg.offset, | |
1230 | ptr_type); | |
1231 | info.datasize | |
1232 | = extract_unsigned_integer (ldi_buf + desc.ldinfo_datasize.offset, | |
1233 | desc.ldinfo_datasize.size, | |
1234 | byte_order); | |
1235 | info.filename = (char *) ldi_buf + desc.ldinfo_filename.offset; | |
1236 | info.member_name = info.filename + strlen (info.filename) + 1; | |
1237 | ||
1238 | return info; | |
1239 | } | |
1240 | ||
d6ac292e | 1241 | /* Append to XML an XML string description of the shared library |
356a5233 JB |
1242 | corresponding to LDI, following the TARGET_OBJECT_LIBRARIES_AIX |
1243 | format. */ | |
1244 | ||
1245 | static void | |
d6ac292e | 1246 | rs6000_aix_shared_library_to_xml (struct ld_info *ldi, std::string &xml) |
356a5233 | 1247 | { |
d6ac292e SM |
1248 | xml += "<library name=\""; |
1249 | xml_escape_text_append (xml, ldi->filename); | |
1250 | xml += '"'; | |
356a5233 JB |
1251 | |
1252 | if (ldi->member_name[0] != '\0') | |
1253 | { | |
d6ac292e SM |
1254 | xml += " member=\""; |
1255 | xml_escape_text_append (xml, ldi->member_name); | |
1256 | xml += '"'; | |
356a5233 JB |
1257 | } |
1258 | ||
d6ac292e SM |
1259 | xml += " text_addr=\""; |
1260 | xml += core_addr_to_string (ldi->textorg); | |
1261 | xml += '"'; | |
356a5233 | 1262 | |
d6ac292e SM |
1263 | xml += " text_size=\""; |
1264 | xml += pulongest (ldi->textsize); | |
1265 | xml += '"'; | |
356a5233 | 1266 | |
d6ac292e SM |
1267 | xml += " data_addr=\""; |
1268 | xml += core_addr_to_string (ldi->dataorg); | |
1269 | xml += '"'; | |
356a5233 | 1270 | |
d6ac292e SM |
1271 | xml += " data_size=\""; |
1272 | xml += pulongest (ldi->datasize); | |
1273 | xml += '"'; | |
356a5233 | 1274 | |
d6ac292e | 1275 | xml += "></library>"; |
356a5233 JB |
1276 | } |
1277 | ||
1278 | /* Convert the ld_info binary data provided by the AIX loader into | |
1279 | an XML representation following the TARGET_OBJECT_LIBRARIES_AIX | |
1280 | format. | |
1281 | ||
1282 | LDI_BUF is a buffer containing the ld_info data. | |
1283 | READBUF, OFFSET and LEN follow the same semantics as target_ops' | |
1284 | to_xfer_partial target_ops method. | |
1285 | ||
1286 | If CLOSE_LDINFO_FD is nonzero, then this routine also closes | |
1287 | the ldinfo_fd file descriptor. This is useful when the ldinfo | |
1288 | data is obtained via ptrace, as ptrace opens a file descriptor | |
1289 | for each and every entry; but we cannot use this descriptor | |
1290 | as the consumer of the XML library list might live in a different | |
1291 | process. */ | |
1292 | ||
c09f20e4 | 1293 | ULONGEST |
356a5233 | 1294 | rs6000_aix_ld_info_to_xml (struct gdbarch *gdbarch, const gdb_byte *ldi_buf, |
b55e14c7 | 1295 | gdb_byte *readbuf, ULONGEST offset, ULONGEST len, |
356a5233 JB |
1296 | int close_ldinfo_fd) |
1297 | { | |
d6ac292e | 1298 | std::string xml = "<library-list-aix version=\"1.0\">\n"; |
356a5233 JB |
1299 | |
1300 | while (1) | |
1301 | { | |
1302 | struct ld_info ldi = rs6000_aix_extract_ld_info (gdbarch, ldi_buf); | |
1303 | ||
d6ac292e | 1304 | rs6000_aix_shared_library_to_xml (&ldi, xml); |
356a5233 JB |
1305 | if (close_ldinfo_fd) |
1306 | close (ldi.fd); | |
1307 | ||
1308 | if (!ldi.next) | |
1309 | break; | |
1310 | ldi_buf = ldi_buf + ldi.next; | |
1311 | } | |
1312 | ||
d6ac292e | 1313 | xml += "</library-list-aix>\n"; |
356a5233 | 1314 | |
d6ac292e | 1315 | ULONGEST len_avail = xml.length (); |
356a5233 JB |
1316 | if (offset >= len_avail) |
1317 | len= 0; | |
1318 | else | |
1319 | { | |
1320 | if (len > len_avail - offset) | |
dda83cd7 | 1321 | len = len_avail - offset; |
d6ac292e | 1322 | memcpy (readbuf, xml.data () + offset, len); |
356a5233 JB |
1323 | } |
1324 | ||
356a5233 JB |
1325 | return len; |
1326 | } | |
1327 | ||
1328 | /* Implement the core_xfer_shared_libraries_aix gdbarch method. */ | |
1329 | ||
c09f20e4 | 1330 | static ULONGEST |
356a5233 JB |
1331 | rs6000_aix_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch, |
1332 | gdb_byte *readbuf, | |
1333 | ULONGEST offset, | |
7ec1862d | 1334 | ULONGEST len) |
356a5233 JB |
1335 | { |
1336 | struct bfd_section *ldinfo_sec; | |
1337 | int ldinfo_size; | |
356a5233 JB |
1338 | |
1339 | ldinfo_sec = bfd_get_section_by_name (core_bfd, ".ldinfo"); | |
1340 | if (ldinfo_sec == NULL) | |
1341 | error (_("cannot find .ldinfo section from core file: %s"), | |
1342 | bfd_errmsg (bfd_get_error ())); | |
fd361982 | 1343 | ldinfo_size = bfd_section_size (ldinfo_sec); |
356a5233 | 1344 | |
984c7238 | 1345 | gdb::byte_vector ldinfo_buf (ldinfo_size); |
356a5233 JB |
1346 | |
1347 | if (! bfd_get_section_contents (core_bfd, ldinfo_sec, | |
984c7238 | 1348 | ldinfo_buf.data (), 0, ldinfo_size)) |
356a5233 JB |
1349 | error (_("unable to read .ldinfo section from core file: %s"), |
1350 | bfd_errmsg (bfd_get_error ())); | |
1351 | ||
984c7238 TT |
1352 | return rs6000_aix_ld_info_to_xml (gdbarch, ldinfo_buf.data (), readbuf, |
1353 | offset, len, 0); | |
356a5233 JB |
1354 | } |
1355 | ||
1f82754b JB |
1356 | static void |
1357 | rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
1358 | { | |
08106042 | 1359 | ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); |
4a7622d1 | 1360 | |
1f82754b JB |
1361 | /* RS6000/AIX does not support PT_STEP. Has to be simulated. */ |
1362 | set_gdbarch_software_single_step (gdbarch, rs6000_software_single_step); | |
6f7f3f0d | 1363 | |
2454a024 | 1364 | /* Displaced stepping is currently not supported in combination with |
187b041e SM |
1365 | software single-stepping. These override the values set by |
1366 | rs6000_gdbarch_init. */ | |
2454a024 UW |
1367 | set_gdbarch_displaced_step_copy_insn (gdbarch, NULL); |
1368 | set_gdbarch_displaced_step_fixup (gdbarch, NULL); | |
187b041e SM |
1369 | set_gdbarch_displaced_step_prepare (gdbarch, NULL); |
1370 | set_gdbarch_displaced_step_finish (gdbarch, NULL); | |
2454a024 | 1371 | |
4a7622d1 UW |
1372 | set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call); |
1373 | set_gdbarch_return_value (gdbarch, rs6000_return_value); | |
1374 | set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT); | |
1375 | ||
1376 | /* Handle RS/6000 function pointers (which are really function | |
1377 | descriptors). */ | |
1378 | set_gdbarch_convert_from_func_ptr_addr | |
1379 | (gdbarch, rs6000_convert_from_func_ptr_addr); | |
1380 | ||
7a61a01c | 1381 | /* Core file support. */ |
23ea9aeb AA |
1382 | set_gdbarch_iterate_over_regset_sections |
1383 | (gdbarch, rs6000_aix_iterate_over_regset_sections); | |
356a5233 JB |
1384 | set_gdbarch_core_xfer_shared_libraries_aix |
1385 | (gdbarch, rs6000_aix_core_xfer_shared_libraries_aix); | |
a8ea150e | 1386 | set_gdbarch_core_read_description (gdbarch, ppc_aix_core_read_description); |
7a61a01c | 1387 | |
4a7622d1 UW |
1388 | if (tdep->wordsize == 8) |
1389 | tdep->lr_frame_offset = 16; | |
1390 | else | |
1391 | tdep->lr_frame_offset = 8; | |
1392 | ||
1393 | if (tdep->wordsize == 4) | |
1394 | /* PowerOpen / AIX 32 bit. The saved area or red zone consists of | |
1395 | 19 4 byte GPRS + 18 8 byte FPRs giving a total of 220 bytes. | |
1396 | Problem is, 220 isn't frame (16 byte) aligned. Round it up to | |
1397 | 224. */ | |
1398 | set_gdbarch_frame_red_zone_size (gdbarch, 224); | |
1399 | else | |
26fca3f1 AVK |
1400 | /* In 64 bit mode the red zone should have 18 8 byte GPRS + 18 8 byte |
1401 | FPRS making it 288 bytes. This is 16 byte aligned as well. */ | |
1402 | set_gdbarch_frame_red_zone_size (gdbarch, 288); | |
38a69d0a | 1403 | |
53375380 PA |
1404 | if (tdep->wordsize == 8) |
1405 | set_gdbarch_wchar_bit (gdbarch, 32); | |
1406 | else | |
1407 | set_gdbarch_wchar_bit (gdbarch, 16); | |
1408 | set_gdbarch_wchar_signed (gdbarch, 0); | |
38a69d0a | 1409 | set_gdbarch_auto_wide_charset (gdbarch, rs6000_aix_auto_wide_charset); |
4d1eb6b4 | 1410 | |
9e468e95 | 1411 | set_gdbarch_so_ops (gdbarch, &solib_aix_so_ops); |
cdcda965 | 1412 | frame_unwind_append_unwinder (gdbarch, &aix_sighandle_frame_unwind); |
1f82754b JB |
1413 | } |
1414 | ||
6c265988 | 1415 | void _initialize_rs6000_aix_tdep (); |
1f82754b | 1416 | void |
6c265988 | 1417 | _initialize_rs6000_aix_tdep () |
1f82754b JB |
1418 | { |
1419 | gdbarch_register_osabi_sniffer (bfd_arch_rs6000, | |
dda83cd7 SM |
1420 | bfd_target_xcoff_flavour, |
1421 | rs6000_aix_osabi_sniffer); | |
7a61a01c | 1422 | gdbarch_register_osabi_sniffer (bfd_arch_powerpc, |
dda83cd7 SM |
1423 | bfd_target_xcoff_flavour, |
1424 | rs6000_aix_osabi_sniffer); | |
1f82754b JB |
1425 | |
1426 | gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_AIX, | |
dda83cd7 | 1427 | rs6000_aix_init_osabi); |
7a61a01c | 1428 | gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_AIX, |
dda83cd7 | 1429 | rs6000_aix_init_osabi); |
1f82754b JB |
1430 | } |
1431 |