* 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:
John Gilmore 1991-11-12 15:50:47 +00:00
parent 37b637f3b7
commit 41abdfbd2d
6 changed files with 3176 additions and 0 deletions

377
gdb/rs6000-pinsn.c Normal file
View 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
View 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), &registers[REGISTER_BYTE (31-ii+FP0_REGNUM)], 8);
/* gpr's r0..r31 */
for (ii=1; ii <=32; ++ii)
write_memory (sp-256-(ii*4), &registers[REGISTER_BYTE (32-ii)], 4);
/* so far, 32*2 + 32 words = 384 bytes have been written. We need 6 words
(24 bytes) for the rest of the registers. It brings the total to 408
bytes.
save sp or so call back chain right here. */
write_memory (sp-408, &sp, 4);
sp -= 408;
/* And finally, this is the back chain. */
write_memory (sp+8, &pc, 4);
}
/* Pop a dummy frame.
In rs6000 when we push a dummy frame, we save all of the registers. This
is usually done before user calls a function explicitly.
After a dummy frame is pushed, some instructions are copied into stack, and
stack pointer is decremented even more. Since we don't have a frame pointer to
get back to the parent frame of the dummy, we start having trouble poping it.
Therefore, we keep a dummy frame stack, keeping addresses of dummy frames as
such. When poping happens and when we detect that was a dummy frame, we pop
it back to its parent by using dummy frame stack (`dummy_frame_addr' array).
*/
pop_dummy_frame ()
{
CORE_ADDR sp, pc;
int ii;
sp = dummy_frame_addr [--dummy_frame_count];
/* restore all fpr's. */
for (ii = 1; ii <= 32; ++ii)
read_memory (sp-(ii*8), &registers[REGISTER_BYTE (32-ii+FP0_REGNUM)], 8);
/* restore all gpr's */
for (ii=1; ii <= 32; ++ii) {
read_memory (sp-256-(ii*4), &registers[REGISTER_BYTE (32-ii)], 4);
}
read_memory (sp-400, &registers [REGISTER_BYTE(PC_REGNUM)], 4);
/* when a dummy frame was being pushed, we had to decrement %sp first, in
order to secure astack space. Thus, saved %sp (or %r1) value, is not the
one we should restore. Change it with the one we need. */
*(int*)&registers [REGISTER_BYTE(FP_REGNUM)] = sp;
/* Now we can restore all registers. */
store_inferior_registers (-1);
pc = read_pc ();
flush_cached_frames ();
set_current_frame (create_new_frame (sp, pc));
}
/* pop the innermost frame, go back to the caller. */
pop_frame ()
{
int pc, lr, sp, prev_sp; /* %pc, %lr, %sp */
FRAME fr = get_current_frame ();
int offset = 0;
int frameless = 0; /* TRUE if function is frameless */
int addr, ii;
int saved_gpr, saved_fpr; /* # of saved gpr's and fpr's */
pc = read_pc ();
sp = FRAME_FP (fr);
if (stop_stack_dummy && dummy_frame_count) {
pop_dummy_frame ();
return;
}
/* figure out previous %pc value. If the function is frameless, it is
still in the link register, otherwise walk the frames and retrieve the
saved %pc value in the previous frame. */
addr = get_pc_function_start (fr->pc) + FUNCTION_START_OFFSET;
function_frame_info (addr, &frameless, &offset, &saved_gpr, &saved_fpr);
read_memory (sp, &prev_sp, 4);
if (frameless)
lr = read_register (LR_REGNUM);
else
read_memory (prev_sp+8, &lr, 4);
/* reset %pc value. */
write_register (PC_REGNUM, lr);
/* reset register values if any was saved earlier. */
addr = prev_sp - offset;
if (saved_gpr != -1)
for (ii=saved_gpr; ii <= 31; ++ii) {
read_memory (addr, &registers [REGISTER_BYTE (ii)], 4);
addr += sizeof (int);
}
if (saved_fpr != -1)
for (ii=saved_fpr; ii <= 31; ++ii) {
read_memory (addr, &registers [REGISTER_BYTE (ii+FP0_REGNUM)], 8);
addr += 8;
}
write_register (SP_REGNUM, prev_sp);
store_inferior_registers (-1);
flush_cached_frames ();
set_current_frame (create_new_frame (prev_sp, lr));
}
/* fixup the call sequence of a dummy function, with the real function address.
its argumets will be passed by gdb. */
fix_call_dummy(dummyname, pc, fun, nargs, type)
char *dummyname;
int pc;
int fun;
int nargs; /* not used */
int type; /* not used */
{
#define TOC_ADDR_OFFSET 20
#define TARGET_ADDR_OFFSET 28
int ii;
unsigned long target_addr;
unsigned long tocvalue;
target_addr = fun;
tocvalue = find_toc_address (target_addr);
ii = *(int*)((char*)dummyname + TOC_ADDR_OFFSET);
ii = (ii & 0xffff0000) | (tocvalue >> 16);
*(int*)((char*)dummyname + TOC_ADDR_OFFSET) = ii;
ii = *(int*)((char*)dummyname + TOC_ADDR_OFFSET+4);
ii = (ii & 0xffff0000) | (tocvalue & 0x0000ffff);
*(int*)((char*)dummyname + TOC_ADDR_OFFSET+4) = ii;
ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET);
ii = (ii & 0xffff0000) | (target_addr >> 16);
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET) = ii;
ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4);
ii = (ii & 0xffff0000) | (target_addr & 0x0000ffff);
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4) = ii;
}
/* return information about a function frame.
- frameless is TRUE, if function does not save %pc value in its frame.
- offset is the number of bytes used in the frame to save registers.
- saved_gpr is the number of the first saved gpr.
- saved_fpr is the number of the first saved fpr.
*/
function_frame_info (pc, frameless, offset, saved_gpr, saved_fpr)
int pc;
int *frameless, *offset, *saved_gpr, *saved_fpr;
{
unsigned int tmp;
register unsigned int op;
*offset = 0;
*saved_gpr = *saved_fpr = -1;
if (!inferior_pid)
return;
op = read_memory_integer (pc, 4);
if (op == 0x7c0802a6) { /* mflr r0 */
pc += 4;
op = read_memory_integer (pc, 4);
*frameless = 0;
}
else /* else, this is a frameless invocation */
*frameless = 1;
if ((op & 0xfc00003e) == 0x7c000026) { /* mfcr Rx */
pc += 4;
op = read_memory_integer (pc, 4);
}
if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
pc += 4;
op = read_memory_integer (pc, 4);
}
if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
pc += 4; /* store floating register double */
op = read_memory_integer (pc, 4);
}
if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
int tmp2;
*saved_gpr = (op >> 21) & 0x1f;
tmp2 = op & 0xffff;
if (tmp2 > 0x7fff)
tmp2 = 0xffff0000 | tmp2;
if (tmp2 < 0) {
tmp2 = tmp2 * -1;
*saved_fpr = (tmp2 - ((32 - *saved_gpr) * 4)) / 8;
if ( *saved_fpr > 0)
*saved_fpr = 32 - *saved_fpr;
else
*saved_fpr = -1;
}
*offset = tmp2;
}
}
/* Pass the arguments in either registers, or in the stack. In RS6000, the first
eight words of the argument list (that might be less than eight parameters if
some parameters occupy more than one word) are passed in r3..r11 registers.
float and double parameters are passed in fpr's, in addition to that. Rest of
the parameters if any are passed in user stack. There might be cases in which
half of the parameter is copied into registers, the other half is pushed into
stack.
If the function is returning a structure, then the return address is passed
in r3, then the first 7 words of the parametes can be passed in registers,
starting from r4. */
CORE_ADDR
push_arguments (nargs, args, sp, struct_return, struct_addr)
int nargs;
value *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
{
int ii, len;
int argno; /* current argument number */
int argbytes; /* current argument byte */
char tmp_buffer [50];
value arg;
int f_argno = 0; /* current floating point argno */
CORE_ADDR saved_sp, pc;
if ( dummy_frame_count <= 0)
printf ("FATAL ERROR -push_arguments()! frame not found!!\n");
/* The first eight words of ther arguments are passed in registers. Copy
them appropriately.
If the function is returning a `struct', then the first word (which
will be passed in r3) is used for struct return address. In that
case we should advance one word and start from r4 register to copy
parameters. */
ii = struct_return ? 1 : 0;
for (argno=0, argbytes=0; argno < nargs && ii<8; ++ii) {
arg = value_arg_coerce (args[argno]);
len = TYPE_LENGTH (VALUE_TYPE (arg));
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT) {
/* floating point arguments are passed in fpr's, as well as gpr's.
There are 13 fpr's reserved for passing parameters. At this point
there is no way we would run out of them. */
if (len > 8)
printf (
"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
bcopy (VALUE_CONTENTS (arg),
&registers[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], len);
++f_argno;
}
if (len > 4) {
/* Argument takes more than one register. */
while (argbytes < len) {
*(int*)&registers[REGISTER_BYTE(ii+3)] = 0;
bcopy ( ((char*)VALUE_CONTENTS (arg))+argbytes,
&registers[REGISTER_BYTE(ii+3)],
(len - argbytes) > 4 ? 4 : len - argbytes);
++ii, argbytes += 4;
if (ii >= 8)
goto ran_out_of_registers_for_arguments;
}
argbytes = 0;
--ii;
}
else { /* Argument can fit in one register. No problem. */
*(int*)&registers[REGISTER_BYTE(ii+3)] = 0;
bcopy (VALUE_CONTENTS (arg), &registers[REGISTER_BYTE(ii+3)], len);
}
++argno;
}
ran_out_of_registers_for_arguments:
/* location for 8 parameters are always reserved. */
sp -= 4 * 8;
/* another six words for back chain, TOC register, link register, etc. */
sp -= 24;
/* if there are more arguments, allocate space for them in
the stack, then push them starting from the ninth one. */
if ((argno < nargs) || argbytes) {
int space = 0, jj;
value val;
if (argbytes) {
space += ((len - argbytes + 3) & -4);
jj = argno + 1;
}
else
jj = argno;
for (; jj < nargs; ++jj) {
val = value_arg_coerce (args[jj]);
space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
}
/* add location required for the rest of the parameters */
space = (space + 7) & -8;
sp -= space;
/* This is another instance we need to be concerned about securing our
stack space. If we write anything underneath %sp (r1), we might conflict
with the kernel who thinks he is free to use this area. So, update %sp
first before doing anything else. */
write_register (SP_REGNUM, sp);
#if 0
pc = read_pc ();
flush_cached_frames ();
set_current_frame (create_new_frame (sp, pc));
#endif
/* if the last argument copied into the registers didn't fit there
completely, push the rest of it into stack. */
if (argbytes) {
write_memory (
sp+24+(ii*4), ((char*)VALUE_CONTENTS (arg))+argbytes, len - argbytes);
++argno;
ii += ((len - argbytes + 3) & -4) / 4;
}
/* push the rest of the arguments into stack. */
for (; argno < nargs; ++argno) {
arg = value_arg_coerce (args[argno]);
len = TYPE_LENGTH (VALUE_TYPE (arg));
/* float types should be passed in fpr's, as well as in the stack. */
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT && f_argno < 13) {
if (len > 8)
printf (
"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
bcopy (VALUE_CONTENTS (arg),
&registers[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], len);
++f_argno;
}
write_memory (sp+24+(ii*4), VALUE_CONTENTS (arg), len);
ii += ((len + 3) & -4) / 4;
}
}
else {
/* Secure stack areas first, before doing anything else. */
write_register (SP_REGNUM, sp);
#if 0
pc = read_pc ();
flush_cached_frames ();
set_current_frame (create_new_frame (sp, pc));
#endif
}
saved_sp = dummy_frame_addr [dummy_frame_count - 1];
read_memory (saved_sp, tmp_buffer, 24);
write_memory (sp, tmp_buffer, 24);
write_memory (sp, &saved_sp, 4); /* set back chain properly */
store_inferior_registers (-1);
return sp;
}
/* a given return value in `regbuf' with a type `valtype', extract and copy its
value into `valbuf' */
extract_return_value (valtype, regbuf, valbuf)
struct type *valtype;
char regbuf[REGISTER_BYTES];
char *valbuf;
{
if (TYPE_CODE (valtype) == TYPE_CODE_FLT) {
double dd; float ff;
/* floats and doubles are returned in fpr1. fpr's have a size of 8 bytes.
We need to truncate the return value into float size (4 byte) if
necessary. */
if (TYPE_LENGTH (valtype) > 4) /* this is a double */
bcopy (&regbuf[REGISTER_BYTE (FP0_REGNUM + 1)], valbuf,
TYPE_LENGTH (valtype));
else { /* float */
bcopy (&regbuf[REGISTER_BYTE (FP0_REGNUM + 1)], &dd, 8);
ff = (float)dd;
bcopy (&ff, valbuf, sizeof(float));
}
}
else
/* return value is copied starting from r3. */
bcopy (&regbuf[REGISTER_BYTE (3)], valbuf, TYPE_LENGTH (valtype));
}
/* keep keep structure return address in this variable. */
CORE_ADDR rs6000_struct_return_address;
/* Throw away this debugging code. FIXMEmgo. */
print_frame(fram)
int fram;
{
int ii, val;
for (ii=0; ii<40; ++ii) {
if ((ii % 4) == 0)
printf ("\n");
val = read_memory_integer (fram + ii * 4, 4);
printf ("0x%08x\t", val);
}
printf ("\n");
}
/* Indirect function calls use a piece of trampoline code do co context switching,
i.e. to set the new TOC table. Skip such code if exists. */
skip_trampoline_code (pc)
int pc;
{
register unsigned int ii, op;
static unsigned trampoline_code[] = {
0x800b0000, /* l r0,0x0(r11) */
0x90410014, /* st r2,0x14(r1) */
0x7c0903a6, /* mtctr r0 */
0x804b0004, /* l r2,0x4(r11) */
0x816b0008, /* l r11,0x8(r11) */
0x4e800420, /* bctr */
0x4e800020, /* br */
0
};
for (ii=0; trampoline_code[ii]; ++ii) {
op = read_memory_integer (pc + (ii*4), 4);
if (op != trampoline_code [ii])
return NULL;
}
ii = read_register (11); /* r11 holds destination addr */
pc = read_memory_integer (ii, 4); /* (r11) value */
return pc;
}

