* rs6000-pinsn.c, rs6000-tdep.c, rs6000-xdep.c, tm-rs6000.h,
authorJohn Gilmore <gnu@cygnus>
Tue, 12 Nov 1991 15:50:47 +0000 (15:50 +0000)
committerJohn Gilmore <gnu@cygnus>
Tue, 12 Nov 1991 15:50:47 +0000 (15:50 +0000)
xm-rs6000.h:  New files.
* xcoffexec.c:  New file for handling AIX shared libraries.

gdb/rs6000-pinsn.c [new file with mode: 0644]
gdb/rs6000-tdep.c [new file with mode: 0644]
gdb/rs6000-xdep.c [new file with mode: 0644]
gdb/tm-rs6000.h [new file with mode: 0644]
gdb/xcoffexec.c [new file with mode: 0644]
gdb/xm-rs6000.h [new file with mode: 0644]

diff --git a/gdb/rs6000-pinsn.c b/gdb/rs6000-pinsn.c
new file mode 100644 (file)
index 0000000..d1e2399
--- /dev/null
@@ -0,0 +1,377 @@
+/* Print rs6000 instructions for objdump.
+   This file is part of the binutils.
+*/
+
+
+#include <stdio.h>
+#include "defs.h"
+#include "rs6k-opcode.h"
+
+
+/* Print the rs6k instruction at address MEMADDR in debugged memory,
+   on STREAM.  Returns length of the instruction, in bytes.  */
+
+int
+print_insn (memaddr, stream)
+  CORE_ADDR memaddr;
+  FILE *stream;
+{
+       int  pop, eop;                  /* primary and extended opcodes */
+       int  min, max;
+       int  best = -1;                 /* found best opcode index      */
+       int  oldbest = -1;
+       unsigned int the_insn;
+
+       read_memory (memaddr, &the_insn, sizeof (the_insn));
+       pop = (unsigned)(the_insn >> 26);
+       eop = ((the_insn) >> 1) & 0x3ff;
+       min = 0, max = NOPCODES-1;
+
+       while (min < max) {
+         best = (min + max) / 2;
+
+         /* see if we are running in loops */
+         if (best == oldbest)
+           goto not_found;
+         oldbest = best;
+
+         if (pop < rs6k_ops [best].p_opcode)
+           max = best;
+
+         else if (pop > rs6k_ops [best].p_opcode)
+           min = best;
+
+         else {
+           /* opcode matched, check extended opcode. */
+
+           if (rs6k_ops [best].e_opcode == -1) {
+             /* there is no valid extended opcode, what we've got is
+                just fine. */
+             goto insn_found;
+           }
+
+           else if (eop < rs6k_ops [best].e_opcode) {
+
+             while (pop == rs6k_ops [best].p_opcode) {
+               if (eop == rs6k_ops [best].e_opcode)    /* found it! */
+                 goto insn_found;
+               --best;
+             }
+             goto not_found;
+           }
+
+           else if (eop > rs6k_ops [best].e_opcode) {
+
+             while (pop == rs6k_ops [best].p_opcode) {
+               if (eop == rs6k_ops [best].e_opcode)    /* found it! */
+                 goto insn_found;
+               ++best;
+             }
+             goto not_found;
+           }
+
+           else /*  eop == rs6k_ops [best].e_opcode */
+             goto insn_found;
+         }
+       }       
+
+       best = min;
+       if (pop == rs6k_ops [best].p_opcode &&
+           (rs6k_ops [best].e_opcode == -1 || rs6k_ops [best].e_opcode == eop))
+           goto insn_found;
+
+       else
+         goto not_found;
+
+
+insn_found:
+       print_operator (stream, memaddr, the_insn, best);
+       return 4;
+
+not_found:
+       fprintf (stream, "0x%08x", the_insn);
+       return 4;
+}
+
+
+
+/* condition code names */
+static char *cond_code [] = {
+  "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", "nl", "ng", "z", "nz" };
+
+
+print_operator (stream, memaddr, insn_word, insn_no)
+FILE   *stream;
+long   memaddr;
+long   insn_word;
+int    insn_no;
+{
+  char buf [BUFSIZ];
+  char *qq = buf;
+  char *pp = rs6k_ops[insn_no].opr_ext;
+  int tmp;
+  int nocomma = 0;                     /* true if no comma needed */
+
+  *qq = '\0';
+  if (pp) {
+    while (*pp) {
+
+      switch ( *pp ) {
+       case '.':
+         if (insn_word & 0x1)
+          *qq++ = '.';
+         break;
+
+       case 'l':
+         if (insn_word & 0x1)
+          *qq++ = 'l';
+         break;
+
+       case 't':
+         if ((insn_word & 0x03e00000) == 0x01800000)
+          *qq++ = 't';
+         break;
+
+       case 'f':
+         if ((insn_word & 0x03e00000) == 0x00800000)
+          *qq++ = 'f';
+         break;
+
+       case 'a':
+         if (insn_word & 0x2)
+          *qq++ = 'a';
+         break;
+
+       case 'o':
+         if (insn_word & 0x4000)
+          *qq++ = 'o';
+         break;
+
+       case '1':               /* exception #1 for bb/bc ambiguity */
+         tmp = (insn_word >> 21) & 0x1f;       /* extract BO   */
+         if (tmp != 0xc && tmp != 0x4) {
+           /* you can't use `bb' now. switch to `bc' */
+           *(qq-1) = 'c';
+           ++insn_no;
+           pp = rs6k_ops[insn_no].opr_ext;
+           continue;
+         }
+         break;
+
+       default:
+         abort ();
+      }
+      ++pp;
+    }
+  }
+
+  /* tab between orerator and operand */
+  *qq++ = '\t';
+
+  /* parse the operand now. */
+  pp = rs6k_ops[insn_no].oprnd_format;
+
+  while (1) {
+    switch (*pp) {
+      case TO  :
+       sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
+       break;
+
+      case RT  :
+      case RS  :
+       sprintf (qq, "r%d", (insn_word >> 21) & 0x1f);
+       break;
+
+      case LI  :
+       tmp  = (insn_word >> 16) & 0x1f;
+       if (tmp > 11) {
+         fprintf (stderr, "Internal error: unknown cond code: 0x%x\n", insn_word);
+         tmp = 0;
+       }
+       sprintf (qq, "%s", cond_code [tmp]);
+       break;
+
+#if 0
+      case A2  :
+       tmp = (insn_word >> 2) & 0x3fff;
+       if (tmp & 0x2000)
+        tmp -= 0x4000;
+       sprintf (qq, "0x%x", tmp * 4 + memaddr);
+       break;
+#endif
+      case A2  :
+      case TA14        :
+       tmp = (insn_word & 0xfffc);
+       if (tmp & 0x8000)               /* fix sign extension   */
+         tmp -= 0x10000;
+
+       if ((insn_word & 0x2) == 0)     /* if AA not set        */
+         tmp += memaddr;
+
+       sprintf (qq, "0x%x", tmp);
+       break;
+
+      case TA24        :
+       tmp = insn_word & 0x03fffffc;
+       if (tmp & 0x2000000)
+         tmp -= 0x4000000;
+       
+       if ((insn_word & 0x2) == 0)             /* if no AA bit set */
+         tmp += memaddr;
+
+       sprintf (qq, "0x%x", tmp);
+       break;
+
+      case LEV :                       /* for svc only */
+       if (insn_word & 0x2) {          /* SA is set    */
+         nocomma = 1;
+         *qq = '\0';
+       }
+       else
+          sprintf (qq, "%d", (insn_word >> 5) & 0x7f);
+       break;
+
+      case FL1 :                       /* for svc only */
+       if (insn_word & 0x2) {          /* SA is set    */
+         nocomma = 1;
+         *qq = '\0';
+       }
+       else
+          sprintf (qq, "%d", (insn_word >> 12) & 0xf);
+       break;
+
+      case FL2 :                       /* for svc only */
+       nocomma = 0;
+       if (insn_word & 0x2)            /* SA is set    */
+         sprintf (qq, "%d", (insn_word >> 2) & 0x3fff);
+       else
+          sprintf (qq, "%d", (insn_word >> 2) & 0x7);
+       break;
+
+      case RA  :
+       if (nocomma) {
+         sprintf (qq, "r%d)", (insn_word >> 16) & 0x1f);
+         nocomma = 0;
+       }
+       else
+         sprintf (qq, "r%d", (insn_word >> 16) & 0x1f);
+       break;
+
+      case RB  :
+       sprintf (qq, "r%d", (insn_word >> 11) & 0x1f);
+       break;
+
+      case SI  :
+       tmp = insn_word & 0xffff;
+       if (tmp & 0x8000)
+         tmp -= 0x10000;
+       sprintf (qq, "%d", tmp);
+       break;
+
+      case UI  :
+       sprintf (qq, "%d", insn_word & 0xffff);
+       break;
+
+      case BF  :
+       sprintf (qq, "%d", (insn_word >> 23) & 0x7);
+       break;
+
+      case BFA :
+       sprintf (qq, "%d", (insn_word >> 18) & 0x7);
+       break;
+
+      case BT  :
+       sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
+       break;
+
+      case BA  :
+       sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
+       break;
+
+      case BB  :
+       sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
+       break;
+
+      case BO  :
+       sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
+       break;
+
+      case BI  :
+       sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
+       break;
+
+      case SH  :
+       sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
+       break;
+
+      case MB  :
+       sprintf (qq, "0x%x", (insn_word >> 6) & 0x1f);
+       break;
+
+      case ME  :
+       sprintf (qq, "0x%x", (insn_word >> 1) & 0x1f);
+       break;
+
+      case SPR :
+       sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
+       break;
+
+      case DIS :
+       nocomma = 1;
+       tmp = insn_word & 0xffff;
+       if (tmp & 0x8000)
+         tmp -= 0x10000;
+       sprintf (qq, "%d(", tmp);
+       break;
+
+      case FXM :
+       sprintf (qq, "0x%x", (insn_word >> 12) & 0xff);
+       break;
+
+      case FRT :
+      case FRS :
+       sprintf (qq, "f%d", (insn_word >> 21) & 0x1f);
+       break;
+
+      case FRA :
+       sprintf (qq, "f%d", (insn_word >> 16) & 0x1f);
+       break;
+
+      case FRB :
+       sprintf (qq, "f%d", (insn_word >> 11) & 0x1f);
+       break;
+
+      case FRC :
+       sprintf (qq, "f%d", (insn_word >> 6) & 0x1f);
+       break;
+
+      case FLM :
+       sprintf (qq, "0x%x", (insn_word >> 17) & 0xff);
+       break;
+
+      case NB  :
+       sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
+       break;
+
+      case I   :
+       sprintf (qq, "%d", (insn_word >> 12) & 0xf);
+       break;
+
+      default  :
+       sprintf (qq, "Unknown operand format identifier????");
+       abort ();
+    }
+    while (*qq) ++qq;
+    ++pp;
+
+    if (*pp == '\0')
+      break;
+    else if (!nocomma)
+      *qq++ = ',';
+  }
+  *qq = '\0';
+    
+  fprintf (stream, "0x%08x\t%s%s", 
+       insn_word, rs6k_ops[insn_no].operator, buf);
+}
+
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
new file mode 100644 (file)
index 0000000..4003de0
--- /dev/null
@@ -0,0 +1,975 @@
+/* Target-dependent code for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1989, 1991 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+
+#include <a.out.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/core.h>
+
+extern int errno;
+extern int attach_flag;
+
+/* Nonzero if we just simulated a single step break. */
+int one_stepped;
+
+#if 0
+
+/* This is Damon's implementation of single step simulation. It suffers the
+   following program:
+
+   1 main () {
+   2   char buf[10];
+   3   puts ("test");
+   4   strcmp (buf, "test");  puts ("test");
+   5   exit (0);
+   6 }
+
+   You cannot `next' on line 4 in the above program. gdb puts a breakpoint
+   to the return address of `strcmp', and when execution arrives that point,
+   it is still in the line range and gdb attemps to resume it with single 
+   steps. At that point the breakpoint at step_resume_break_address (return 
+   address of strcmp) and single step's breakpoint mixes up and we end up
+   with a breakpoint which its shadow and itself are identical.
+
+   Fix that problem and use this version. FIXMEmgo.
+*/
+
+
+static struct sstep_breaks {
+       int address;
+       int data;
+} tbreak[2];
+
+
+/*
+ * branch_dest -       calculate all places the current instruction may go
+ */
+static
+branch_dest(tb)
+     register struct sstep_breaks *tb; 
+{
+    register ulong opcode, iar;
+    long instr;
+    int immediate, absolute;;
+
+    iar = read_pc();                                   /* current IAR  */
+    target_read_memory(iar, &instr, sizeof (instr));   /* current inst */
+
+    opcode   = instr >> 26;
+    absolute = instr & 2;
+
+    tb[1].address = -1;
+
+    switch (opcode) {
+      case 0x10:                       /* branch conditional   */
+       immediate = ((instr & ~3) << 16) >> 16;
+
+       /*
+        * two possible locations for next instruction
+        */
+       tb[0].address = iar + 4;
+       tb[1].address = immediate + (absolute ? 0 : iar);
+
+       break;
+
+      case 0x12:                       /* branch unconditional */
+       immediate = ((instr & ~3) << 6) >> 6;
+
+       /*
+        * only one possible location for next instr
+        */
+       tb[0].address = immediate + (absolute ? 0 : iar);
+
+       break;
+
+      case 0x13:                       /* branch conditional register  */
+       /*
+        * WE NEED TO CHECK THE CR HERE, TO SEE IF THIS IS
+        * REALLY UNCONDITIONAL.
+        */
+       tb++->address = iar + 4;
+
+       switch ((instr >> 1) & 0x3ff) {
+         case 0x10:                    /* branch conditional register  */
+           tb->address = read_register(LR_REGNUM) & ~3;
+           sigtramp_chk(tb);           /* return from sig handler?     */
+           break;
+
+         case 0x210:                   /* branch cond to CTR           */
+           tb->address = read_register(CTR_REGNUM) & ~3;
+           sigtramp_chk(tb);           /* return from sig handler?     */
+           break;
+
+         default:
+           /*
+            * not a branch.
+            */
+           tb->address = iar + 4;
+           break;
+       }
+       break;
+       
+      default:
+       /*
+        * not a branch, flow proceeds normally
+        */
+       tb->address = iar + 4;
+       break;
+    }
+}
+
+/*
+ * sigtramp_chk -      heuristic check to see if we think we are returning
+ *                     from a signal handler.
+ *
+ * Input:
+ *     tb      -       ^ to a single step branch location
+ *
+ * Note:
+ *     When we are at the "br" instruction returning to a signal handler,
+ *     we return in user mode to an address in the kernel.  If the
+ *     segment of the branch target is 0, we may very well be in a
+ *     signal handler.  From scrounging through this code, we note that
+ *     register 29 has the signal context pointer, from which we can
+ *     determine where we will end up next.
+ */
+sigtramp_chk(tb)
+register struct sstep_breaks *tb; {
+    struct sigcontext sc;
+
+    if (tb->address & 0xf0000000)
+       return;         /* can't have been sigtramp     */
+
+    if (target_read_memory(read_register(GPR29), &sc, sizeof (sc)))
+       return;         /* read fails, heuristic fails  */
+
+    if ((sc.sc_jmpbuf.jmp_context.iar & 0xf0000000) == 0x10000000) {
+       /*
+        * looks like it might be ok.....
+        */
+       tb->address = sc.sc_jmpbuf.jmp_context.iar;
+    }
+}
+
+
+/*
+ * single_step -       no trace mode harware support, or software support.
+ *                     sigh.
+ */
+single_step(signal) {
+    register i;
+
+    if (!one_stepped) {
+       /*
+        * need to set breakpoints for single step.
+        * figure out all places the current instruction could go.
+        */
+       branch_dest(&tbreak[0]);
+
+       /*
+        * always at least one place to go to
+        */
+       target_insert_breakpoint(tbreak[0].address, &tbreak[0].data);
+
+       /*
+        * if there is another possible location, set a breakpoint there
+        * as well.
+        */
+       if (tbreak[1].address != -1)
+           target_insert_breakpoint(tbreak[1].address, &tbreak[1].data);
+
+       one_stepped = 1;
+       ptrace(PT_CONTINUE, inferior_pid, 1, signal, 0);
+    } else {
+       /*
+        * need to clear the breakpoints.
+        */
+       for (i = 0; i < 2; ++i)
+           if (tbreak[i].address != -1)
+               target_remove_breakpoint(tbreak[i].address, &tbreak[i].data);
+
+       one_stepped = 0;
+    }
+
+    return 1;
+}
+
+#else  /* !DAMON'S VERSION */
+
+/* Breakpoint shadows for the single step instructions will be kept here. */
+
+static struct sstep_breaks {
+       int address;
+       int data;
+} stepBreaks[2];
+
+
+/*
+ * Calculate the destination of a branch/jump.  Return -1 if not a branch.
+ */
+static int
+branch_dest (opcode, instr, pc, safety)
+ int opcode, instr, pc, safety;
+{
+  register long offset;
+  unsigned dest;
+  int immediate;
+  int absolute;
+  int ext_op;
+
+  absolute = (int) ((instr >> 1) & 1);
+
+  switch (opcode) {
+     case 18   :
+       immediate = ((instr & ~3) << 6) >> 6;   /* br unconditionl */
+
+     case 16   :  
+       if (opcode != 18)                       /* br conditional */
+         immediate = ((instr & ~3) << 16) >> 16;
+       if (absolute)
+         dest = immediate;     
+       else
+         dest = pc + immediate;
+       break;
+
+      case 19  :
+       ext_op = (instr>>1) & 0x3ff;
+
+       if (ext_op == 16)                       /* br conditional register */
+         dest = read_register (LR_REGNUM) & ~3;
+
+       else if (ext_op == 528)                 /* br cond to count reg */
+         dest = read_register (CTR_REGNUM) & ~3;
+
+       else return -1; 
+       break;
+       
+       default: return -1;
+  }
+  return (dest < 0x10000000) ? safety : dest;
+}
+
+
+
+/* AIX does not support PT_STEP. Simulate it. */
+
+int
+single_step (signal)
+int signal;
+{
+#define        INSNLEN(OPCODE)  4
+
+  static char breakp[] = BREAKPOINT;
+  int ii, insn, ret, loc;
+  int breaks[2], opcode;
+
+  if (!one_stepped) {
+    extern CORE_ADDR text_start;
+    loc = read_pc ();
+
+    ret = read_memory (loc, &insn, sizeof (int));
+    if (ret)
+      printf ("Error in single_step()!!\n");
+
+    breaks[0] = loc + INSNLEN(insn);
+    opcode = insn >> 26;
+    breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
+
+    stepBreaks[1].address = -1;
+
+    for (ii=0; ii < 2; ++ii) {
+
+      /* ignore invalid breakpoint. */
+      if ( breaks[ii] == -1)
+        continue;
+
+      read_memory (breaks[ii], &(stepBreaks[ii].data), sizeof(int));
+
+      ret = write_memory (breaks[ii], breakp, sizeof(int));
+      stepBreaks[ii].address = breaks[ii];
+    }  
+
+    one_stepped = 1;
+    ptrace (PT_CONTINUE, inferior_pid, 1, signal);
+  }
+  else {
+
+    /* remove step breakpoints. */
+    for (ii=0; ii < 2; ++ii)
+      if (stepBreaks[ii].address != -1)
+        write_memory 
+           (stepBreaks[ii].address, &(stepBreaks[ii].data), sizeof(int));
+
+    one_stepped = 0;
+  }
+  return 1;
+}
+#endif /* !DAMON's version of single step. */
+
+
+
+/* return pc value after skipping a function prologue. */
+
+skip_prologue (pc)
+int pc;
+{
+  unsigned int tmp;
+  unsigned int op;
+
+  if (target_read_memory (pc, (char *)&op, sizeof (op)))
+    return pc;                 /* Can't access it -- assume no prologue. */
+  SWAP_TARGET_AND_HOST (&op, sizeof (op));
+
+  /* Assume that subsequent fetches can fail with low probability.  */
+
+  if (op == 0x7c0802a6) {              /* mflr r0 */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+  else                         /* else, this is a frameless invocation */
+    return pc;
+
+  if ((op & 0xfc00003e) == 0x7c000026) { /* mfcr Rx */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
+    pc += 4;                            /* store floating register double */
+    op = read_memory_integer (pc, 4);
+  }
+
+  if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  while (((tmp = op >> 16) == 0x9001) || /* st   r0, NUM(r1) */
+        (tmp == 0x9421) ||             /* stu  r1, NUM(r1) */
+        (op == 0x93e1fffc))            /* st   r31,-4(r1) */
+  {
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  while ((tmp = (op >> 22)) == 0x20f) {        /* l    r31, ... or */
+    pc += 4;                           /* l    r30, ...    */
+    op = read_memory_integer (pc, 4);
+  }
+
+  while ((op & 0xfc1f0000) == 0x90010000) {    /* st r?, NUM(r1) */  
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  if (op == 0x603f0000) {                      /* oril r31, r1, 0x0 */
+    pc += 4;                                   /* this happens if r31 is used as */
+    op = read_memory_integer (pc, 4);          /* frame ptr. (gcc does that)     */
+
+    if ((op >> 16) == 0x907f) {                        /* st r3, NUM(r31) */
+      pc += 4;
+      op = read_memory_integer (pc, 4);
+    }
+  }
+  return pc;
+}
+
+/* text start and end addresses in virtual memory. */
+
+CORE_ADDR text_start;
+CORE_ADDR text_end;
+
+
+/*************************************************************************
+  Support for creating pushind a dummy frame into the stack, and popping
+  frames, etc. 
+*************************************************************************/
+
+#define        DUMMY_FRAME_ADDR_SIZE 10
+
+/* Make sure you initialize these in somewhere, in case gdb gives up what it
+   was debugging and starts debugging something else. FIXMEmgo */
+
+static int dummy_frame_count = 0;
+static int dummy_frame_size = 0;
+static CORE_ADDR *dummy_frame_addr = 0;
+
+extern int stop_stack_dummy;
+
+/* push a dummy frame into stack, save all register. Currently we are saving
+   only gpr's and fpr's, which is not good enough! FIXMEmgo */
+   
+push_dummy_frame ()
+{
+  int sp, pc;                          /* stack pointer and link register */
+  int ii;
+
+  if (dummy_frame_count >= dummy_frame_size) {
+    dummy_frame_size += DUMMY_FRAME_ADDR_SIZE;
+    if (dummy_frame_addr)
+      dummy_frame_addr = (CORE_ADDR*) xrealloc 
+        (dummy_frame_addr, sizeof(CORE_ADDR) * (dummy_frame_size));
+    else
+      dummy_frame_addr = (CORE_ADDR*) 
+       xmalloc (sizeof(CORE_ADDR) * (dummy_frame_size));
+  }
+  
+  sp = read_register(SP_REGNUM);
+  pc = read_register(PC_REGNUM);  
+
+  dummy_frame_addr [dummy_frame_count++] = sp;
+
+  /* Be careful! If the stack pointer is not decremented first, then kernel 
+     thinks he is free to use the sapce underneath it. And kernel actually 
+     uses that area for IPC purposes when executing ptrace(2) calls. So 
+     before writing register values into the new frame, decrement and update
+     %sp first in order to secure your frame. */
+
+  write_register (SP_REGNUM, sp-408);
+
+#if 1
+  /* gdb relies on the state of current_frame. We'd better update it,
+     otherwise things like do_registers_info() wouldn't work properly! */
+
+  flush_cached_frames ();
+  set_current_frame (create_new_frame (sp-408, pc));
+#endif /* 0 */
+
+  /* save program counter in link register's space. */
+  write_memory (sp+8, &pc, 4);
+
+  /* save full floating point registers here. They will be from F14..F31
+     for know. I am not sure if we need to save everything here! */
+
+  /* fpr's, f0..f31 */
+  for (ii = 0; ii < 32; ++ii)
+    write_memory (sp-8-(ii*8), &registers[REGISTER_BYTE (31-ii+FP0_REGNUM)], 8);
+
+  /* gpr's r0..r31 */
+  for (ii=1; ii <=32; ++ii)
+    write_memory (sp-256-(ii*4), &registers[REGISTER_BYTE (32-ii)], 4);
+
+  /* so far, 32*2 + 32 words = 384 bytes have been written. We need 6 words
+     (24 bytes) for the rest of the registers. It brings the total to 408 
+     bytes.
+     save sp or so call back chain right here. */
+  write_memory (sp-408, &sp, 4);
+  sp -= 408;
+
+  /* And finally, this is the back chain. */
+  write_memory (sp+8, &pc, 4);
+}
+
+
+/* Pop a dummy frame.
+
+   In rs6000 when we push a dummy frame, we save all of the registers. This
+   is usually done before user calls a function explicitly.
+
+   After a dummy frame is pushed, some instructions are copied into stack, and
+   stack pointer is decremented even more. Since we don't have a frame pointer to
+   get back to the parent frame of the dummy, we start having trouble poping it.
+   Therefore, we keep a dummy frame stack, keeping addresses of dummy frames as
+   such. When poping happens and when we detect that was a dummy frame, we pop
+   it back to its parent by using dummy frame stack (`dummy_frame_addr' array).
+ */
+   
+pop_dummy_frame ()
+{
+  CORE_ADDR sp, pc;
+  int ii;
+  sp = dummy_frame_addr [--dummy_frame_count];
+
+  /* restore all fpr's. */
+  for (ii = 1; ii <= 32; ++ii)
+    read_memory (sp-(ii*8), &registers[REGISTER_BYTE (32-ii+FP0_REGNUM)], 8);
+
+  /* restore all gpr's */
+  for (ii=1; ii <= 32; ++ii) {
+    read_memory (sp-256-(ii*4), &registers[REGISTER_BYTE (32-ii)], 4);
+  }
+
+  read_memory (sp-400, &registers [REGISTER_BYTE(PC_REGNUM)], 4);
+
+  /* when a dummy frame was being pushed, we had to decrement %sp first, in 
+     order to secure astack space. Thus, saved %sp (or %r1) value, is not the
+     one we should restore. Change it with the one we need. */
+
+  *(int*)&registers [REGISTER_BYTE(FP_REGNUM)] = sp;
+
+  /* Now we can restore all registers. */
+
+  store_inferior_registers (-1);
+  pc = read_pc ();
+  flush_cached_frames ();
+  set_current_frame (create_new_frame (sp, pc));
+}
+
+
+/* pop the innermost frame, go back to the caller. */
+
+pop_frame ()
+{
+  int pc, lr, sp, prev_sp;             /* %pc, %lr, %sp */
+  FRAME fr = get_current_frame ();
+  int offset = 0;
+  int frameless = 0;                   /* TRUE if function is frameless */
+  int addr, ii;
+  int saved_gpr, saved_fpr;            /* # of saved gpr's and fpr's */
+
+  pc = read_pc ();
+  sp = FRAME_FP (fr);
+
+  if (stop_stack_dummy && dummy_frame_count) {
+    pop_dummy_frame ();
+    return;
+  }
+
+  /* figure out previous %pc value. If the function is frameless, it is 
+     still in the link register, otherwise walk the frames and retrieve the
+     saved %pc value in the previous frame. */
+
+  addr = get_pc_function_start (fr->pc) + FUNCTION_START_OFFSET;
+  function_frame_info (addr, &frameless, &offset, &saved_gpr, &saved_fpr);
+
+  read_memory (sp, &prev_sp, 4);
+  if (frameless)
+    lr = read_register (LR_REGNUM);
+  else
+    read_memory (prev_sp+8, &lr, 4);
+
+  /* reset %pc value. */
+  write_register (PC_REGNUM, lr);
+
+  /* reset register values if any was saved earlier. */
+  addr = prev_sp - offset;
+
+  if (saved_gpr != -1)
+    for (ii=saved_gpr; ii <= 31; ++ii) {
+      read_memory (addr, &registers [REGISTER_BYTE (ii)], 4);
+      addr += sizeof (int);
+    }
+
+  if (saved_fpr != -1)
+    for (ii=saved_fpr; ii <= 31; ++ii) {
+      read_memory (addr, &registers [REGISTER_BYTE (ii+FP0_REGNUM)], 8);
+      addr += 8;
+  }
+
+  write_register (SP_REGNUM, prev_sp);
+  store_inferior_registers (-1);
+  flush_cached_frames ();
+  set_current_frame (create_new_frame (prev_sp, lr));
+}
+
+
+/* fixup the call sequence of a dummy function, with the real function address.
+   its argumets will be passed by gdb. */
+
+fix_call_dummy(dummyname, pc, fun, nargs, type)
+  char *dummyname;
+  int pc;
+  int fun;
+  int nargs;                                   /* not used */
+  int type;                                    /* not used */
+
+{
+#define        TOC_ADDR_OFFSET         20
+#define        TARGET_ADDR_OFFSET      28
+
+  int ii;
+  unsigned long target_addr;
+  unsigned long tocvalue;
+
+  target_addr = fun;
+  tocvalue = find_toc_address (target_addr);
+
+  ii  = *(int*)((char*)dummyname + TOC_ADDR_OFFSET);
+  ii = (ii & 0xffff0000) | (tocvalue >> 16);
+  *(int*)((char*)dummyname + TOC_ADDR_OFFSET) = ii;
+
+  ii  = *(int*)((char*)dummyname + TOC_ADDR_OFFSET+4);
+  ii = (ii & 0xffff0000) | (tocvalue & 0x0000ffff);
+  *(int*)((char*)dummyname + TOC_ADDR_OFFSET+4) = ii;
+
+  ii  = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET);
+  ii = (ii & 0xffff0000) | (target_addr >> 16);
+  *(int*)((char*)dummyname + TARGET_ADDR_OFFSET) = ii;
+
+  ii  = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4);
+  ii = (ii & 0xffff0000) | (target_addr & 0x0000ffff);
+  *(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4) = ii;
+}
+
+
+
+/* return information about a function frame.
+    - frameless is TRUE, if function does not save %pc value in its frame.
+    - offset is the number of bytes used in the frame to save registers.
+    - saved_gpr is the number of the first saved gpr.
+    - saved_fpr is the number of the first saved fpr.
+ */
+function_frame_info (pc, frameless, offset, saved_gpr, saved_fpr)
+  int pc;
+  int *frameless, *offset, *saved_gpr, *saved_fpr;
+{
+  unsigned int tmp;
+  register unsigned int op;
+
+  *offset = 0;
+  *saved_gpr = *saved_fpr = -1;
+
+  if (!inferior_pid)
+    return;
+
+  op  = read_memory_integer (pc, 4);
+  if (op == 0x7c0802a6) {              /* mflr r0 */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+    *frameless = 0;
+  }
+  else                         /* else, this is a frameless invocation */
+    *frameless = 1;
+
+
+  if ((op & 0xfc00003e) == 0x7c000026) { /* mfcr Rx */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
+    pc += 4;
+    op = read_memory_integer (pc, 4);
+  }
+
+  if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
+    pc += 4;                            /* store floating register double */
+    op = read_memory_integer (pc, 4);
+  }
+
+  if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
+    int tmp2;
+    *saved_gpr = (op >> 21) & 0x1f;
+    tmp2 = op & 0xffff;
+    if (tmp2 > 0x7fff)
+      tmp2 = 0xffff0000 | tmp2;
+
+    if (tmp2 < 0) {
+      tmp2 = tmp2 * -1;
+      *saved_fpr = (tmp2 - ((32 - *saved_gpr) * 4)) / 8;
+      if ( *saved_fpr > 0)
+        *saved_fpr = 32 - *saved_fpr;
+      else
+        *saved_fpr = -1;
+    }
+    *offset = tmp2;
+  }
+}
+
+
+/* Pass the arguments in either registers, or in the stack. In RS6000, the first
+   eight words of the argument list (that might be less than eight parameters if
+   some parameters occupy more than one word) are passed in r3..r11 registers.
+   float and double parameters are passed in fpr's, in addition to that. Rest of
+   the parameters if any are passed in user stack. There might be cases in which
+   half of the parameter is copied into registers, the other half is pushed into
+   stack.
+
+   If the function is returning a structure, then the return address is passed
+   in r3, then the first 7 words of the parametes can be passed in registers,
+   starting from r4. */
+
+CORE_ADDR
+push_arguments (nargs, args, sp, struct_return, struct_addr)
+  int nargs;
+  value *args;
+  CORE_ADDR sp;
+  int struct_return;
+  CORE_ADDR struct_addr;
+{
+  int ii, len;
+  int argno;                                   /* current argument number */
+  int argbytes;                                        /* current argument byte */
+  char tmp_buffer [50];
+  value arg;
+  int f_argno = 0;                             /* current floating point argno */
+
+  CORE_ADDR saved_sp, pc;
+
+  if ( dummy_frame_count <= 0)
+    printf ("FATAL ERROR -push_arguments()! frame not found!!\n");
+
+  /* The first eight words of ther arguments are passed in registers. Copy
+     them appropriately.
+
+     If the function is returning a `struct', then the first word (which 
+     will be passed in r3) is used for struct return address. In that
+     case we should advance one word and start from r4 register to copy 
+     parameters. */
+
+  ii =  struct_return ? 1 : 0;
+
+  for (argno=0, argbytes=0; argno < nargs && ii<8; ++ii) {
+
+    arg = value_arg_coerce (args[argno]);
+    len = TYPE_LENGTH (VALUE_TYPE (arg));
+
+    if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT) {
+
+      /* floating point arguments are passed in fpr's, as well as gpr's.
+         There are 13 fpr's reserved for passing parameters. At this point
+         there is no way we would run out of them. */
+
+      if (len > 8)
+        printf (
+"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+
+      bcopy (VALUE_CONTENTS (arg), 
+         &registers[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], len);
+      ++f_argno;
+    }
+
+    if (len > 4) {
+
+      /* Argument takes more than one register. */
+      while (argbytes < len) {
+
+       *(int*)&registers[REGISTER_BYTE(ii+3)] = 0;
+       bcopy ( ((char*)VALUE_CONTENTS (arg))+argbytes, 
+                       &registers[REGISTER_BYTE(ii+3)], 
+                       (len - argbytes) > 4 ? 4 : len - argbytes);
+       ++ii, argbytes += 4;
+
+       if (ii >= 8)
+         goto ran_out_of_registers_for_arguments;
+      }
+      argbytes = 0;
+      --ii;
+    }
+    else {        /* Argument can fit in one register. No problem. */
+      *(int*)&registers[REGISTER_BYTE(ii+3)] = 0;
+      bcopy (VALUE_CONTENTS (arg), &registers[REGISTER_BYTE(ii+3)], len);
+    }
+    ++argno;
+  }
+
+ran_out_of_registers_for_arguments:
+
+  /* location for 8 parameters are always reserved. */
+  sp -= 4 * 8;
+
+  /* another six words for back chain, TOC register, link register, etc. */
+  sp -= 24;
+
+  /* if there are more arguments, allocate space for them in 
+     the stack, then push them starting from the ninth one. */
+
+  if ((argno < nargs) || argbytes) {
+    int space = 0, jj;
+    value val;
+
+    if (argbytes) {
+      space += ((len - argbytes + 3) & -4);
+      jj = argno + 1;
+    }
+    else
+      jj = argno;
+
+    for (; jj < nargs; ++jj) {
+      val = value_arg_coerce (args[jj]);
+      space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
+    }
+
+    /* add location required for the rest of the parameters */
+    space = (space + 7) & -8;
+    sp -= space;
+
+    /* This is another instance we need to be concerned about securing our
+       stack space. If we write anything underneath %sp (r1), we might conflict
+       with the kernel who thinks he is free to use this area. So, update %sp
+       first before doing anything else. */
+
+    write_register (SP_REGNUM, sp);
+
+#if 0
+    pc = read_pc ();
+    flush_cached_frames ();
+    set_current_frame (create_new_frame (sp, pc));
+#endif
+
+    /* if the last argument copied into the registers didn't fit there 
+       completely, push the rest of it into stack. */
+
+    if (argbytes) {
+      write_memory (
+        sp+24+(ii*4), ((char*)VALUE_CONTENTS (arg))+argbytes, len - argbytes);
+      ++argno;
+      ii += ((len - argbytes + 3) & -4) / 4;
+    }
+
+    /* push the rest of the arguments into stack. */
+    for (; argno < nargs; ++argno) {
+
+      arg = value_arg_coerce (args[argno]);
+      len = TYPE_LENGTH (VALUE_TYPE (arg));
+
+
+      /* float types should be passed in fpr's, as well as in the stack. */
+      if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT && f_argno < 13) {
+
+        if (len > 8)
+          printf (
+"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+
+        bcopy (VALUE_CONTENTS (arg), 
+           &registers[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], len);
+        ++f_argno;
+      }
+
+      write_memory (sp+24+(ii*4), VALUE_CONTENTS (arg), len);
+      ii += ((len + 3) & -4) / 4;
+    }
+  }
+  else {
+
+    /* Secure stack areas first, before doing anything else. */
+    write_register (SP_REGNUM, sp);
+
+#if 0
+    pc = read_pc ();
+    flush_cached_frames ();
+    set_current_frame (create_new_frame (sp, pc));
+#endif
+  }
+
+  saved_sp = dummy_frame_addr [dummy_frame_count - 1];
+  read_memory (saved_sp, tmp_buffer, 24);
+  write_memory (sp, tmp_buffer, 24);
+
+    write_memory (sp, &saved_sp, 4);   /* set back chain properly */
+
+  store_inferior_registers (-1);
+  return sp;
+}
+
+/* a given return value in `regbuf' with a type `valtype', extract and copy its
+   value into `valbuf' */
+
+extract_return_value (valtype, regbuf, valbuf)
+  struct type *valtype;
+  char regbuf[REGISTER_BYTES];
+  char *valbuf;
+{
+
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT) {
+
+    double dd; float ff;
+    /* floats and doubles are returned in fpr1. fpr's have a size of 8 bytes.
+       We need to truncate the return value into float size (4 byte) if
+       necessary. */
+
+    if (TYPE_LENGTH (valtype) > 4)             /* this is a double */
+      bcopy (&regbuf[REGISTER_BYTE (FP0_REGNUM + 1)], valbuf, 
+                                               TYPE_LENGTH (valtype));
+    else {             /* float */
+      bcopy (&regbuf[REGISTER_BYTE (FP0_REGNUM + 1)], &dd, 8);
+      ff = (float)dd;
+      bcopy (&ff, valbuf, sizeof(float));
+    }
+  }
+  else
+    /* return value is copied starting from r3. */
+    bcopy (&regbuf[REGISTER_BYTE (3)], valbuf, TYPE_LENGTH (valtype));
+}
+
+
+/* keep keep structure return address in this variable. */
+
+CORE_ADDR rs6000_struct_return_address;
+
+
+/* Throw away this debugging code. FIXMEmgo. */
+print_frame(fram)
+int fram;
+{
+  int ii, val;
+  for (ii=0; ii<40; ++ii) {
+    if ((ii % 4) == 0)
+      printf ("\n");
+    val = read_memory_integer (fram + ii * 4, 4);
+    printf ("0x%08x\t", val);
+  }
+  printf ("\n");
+}
+
+
+
+/* Indirect function calls use a piece of trampoline code do co context switching,
+   i.e. to set the new TOC table. Skip such code if exists. */
+
+skip_trampoline_code (pc)
+int pc;
+{
+  register unsigned int ii, op;
+
+  static unsigned trampoline_code[] = {
+       0x800b0000,                     /*     l   r0,0x0(r11)  */
+       0x90410014,                     /*    st   r2,0x14(r1)  */
+       0x7c0903a6,                     /* mtctr   r0           */
+       0x804b0004,                     /*     l   r2,0x4(r11)  */
+       0x816b0008,                     /*     l  r11,0x8(r11)  */
+       0x4e800420,                     /*  bctr                */
+       0x4e800020,                     /*    br                */
+       0
+  };
+
+  for (ii=0; trampoline_code[ii]; ++ii) {
+    op  = read_memory_integer (pc + (ii*4), 4);
+    if (op != trampoline_code [ii])
+      return NULL;
+  }
+  ii = read_register (11);             /* r11 holds destination addr   */
+  pc = read_memory_integer (ii, 4);    /* (r11) value                  */
+  return pc;
+}
+
diff --git a/gdb/rs6000-xdep.c b/gdb/rs6000-xdep.c
new file mode 100644 (file)
index 0000000..7d0917b
--- /dev/null
@@ -0,0 +1,364 @@
+/* IBM RS/6000 host-dependent code for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1989, 1991 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+
+#include <a.out.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/core.h>
+#include <sys/ldr.h>
+
+extern int errno;
+extern int attach_flag;
+
+/* 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    */
+};
+
+
+/* Nonzero if we just simulated a single step break. */
+extern int one_stepped;
+
+\f
+fetch_inferior_registers ()
+{
+  int ii;
+  extern char registers[];
+
+  /* read 32 general purpose registers. */
+
+  for (ii=0; ii < 32; ++ii)
+    *(int*)&registers[REGISTER_BYTE (ii)] = 
+       ptrace (PT_READ_GPR, inferior_pid, ii, 0, 0);
+
+  /* read general purpose floating point registers. */
+
+  for (ii=0; ii < 32; ++ii)
+    ptrace (PT_READ_FPR, inferior_pid, 
+       (int*)&registers [REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
+
+  /* read special registers. */
+  for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii)
+    *(int*)&registers[REGISTER_BYTE (FIRST_SP_REGNUM+ii)] = 
+       ptrace (PT_READ_GPR, inferior_pid, special_regs[ii], 0, 0);
+}
+
+/* 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).  */
+
+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, ii,
+               *(int*)&registers[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, 
+                 (int*)&registers[REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
+        if ( errno ) {
+         perror ("ptrace write_fpr"); errno = 0;
+        }
+      }
+
+      /* write special registers. */
+      for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii) {
+        ptrace (PT_WRITE_GPR, inferior_pid, special_regs[ii],
+                *(int*)&registers[REGISTER_BYTE (FIRST_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, regno,
+               *(int*)&registers[REGISTER_BYTE (regno)], 0);
+  }
+
+  else if (regno <= FPLAST_REGNUM) {           /* a FPR */
+    ptrace (PT_WRITE_FPR, inferior_pid, 
+       (int*)&registers[REGISTER_BYTE (regno)], regno-FP0_REGNUM+FPR0, 0);
+  }
+
+  else if (regno <= LAST_SP_REGNUM) {          /* a special register */
+
+    ptrace (PT_WRITE_GPR, inferior_pid, special_regs [regno-FIRST_SP_REGNUM],
+               *(int*)&registers[REGISTER_BYTE (regno)], 0);
+  }
+
+  else
+    fprintf (stderr, "Gdb error: register no %d not implemented.\n", regno);
+
+  if ( errno ) {
+    perror ("ptrace write");  errno = 0;
+    return -1;
+  }
+  return 0;
+}
+
+void
+fetch_core_registers (core_reg_sect, core_reg_size, which)
+     char *core_reg_sect;
+     unsigned core_reg_size;
+     int which;
+{
+  /* fetch GPRs and special registers from the first register section
+     in core bfd. */
+  if (which == 0) {
+
+    /* copy GPRs first. */
+    bcopy (core_reg_sect, registers, 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);
+    bcopy (core_reg_sect, &registers [REGISTER_BYTE (FIRST_SP_REGNUM)],
+                       (LAST_SP_REGNUM - FIRST_SP_REGNUM + 1) * 4);
+  }
+
+  /* fetch floating point registers from register section 2 in core bfd. */
+  else if (which == 2)
+    bcopy (core_reg_sect, &registers [REGISTER_BYTE (FP0_REGNUM)], 32 * 8);
+
+  else
+    fprintf (stderr, "Gdb error: unknown parameter to fetch_core_registers().\n");
+}
+
+
+frameless_function_invocation (fi)
+struct frame_info *fi;
+{
+  int ret;
+  CORE_ADDR func_start, after_prologue;                                         
+
+#if 0
+  func_start = (LOAD_ADDR (get_pc_function_start (fi->pc)) +
+               FUNCTION_START_OFFSET);                                  
+#else
+  func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
+#endif
+  if (func_start)                                                        
+    {                                                                   
+      after_prologue = func_start;                                      
+      SKIP_PROLOGUE (after_prologue);                                   
+      ret  = (after_prologue == func_start);                    
+    }                                                                   
+  else                                                                  
+    /* If we can't find the start of the function, we don't really */    
+    /* know whether the function is frameless, but we should be           */    
+    /* able to get a reasonable (i.e. best we can do under the    */    
+    /* circumstances) backtrace by saying that it isn't.  */            
+       ret = 0;
+  return ret;
+
+}
+
+
+/* aixcoff_relocate_symtab -   hook for symbol table relocation.
+   also reads shared libraries.. */
+
+aixcoff_relocate_symtab (pid)
+unsigned int pid;
+{
+#define        MAX_LOAD_SEGS 64                /* maximum number of load segments */
+
+    extern int compare_misc_functions ();
+    struct ld_info *ldi;
+    int temp;
+
+    ldi = (void *) alloca(MAX_LOAD_SEGS * sizeof (*ldi));
+
+    /* According to my humble theory, aixcoff 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, ldi, MAX_LOAD_SEGS * sizeof(*ldi), ldi);
+    if (errno)
+      perror_with_name ("ptrace ldinfo");
+
+    vmap_ldinfo(ldi);
+
+   do {
+     add_text_to_loadinfo (ldi->ldinfo_textorg, ldi->ldinfo_dataorg);
+    } while (ldi->ldinfo_next
+            && (ldi = (void *) (ldi->ldinfo_next + (char *) ldi)));
+
+  /* Now that we've jumbled things around, re-sort them.  */
+  sort_misc_function_vector ();
+
+  /* relocate the exec and core sections as well. */
+  vmap_exec ();
+}
+
+
+/* Keep an array of load segment information and their TOC table addresses.
+   This info will be useful when calling a shared library function by hand. */
+   
+typedef struct {
+  unsigned long textorg, dataorg, toc_offset;
+} LoadInfo;
+
+#define        LOADINFOLEN     10
+
+static LoadInfo *loadInfo = NULL;
+static int     loadInfoLen = 0;
+static int     loadInfoTocIndex = 0;
+static int     loadInfoTextIndex = 0;
+
+
+xcoff_init_loadinfo ()
+{
+  loadInfoTocIndex = 0;
+  loadInfoTextIndex = 0;
+
+  if (loadInfoLen == 0) {
+    loadInfo = (void*) xmalloc (sizeof (LoadInfo) * LOADINFOLEN);
+    loadInfoLen = LOADINFOLEN;
+  }
+}
+
+
+free_loadinfo ()
+{
+  if (loadInfo)
+    free (loadInfo);
+  loadInfo = NULL;
+  loadInfoLen = 0;
+  loadInfoTocIndex = 0;
+  loadInfoTextIndex = 0;
+}
+
+
+xcoff_add_toc_to_loadinfo (unsigned long tocaddr)
+{
+  while (loadInfoTocIndex >= loadInfoLen) {
+    loadInfoLen += LOADINFOLEN;
+    loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
+  }
+  loadInfo [loadInfoTocIndex++].toc_offset = tocaddr;
+}
+
+
+add_text_to_loadinfo (unsigned long textaddr, unsigned long dataaddr)
+{
+  while (loadInfoTextIndex >= loadInfoLen) {
+    loadInfoLen += LOADINFOLEN;
+    loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
+  }
+  loadInfo [loadInfoTextIndex].textorg = textaddr;
+  loadInfo [loadInfoTextIndex].dataorg = dataaddr;
+  ++loadInfoTextIndex;
+}
+
+
+unsigned long
+find_toc_address (unsigned long pc)
+{
+  int ii, toc_entry;
+
+  for (ii=0; ii < loadInfoTextIndex; ++ii)
+    if (pc > loadInfo [ii].textorg)
+      toc_entry = ii;
+
+  return loadInfo [toc_entry].dataorg + loadInfo [toc_entry].toc_offset;
+}
+
+
+/* execute one dummy breakpoint instruction. This way we give kernel
+   a chance to do some housekeeping and update inferior's internal data,
+   including u_area. */
+
+exec_one_dummy_insn ()
+{
+#define        DUMMY_INSN_ADDR 0x10000200
+
+  unsigned long shadow;
+  unsigned int status, pid;
+
+  target_insert_breakpoint (DUMMY_INSN_ADDR, &shadow);
+
+  errno = 0;
+  ptrace (PT_CONTINUE, inferior_pid, DUMMY_INSN_ADDR, 0, 0);
+  if (errno)
+    perror ("pt_continue");
+
+  do {
+    pid = wait (&status);
+  } while (pid != inferior_pid);
+    
+  target_remove_breakpoint (DUMMY_INSN_ADDR, &shadow);
+}
+
diff --git a/gdb/tm-rs6000.h b/gdb/tm-rs6000.h
new file mode 100644 (file)
index 0000000..ce47df6
--- /dev/null
@@ -0,0 +1,461 @@
+/* Parameters for target execution on an RS6000, for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+   Contributed by IBM Corporation.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+extern int     symtab_relocated;
+
+/* text addresses in a core file does not necessarily match to symbol table,
+   if symbol table relocation wasn't done yet. */
+
+#define        CORE_NEEDS_RELOCATION(PC)       \
+  if (!symtab_relocated && !inferior_pid && (PC) > 0x10000000) \
+    (PC) -= (0x10000000 + text_adjustment (exec_bfd));
+
+/* Conversion between a register number in stab string to actual register num. */
+
+#define        STAB_REG_TO_REGNUM(value)       (value)
+
+/* return true if a given `pc' value is in `call dummy' function. */
+
+#define        PC_IN_CALL_DUMMY(STOP_PC, STOP_SP, STOP_FRAME_ADDR)     \
+       (STOP_SP < STOP_PC && STOP_PC < STACK_END_ADDR)
+
+/* For each symtab, we keep track of which BFD it came from.  */
+#define        EXTRA_SYMTAB_INFO       \
+       unsigned    nonreloc:1;         /* TRUE if non relocatable */
+
+#define        INIT_EXTRA_SYMTAB_INFO(symtab)  \
+       symtab->nonreloc = 0;           \
+
+extern unsigned int text_start, data_start;
+extern int inferior_pid;
+extern char *corefile;
+
+/* setpgrp() messes up controling terminal. The other version of it
+   requires libbsd.a. */
+#define        setpgrp(XX,YY)          setpgid (XX, YY)
+
+/* We are missing register descriptions in the system header files. Sigh! */
+
+struct regs {
+       int     gregs [32];     /* general purpose registers */
+       int     pc;             /* program conter       */
+       int     ps;             /* processor status, or machine state */
+};
+
+struct fp_status {
+       double  fpregs [32];                    /* floating GP registers */
+};
+
+/* Define the byte order of the machine.  */
+
+#define TARGET_BYTE_ORDER      BIG_ENDIAN
+
+/* Define this if the C compiler puts an underscore at the front
+   of external names before giving them to the linker.  */
+
+#undef NAMES_HAVE_UNDERSCORE
+
+/* Offset from address of function to start of its code.
+   Zero on most machines.  */
+
+#define FUNCTION_START_OFFSET 0
+
+/* Advance PC across any function entry prologue instructions
+   to reach some "real" code.  */
+
+#define SKIP_PROLOGUE(pc)      pc = skip_prologue (pc)
+
+/* If PC is in some function-call trampoline code, return the PC
+   where the function itself actually starts.  If not, return NULL.  */
+
+#define        SKIP_TRAMPOLINE_CODE(pc)        skip_trampoline_code (pc)
+
+/* When a child process is just starting, we sneak in and relocate
+   the symbol table (and other stuff) after the dynamic linker has
+   figured out where they go.  */
+
+#define        SOLIB_CREATE_INFERIOR_HOOK(PID) aixcoff_relocate_symtab (PID)
+
+/* When a target process or core-file has been attached, we sneak in
+   and figure out where the shared libraries have got to.  */
+
+#define        SOLIB_ADD(a, b, c)              aixcoff_relocate_symtab (inferior_pid)
+
+/* Immediately after a function call, return the saved pc.
+   Can't go through the frames for this because on some machines
+   the new frame is not set up until the new function executes
+   some instructions.  */
+
+extern char registers[];
+
+#define        SAVED_PC_AFTER_CALL(frame)      \
+       (*(int*)&registers[REGISTER_BYTE (LR_REGNUM)])
+
+/*#define SAVED_PC_AFTER_CALL(frame)   saved_pc_after_call(frame) */
+
+
+/* Address of end of stack space.  */
+
+#define STACK_END_ADDR 0x2ff80000
+
+/* Stack grows downward.  */
+
+#define INNER_THAN <
+
+#if 0
+/* No, we shouldn't use this. push_arguments() should leave stack in a
+   proper alignment! */
+/* Stack has strict alignment. */
+
+#define STACK_ALIGN(ADDR)      (((ADDR)+7)&-8)
+#endif
+
+/* This is how argumets pushed onto stack or passed in registers. */
+
+#define        PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
+  sp = push_arguments(nargs, args, sp, struct_return, struct_addr)
+
+/* Sequence of bytes for breakpoint instruction.  */
+
+#define BREAKPOINT {0x7d, 0x82, 0x10, 0x08}
+
+/* Amount PC must be decremented by after a breakpoint.
+   This is often the number of bytes in BREAKPOINT
+   but not always.  */
+
+#define DECR_PC_AFTER_BREAK 0
+
+/* Nonzero if instruction at PC is a return instruction.  */
+/* Allow any of the return instructions, including a trapv and a return
+   from interrupt.  */
+
+#define ABOUT_TO_RETURN(pc)  \
+   ((read_memory_integer (pc, 4) & 0xfe8007ff) == 0x4e800020)
+
+/* Return 1 if P points to an invalid floating point value.  */
+
+#define INVALID_FLOAT(p, len) 0   /* Just a first guess; not checked */
+
+/* Largest integer type */
+
+#define LONGEST long
+
+/* Name of the builtin type for the LONGEST type above. */
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+
+/* Say how long (ordinary) registers are.  */
+
+#define REGISTER_TYPE long
+
+/* Number of machine registers */
+
+#define NUM_REGS 71
+
+/* Initializer for an array of names of registers.
+   There should be NUM_REGS strings in this initializer.  */
+
+#define REGISTER_NAMES  \
+ {"r0", "sp", "toc", "r3", "r4", "r5", "r6", "r7",  \
+  "r8", "r9", "r10","r11","r12","r13","r14","r15", \
+  "r16","r17","r18","r19","r20","r21","r22","r23", \
+  "r24","r25","r26","r27","r28","r29","r30","r31", \
+  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",  \
+  "f8", "f9", "f10","f11","f12","f13","f14","f15", \
+  "f16","f17","f18","f19","f20","f21","f22","f23", \
+  "f24","f25","f26","f27","f28","f29","f30","f31", \
+  "pc", "ps", "cnd", "lr", "cnt", "xer", "mq" }
+
+/* Register numbers of various important registers.
+   Note that some of these values are "real" register numbers,
+   and correspond to the general registers of the machine,
+   and some are "phony" register numbers which are too large
+   to be actual register numbers as far as the user is concerned
+   but do serve to get the desired values when passed to read_register.  */
+
+#define FP_REGNUM 1            /* Contains address of executing stack frame */
+#define SP_REGNUM 1            /* Contains address of top of stack */
+#define        TOC_REGNUM 2            /* TOC register */
+#define FP0_REGNUM 32          /* Floating point register 0 */
+#define FPLAST_REGNUM 63       /* Last floating point register */  
+
+/* Special purpose registers... */
+/* P.S. keep these in the same order as in /usr/mstsave.h `mstsave' structure, for
+   easier processing */
+
+#define PC_REGNUM 64           /* Program counter (instruction address %iar) */
+#define PS_REGNUM 65           /* Processor (or machine) status (%msr) */
+#define        CR_REGNUM 66            /* Condition register */
+#define        LR_REGNUM 67            /* Link register */
+#define        CTR_REGNUM 68           /* Count register */
+#define        XER_REGNUM 69           /* Fixed point exception registers */
+#define        MQ_REGNUM 70            /* Multiply/quotient register */
+
+#define        FIRST_SP_REGNUM 64      /* first special register number */
+#define LAST_SP_REGNUM  70     /* last special register number */
+
+/* Total amount of space needed to store our copies of the machine's
+   register state, the array `registers'.
+
+       32 4-byte gpr's
+       32 8-byte fpr's
+       7  4-byte special purpose registers, 
+
+   total 416 bytes. Keep some extra space for now, in case to add more. */
+
+#define REGISTER_BYTES 420
+
+
+/* Index within `registers' of the first byte of the space for
+   register N.  */
+
+#define REGISTER_BYTE(N)  \
+ (                                                             \
+  ((N) > FPLAST_REGNUM) ? ((((N) - FPLAST_REGNUM -1) * 4) + 384)\
+  :((N) >= FP0_REGNUM) ? ((((N) - FP0_REGNUM) * 8) + 128)      \
+  :((N) * 4) )
+
+/* Number of bytes of storage in the actual machine representation
+   for register N. */
+/* Note that the unsigned cast here forces the result of the
+   subtractiion to very high positive values if N < FP0_REGNUM */
+
+#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 32 ? 8 : 4)
+
+/* Number of bytes of storage in the program's representation
+   for register N.  On the RS6000, all regs are 4 bytes
+   except the floating point regs which are 8-byte doubles.  */
+
+#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 32 ? 8 : 4)
+
+/* Largest value REGISTER_RAW_SIZE can have.  */
+
+#define MAX_REGISTER_RAW_SIZE 8
+
+/* Largest value REGISTER_VIRTUAL_SIZE can have.  */
+
+#define MAX_REGISTER_VIRTUAL_SIZE 8
+
+/* convert a dbx stab register number (from `r' declaration) to a gdb REGNUM */
+
+#define STAB_REG_TO_REGNUM(value)      (value)
+
+/* Nonzero if register N requires conversion
+   from raw format to virtual format.  */
+
+#define REGISTER_CONVERTIBLE(N) ((N) >= FP0_REGNUM && (N) <= FPLAST_REGNUM)
+
+/* Convert data from raw format for register REGNUM
+   to virtual format for register REGNUM.  */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO)    \
+   bcopy ((FROM), (TO), REGISTER_RAW_SIZE (REGNUM))
+
+/* Convert data from virtual format for register REGNUM
+   to raw format for register REGNUM.  */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO)        \
+   bcopy ((FROM), (TO), REGISTER_RAW_SIZE (REGNUM))
+
+/* Return the GDB type object for the "standard" data type
+   of data in register N.  */
+
+#define REGISTER_VIRTUAL_TYPE(N) \
+ (((unsigned)(N) - FP0_REGNUM) < 32 ? builtin_type_double : builtin_type_int)
+
+/* Store the address of the place in which to copy the structure the
+   subroutine will return.  This is called from call_function. */
+/* in RS6000, struct return addresses are passed as an extra parameter in r3.
+   In function return, callee is not responsible of returning this address back.
+   Since gdb needs to find it, we will store in a designated variable
+   `rs6000_struct_return_address'. */
+
+extern unsigned int rs6000_struct_return_address;
+
+#define STORE_STRUCT_RETURN(ADDR, SP)  \
+  { write_register (3, (ADDR));                \
+    rs6000_struct_return_address = (unsigned int)(ADDR); }
+
+/* Extract from an array REGBUF containing the (raw) register state
+   a function return value of type TYPE, and copy that, in virtual format,
+   into VALBUF.  */
+
+/* #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+  bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) */
+
+#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+  extract_return_value(TYPE,REGBUF,VALBUF)
+
+/* Write into appropriate registers a function return value
+   of type TYPE, given in virtual format.  */
+
+#define STORE_RETURN_VALUE(TYPE,VALBUF) \
+  printf ("FIXMEmgo! STORE_RETURN_VALUE not implemented yet!\n")
+
+/* Extract from an array REGBUF containing the (raw) register state
+   the address in which a function should return its structure value,
+   as a CORE_ADDR (or an expression that can be used as one).  */
+
+#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF)   rs6000_struct_return_address
+
+
+/* Do implement the attach and detach commands.  */
+
+#define ATTACH_DETACH  /* FIXMEmgo! Not implemented yet! */
+
+\f
+/* Describe the pointer in each stack frame to the previous stack frame
+   (its caller).  */
+
+/* FRAME_CHAIN takes a frame's nominal address
+   and produces the frame's chain-pointer.
+
+   FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
+   and produces the nominal address of the caller frame.
+
+   However, if FRAME_CHAIN_VALID returns zero,
+   it means the given frame is the outermost one and has no caller.
+   In that case, FRAME_CHAIN_COMBINE is not used.  */
+
+/* In the case of the RS6000, the frame's nominal address
+   is the address of a 4-byte word containing the calling frame's address.  */
+
+#define FRAME_CHAIN(thisframe)  \
+  (outside_startup_file ((thisframe)->pc) ?    \
+   read_memory_integer ((thisframe)->frame, 4) :\
+   0)
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+  (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe))))
+
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+
+/* Define other aspects of the stack frame.  */
+
+/* A macro that tells us whether the function invocation represented
+   by FI does not have a frame on the stack associated with it.  If it
+   does not, FRAMELESS is set to 1, else 0.  */
+
+#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
+       FRAMELESS = frameless_function_invocation (FI)
+
+/* Frameless function invocation in IBM RS/6000 is half-done. It perfectly
+   sets up a new frame, e.g. a new frame (in fact stack) pointer, etc, but it 
+   doesn't save the %pc. In the following, even though it is considered a 
+   frameless invocation, we still need to walk one frame up. */
+
+#define        INIT_EXTRA_FRAME_INFO(fromleaf, fi)     \
+       if (fromleaf) {                 \
+         int tmp = 0;                  \
+         read_memory ((fi)->frame, &tmp, sizeof (int));        \
+         (fi)->frame = tmp;            \
+       }
+
+#define FRAME_SAVED_PC(FRAME)          \
+       read_memory_integer (read_memory_integer ((FRAME)->frame, 4)+8, 4)
+
+#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+
+/* Set VAL to the number of args passed to frame described by FI.
+   Can set VAL to -1, meaning no way to tell.  */
+
+/* We can't tell how many args there are
+   now that the C compiler delays popping them.  */
+
+#define FRAME_NUM_ARGS(val,fi) (val = -1)
+
+/* Return number of bytes at start of arglist that are not really args.  */
+
+#define FRAME_ARGS_SKIP 8      /* Not sure on this. FIXMEmgo */
+
+/* Put here the code to store, into a struct frame_saved_regs,
+   the addresses of the saved registers of frame described by FRAME_INFO.
+   This includes special registers such as pc and fp saved in special
+   ways in the stack frame.  sp is even more special:
+   the address we return for it IS the sp for the next frame.  */
+
+#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs)            \
+       printf ("FIXMEmgo! FRAME_FIND_SAVED_REGS() not implemented!\n")
+\f
+/* Things needed for making the inferior call functions.  */
+
+/* Push an empty stack frame, to record the current PC, etc.  */
+/* Change these names into rs6k_{push, pop}_frame(). FIXMEmgo. */
+
+#define PUSH_DUMMY_FRAME       push_dummy_frame ()
+
+/* Discard from the stack the innermost frame, 
+   restoring all saved registers.  */
+
+#define POP_FRAME      pop_frame ()
+
+/* This sequence of words is the instructions:
+
+       mflr    r0              // 0x7c0802a6
+                               // save fpr's
+       stfd    r?, num(r1)     // 0xd8010000 there should be 32 of this??
+                               // save gpr's
+       stm     r0, num(r1)     // 0xbc010000
+       stu     r1, num(r1)     // 0x94210000
+
+       // the function we want to branch might be in a different load 
+       // segment. reset the toc register. Note that the actual toc address
+       // will be fix by fix_call_dummy () along with function address.
+
+       st      r2, 0x14(r1)    // 0x90410014 save toc register
+       liu     r2, 0x1234      // 0x3c401234 reset a new toc value 0x12345678
+       oril    r2, r2,0x5678   // 0x60425678   
+
+                               // load absolute address 0x12345678 to r0
+       liu     r0, 0x1234      // 0x3c001234
+       oril    r0, r0,0x5678   // 0x60005678
+       mtctr   r0              // 0x7c0903a6 ctr <- r0
+       bctrl                   // 0x4e800421 jump subroutine 0x12345678 (%ctr)
+       cror    0xf, 0xf, 0xf   // 0x4def7b82
+       brpt                    // 0x7d821008, breakpoint
+       cror    0xf, 0xf, 0xf   // 0x4def7b82 (for 8 byte alignment)
+
+
+  We actually start executing by saving the toc register first, since the pushing 
+  of the registers is done by PUSH_DUMMY_FRAME.  If this were real code,
+  the arguments for the function called by the `bctrl' would be pushed
+  between the `stu' and the `bctrl', and we could allow it to execute through.
+  But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
+  and we cannot allow to push the registers again.
+*/
+       
+#define CALL_DUMMY {0x7c0802a6, 0xd8010000, 0xbc010000, 0x94210000, \
+                   0x90410014, 0x3c401234, 0x60425678,             \
+                   0x3c001234, 0x60005678, 0x7c0903a6, 0x4e800421, \
+                   0x4def7b82, 0x7d821008, 0x4def7b82 }
+
+
+/* keep this as multiple of 8 (%sp requires 8 byte alignment) */
+#define CALL_DUMMY_LENGTH 56
+
+#define CALL_DUMMY_START_OFFSET 16
+
+/* Insert the specified number of args and function address
+   into a call sequence of the above form stored at DUMMYNAME.  */
+
+#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, using_gcc) \
+       fix_call_dummy(dummyname, pc, fun, nargs, type)
diff --git a/gdb/xcoffexec.c b/gdb/xcoffexec.c
new file mode 100644 (file)
index 0000000..f1bd3d8
--- /dev/null
@@ -0,0 +1,932 @@
+/* Execute AIXcoff files, for GDB.
+   Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
+   Derived from exec.c.  Modified by IBM Corporation.
+   Donated by IBM Corporation and Cygnus Support.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* xcoff-exec -        deal with executing XCOFF files.  */
+  
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/ldr.h>
+
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "symfile.h"
+
+#include "libbfd.h"            /* BFD internals (sigh!)  FIXME */
+
+struct section_table *exec_sections, *exec_sections_end;
+
+#define eq(s0, s1)     !strcmp(s0, s1)
+
+/* Whether to open exec and core files read-only or read-write.  */
+
+int write_files = 0;
+
+bfd *exec_bfd;                 /* needed by core.c     */
+
+extern char *getenv();
+extern void child_create_inferior (), child_attach ();
+extern void add_syms_addr_command ();
+extern void symbol_file_command ();
+static void exec_files_info();
+
+/*
+ * the vmap struct is used to describe the virtual address space of
+ * the target we are manipulating.  The first entry is always the "exec"
+ * file.  Subsequent entries correspond to other objects that are
+ * mapped into the address space of a process created from the "exec" file.
+ * These are either in response to exec()ing the file, in which case all
+ * shared libraries are loaded, or a "load" system call, followed by the
+ * user's issuance of a "load" command.
+ */
+struct vmap {
+       struct vmap *nxt;       /* ^ to next in chain                   */
+       bfd *bfd;               /* BFD for mappable object library      */
+       char *name;             /* ^ to object file name                */
+       char *member;           /* ^ to member name                     */
+       CORE_ADDR tstart;       /* virtual addr where member is mapped  */
+       CORE_ADDR tend;         /* virtual upper bound of member        */
+       CORE_ADDR tadj;         /* heuristically derived adjustment     */
+       CORE_ADDR dstart;       /* virtual address of data start        */
+       CORE_ADDR dend;         /* vitrual address of data end          */
+};
+
+
+struct vmap_and_bfd {
+  bfd *pbfd;
+  struct vmap *pvmap;
+};
+
+static struct vmap *vmap;      /* current vmap                         */
+
+extern struct target_ops exec_ops;
+
+
+/* exec_close -        done with exec file, clean up all resources. */
+
+void
+exec_close(quitting) {
+       register struct vmap *vp, *nxt;
+
+       for (nxt = vmap; vp = nxt; ) {
+               nxt = vp->nxt;
+               bfd_close(vp->bfd);
+               free_named_symtabs(vp->name, vp->member);       /* XXX  */
+               free(vp);
+       }
+
+       vmap = 0;
+       exec_bfd = 0;
+}
+
+/*
+ * exec_file_command - handle the "exec" command, &c.
+ */
+void
+exec_file_command(filename, from_tty)
+char *filename;
+{
+  bfd *bfd;
+
+  target_preopen(from_tty);
+  unpush_target(&exec_ops);
+
+  /* Now open and digest the file the user requested, if any. */
+
+  if (filename) {
+       char *scratch_pathname;
+       int scratch_chan;
+      
+       filename = tilde_expand(filename);
+       make_cleanup(free, filename);
+      
+       scratch_chan = openp(getenv("PATH"), 1, filename, O_RDONLY, 0
+                            , &scratch_pathname);
+       if (scratch_chan < 0)
+         perror_with_name(filename);
+
+       bfd = bfd_fdopenr(scratch_pathname, NULL, scratch_chan);
+       if (!bfd)
+         error("Could not open `%s' as an executable file: %s"
+                     , scratch_pathname, bfd_errmsg(bfd_error));
+
+       /* make sure we have an object file */
+
+       if (!bfd_check_format(bfd, bfd_object))
+               error("\"%s\": not in executable format: %s."
+                     , scratch_pathname, bfd_errmsg(bfd_error));
+
+
+       /* setup initial vmap */
+
+       map_vmap (bfd, 0);
+       if (!vmap)
+               error("Can't find the file sections in `%s': %s"
+                     , bfd->filename, bfd_errmsg(bfd_error));
+
+       exec_bfd = bfd;
+
+       if (build_section_table (exec_bfd, &exec_sections, &exec_sections_end))
+         error ("Can't find the file sections in `%s': %s", 
+               exec_bfd->filename, bfd_errmsg (bfd_error));
+
+       /* make sure core, if present, matches */
+       validate_files();
+
+       push_target(&exec_ops);
+
+       /* Tell display code(if any) about the changed file name. */
+
+       if (exec_file_display_hook)
+               (*exec_file_display_hook)(filename);
+  } 
+  else {
+       exec_close(0);  /* just in case */
+       if (from_tty)
+         printf("No exec file now.\n");
+  }
+}
+
+/* Set both the exec file and the symbol file, in one command.  What a
+ * novelty.  Why did GDB go through four major releases before this
+ * command was added?
+ */
+void
+file_command(arg, from_tty)
+char *arg; {
+
+       exec_file_command(arg, from_tty);
+       symbol_file_command(arg, from_tty);
+}
+
+/* Locate all mappable sections of a BFD file. 
+   table_pp_char is a char * to get it through bfd_map_over_sections;
+   we cast it back to its proper type.  */
+
+void
+add_to_section_table (abfd, asect, table_pp_char)
+     bfd *abfd;
+     sec_ptr asect;
+     char *table_pp_char;
+{
+  struct section_table **table_pp = (struct section_table **)table_pp_char;
+  flagword aflag;
+
+  aflag = bfd_get_section_flags (abfd, asect);
+  /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
+  if (!(aflag & SEC_LOAD))
+    return;
+  (*table_pp)->sec_ptr = asect;
+  (*table_pp)->addr = bfd_section_vma (abfd, asect);
+  (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect);
+  (*table_pp)++;
+}
+
+int
+build_section_table (some_bfd, start, end)
+     bfd *some_bfd;
+     struct section_table **start, **end;
+{
+  unsigned count;
+
+  count = bfd_count_sections (some_bfd);
+  if (count == 0)
+    abort();   /* return 1? */
+  if (*start)
+    free (*start);
+  *start = (struct section_table *) xmalloc (count * sizeof (**start));
+  *end = *start;
+  bfd_map_over_sections (some_bfd, add_to_section_table, (char *)end);
+  if (*end > *start + count)
+    abort();
+  /* We could realloc the table, but it probably loses for most files.  */
+  return 0;
+}
+
+/*
+ * lookup_symtab_bfd - find if we currently have any symbol tables from bfd
+ */
+struct objfile *
+lookup_objfile_bfd(bfd *bfd) {
+       register struct objfile *s;
+
+       for (s = object_files; s; s = s->next)
+               if (s->obfd == bfd)
+                       return s;
+       return 0;
+}
+
+
+void
+sex_to_vmap(bfd *bf, sec_ptr sex, struct vmap_and_bfd *vmap_bfd) 
+{
+  register struct vmap *vp, **vpp;
+  register struct symtab *syms;
+  bfd *arch = vmap_bfd->pbfd;
+  vp = vmap_bfd->pvmap;
+
+  if ((bfd_get_section_flags(bf, sex) & SEC_LOAD) == 0)
+    return;
+
+  if (!strcmp(bfd_section_name(bf, sex), ".text")) {
+    vp->tstart = 0;
+    vp->tend   = vp->tstart + bfd_section_size(bf, sex);
+
+    /* This is quite a tacky way to recognize the `exec' load segment (rather
+       than shared libraries. You should use `arch' instead. FIXMEmgo */
+    if (!vmap)
+      vp->tadj = sex->filepos - bfd_section_vma(bf, sex);
+    else
+      vp->tadj = 0;
+  }
+
+  else if (!strcmp(bfd_section_name(bf, sex), ".data")) {
+    vp->dstart = 0;
+    vp->dend   = vp->dstart + bfd_section_size(bf, sex);
+  }
+
+  else if (!strcmp(bfd_section_name(bf, sex), ".bss")) /* FIXMEmgo */
+    printf ("bss section in exec! Don't know what the heck to do!\n");
+}
+
+/* Make a vmap for the BFD "bf", which might be a member of the archive
+   BFD "arch".  If we have not yet read in symbols for this file, do so.  */
+
+map_vmap (bfd *bf, bfd *arch)
+{
+  struct vmap_and_bfd vmap_bfd;
+  struct vmap *vp, **vpp;
+  struct objfile *obj;
+  char *name;
+
+  vp = (void*) xmalloc (sizeof (*vp));
+  vp->nxt = 0;
+  vp->bfd = bf;
+  vp->name = bfd_get_filename(arch ? arch : bf);
+  vp->member = arch ? bfd_get_filename(bf) : "";
+  
+  vmap_bfd.pbfd = arch;
+  vmap_bfd.pvmap = vp;
+  bfd_map_over_sections (bf, sex_to_vmap, &vmap_bfd);
+
+  obj = lookup_objfile_bfd (bf);
+  if (exec_bfd && !obj) {
+    name = savestring (bfd_get_filename (bf), strlen (bfd_get_filename (bf)));
+    obj = allocate_objfile (bf, name);
+    syms_from_objfile (obj, 0, 0);
+  }
+
+  /* find the end of the list, and append. */
+  for (vpp = &vmap; *vpp; vpp = &(*vpp)->nxt)
+  ;
+  *vpp = vp;
+}
+
+
+/* true, if symbol table and misc_function_vector is relocated. */
+
+int symtab_relocated = 0;
+
+
+/*  vmap_symtab -      handle symbol translation on vmapping */
+
+vmap_symtab(vp, old_start, vip)
+register struct vmap *vp;
+CORE_ADDR old_start;
+struct stat *vip; 
+{
+       register struct symtab *s;
+
+       /*
+        * for each symbol table generated from the vp->bfd
+        */
+       for (s = symtab_list; s; s = s->next) {
+
+         /* skip over if this is not relocatable and doesn't have a line table */
+         if (s->nonreloc && !LINETABLE (s))
+           continue;
+
+               /* matching the symbol table's BFD and the *vp's BFD is hairy.
+                  exec_file creates a seperate BFD for possibly the
+                  same file as symbol_file.FIXME ALL THIS MUST BE RECTIFIED. */
+
+               if (s->objfile->obfd == vp->bfd) {
+                       /* if they match, we luck out. */
+                       ;
+               } else if (vp->member[0]) {
+                       /* no match, and member present, not this one. */
+                       continue;
+               } else {
+                       struct stat si;
+                       FILE *io;
+
+                       /*
+                        * no match, and no member. need to be sure.
+                        */
+                       io = bfd_cache_lookup(s->objfile->obfd);
+                       if (!io)
+                               fatal("cannot find BFD's iostream for sym");
+                       /*
+                        * see if we are referring to the same file
+                        */
+                       if (fstat(fileno(io), &si) < 0)
+                               fatal("cannot fstat BFD for sym");
+
+                       if (si.st_dev != vip->st_dev
+                           || si.st_ino != vip->st_ino)
+                               continue;
+               }
+
+               if (vp->tstart != old_start)
+                 vmap_symtab_1(s, vp, old_start);
+       }
+
+       if (vp->tstart != old_start)
+         fixup_misc_vector (vp->tstart - old_start);
+
+       symtab_relocated = 1;
+}
+
+
+fixup_misc_vector (int disp)
+{
+  int ii;
+  for (ii=0; ii < misc_function_count; ++ii)
+    if (misc_function_vector[ii].address < 0x10000000)
+      misc_function_vector[ii].address += disp;
+}
+
+
+vmap_symtab_1(s, vp, old_start)
+register struct symtab *s;
+register struct vmap *vp;
+CORE_ADDR old_start; 
+{
+    register int i, j;
+    int len, blen;
+    register struct linetable *l;
+    struct blockvector *bv;
+    register struct block *b;
+    int depth;
+    register ulong reloc, dreloc;
+    
+    if ((reloc = vp->tstart - old_start) == 0)
+       return;
+
+    dreloc = vp->dstart;                       /* data relocation */
+
+    /*
+     * The line table must be relocated.  This is only present for
+     * b.text sections, so only vp->text type maps need be considered.
+     */
+    l = LINETABLE (s);
+    len = l->nitems;
+    for (i = 0; i < len; i++)
+       l->item[i].pc += reloc;
+
+    /* if this symbol table is not relocatable, only line table should
+       be relocated and the rest ignored. */
+    if (s->nonreloc)
+      return;
+    
+    bv  = BLOCKVECTOR(s);
+    len = BLOCKVECTOR_NBLOCKS(bv);
+    
+    for (i = 0; i < len; i++) {
+       b = BLOCKVECTOR_BLOCK(bv, i);
+       
+       BLOCK_START(b) += reloc;
+       BLOCK_END(b)   += reloc;
+       
+       blen = BLOCK_NSYMS(b);
+       for (j = 0; j < blen; j++) {
+           register struct symbol *sym;
+           
+           sym = BLOCK_SYM(b, j);
+           switch (SYMBOL_NAMESPACE(sym)) {
+             case STRUCT_NAMESPACE:
+             case UNDEF_NAMESPACE:
+               continue;
+               
+             case LABEL_NAMESPACE:
+             case VAR_NAMESPACE:
+               break;
+           }
+           
+           switch (SYMBOL_CLASS(sym)) {
+             case LOC_CONST:
+             case LOC_CONST_BYTES:
+             case LOC_LOCAL:
+             case LOC_REGISTER:
+             case LOC_ARG:
+             case LOC_LOCAL_ARG:
+             case LOC_REF_ARG:
+             case LOC_REGPARM:
+             case LOC_TYPEDEF:
+               continue;
+               
+#ifdef FIXME
+             case LOC_EXTERNAL:
+#endif
+             case LOC_LABEL:
+               SYMBOL_VALUE_ADDRESS(sym) += reloc;
+               break;
+
+             case LOC_STATIC:
+               SYMBOL_VALUE_ADDRESS(sym) += dreloc;
+               break;
+
+             case LOC_BLOCK:
+               break;
+               
+             default:
+               fatal("botched symbol class %x"
+                     , SYMBOL_CLASS(sym));
+               break;
+           }
+       }
+    }
+}
+
+/*
+ * add_vmap -  add a new vmap entry based on ldinfo() information
+ */
+add_vmap(ldi)
+register struct ld_info *ldi; {
+       bfd *bfd, *last;
+       register char *mem;
+
+       mem = ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;
+       bfd = bfd_fdopenr(ldi->ldinfo_filename, NULL, ldi->ldinfo_fd);
+       if (!bfd)
+               error("Could not open `%s' as an executable file: %s"
+                     , ldi->ldinfo_filename, bfd_errmsg(bfd_error));
+
+
+       /* make sure we have an object file */
+
+       if (bfd_check_format(bfd, bfd_object))
+               map_vmap (bfd, 0);
+
+       else if (bfd_check_format(bfd, bfd_archive)) {
+               last = 0;
+               /*
+                * FIXME??? am I tossing BFDs?  bfd?
+                */
+               while (last = bfd_openr_next_archived_file(bfd, last))
+                       if (eq(mem, last->filename))
+                               break;
+
+               if (!last) {
+                       bfd_close(bfd);
+/* FIXME -- should be error */
+                       warning("\"%s\": member \"%s\" missing.",
+                             bfd->filename, mem);
+                       return;
+               }
+
+               if (!bfd_check_format(last, bfd_object)) {
+                       bfd_close(last);        /* XXX???       */
+                       goto obj_err;
+               }
+
+               map_vmap (last, bfd);
+       }
+       else {
+           obj_err:
+               bfd_close(bfd);
+/* FIXME -- should be error */
+               warning("\"%s\": not in executable format: %s."
+                     , ldi->ldinfo_filename, bfd_errmsg(bfd_error));
+               return;
+       }
+}
+
+
+/* As well as symbol tables, exec_sections need relocation. Otherwise after
+   the inferior process terminates, symbol table is relocated but there is
+   no inferior process. Thus, we have to use `exec' bfd, rather than the inferior
+   process's memory space, when lookipng at symbols.
+   `exec_sections' need to be relocated only once though, as long as the exec
+   file was not changed.
+*/
+vmap_exec ()
+{
+  static bfd *execbfd;
+  if (execbfd == exec_bfd)
+    return;
+
+  execbfd = exec_bfd;
+
+  if (!vmap || !exec_sections) {
+    printf ("WARNING: vmap not found in vmap_exec()!\n");
+    return;
+  }
+  /* First exec section is `.text', second is `.data'. If this is changed,
+     then this routine will choke. Better you should check section names,
+     FIXMEmgo. */
+  exec_sections [0].addr += vmap->tstart;
+  exec_sections [0].endaddr += vmap->tstart;
+  exec_sections [1].addr += vmap->dstart;
+  exec_sections [1].endaddr += vmap->dstart;
+}
+
+
+int
+text_adjustment (abfd)
+bfd *abfd;
+{
+  static bfd *execbfd;
+  static int adjustment;
+  sec_ptr  sect;
+
+  if (exec_bfd == execbfd)
+    return adjustment;
+
+  sect = bfd_get_section_by_name (abfd, ".text");
+  if (sect)
+    adjustment = sect->filepos - sect->vma;
+  else
+    adjustment = 0x200;                                /* just a wild assumption */
+
+  return adjustment;
+}
+
+
+/*
+ * vmap_ldinfo -       update VMAP info with ldinfo() information
+ *
+ * Input:
+ *     ldi     -       ^ to ldinfo() results.
+ */
+vmap_ldinfo(ldi)
+register struct ld_info *ldi;
+{
+  struct stat ii, vi;
+  register struct vmap *vp;
+  register got_one, retried;
+  CORE_ADDR ostart;
+
+  /*
+   * 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)
+               fatal("cannot fstat(%d) on %s"
+                     , ldi->ldinfo_fd
+                     , name);
+retry:
+       for (got_one = 0, vp = vmap; vp; vp = vp->nxt) {
+               FILE *io;
+
+               /* The filenames are not always sufficient to match on. */
+               if ((name[0] == "/"
+                   && !eq(name, vp->name))
+                   || (memb[0] && !eq(memb, vp->member)))
+                       continue;
+
+               /* totally opaque! */
+               io = bfd_cache_lookup(vp->bfd);
+               if (!io)
+                       fatal("cannot find BFD's iostream for %s"
+                             , vp->name);
+
+               /* see if we are referring to the same file */
+               if (fstat(fileno(io), &vi) < 0)
+                       fatal("cannot fstat BFD for %s", vp->name);
+
+               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! */
+               ostart = vp->tstart;
+
+               vp->tstart = ldi->ldinfo_textorg;
+               vp->tend   = vp->tstart + ldi->ldinfo_textsize;
+               vp->dstart = ldi->ldinfo_dataorg;
+               vp->dend   = vp->dstart + ldi->ldinfo_datasize;
+
+               if (vp->tadj) {
+                 vp->tstart += vp->tadj;
+                 vp->tend   += vp->tadj;
+               }
+
+               /* relocate symbol table(s). */
+               vmap_symtab(vp, ostart, &vi);
+
+               /* 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)));
+
+  breakpoint_re_set();
+}
+
+/*
+ * vmap_inferior -     print VMAP info for inferior
+ */
+vmap_inferior() {
+
+       if (inferior_pid == 0)
+               return 0;               /* normal processing    */
+
+       exec_files_info();
+
+       return 1;
+}
+
+/* Read or write the exec file.
+
+   Args are address within exec file, address within gdb address-space,
+   length, and a flag indicating whether to read or write.
+
+   Result is a length:
+
+       0:    We cannot handle this address and length.
+       > 0:  We have handled N bytes starting at this address.
+             (If N == length, we did it all.)  We might be able
+             to handle more bytes beyond this length, but no
+             promises.
+       < 0:  We cannot handle this address, but if somebody
+             else handles (-N) bytes, we can start from there.
+
+    The same routine is used to handle both core and exec files;
+    we just tail-call it with more arguments to select between them.  */
+
+int
+xfer_memory (memaddr, myaddr, len, write, abfd, sections, sections_end)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+     bfd *abfd;
+     struct section_table *sections, *sections_end;
+{
+  boolean res;
+  struct section_table *p;
+  CORE_ADDR nextsectaddr, memend;
+  boolean (*xfer_fn) ();
+
+  if (len <= 0)
+    abort();
+
+  memend = memaddr + len;
+  xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents;
+  nextsectaddr = memend;
+
+  for (p = sections; p < sections_end; p++)
+    {
+      if (p->addr <= memaddr)
+       if (p->endaddr >= memend)
+         {
+           /* Entire transfer is within this section.  */
+           res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
+           return (res != false)? len: 0;
+         }
+       else if (p->endaddr <= memaddr)
+         {
+           /* This section ends before the transfer starts.  */
+           continue;
+         }
+       else 
+         {
+           /* This section overlaps the transfer.  Just do half.  */
+           len = p->endaddr - memaddr;
+           res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
+           return (res != false)? len: 0;
+         }
+      else if (p->addr < nextsectaddr)
+       nextsectaddr = p->addr;
+    }
+
+  if (nextsectaddr >= memend)
+    return 0;                          /* We can't help */
+  else
+    return - (nextsectaddr - memaddr); /* Next boundary where we can help */
+}
+
+/* The function called by target_xfer_memory via our target_ops */
+
+int
+exec_xfer_memory (memaddr, myaddr, len, write)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+{
+  return xfer_memory (memaddr, myaddr, len, write,
+                     exec_bfd, exec_sections, exec_sections_end);
+}
+
+/*
+ * exec_files_info -   "info files" command processor
+ */
+static void
+exec_files_info() {
+       register struct vmap *vp = vmap;
+
+       if (!vp)
+               return;
+
+       printf("\tMapping info for file `%s'.\n", vp->name);
+       printf("\t  %8.8s   %8.8s %8.8s %s\n"
+              , "start", "end", "section", "file(member)");
+
+       for (; vp; vp = vp->nxt)
+               printf("\t0x%8.8x 0x%8.8x %s%s%s%s\n"
+                      , vp->tstart
+                      , vp->tend
+                      , vp->name
+                      , *vp->member ? "(" : ""
+                      ,  vp->member
+                      , *vp->member ? ")" : "");
+}
+
+#ifdef DAMON
+  Damon's implementation of set_section_command! It is based on the sex member
+  (which is a section pointer from vmap) of vmap.
+  We will not have multiple vmap entries (one for each section), rather transmit
+  text and data base offsets and fix them at the same time. Elimination of sex
+  entry in vmap make this function obsolute, use the one from exec.c. 
+  Need further testing!!       FIXMEmgo.
+
+static void
+set_section_command(args, from_tty)
+char *args; 
+{
+       register struct vmap *vp = vmap;
+       char *secname;
+       unsigned seclen;
+       unsigned long secaddr;
+       char secprint[100];
+       long offset;
+
+       if (args == 0)
+               error("Must specify section name and its virtual address");
+
+       /* Parse out section name */
+       for (secname = args; !isspace(*args); args++)
+               ;
+       seclen = args - secname;
+
+       /* Parse out new virtual address */
+       secaddr = parse_and_eval_address(args);
+
+       for (vp = vmap; vp; vp = vp->nxt) {
+               if (!strncmp(secname
+                            , bfd_section_name(vp->bfd, vp->sex), seclen)
+                   && bfd_section_name(vp->bfd, vp->sex)[seclen] == '\0') {
+                       offset = secaddr - vp->tstart;
+                       vp->tstart += offset;
+                       vp->tend   += offset;
+                       exec_files_info();
+                       return;
+               }
+       } 
+
+       if (seclen >= sizeof(secprint))
+               seclen = sizeof(secprint) - 1;
+       strncpy(secprint, secname, seclen);
+       secprint[seclen] = '\0';
+       error("Section %s not found", secprint);
+}
+#else
+static void
+set_section_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  struct section_table *p;
+  char *secname;
+  unsigned seclen;
+  unsigned long secaddr;
+  char secprint[100];
+  long offset;
+
+  if (args == 0)
+    error ("Must specify section name and its virtual address");
+
+  /* Parse out section name */
+  for (secname = args; !isspace(*args); args++) ;
+  seclen = args - secname;
+
+  /* Parse out new virtual address */
+  secaddr = parse_and_eval_address (args);
+
+  for (p = exec_sections; p < exec_sections_end; p++) {
+    if (!strncmp (secname, bfd_section_name (exec_bfd, p->sec_ptr), seclen)
+       && bfd_section_name (exec_bfd, p->sec_ptr)[seclen] == '\0') {
+      offset = secaddr - p->addr;
+      p->addr += offset;
+      p->endaddr += offset;
+      exec_files_info();
+      return;
+    }
+  } 
+  if (seclen >= sizeof (secprint))
+    seclen = sizeof (secprint) - 1;
+  strncpy (secprint, secname, seclen);
+  secprint[seclen] = '\0';
+  error ("Section %s not found", secprint);
+}
+
+#endif /* !DAMON */
+
+struct target_ops exec_ops = {
+       "exec", "Local exec file",
+       "Use an executable file as a target.\n\
+Specify the filename of the executable file.",
+       exec_file_command, exec_close, /* open, close */
+       child_attach, 0, 0, 0, /* attach, detach, resume, wait, */
+       0, 0, /* fetch_registers, store_registers, */
+       0, 0, 0, /* prepare_to_store, conv_to, conv_from, */
+       exec_xfer_memory, exec_files_info,
+       0, 0, /* insert_breakpoint, remove_breakpoint, */
+       0, 0, 0, 0, 0, /* terminal stuff */
+       0, 0, /* kill, load */
+       0, 0, /* call fn, lookup sym */
+       child_create_inferior,
+       0, /* mourn_inferior */
+       file_stratum, 0, /* next */
+       0, 1, 0, 0, 0,  /* all mem, mem, stack, regs, exec */
+       0, 0,                   /* section pointers */
+       OPS_MAGIC,              /* Always the last thing */
+};
+
+
+void
+_initialize_exec()
+{
+
+  add_com("file", class_files, file_command,
+          "Use FILE as program to be debugged.\n\
+It is read for its symbols, for getting the contents of pure memory,\n\
+and it is the program executed when you use the `run' command.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+($PATH) is searched for a command of that name.\n\
+No arg means to have no executable file and no symbols.");
+
+  add_com("exec-file", class_files, exec_file_command,
+          "Use FILE as program for getting contents of pure memory.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+is searched for a command of that name.\n\
+No arg means have no executable file.");
+
+  add_com("section", class_files, set_section_command,
+   "Change the base address of section SECTION of the exec file to ADDR.\n\
+This can be used if the exec file does not contain section addresses,\n\
+(such as in the a.out format), or when the addresses specified in the\n\
+file itself are wrong.  Each section must be changed separately.  The\n\
+``info files'' command lists all the sections and their addresses.");
+
+  add_target(&exec_ops);
+}
diff --git a/gdb/xm-rs6000.h b/gdb/xm-rs6000.h
new file mode 100644 (file)
index 0000000..2c0c101
--- /dev/null
@@ -0,0 +1,67 @@
+/* Parameters for hosting on an RS6000, for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+   Contributed by IBM Corporation.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Big end is at the low address */
+
+#define        HOST_BYTE_ORDER BIG_ENDIAN
+
+#define        HAVE_TERMIO 1
+#define        USG 1
+#define        HAVE_SIGSETMASK 1
+
+/* This system requires that we open a terminal with O_NOCTTY for it to
+   not become our controlling terminal.  */
+
+#define        USE_O_NOCTTY
+
+/* Get rid of any system-imposed stack limit if possible.  */
+
+#define SET_STACK_LIMIT_HUGE
+
+/* Brain death inherited from PC's pervades.  */
+#undef NULL
+#define NULL 0
+
+/* The IBM compiler requires this in order to properly compile alloca().  */
+#pragma alloca
+
+#define        vfork   fork
+
+/* Do implement the attach and detach commands.  */
+
+#define ATTACH_DETACH
+
+/* Override copies of {fetch,store}_inferior_registers in infptrace.c.  */
+
+#define FETCH_INFERIOR_REGISTERS
+
+/* Setpgrp() takes arguments, unlike ordinary Sys V's.  */
+
+#define        SETPGRP_ARGS
+
+/* RS6000/AIXCOFF does not support PT_STEP. Has to be simulated. */
+
+#define NO_SINGLE_STEP
+
+/* Interface between xcoff symbol reading code and AIX shared library
+   handling code.  FIXME, this probably needs generalizing.  */
+
+#define XCOFF_INIT_LOADINFO()  xcoff_init_loadinfo()
+#define XCOFF_ADD_TOC_TO_LOADINFO(x)   xcoff_add_toc_to_loadinfo (x)