#include "defs.h"
#include <sys/types.h>
#include <signal.h>
#include "gdb_string.h"
#include "bfd.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
#include "target.h"
#include "inferior.h"
#include "solist.h"
#ifdef USE_LDR_ROUTINES
# include <loader.h>
#endif
#ifndef USE_LDR_ROUTINES
#define RLD_CONTEXT_ADDRESS 0x3ffc0000000
typedef struct
{
CORE_ADDR next;
CORE_ADDR previous;
CORE_ADDR unknown1;
CORE_ADDR module_name;
CORE_ADDR modinfo_addr;
long module_id;
CORE_ADDR unknown2;
CORE_ADDR unknown3;
long region_count;
CORE_ADDR regioninfo_addr;
}
ldr_module_info_t;
typedef struct
{
long unknown1;
CORE_ADDR regionname_addr;
long protection;
CORE_ADDR vaddr;
CORE_ADDR mapaddr;
long size;
long unknown2[5];
}
ldr_region_info_t;
typedef struct
{
CORE_ADDR unknown1;
CORE_ADDR unknown2;
CORE_ADDR head;
CORE_ADDR tail;
}
ldr_context_t;
#endif
struct lm_sec
{
CORE_ADDR offset;
CORE_ADDR nameaddr;
const char *name;
};
struct lm_info
{
int isloader;
int nsecs;
struct lm_sec secs[1];
};
struct read_map_ctxt
{
#ifdef USE_LDR_ROUTINES
ldr_process_t proc;
ldr_module_t next;
#else
CORE_ADDR next;
CORE_ADDR tail;
#endif
};
extern void _initialize_osf_solib (void);
#ifdef USE_LDR_ROUTINES
# if 0
static int
ldr_read_memory (CORE_ADDR memaddr, char *myaddr, int len, int readstring)
{
int result;
char *buffer;
if (readstring)
{
target_read_string (memaddr, &buffer, len, &result);
if (result == 0)
strcpy (myaddr, buffer);
xfree (buffer);
}
else
result = target_read_memory (memaddr, myaddr, len);
if (result != 0)
result = -result;
return result;
}
# endif
#endif
static int
lm_sec_cmp (const void *p1, const void *p2)
{
const struct lm_sec *lms1 = p1, *lms2 = p2;
return strcmp (lms1->name, lms2->name);
}
static void
lm_secs_sort (struct lm_info *lmi)
{
qsort (lmi->secs, lmi->nsecs, sizeof *lmi->secs, lm_sec_cmp);
}
static void
fetch_sec_names (struct lm_info *lmi)
{
#ifndef USE_LDR_ROUTINES
int i, errcode;
struct lm_sec *lms;
char *name;
for (i = 0; i < lmi->nsecs; i++)
{
lms = lmi->secs + i;
target_read_string (lms->nameaddr, &name, PATH_MAX, &errcode);
if (errcode != 0)
{
warning ("unable to read shared sec name at 0x%lx", lms->nameaddr);
name = xstrdup ("");
}
lms->name = name;
}
lm_secs_sort (lmi);
#endif
}
static void
osf_relocate_section_addresses (struct so_list *so,
struct section_table *sec)
{
struct lm_info *lmi;
struct lm_sec lms_key, *lms;
lmi = so->lm_info;
if (lmi->nsecs && !lmi->secs[0].name)
fetch_sec_names (lmi);
lms_key.name = sec->the_bfd_section->name;
lms = bsearch (&lms_key, lmi->secs, lmi->nsecs, sizeof *lms, lm_sec_cmp);
if (lms)
{
sec->addr += lms->offset;
sec->endaddr += lms->offset;
}
}
static void
osf_free_so (struct so_list *so)
{
int i;
const char *name;
for (i = 0; i < so->lm_info->nsecs; i++)
{
name = so->lm_info->secs[i].name;
if (name)
xfree ((void *) name);
}
xfree (so->lm_info);
}
static void
osf_clear_solib (void)
{
return;
}
static void
osf_solib_create_inferior_hook (void)
{
if (symfile_objfile == NULL
|| symfile_objfile->obfd == NULL
|| ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0))
return;
clear_proceed_status ();
stop_soon_quietly = 1;
stop_signal = TARGET_SIGNAL_0;
do
{
target_resume (minus_one_ptid, 0, stop_signal);
wait_for_inferior ();
}
while (stop_signal != TARGET_SIGNAL_TRAP);
solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
stop_soon_quietly = 0;
re_enable_breakpoints_in_shlibs ();
}
static void
osf_special_symbol_handling (void)
{
return;
}
static int
open_map (struct read_map_ctxt *ctxt)
{
#ifdef USE_LDR_ROUTINES
ctxt->proc = ldr_my_process ();
if (ldr_xattach (ctxt->proc) != 0)
return 0;
ctxt->next = LDR_NULL_MODULE;
#else
CORE_ADDR ldr_context_addr, prev, next;
ldr_context_t ldr_context;
if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS,
(char *) &ldr_context_addr,
sizeof (CORE_ADDR)) != 0)
return 0;
if (target_read_memory (ldr_context_addr,
(char *) &ldr_context,
sizeof (ldr_context_t)) != 0)
return 0;
ctxt->next = ldr_context.head;
ctxt->tail = ldr_context.tail;
#endif
return 1;
}
static void
init_so (struct so_list *so, char *name, int isloader, int nsecs)
{
int namelen, i;
memset (so, 0, sizeof *so);
namelen = strlen (name);
if (namelen >= SO_NAME_MAX_PATH_SIZE)
namelen = SO_NAME_MAX_PATH_SIZE - 1;
memcpy (so->so_original_name, name, namelen);
so->so_original_name[namelen] = '\0';
memcpy (so->so_name, so->so_original_name, namelen + 1);
so->lm_info = xmalloc ((unsigned) &(((struct lm_info *)0)->secs) +
nsecs * sizeof *so->lm_info);
so->lm_info->isloader = isloader;
so->lm_info->nsecs = nsecs;
for (i = 0; i < nsecs; i++)
so->lm_info->secs[i].name = NULL;
}
static void
init_sec (struct so_list *so, int secidx, CORE_ADDR nameaddr,
const char *name, CORE_ADDR vaddr, CORE_ADDR mapaddr)
{
struct lm_sec *lms;
lms = so->lm_info->secs + secidx;
lms->nameaddr = nameaddr;
lms->name = name;
lms->offset = mapaddr - vaddr;
}
static int
read_map (struct read_map_ctxt *ctxt, struct so_list *so)
{
ldr_module_info_t minf;
ldr_region_info_t rinf;
#ifdef USE_LDR_ROUTINES
size_t size;
ldr_region_t i;
if (ldr_next_module (ctxt->proc, &ctxt->next) != 0)
return 0;
if (ctxt->next == LDR_NULL_MODULE)
return 0;
if (ldr_inq_module (ctxt->proc, ctxt->next, &minf, sizeof minf, &size) != 0)
return 0;
init_so (so, minf.lmi_name, 0, minf.lmi_nregion);
for (i = 0; i < minf.lmi_nregion; i++)
{
if (ldr_inq_region (ctxt->proc, ctxt->next, i, &rinf,
sizeof rinf, &size) != 0)
goto err;
init_sec (so, (int) i, 0, xstrdup (rinf.lri_name),
(CORE_ADDR) rinf.lri_vaddr, (CORE_ADDR) rinf.lri_mapaddr);
}
lm_secs_sort (so->lm_info);
#else
char *name;
int errcode, i;
if (!ctxt->next)
return 0;
if (target_read_memory (ctxt->next, (char *) &minf, sizeof minf) != 0)
return 0;
if (ctxt->next == ctxt->tail)
ctxt->next = 0;
else
ctxt->next = minf.next;
target_read_string (minf.module_name, &name, PATH_MAX, &errcode);
if (errcode != 0)
return 0;
init_so (so, name, !minf.modinfo_addr, minf.region_count);
xfree (name);
for (i = 0; i < minf.region_count; i++)
{
if (target_read_memory (minf.regioninfo_addr + i * sizeof rinf,
(char *) &rinf, sizeof rinf) != 0)
goto err;
init_sec (so, i, rinf.regionname_addr, NULL, rinf.vaddr, rinf.mapaddr);
}
#endif
return 1;
err:
osf_free_so (so);
return 0;
}
static void
close_map (struct read_map_ctxt *ctxt)
{
#ifdef USE_LDR_ROUTINES
ldr_xdetach (ctxt->proc);
#endif
}
static struct so_list *
osf_current_sos (void)
{
struct so_list *head = NULL, *tail, *newtail, so;
struct read_map_ctxt ctxt;
int skipped_main;
if (!open_map (&ctxt))
return NULL;
for (skipped_main = 0;;)
{
if (!read_map (&ctxt, &so))
break;
if (!so.lm_info->isloader && !skipped_main)
{
osf_free_so (&so);
skipped_main = 1;
continue;
}
newtail = xmalloc (sizeof *newtail);
if (!head)
head = newtail;
else
tail->next = newtail;
tail = newtail;
memcpy (tail, &so, sizeof so);
tail->next = NULL;
}
done:
close_map (&ctxt);
return head;
}
static int
osf_open_symbol_file_object (void *from_ttyp)
{
struct read_map_ctxt ctxt;
struct so_list so;
int found;
if (symfile_objfile)
if (!query ("Attempt to reload symbols from process? "))
return 0;
if (!open_map (&ctxt))
return 0;
for (found = 0; !found;)
{
if (!read_map (&ctxt, &so))
break;
found = !so.lm_info->isloader;
osf_free_so (&so);
}
close_map (&ctxt);
if (found)
symbol_file_add_main (so.so_name, *(int *) from_ttyp);
return found;
}
static int
osf_in_dynsym_resolve_code (CORE_ADDR pc)
{
return 0;
}
static struct target_so_ops osf_so_ops;
void
_initialize_osf_solib (void)
{
osf_so_ops.relocate_section_addresses = osf_relocate_section_addresses;
osf_so_ops.free_so = osf_free_so;
osf_so_ops.clear_solib = osf_clear_solib;
osf_so_ops.solib_create_inferior_hook = osf_solib_create_inferior_hook;
osf_so_ops.special_symbol_handling = osf_special_symbol_handling;
osf_so_ops.current_sos = osf_current_sos;
osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object;
osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code;
current_target_so_ops = &osf_so_ops;
}