/* Target-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h"
#include "symtab.h"
#include "target.h"
+#include "gdbcore.h"
+
+#include "xcoffsolib.h"
#include <sys/param.h>
#include <sys/dir.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 struct obstack frame_cache_obstack;
extern int errno;
-extern int attach_flag;
/* Nonzero if we just simulated a single step break. */
int one_stepped;
-
/* Breakpoint shadows for the single step instructions will be kept here. */
static struct sstep_breaks {
- int address;
- int data;
+ /* Address, or 0 if this is not in use. */
+ CORE_ADDR address;
+ /* Shadow contents. */
+ char data[4];
} stepBreaks[2];
+/* 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 void
+frame_get_cache_fsr PARAMS ((struct frame_info *fi,
+ struct aix_framedata *fdatap));
/*
* Calculate the destination of a branch/jump. Return -1 if not a branch.
*/
-static int
+static CORE_ADDR
branch_dest (opcode, instr, pc, safety)
- int opcode, instr, pc, safety;
+ int opcode;
+ int instr;
+ CORE_ADDR pc;
+ CORE_ADDR safety;
{
register long offset;
- unsigned dest;
+ CORE_ADDR dest;
int immediate;
int absolute;
int ext_op;
switch (opcode) {
case 18 :
- immediate = ((instr & ~3) << 6) >> 6; /* br unconditionl */
+ immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */
case 16 :
if (opcode != 18) /* br conditional */
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;
/* AIX does not support PT_STEP. Simulate it. */
-int
+void
single_step (signal)
-int signal;
+ int signal;
{
#define INSNLEN(OPCODE) 4
static char breakp[] = BREAKPOINT;
- int ii, insn, ret, loc;
- int breaks[2], opcode;
+ int ii, insn;
+ CORE_ADDR loc;
+ CORE_ADDR breaks[2];
+ int 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");
+ read_memory (loc, (char *) &insn, 4);
breaks[0] = loc + INSNLEN(insn);
opcode = insn >> 26;
if (breaks[1] == breaks[0])
breaks[1] = -1;
- stepBreaks[1].address = -1;
+ stepBreaks[1].address = 0;
for (ii=0; ii < 2; ++ii) {
if ( breaks[ii] == -1)
continue;
- read_memory (breaks[ii], &(stepBreaks[ii].data), sizeof(int));
+ read_memory (breaks[ii], stepBreaks[ii].data, 4);
- ret = write_memory (breaks[ii], breakp, sizeof(int));
+ write_memory (breaks[ii], breakp, 4);
stepBreaks[ii].address = breaks[ii];
}
one_stepped = 1;
- ptrace (PT_CONTINUE, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal, 0);
- }
- else {
+ } else {
/* remove step breakpoints. */
for (ii=0; ii < 2; ++ii)
- if (stepBreaks[ii].address != -1)
+ if (stepBreaks[ii].address != 0)
write_memory
- (stepBreaks[ii].address, &(stepBreaks[ii].data), sizeof(int));
+ (stepBreaks[ii].address, stepBreaks[ii].data, 4);
one_stepped = 0;
}
- errno = 0;
- return 1;
+ errno = 0; /* FIXME, don't ignore errors! */
+ /* What errors? {read,write}_memory call error(). */
}
/* return pc value after skipping a function prologue. */
skip_prologue (pc)
-int pc;
+CORE_ADDR pc;
{
unsigned int tmp;
- unsigned int op;
+ unsigned int op; /* FIXME, assumes instruction size matches host int!!! */
if (target_read_memory (pc, (char *)&op, sizeof (op)))
return pc; /* Can't access it -- assume no prologue. */
return pc - 4; /* don't skip over this branch */
}
+ 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) */
+ (tmp == 0x93e1)) /* st r31,NUM(r1) */
{
pc += 4;
op = read_memory_integer (pc, 4);
function as well. */
tmp = find_pc_misc_function (pc);
- if (tmp >= 0 && !strcmp (misc_function_vector [tmp].name, "main"))
+ if (tmp >= 0 && STREQ (misc_function_vector [tmp].name, "main"))
return pc + 8;
}
}
}
-/* 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.
/* 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 */
+void
push_dummy_frame ()
{
- int sp, pc; /* stack pointer and link register */
+ /* stack pointer. */
+ CORE_ADDR sp;
+
+ /* link register. */
+ CORE_ADDR pc;
+ /* Same thing, target byte order. */
+ char pc_targ[4];
+
int ii;
- fetch_inferior_registers (-1);
+ target_fetch_registers (-1);
if (dummy_frame_count >= dummy_frame_size) {
dummy_frame_size += DUMMY_FRAME_ADDR_SIZE;
}
sp = read_register(SP_REGNUM);
- pc = read_register(PC_REGNUM);
+ pc = read_register(PC_REGNUM);
+ memcpy (pc_targ, (char *) &pc, 4);
dummy_frame_addr [dummy_frame_count++] = sp;
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. */
sp -= DUMMY_FRAME_SIZE;
/* And finally, this is the back chain. */
- write_memory (sp+8, &pc, 4);
+ write_memory (sp+8, pc_targ, 4);
}
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).
+
+FIXME: This whole concept is broken. You should be able to detect
+a dummy stack frame *on the user's stack itself*. When you do,
+then you know the format of that stack frame -- including its
+saved SP register! There should *not* be a separate stack in the
*/
pop_dummy_frame ()
/* Now we can restore all registers. */
- store_inferior_registers (-1);
+ target_store_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. */
+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 ();
int addr, ii;
addr = get_pc_function_start (fr->pc) + FUNCTION_START_OFFSET;
function_frame_info (addr, &fdata);
- read_memory (sp, &prev_sp, 4);
+ prev_sp = read_memory_integer (sp, 4);
if (fdata.frameless)
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);
if (fdata.saved_gpr != -1)
for (ii=fdata.saved_gpr; ii <= 31; ++ii) {
read_memory (addr, ®isters [REGISTER_BYTE (ii)], 4);
- addr += sizeof (int);
+ addr += 4;
}
if (fdata.saved_fpr != -1)
}
write_register (SP_REGNUM, prev_sp);
- store_inferior_registers (-1);
+ 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. */
+void
fix_call_dummy(dummyname, pc, fun, nargs, type)
char *dummyname;
- int pc;
- int fun;
+ CORE_ADDR pc;
+ CORE_ADDR 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;
+ CORE_ADDR target_addr;
+ CORE_ADDR tocvalue;
target_addr = fun;
tocvalue = find_toc_address (target_addr);
}
-
/* return information about a function frame.
in struct aix_frameinfo fdata:
- - frameless is TRUE, if function does not save %pc value in its frame.
+ - frameless is TRUE, if function does not have a frame.
+ - nosavedpc 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.
- alloca_reg is the number of the register used for alloca() handling.
Otherwise -1.
*/
+void
function_frame_info (pc, fdata)
- int pc;
+ CORE_ADDR pc;
struct aix_framedata *fdata;
{
unsigned int tmp;
fdata->offset = 0;
fdata->saved_gpr = fdata->saved_fpr = fdata->alloca_reg = -1;
+ fdata->frameless = 1;
op = read_memory_integer (pc, 4);
if (op == 0x7c0802a6) { /* mflr r0 */
pc += 4;
op = read_memory_integer (pc, 4);
+ fdata->nosavedpc = 0;
fdata->frameless = 0;
}
- else /* else, this is a frameless invocation */
- fdata->frameless = 1;
-
+ else /* else, pc is not saved */
+ fdata->nosavedpc = 1;
if ((op & 0xfc00003e) == 0x7c000026) { /* mfcr Rx */
pc += 4;
op = read_memory_integer (pc, 4);
+ fdata->frameless = 0;
}
if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
if (op == 0x4def7b82 || /* crorc 15, 15, 15 */
op == 0x0)
return; /* prologue is over */
+ fdata->frameless = 0;
}
if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
pc += 4; /* store floating register double */
op = read_memory_integer (pc, 4);
+ fdata->frameless = 0;
}
if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
fdata->saved_gpr = (op >> 21) & 0x1f;
tmp2 = op & 0xffff;
if (tmp2 > 0x7fff)
- tmp2 = 0xffff0000 | tmp2;
+ tmp2 = (~0 &~ 0xffff) | tmp2;
if (tmp2 < 0) {
tmp2 = tmp2 * -1;
fdata->offset = tmp2;
pc += 4;
op = read_memory_integer (pc, 4);
+ fdata->frameless = 0;
}
while (((tmp = op >> 16) == 0x9001) || /* st r0, NUM(r1) */
(tmp == 0x9421) || /* stu r1, NUM(r1) */
- (op == 0x93e1fffc)) /* st r31,-4(r1) */
+ (tmp == 0x93e1)) /* st r31, NUM(r1) */
{
+ int tmp2;
+
/* gcc takes a short cut and uses this instruction to save r31 only. */
- if (op == 0x93e1fffc) {
+ if (tmp == 0x93e1) {
if (fdata->offset)
/* fatal ("Unrecognized prolog."); */
printf ("Unrecognized prolog!\n");
fdata->saved_gpr = 31;
- fdata->offset = 4;
+ tmp2 = op & 0xffff;
+ if (tmp2 > 0x7fff) {
+ tmp2 = - ((~0 &~ 0xffff) | tmp2);
+ fdata->saved_fpr = (tmp2 - ((32 - 31) * 4)) / 8;
+ if ( fdata->saved_fpr > 0)
+ fdata->saved_fpr = 32 - fdata->saved_fpr;
+ else
+ fdata->saved_fpr = -1;
+ }
+ fdata->offset = tmp2;
}
pc += 4;
op = read_memory_integer (pc, 4);
+ fdata->frameless = 0;
}
while ((tmp = (op >> 22)) == 0x20f) { /* l r31, ... or */
pc += 4; /* l r30, ... */
op = read_memory_integer (pc, 4);
+ fdata->frameless = 0;
}
/* store parameters into stack */
{
pc += 4; /* store fpr double */
op = read_memory_integer (pc, 4);
+ fdata->frameless = 0;
}
- if (op == 0x603f0000) /* oril r31, r1, 0x0 */
+ if (op == 0x603f0000) { /* oril r31, r1, 0x0 */
fdata->alloca_reg = 31;
+ fdata->frameless = 0;
+ }
}
++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;
}
}
write_memory (sp, &saved_sp, 4); /* set back chain properly */
- store_inferior_registers (-1);
+ target_store_registers (-1);
return sp;
}
/* a given return value in `regbuf' with a type `valtype', extract and copy its
value into `valbuf' */
+void
extract_return_value (valtype, regbuf, valbuf)
struct type *valtype;
char regbuf[REGISTER_BYTES];
}
-/* keep keep structure return address in this variable. */
+/* keep structure return address in this variable.
+ FIXME: This is a horrid kludge which should not be allowed to continue
+ living. This only allows a single nested call to a structure-returning
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 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).
Result is desired PC to step until, or NULL if we are not in
trampoline code. */
+CORE_ADDR
skip_trampoline_code (pc)
-int pc;
+CORE_ADDR pc;
{
register unsigned int ii, op;
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 */
return pc;
}
+
+/* Determines whether the function FI has a frame on the stack or not.
+ Called from the FRAMELESS_FUNCTION_INVOCATION macro in tm.h with a
+ second argument of 0, and from the FRAME_SAVED_PC macro with a
+ second argument of 1. */
+
+int
+frameless_function_invocation (fi, pcsaved)
+struct frame_info *fi;
+int pcsaved;
+{
+ CORE_ADDR func_start;
+ struct aix_framedata fdata;
+
+ if (fi->next != NULL)
+ /* Don't even think about framelessness except on the innermost frame. */
+ 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
+ to inspect the instructions. */
+
+ if (!func_start)
+ return 0;
+
+ function_frame_info (func_start, &fdata);
+ return pcsaved ? fdata.nosavedpc : fdata.frameless;
+}
+
+
+/* If saved registers of frame FI are not known yet, read and cache them.
+ &FDATAP contains aix_framedata; TDATAP can be NULL,
+ in which case the framedata are read. */
+
+static void
+frame_get_cache_fsr (fi, fdatap)
+ struct frame_info *fi;
+ struct aix_framedata *fdatap;
+{
+ int ii;
+ CORE_ADDR frame_addr;
+ struct aix_framedata work_fdata;
+
+ if (fi->cache_fsr)
+ return;
+
+ if (fdatap == NULL) {
+ fdatap = &work_fdata;
+ function_frame_info (get_pc_function_start (fi->pc), fdatap);
+ }
+
+ 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));
+
+ if (fi->prev && fi->prev->frame)
+ frame_addr = fi->prev->frame;
+ else
+ frame_addr = read_memory_integer (fi->frame, 4);
+
+ /* if != -1, fdatap->saved_fpr is the smallest number of saved_fpr.
+ All fpr's from saved_fpr to fp31 are saved right underneath caller
+ stack pointer, starting from fp31 first. */
+
+ if (fdatap->saved_fpr >= 0) {
+ for (ii=31; ii >= fdatap->saved_fpr; --ii)
+ fi->cache_fsr->regs [FP0_REGNUM + ii] = frame_addr - ((32 - ii) * 8);
+ frame_addr -= (32 - fdatap->saved_fpr) * 8;
+ }
+
+ /* if != -1, fdatap->saved_gpr is the smallest number of saved_gpr.
+ All gpr's from saved_gpr to gpr31 are saved right under saved fprs,
+ starting from r31 first. */
+
+ if (fdatap->saved_gpr >= 0)
+ for (ii=31; ii >= fdatap->saved_gpr; --ii)
+ fi->cache_fsr->regs [ii] = frame_addr - ((32 - ii) * 4);
+}
+
+/* Return the address of a frame. This is the inital %sp value when the frame
+ was first allocated. For functions calling alloca(), it might be saved in
+ an alloca register. */
+
+CORE_ADDR
+frame_initial_stack_address (fi)
+ struct frame_info *fi;
+{
+ CORE_ADDR tmpaddr;
+ struct aix_framedata fdata;
+ struct frame_info *callee_fi;
+
+ /* if the initial stack pointer (frame address) of this frame is known,
+ just return it. */
+
+ if (fi->initial_sp)
+ return fi->initial_sp;
+
+ /* find out if this function is using an alloca register.. */
+
+ function_frame_info (get_pc_function_start (fi->pc), &fdata);
+
+ /* if saved registers of this frame are not known yet, read and cache them. */
+
+ if (!fi->cache_fsr)
+ frame_get_cache_fsr (fi, &fdata);
+
+ /* If no alloca register used, then fi->frame is the value of the %sp for
+ this frame, and it is good enough. */
+
+ if (fdata.alloca_reg < 0) {
+ fi->initial_sp = fi->frame;
+ return fi->initial_sp;
+ }
+
+ /* This function has an alloca register. If this is the top-most frame
+ (with the lowest address), the value in alloca register is good. */
+
+ if (!fi->next)
+ return fi->initial_sp = read_register (fdata.alloca_reg);
+
+ /* Otherwise, this is a caller frame. Callee has usually already saved
+ registers, but there are exceptions (such as when the callee
+ has no parameters). Find the address in which caller's alloca
+ register is saved. */
+
+ for (callee_fi = fi->next; callee_fi; callee_fi = callee_fi->next) {
+
+ if (!callee_fi->cache_fsr)
+ frame_get_cache_fsr (callee_fi, NULL);
+
+ /* this is the address in which alloca register is saved. */
+
+ tmpaddr = callee_fi->cache_fsr->regs [fdata.alloca_reg];
+ if (tmpaddr) {
+ fi->initial_sp = read_memory_integer (tmpaddr, 4);
+ return fi->initial_sp;
+ }
+
+ /* Go look into deeper levels of the frame chain to see if any one of
+ the callees has saved alloca register. */
+ }
+
+ /* If alloca register was not saved, by the callee (or any of its callees)
+ then the value in the register is still good. */
+
+ return fi->initial_sp = read_register (fdata.alloca_reg);
+}
+
+FRAME_ADDR
+rs6000_frame_chain (thisframe)
+ struct frame_info *thisframe;
+{
+ FRAME_ADDR fp;
+ if (inside_entry_file ((thisframe)->pc))
+ return 0;
+ if (thisframe->signal_handler_caller)
+ {
+ /* This was determined by experimentation on AIX 3.2. Perhaps
+ it corresponds to some offset in /usr/include/sys/user.h or
+ something like that. Using some system include file would
+ have the advantage of probably being more robust in the face
+ of OS upgrades, but the disadvantage of being wrong for
+ cross-debugging. */
+
+#define SIG_FRAME_FP_OFFSET 284
+ fp = read_memory_integer (thisframe->frame + SIG_FRAME_FP_OFFSET, 4);
+ }
+ else
+ fp = read_memory_integer ((thisframe)->frame, 4);
+
+ return fp;
+}
+
+\f
+/* xcoff_relocate_symtab - hook for symbol table relocation.
+ also reads shared libraries.. */
+
+xcoff_relocate_symtab (pid)
+unsigned int pid;
+{
+#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 {
+ /* We are allowed to assume CORE_ADDR == pointer. This code is
+ native only. */
+ add_text_to_loadinfo ((CORE_ADDR) ldi->ldinfo_textorg,
+ (CORE_ADDR) 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
+
+ /* relocate the exec and core sections as well. */
+ vmap_exec ();
+}
+\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 */
+
+void
+xcoff_add_toc_to_loadinfo (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;
+}
+
+
+/* FIXME: 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! */
+
+static CORE_ADDR
+find_toc_address (pc)
+ CORE_ADDR pc;
+{
+ int ii, toc_entry, tocbase = 0;
+
+ 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;
+}