/* Target-dependent code for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "xcoffsolib.h"
-#include <sys/param.h>
-#include <sys/dir.h>
-#include <sys/user.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
#include <a.out.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/core.h>
-#include <sys/ldr.h>
-
extern struct obstack frame_cache_obstack;
switch (opcode) {
case 18 :
immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */
+ if (absolute)
+ dest = immediate;
+ else
+ dest = pc + immediate;
+ break;
case 16 :
- if (opcode != 18) /* br conditional */
- immediate = ((instr & ~3) << 16) >> 16;
+ immediate = ((instr & ~3) << 16) >> 16; /* br conditional */
if (absolute)
dest = immediate;
else
dest = read_register (LR_REGNUM) & ~3;
else if (ext_op == 528) /* br cond to count reg */
- dest = read_register (CTR_REGNUM) & ~3;
-
+ {
+ dest = read_register (CTR_REGNUM) & ~3;
+
+ /* If we are about to execute a system call, dest is something
+ like 0x22fc or 0x3b00. Upon completion the system call
+ will return to the address in the link register. */
+ if (dest < TEXT_SEGMENT_BASE)
+ dest = read_register (LR_REGNUM) & ~3;
+ }
else return -1;
break;
{
#define INSNLEN(OPCODE) 4
- static char breakp[] = BREAKPOINT;
+ static char le_breakp[] = LITTLE_BREAKPOINT;
+ static char be_breakp[] = BIG_BREAKPOINT;
+ char *breakp = TARGET_BYTE_ORDER == BIG_ENDIAN ? be_breakp : le_breakp;
int ii, insn;
CORE_ADDR loc;
CORE_ADDR breaks[2];
if (!one_stepped) {
loc = read_pc ();
- read_memory (loc, &insn, 4);
+ insn = read_memory_integer (loc, 4);
breaks[0] = loc + INSNLEN(insn);
opcode = insn >> 26;
skip_prologue (pc)
CORE_ADDR pc;
{
+ char buf[4];
unsigned int tmp;
- unsigned int op; /* FIXME, assumes instruction size matches host int!!! */
+ unsigned long op;
- if (target_read_memory (pc, (char *)&op, sizeof (op)))
+ if (target_read_memory (pc, buf, 4))
return pc; /* Can't access it -- assume no prologue. */
- SWAP_TARGET_AND_HOST (&op, sizeof (op));
+ op = extract_unsigned_integer (buf, 4);
/* Assume that subsequent fetches can fail with low probability. */
If the next is not a nop, this branch was part of the function
prologue. */
- if (op == 0x4def7b82 || /* crorc 15, 15, 15 */
+ if (op == 0x4def7b82 || /* crorc 15, 15, 15 */
op == 0x0)
- return pc - 4; /* don't skip over this branch */
+ return pc - 4; /* don't skip over this branch */
}
- if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
- pc += 4; /* store floating register double */
+ 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) */
+ 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) */
- (tmp == 0x93e1)) /* st r31,NUM(r1) */
- {
+ while ((op & 0xfc1f0000) == 0x90010000 && /* st rx,NUM(r1), rx >= r13 */
+ (op & 0x03e00000) >= 0x01a00000) {
+ pc += 4;
+ op = read_memory_integer (pc, 4);
+ }
+
+ if (op == 0x90010008) { /* st r0,8(r1) */
+ pc += 4;
+ op = read_memory_integer (pc, 4);
+ }
+
+ if (op == 0x91810004) { /* st r12,4(r1) */
+ pc += 4;
+ op = read_memory_integer (pc, 4);
+ }
+
+ if ((op & 0xffff0000) == 0x94210000) { /* stu r1,NUM(r1) */
pc += 4;
op = read_memory_integer (pc, 4);
}
op = read_memory_integer (pc, 4);
}
- if (op == 0x603f0000) { /* oril r31, r1, 0x0 */
+ if (op == 0x603f0000 /* oril r31, r1, 0x0 */
+ || op == 0x7c3f0b78) { /* mr r31, r1 */
pc += 4; /* this happens if r31 is used as */
op = read_memory_integer (pc, 4); /* frame ptr. (gcc does that) */
void
push_dummy_frame ()
{
- int sp, pc; /* stack pointer and link register */
+ /* stack pointer. */
+ CORE_ADDR sp;
+ /* Same thing, target byte order. */
+ char sp_targ[4];
+
+ /* link register. */
+ CORE_ADDR pc;
+ /* Same thing, target byte order. */
+ char pc_targ[4];
+
int ii;
target_fetch_registers (-1);
}
sp = read_register(SP_REGNUM);
- pc = read_register(PC_REGNUM);
+ pc = read_register(PC_REGNUM);
+ store_address (pc_targ, 4, pc);
dummy_frame_addr [dummy_frame_count++] = sp;
otherwise things like do_registers_info() wouldn't work properly! */
flush_cached_frames ();
- set_current_frame (create_new_frame (sp-DUMMY_FRAME_SIZE, pc));
/* save program counter in link register's space. */
- write_memory (sp+8, &pc, 4);
+ write_memory (sp+8, pc_targ, 4);
/* save all floating point and general purpose registers here. */
}
/* Save sp or so called back chain right here. */
- write_memory (sp-DUMMY_FRAME_SIZE, &sp, 4);
+ store_address (sp_targ, 4, sp);
+ write_memory (sp-DUMMY_FRAME_SIZE, sp_targ, 4);
sp -= DUMMY_FRAME_SIZE;
/* And finally, this is the back chain. */
- write_memory (sp+8, &pc, 4);
+ write_memory (sp+8, pc_targ, 4);
}
target_store_registers (-1);
pc = read_pc ();
flush_cached_frames ();
- set_current_frame (create_new_frame (sp, pc));
}
void
pop_frame ()
{
- int pc, lr, sp, prev_sp; /* %pc, %lr, %sp */
+ CORE_ADDR pc, lr, sp, prev_sp; /* %pc, %lr, %sp */
struct aix_framedata fdata;
- FRAME fr = get_current_frame ();
+ struct frame_info *frame = get_current_frame ();
int addr, ii;
pc = read_pc ();
- sp = FRAME_FP (fr);
+ sp = FRAME_FP (frame);
if (stop_stack_dummy && dummy_frame_count) {
pop_dummy_frame ();
return;
}
+ /* Make sure that all registers are valid. */
+ read_register_bytes (0, NULL, REGISTER_BYTES);
+
/* 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;
+ addr = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
function_frame_info (addr, &fdata);
- read_memory (sp, &prev_sp, 4);
if (fdata.frameless)
+ prev_sp = sp;
+ else
+ prev_sp = read_memory_integer (sp, 4);
+ if (fdata.nosavedpc)
lr = read_register (LR_REGNUM);
else
- read_memory (prev_sp+8, &lr, 4);
+ lr = read_memory_integer (prev_sp+8, 4);
/* reset %pc value. */
write_register (PC_REGNUM, lr);
addr = prev_sp - fdata.offset;
if (fdata.saved_gpr != -1)
- for (ii=fdata.saved_gpr; ii <= 31; ++ii) {
+ for (ii = fdata.saved_gpr; ii <= 31; ++ii) {
read_memory (addr, ®isters [REGISTER_BYTE (ii)], 4);
addr += 4;
}
if (fdata.saved_fpr != -1)
- for (ii=fdata.saved_fpr; ii <= 31; ++ii) {
+ for (ii = fdata.saved_fpr; ii <= 31; ++ii) {
read_memory (addr, ®isters [REGISTER_BYTE (ii+FP0_REGNUM)], 8);
addr += 8;
}
write_register (SP_REGNUM, prev_sp);
target_store_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. */
{
unsigned int tmp;
register unsigned int op;
+ char buf[4];
fdata->offset = 0;
fdata->saved_gpr = fdata->saved_fpr = fdata->alloca_reg = -1;
fdata->frameless = 1;
- op = read_memory_integer (pc, 4);
+ /* Do not error out if we can't access the instructions. */
+ if (target_read_memory (pc, buf, 4))
+ return;
+ op = extract_unsigned_integer (buf, 4);
if (op == 0x7c0802a6) { /* mflr r0 */
pc += 4;
op = read_memory_integer (pc, 4);
if (tmp == 0x93e1) {
if (fdata->offset)
/* fatal ("Unrecognized prolog."); */
- printf ("Unrecognized prolog!\n");
+ printf_unfiltered ("Unrecognized prolog!\n");
fdata->saved_gpr = 31;
tmp2 = op & 0xffff;
fdata->frameless = 0;
}
- if (op == 0x603f0000) { /* oril r31, r1, 0x0 */
- fdata->alloca_reg = 31;
- fdata->frameless = 0;
- }
+ if (op == 0x603f0000 /* oril r31, r1, 0x0 */
+ || op == 0x7c3f0b78) /* mr r31, r1 */
+ {
+ fdata->alloca_reg = 31;
+ fdata->frameless = 0;
+ }
}
CORE_ADDR
push_arguments (nargs, args, sp, struct_return, struct_addr)
int nargs;
- value *args;
+ value_ptr *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
int argno; /* current argument number */
int argbytes; /* current argument byte */
char tmp_buffer [50];
- value arg;
+ value_ptr 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");
+ printf_unfiltered ("FATAL ERROR -push_arguments()! frame not found!!\n");
/* The first eight words of ther arguments are passed in registers. Copy
them appropriately.
for (argno=0, argbytes=0; argno < nargs && ii<8; ++ii) {
- arg = value_arg_coerce (args[argno]);
+ arg = args[argno];
len = TYPE_LENGTH (VALUE_TYPE (arg));
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT) {
there is no way we would run out of them. */
if (len > 8)
- printf (
+ printf_unfiltered (
"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);
+ memcpy (®isters[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], VALUE_CONTENTS (arg),
+ len);
++f_argno;
}
while (argbytes < len) {
*(int*)®isters[REGISTER_BYTE(ii+3)] = 0;
- bcopy ( ((char*)VALUE_CONTENTS (arg))+argbytes,
- ®isters[REGISTER_BYTE(ii+3)],
+ memcpy (®isters[REGISTER_BYTE(ii+3)],
+ ((char*)VALUE_CONTENTS (arg))+argbytes,
(len - argbytes) > 4 ? 4 : len - argbytes);
++ii, argbytes += 4;
}
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);
+ memcpy (®isters[REGISTER_BYTE(ii+3)], VALUE_CONTENTS (arg), len);
}
++argno;
}
if ((argno < nargs) || argbytes) {
int space = 0, jj;
- value val;
+ value_ptr val;
if (argbytes) {
space += ((len - argbytes + 3) & -4);
jj = argno;
for (; jj < nargs; ++jj) {
- val = value_arg_coerce (args[jj]);
+ val = args[jj];
space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
}
/* push the rest of the arguments into stack. */
for (; argno < nargs; ++argno) {
- arg = value_arg_coerce (args[argno]);
+ arg = args[argno];
len = TYPE_LENGTH (VALUE_TYPE (arg));
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT && f_argno < 13) {
if (len > 8)
- printf (
+ printf_unfiltered (
"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);
+ memcpy (®isters[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], VALUE_CONTENTS (arg),
+ len);
++f_argno;
}
- write_memory (sp+24+(ii*4), VALUE_CONTENTS (arg), len);
+ write_memory (sp+24+(ii*4), (char *) VALUE_CONTENTS (arg), len);
ii += ((len + 3) & -4) / 4;
}
}
read_memory (saved_sp, tmp_buffer, 24);
write_memory (sp, tmp_buffer, 24);
- write_memory (sp, &saved_sp, 4); /* set back chain properly */
+ /* set back chain properly */
+ store_address (tmp_buffer, 4, saved_sp);
+ write_memory (sp, tmp_buffer, 4);
target_store_registers (-1);
return sp;
necessary. */
if (TYPE_LENGTH (valtype) > 4) /* this is a double */
- bcopy (®buf[REGISTER_BYTE (FP0_REGNUM + 1)], valbuf,
+ memcpy (valbuf, ®buf[REGISTER_BYTE (FP0_REGNUM + 1)],
TYPE_LENGTH (valtype));
else { /* float */
- bcopy (®buf[REGISTER_BYTE (FP0_REGNUM + 1)], &dd, 8);
+ memcpy (&dd, ®buf[REGISTER_BYTE (FP0_REGNUM + 1)], 8);
ff = (float)dd;
- bcopy (&ff, valbuf, sizeof(float));
+ memcpy (valbuf, &ff, sizeof(float));
}
}
else
/* return value is copied starting from r3. */
- bcopy (®buf[REGISTER_BYTE (3)], valbuf, TYPE_LENGTH (valtype));
+ memcpy (valbuf, ®buf[REGISTER_BYTE (3)], TYPE_LENGTH (valtype));
}
CORE_ADDR rs6000_struct_return_address;
-/* Throw away this debugging code. FIXMEmgo. */
-void
-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 to do context
switching, i.e. to set the new TOC table. Skip such code if we are on
its first instruction (as when we have single-stepped to here).
+ Also skip shared library trampoline code (which is different from
+ indirect function call trampolines).
Result is desired PC to step until, or NULL if we are not in
trampoline code. */
CORE_ADDR pc;
{
register unsigned int ii, op;
+ CORE_ADDR solib_target_pc;
static unsigned trampoline_code[] = {
0x800b0000, /* l r0,0x0(r11) */
0
};
+ /* If pc is in a shared library trampoline, return its target. */
+ solib_target_pc = find_solib_trampoline_target (pc);
+ if (solib_target_pc)
+ return solib_target_pc;
+
for (ii=0; trampoline_code[ii]; ++ii) {
op = read_memory_integer (pc + (ii*4), 4);
if (op != trampoline_code [ii])
- return NULL;
+ return 0;
}
ii = read_register (11); /* r11 holds destination addr */
pc = read_memory_integer (ii, 4); /* (r11) value */
CORE_ADDR func_start;
struct aix_framedata fdata;
+ if (fi->next != NULL)
+ /* Don't even think about framelessness except on the innermost frame. */
+ /* FIXME: Can also be frameless if fi->next->signal_handler_caller (if
+ a signal happens while executing in a frameless function). */
+ return 0;
+
func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
/* If we failed to find the start of the function, it is a mistake
fi->cache_fsr = (struct frame_saved_regs *)
obstack_alloc (&frame_cache_obstack, sizeof (struct frame_saved_regs));
- bzero (fi->cache_fsr, sizeof (struct frame_saved_regs));
+ memset (fi->cache_fsr, '\0', sizeof (struct frame_saved_regs));
if (fi->prev && fi->prev->frame)
frame_addr = fi->prev->frame;
return fi->initial_sp = read_register (fdata.alloca_reg);
}
-/* xcoff_relocate_symtab - hook for symbol table relocation.
- also reads shared libraries.. */
-
-xcoff_relocate_symtab (pid)
-unsigned int pid;
+CORE_ADDR
+rs6000_frame_chain (thisframe)
+ struct frame_info *thisframe;
{
-#define MAX_LOAD_SEGS 64 /* maximum number of load segments */
-
- struct ld_info *ldi;
- int temp;
-
- ldi = (void *) alloca(MAX_LOAD_SEGS * sizeof (*ldi));
-
- /* According to my humble theory, AIX has some timing problems and
- when the user stack grows, kernel doesn't update stack info in time
- and ptrace calls step on user stack. That is why we sleep here a little,
- and give kernel to update its internals. */
-
- usleep (36000);
-
- errno = 0;
- ptrace(PT_LDINFO, pid, (PTRACE_ARG3_TYPE) ldi,
- MAX_LOAD_SEGS * sizeof(*ldi), ldi);
- if (errno) {
- perror_with_name ("ptrace ldinfo");
- return 0;
- }
-
- 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)));
-
-#if 0
- /* Now that we've jumbled things around, re-sort them. */
- sort_minimal_symbols ();
-#endif
+ CORE_ADDR fp;
+ if (inside_entry_file ((thisframe)->pc))
+ return 0;
+ if (thisframe->signal_handler_caller)
+ fp = read_memory_integer (thisframe->frame + SIG_FRAME_FP_OFFSET, 4);
+ else
+ fp = read_memory_integer ((thisframe)->frame, 4);
- /* relocate the exec and core sections as well. */
- vmap_exec ();
+ return fp;
}
\f
/* Keep an array of load segment information and their TOC table addresses.
/* this is called from xcoffread.c */
void
-xcoff_add_toc_to_loadinfo (unsigned long tocoff)
+xcoff_add_toc_to_loadinfo (tocoff)
+ unsigned long tocoff;
{
while (loadinfotocindex >= loadinfolen) {
loadinfolen += LOADINFOLEN;
loadinfo [loadinfotocindex++].toc_offset = tocoff;
}
-
void
add_text_to_loadinfo (textaddr, dataaddr)
CORE_ADDR textaddr;
}
-/* FIXME: This assumes that the "textorg" and "dataorg" elements
+/* Note that this assumes that the "textorg" and "dataorg" elements
of a member of this array are correlated with the "toc_offset"
- element of the same member. But they are sequentially assigned in wildly
- different places, and probably there is no correlation. FIXME! */
+ element of the same member. This is taken care of because the loops
+ which assign the former (in xcoff_relocate_symtab or xcoff_relocate_core)
+ and the latter (in scan_xcoff_symtab, via vmap_symtab, in vmap_ldinfo
+ or xcoff_relocate_core) traverse the same objfiles in the same order. */
static CORE_ADDR
find_toc_address (pc)
return loadinfo[toc_entry].dataorg + loadinfo[toc_entry].toc_offset;
}
+
+#ifdef GDB_TARGET_POWERPC
+int
+gdb_print_insn_powerpc (memaddr, info)
+ bfd_vma memaddr;
+ disassemble_info *info;
+{
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ return print_insn_big_powerpc (memaddr, info);
+ else
+ return print_insn_little_powerpc (memaddr, info);
+}
+#endif
+
+void
+_initialize_rs6000_tdep ()
+{
+ /* FIXME, this should not be decided via ifdef. */
+#ifdef GDB_TARGET_POWERPC
+ tm_print_insn = gdb_print_insn_powerpc;
+#else
+ tm_print_insn = print_insn_rs6000;
+#endif
+}