macosx-nat-dyld-info.c [plain text]
#include "macosx-nat-dyld-info.h"
#include "macosx-nat-dyld-path.h"
#include <string.h>
#include <ctype.h>
#include "defs.h"
#include "inferior.h"
#include "symfile.h"
#include "symtab.h"
#include "gdbcmd.h"
#include "objfiles.h"
const char *dyld_reason_string (dyld_objfile_reason r)
{
switch (r) {
case dyld_reason_deallocated: return "deallocated";
case dyld_reason_user: return "user";
case dyld_reason_cached_library: return "cached-lib";
case dyld_reason_cached_executable: return "cached-exec";
case dyld_reason_init: return "init";
case dyld_reason_executable: return "exec";
case dyld_reason_dyld: return "dyld";
case dyld_reason_cfm: return "cfm";
default: return "???";
}
}
void dyld_check_entry (struct dyld_objfile_entry *e)
{
}
void dyld_objfile_entry_clear (struct dyld_objfile_entry *e)
{
e->prefix = NULL;
e->dyld_name = NULL;
e->dyld_name_valid = 0;
e->dyld_addr = 0;
e->dyld_slide = 0;
e->dyld_index = 0;
e->dyld_valid = 0;
e->dyld_length = 0;
e->cfm_container = 0;
e->user_name = NULL;
e->image_name = NULL;
e->image_name_valid = 0;
e->image_addr = 0;
e->image_addr_valid = 0;
e->text_name = NULL;
e->text_name_valid = 0;
e->abfd = NULL;
e->sym_bfd = NULL;
e->sym_objfile = NULL;
e->objfile = NULL;
e->loaded_name = NULL;
e->loaded_memaddr = 0;
e->loaded_addr = 0;
e->loaded_offset = 0;
e->loaded_addrisoffset = 0;
e->loaded_from_memory = 0;
e->loaded_error = 0;
e->load_flag = -1;
e->reason = 0;
e->allocated = 0;
}
void dyld_objfile_info_init (struct dyld_objfile_info *i)
{
i->entries = NULL;
i->nents = 0;
i->maxents = 0;
i->sections = NULL;
i->sections_end = NULL;
}
void dyld_objfile_info_pack (struct dyld_objfile_info *i)
{
unsigned int j;
for (j = 0; j < i->nents; j++) {
if (! i->entries[j].allocated) {
memmove (&i->entries[j], &i->entries[j + 1], (i->nents - j) * sizeof (struct dyld_objfile_entry));
i->nents--;
j--;
}
}
}
void dyld_objfile_info_free (struct dyld_objfile_info *i)
{
CHECK_FATAL (i != NULL);
if (i->entries != NULL) {
xfree (i->entries);
i->entries = NULL;
}
i->nents = 0;
i->maxents = 0;
}
int dyld_objfile_entry_compare (struct dyld_objfile_entry *a, struct dyld_objfile_entry *b)
{
#define COMPARE_SCALAR(field) { \
if (a->field != b->field) { \
return 1; \
} \
}
#define COMPARE_STRING(field) { \
if (a->field != b->field) { \
if ((a->field == NULL) || (b->field == NULL)) { \
return 1; \
} else if (strcmp (a->field, b->field) != 0) { \
return 1; \
} \
} \
}
COMPARE_STRING(prefix);
COMPARE_STRING(dyld_name);
COMPARE_SCALAR(dyld_name_valid);
COMPARE_SCALAR(dyld_addr);
COMPARE_SCALAR(dyld_slide);
COMPARE_SCALAR(dyld_index);
COMPARE_SCALAR(dyld_valid);
COMPARE_SCALAR(cfm_container);
COMPARE_STRING(user_name);
COMPARE_STRING(image_name);
COMPARE_SCALAR(image_name_valid);
COMPARE_SCALAR(image_addr);
COMPARE_SCALAR(image_addr_valid);
COMPARE_STRING(text_name);
COMPARE_SCALAR(text_name_valid);
COMPARE_SCALAR(abfd);
COMPARE_SCALAR(sym_bfd);
COMPARE_SCALAR(objfile);
COMPARE_SCALAR(sym_objfile);
COMPARE_STRING(loaded_name);
COMPARE_SCALAR(loaded_memaddr);
COMPARE_SCALAR(loaded_addr);
COMPARE_SCALAR(loaded_offset);
COMPARE_SCALAR(loaded_addrisoffset);
COMPARE_SCALAR(loaded_from_memory);
COMPARE_SCALAR(loaded_error);
COMPARE_SCALAR(load_flag);
COMPARE_SCALAR(reason);
COMPARE_SCALAR(allocated);
#undef COMPARE_SCALAR
#undef COMPARE_STRING
return 0;
}
int dyld_objfile_info_compare (struct dyld_objfile_info *a, struct dyld_objfile_info *b)
{
unsigned int i;
if (a->nents != b->nents) { return 1; }
if (a->maxents != b->maxents) { return 1; }
for (i = 0; i < a->nents; i++) {
if (dyld_objfile_entry_compare (&a->entries[i], &b->entries[i]) != 0) {
return 1;
}
}
return 0;
}
void
dyld_objfile_info_copy_entries (struct dyld_objfile_info *d, struct dyld_objfile_info *s, unsigned int mask)
{
struct dyld_objfile_entry *e, *n;
unsigned int i;
for (i = 0; i < s->nents; i++) {
e = &s->entries[i];
if (! e->allocated) {
continue;
}
if (e->reason & mask) {
n = dyld_objfile_entry_alloc (d);
*n = *e;
}
}
}
void dyld_objfile_info_copy (struct dyld_objfile_info *d, struct dyld_objfile_info *s)
{
dyld_objfile_info_init (d);
if (s->maxents == 0) {
return;
}
d->entries = xmalloc (s->maxents * sizeof (struct dyld_objfile_entry));
d->nents = s->nents;
d->maxents = s->maxents;
memcpy (d->entries, s->entries, s->nents * sizeof (struct dyld_objfile_entry));
}
struct dyld_objfile_entry *dyld_objfile_entry_alloc (struct dyld_objfile_info *i)
{
struct dyld_objfile_entry *e = NULL;
if (i->nents < i->maxents) {
e = &i->entries[i->nents++];
} else {
i->maxents = (i->nents > 0) ? (i->nents * 2) : 16;
if (i->entries == NULL) {
i->entries = xmalloc (i->maxents * sizeof (struct dyld_objfile_entry));
} else {
i->entries = xrealloc (i->entries, i->maxents * sizeof (struct dyld_objfile_entry));
}
e = &i->entries[i->nents++];
}
dyld_objfile_entry_clear (e);
e->allocated = 1;
return e;
}
const int dyld_entry_source_filename_is_absolute
(struct dyld_objfile_entry *e)
{
CHECK_FATAL (e != NULL);
CHECK_FATAL (e->allocated);
if (e->loaded_name != NULL) {
return 1;
} else if (e->user_name != NULL) {
return 1;
} else if (e->dyld_name != NULL) {
return 1;
} else if (e->image_name != NULL) {
return 0;
} else if (e->text_name != NULL) {
return 0;
} else {
return 0;
}
}
const char *dyld_entry_source_filename
(struct dyld_objfile_entry *e)
{
CHECK_FATAL (e != NULL);
CHECK_FATAL (e->allocated);
if (e->loaded_name != NULL) {
return e->loaded_name;
} else if (e->user_name != NULL) {
return e->user_name;
} else if (e->dyld_name != NULL) {
return e->dyld_name;
} else if (e->image_name != NULL) {
return e->image_name;
} else if (e->text_name != NULL) {
return e->text_name;
} else {
return NULL;
}
}
char *dyld_offset_string (unsigned long offset)
{
char *ret = NULL;
if (offset > LONG_MAX) {
xasprintf (&ret, "-0x%lx", ((ULONG_MAX - offset) + 1));
} else {
xasprintf (&ret, "0x%lx", offset);
}
return ret;
}
char *dyld_entry_string (struct dyld_objfile_entry *e, int print_basenames)
{
char *name;
char *addr;
char *slide;
char *prefix;
char *ret;
char *ret2;
dyld_entry_info (e, print_basenames, &name, &addr, &slide, &prefix);
if (name == NULL)
{
if (addr != NULL)
{
if (slide != NULL)
xasprintf (&ret, "[memory at %s] (offset %s)", addr, slide);
else
xasprintf (&ret, "[memory at %s]", addr);
}
else
{
if (slide == NULL)
ret = NULL;
else
xasprintf (&ret, "(offset %s)", slide);
}
}
else
{
if (slide == NULL)
{
if (addr == NULL)
xasprintf (&ret, "\"%s\"", name);
else
xasprintf (&ret, "\"%s\" at %s", name, addr);
}
else
{
if (addr == NULL)
xasprintf (&ret, "\"%s\" (offset %s)", name, slide);
else
xasprintf (&ret, "\"%s\" at %s (offset %s)", name, addr, slide);
}
if (prefix != NULL)
{
xasprintf (&ret2, "%s with prefix \"%s\"", ret, prefix);
xfree (ret);
ret = ret2;
}
}
xfree (name);
xfree (addr);
xfree (slide);
xfree (prefix);
return xstrdup (ret);
}
void dyld_entry_out (struct ui_out *uiout, struct dyld_objfile_entry *e, int print_basenames)
{
char *name;
char *addr;
char *slide;
char *prefix;
dyld_entry_info (e, print_basenames, &name, &addr, &slide, &prefix);
if (name == NULL)
{
if (ui_out_is_mi_like_p (uiout))
{
const char *name = dyld_entry_source_filename (e);
if (name != NULL)
{
ui_out_text (uiout, "\"");
ui_out_field_string (uiout, "path", name);
ui_out_text (uiout, "\"");
}
else
{
char *s = dyld_entry_string (e, print_basenames);
ui_out_text (uiout, "\"");
ui_out_field_string (uiout, "path", s);
ui_out_text (uiout, "\"");
xfree (s);
}
}
else
ui_out_field_skip (uiout, "path");
if (addr != NULL)
{
ui_out_text (uiout, "[memory at ");
ui_out_field_string (uiout, "loaded_addr", addr);
if (slide != NULL)
{
ui_out_text (uiout, "] (offset ");
ui_out_field_string (uiout, "slide", slide);
ui_out_text (uiout, ")");
}
else
{
ui_out_field_skip (uiout, "slide");
ui_out_text (uiout, "]");
}
}
else
{
ui_out_field_skip (uiout, "loaded_addr");
if (slide == NULL)
ui_out_field_skip (uiout, "slide");
else
{
ui_out_text (uiout, "(offset ");
ui_out_field_string (uiout, "slide", slide);
ui_out_text (uiout, ")");
}
}
}
else
{
ui_out_text (uiout, "\"");
ui_out_field_string (uiout, "path", name);
ui_out_text (uiout, "\"");
if (slide == NULL)
{
ui_out_field_skip (uiout, "slide");
if (addr == NULL)
ui_out_field_skip (uiout, "addr");
else
{
ui_out_text (uiout, " at ");
ui_out_field_string (uiout, "loaded_addr", addr);
}
}
else
{
if (addr == NULL)
{
ui_out_field_skip (uiout, "loaded_addr");
ui_out_text (uiout, " (offset ");
ui_out_field_string (uiout, "slide", slide);
ui_out_text (uiout, ")");
}
else
{
ui_out_text (uiout, " at ");
ui_out_field_string (uiout, "loaded_addr", addr);
ui_out_text (uiout, " (offset ");
ui_out_field_string (uiout, "slide", slide);
ui_out_text (uiout, ")");
}
}
if (prefix == NULL)
{
ui_out_field_skip (uiout, "prefix");
}
else
{
ui_out_text (uiout, " with prefix \"");
ui_out_field_string (uiout, "prefix", prefix);
ui_out_text (uiout, "\"");
}
}
xfree (name);
xfree (addr);
xfree (slide);
xfree (prefix);
}
void
dyld_entry_info (struct dyld_objfile_entry *e, int print_basenames,
char **name, char **addr, char **slide, char **prefix)
{
CHECK_FATAL (e != NULL);
*name = NULL;
*addr = NULL;
*slide = NULL;
*prefix = NULL;
if (e->objfile) {
if (e->loaded_from_memory) {
CHECK_FATAL (! e->loaded_addrisoffset);
CHECK_FATAL (e->loaded_addr == e->loaded_memaddr);
if (e->image_addr_valid) {
*slide = dyld_offset_string ((unsigned long) (e->loaded_memaddr - e->image_addr));
xasprintf (addr, "0x%lx", (unsigned long) e->loaded_memaddr);
} else {
xasprintf (addr, "0x%lx", (unsigned long) e->loaded_memaddr);
}
} else {
const char *loaded_name;
if (! print_basenames) {
if (e->loaded_name != NULL) {
loaded_name = strrchr (e->loaded_name, '/');
if (loaded_name == NULL) {
loaded_name = e->loaded_name;
} else {
loaded_name++;
}
} else {
loaded_name = NULL;
}
} else {
loaded_name = e->loaded_name;
}
if (loaded_name != NULL) {
int namelen = strlen (loaded_name) + 1;
*name = (char *) xmalloc (namelen);
memcpy (*name, loaded_name, namelen);
}
if (e->loaded_addrisoffset) {
if (e->image_addr_valid) {
*slide = dyld_offset_string ((unsigned long) e->loaded_offset);
xasprintf (addr, "0x%lx", (unsigned long) e->image_addr);
} else {
*slide = dyld_offset_string ((unsigned long) e->loaded_offset);
}
} else {
if (e->dyld_valid) {
*slide = dyld_offset_string ((unsigned long) e->dyld_slide);
xasprintf (addr, "0x%lx", (unsigned long) e->loaded_addr);
} else {
if (e->image_addr_valid) {
*slide = dyld_offset_string ((unsigned long) (e->loaded_addr - e->image_addr));
xasprintf (addr, "0x%lx", (unsigned long) e->loaded_addr);
} else {
xasprintf (addr, "0x%lx", (unsigned long) e->loaded_addr);
}
}
}
}
} else {
const char *s;
const char *tmp;
int namelen;
s = dyld_entry_source_filename (e);
if (s == NULL) {
s = "[UNKNOWN]";
}
if (! print_basenames) {
tmp = strrchr (s, '/');
if (tmp == NULL) {
tmp = s;
} else {
tmp++;
}
} else {
tmp = s;
}
if (tmp != NULL) {
namelen = strlen (tmp) + 1;
*name = xmalloc (namelen);
memcpy (*name, tmp, namelen);
}
}
if ((e->prefix != NULL) && (e->prefix[0] != '\0')) {
int prefixlen = strlen (e->prefix) + 1;
*prefix = xmalloc (prefixlen);
memcpy (*prefix, e->prefix, prefixlen);
}
}
int dyld_resolve_shlib_num
(struct dyld_objfile_info *s, unsigned int num, struct dyld_objfile_entry **eptr, struct objfile **optr)
{
struct objfile *objfile;
struct objfile *temp;
unsigned int i;
CHECK_FATAL (eptr != NULL);
CHECK_FATAL (optr != NULL);
*eptr = NULL;
*optr = NULL;
for (i = 0; i < s->nents; i++) {
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
continue;
}
num--;
if (num == 0) {
*eptr = j;
*optr = j->objfile;
return 0;
}
}
ALL_OBJFILES_SAFE (objfile, temp) {
int found = 0;
for (i = 0; i < s->nents; i++) {
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
continue;
}
if (j->objfile == objfile) {
found = 1;
}
}
if (! found) {
num--;
}
if (num == 0) {
*eptr = NULL;
*optr = objfile;
return 0;
}
}
return -1;
}
int dyld_entry_shlib_num
(struct dyld_objfile_info *s, struct dyld_objfile_entry *eptr, unsigned int *numptr)
{
unsigned int num = 0;
unsigned int i;
CHECK_FATAL (numptr != NULL);
*numptr = num;
for (i = 0; i < s->nents; i++) {
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
continue;
}
if (j == eptr) {
*numptr = num;
return 0;
}
num++;
}
*numptr = 0;
return -1;
}
unsigned int
dyld_shlib_info_basename_length
(struct dyld_objfile_info *s, unsigned int reason_mask)
{
unsigned int i;
unsigned int baselen = 0;
struct objfile *objfile, *temp;
for (i = 0; i < s->nents; i++) {
const char *name = NULL;
const char *tfname = NULL;
unsigned int tfnamelen = 0;
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
continue;
}
if (! (j->reason & reason_mask)) {
continue;
}
name = dyld_entry_source_filename (j);
if (name == NULL) {
if (baselen < 1) {
baselen = 1;
}
} else {
dyld_library_basename (name, &tfname, &tfnamelen, NULL, NULL);
if (baselen < tfnamelen) {
baselen = tfnamelen;
}
}
}
if (! (reason_mask & dyld_reason_user)) {
return baselen;
}
ALL_OBJFILES_SAFE (objfile, temp) {
const char *name = NULL;
const char *tfname = NULL;
unsigned int tfnamelen = 0;
int found = 0;
for (i = 0; i < s->nents; i++) {
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
continue;
}
if (j->objfile == objfile) {
found = 1;
}
}
if (! found) {
struct dyld_objfile_entry tentry;
dyld_convert_entry (objfile, &tentry);
name = dyld_entry_source_filename (&tentry);
if (name == NULL) {
if (baselen < 1) {
baselen = 1;
}
} else {
dyld_library_basename (name, &tfname, &tfnamelen, NULL, NULL);
if (baselen < tfnamelen) {
baselen = tfnamelen;
}
}
}
}
return baselen;
}
int dyld_entry_shlib_num_matches (int shlibnum, const char *args, int verbose)
{
const char *p, *p1;
int num;
if (args == NULL)
error_no_arg ("one or more shlib numbers");
if (args[0] == '\0')
error_no_arg ("one or more shlib numbers");
p = args;
while (*p)
{
p1 = p;
num = get_number_or_range (&p1);
if (num == 0)
{
if (verbose)
warning ("bad shlib number at or near '%s'", p);
return 0;
}
if (num == shlibnum)
return 1;
p = p1;
}
return 0;
}
void dyld_print_entry_info (struct dyld_objfile_entry *j, unsigned int shlibnum,
unsigned int baselen)
{
const char *name = NULL;
const char *tfname = NULL;
unsigned int tfnamelen = 0;
int is_framework, is_bundle;
char *fname = NULL;
char addrbuf[24];
const char *ptr;
name = dyld_entry_source_filename (j);
if (name == NULL) {
fname = savestring ("-", strlen ("-"));
is_framework = 0;
is_bundle = 0;
} else {
dyld_library_basename (name, &tfname, &tfnamelen, &is_framework, &is_bundle);
fname = savestring (tfname, tfnamelen);
}
if (j->dyld_valid) {
snprintf (addrbuf, 24, "0x%lx", (unsigned long) j->dyld_addr);
} else {
strcpy (addrbuf, "-");
}
if (baselen < strlen (fname)) {
baselen = strlen (fname);
}
ui_out_list_begin (uiout, "shlib-info");
if (shlibnum < 10)
ui_out_text (uiout, " ");
else if (shlibnum < 100)
ui_out_text (uiout, " ");
ui_out_field_int (uiout, "num", shlibnum);
ui_out_spaces (uiout, 1);
ui_out_field_string (uiout, "name", fname);
ui_out_spaces (uiout, baselen - strlen (fname) + 1);
ptr = is_framework ? "F" : (is_bundle ? "B" : "-");
ui_out_field_string (uiout, "kind", ptr);
if (strlen (ptr) == 0)
ui_out_spaces (uiout, 1);
ui_out_spaces (uiout, 1);
ui_out_field_string (uiout, "dyld-addr", addrbuf);
ui_out_spaces (uiout, 10 - strlen (addrbuf));
ui_out_spaces (uiout, 1);
ptr = dyld_reason_string (j->reason);
ui_out_spaces (uiout, 11 - strlen (ptr));
ui_out_field_string (uiout, "reason", ptr);
ui_out_spaces (uiout, 1);
if (j->load_flag == OBJF_SYM_ALL) {
ptr = "Y";
} else if (j->load_flag == OBJF_SYM_NONE) {
ptr = "N";
} else if (j->load_flag == OBJF_SYM_EXTERN) {
ptr = "E";
} else {
ptr = "?";
}
ui_out_field_string (uiout, "requested-state", ptr);
ui_out_spaces (uiout, 1);
if (j->loaded_error) {
ptr = "!";
} else {
if (j->objfile != NULL) {
if (! dyld_objfile_allocated (j->objfile)) {
ptr = "!";
} else if (j->objfile->symflags == OBJF_SYM_ALL) {
ptr = "Y";
} else if (j->objfile->symflags == OBJF_SYM_NONE) {
ptr = "N";
} else if (j->objfile->symflags == OBJF_SYM_EXTERN) {
ptr = "E";
} else {
ptr = "?";
}
} else if (j->abfd != NULL) {
ptr = "B";
} else {
ptr = "N";
}
}
ui_out_field_string (uiout, "state", ptr);
ui_out_spaces (uiout, 1);
dyld_entry_out (uiout, j, 1);
ui_out_list_end (uiout);
ui_out_text (uiout, "\n");
}
void dyld_convert_entry (struct objfile *o, struct dyld_objfile_entry *e)
{
dyld_objfile_entry_clear (e);
e->allocated = 1;
e->reason = dyld_reason_user;
e->objfile = o;
e->abfd = o->obfd;
if (e->abfd != NULL)
e->loaded_name = bfd_get_filename (e->abfd);
}
void dyld_print_shlib_info (struct dyld_objfile_info *s, unsigned int reason_mask, int header, const char *args)
{
unsigned int baselen = 0;
char *basepad = NULL;
unsigned int shlibnum = 0;
struct objfile *objfile, *temp;
unsigned int i;
baselen = dyld_shlib_info_basename_length (s, reason_mask);
if (baselen < 12) {
baselen = 12;
}
basepad = xmalloc (baselen + 1);
memset (basepad, ' ', baselen);
basepad[baselen] = '\0';
if (header)
ui_out_text_fmt (uiout,
"%s Requested State Current State\n"
"Num Basename%s Type Address Reason | | Source \n"
" | |%s | | | | | | \n",
basepad + 12, basepad + 12, basepad + 12);
if (args != NULL)
dyld_entry_shlib_num_matches (-1, args, 1);
for (i = 0; i < s->nents; i++) {
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
if (reason_mask & dyld_reason_deallocated)
printf_filtered ("[DEALLOCATED]\n");
continue;
}
shlibnum++;
if (! (j->reason & reason_mask)) {
continue;
}
if ((args == NULL) || dyld_entry_shlib_num_matches (shlibnum, args, 0)) {
dyld_print_entry_info (j, shlibnum, baselen);
}
}
ALL_OBJFILES_SAFE (objfile, temp) {
int found = 0;
for (i = 0; i < s->nents; i++) {
struct dyld_objfile_entry *j = &s->entries[i];
if (! j->allocated) {
continue;
}
if (j->objfile == objfile) {
found = 1;
}
}
if (! found) {
struct dyld_objfile_entry tentry;
shlibnum++;
if (! (reason_mask & dyld_reason_user)) {
continue;
}
if ((args == NULL) || dyld_entry_shlib_num_matches (shlibnum, args, 0)) {
dyld_convert_entry (objfile, &tentry);
dyld_print_entry_info (&tentry, shlibnum, baselen);
}
}
}
}
unsigned int dyld_next_allocated_shlib (struct dyld_objfile_info *info, unsigned int n)
{
struct dyld_objfile_entry *o;
for (;;) {
if (n >= info->nents)
return n;
o = &info->entries[n];
if (o->allocated)
return n;
n++;
}
}