364
gdb/rs6000-xdep.c Normal file
View 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*)&registers[REGISTER_BYTE (ii)] =
ptrace (PT_READ_GPR, inferior_pid, ii, 0, 0);
/* read general purpose floating point registers. */
for (ii=0; ii < 32; ++ii)
ptrace (PT_READ_FPR, inferior_pid,
(int*)&registers [REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
/* read special registers. */
for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii)
*(int*)&registers[REGISTER_BYTE (FIRST_SP_REGNUM+ii)] =
ptrace (PT_READ_GPR, inferior_pid, special_regs[ii], 0, 0);
}
/* Store our register values back into the inferior.
If REGNO is -1, do this for all registers.
Otherwise, REGNO specifies which register (so we can save time). */
store_inferior_registers (regno)
int regno;
{
extern char registers[];
errno = 0;
if (regno == -1) { /* for all registers.. */
int ii;
/* execute one dummy instruction (which is a breakpoint) in inferior
process. So give kernel a chance to do internal house keeping.
Otherwise the following ptrace(2) calls will mess up user stack
since kernel will get confused about the bottom of the stack (%sp) */
exec_one_dummy_insn ();
/* write general purpose registers first! */
for ( ii=GPR0; ii<=GPR31; ++ii) {
ptrace (PT_WRITE_GPR, inferior_pid, ii,
*(int*)&registers[REGISTER_BYTE (ii)], 0);
if ( errno ) {
perror ("ptrace write_gpr"); errno = 0;
}
}
/* write floating point registers now. */
for ( ii=0; ii < 32; ++ii) {
ptrace (PT_WRITE_FPR, inferior_pid,
(int*)&registers[REGISTER_BYTE (FP0_REGNUM+ii)], FPR0+ii, 0);
if ( errno ) {
perror ("ptrace write_fpr"); errno = 0;
}
}
/* write special registers. */
for (ii=0; ii <= LAST_SP_REGNUM-FIRST_SP_REGNUM; ++ii) {
ptrace (PT_WRITE_GPR, inferior_pid, special_regs[ii],
*(int*)&registers[REGISTER_BYTE (FIRST_SP_REGNUM+ii)], 0);
if ( errno ) {
perror ("ptrace write_gpr"); errno = 0;
}
}
}
/* else, a specific register number is given... */
else if (regno < FP0_REGNUM) { /* a GPR */
ptrace (PT_WRITE_GPR, inferior_pid, regno,
*(int*)&registers[REGISTER_BYTE (regno)], 0);
}
else if (regno <= FPLAST_REGNUM) { /* a FPR */
ptrace (PT_WRITE_FPR, inferior_pid,
(int*)&registers[REGISTER_BYTE (regno)], regno-FP0_REGNUM+FPR0, 0);
}
else if (regno <= LAST_SP_REGNUM) { /* a special register */
ptrace (PT_WRITE_GPR, inferior_pid, special_regs [regno-FIRST_SP_REGNUM],
*(int*)&registers[REGISTER_BYTE (regno)], 0);
}
else
fprintf (stderr, "Gdb error: register no %d not implemented.\n", regno);
if ( errno ) {
perror ("ptrace write"); errno = 0;
return -1;
}
return 0;
}
void
fetch_core_registers (core_reg_sect, core_reg_size, which)
char *core_reg_sect;
unsigned core_reg_size;
int which;
{
/* fetch GPRs and special registers from the first register section
in core bfd. */
if (which == 0) {
/* copy GPRs first. */
bcopy (core_reg_sect, registers, 32 * 4);
/* gdb's internal register template and bfd's register section layout
should share a common include file. FIXMEmgo */
/* then comes special registes. They are supposed to be in the same
order in gdb template and bfd `.reg' section. */
core_reg_sect += (32 * 4);
bcopy (core_reg_sect, &registers [REGISTER_BYTE (FIRST_SP_REGNUM)],
(LAST_SP_REGNUM - FIRST_SP_REGNUM + 1) * 4);
}
/* fetch floating point registers from register section 2 in core bfd. */
else if (which == 2)
bcopy (core_reg_sect, &registers [REGISTER_BYTE (FP0_REGNUM)], 32 * 8);
else
fprintf (stderr, "Gdb error: unknown parameter to fetch_core_registers().\n");
}
frameless_function_invocation (fi)
struct frame_info *fi;
{
int ret;
CORE_ADDR func_start, after_prologue;
#if 0
func_start = (LOAD_ADDR (get_pc_function_start (fi->pc)) +
FUNCTION_START_OFFSET);
#else
func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
#endif
if (func_start)
{
after_prologue = func_start;
SKIP_PROLOGUE (after_prologue);
ret = (after_prologue == func_start);
}
else
/* If we can't find the start of the function, we don't really */
/* know whether the function is frameless, but we should be */
/* able to get a reasonable (i.e. best we can do under the */
/* circumstances) backtrace by saying that it isn't. */
ret = 0;
return ret;
}
/* aixcoff_relocate_symtab - hook for symbol table relocation.
also reads shared libraries.. */
aixcoff_relocate_symtab (pid)
unsigned int pid;
{
#define MAX_LOAD_SEGS 64 /* maximum number of load segments */
extern int compare_misc_functions ();
struct ld_info *ldi;
int temp;
ldi = (void *) alloca(MAX_LOAD_SEGS * sizeof (*ldi));
/* According to my humble theory, aixcoff has some timing problems and
when the user stack grows, kernel doesn't update stack info in time
and ptrace calls step on user stack. That is why we sleep here a little,
and give kernel to update its internals. */
usleep (36000);
errno = 0;
ptrace(PT_LDINFO, pid, ldi, MAX_LOAD_SEGS * sizeof(*ldi), ldi);
if (errno)
perror_with_name ("ptrace ldinfo");
vmap_ldinfo(ldi);
do {
add_text_to_loadinfo (ldi->ldinfo_textorg, ldi->ldinfo_dataorg);
} while (ldi->ldinfo_next
&& (ldi = (void *) (ldi->ldinfo_next + (char *) ldi)));
/* Now that we've jumbled things around, re-sort them. */
sort_misc_function_vector ();
/* relocate the exec and core sections as well. */
vmap_exec ();
}
/* Keep an array of load segment information and their TOC table addresses.
This info will be useful when calling a shared library function by hand. */
typedef struct {
unsigned long textorg, dataorg, toc_offset;
} LoadInfo;
#define LOADINFOLEN 10
static LoadInfo *loadInfo = NULL;
static int loadInfoLen = 0;
static int loadInfoTocIndex = 0;
static int loadInfoTextIndex = 0;
xcoff_init_loadinfo ()
{
loadInfoTocIndex = 0;
loadInfoTextIndex = 0;
if (loadInfoLen == 0) {
loadInfo = (void*) xmalloc (sizeof (LoadInfo) * LOADINFOLEN);
loadInfoLen = LOADINFOLEN;
}
}
free_loadinfo ()
{
if (loadInfo)
free (loadInfo);
loadInfo = NULL;
loadInfoLen = 0;
loadInfoTocIndex = 0;
loadInfoTextIndex = 0;
}
xcoff_add_toc_to_loadinfo (unsigned long tocaddr)
{
while (loadInfoTocIndex >= loadInfoLen) {
loadInfoLen += LOADINFOLEN;
loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
}
loadInfo [loadInfoTocIndex++].toc_offset = tocaddr;
}
add_text_to_loadinfo (unsigned long textaddr, unsigned long dataaddr)
{
while (loadInfoTextIndex >= loadInfoLen) {
loadInfoLen += LOADINFOLEN;
loadInfo = (void*) xrealloc (loadInfo, sizeof(LoadInfo) * loadInfoLen);
}
loadInfo [loadInfoTextIndex].textorg = textaddr;
loadInfo [loadInfoTextIndex].dataorg = dataaddr;
++loadInfoTextIndex;
}
unsigned long
find_toc_address (unsigned long pc)
{
int ii, toc_entry;
for (ii=0; ii < loadInfoTextIndex; ++ii)
if (pc > loadInfo [ii].textorg)
toc_entry = ii;
return loadInfo [toc_entry].dataorg + loadInfo [toc_entry].toc_offset;
}
/* execute one dummy breakpoint instruction. This way we give kernel
a chance to do some housekeeping and update inferior's internal data,
including u_area. */
exec_one_dummy_insn ()
{
#define DUMMY_INSN_ADDR 0x10000200
unsigned long shadow;
unsigned int status, pid;
target_insert_breakpoint (DUMMY_INSN_ADDR, &shadow);
errno = 0;
ptrace (PT_CONTINUE, inferior_pid, DUMMY_INSN_ADDR, 0, 0);
if (errno)
perror ("pt_continue");
do {
pid = wait (&status);
} while (pid != inferior_pid);
target_remove_breakpoint (DUMMY_INSN_ADDR, &shadow);
}

