/* Target-dependent code for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
Free Software Foundation, Inc.
This file is part of GDB.
#include "symtab.h"
#include "target.h"
#include "gdbcore.h"
-
+#include "symfile.h"
+#include "objfiles.h"
#include "xcoffsolib.h"
-#include <a.out.h>
-
extern struct obstack frame_cache_obstack;
extern int errno;
char data[4];
} stepBreaks[2];
+/* Hook for determining the TOC address when calling functions in the
+ inferior under AIX. The initialization code in rs6000-nat.c sets
+ this hook to point to find_toc_address. */
+
+CORE_ADDR (*find_toc_address_hook) PARAMS ((CORE_ADDR)) = NULL;
+
/* Static function prototypes */
-static CORE_ADDR
-find_toc_address PARAMS ((CORE_ADDR pc));
+static CORE_ADDR branch_dest PARAMS ((int opcode, int instr, CORE_ADDR pc,
+ CORE_ADDR safety));
-static CORE_ADDR
-branch_dest PARAMS ((int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety));
+static void frame_get_cache_fsr PARAMS ((struct frame_info *fi,
+ struct rs6000_framedata *fdatap));
-static void
-frame_get_cache_fsr PARAMS ((struct frame_info *fi,
- struct rs6000_framedata *fdatap));
+static void pop_dummy_frame PARAMS ((void));
+
+/* Calculate the destination of a branch/jump. Return -1 if not a branch. */
-/*
- * Calculate the destination of a branch/jump. Return -1 if not a branch.
- */
static CORE_ADDR
branch_dest (opcode, instr, pc, safety)
int opcode;
CORE_ADDR pc;
CORE_ADDR safety;
{
- register long offset;
CORE_ADDR dest;
int immediate;
int absolute;
ext_op = (instr>>1) & 0x3ff;
if (ext_op == 16) /* br conditional register */
- dest = read_register (LR_REGNUM) & ~3;
+ {
+ dest = read_register (LR_REGNUM) & ~3;
+
+ /* If we are about to return from a signal handler, dest is
+ something like 0x3c90. The current frame is a signal handler
+ caller frame, upon completion of the sigreturn system call
+ execution will return to the saved PC in the frame. */
+ if (dest < TEXT_SEGMENT_BASE)
+ {
+ struct frame_info *fi;
+
+ fi = get_current_frame ();
+ if (fi != NULL)
+ dest = read_memory_integer (fi->frame + SIG_FRAME_PC_OFFSET,
+ 4);
+ }
+ }
else if (ext_op == 528) /* br cond to count reg */
{
void
single_step (signal)
- int signal;
+ enum target_signal signal;
{
#define INSNLEN(OPCODE) 4
int cr_reg = 0;
int reg;
int framep = 0;
+ int minimal_toc_loaded = 0;
static struct rs6000_framedata zero_frame;
*fdata = zero_frame;
} else if ((op & 0xffff0000) == 0x3c000000) { /* addis 0,0,NUM, used for >= 32k frames */
fdata->offset = (op & 0x0000ffff) << 16;
+ fdata->frameless = 0;
continue;
} else if ((op & 0xffff0000) == 0x60000000) { /* ori 0,0,NUM, 2nd half of >= 32k frames */
fdata->offset |= (op & 0x0000ffff);
+ fdata->frameless = 0;
continue;
} else if ((op & 0xffff0000) == lr_reg) { /* st Rx,NUM(r1) where Rx == lr */
} else if (op == 0x48000005) { /* bl .+4 used in -mrelocatable */
continue;
+ } else if (op == 0x48000004) { /* b .+4 (xlc) */
+ break;
+
} else if (((op & 0xffff0000) == 0x801e0000 || /* lwz 0,NUM(r30), used in V.4 -mrelocatable */
op == 0x7fc0f214) && /* add r30,r0,r30, used in V.4 -mrelocatable */
lr_reg == 0x901e0000) {
} else if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
+ fdata->frameless = 0;
/* Don't skip over the subroutine call if it is not within the first
three instructions of the prologue. */
if ((pc - orig_pc) > 8)
/* update stack pointer */
} else if ((op & 0xffff0000) == 0x94210000) { /* stu r1,NUM(r1) */
+ fdata->frameless = 0;
fdata->offset = SIGNED_SHORT (op);
offset = fdata->offset;
continue;
} else if (op == 0x7c21016e) { /* stwux 1,1,0 */
+ fdata->frameless = 0;
offset = fdata->offset;
continue;
/* Load up minimal toc pointer */
- } else if ((op >> 22) == 0x20f) { /* l r31,... or l r30,... */
+ } else if ((op >> 22) == 0x20f
+ && ! minimal_toc_loaded) { /* l r31,... or l r30,... */
+ minimal_toc_loaded = 1;
continue;
/* store parameters in stack */
/* store parameters in stack via frame pointer */
} else if (framep &&
- (op & 0xfc1f0000) == 0x901f0000 || /* st rx,NUM(r1) */
+ ((op & 0xfc1f0000) == 0x901f0000 || /* st rx,NUM(r1) */
(op & 0xfc1f0000) == 0xd81f0000 || /* stfd Rx,NUM(r1) */
- (op & 0xfc1f0000) == 0xfc1f0000) { /* frsp, fp?,NUM(r1) */
+ (op & 0xfc1f0000) == 0xfc1f0000)) { /* frsp, fp?,NUM(r1) */
continue;
/* Set up frame pointer */
} else if (op == 0x603f0000 /* oril r31, r1, 0x0 */
|| op == 0x7c3f0b78) { /* mr r31, r1 */
+ fdata->frameless = 0;
framep = 1;
fdata->alloca_reg = 31;
continue;
+ /* Another way to set up the frame pointer. */
+ } else if ((op & 0xfc1fffff) == 0x38010000) { /* addi rX, r1, 0x0 */
+ fdata->frameless = 0;
+ framep = 1;
+ fdata->alloca_reg = (op & ~0x38010000) >> 21;
+ continue;
+
} else {
break;
}
}
#endif /* 0 */
- fdata->frameless = (pc == orig_pc);
fdata->offset = - fdata->offset;
return pc;
}
/* Same thing, target byte order. */
char pc_targ[4];
+ /* Needed to figure out where to save the dummy link area.
+ FIXME: There should be an easier way to do this, no? tiemann 9/9/95. */
+ struct rs6000_framedata fdata;
+
int ii;
target_fetch_registers (-1);
pc = read_register(PC_REGNUM);
store_address (pc_targ, 4, pc);
+ (void) skip_prologue (get_pc_function_start (pc) + FUNCTION_START_OFFSET, &fdata);
+
dummy_frame_addr [dummy_frame_count++] = sp;
/* Be careful! If the stack pointer is not decremented first, then kernel
before writing register values into the new frame, decrement and update
%sp first in order to secure your frame. */
+ /* FIXME: We don't check if the stack really has this much space.
+ This is a problem on the ppc simulator (which only grants one page
+ (4096 bytes) by default. */
+
write_register (SP_REGNUM, sp-DUMMY_FRAME_SIZE);
/* gdb relies on the state of current_frame. We'd better update it,
flush_cached_frames ();
/* save program counter in link register's space. */
- write_memory (sp+8, pc_targ, 4);
+ write_memory (sp + (fdata.lr_offset ? fdata.lr_offset : DEFAULT_LR_SAVE),
+ pc_targ, 4);
/* save all floating point and general purpose registers here. */
GDB process that keeps track of these dummy frames! -- gnu@cygnus.com Aug92
*/
+static void
pop_dummy_frame ()
{
CORE_ADDR sp, pc;
®isters[REGISTER_BYTE (FPLAST_REGNUM + ii)], 4);
read_memory (sp-(DUMMY_FRAME_SIZE-8),
- ®isters [REGISTER_BYTE(PC_REGNUM)], 4);
+ ®isters [REGISTER_BYTE(PC_REGNUM)], 4);
/* when a dummy frame was being pushed, we had to decrement %sp first, in
order to secure astack space. Thus, saved %sp (or %r1) value, is not the
its argumets will be passed by gdb. */
void
-fix_call_dummy(dummyname, pc, fun, nargs, type)
- char *dummyname;
- CORE_ADDR pc;
- CORE_ADDR fun;
- int nargs; /* not used */
- int type; /* not used */
+rs6000_fix_call_dummy (dummyname, pc, fun, nargs, args, type, gcc_p)
+ char *dummyname;
+ CORE_ADDR pc;
+ CORE_ADDR fun;
+ int nargs;
+ value_ptr *args;
+ struct type *type;
+ int gcc_p;
{
#define TOC_ADDR_OFFSET 20
#define TARGET_ADDR_OFFSET 28
int ii;
CORE_ADDR target_addr;
- CORE_ADDR tocvalue;
- target_addr = fun;
- tocvalue = find_toc_address (target_addr);
+ if (find_toc_address_hook != NULL)
+ {
+ CORE_ADDR tocvalue;
- ii = *(int*)((char*)dummyname + TOC_ADDR_OFFSET);
- ii = (ii & 0xffff0000) | (tocvalue >> 16);
- *(int*)((char*)dummyname + TOC_ADDR_OFFSET) = ii;
+ tocvalue = (*find_toc_address_hook) (fun);
+ 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 + TOC_ADDR_OFFSET+4);
+ ii = (ii & 0xffff0000) | (tocvalue & 0x0000ffff);
+ *(int*)((char*)dummyname + TOC_ADDR_OFFSET+4) = ii;
+ }
+ target_addr = fun;
ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET);
ii = (ii & 0xffff0000) | (target_addr >> 16);
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET) = ii;
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4) = ii;
}
-/* 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
+/* 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,
+ in r3, then the first 7 words of the parameters can be passed in registers,
starting from r4. */
CORE_ADDR
push_arguments (nargs, args, sp, struct_return, struct_addr)
- int nargs;
- value_ptr *args;
- CORE_ADDR sp;
- int struct_return;
- CORE_ADDR struct_addr;
+ int nargs;
+ value_ptr *args;
+ CORE_ADDR sp;
+ int struct_return;
+ CORE_ADDR struct_addr;
{
- int ii, len;
+ int ii;
+ int len = 0;
int argno; /* current argument number */
int argbytes; /* current argument byte */
char tmp_buffer [50];
- value_ptr arg;
int f_argno = 0; /* current floating point argno */
+ value_ptr arg = 0;
+ struct type *type;
- CORE_ADDR saved_sp, pc;
+ CORE_ADDR saved_sp;
if ( dummy_frame_count <= 0)
printf_unfiltered ("FATAL ERROR -push_arguments()! frame not found!!\n");
for (argno=0, argbytes=0; argno < nargs && ii<8; ++ii) {
arg = args[argno];
- len = TYPE_LENGTH (VALUE_TYPE (arg));
+ type = check_typedef (VALUE_TYPE (arg));
+ len = TYPE_LENGTH (type);
- if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FLT) {
+ if (TYPE_CODE (type) == 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
if ((argno < nargs) || argbytes) {
int space = 0, jj;
- value_ptr val;
if (argbytes) {
space += ((len - argbytes + 3) & -4);
jj = argno;
for (; jj < nargs; ++jj) {
- val = args[jj];
+ value_ptr val = args[jj];
space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
}
for (; argno < nargs; ++argno) {
arg = args[argno];
- len = TYPE_LENGTH (VALUE_TYPE (arg));
+ type = check_typedef (VALUE_TYPE (arg));
+ len = TYPE_LENGTH (type);
/* 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 (TYPE_CODE (type) == TYPE_CODE_FLT && f_argno < 13) {
if (len > 8)
printf_unfiltered (
void
extract_return_value (valtype, regbuf, valbuf)
- struct type *valtype;
- char regbuf[REGISTER_BYTES];
- char *valbuf;
+ struct type *valtype;
+ char regbuf[REGISTER_BYTES];
+ char *valbuf;
{
int offset = 0;
CORE_ADDR
skip_trampoline_code (pc)
-CORE_ADDR pc;
+ CORE_ADDR pc;
{
register unsigned int ii, op;
CORE_ADDR solib_target_pc;
return pc;
}
-
/* Determines whether the function FI has a frame on the stack or not. */
+
int
frameless_function_invocation (fi)
struct frame_info *fi;
CORE_ADDR func_start;
struct rs6000_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). */
+ /* Don't even think about framelessness except on the innermost frame
+ or if the function was interrupted by a signal. */
+ if (fi->next != NULL && !fi->next->signal_handler_caller)
return 0;
- func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
+ func_start = get_pc_function_start (fi->pc);
/* If we failed to find the start of the function, it is a mistake
to inspect the instructions. */
if (!func_start)
- return 0;
+ {
+ /* A frame with a zero PC is usually created by dereferencing a NULL
+ function pointer, normally causing an immediate core dump of the
+ inferior. Mark function as frameless, as the inferior has no chance
+ of setting up a stack frame. */
+ if (fi->pc == 0)
+ return 1;
+ else
+ return 0;
+ }
+ func_start += FUNCTION_START_OFFSET;
(void) skip_prologue (func_start, &fdata);
return fdata.frameless;
}
/* Return the PC saved in a frame */
+
unsigned long
frame_saved_pc (fi)
struct frame_info *fi;
{
CORE_ADDR func_start;
struct rs6000_framedata fdata;
- int frameless;
if (fi->signal_handler_caller)
return read_memory_integer (fi->frame + SIG_FRAME_PC_OFFSET, 4);
(void) skip_prologue (func_start, &fdata);
if (fdata.lr_offset == 0 && fi->next != NULL)
- return read_memory_integer (rs6000_frame_chain (fi) + DEFAULT_LR_SAVE, 4);
+ {
+ if (fi->next->signal_handler_caller)
+ return read_memory_integer (fi->next->frame + SIG_FRAME_LR_OFFSET, 4);
+ else
+ return read_memory_integer (rs6000_frame_chain (fi) + DEFAULT_LR_SAVE,
+ 4);
+ }
if (fdata.lr_offset == 0)
return read_register (LR_REGNUM);
return 0;
if (thisframe->signal_handler_caller)
fp = read_memory_integer (thisframe->frame + SIG_FRAME_FP_OFFSET, 4);
+ else if (thisframe->next != NULL
+ && thisframe->next->signal_handler_caller
+ && frameless_function_invocation (thisframe))
+ /* A frameless function interrupted by a signal did not change the
+ frame pointer. */
+ fp = FRAME_FP (thisframe);
else
fp = read_memory_integer ((thisframe)->frame, 4);
return fp;
}
\f
-/* 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. */
-
-struct loadinfo {
- CORE_ADDR textorg, dataorg;
- unsigned long toc_offset;
-};
-
-#define LOADINFOLEN 10
-
-static struct loadinfo *loadinfo = NULL;
-static int loadinfolen = 0;
-static int loadinfotocindex = 0;
-static int loadinfotextindex = 0;
-
-
-void
-xcoff_init_loadinfo ()
-{
- loadinfotocindex = 0;
- loadinfotextindex = 0;
-
- if (loadinfolen == 0) {
- loadinfo = (struct loadinfo *)
- xmalloc (sizeof (struct loadinfo) * LOADINFOLEN);
- loadinfolen = LOADINFOLEN;
- }
-}
-
-
-/* FIXME -- this is never called! */
-void
-free_loadinfo ()
-{
- if (loadinfo)
- free (loadinfo);
- loadinfo = NULL;
- loadinfolen = 0;
- loadinfotocindex = 0;
- loadinfotextindex = 0;
-}
-
-/* this is called from xcoffread.c */
+/* Return nonzero if ADDR (a function pointer) is in the data space and
+ is therefore a special function pointer. */
-void
-xcoff_add_toc_to_loadinfo (tocoff)
- unsigned long tocoff;
-{
- while (loadinfotocindex >= loadinfolen) {
- loadinfolen += LOADINFOLEN;
- loadinfo = (struct loadinfo *)
- xrealloc (loadinfo, sizeof(struct loadinfo) * loadinfolen);
- }
- loadinfo [loadinfotocindex++].toc_offset = tocoff;
-}
-
-void
-add_text_to_loadinfo (textaddr, dataaddr)
- CORE_ADDR textaddr;
- CORE_ADDR dataaddr;
-{
- while (loadinfotextindex >= loadinfolen) {
- loadinfolen += LOADINFOLEN;
- loadinfo = (struct loadinfo *)
- xrealloc (loadinfo, sizeof(struct loadinfo) * loadinfolen);
- }
- loadinfo [loadinfotextindex].textorg = textaddr;
- loadinfo [loadinfotextindex].dataorg = dataaddr;
- ++loadinfotextindex;
-}
-
-
-/* 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. 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)
- CORE_ADDR pc;
+int
+is_magic_function_pointer (addr)
+ CORE_ADDR addr;
{
- int ii, toc_entry, tocbase = 0;
+ struct obj_section *s;
- for (ii=0; ii < loadinfotextindex; ++ii)
- if (pc > loadinfo[ii].textorg && loadinfo[ii].textorg > tocbase) {
- toc_entry = ii;
- tocbase = loadinfo[ii].textorg;
- }
-
- return loadinfo[toc_entry].dataorg + loadinfo[toc_entry].toc_offset;
+ s = find_pc_section (addr);
+ if (s && s->the_bfd_section->flags & SEC_CODE)
+ return 0;
+ else
+ return 1;
}
#ifdef GDB_TARGET_POWERPC