* rs6000-pinsn.c, rs6000-tdep.c, rs6000-xdep.c, tm-rs6000.h,
[deliverable/binutils-gdb.git] / gdb / rs6000-xdep.c
CommitLineData
41abdfbd
JG
1/* IBM RS/6000 host-dependent code for GDB, the GNU debugger.
2 Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
3
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include <stdio.h>
21#include "defs.h"
22#include "param.h"
23#include "frame.h"
24#include "inferior.h"
25#include "symtab.h"
26#include "target.h"
27
28#include <sys/param.h>
29#include <sys/dir.h>
30#include <sys/user.h>
31#include <signal.h>
32#include <sys/ioctl.h>
33#include <fcntl.h>
34
35#include <sys/ptrace.h>
36#include <sys/reg.h>
37
38#include <a.out.h>
39#include <sys/file.h>
40#include <sys/stat.h>
41#include <sys/core.h>
42#include <sys/ldr.h>
43
44extern int errno;
45extern int attach_flag;
46
47/* Conversion from gdb-to-system special purpose register numbers.. */
48
49static int special_regs[] = {
50 IAR, /* PC_REGNUM */
51 MSR, /* PS_REGNUM */
52 CR, /* CR_REGNUM */
53 LR, /* LR_REGNUM */
54 CTR, /* CTR_REGNUM */
55 XER, /* XER_REGNUM */
56 MQ /* MQ_REGNUM */
57};
58
59
60/* Nonzero if we just simulated a single step break. */
61extern int one_stepped;
62
63\f
64fetch_inferior_registers ()
65{
66 int ii;
67 extern char registers[];
68
69 /* read 32 general purpose registers. */
70
71 for (ii=0; ii < 32; ++ii)
72 *(int*)&registers[REGISTER_BYTE (ii)] =
73 ptrace (PT_READ_GPR, inferior_pid, ii, 0, 0);
74
75 /* read general purpose floating point registers. */
76
77 for (ii=0; ii < 32; ++ii)
78 ptrace (PT_READ_FPR, inferior_pid,
79 (int*)&registers [REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
80
81 /* read special registers. */
82 for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii)
83 *(int*)&registers[REGISTER_BYTE (FIRST_SP_REGNUM+ii)] =
84 ptrace (PT_READ_GPR, inferior_pid, special_regs[ii], 0, 0);
85}
86
87/* Store our register values back into the inferior.
88 If REGNO is -1, do this for all registers.
89 Otherwise, REGNO specifies which register (so we can save time). */
90
91store_inferior_registers (regno)
92 int regno;
93{
94 extern char registers[];
95
96 errno = 0;
97
98 if (regno == -1) { /* for all registers.. */
99 int ii;
100
101 /* execute one dummy instruction (which is a breakpoint) in inferior
102 process. So give kernel a chance to do internal house keeping.
103 Otherwise the following ptrace(2) calls will mess up user stack
104 since kernel will get confused about the bottom of the stack (%sp) */
105
106 exec_one_dummy_insn ();
107
108 /* write general purpose registers first! */
109 for ( ii=GPR0; ii<=GPR31; ++ii) {
110 ptrace (PT_WRITE_GPR, inferior_pid, ii,
111 *(int*)&registers[REGISTER_BYTE (ii)], 0);
112 if ( errno ) {
113 perror ("ptrace write_gpr"); errno = 0;
114 }
115 }
116
117 /* write floating point registers now. */
118 for ( ii=0; ii < 32; ++ii) {
119 ptrace (PT_WRITE_FPR, inferior_pid,
120 (int*)&registers[REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
121 if ( errno ) {
122 perror ("ptrace write_fpr"); errno = 0;
123 }
124 }
125
126 /* write special registers. */
127 for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii) {
128 ptrace (PT_WRITE_GPR, inferior_pid, special_regs[ii],
129 *(int*)&registers[REGISTER_BYTE (FIRST_SP_REGNUM+ii)], 0);
130 if ( errno ) {
131 perror ("ptrace write_gpr"); errno = 0;
132 }
133 }
134 }
135
136 /* else, a specific register number is given... */
137
138 else if (regno < FP0_REGNUM) { /* a GPR */
139
140 ptrace (PT_WRITE_GPR, inferior_pid, regno,
141 *(int*)&registers[REGISTER_BYTE (regno)], 0);
142 }
143
144 else if (regno <= FPLAST_REGNUM) { /* a FPR */
145 ptrace (PT_WRITE_FPR, inferior_pid,
146 (int*)&registers[REGISTER_BYTE (regno)], regno-FP0_REGNUM+FPR0, 0);
147 }
148
149 else if (regno <= LAST_SP_REGNUM) { /* a special register */
150
151 ptrace (PT_WRITE_GPR, inferior_pid, special_regs [regno-FIRST_SP_REGNUM],
152 *(int*)&registers[REGISTER_BYTE (regno)], 0);
153 }
154
155 else
156 fprintf (stderr, "Gdb error: register no %d not implemented.\n", regno);
157
158 if ( errno ) {
159 perror ("ptrace write"); errno = 0;
160 return -1;
161 }
162 return 0;
163}
164
165void
166fetch_core_registers (core_reg_sect, core_reg_size, which)
167 char *core_reg_sect;
168 unsigned core_reg_size;
169 int which;
170{
171 /* fetch GPRs and special registers from the first register section
172 in core bfd. */
173 if (which == 0) {
174
175 /* copy GPRs first. */
176 bcopy (core_reg_sect, registers, 32 * 4);
177
178 /* gdb's internal register template and bfd's register section layout
179 should share a common include file. FIXMEmgo */
180 /* then comes special registes. They are supposed to be in the same
181 order in gdb template and bfd `.reg' section. */
182 core_reg_sect += (32 * 4);
183 bcopy (core_reg_sect, &registers [REGISTER_BYTE (FIRST_SP_REGNUM)],
184 (LAST_SP_REGNUM - FIRST_SP_REGNUM + 1) * 4);
185 }
186
187 /* fetch floating point registers from register section 2 in core bfd. */
188 else if (which == 2)
189 bcopy (core_reg_sect, &registers [REGISTER_BYTE (FP0_REGNUM)], 32 * 8);
190
191 else
192 fprintf (stderr, "Gdb error: unknown parameter to fetch_core_registers().\n");
193}
194
195
196frameless_function_invocation (fi)
197struct frame_info *fi;
198{
199 int ret;
200 CORE_ADDR func_start, after_prologue;
201
202#if 0
203 func_start = (LOAD_ADDR (get_pc_function_start (fi->pc)) +
204 FUNCTION_START_OFFSET);
205#else
206 func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
207#endif
208 if (func_start)
209 {
210 after_prologue = func_start;
211 SKIP_PROLOGUE (after_prologue);
212 ret = (after_prologue == func_start);
213 }
214 else
215 /* If we can't find the start of the function, we don't really */
216 /* know whether the function is frameless, but we should be */
217 /* able to get a reasonable (i.e. best we can do under the */
218 /* circumstances) backtrace by saying that it isn't. */
219 ret = 0;
220
221 return ret;
222
223}
224
225
226/* aixcoff_relocate_symtab - hook for symbol table relocation.
227 also reads shared libraries.. */
228
229aixcoff_relocate_symtab (pid)
230unsigned int pid;
231{
232#define MAX_LOAD_SEGS 64 /* maximum number of load segments */
233
234 extern int compare_misc_functions ();
235 struct ld_info *ldi;
236 int temp;
237
238 ldi = (void *) alloca(MAX_LOAD_SEGS * sizeof (*ldi));
239
240 /* According to my humble theory, aixcoff has some timing problems and
241 when the user stack grows, kernel doesn't update stack info in time
242 and ptrace calls step on user stack. That is why we sleep here a little,
243 and give kernel to update its internals. */
244
245 usleep (36000);
246
247 errno = 0;
248 ptrace(PT_LDINFO, pid, ldi, MAX_LOAD_SEGS * sizeof(*ldi), ldi);
249 if (errno)
250 perror_with_name ("ptrace ldinfo");
251
252 vmap_ldinfo(ldi);
253
254 do {
255 add_text_to_loadinfo (ldi->ldinfo_textorg, ldi->ldinfo_dataorg);
256 } while (ldi->ldinfo_next
257 && (ldi = (void *) (ldi->ldinfo_next + (char *) ldi)));
258
259 /* Now that we've jumbled things around, re-sort them. */
260 sort_misc_function_vector ();
261
262 /* relocate the exec and core sections as well. */
263 vmap_exec ();
264}
265
266
267/* Keep an array of load segment information and their TOC table addresses.
268 This info will be useful when calling a shared library function by hand. */
269
270typedef struct {
271 unsigned long textorg, dataorg, toc_offset;
272} LoadInfo;
273
274#define LOADINFOLEN 10
275
276static LoadInfo *loadInfo = NULL;
277static int loadInfoLen = 0;
278static int loadInfoTocIndex = 0;
279static int loadInfoTextIndex = 0;
280
281
282xcoff_init_loadinfo ()
283{
284 loadInfoTocIndex = 0;
285 loadInfoTextIndex = 0;
286
287 if (loadInfoLen == 0) {
288 loadInfo = (void*) xmalloc (sizeof (LoadInfo) * LOADINFOLEN);
289 loadInfoLen = LOADINFOLEN;
290 }
291}
292
293
294free_loadinfo ()
295{
296 if (loadInfo)
297 free (loadInfo);
298 loadInfo = NULL;
299 loadInfoLen = 0;
300 loadInfoTocIndex = 0;
301 loadInfoTextIndex = 0;
302}
303
304
305xcoff_add_toc_to_loadinfo (unsigned long tocaddr)
306{
307 while (loadInfoTocIndex >= loadInfoLen) {
308 loadInfoLen += LOADINFOLEN;
309 loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
310 }
311 loadInfo [loadInfoTocIndex++].toc_offset = tocaddr;
312}
313
314
315add_text_to_loadinfo (unsigned long textaddr, unsigned long dataaddr)
316{
317 while (loadInfoTextIndex >= loadInfoLen) {
318 loadInfoLen += LOADINFOLEN;
319 loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
320 }
321 loadInfo [loadInfoTextIndex].textorg = textaddr;
322 loadInfo [loadInfoTextIndex].dataorg = dataaddr;
323 ++loadInfoTextIndex;
324}
325
326
327unsigned long
328find_toc_address (unsigned long pc)
329{
330 int ii, toc_entry;
331
332 for (ii=0; ii < loadInfoTextIndex; ++ii)
333 if (pc > loadInfo [ii].textorg)
334 toc_entry = ii;
335
336 return loadInfo [toc_entry].dataorg + loadInfo [toc_entry].toc_offset;
337}
338
339
340/* execute one dummy breakpoint instruction. This way we give kernel
341 a chance to do some housekeeping and update inferior's internal data,
342 including u_area. */
343
344exec_one_dummy_insn ()
345{
346#define DUMMY_INSN_ADDR 0x10000200
347
348 unsigned long shadow;
349 unsigned int status, pid;
350
351 target_insert_breakpoint (DUMMY_INSN_ADDR, &shadow);
352
353 errno = 0;
354 ptrace (PT_CONTINUE, inferior_pid, DUMMY_INSN_ADDR, 0, 0);
355 if (errno)
356 perror ("pt_continue");
357
358 do {
359 pid = wait (&status);
360 } while (pid != inferior_pid);
361
362 target_remove_breakpoint (DUMMY_INSN_ADDR, &shadow);
363}
364
This page took 0.036138 seconds and 4 git commands to generate.