1 /* IBM RS/6000 host-dependent code for GDB, the GNU debugger.
2 Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
4 This file is part of GDB.
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.
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.
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. */
28 #include <sys/param.h>
32 #include <sys/ioctl.h>
35 #include <sys/ptrace.h>
45 extern int attach_flag;
47 /* Conversion from gdb-to-system special purpose register numbers.. */
49 static int special_regs[] = {
60 /* Nonzero if we just simulated a single step break. */
61 extern int one_stepped;
64 fetch_inferior_registers ()
67 extern char registers[];
69 /* read 32 general purpose registers. */
71 for (ii=0; ii < 32; ++ii)
72 *(int*)®isters[REGISTER_BYTE (ii)] =
73 ptrace (PT_READ_GPR, inferior_pid, ii, 0, 0);
75 /* read general purpose floating point registers. */
77 for (ii=0; ii < 32; ++ii)
78 ptrace (PT_READ_FPR, inferior_pid,
79 (int*)®isters [REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
81 /* read special registers. */
82 for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii)
83 *(int*)®isters[REGISTER_BYTE (FIRST_SP_REGNUM+ii)] =
84 ptrace (PT_READ_GPR, inferior_pid, special_regs[ii], 0, 0);
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). */
91 store_inferior_registers (regno)
94 extern char registers[];
98 if (regno == -1) { /* for all registers.. */
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) */
106 exec_one_dummy_insn ();
108 /* write general purpose registers first! */
109 for ( ii=GPR0; ii<=GPR31; ++ii) {
110 ptrace (PT_WRITE_GPR, inferior_pid, ii,
111 *(int*)®isters[REGISTER_BYTE (ii)], 0);
113 perror ("ptrace write_gpr"); errno = 0;
117 /* write floating point registers now. */
118 for ( ii=0; ii < 32; ++ii) {
119 ptrace (PT_WRITE_FPR, inferior_pid,
120 (int*)®isters[REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
122 perror ("ptrace write_fpr"); errno = 0;
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*)®isters[REGISTER_BYTE (FIRST_SP_REGNUM+ii)], 0);
131 perror ("ptrace write_gpr"); errno = 0;
136 /* else, a specific register number is given... */
138 else if (regno < FP0_REGNUM) { /* a GPR */
140 ptrace (PT_WRITE_GPR, inferior_pid, regno,
141 *(int*)®isters[REGISTER_BYTE (regno)], 0);
144 else if (regno <= FPLAST_REGNUM) { /* a FPR */
145 ptrace (PT_WRITE_FPR, inferior_pid,
146 (int*)®isters[REGISTER_BYTE (regno)], regno-FP0_REGNUM+FPR0, 0);
149 else if (regno <= LAST_SP_REGNUM) { /* a special register */
151 ptrace (PT_WRITE_GPR, inferior_pid, special_regs [regno-FIRST_SP_REGNUM],
152 *(int*)®isters[REGISTER_BYTE (regno)], 0);
156 fprintf (stderr, "Gdb error: register no %d not implemented.\n", regno);
159 perror ("ptrace write"); errno = 0;
166 fetch_core_registers (core_reg_sect, core_reg_size, which)
168 unsigned core_reg_size;
171 /* fetch GPRs and special registers from the first register section
175 /* copy GPRs first. */
176 bcopy (core_reg_sect, registers, 32 * 4);
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, ®isters [REGISTER_BYTE (FIRST_SP_REGNUM)],
184 (LAST_SP_REGNUM - FIRST_SP_REGNUM + 1) * 4);
187 /* fetch floating point registers from register section 2 in core bfd. */
189 bcopy (core_reg_sect, ®isters [REGISTER_BYTE (FP0_REGNUM)], 32 * 8);
192 fprintf (stderr, "Gdb error: unknown parameter to fetch_core_registers().\n");
196 frameless_function_invocation (fi)
197 struct frame_info *fi;
200 CORE_ADDR func_start, after_prologue;
203 func_start = (LOAD_ADDR (get_pc_function_start (fi->pc)) +
204 FUNCTION_START_OFFSET);
206 func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
210 after_prologue = func_start;
211 SKIP_PROLOGUE (after_prologue);
212 ret = (after_prologue == func_start);
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. */
226 /* aixcoff_relocate_symtab - hook for symbol table relocation.
227 also reads shared libraries.. */
229 aixcoff_relocate_symtab (pid)
232 #define MAX_LOAD_SEGS 64 /* maximum number of load segments */
234 extern int compare_misc_functions ();
238 ldi = (void *) alloca(MAX_LOAD_SEGS * sizeof (*ldi));
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. */
248 ptrace(PT_LDINFO, pid, ldi, MAX_LOAD_SEGS * sizeof(*ldi), ldi);
250 perror_with_name ("ptrace ldinfo");
255 add_text_to_loadinfo (ldi->ldinfo_textorg, ldi->ldinfo_dataorg);
256 } while (ldi->ldinfo_next
257 && (ldi = (void *) (ldi->ldinfo_next + (char *) ldi)));
259 /* Now that we've jumbled things around, re-sort them. */
260 sort_misc_function_vector ();
262 /* relocate the exec and core sections as well. */
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. */
271 unsigned long textorg, dataorg, toc_offset;
274 #define LOADINFOLEN 10
276 static LoadInfo *loadInfo = NULL;
277 static int loadInfoLen = 0;
278 static int loadInfoTocIndex = 0;
279 static int loadInfoTextIndex = 0;
282 xcoff_init_loadinfo ()
284 loadInfoTocIndex = 0;
285 loadInfoTextIndex = 0;
287 if (loadInfoLen == 0) {
288 loadInfo = (void*) xmalloc (sizeof (LoadInfo) * LOADINFOLEN);
289 loadInfoLen = LOADINFOLEN;
300 loadInfoTocIndex = 0;
301 loadInfoTextIndex = 0;
305 xcoff_add_toc_to_loadinfo (unsigned long tocaddr)
307 while (loadInfoTocIndex >= loadInfoLen) {
308 loadInfoLen += LOADINFOLEN;
309 loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
311 loadInfo [loadInfoTocIndex++].toc_offset = tocaddr;
315 add_text_to_loadinfo (unsigned long textaddr, unsigned long dataaddr)
317 while (loadInfoTextIndex >= loadInfoLen) {
318 loadInfoLen += LOADINFOLEN;
319 loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
321 loadInfo [loadInfoTextIndex].textorg = textaddr;
322 loadInfo [loadInfoTextIndex].dataorg = dataaddr;
328 find_toc_address (unsigned long pc)
332 for (ii=0; ii < loadInfoTextIndex; ++ii)
333 if (pc > loadInfo [ii].textorg)
336 return loadInfo [toc_entry].dataorg + loadInfo [toc_entry].toc_offset;
340 /* execute one dummy breakpoint instruction. This way we give kernel
341 a chance to do some housekeeping and update inferior's internal data,
344 exec_one_dummy_insn ()
346 #define DUMMY_INSN_ADDR 0x10000200
348 unsigned long shadow;
349 unsigned int status, pid;
351 target_insert_breakpoint (DUMMY_INSN_ADDR, &shadow);
354 ptrace (PT_CONTINUE, inferior_pid, DUMMY_INSN_ADDR, 0, 0);
356 perror ("pt_continue");
359 pid = wait (&status);
360 } while (pid != inferior_pid);
362 target_remove_breakpoint (DUMMY_INSN_ADDR, &shadow);