#include "defs.h"
#include "inferior.h"
#include "gdbcore.h"
#include "target.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 (free, 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 = true;
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)
{
register struct so_list *so = NULL;
struct so_list *so_last = NULL;
char *re_err;
int count;
int old;
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)
{
free ((PTR) so_list_head->sections);
}
if (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)
free ((PTR) bfd_filename);
free (so_list_head->so_name);
free ((PTR) 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 (-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");
}
if (auto_solib_add)
solib_add ((char *) 0, 0, (struct target_ops *) 0);
stop_soon_quietly = 0;
}
static void
sharedlibrary_command (char *args, int from_tty)
{
dont_repeat ();
solib_add (args, from_tty, (struct target_ops *) 0);
}
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_zinteger,
(char *) &auto_solib_add,
"Set autoloading of shared library symbols.\n\
If nonzero, symbols from all shared object libraries will be loaded\n\
automatically when the inferior begins execution or when the dynamic linker\n\
informs gdb that a new library has been loaded. Otherwise, symbols\n\
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);
}