diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /gdb/rs6000-nat.c | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'gdb/rs6000-nat.c')
-rw-r--r-- | gdb/rs6000-nat.c | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c new file mode 100644 index 0000000..c74a36f --- /dev/null +++ b/gdb/rs6000-nat.c @@ -0,0 +1,845 @@ +/* IBM RS/6000 native-dependent code for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991, 1992, 1994, 1995, 1996, 1997, 1998 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "target.h" +#include "gdbcore.h" +#include "xcoffsolib.h" +#include "symfile.h" +#include "objfiles.h" +#include "libbfd.h" /* For bfd_cache_lookup (FIXME) */ +#include "bfd.h" +#include "gdb-stabs.h" + +#include <sys/ptrace.h> +#include <sys/reg.h> + +#include <sys/param.h> +#include <sys/dir.h> +#include <sys/user.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include <a.out.h> +#include <sys/file.h> +#include "gdb_stat.h" +#include <sys/core.h> +#include <sys/ldr.h> + +extern int errno; + +extern struct vmap * map_vmap PARAMS ((bfd *bf, bfd *arch)); + +extern struct target_ops exec_ops; + +static void +vmap_exec PARAMS ((void)); + +static void +vmap_ldinfo PARAMS ((struct ld_info *)); + +static struct vmap * +add_vmap PARAMS ((struct ld_info *)); + +static int +objfile_symbol_add PARAMS ((char *)); + +static void +vmap_symtab PARAMS ((struct vmap *)); + +static void +fetch_core_registers PARAMS ((char *, unsigned int, int, CORE_ADDR)); + +static void +exec_one_dummy_insn PARAMS ((void)); + +extern void +fixup_breakpoints PARAMS ((CORE_ADDR low, CORE_ADDR high, CORE_ADDR delta)); + +/* Conversion from gdb-to-system special purpose register numbers.. */ + +static int special_regs[] = { + IAR, /* PC_REGNUM */ + MSR, /* PS_REGNUM */ + CR, /* CR_REGNUM */ + LR, /* LR_REGNUM */ + CTR, /* CTR_REGNUM */ + XER, /* XER_REGNUM */ + MQ /* MQ_REGNUM */ +}; + +void +fetch_inferior_registers (regno) + int regno; +{ + int ii; + extern char registers[]; + + if (regno < 0) { /* for all registers */ + + /* read 32 general purpose registers. */ + + for (ii=0; ii < 32; ++ii) + *(int*)®isters[REGISTER_BYTE (ii)] = + ptrace (PT_READ_GPR, inferior_pid, (PTRACE_ARG3_TYPE) ii, 0, 0); + + /* read general purpose floating point registers. */ + + for (ii=0; ii < 32; ++ii) + ptrace (PT_READ_FPR, inferior_pid, + (PTRACE_ARG3_TYPE) ®isters [REGISTER_BYTE (FP0_REGNUM+ii)], + FPR0+ii, 0); + + /* read special registers. */ + for (ii=0; ii <= LAST_UISA_SP_REGNUM-FIRST_UISA_SP_REGNUM; ++ii) + *(int*)®isters[REGISTER_BYTE (FIRST_UISA_SP_REGNUM+ii)] = + ptrace (PT_READ_GPR, inferior_pid, (PTRACE_ARG3_TYPE) special_regs[ii], + 0, 0); + + registers_fetched (); + return; + } + + /* else an individual register is addressed. */ + + else if (regno < FP0_REGNUM) { /* a GPR */ + *(int*)®isters[REGISTER_BYTE (regno)] = + ptrace (PT_READ_GPR, inferior_pid, (PTRACE_ARG3_TYPE) regno, 0, 0); + } + else if (regno <= FPLAST_REGNUM) { /* a FPR */ + ptrace (PT_READ_FPR, inferior_pid, + (PTRACE_ARG3_TYPE) ®isters [REGISTER_BYTE (regno)], + (regno-FP0_REGNUM+FPR0), 0); + } + else if (regno <= LAST_UISA_SP_REGNUM) { /* a special register */ + *(int*)®isters[REGISTER_BYTE (regno)] = + ptrace (PT_READ_GPR, inferior_pid, + (PTRACE_ARG3_TYPE) special_regs[regno-FIRST_UISA_SP_REGNUM], + 0, 0); + } + else + fprintf_unfiltered (gdb_stderr, + "gdb error: register no %d not implemented.\n", + regno); + + register_valid [regno] = 1; +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + extern char registers[]; + + errno = 0; + + if (regno == -1) + { /* for all registers.. */ + int ii; + + /* execute one dummy instruction (which is a breakpoint) in inferior + process. So give kernel a chance to do internal house keeping. + Otherwise the following ptrace(2) calls will mess up user stack + since kernel will get confused about the bottom of the stack (%sp) */ + + exec_one_dummy_insn (); + + /* write general purpose registers first! */ + for ( ii=GPR0; ii<=GPR31; ++ii) + { + ptrace (PT_WRITE_GPR, inferior_pid, (PTRACE_ARG3_TYPE) ii, + *(int*)®isters[REGISTER_BYTE (ii)], 0); + if (errno) + { + perror ("ptrace write_gpr"); + errno = 0; + } + } + + /* write floating point registers now. */ + for ( ii=0; ii < 32; ++ii) + { + ptrace (PT_WRITE_FPR, inferior_pid, + (PTRACE_ARG3_TYPE) ®isters[REGISTER_BYTE (FP0_REGNUM+ii)], + FPR0+ii, 0); + if (errno) + { + perror ("ptrace write_fpr"); + errno = 0; + } + } + + /* write special registers. */ + for (ii=0; ii <= LAST_UISA_SP_REGNUM-FIRST_UISA_SP_REGNUM; ++ii) + { + ptrace (PT_WRITE_GPR, inferior_pid, + (PTRACE_ARG3_TYPE) special_regs[ii], + *(int*)®isters[REGISTER_BYTE (FIRST_UISA_SP_REGNUM+ii)], + 0); + if (errno) + { + perror ("ptrace write_gpr"); + errno = 0; + } + } + } + + /* else, a specific register number is given... */ + + else if (regno < FP0_REGNUM) /* a GPR */ + { + ptrace (PT_WRITE_GPR, inferior_pid, (PTRACE_ARG3_TYPE) regno, + *(int*)®isters[REGISTER_BYTE (regno)], 0); + } + + else if (regno <= FPLAST_REGNUM) /* a FPR */ + { + ptrace (PT_WRITE_FPR, inferior_pid, + (PTRACE_ARG3_TYPE) ®isters[REGISTER_BYTE (regno)], + regno - FP0_REGNUM + FPR0, 0); + } + + else if (regno <= LAST_UISA_SP_REGNUM) /* a special register */ + { + ptrace (PT_WRITE_GPR, inferior_pid, + (PTRACE_ARG3_TYPE) special_regs [regno-FIRST_UISA_SP_REGNUM], + *(int*)®isters[REGISTER_BYTE (regno)], 0); + } + + else + fprintf_unfiltered (gdb_stderr, + "Gdb error: register no %d not implemented.\n", + regno); + + if (errno) + { + perror ("ptrace write"); + errno = 0; + } +} + +/* Execute one dummy breakpoint instruction. This way we give the kernel + a chance to do some housekeeping and update inferior's internal data, + including u_area. */ + +static void +exec_one_dummy_insn () +{ +#define DUMMY_INSN_ADDR (TEXT_SEGMENT_BASE)+0x200 + + char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ + int status, pid; + CORE_ADDR prev_pc; + + /* We plant one dummy breakpoint into DUMMY_INSN_ADDR address. We + assume that this address will never be executed again by the real + code. */ + + target_insert_breakpoint (DUMMY_INSN_ADDR, shadow_contents); + + errno = 0; + + /* You might think this could be done with a single ptrace call, and + you'd be correct for just about every platform I've ever worked + on. However, rs6000-ibm-aix4.1.3 seems to have screwed this up -- + the inferior never hits the breakpoint (it's also worth noting + powerpc-ibm-aix4.1.3 works correctly). */ + prev_pc = read_pc (); + write_pc (DUMMY_INSN_ADDR); + ptrace (PT_CONTINUE, inferior_pid, (PTRACE_ARG3_TYPE)1, 0, 0); + + if (errno) + perror ("pt_continue"); + + do { + pid = wait (&status); + } while (pid != inferior_pid); + + write_pc (prev_pc); + target_remove_breakpoint (DUMMY_INSN_ADDR, shadow_contents); +} + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + CORE_ADDR reg_addr; /* Unused in this version */ +{ + /* fetch GPRs and special registers from the first register section + in core bfd. */ + if (which == 0) + { + /* copy GPRs first. */ + memcpy (registers, core_reg_sect, 32 * 4); + + /* gdb's internal register template and bfd's register section layout + should share a common include file. FIXMEmgo */ + /* then comes special registes. They are supposed to be in the same + order in gdb template and bfd `.reg' section. */ + core_reg_sect += (32 * 4); + memcpy (®isters [REGISTER_BYTE (FIRST_UISA_SP_REGNUM)], + core_reg_sect, + (LAST_UISA_SP_REGNUM - FIRST_UISA_SP_REGNUM + 1) * 4); + } + + /* fetch floating point registers from register section 2 in core bfd. */ + else if (which == 2) + memcpy (®isters [REGISTER_BYTE (FP0_REGNUM)], core_reg_sect, 32 * 8); + + else + fprintf_unfiltered + (gdb_stderr, + "Gdb error: unknown parameter to fetch_core_registers().\n"); +} + +/* handle symbol translation on vmapping */ + +static void +vmap_symtab (vp) + register struct vmap *vp; +{ + register struct objfile *objfile; + struct section_offsets *new_offsets; + int i; + + objfile = vp->objfile; + if (objfile == NULL) + { + /* OK, it's not an objfile we opened ourselves. + Currently, that can only happen with the exec file, so + relocate the symbols for the symfile. */ + if (symfile_objfile == NULL) + return; + objfile = symfile_objfile; + } + + new_offsets = alloca + (sizeof (struct section_offsets) + + sizeof (new_offsets->offsets) * objfile->num_sections); + + for (i = 0; i < objfile->num_sections; ++i) + ANOFFSET (new_offsets, i) = ANOFFSET (objfile->section_offsets, i); + + /* The symbols in the object file are linked to the VMA of the section, + relocate them VMA relative. */ + ANOFFSET (new_offsets, SECT_OFF_TEXT) = vp->tstart - vp->tvma; + ANOFFSET (new_offsets, SECT_OFF_DATA) = vp->dstart - vp->dvma; + ANOFFSET (new_offsets, SECT_OFF_BSS) = vp->dstart - vp->dvma; + + objfile_relocate (objfile, new_offsets); +} + +/* Add symbols for an objfile. */ + +static int +objfile_symbol_add (arg) + char *arg; +{ + struct objfile *obj = (struct objfile *) arg; + + syms_from_objfile (obj, 0, 0, 0); + new_symfile_objfile (obj, 0, 0); + return 1; +} + +/* Add a new vmap entry based on ldinfo() information. + + If ldi->ldinfo_fd is not valid (e.g. this struct ld_info is from a + core file), the caller should set it to -1, and we will open the file. + + Return the vmap new entry. */ + +static struct vmap * +add_vmap (ldi) + register struct ld_info *ldi; +{ + bfd *abfd, *last; + register char *mem, *objname; + struct objfile *obj; + struct vmap *vp; + + /* This ldi structure was allocated using alloca() in + xcoff_relocate_symtab(). Now we need to have persistent object + and member names, so we should save them. */ + + mem = ldi->ldinfo_filename + strlen (ldi->ldinfo_filename) + 1; + mem = savestring (mem, strlen (mem)); + objname = savestring (ldi->ldinfo_filename, strlen (ldi->ldinfo_filename)); + + if (ldi->ldinfo_fd < 0) + /* Note that this opens it once for every member; a possible + enhancement would be to only open it once for every object. */ + abfd = bfd_openr (objname, gnutarget); + else + abfd = bfd_fdopenr (objname, gnutarget, ldi->ldinfo_fd); + if (!abfd) + error ("Could not open `%s' as an executable file: %s", + objname, bfd_errmsg (bfd_get_error ())); + + /* make sure we have an object file */ + + if (bfd_check_format (abfd, bfd_object)) + vp = map_vmap (abfd, 0); + + else if (bfd_check_format (abfd, bfd_archive)) + { + last = 0; + /* FIXME??? am I tossing BFDs? bfd? */ + while ((last = bfd_openr_next_archived_file (abfd, last))) + if (STREQ (mem, last->filename)) + break; + + if (!last) + { + bfd_close (abfd); + /* FIXME -- should be error */ + warning ("\"%s\": member \"%s\" missing.", abfd->filename, mem); + return 0; + } + + if (!bfd_check_format(last, bfd_object)) + { + bfd_close (last); /* XXX??? */ + goto obj_err; + } + + vp = map_vmap (last, abfd); + } + else + { + obj_err: + bfd_close (abfd); + error ("\"%s\": not in executable format: %s.", + objname, bfd_errmsg (bfd_get_error ())); + /*NOTREACHED*/ + } + obj = allocate_objfile (vp->bfd, 0, 0, 0); + vp->objfile = obj; + +#ifndef SOLIB_SYMBOLS_MANUAL + if (catch_errors (objfile_symbol_add, (char *)obj, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + /* Note this is only done if symbol reading was successful. */ + vmap_symtab (vp); + vp->loaded = 1; + } +#endif + return vp; +} + +/* update VMAP info with ldinfo() information + Input is ptr to ldinfo() results. */ + +static void +vmap_ldinfo (ldi) + register struct ld_info *ldi; +{ + struct stat ii, vi; + register struct vmap *vp; + int got_one, retried; + int got_exec_file = 0; + + /* For each *ldi, see if we have a corresponding *vp. + If so, update the mapping, and symbol table. + If not, add an entry and symbol table. */ + + do { + char *name = ldi->ldinfo_filename; + char *memb = name + strlen(name) + 1; + + retried = 0; + + if (fstat (ldi->ldinfo_fd, &ii) < 0) + { + /* The kernel sets ld_info to -1, if the process is still using the + object, and the object is removed. Keep the symbol info for the + removed object and issue a warning. */ + warning ("%s (fd=%d) has disappeared, keeping its symbols", + name, ldi->ldinfo_fd); + continue; + } + retry: + for (got_one = 0, vp = vmap; vp; vp = vp->nxt) + { + struct objfile *objfile; + + /* First try to find a `vp', which is the same as in ldinfo. + If not the same, just continue and grep the next `vp'. If same, + relocate its tstart, tend, dstart, dend values. If no such `vp' + found, get out of this for loop, add this ldi entry as a new vmap + (add_vmap) and come back, find its `vp' and so on... */ + + /* The filenames are not always sufficient to match on. */ + + if ((name[0] == '/' && !STREQ(name, vp->name)) + || (memb[0] && !STREQ(memb, vp->member))) + continue; + + /* See if we are referring to the same file. + We have to check objfile->obfd, symfile.c:reread_symbols might + have updated the obfd after a change. */ + objfile = vp->objfile == NULL ? symfile_objfile : vp->objfile; + if (objfile == NULL + || objfile->obfd == NULL + || bfd_stat (objfile->obfd, &vi) < 0) + { + warning ("Unable to stat %s, keeping its symbols", name); + continue; + } + + if (ii.st_dev != vi.st_dev || ii.st_ino != vi.st_ino) + continue; + + if (!retried) + close (ldi->ldinfo_fd); + + ++got_one; + + /* Found a corresponding VMAP. Remap! */ + + /* We can assume pointer == CORE_ADDR, this code is native only. */ + vp->tstart = (CORE_ADDR) ldi->ldinfo_textorg; + vp->tend = vp->tstart + ldi->ldinfo_textsize; + vp->dstart = (CORE_ADDR) ldi->ldinfo_dataorg; + vp->dend = vp->dstart + ldi->ldinfo_datasize; + + /* The run time loader maps the file header in addition to the text + section and returns a pointer to the header in ldinfo_textorg. + Adjust the text start address to point to the real start address + of the text section. */ + vp->tstart += vp->toffs; + + /* The objfile is only NULL for the exec file. */ + if (vp->objfile == NULL) + got_exec_file = 1; + + /* relocate symbol table(s). */ + vmap_symtab (vp); + + /* There may be more, so we don't break out of the loop. */ + } + + /* if there was no matching *vp, we must perforce create the sucker(s) */ + if (!got_one && !retried) + { + add_vmap (ldi); + ++retried; + goto retry; + } + } while (ldi->ldinfo_next + && (ldi = (void *) (ldi->ldinfo_next + (char *) ldi))); + + /* If we don't find the symfile_objfile anywhere in the ldinfo, it + is unlikely that the symbol file is relocated to the proper + address. And we might have attached to a process which is + running a different copy of the same executable. */ + if (symfile_objfile != NULL && !got_exec_file) + { + warning_begin (); + fputs_unfiltered ("Symbol file ", gdb_stderr); + fputs_unfiltered (symfile_objfile->name, gdb_stderr); + fputs_unfiltered ("\nis not mapped; discarding it.\n\ +If in fact that file has symbols which the mapped files listed by\n\ +\"info files\" lack, you can load symbols with the \"symbol-file\" or\n\ +\"add-symbol-file\" commands (note that you must take care of relocating\n\ +symbols to the proper address).\n", gdb_stderr); + free_objfile (symfile_objfile); + symfile_objfile = NULL; + } + breakpoint_re_set (); +} + +/* As well as symbol tables, exec_sections need relocation. After + the inferior process' termination, there will be a relocated symbol + table exist with no corresponding inferior process. At that time, we + need to use `exec' bfd, rather than the inferior process's memory space + to look up symbols. + + `exec_sections' need to be relocated only once, as long as the exec + file remains unchanged. +*/ + +static void +vmap_exec () +{ + static bfd *execbfd; + int i; + + if (execbfd == exec_bfd) + return; + + execbfd = exec_bfd; + + if (!vmap || !exec_ops.to_sections) + error ("vmap_exec: vmap or exec_ops.to_sections == 0\n"); + + for (i=0; &exec_ops.to_sections[i] < exec_ops.to_sections_end; i++) + { + if (STREQ(".text", exec_ops.to_sections[i].the_bfd_section->name)) + { + exec_ops.to_sections[i].addr += vmap->tstart - vmap->tvma; + exec_ops.to_sections[i].endaddr += vmap->tstart - vmap->tvma; + } + else if (STREQ(".data", exec_ops.to_sections[i].the_bfd_section->name)) + { + exec_ops.to_sections[i].addr += vmap->dstart - vmap->dvma; + exec_ops.to_sections[i].endaddr += vmap->dstart - vmap->dvma; + } + else if (STREQ(".bss", exec_ops.to_sections[i].the_bfd_section->name)) + { + exec_ops.to_sections[i].addr += vmap->dstart - vmap->dvma; + exec_ops.to_sections[i].endaddr += vmap->dstart - vmap->dvma; + } + } +} + +/* xcoff_relocate_symtab - hook for symbol table relocation. + also reads shared libraries.. */ + +void +xcoff_relocate_symtab (pid) + unsigned int pid; +{ +#define MAX_LOAD_SEGS 64 /* maximum number of load segments */ + + struct ld_info *ldi; + + ldi = (void *) alloca(MAX_LOAD_SEGS * sizeof (*ldi)); + + /* According to my humble theory, AIX has some timing problems and + when the user stack grows, kernel doesn't update stack info in time + and ptrace calls step on user stack. That is why we sleep here a little, + and give kernel to update its internals. */ + + usleep (36000); + + errno = 0; + ptrace (PT_LDINFO, pid, (PTRACE_ARG3_TYPE) ldi, + MAX_LOAD_SEGS * sizeof(*ldi), (int *) ldi); + if (errno) + perror_with_name ("ptrace ldinfo"); + + vmap_ldinfo (ldi); + + /* relocate the exec and core sections as well. */ + vmap_exec (); +} + +/* Core file stuff. */ + +/* Relocate symtabs and read in shared library info, based on symbols + from the core file. */ + +void +xcoff_relocate_core (target) + struct target_ops *target; +{ +/* Offset of member MEMBER in a struct of type TYPE. */ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) +#endif + +/* Size of a struct ld_info except for the variable-length filename. */ +#define LDINFO_SIZE (offsetof (struct ld_info, ldinfo_filename)) + + sec_ptr ldinfo_sec; + int offset = 0; + struct ld_info *ldip; + struct vmap *vp; + + /* Allocated size of buffer. */ + int buffer_size = LDINFO_SIZE; + char *buffer = xmalloc (buffer_size); + struct cleanup *old = make_cleanup (free_current_contents, &buffer); + + /* FIXME, this restriction should not exist. For now, though I'll + avoid coredumps with error() pending a real fix. */ + if (vmap == NULL) + error + ("Can't debug a core file without an executable file (on the RS/6000)"); + + ldinfo_sec = bfd_get_section_by_name (core_bfd, ".ldinfo"); + if (ldinfo_sec == NULL) + { + bfd_err: + fprintf_filtered (gdb_stderr, "Couldn't get ldinfo from core file: %s\n", + bfd_errmsg (bfd_get_error ())); + do_cleanups (old); + return; + } + do + { + int i; + int names_found = 0; + + /* Read in everything but the name. */ + if (bfd_get_section_contents (core_bfd, ldinfo_sec, buffer, + offset, LDINFO_SIZE) == 0) + goto bfd_err; + + /* Now the name. */ + i = LDINFO_SIZE; + do + { + if (i == buffer_size) + { + buffer_size *= 2; + buffer = xrealloc (buffer, buffer_size); + } + if (bfd_get_section_contents (core_bfd, ldinfo_sec, &buffer[i], + offset + i, 1) == 0) + goto bfd_err; + if (buffer[i++] == '\0') + ++names_found; + } while (names_found < 2); + + ldip = (struct ld_info *) buffer; + + /* Can't use a file descriptor from the core file; need to open it. */ + ldip->ldinfo_fd = -1; + + /* The first ldinfo is for the exec file, allocated elsewhere. */ + if (offset == 0) + vp = vmap; + else + vp = add_vmap (ldip); + + offset += ldip->ldinfo_next; + + /* We can assume pointer == CORE_ADDR, this code is native only. */ + vp->tstart = (CORE_ADDR) ldip->ldinfo_textorg; + vp->tend = vp->tstart + ldip->ldinfo_textsize; + vp->dstart = (CORE_ADDR) ldip->ldinfo_dataorg; + vp->dend = vp->dstart + ldip->ldinfo_datasize; + + /* The run time loader maps the file header in addition to the text + section and returns a pointer to the header in ldinfo_textorg. + Adjust the text start address to point to the real start address + of the text section. */ + vp->tstart += vp->toffs; + + /* Unless this is the exec file, + add our sections to the section table for the core target. */ + if (vp != vmap) + { + int count; + struct section_table *stp; + int update_coreops; + + /* We must update the to_sections field in the core_ops structure + now to avoid dangling pointer dereferences. */ + update_coreops = core_ops.to_sections == target->to_sections; + + count = target->to_sections_end - target->to_sections; + count += 2; + target->to_sections = (struct section_table *) + xrealloc (target->to_sections, + sizeof (struct section_table) * count); + target->to_sections_end = target->to_sections + count; + + /* Update the to_sections field in the core_ops structure + if needed. */ + if (update_coreops) + { + core_ops.to_sections = target->to_sections; + core_ops.to_sections_end = target->to_sections_end; + } + stp = target->to_sections_end - 2; + + stp->bfd = vp->bfd; + stp->the_bfd_section = bfd_get_section_by_name (stp->bfd, ".text"); + stp->addr = vp->tstart; + stp->endaddr = vp->tend; + stp++; + + stp->bfd = vp->bfd; + stp->the_bfd_section = bfd_get_section_by_name (stp->bfd, ".data"); + stp->addr = vp->dstart; + stp->endaddr = vp->dend; + } + + vmap_symtab (vp); + } while (ldip->ldinfo_next != 0); + vmap_exec (); + breakpoint_re_set (); + do_cleanups (old); +} + +int +kernel_u_size () +{ + return (sizeof (struct user)); +} + +/* Under AIX, we have to pass the correct TOC pointer to a function + when calling functions in the inferior. + We try to find the relative toc offset of the objfile containing PC + and add the current load address of the data segment from the vmap. */ + +static CORE_ADDR +find_toc_address (pc) + CORE_ADDR pc; +{ + struct vmap *vp; + + for (vp = vmap; vp; vp = vp->nxt) + { + if (pc >= vp->tstart && pc < vp->tend) + { + /* vp->objfile is only NULL for the exec file. */ + return vp->dstart + get_toc_offset (vp->objfile == NULL + ? symfile_objfile + : vp->objfile); + } + } + error ("Unable to find TOC entry for pc 0x%x\n", pc); +} + +/* Register that we are able to handle rs6000 core file formats. */ + +static struct core_fns rs6000_core_fns = +{ + bfd_target_coff_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_rs6000 () +{ + /* Initialize hook in rs6000-tdep.c for determining the TOC address when + calling functions in the inferior. */ + find_toc_address_hook = &find_toc_address; + + /* For native configurations, where this module is included, inform + the xcoffsolib module where it can find the function for symbol table + relocation at runtime. */ + xcoff_relocate_symtab_hook = &xcoff_relocate_symtab; + add_core_fns (&rs6000_core_fns); +} |