#include "defs.h"
#include "inferior.h"
#include "gdbcore.h"
#include "target.h"
#include "regcache.h"
#include "gdb_string.h"
#include <sys/time.h>
#include <sys/procfs.h>
#include <setjmp.h>
#include "gregset.h"
static void fetch_core_registers (char *, unsigned int, int, CORE_ADDR);
#define JB_ELEMENT_SIZE 4
void
supply_gregset (gregset_t *gregsetp)
{
register int regi;
register greg_t *regp = &(*gregsetp)[0];
int gregoff = sizeof (greg_t) - MIPS_REGSIZE;
static char zerobuf[MAX_REGISTER_RAW_SIZE] =
{0};
for (regi = 0; regi <= CTX_RA; regi++)
supply_register (regi, (char *) (regp + regi) + gregoff);
supply_register (PC_REGNUM, (char *) (regp + CTX_EPC) + gregoff);
supply_register (HI_REGNUM, (char *) (regp + CTX_MDHI) + gregoff);
supply_register (LO_REGNUM, (char *) (regp + CTX_MDLO) + gregoff);
supply_register (CAUSE_REGNUM, (char *) (regp + CTX_CAUSE) + gregoff);
supply_register (BADVADDR_REGNUM, zerobuf);
}
void
fill_gregset (gregset_t *gregsetp, int regno)
{
int regi;
register greg_t *regp = &(*gregsetp)[0];
for (regi = 0; regi <= CTX_RA; regi++)
if ((regno == -1) || (regno == regi))
*(regp + regi) =
extract_signed_integer (®isters[REGISTER_BYTE (regi)],
REGISTER_RAW_SIZE (regi));
if ((regno == -1) || (regno == PC_REGNUM))
*(regp + CTX_EPC) =
extract_signed_integer (®isters[REGISTER_BYTE (PC_REGNUM)],
REGISTER_RAW_SIZE (PC_REGNUM));
if ((regno == -1) || (regno == CAUSE_REGNUM))
*(regp + CTX_CAUSE) =
extract_signed_integer (®isters[REGISTER_BYTE (CAUSE_REGNUM)],
REGISTER_RAW_SIZE (CAUSE_REGNUM));
if ((regno == -1) || (regno == HI_REGNUM))
*(regp + CTX_MDHI) =
extract_signed_integer (®isters[REGISTER_BYTE (HI_REGNUM)],
REGISTER_RAW_SIZE (HI_REGNUM));
if ((regno == -1) || (regno == LO_REGNUM))
*(regp + CTX_MDLO) =
extract_signed_integer (®isters[REGISTER_BYTE (LO_REGNUM)],
REGISTER_RAW_SIZE (LO_REGNUM));
}
void
supply_fpregset (fpregset_t *fpregsetp)
{
register int regi;
static char zerobuf[MAX_REGISTER_RAW_SIZE] =
{0};
for (regi = 0; regi < 32; regi++)
supply_register (FP0_REGNUM + regi,
(char *) &fpregsetp->fp_r.fp_regs[regi]);
supply_register (FCRCS_REGNUM, (char *) &fpregsetp->fp_csr);
supply_register (FCRIR_REGNUM, zerobuf);
}
void
fill_fpregset (fpregset_t *fpregsetp, int regno)
{
int regi;
char *from, *to;
for (regi = FP0_REGNUM; regi < FP0_REGNUM + 32; regi++)
{
if ((regno == -1) || (regno == regi))
{
from = (char *) ®isters[REGISTER_BYTE (regi)];
to = (char *) &(fpregsetp->fp_r.fp_regs[regi - FP0_REGNUM]);
memcpy (to, from, REGISTER_RAW_SIZE (regi));
}
}
if ((regno == -1) || (regno == FCRCS_REGNUM))
fpregsetp->fp_csr = *(unsigned *) ®isters[REGISTER_BYTE (FCRCS_REGNUM)];
}
int
get_longjmp_target (CORE_ADDR *pc)
{
char *buf;
CORE_ADDR jb_addr;
buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
jb_addr = read_register (A0_REGNUM);
if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
TARGET_PTR_BIT / TARGET_CHAR_BIT))
return 0;
*pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
return 1;
}
static void
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
int which, CORE_ADDR reg_addr)
{
if (core_reg_size == REGISTER_BYTES)
{
memcpy ((char *) registers, core_reg_sect, core_reg_size);
}
else if (MIPS_REGSIZE == 4 &&
core_reg_size == (2 * MIPS_REGSIZE) * NUM_REGS)
{
char *srcp = core_reg_sect;
char *dstp = registers;
int regno;
for (regno = 0; regno < NUM_REGS; regno++)
{
if (regno >= FP0_REGNUM && regno < (FP0_REGNUM + 32))
{
*dstp++ = *srcp++;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
if (REGISTER_RAW_SIZE (regno) == 4)
{
srcp += 4;
}
else
{
*dstp++ = *srcp++;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
}
}
else
{
srcp += 4;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
*dstp++ = *srcp++;
}
}
}
else
{
warning ("wrong size gregset struct in core file");
return;
}
registers_fetched ();
}
#include <sys/types.h>
#include <signal.h>
#include <sys/param.h>
#include <fcntl.h>
#define __SYM_H__
#define __SYMCONST_H__
#include <obj.h>
#ifdef HAVE_OBJLIST_H
#include <objlist.h>
#endif
#ifdef NEW_OBJ_INFO_MAGIC
#define HANDLE_NEW_OBJ_LIST
#endif
#include "symtab.h"
#include "bfd.h"
#include "symfile.h"
#include "objfiles.h"
#include "command.h"
#include "frame.h"
#include "gdb_regex.h"
#include "inferior.h"
#include "language.h"
#include "gdbcmd.h"
#define DEBUG_BASE "__rld_obj_head"
typedef enum
{
OBJ_LIST_OLD,
OBJ_LIST_32,
OBJ_LIST_64
}
obj_list_variant;
struct link_map
{
obj_list_variant l_variant;
CORE_ADDR l_lladdr;
CORE_ADDR l_next;
};
#define LM_OFFSET(so) ((so) -> offset)
#define LM_ADDR(so) ((so) -> lmstart)
char shadow_contents[BREAKPOINT_MAX];
struct so_list
{
struct so_list *next;
struct link_map lm;
CORE_ADDR offset;
char *so_name;
CORE_ADDR lmstart;
CORE_ADDR lmend;
char symbols_loaded;
char from_tty;
struct objfile *objfile;
struct section_table *sections;
struct section_table *sections_end;
struct section_table *textsection;
bfd *abfd;
};
static struct so_list *so_list_head;
static CORE_ADDR debug_base;
static CORE_ADDR breakpoint_addr;
static void sharedlibrary_command (char *, int);
static int enable_break (void);
static int disable_break (void);
static void info_sharedlibrary_command (char *, int);
static int symbol_add_stub (void *);
static struct so_list *find_solib (struct so_list *);
static struct link_map *first_link_map_member (void);
static struct link_map *next_link_map_member (struct so_list *);
static void xfer_link_map_member (struct so_list *, struct link_map *);
static CORE_ADDR locate_base (void);
static int solib_map_sections (void *);
static int
solib_map_sections (void *arg)
{
struct so_list *so = (struct so_list *) arg;
char *filename;
char *scratch_pathname;
int scratch_chan;
struct section_table *p;
struct cleanup *old_chain;
bfd *abfd;
filename = tilde_expand (so->so_name);
old_chain = make_cleanup (xfree, filename);
scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
&scratch_pathname);
if (scratch_chan < 0)
{
scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename,
O_RDONLY, 0, &scratch_pathname);
}
if (scratch_chan < 0)
{
perror_with_name (filename);
}
abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan);
if (!abfd)
{
close (scratch_chan);
error ("Could not open `%s' as an executable file: %s",
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
so->abfd = abfd;
abfd->cacheable = 1;
if (!bfd_check_format (abfd, bfd_object))
{
error ("\"%s\": not in executable format: %s.",
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
if (build_section_table (abfd, &so->sections, &so->sections_end))
{
error ("Can't find the file sections in `%s': %s",
bfd_get_filename (exec_bfd), bfd_errmsg (bfd_get_error ()));
}
for (p = so->sections; p < so->sections_end; p++)
{
p->addr += LM_OFFSET (so);
p->endaddr += LM_OFFSET (so);
so->lmend = (CORE_ADDR) max (p->endaddr, so->lmend);
if (STREQ (p->the_bfd_section->name, ".text"))
{
so->textsection = p;
}
}
do_cleanups (old_chain);
return (1);
}
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);
}
static struct link_map *
first_link_map_member (void)
{
struct obj_list *listp;
struct obj_list list_old;
struct link_map *lm;
static struct link_map first_lm;
CORE_ADDR lladdr;
CORE_ADDR next_lladdr;
debug_base = locate_base ();
if (debug_base == 0)
return NULL;
read_memory (debug_base, (char *) &listp, sizeof (struct obj_list *));
if (listp == NULL)
return NULL;
lladdr = host_pointer_to_address (listp);
read_memory (lladdr, (char *) &list_old, sizeof (struct obj_list));
next_lladdr = host_pointer_to_address (list_old.next);
#ifdef HANDLE_NEW_OBJ_LIST
if (list_old.data == NEW_OBJ_INFO_MAGIC)
{
Elf32_Obj_Info list_32;
read_memory (lladdr, (char *) &list_32, sizeof (Elf32_Obj_Info));
if (list_32.oi_size != sizeof (Elf32_Obj_Info))
return NULL;
next_lladdr = (CORE_ADDR) list_32.oi_next;
}
#endif
if (next_lladdr == 0)
return NULL;
first_lm.l_lladdr = next_lladdr;
lm = &first_lm;
return lm;
}
static struct link_map *
next_link_map_member (struct so_list *so_list_ptr)
{
struct link_map *lm = &so_list_ptr->lm;
CORE_ADDR next_lladdr = lm->l_next;
static struct link_map next_lm;
if (next_lladdr == 0)
{
int status = 0;
if (lm->l_variant == OBJ_LIST_OLD)
{
struct obj_list list_old;
status = target_read_memory (lm->l_lladdr,
(char *) &list_old,
sizeof (struct obj_list));
next_lladdr = host_pointer_to_address (list_old.next);
}
#ifdef HANDLE_NEW_OBJ_LIST
else if (lm->l_variant == OBJ_LIST_32)
{
Elf32_Obj_Info list_32;
status = target_read_memory (lm->l_lladdr,
(char *) &list_32,
sizeof (Elf32_Obj_Info));
next_lladdr = (CORE_ADDR) list_32.oi_next;
}
#endif
if (status != 0 || next_lladdr == 0)
return NULL;
}
next_lm.l_lladdr = next_lladdr;
lm = &next_lm;
return lm;
}
static void
xfer_link_map_member (struct so_list *so_list_ptr, struct link_map *lm)
{
struct obj_list list_old;
CORE_ADDR lladdr = lm->l_lladdr;
struct link_map *new_lm = &so_list_ptr->lm;
int errcode;
read_memory (lladdr, (char *) &list_old, sizeof (struct obj_list));
new_lm->l_variant = OBJ_LIST_OLD;
new_lm->l_lladdr = lladdr;
new_lm->l_next = host_pointer_to_address (list_old.next);
#ifdef HANDLE_NEW_OBJ_LIST
if (list_old.data == NEW_OBJ_INFO_MAGIC)
{
Elf32_Obj_Info list_32;
read_memory (lladdr, (char *) &list_32, sizeof (Elf32_Obj_Info));
if (list_32.oi_size != sizeof (Elf32_Obj_Info))
return;
new_lm->l_variant = OBJ_LIST_32;
new_lm->l_next = (CORE_ADDR) list_32.oi_next;
target_read_string ((CORE_ADDR) list_32.oi_pathname,
&so_list_ptr->so_name,
list_32.oi_pathname_len + 1, &errcode);
if (errcode != 0)
memory_error (errcode, (CORE_ADDR) list_32.oi_pathname);
LM_ADDR (so_list_ptr) = (CORE_ADDR) list_32.oi_ehdr;
LM_OFFSET (so_list_ptr) =
(CORE_ADDR) list_32.oi_ehdr - (CORE_ADDR) list_32.oi_orig_ehdr;
}
else
#endif
{
#if defined (_MIPS_SIM_NABI32) && _MIPS_SIM == _MIPS_SIM_NABI32
char buf[432];
read_memory ((CORE_ADDR) list_old.data, buf, sizeof (buf));
target_read_string (extract_address (&buf[236], 4),
&so_list_ptr->so_name,
INT_MAX, &errcode);
if (errcode != 0)
memory_error (errcode, extract_address (&buf[236], 4));
LM_ADDR (so_list_ptr) = extract_address (&buf[196], 4);
LM_OFFSET (so_list_ptr) =
extract_address (&buf[196], 4) - extract_address (&buf[248], 4);
#else
struct obj obj_old;
read_memory ((CORE_ADDR) list_old.data, (char *) &obj_old,
sizeof (struct obj));
target_read_string ((CORE_ADDR) obj_old.o_path,
&so_list_ptr->so_name,
INT_MAX, &errcode);
if (errcode != 0)
memory_error (errcode, (CORE_ADDR) obj_old.o_path);
LM_ADDR (so_list_ptr) = (CORE_ADDR) obj_old.o_praw;
LM_OFFSET (so_list_ptr) =
(CORE_ADDR) obj_old.o_praw - obj_old.o_base_address;
#endif
}
catch_errors (solib_map_sections, (char *) so_list_ptr,
"Error while mapping shared library sections:\n",
RETURN_MASK_ALL);
}
static struct so_list *
find_solib (struct so_list *so_list_ptr)
{
struct so_list *so_list_next = NULL;
struct link_map *lm = NULL;
struct so_list *new;
if (so_list_ptr == NULL)
{
if ((so_list_next = so_list_head) == NULL)
{
lm = first_link_map_member ();
}
}
else
{
lm = next_link_map_member (so_list_ptr);
so_list_next = so_list_ptr->next;
}
if ((so_list_next == NULL) && (lm != NULL))
{
new = (struct so_list *) xmalloc (sizeof (struct so_list));
memset ((char *) new, 0, sizeof (struct so_list));
if (so_list_ptr != NULL)
{
so_list_ptr->next = new;
}
else
{
so_list_head = new;
}
so_list_next = new;
xfer_link_map_member (new, lm);
}
return (so_list_next);
}
static int
symbol_add_stub (void *arg)
{
register struct so_list *so = (struct so_list *) arg;
CORE_ADDR text_addr = 0;
struct section_addr_info section_addrs;
memset (§ion_addrs, 0, sizeof (section_addrs));
if (so->textsection)
text_addr = so->textsection->addr;
else if (so->abfd != NULL)
{
asection *lowest_sect;
lowest_sect = bfd_get_section_by_name (so->abfd, ".text");
if (lowest_sect == NULL)
bfd_map_over_sections (so->abfd, find_lowest_section,
(PTR) &lowest_sect);
if (lowest_sect)
text_addr = bfd_section_vma (so->abfd, lowest_sect) + LM_OFFSET (so);
}
section_addrs.other[0].name = ".text";
section_addrs.other[0].addr = text_addr;
so->objfile = symbol_file_add (so->so_name, so->from_tty,
§ion_addrs, 0, 0);
return (1);
}
void
solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
{
register struct so_list *so = NULL;
struct so_list *so_last = NULL;
char *re_err;
int count;
int old;
if (!readsyms)
return;
if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL)
{
error ("Invalid regexp: %s", re_err);
}
if (target)
{
so = NULL;
count = 0;
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0])
{
count += so->sections_end - so->sections;
}
}
if (count)
{
old = target_resize_to_sections (target, count);
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0])
{
count = so->sections_end - so->sections;
memcpy ((char *) (target->to_sections + old),
so->sections,
(sizeof (struct section_table)) * count);
old += count;
}
}
}
}
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0] && re_exec (so->so_name))
{
so->from_tty = from_tty;
if (so->symbols_loaded)
{
if (from_tty)
{
printf_unfiltered ("Symbols already loaded for %s\n", so->so_name);
}
}
else if (catch_errors
(symbol_add_stub, (char *) so,
"Error while reading shared library symbols:\n",
RETURN_MASK_ALL))
{
so_last = so;
so->symbols_loaded = 1;
}
}
}
if (so_last)
reinit_frame_cache ();
}
static void
info_sharedlibrary_command (char *ignore, int from_tty)
{
register struct so_list *so = NULL;
int header_done = 0;
if (exec_bfd == NULL)
{
printf_unfiltered ("No executable file.\n");
return;
}
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0])
{
if (!header_done)
{
printf_unfiltered ("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read",
"Shared Object Library");
header_done++;
}
printf_unfiltered ("%-12s",
local_hex_string_custom ((unsigned long) LM_ADDR (so),
"08l"));
printf_unfiltered ("%-12s",
local_hex_string_custom ((unsigned long) so->lmend,
"08l"));
printf_unfiltered ("%-12s", so->symbols_loaded ? "Yes" : "No");
printf_unfiltered ("%s\n", so->so_name);
}
}
if (so_list_head == NULL)
{
printf_unfiltered ("No shared libraries loaded at this time.\n");
}
}
char *
solib_address (CORE_ADDR address)
{
register struct so_list *so = 0;
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0])
{
if ((address >= (CORE_ADDR) LM_ADDR (so)) &&
(address < (CORE_ADDR) so->lmend))
return (so->so_name);
}
}
return (0);
}
void
clear_solib (void)
{
struct so_list *next;
char *bfd_filename;
disable_breakpoints_in_shlibs (1);
while (so_list_head)
{
if (so_list_head->sections)
{
xfree (so_list_head->sections);
}
if (so_list_head->abfd)
{
remove_target_sections (so_list_head->abfd);
bfd_filename = bfd_get_filename (so_list_head->abfd);
if (!bfd_close (so_list_head->abfd))
warning ("cannot close \"%s\": %s",
bfd_filename, bfd_errmsg (bfd_get_error ()));
}
else
bfd_filename = NULL;
next = so_list_head->next;
if (bfd_filename)
xfree (bfd_filename);
xfree (so_list_head->so_name);
xfree (so_list_head);
so_list_head = next;
}
debug_base = 0;
}
static int
disable_break (void)
{
int status = 1;
if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0)
{
status = 0;
}
if (stop_pc != breakpoint_addr)
{
warning ("stopped at unknown breakpoint while handling shared libraries");
}
return (status);
}
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;
}
void
solib_create_inferior_hook (void)
{
if (!enable_break ())
{
warning ("shared library handler failed to enable breakpoint");
return;
}
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);
if (DECR_PC_AFTER_BREAK)
{
stop_pc -= DECR_PC_AFTER_BREAK;
write_register (PC_REGNUM, stop_pc);
}
if (!disable_break ())
{
warning ("shared library handler failed to disable breakpoint");
}
solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
stop_soon_quietly = 0;
}
static void
sharedlibrary_command (char *args, int from_tty)
{
dont_repeat ();
solib_add (args, from_tty, (struct target_ops *) 0, 1);
}
void
_initialize_solib (void)
{
add_com ("sharedlibrary", class_files, sharedlibrary_command,
"Load shared object library symbols for files matching REGEXP.");
add_info ("sharedlibrary", info_sharedlibrary_command,
"Status of loaded shared object libraries.");
add_show_from_set
(add_set_cmd ("auto-solib-add", class_support, var_boolean,
(char *) &auto_solib_add,
"Set autoloading of shared library symbols.\n\
If \"on\", symbols from all shared object libraries will be loaded\n\
automatically when the inferior begins execution, when the dynamic linker\n\
informs gdb that a new library has been loaded, or when attaching to the\n\
inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
&setlist),
&showlist);
}
static struct core_fns irix5_core_fns =
{
bfd_target_unknown_flavour,
default_check_format,
default_core_sniffer,
fetch_core_registers,
NULL
};
void
_initialize_core_irix5 (void)
{
add_core_fns (&irix5_core_fns);
}