xm-rs6000.h: New files.
* xcoffexec.c: New file for handling AIX shared libraries.
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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), ®isters[REGISTER_BYTE (31-ii+FP0_REGNUM)], 8);
+
+ /* gpr's r0..r31 */
+ for (ii=1; ii <=32; ++ii)
+ write_memory (sp-256-(ii*4), ®isters[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), ®isters[REGISTER_BYTE (32-ii+FP0_REGNUM)], 8);
+
+ /* restore all gpr's */
+ for (ii=1; ii <= 32; ++ii) {
+ read_memory (sp-256-(ii*4), ®isters[REGISTER_BYTE (32-ii)], 4);
+ }
+
+ read_memory (sp-400, ®isters [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*)®isters [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, ®isters [REGISTER_BYTE (ii)], 4);
+ addr += sizeof (int);
+ }
+
+ if (saved_fpr != -1)
+ for (ii=saved_fpr; ii <= 31; ++ii) {
+ read_memory (addr, ®isters [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),
+ ®isters[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], len);
+ ++f_argno;
+ }
+
+ if (len > 4) {
+
+ /* Argument takes more than one register. */
+ while (argbytes < len) {
+
+ *(int*)®isters[REGISTER_BYTE(ii+3)] = 0;
+ bcopy ( ((char*)VALUE_CONTENTS (arg))+argbytes,
+ ®isters[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*)®isters[REGISTER_BYTE(ii+3)] = 0;
+ bcopy (VALUE_CONTENTS (arg), ®isters[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),
+ ®isters[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 (®buf[REGISTER_BYTE (FP0_REGNUM + 1)], valbuf,
+ TYPE_LENGTH (valtype));
+ else { /* float */
+ bcopy (®buf[REGISTER_BYTE (FP0_REGNUM + 1)], &dd, 8);
+ ff = (float)dd;
+ bcopy (&ff, valbuf, sizeof(float));
+ }
+ }
+ else
+ /* return value is copied starting from r3. */
+ bcopy (®buf[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;
+}
+
--- /dev/null
+/* 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*)®isters[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*)®isters [REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
+
+ /* read special registers. */
+ for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii)
+ *(int*)®isters[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*)®isters[REGISTER_BYTE (ii)], 0);
+ if ( errno ) {
+ perror ("ptrace write_gpr"); errno = 0;
+ }
+ }
+
+ /* write floating point registers now. */
+ for ( ii=0; ii < 32; ++ii) {
+ ptrace (PT_WRITE_FPR, inferior_pid,
+ (int*)®isters[REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
+ if ( errno ) {
+ perror ("ptrace write_fpr"); errno = 0;
+ }
+ }
+
+ /* write special registers. */
+ for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii) {
+ ptrace (PT_WRITE_GPR, inferior_pid, special_regs[ii],
+ *(int*)®isters[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*)®isters[REGISTER_BYTE (regno)], 0);
+ }
+
+ else if (regno <= FPLAST_REGNUM) { /* a FPR */
+ ptrace (PT_WRITE_FPR, inferior_pid,
+ (int*)®isters[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*)®isters[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, ®isters [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, ®isters [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);
+}
+
--- /dev/null
+/* 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*)®isters[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)
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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)