461
gdb/tm-rs6000.h Normal file
View 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*)&registers[REGISTER_BYTE (LR_REGNUM)])
/*#define SAVED_PC_AFTER_CALL(frame) saved_pc_after_call(frame) */
/* Address of end of stack space. */
#define STACK_END_ADDR 0x2ff80000
/* Stack grows downward. */
#define INNER_THAN <
#if 0
/* No, we shouldn't use this. push_arguments() should leave stack in a
proper alignment! */
/* Stack has strict alignment. */
#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8)
#endif
/* This is how argumets pushed onto stack or passed in registers. */
#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
sp = push_arguments(nargs, args, sp, struct_return, struct_addr)
/* Sequence of bytes for breakpoint instruction. */
#define BREAKPOINT {0x7d, 0x82, 0x10, 0x08}
/* Amount PC must be decremented by after a breakpoint.
This is often the number of bytes in BREAKPOINT
but not always. */
#define DECR_PC_AFTER_BREAK 0
/* Nonzero if instruction at PC is a return instruction. */
/* Allow any of the return instructions, including a trapv and a return
from interrupt. */
#define ABOUT_TO_RETURN(pc) \
((read_memory_integer (pc, 4) & 0xfe8007ff) == 0x4e800020)
/* Return 1 if P points to an invalid floating point value. */
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
/* Largest integer type */
#define LONGEST long
/* Name of the builtin type for the LONGEST type above. */
#define BUILTIN_TYPE_LONGEST builtin_type_long
/* Say how long (ordinary) registers are. */
#define REGISTER_TYPE long
/* Number of machine registers */
#define NUM_REGS 71
/* Initializer for an array of names of registers.
There should be NUM_REGS strings in this initializer. */
#define REGISTER_NAMES \
{"r0", "sp", "toc", "r3", "r4", "r5", "r6", "r7", \
"r8", "r9", "r10","r11","r12","r13","r14","r15", \
"r16","r17","r18","r19","r20","r21","r22","r23", \
"r24","r25","r26","r27","r28","r29","r30","r31", \
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
"f8", "f9", "f10","f11","f12","f13","f14","f15", \
"f16","f17","f18","f19","f20","f21","f22","f23", \
"f24","f25","f26","f27","f28","f29","f30","f31", \
"pc", "ps", "cnd", "lr", "cnt", "xer", "mq" }
/* Register numbers of various important registers.
Note that some of these values are "real" register numbers,
and correspond to the general registers of the machine,
and some are "phony" register numbers which are too large
to be actual register numbers as far as the user is concerned
but do serve to get the desired values when passed to read_register. */
#define FP_REGNUM 1 /* Contains address of executing stack frame */
#define SP_REGNUM 1 /* Contains address of top of stack */
#define TOC_REGNUM 2 /* TOC register */
#define FP0_REGNUM 32 /* Floating point register 0 */
#define FPLAST_REGNUM 63 /* Last floating point register */
/* Special purpose registers... */
/* P.S. keep these in the same order as in /usr/mstsave.h `mstsave' structure, for
easier processing */
#define PC_REGNUM 64 /* Program counter (instruction address %iar) */
#define PS_REGNUM 65 /* Processor (or machine) status (%msr) */
#define CR_REGNUM 66 /* Condition register */
#define LR_REGNUM 67 /* Link register */
#define CTR_REGNUM 68 /* Count register */
#define XER_REGNUM 69 /* Fixed point exception registers */
#define MQ_REGNUM 70 /* Multiply/quotient register */
#define FIRST_SP_REGNUM 64 /* first special register number */
#define LAST_SP_REGNUM 70 /* last special register number */
/* Total amount of space needed to store our copies of the machine's
register state, the array `registers'.
32 4-byte gpr's
32 8-byte fpr's
7 4-byte special purpose registers,
total 416 bytes. Keep some extra space for now, in case to add more. */
#define REGISTER_BYTES 420
/* Index within `registers' of the first byte of the space for
register N. */
#define REGISTER_BYTE(N) \
( \
((N) > FPLAST_REGNUM) ? ((((N) - FPLAST_REGNUM -1) * 4) + 384)\
:((N) >= FP0_REGNUM) ? ((((N) - FP0_REGNUM) * 8) + 128) \
:((N) * 4) )
/* Number of bytes of storage in the actual machine representation
for register N. */
/* Note that the unsigned cast here forces the result of the
subtractiion to very high positive values if N < FP0_REGNUM */
#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 32 ? 8 : 4)
/* Number of bytes of storage in the program's representation
for register N. On the RS6000, all regs are 4 bytes
except the floating point regs which are 8-byte doubles. */
#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 32 ? 8 : 4)
/* Largest value REGISTER_RAW_SIZE can have. */
#define MAX_REGISTER_RAW_SIZE 8
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
#define MAX_REGISTER_VIRTUAL_SIZE 8
/* convert a dbx stab register number (from `r' declaration) to a gdb REGNUM */
#define STAB_REG_TO_REGNUM(value) (value)
/* Nonzero if register N requires conversion
from raw format to virtual format. */
#define REGISTER_CONVERTIBLE(N) ((N) >= FP0_REGNUM && (N) <= FPLAST_REGNUM)
/* Convert data from raw format for register REGNUM
to virtual format for register REGNUM. */
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
bcopy ((FROM), (TO), REGISTER_RAW_SIZE (REGNUM))
/* Convert data from virtual format for register REGNUM
to raw format for register REGNUM. */
#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
bcopy ((FROM), (TO), REGISTER_RAW_SIZE (REGNUM))
/* Return the GDB type object for the "standard" data type
of data in register N. */
#define REGISTER_VIRTUAL_TYPE(N) \
(((unsigned)(N) - FP0_REGNUM) < 32 ? builtin_type_double : builtin_type_int)
/* Store the address of the place in which to copy the structure the
subroutine will return. This is called from call_function. */
/* in RS6000, struct return addresses are passed as an extra parameter in r3.
In function return, callee is not responsible of returning this address back.
Since gdb needs to find it, we will store in a designated variable
`rs6000_struct_return_address'. */
extern unsigned int rs6000_struct_return_address;
#define STORE_STRUCT_RETURN(ADDR, SP) \
{ write_register (3, (ADDR)); \
rs6000_struct_return_address = (unsigned int)(ADDR); }
/* Extract from an array REGBUF containing the (raw) register state
a function return value of type TYPE, and copy that, in virtual format,
into VALBUF. */
/* #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) */
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
extract_return_value(TYPE,REGBUF,VALBUF)
/* Write into appropriate registers a function return value
of type TYPE, given in virtual format. */
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
printf ("FIXMEmgo! STORE_RETURN_VALUE not implemented yet!\n")
/* Extract from an array REGBUF containing the (raw) register state
the address in which a function should return its structure value,
as a CORE_ADDR (or an expression that can be used as one). */
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) rs6000_struct_return_address
/* Do implement the attach and detach commands. */
#define ATTACH_DETACH /* FIXMEmgo! Not implemented yet! */
/* 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
View 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
View 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)