Browse Source
* solib-irix.c: ...to here. Revised substantially to work with generic solib framework.drow-cplus-branch
3 changed files with 732 additions and 1047 deletions
File diff suppressed because it is too large
@ -0,0 +1,725 @@ |
|||
/* Shared library support for IRIX.
|
|||
Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 |
|||
Free Software Foundation, Inc. |
|||
|
|||
This file was created using portions of irix5-nat.c originally |
|||
contributed to GDB by Ian Lance Taylor. |
|||
|
|||
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., 59 Temple Place - Suite 330, |
|||
Boston, MA 02111-1307, USA. */ |
|||
|
|||
#include "defs.h" |
|||
|
|||
#include "symtab.h" |
|||
#include "bfd.h" |
|||
#include "symfile.h" |
|||
#include "objfiles.h" |
|||
#include "gdbcore.h" |
|||
#include "target.h" |
|||
#include "inferior.h" |
|||
|
|||
#include "solist.h" |
|||
|
|||
/* Link map info to include in an allocate so_list entry. Unlike some
|
|||
of the other solib backends, this (Irix) backend chooses to decode |
|||
the link map info obtained from the target and store it as (mostly) |
|||
CORE_ADDRs which need no further decoding. This is more convenient |
|||
because there are three different link map formats to worry about. |
|||
We use a single routine (fetch_lm_info) to read (and decode) the target |
|||
specific link map data. */ |
|||
|
|||
struct lm_info |
|||
{ |
|||
CORE_ADDR addr; /* address of obj_info or obj_list
|
|||
struct on target (from which the |
|||
following information is obtained). */ |
|||
CORE_ADDR next; /* address of next item in list. */ |
|||
CORE_ADDR reloc_offset; /* amount to relocate by */ |
|||
CORE_ADDR pathname_addr; /* address of pathname */ |
|||
int pathname_len; /* length of pathname */ |
|||
}; |
|||
|
|||
/* It's not desirable to use the system header files to obtain the
|
|||
structure of the obj_list or obj_info structs. Therefore, we use a |
|||
platform neutral representation which has been derived from the IRIX |
|||
header files. */ |
|||
|
|||
typedef struct |
|||
{ |
|||
char b[4]; |
|||
} |
|||
gdb_int32_bytes; |
|||
typedef struct |
|||
{ |
|||
char b[8]; |
|||
} |
|||
gdb_int64_bytes; |
|||
|
|||
/* The "old" obj_list struct. This is used with old (o32) binaries.
|
|||
The ``data'' member points at a much larger and more complicated |
|||
struct which we will only refer to by offsets. See |
|||
fetch_lm_info(). */ |
|||
|
|||
struct irix_obj_list |
|||
{ |
|||
gdb_int32_bytes data; |
|||
gdb_int32_bytes next; |
|||
gdb_int32_bytes prev; |
|||
}; |
|||
|
|||
/* The ELF32 and ELF64 versions of the above struct. The oi_magic value
|
|||
corresponds to the ``data'' value in the "old" struct. When this value |
|||
is 0xffffffff, the data will be in one of the following formats. The |
|||
``oi_size'' field is used to decide which one we actually have. */ |
|||
|
|||
struct irix_elf32_obj_info |
|||
{ |
|||
gdb_int32_bytes oi_magic; |
|||
gdb_int32_bytes oi_size; |
|||
gdb_int32_bytes oi_next; |
|||
gdb_int32_bytes oi_prev; |
|||
gdb_int32_bytes oi_ehdr; |
|||
gdb_int32_bytes oi_orig_ehdr; |
|||
gdb_int32_bytes oi_pathname; |
|||
gdb_int32_bytes oi_pathname_len; |
|||
}; |
|||
|
|||
struct irix_elf64_obj_info |
|||
{ |
|||
gdb_int32_bytes oi_magic; |
|||
gdb_int32_bytes oi_size; |
|||
gdb_int64_bytes oi_next; |
|||
gdb_int64_bytes oi_prev; |
|||
gdb_int64_bytes oi_ehdr; |
|||
gdb_int64_bytes oi_orig_ehdr; |
|||
gdb_int64_bytes oi_pathname; |
|||
gdb_int32_bytes oi_pathname_len; |
|||
gdb_int32_bytes padding; |
|||
}; |
|||
|
|||
/* Union of all of the above (plus a split out magic field). */ |
|||
|
|||
union irix_obj_info |
|||
{ |
|||
gdb_int32_bytes magic; |
|||
struct irix_obj_list ol32; |
|||
struct irix_elf32_obj_info oi32; |
|||
struct irix_elf64_obj_info oi64; |
|||
}; |
|||
|
|||
/* MIPS sign extends its 32 bit addresses. We could conceivably use
|
|||
extract_typed_address here, but to do so, we'd have to construct an |
|||
appropriate type. Calling extract_signed_integer or |
|||
extract_address seems simpler. */ |
|||
|
|||
static CORE_ADDR |
|||
extract_mips_address (void *addr, int len) |
|||
{ |
|||
if (len <= 32) |
|||
return extract_signed_integer (addr, len); |
|||
else |
|||
return extract_address (addr, len); |
|||
} |
|||
|
|||
/* Fetch and return the link map data associated with ADDR. Note that
|
|||
this routine automatically determines which (of three) link map |
|||
formats is in use by the target. */ |
|||
|
|||
struct lm_info |
|||
fetch_lm_info (CORE_ADDR addr) |
|||
{ |
|||
struct lm_info li; |
|||
union irix_obj_info buf; |
|||
|
|||
li.addr = addr; |
|||
|
|||
/* The smallest region that we'll need is for buf.ol32. We'll read
|
|||
that first. We'll read more of the buffer later if we have to deal |
|||
with one of the other cases. (We don't want to incur a memory error |
|||
if we were to read a larger region that generates an error due to |
|||
being at the end of a page or the like.) */ |
|||
read_memory (addr, (char *) &buf, sizeof (buf.ol32)); |
|||
|
|||
if (extract_unsigned_integer (&buf.magic, sizeof (buf.magic)) != 0xffffffff) |
|||
{ |
|||
/* Use buf.ol32... */ |
|||
char obj_buf[432]; |
|||
CORE_ADDR obj_addr = extract_mips_address (&buf.ol32.data, |
|||
sizeof (buf.ol32.data)); |
|||
li.next = extract_mips_address (&buf.ol32.next, sizeof (buf.ol32.next)); |
|||
|
|||
read_memory (obj_addr, obj_buf, sizeof (obj_buf)); |
|||
|
|||
li.pathname_addr = extract_mips_address (&obj_buf[236], 4); |
|||
li.pathname_len = 0; /* unknown */ |
|||
li.reloc_offset = extract_mips_address (&obj_buf[196], 4) |
|||
- extract_mips_address (&obj_buf[248], 4); |
|||
|
|||
} |
|||
else if (extract_unsigned_integer (&buf.oi32.oi_size, |
|||
sizeof (buf.oi32.oi_size)) |
|||
== sizeof (buf.oi32)) |
|||
{ |
|||
/* Use buf.oi32... */ |
|||
|
|||
/* Read rest of buffer. */ |
|||
read_memory (addr + sizeof (buf.ol32), |
|||
((char *) &buf) + sizeof (buf.ol32), |
|||
sizeof (buf.oi32) - sizeof (buf.ol32)); |
|||
|
|||
/* Fill in fields using buffer contents. */ |
|||
li.next = extract_mips_address (&buf.oi32.oi_next, |
|||
sizeof (buf.oi32.oi_next)); |
|||
li.reloc_offset = extract_mips_address (&buf.oi32.oi_ehdr, |
|||
sizeof (buf.oi32.oi_ehdr)) |
|||
- extract_mips_address (&buf.oi32.oi_orig_ehdr, |
|||
sizeof (buf.oi32.oi_orig_ehdr)); |
|||
li.pathname_addr = extract_mips_address (&buf.oi32.oi_pathname, |
|||
sizeof (buf.oi32.oi_pathname)); |
|||
li.pathname_len = extract_unsigned_integer (&buf.oi32.oi_pathname_len, |
|||
sizeof (buf.oi32. |
|||
oi_pathname_len)); |
|||
} |
|||
else if (extract_unsigned_integer (&buf.oi64.oi_size, |
|||
sizeof (buf.oi64.oi_size)) |
|||
== sizeof (buf.oi64)) |
|||
{ |
|||
/* Use buf.oi64... */ |
|||
|
|||
/* Read rest of buffer. */ |
|||
read_memory (addr + sizeof (buf.ol32), |
|||
((char *) &buf) + sizeof (buf.ol32), |
|||
sizeof (buf.oi64) - sizeof (buf.ol32)); |
|||
|
|||
/* Fill in fields using buffer contents. */ |
|||
li.next = extract_mips_address (&buf.oi64.oi_next, |
|||
sizeof (buf.oi64.oi_next)); |
|||
li.reloc_offset = extract_mips_address (&buf.oi64.oi_ehdr, |
|||
sizeof (buf.oi64.oi_ehdr)) |
|||
- extract_mips_address (&buf.oi64.oi_orig_ehdr, |
|||
sizeof (buf.oi64.oi_orig_ehdr)); |
|||
li.pathname_addr = extract_mips_address (&buf.oi64.oi_pathname, |
|||
sizeof (buf.oi64.oi_pathname)); |
|||
li.pathname_len = extract_unsigned_integer (&buf.oi64.oi_pathname_len, |
|||
sizeof (buf.oi64. |
|||
oi_pathname_len)); |
|||
} |
|||
else |
|||
{ |
|||
error ("Unable to fetch shared library obj_info or obj_list info."); |
|||
} |
|||
|
|||
return li; |
|||
} |
|||
|
|||
/* The symbol which starts off the list of shared libraries. */ |
|||
#define DEBUG_BASE "__rld_obj_head" |
|||
|
|||
char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ |
|||
|
|||
static CORE_ADDR debug_base; /* Base of dynamic linker structures */ |
|||
static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ |
|||
|
|||
/*
|
|||
|
|||
LOCAL FUNCTION |
|||
|
|||
locate_base -- locate the base address of dynamic linker structs |
|||
|
|||
SYNOPSIS |
|||
|
|||
CORE_ADDR locate_base (void) |
|||
|
|||
DESCRIPTION |
|||
|
|||
For both the SunOS and SVR4 shared library implementations, if the |
|||
inferior executable has been linked dynamically, there is a single |
|||
address somewhere in the inferior's data space which is the key to |
|||
locating all of the dynamic linker's runtime structures. This |
|||
address is the value of the symbol defined by the macro DEBUG_BASE. |
|||
The job of this function is to find and return that address, or to |
|||
return 0 if there is no such address (the executable is statically |
|||
linked for example). |
|||
|
|||
For SunOS, the job is almost trivial, since the dynamic linker and |
|||
all of it's structures are statically linked to the executable at |
|||
link time. Thus the symbol for the address we are looking for has |
|||
already been added to the minimal symbol table for the executable's |
|||
objfile at the time the symbol file's symbols were read, and all we |
|||
have to do is look it up there. Note that we explicitly do NOT want |
|||
to find the copies in the shared library. |
|||
|
|||
The SVR4 version is much more complicated because the dynamic linker |
|||
and it's structures are located in the shared C library, which gets |
|||
run as the executable's "interpreter" by the kernel. We have to go |
|||
to a lot more work to discover the address of DEBUG_BASE. Because |
|||
of this complexity, we cache the value we find and return that value |
|||
on subsequent invocations. Note there is no copy in the executable |
|||
symbol tables. |
|||
|
|||
Irix 5 is basically like SunOS. |
|||
|
|||
Note that we can assume nothing about the process state at the time |
|||
we need to find this address. We may be stopped on the first instruc- |
|||
tion of the interpreter (C shared library), the first instruction of |
|||
the executable itself, or somewhere else entirely (if we attached |
|||
to the process for example). |
|||
|
|||
*/ |
|||
|
|||
static CORE_ADDR |
|||
locate_base (void) |
|||
{ |
|||
struct minimal_symbol *msymbol; |
|||
CORE_ADDR address = 0; |
|||
|
|||
msymbol = lookup_minimal_symbol (DEBUG_BASE, NULL, symfile_objfile); |
|||
if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) |
|||
{ |
|||
address = SYMBOL_VALUE_ADDRESS (msymbol); |
|||
} |
|||
return (address); |
|||
} |
|||
|
|||
/*
|
|||
|
|||
LOCAL FUNCTION |
|||
|
|||
disable_break -- remove the "mapping changed" breakpoint |
|||
|
|||
SYNOPSIS |
|||
|
|||
static int disable_break () |
|||
|
|||
DESCRIPTION |
|||
|
|||
Removes the breakpoint that gets hit when the dynamic linker |
|||
completes a mapping change. |
|||
|
|||
*/ |
|||
|
|||
static int |
|||
disable_break (void) |
|||
{ |
|||
int status = 1; |
|||
|
|||
|
|||
/* Note that breakpoint address and original contents are in our address
|
|||
space, so we just need to write the original contents back. */ |
|||
|
|||
if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) |
|||
{ |
|||
status = 0; |
|||
} |
|||
|
|||
/* For the SVR4 version, we always know the breakpoint address. For the
|
|||
SunOS version we don't know it until the above code is executed. |
|||
Grumble if we are stopped anywhere besides the breakpoint address. */ |
|||
|
|||
if (stop_pc != breakpoint_addr) |
|||
{ |
|||
warning |
|||
("stopped at unknown breakpoint while handling shared libraries"); |
|||
} |
|||
|
|||
return (status); |
|||
} |
|||
|
|||
/*
|
|||
|
|||
LOCAL FUNCTION |
|||
|
|||
enable_break -- arrange for dynamic linker to hit breakpoint |
|||
|
|||
SYNOPSIS |
|||
|
|||
int enable_break (void) |
|||
|
|||
DESCRIPTION |
|||
|
|||
This functions inserts a breakpoint at the entry point of the |
|||
main executable, where all shared libraries are mapped in. |
|||
*/ |
|||
|
|||
static int |
|||
enable_break (void) |
|||
{ |
|||
if (symfile_objfile != NULL |
|||
&& target_insert_breakpoint (symfile_objfile->ei.entry_point, |
|||
shadow_contents) == 0) |
|||
{ |
|||
breakpoint_addr = symfile_objfile->ei.entry_point; |
|||
return 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/*
|
|||
|
|||
LOCAL FUNCTION |
|||
|
|||
irix_solib_create_inferior_hook -- shared library startup support |
|||
|
|||
SYNOPSIS |
|||
|
|||
void solib_create_inferior_hook() |
|||
|
|||
DESCRIPTION |
|||
|
|||
When gdb starts up the inferior, it nurses it along (through the |
|||
shell) until it is ready to execute it's first instruction. At this |
|||
point, this function gets called via expansion of the macro |
|||
SOLIB_CREATE_INFERIOR_HOOK. |
|||
|
|||
For SunOS executables, this first instruction is typically the |
|||
one at "_start", or a similar text label, regardless of whether |
|||
the executable is statically or dynamically linked. The runtime |
|||
startup code takes care of dynamically linking in any shared |
|||
libraries, once gdb allows the inferior to continue. |
|||
|
|||
For SVR4 executables, this first instruction is either the first |
|||
instruction in the dynamic linker (for dynamically linked |
|||
executables) or the instruction at "start" for statically linked |
|||
executables. For dynamically linked executables, the system |
|||
first exec's /lib/libc.so.N, which contains the dynamic linker, |
|||
and starts it running. The dynamic linker maps in any needed |
|||
shared libraries, maps in the actual user executable, and then |
|||
jumps to "start" in the user executable. |
|||
|
|||
For both SunOS shared libraries, and SVR4 shared libraries, we |
|||
can arrange to cooperate with the dynamic linker to discover the |
|||
names of shared libraries that are dynamically linked, and the |
|||
base addresses to which they are linked. |
|||
|
|||
This function is responsible for discovering those names and |
|||
addresses, and saving sufficient information about them to allow |
|||
their symbols to be read at a later time. |
|||
|
|||
FIXME |
|||
|
|||
Between enable_break() and disable_break(), this code does not |
|||
properly handle hitting breakpoints which the user might have |
|||
set in the startup code or in the dynamic linker itself. Proper |
|||
handling will probably have to wait until the implementation is |
|||
changed to use the "breakpoint handler function" method. |
|||
|
|||
Also, what if child has exit()ed? Must exit loop somehow. |
|||
*/ |
|||
|
|||
static void |
|||
irix_solib_create_inferior_hook (void) |
|||
{ |
|||
if (!enable_break ()) |
|||
{ |
|||
warning ("shared library handler failed to enable breakpoint"); |
|||
return; |
|||
} |
|||
|
|||
/* Now run the target. It will eventually hit the breakpoint, at
|
|||
which point all of the libraries will have been mapped in and we |
|||
can go groveling around in the dynamic linker structures to find |
|||
out what we need to know about them. */ |
|||
|
|||
clear_proceed_status (); |
|||
stop_soon_quietly = 1; |
|||
stop_signal = TARGET_SIGNAL_0; |
|||
do |
|||
{ |
|||
target_resume (pid_to_ptid (-1), 0, stop_signal); |
|||
wait_for_inferior (); |
|||
} |
|||
while (stop_signal != TARGET_SIGNAL_TRAP); |
|||
|
|||
/* We are now either at the "mapping complete" breakpoint (or somewhere
|
|||
else, a condition we aren't prepared to deal with anyway), so adjust |
|||
the PC as necessary after a breakpoint, disable the breakpoint, and |
|||
add any shared libraries that were mapped in. */ |
|||
|
|||
if (!disable_break ()) |
|||
{ |
|||
warning ("shared library handler failed to disable breakpoint"); |
|||
} |
|||
|
|||
/* solib_add will call reinit_frame_cache.
|
|||
But we are stopped in the startup code and we might not have symbols |
|||
for the startup code, so heuristic_proc_start could be called |
|||
and will put out an annoying warning. |
|||
Delaying the resetting of stop_soon_quietly until after symbol loading |
|||
suppresses the warning. */ |
|||
solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add); |
|||
stop_soon_quietly = 0; |
|||
re_enable_breakpoints_in_shlibs (); |
|||
} |
|||
|
|||
/* LOCAL FUNCTION
|
|||
|
|||
current_sos -- build a list of currently loaded shared objects |
|||
|
|||
SYNOPSIS |
|||
|
|||
struct so_list *current_sos () |
|||
|
|||
DESCRIPTION |
|||
|
|||
Build a list of `struct so_list' objects describing the shared |
|||
objects currently loaded in the inferior. This list does not |
|||
include an entry for the main executable file. |
|||
|
|||
Note that we only gather information directly available from the |
|||
inferior --- we don't examine any of the shared library files |
|||
themselves. The declaration of `struct so_list' says which fields |
|||
we provide values for. */ |
|||
|
|||
static struct so_list * |
|||
irix_current_sos (void) |
|||
{ |
|||
CORE_ADDR lma; |
|||
char addr_buf[8]; |
|||
struct so_list *head = 0; |
|||
struct so_list **link_ptr = &head; |
|||
int is_first = 1; |
|||
struct lm_info lm; |
|||
|
|||
/* Make sure we've looked up the inferior's dynamic linker's base
|
|||
structure. */ |
|||
if (!debug_base) |
|||
{ |
|||
debug_base = locate_base (); |
|||
|
|||
/* If we can't find the dynamic linker's base structure, this
|
|||
must not be a dynamically linked executable. Hmm. */ |
|||
if (!debug_base) |
|||
return 0; |
|||
} |
|||
|
|||
read_memory (debug_base, addr_buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT); |
|||
lma = extract_mips_address (addr_buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT); |
|||
|
|||
while (lma) |
|||
{ |
|||
lm = fetch_lm_info (lma); |
|||
if (!is_first) |
|||
{ |
|||
int errcode; |
|||
char *name_buf; |
|||
int name_size; |
|||
struct so_list *new |
|||
= (struct so_list *) xmalloc (sizeof (struct so_list)); |
|||
struct cleanup *old_chain = make_cleanup (xfree, new); |
|||
|
|||
memset (new, 0, sizeof (*new)); |
|||
|
|||
new->lm_info = xmalloc (sizeof (struct lm_info)); |
|||
make_cleanup (xfree, new->lm_info); |
|||
|
|||
*new->lm_info = lm; |
|||
|
|||
/* Extract this shared object's name. */ |
|||
name_size = lm.pathname_len; |
|||
if (name_size == 0) |
|||
name_size = SO_NAME_MAX_PATH_SIZE - 1; |
|||
|
|||
if (name_size >= SO_NAME_MAX_PATH_SIZE) |
|||
{ |
|||
name_size = SO_NAME_MAX_PATH_SIZE - 1; |
|||
warning |
|||
("current_sos: truncating name of %d characters to only %d characters", |
|||
lm.pathname_len, name_size); |
|||
} |
|||
|
|||
target_read_string (lm.pathname_addr, &name_buf, |
|||
name_size, &errcode); |
|||
if (errcode != 0) |
|||
{ |
|||
warning ("current_sos: Can't read pathname for load map: %s\n", |
|||
safe_strerror (errcode)); |
|||
} |
|||
else |
|||
{ |
|||
strncpy (new->so_name, name_buf, name_size); |
|||
new->so_name[name_size] = '\0'; |
|||
xfree (name_buf); |
|||
strcpy (new->so_original_name, new->so_name); |
|||
} |
|||
|
|||
new->next = 0; |
|||
*link_ptr = new; |
|||
link_ptr = &new->next; |
|||
|
|||
discard_cleanups (old_chain); |
|||
} |
|||
is_first = 0; |
|||
lma = lm.next; |
|||
} |
|||
|
|||
return head; |
|||
} |
|||
|
|||
/*
|
|||
|
|||
LOCAL FUNCTION |
|||
|
|||
irix_open_symbol_file_object |
|||
|
|||
SYNOPSIS |
|||
|
|||
void irix_open_symbol_file_object (void *from_tty) |
|||
|
|||
DESCRIPTION |
|||
|
|||
If no open symbol file, attempt to locate and open the main symbol |
|||
file. On IRIX, this is the first link map entry. If its name is |
|||
here, we can open it. Useful when attaching to a process without |
|||
first loading its symbol file. |
|||
|
|||
If FROM_TTYP dereferences to a non-zero integer, allow messages to |
|||
be printed. This parameter is a pointer rather than an int because |
|||
open_symbol_file_object() is called via catch_errors() and |
|||
catch_errors() requires a pointer argument. */ |
|||
|
|||
static int |
|||
irix_open_symbol_file_object (void *from_ttyp) |
|||
{ |
|||
CORE_ADDR lma; |
|||
char addr_buf[8]; |
|||
struct lm_info lm; |
|||
struct cleanup *cleanups; |
|||
int errcode; |
|||
int from_tty = *(int *) from_ttyp; |
|||
char *filename; |
|||
|
|||
if (symfile_objfile) |
|||
if (!query ("Attempt to reload symbols from process? ")) |
|||
return 0; |
|||
|
|||
if ((debug_base = locate_base ()) == 0) |
|||
return 0; /* failed somehow... */ |
|||
|
|||
/* First link map member should be the executable. */ |
|||
read_memory (debug_base, addr_buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT); |
|||
lma = extract_mips_address (addr_buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT); |
|||
if (lma == 0) |
|||
return 0; /* failed somehow... */ |
|||
|
|||
lm = fetch_lm_info (lma); |
|||
|
|||
if (lm.pathname_addr == 0) |
|||
return 0; /* No filename. */ |
|||
|
|||
/* Now fetch the filename from target memory. */ |
|||
target_read_string (lm.pathname_addr, &filename, SO_NAME_MAX_PATH_SIZE - 1, |
|||
&errcode); |
|||
|
|||
if (errcode) |
|||
{ |
|||
warning ("failed to read exec filename from attached file: %s", |
|||
safe_strerror (errcode)); |
|||
return 0; |
|||
} |
|||
|
|||
cleanups = make_cleanup (xfree, filename); |
|||
/* Have a pathname: read the symbol file. */ |
|||
symbol_file_add_main (filename, from_tty); |
|||
|
|||
do_cleanups (cleanups); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
|
|||
/*
|
|||
|
|||
LOCAL FUNCTION |
|||
|
|||
irix_special_symbol_handling -- additional shared library symbol handling |
|||
|
|||
SYNOPSIS |
|||
|
|||
void irix_special_symbol_handling () |
|||
|
|||
DESCRIPTION |
|||
|
|||
Once the symbols from a shared object have been loaded in the usual |
|||
way, we are called to do any system specific symbol handling that |
|||
is needed. |
|||
|
|||
For SunOS4, this consisted of grunging around in the dynamic |
|||
linkers structures to find symbol definitions for "common" symbols |
|||
and adding them to the minimal symbol table for the runtime common |
|||
objfile. |
|||
|
|||
However, for IRIX, there's nothing to do. |
|||
|
|||
*/ |
|||
|
|||
static void |
|||
irix_special_symbol_handling (void) |
|||
{ |
|||
} |
|||
|
|||
/* Using the solist entry SO, relocate the addresses in SEC. */ |
|||
|
|||
static void |
|||
irix_relocate_section_addresses (struct so_list *so, |
|||
struct section_table *sec) |
|||
{ |
|||
sec->addr += so->lm_info->reloc_offset; |
|||
sec->endaddr += so->lm_info->reloc_offset; |
|||
} |
|||
|
|||
/* Free the lm_info struct. */ |
|||
|
|||
static void |
|||
irix_free_so (struct so_list *so) |
|||
{ |
|||
xfree (so->lm_info); |
|||
} |
|||
|
|||
/* Clear backend specific state. */ |
|||
|
|||
static void |
|||
irix_clear_solib (void) |
|||
{ |
|||
debug_base = 0; |
|||
} |
|||
|
|||
/* Return 1 if PC lies in the dynamic symbol resolution code of the
|
|||
run time loader. */ |
|||
static int |
|||
irix_in_dynsym_resolve_code (CORE_ADDR pc) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
static struct target_so_ops irix_so_ops; |
|||
|
|||
void |
|||
_initialize_irix_solib (void) |
|||
{ |
|||
irix_so_ops.relocate_section_addresses = irix_relocate_section_addresses; |
|||
irix_so_ops.free_so = irix_free_so; |
|||
irix_so_ops.clear_solib = irix_clear_solib; |
|||
irix_so_ops.solib_create_inferior_hook = irix_solib_create_inferior_hook; |
|||
irix_so_ops.special_symbol_handling = irix_special_symbol_handling; |
|||
irix_so_ops.current_sos = irix_current_sos; |
|||
irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object; |
|||
irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code; |
|||
|
|||
/* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ |
|||
current_target_so_ops = &irix_so_ops; |
|||
} |
|||
Loading…
Reference in new issue