]> Git Repo - binutils.git/blob - gdb/rs6000-xdep.c
ansi name abuse changes
[binutils.git] / gdb / rs6000-xdep.c
1 /* IBM RS/6000 host-dependent code for GDB, the GNU debugger.
2    Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 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
44 extern int errno;
45 extern int attach_flag;
46
47 /* Conversion from gdb-to-system special purpose register numbers.. */
48
49 static 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. */
61 extern int one_stepped;
62
63 \f
64 fetch_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
91 store_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
165 void
166 fetch_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
196 frameless_function_invocation (fi)
197 struct 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
229 aixcoff_relocate_symtab (pid)
230 unsigned 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    
270 typedef struct {
271   unsigned long textorg, dataorg, toc_offset;
272 } LoadInfo;
273
274 #define LOADINFOLEN     10
275
276 static  LoadInfo *loadInfo = NULL;
277 static  int     loadInfoLen = 0;
278 static  int     loadInfoTocIndex = 0;
279 static  int     loadInfoTextIndex = 0;
280
281
282 xcoff_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
294 free_loadinfo ()
295 {
296   if (loadInfo)
297     free (loadInfo);
298   loadInfo = NULL;
299   loadInfoLen = 0;
300   loadInfoTocIndex = 0;
301   loadInfoTextIndex = 0;
302 }
303
304
305 xcoff_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
315 add_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
327 unsigned long
328 find_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
344 exec_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.044959 seconds and 4 git commands to generate.