mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 19:14:52 +08:00
* rs6000-pinsn.c, rs6000-tdep.c, rs6000-xdep.c, tm-rs6000.h,
xm-rs6000.h: New files. * xcoffexec.c: New file for handling AIX shared libraries.
This commit is contained in:
parent
37b637f3b7
commit
41abdfbd2d
377
gdb/rs6000-pinsn.c
Normal file
377
gdb/rs6000-pinsn.c
Normal file
@ -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);
|
||||
}
|
||||
|
975
gdb/rs6000-tdep.c
Normal file
975
gdb/rs6000-tdep.c
Normal file
@ -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), ®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;
|
||||
}
|
||||
|
364
gdb/rs6000-xdep.c
Normal file
364
gdb/rs6000-xdep.c
Normal file
@ -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;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
461
gdb/tm-rs6000.h
Normal file
461
gdb/tm-rs6000.h
Normal file
@ -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*)®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! */
|
||||
|
||||
|
||||
/* 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")
|
||||
|
||||
/* 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)
|
932
gdb/xcoffexec.c
Normal file
932
gdb/xcoffexec.c
Normal file
@ -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);
|
||||
}
|
67
gdb/xm-rs6000.h
Normal file
67
gdb/xm-rs6000.h
Normal file
@ -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)
|
Loading…
Reference in New Issue
Block a user