fix-and-continue.c [plain text]
#include <string.h>
#include <mach-o/dyld.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>
#include <stdint.h>
#include <dlfcn.h>
#include "defs.h"
#include "value.h"
#include "gdbtypes.h"
#include "objfiles.h"
#include "command.h"
#include "completer.h"
#include "frame.h"
#include "target.h"
#include "gdbcore.h"
#include "inferior.h"
#include "symfile.h"
#include "gdbthread.h"
#include "gdb.h"
#include "ui-out.h"
#include "cli-out.h"
#include "symtab.h"
#include "regcache.h"
#include "gdbcmd.h"
#include "language.h"
#include "dictionary.h"
#include "block.h"
#include <readline/readline.h>
#include "osabi.h"
#include "exceptions.h"
#include "filenames.h"
#if defined (TARGET_I386)
#include "i386-tdep.h"
#endif
#ifdef MACOSX_DYLD
#include "macosx-nat-dyld-process.h"
#endif
struct active_threads {
int num;
struct active_func *active_func_chain;
CORE_ADDR pc;
struct active_threads *next;
};
struct active_func {
struct active_func * next;
struct symbol * sym;
int level, line;
CORE_ADDR addr, fp;
const char *file, *dir;
};
struct fixeddatum {
CORE_ADDR addr;
int size;
int oldval, newval;
struct fixeddatum * next;
};
struct obsoletedsym {
struct minimal_symbol * oldmsym, *newmsym;
struct symbol * oldsym, *newsym;
struct obsoletedsym * next;
};
struct fixinfo {
const char *src_filename;
const char *src_basename;
const char *bundle_filename;
const char *bundle_basename;
const char *original_objfile_filename;
const char *canonical_source_filename;
struct active_threads *active_functions;
struct fixedobj *fixed_object_files;
struct fixedobj *most_recent_fix;
int complete;
struct fixinfo *next;
};
struct fixedobj {
const char *bundle_filename;
struct fixeddatum *firstdatum, *lastdatum;
struct obsoletedsym *obsoletedsym;
struct fixedobj *next;
};
static struct fixinfo *fixinfo_chain = NULL;
struct file_static_fixups {
CORE_ADDR addr;
CORE_ADDR value;
struct symbol *new_sym;
struct minimal_symbol *new_msym;
struct symbol *original_sym;
struct minimal_symbol *original_msym;
};
static void get_fixed_file (struct fixinfo *);
static int load_fixed_objfile (const char *);
static void do_final_fix_fixups (struct fixinfo *curfixinfo);
static void redirect_file_statics (struct fixinfo *);
static void find_new_static_symbols (struct fixinfo *, struct file_static_fixups *, int);
static void find_orig_static_symbols (struct fixinfo *, struct file_static_fixups *, int);
static void redirect_statics (struct file_static_fixups *, int);
static int find_and_parse_nonlazy_ptr_sect (struct fixinfo *, struct file_static_fixups **);
static struct objfile ** build_list_of_objfiles_to_update (struct fixinfo *);
static void redirect_old_function (struct fixinfo *, struct symbol *, struct symbol *, int);
CORE_ADDR decode_fix_and_continue_trampoline (CORE_ADDR);
static int in_active_func (const char *, struct active_threads *);
static struct active_func *create_current_active_funcs_list (const char *);
void do_final_fix_fixups_global_syms (struct block *newglobals, struct objfile *oldobj, struct fixinfo *curfixinfo);
static void do_final_fix_fixups_static_syms (struct block *newstatics, struct objfile *oldobj, struct fixinfo *curfixinfo);
static void pre_load_and_check_file (struct fixinfo *);
static void force_psymtab_expansion (struct objfile *, const char *, const char *);
static void expand_all_objfile_psymtabs (struct objfile *);
static void free_active_threads_struct (struct active_threads *);
static struct active_threads * create_current_threads_list (const char *);
static struct fixinfo *get_fixinfo_for_new_request (const char *);
int file_exists_p (const char *);
static void do_pre_load_checks (struct fixinfo *, struct objfile *);
static void check_restrictions_globals (struct fixinfo *, struct objfile *);
static void check_restrictions_statics (struct fixinfo *, struct objfile *);
static void check_restrictions_locals (struct fixinfo *, struct objfile *);
static void check_restrictions_function (const char *, int, struct block *,
struct block *);
static int sym_is_argument (struct symbol *);
static int sym_is_local (struct symbol *);
static void free_half_finished_fixinfo (struct fixinfo *);
static void mark_previous_fixes_obsolete (struct fixinfo *);
static const char *getbasename (const char *);
static void print_active_functions (struct fixinfo *);
static struct symtab *find_symtab_by_name (struct objfile *, const char *);
static struct symbol *search_for_coalesced_symbol (struct objfile *,
struct symbol *);
static void restore_language (void *);
static struct cleanup *set_current_language (const char *);
static void find_original_object_file_name (struct fixinfo *);
static struct objfile *find_original_object_file (struct fixinfo *);
static struct symtab *find_original_symtab (struct fixinfo *);
static struct partial_symtab *find_original_psymtab (struct fixinfo *);
static struct objfile *raise_objfile_load_level (struct objfile *);
int fix_and_continue_debug_flag = 0;
#ifndef TARGET_ADDRESS_BYTES
#define TARGET_ADDRESS_BYTES (TARGET_LONG_BIT / TARGET_CHAR_BIT)
#endif
static void
fix_command (char *args, int from_tty)
{
char **argv;
char *source_filename, *bundle_filename;
struct cleanup *cleanups;
const char *usage = "Usage: fix bundle-filename source-filename [object-filename]";
if (!args || args[0] == '\0')
error ("%s", usage);
argv = buildargv (args);
cleanups = make_cleanup_freeargv (argv);
if (argv[0] == NULL || strlen (argv[0]) == 0 ||
argv[1] == NULL || strlen (argv[1]) == 0)
error ("%s", usage);
if (argv[2] != NULL &&
(strlen (argv[2]) == 0 || argv[3] != NULL))
error ("%s", usage);
bundle_filename = argv[0];
source_filename = argv[1];
if (!source_filename || strlen (source_filename) == 0 ||
!bundle_filename || strlen (bundle_filename) == 0)
error ("%s", usage);
fix_command_1 (source_filename, bundle_filename, NULL);
if (!ui_out_is_mi_like_p (uiout) && from_tty)
{
printf_filtered ("Fix succeeded.\n");
}
do_cleanups (cleanups);
}
void
fix_command_1 (const char *source_filename,
const char *bundle_filename,
const char *solib_filename)
{
struct fixinfo *cur;
struct cleanup *wipe;
char tmpbuf[MAXPATHLEN];
char *fn;
if (source_filename == NULL || *source_filename == '\0' ||
bundle_filename == NULL || *bundle_filename == '\0')
error ("Source or bundle filename not provided.");
if (bundle_filename && *bundle_filename == '\0')
bundle_filename = NULL;
source_filename = tilde_expand (source_filename);
if (source_filename == NULL)
error ("Source filename not found.");
fn = tilde_expand (bundle_filename);
if (fn)
{
char *ret = realpath (fn, tmpbuf);
if (ret)
bundle_filename = xstrdup (ret);
else
bundle_filename = NULL;
xfree (fn);
}
else
error ("Bundle filename '%s' not found.", bundle_filename);
if (bundle_filename == NULL)
error ("Bundle filename not found.");
if (solib_filename)
{
if (!IS_ABSOLUTE_PATH (solib_filename))
{
struct objfile *o = find_objfile_by_name (solib_filename, 0);
if (o && o->name)
solib_filename = o->name;
}
fn = tilde_expand (solib_filename);
if (fn)
{
char *ret = realpath (fn, tmpbuf);
if (ret)
solib_filename = xstrdup (ret);
else
solib_filename = NULL;
xfree (fn);
}
else
error ("Dylib filename '%s' not found.", solib_filename);
if (solib_filename == NULL)
error ("Dylib not found.");
}
if (!file_exists_p (source_filename))
error ("Source file '%s' not found.", source_filename);
if (!file_exists_p (bundle_filename))
error ("Bundle '%s' not found.", bundle_filename);
if (solib_filename && !file_exists_p (solib_filename))
error ("Dylib/executable '%s' not found.", solib_filename);
if (find_objfile_by_name (bundle_filename, 1))
error ("Bundle '%s' has already been loaded.", bundle_filename);
wipe = set_current_language (source_filename);
cur = get_fixinfo_for_new_request (source_filename);
cur->bundle_filename = bundle_filename;
cur->bundle_basename = getbasename (bundle_filename);
if (solib_filename)
raise_objfile_load_level (find_objfile_by_name (solib_filename, 1));
find_original_object_file_name (cur);
pre_load_and_check_file (cur);
get_fixed_file (cur);
mark_previous_fixes_obsolete (cur);
do_final_fix_fixups (cur);
print_active_functions (cur);
do_cleanups (wipe);
}
static void
mark_previous_fixes_obsolete (struct fixinfo *cur)
{
struct fixedobj *fo;
struct minimal_symbol *msym;
struct objfile *fo_objfile;
for (fo = cur->fixed_object_files; fo != NULL; fo = fo->next)
{
fo_objfile = find_objfile_by_name (fo->bundle_filename, 1);
if (fo_objfile == NULL)
{
warning ("fixed object file entry for '%s' has a NULL objfile ptr! "
"Will try continuing", fo->bundle_filename);
continue;
}
if (fo == cur->most_recent_fix)
continue;
ALL_OBJFILE_MSYMBOLS (fo_objfile, msym)
if (MSYMBOL_TYPE (msym) != mst_data &&
MSYMBOL_TYPE (msym) != mst_bss &&
MSYMBOL_TYPE (msym) != mst_file_data &&
MSYMBOL_TYPE (msym) != mst_file_bss)
{
MSYMBOL_OBSOLETED (msym) = 1;
}
int i;
struct dict_iterator j;
struct symbol *sym;
struct symtab *st;
struct partial_symtab *pst;
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (fo_objfile, st)
{
if (st->primary == 1)
for (i = 0; i < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (st)); i++)
ALL_BLOCK_SYMBOLS (BLOCKVECTOR_BLOCK (BLOCKVECTOR (st), i), j, sym)
if (SYMBOL_DOMAIN (sym) != VAR_DOMAIN ||
SYMBOL_CLASS (sym) != LOC_STATIC)
SYMTAB_OBSOLETED (st) = 51;
}
ALL_OBJFILE_PSYMTABS (fo_objfile, pst)
{
PSYMTAB_OBSOLETED (pst) = 51;
}
}
PSYMTAB_OBSOLETED (find_original_psymtab (cur)) = 51;
SYMTAB_OBSOLETED (find_original_symtab (cur)) = 51;
}
static struct fixinfo *
get_fixinfo_for_new_request (const char *source_filename)
{
struct fixinfo *i, *prev = NULL;
i = fixinfo_chain;
while (i != NULL)
{
if (i->complete == 0 && prev == NULL)
{
fixinfo_chain = i->next;
free_half_finished_fixinfo (i);
i = fixinfo_chain;
continue;
}
if (i->complete == 0)
{
prev->next = i->next;
free_half_finished_fixinfo (i);
i = fixinfo_chain;
continue;
}
prev = i;
i = i->next;
}
for (i = fixinfo_chain; i != NULL; i = i->next)
{
if (!strcmp (i->src_filename, source_filename) && i->complete)
return (i);
}
i = (struct fixinfo *) xmalloc (sizeof (struct fixinfo));
memset (i, 0, sizeof (struct fixinfo));
if (fixinfo_chain == NULL)
fixinfo_chain = i;
else
i->next = fixinfo_chain;
i->src_filename = source_filename;
i->src_basename = getbasename (source_filename);
i->complete = 0;
return (i);
}
static void
free_half_finished_fixinfo (struct fixinfo *f)
{
if (f->fixed_object_files != NULL)
{
warning ("free_half_finished_fixinfo: incomplete fixinfo was too complete");
return;
}
if (f->src_filename != NULL)
xfree ((char *) f->src_filename);
if (f->bundle_filename != NULL)
xfree ((char *) f->bundle_filename);
if (f->active_functions != NULL)
free_active_threads_struct (f->active_functions);
if (f->original_objfile_filename != NULL)
xfree ((char *) f->original_objfile_filename);
xfree (f);
}
static char *
get_dlerror_message ()
{
char dyld_errmsg[MAXPATHLEN * 3];
dyld_errmsg[0] = '\0';
struct value *ref_to_dlerror;
struct value *retval;
CORE_ADDR dlerror_msg_addr;
ref_to_dlerror = find_function_in_inferior ("dlerror",
builtin_type_voidptrfuncptr);
retval = call_function_by_hand_expecting_type (ref_to_dlerror,
builtin_type_void_data_ptr, 0, NULL, 1);
dlerror_msg_addr = value_as_address (retval);
if (dlerror_msg_addr != 0)
{
read_memory_string (dlerror_msg_addr, dyld_errmsg,
sizeof (dyld_errmsg) - 1);
if (dyld_errmsg[0] != '\0')
{
char *c;
dyld_errmsg[sizeof (dyld_errmsg) - 1] = '\0';
c = dyld_errmsg + strlen (dyld_errmsg) - 1;
if (*c == '\r' || *c == '\n')
*c = '\0';
return xstrdup (dyld_errmsg);
}
}
return NULL;
}
static void
get_fixed_file (struct fixinfo *cur)
{
struct partial_symtab *ps = NULL;
struct fixedobj *flp;
struct objfile *fixedobj_objfile;
struct fixedobj *fixedobj;
int loaded_ok;
fixedobj = xmalloc (sizeof (struct fixedobj));
fixedobj->bundle_filename = cur->bundle_filename;
fixedobj->firstdatum = NULL;
fixedobj->lastdatum = NULL;
fixedobj->obsoletedsym = NULL;
fixedobj->next = NULL;
loaded_ok = load_fixed_objfile (fixedobj->bundle_filename);
fixedobj_objfile = find_objfile_by_name (fixedobj->bundle_filename, 1);
if (loaded_ok != 1)
{
char *err = get_dlerror_message ();
#ifdef MACOSX_DYLD
if (fixedobj_objfile != NULL)
remove_objfile_from_dyld_records (fixedobj_objfile);
#endif
if (err)
error ("Not able to load Fix bundle with error: '%s'", err);
else
error ("NSLinkModule was not able to correctly load the Fix bundle, "
"most likely due to unresolved external references.");
xfree (err);
}
if (fixedobj_objfile == NULL)
error ("Unable to load fixed object file '%s'.", fixedobj->bundle_filename);
fixedobj_objfile = raise_objfile_load_level (fixedobj_objfile);
if (cur->fixed_object_files == NULL)
cur->fixed_object_files = fixedobj;
else
{
for (flp = cur->fixed_object_files; flp->next != NULL; flp = flp->next)
;
flp->next = fixedobj;
}
cur->most_recent_fix = fixedobj;
ALL_OBJFILE_PSYMTABS (fixedobj_objfile, ps)
PSYMTAB_TO_SYMTAB (ps);
cur->complete = 1;
}
static const char *
getbasename (const char *name)
{
const char *p = strrchr (name, '/');
if (p)
return (p + 1);
else
return name;
}
static int
load_fixed_objfile (const char *name)
{
struct value **libraryvec, *val, **args;
int i, librarylen;
struct value *ref_to_dlopen;
ref_to_dlopen = find_function_in_inferior ("dlopen",
builtin_type_voidptrfuncptr);
librarylen = strlen (name);
libraryvec = (struct value **)
alloca (sizeof (struct value *) * (librarylen + 2));
for (i = 0; i < librarylen + 1; i++)
libraryvec [i] = value_from_longest (builtin_type_char, name[i]);
args = (struct value **) alloca (sizeof (struct value *) * 3);
args[0] = value_array (0, librarylen, libraryvec);
args[1] = value_from_longest (builtin_type_int, RTLD_LOCAL | RTLD_NOW);
args[2] = NULL;
val = call_function_by_hand_expecting_type
(ref_to_dlopen, builtin_type_void_data_ptr, 2, args, 1);
if (value_as_address (val) == 0)
return 0;
return 1;
}
static void
do_final_fix_fixups (struct fixinfo *cur)
{
struct objfile *most_recent_fix_objfile;
struct symtab *newsymtab = NULL;
struct blockvector *newbv;
struct block *newblock;
struct objfile **objfiles_to_update;
struct cleanup *cleanups;
int i;
most_recent_fix_objfile = find_objfile_by_name
(cur->most_recent_fix->bundle_filename, 1);
objfiles_to_update = build_list_of_objfiles_to_update (cur);
cleanups = make_cleanup (xfree, objfiles_to_update);
for (i = 0; objfiles_to_update[i] != NULL; i++)
{
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (most_recent_fix_objfile, newsymtab)
{
if (newsymtab->primary != 1)
continue;
newbv = BLOCKVECTOR (newsymtab);
newblock = BLOCKVECTOR_BLOCK (newbv, GLOBAL_BLOCK);
do_final_fix_fixups_global_syms (newblock, objfiles_to_update[i], cur);
newblock = BLOCKVECTOR_BLOCK (newbv, STATIC_BLOCK);
do_final_fix_fixups_static_syms (newblock, objfiles_to_update[i], cur);
}
}
redirect_file_statics (cur);
do_cleanups (cleanups);
}
static void
redirect_file_statics (struct fixinfo *cur)
{
struct file_static_fixups *indirect_entries;
struct cleanup *wipe;
int indirect_entry_count;
indirect_entry_count = find_and_parse_nonlazy_ptr_sect (cur,
&indirect_entries);
if (indirect_entries == NULL || indirect_entry_count == 0)
return;
wipe = make_cleanup (xfree, indirect_entries);
find_new_static_symbols (cur, indirect_entries, indirect_entry_count);
find_orig_static_symbols (cur, indirect_entries, indirect_entry_count);
redirect_statics (indirect_entries, indirect_entry_count);
do_cleanups (wipe);
}
static void
find_new_static_symbols (struct fixinfo *cur,
struct file_static_fixups *indirect_entries,
int indirect_entry_count)
{
struct symtab *symtab;
struct block *b;
struct symbol *sym;
int j;
struct dict_iterator i;
struct objfile *most_recent_fix_objfile;
most_recent_fix_objfile = find_objfile_by_name
(cur->most_recent_fix->bundle_filename, 1);
for (j = 0; j < indirect_entry_count; j++)
{
CORE_ADDR addr = indirect_entries[j].value;
int matched = 0;
ALL_OBJFILE_SYMTABS (most_recent_fix_objfile, symtab)
{
if (symtab->primary != 1)
continue;
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
ALL_BLOCK_SYMBOLS (b, i, sym)
{
if (SYMBOL_CLASS (sym) == LOC_STATIC &&
SYMBOL_VALUE_ADDRESS (sym) == addr)
{
indirect_entries[j].new_sym = sym;
matched = 1;
break;
}
}
if (!matched)
{
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), GLOBAL_BLOCK);
ALL_BLOCK_SYMBOLS (b, i, sym)
{
if (SYMBOL_CLASS (sym) == LOC_STATIC &&
SYMBOL_VALUE_ADDRESS (sym) == addr)
{
indirect_entries[j].new_sym = sym;
matched = 1;
break;
}
}
}
if (matched)
{
indirect_entries[j].new_msym =
lookup_minimal_symbol
(SYMBOL_LINKAGE_NAME (indirect_entries[j].new_sym),
NULL, most_recent_fix_objfile);
}
}
}
}
static void
find_orig_static_symbols (struct fixinfo *cur,
struct file_static_fixups *indirect_entries,
int indirect_entry_count)
{
int i;
struct symbol *new_sym, *orig_sym;
struct block *static_bl, *global_bl;
struct fixedobj original_file;
struct fixedobj *f;
struct objfile *f_objfile;
struct symtab *f_symtab;
original_file.bundle_filename = cur->original_objfile_filename;
original_file.next = cur->fixed_object_files;
f = &original_file;
while (f != NULL)
{
if (!strcmp (f->bundle_filename, cur->most_recent_fix->bundle_filename))
{
f = f->next;
continue;
}
f_objfile = find_objfile_by_name (f->bundle_filename, 1);
f_symtab = find_symtab_by_name (f_objfile, cur->canonical_source_filename);
static_bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (f_symtab), STATIC_BLOCK);
global_bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (f_symtab), GLOBAL_BLOCK);
for (i = 0; i < indirect_entry_count; i++)
{
if (indirect_entries[i].original_sym != NULL)
continue;
new_sym = indirect_entries[i].new_sym;
if (new_sym == NULL)
continue;
orig_sym = lookup_block_symbol (static_bl,
SYMBOL_PRINT_NAME (new_sym),
SYMBOL_LINKAGE_NAME (new_sym),
SYMBOL_DOMAIN (new_sym));
if (orig_sym == NULL)
orig_sym = lookup_block_symbol (global_bl,
SYMBOL_PRINT_NAME (new_sym),
SYMBOL_LINKAGE_NAME (new_sym),
SYMBOL_DOMAIN (new_sym));
if (orig_sym == NULL)
orig_sym = search_for_coalesced_symbol (f_objfile, new_sym);
if (orig_sym)
{
indirect_entries[i].original_sym = orig_sym;
indirect_entries[i].original_msym =
lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (orig_sym),
NULL, f_objfile);
if (indirect_entries[i].original_msym == NULL &&
fix_and_continue_debug_flag)
{
printf_unfiltered ("DEBUG: Found orig sym but unable to find orig msym for %s\n",
SYMBOL_LINKAGE_NAME (orig_sym));
}
}
}
f = f->next;
}
}
static void
redirect_statics (struct file_static_fixups *indirect_entries,
int indirect_entry_count)
{
int i;
gdb_byte buf[TARGET_ADDRESS_BYTES];
for (i = 0; i < indirect_entry_count; i++)
{
if (fix_and_continue_debug_flag)
{
if (indirect_entries[i].addr == (CORE_ADDR) NULL)
printf_filtered
("DEBUG: Static entry addr for file static #%d was zero.\n", i);
if (indirect_entries[i].value == (CORE_ADDR) NULL)
printf_filtered
("DEBUG: Destination addr for file static #%d was zero.\n", i);
if (indirect_entries[i].new_sym == NULL)
printf_filtered
("DEBUG: Could not find new symbol for static #%d\n", i);
if (indirect_entries[i].new_msym == NULL)
printf_filtered
("DEBUG: Could not find new msymbol for static #%d\n", i);
if (indirect_entries[i].original_sym == NULL)
printf_filtered
("DEBUG: Could not find original symbol for static #%d\n", i);
if (indirect_entries[i].original_msym == NULL)
printf_filtered
("DEBUG: Could not find original msymbol for static #%d\n", i);
}
if (indirect_entries[i].new_sym == NULL ||
indirect_entries[i].original_sym == NULL ||
indirect_entries[i].new_msym == NULL ||
indirect_entries[i].original_msym == NULL)
continue;
if (indirect_entries[i].value == (CORE_ADDR) NULL ||
indirect_entries[i].addr == (CORE_ADDR) NULL)
continue;
if (SYMBOL_VALUE_ADDRESS (indirect_entries[i].original_msym) == 0
|| SYMBOL_VALUE_ADDRESS (indirect_entries[i].new_msym) == 0)
continue;
store_unsigned_integer (buf, TARGET_ADDRESS_BYTES,
SYMBOL_VALUE_ADDRESS (indirect_entries[i].original_msym));
write_memory (indirect_entries[i].addr, buf, TARGET_ADDRESS_BYTES);
SYMBOL_OBSOLETED (indirect_entries[i].original_sym) = 0;
MSYMBOL_OBSOLETED (indirect_entries[i].original_msym) = 0;
SYMBOL_OBSOLETED (indirect_entries[i].new_sym) = 1;
MSYMBOL_OBSOLETED (indirect_entries[i].new_msym) = 1;
if (fix_and_continue_debug_flag)
printf_filtered ("DEBUG: Redirected file static %s from 0x%s to 0x%s\n",
SYMBOL_PRINT_NAME (indirect_entries[i].original_sym),
paddr_nz (SYMBOL_VALUE_ADDRESS (indirect_entries[i].new_msym)),
paddr_nz (SYMBOL_VALUE_ADDRESS (indirect_entries[i].original_msym)));
}
}
static int
find_and_parse_nonlazy_ptr_sect (struct fixinfo *cur,
struct file_static_fixups **indirect_entries)
{
struct objfile *most_recent_fix_objfile;
struct obj_section *indirect_ptr_section, *j;
CORE_ADDR indirect_ptr_section_start;
bfd_size_type indirect_ptr_section_size;
int nl_symbol_ptr_count = 0;
int actual_entry_count;
gdb_byte *buf;
struct cleanup *wipe;
int i;
*indirect_entries = NULL;
indirect_ptr_section = NULL;
most_recent_fix_objfile = find_objfile_by_name
(cur->most_recent_fix->bundle_filename, 1);
ALL_OBJFILE_OSECTIONS (most_recent_fix_objfile, j)
if (strcmp ("LC_SEGMENT.__IMPORT.__pointers",
bfd_section_name (most_recent_fix_objfile->obfd,
j->the_bfd_section)) == 0
|| strcmp ("LC_SEGMENT.__DATA.__nl_symbol_ptr",
bfd_section_name (most_recent_fix_objfile->obfd,
j->the_bfd_section)) == 0)
{
indirect_ptr_section = j;
break;
}
if (indirect_ptr_section == NULL)
return 0;
indirect_ptr_section_start = indirect_ptr_section->addr;
indirect_ptr_section_size =
indirect_ptr_section->endaddr - indirect_ptr_section->addr;
if (indirect_ptr_section_size == 0)
return 0;
if (indirect_ptr_section_size % TARGET_ADDRESS_BYTES != 0)
error ("Incorrect non-lazy symbol pointer section size!");
nl_symbol_ptr_count = indirect_ptr_section_size / TARGET_ADDRESS_BYTES;
*indirect_entries = (struct file_static_fixups *) xmalloc
(sizeof (struct file_static_fixups) * nl_symbol_ptr_count);
buf = xmalloc (nl_symbol_ptr_count * TARGET_ADDRESS_BYTES);
wipe = make_cleanup (xfree, buf);
read_memory (indirect_ptr_section_start, buf,
nl_symbol_ptr_count * TARGET_ADDRESS_BYTES);
actual_entry_count = 0;
for (i = 0; i < nl_symbol_ptr_count; i++)
{
CORE_ADDR destination_address;
struct obj_section *asect;
destination_address = extract_unsigned_integer
(buf + i * TARGET_ADDRESS_BYTES, TARGET_ADDRESS_BYTES);
if (destination_address == 0)
continue;
asect = find_pc_section (destination_address);
if (asect == NULL || asect->objfile != most_recent_fix_objfile)
continue;
(*indirect_entries)[actual_entry_count].addr =
indirect_ptr_section_start + i * TARGET_ADDRESS_BYTES;
(*indirect_entries)[actual_entry_count].value = destination_address;
(*indirect_entries)[actual_entry_count].new_sym = NULL;
(*indirect_entries)[actual_entry_count].new_msym = NULL;
(*indirect_entries)[actual_entry_count].original_sym = NULL;
(*indirect_entries)[actual_entry_count].original_msym = NULL;
actual_entry_count++;
}
do_cleanups (wipe);
return (actual_entry_count);
}
static struct objfile **
build_list_of_objfiles_to_update (struct fixinfo *cur)
{
struct fixedobj *i;
struct objfile **old_objfiles;
int count, j;
count = 2;
for (i = cur->fixed_object_files; i != NULL; i = i->next)
{
if (i == cur->most_recent_fix)
continue;
count++;
}
old_objfiles = (struct objfile **)
xmalloc (sizeof (struct objfile *) * count);
old_objfiles[0] = find_original_object_file (cur);
j = 1;
for (i = cur->fixed_object_files; i != NULL; i = i->next)
{
if (i == cur->most_recent_fix)
continue;
old_objfiles[j++] = find_objfile_by_name (i->bundle_filename, 1);
}
old_objfiles[j] = NULL;
return (old_objfiles);
}
void
do_final_fix_fixups_global_syms (struct block *newglobals,
struct objfile *oldobj,
struct fixinfo *curfixinfo)
{
struct symtab *oldsymtab;
struct blockvector *oldbv;
struct block *oldblock;
struct symbol *oldsym = NULL;
struct dict_iterator j;
struct symbol *cursym, *newsym;
ALL_BLOCK_SYMBOLS (newglobals, j, cursym)
{
newsym = lookup_block_symbol (newglobals, SYMBOL_PRINT_NAME (cursym),
SYMBOL_LINKAGE_NAME (cursym), VAR_DOMAIN);
if (!newsym || SYMBOL_CLASS (newsym) == LOC_TYPEDEF)
continue;
if (!oldobj)
continue;
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (oldobj, oldsymtab)
{
if (oldsymtab->primary != 1)
continue;
oldbv = BLOCKVECTOR (oldsymtab);
oldblock = BLOCKVECTOR_BLOCK (oldbv, GLOBAL_BLOCK);
if (oldblock != newglobals)
{
oldsym = lookup_block_symbol (oldblock,
SYMBOL_PRINT_NAME (cursym),
SYMBOL_LINKAGE_NAME (cursym), VAR_DOMAIN);
if (oldsym)
break;
}
}
if (!oldsym)
continue;
if (TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_FUNC)
{
if (fix_and_continue_debug_flag)
printf_filtered ("DEBUG: fixed up global %s "
"(newaddr 0x%s, oldaddr 0x%s)\n",
SYMBOL_PRINT_NAME (newsym),
paddr_nz (BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (newsym))),
paddr_nz (BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (oldsym))));
redirect_old_function (curfixinfo, newsym, oldsym,
in_active_func (SYMBOL_LINKAGE_NAME (cursym),
curfixinfo->active_functions));
}
}
}
static void
do_final_fix_fixups_static_syms (struct block *newstatics,
struct objfile *oldobj,
struct fixinfo *curfixinfo)
{
struct symtab *oldsymtab;
struct blockvector *oldbv;
struct block *oldblock;
struct symbol *oldsym = NULL;
struct dict_iterator j;
struct symbol *cursym, *newsym;
struct objfile *original_objfile = find_original_object_file (curfixinfo);
if (!oldobj)
return;
ALL_BLOCK_SYMBOLS (newstatics, j, cursym)
{
newsym = lookup_block_symbol (newstatics, SYMBOL_PRINT_NAME (cursym),
SYMBOL_LINKAGE_NAME (cursym), VAR_DOMAIN);
if (!newsym || SYMBOL_CLASS (newsym) == LOC_TYPEDEF)
continue;
if (SYMBOL_TYPE (newsym) == NULL
|| TYPE_CODE (SYMBOL_TYPE (newsym)) != TYPE_CODE_FUNC)
continue;
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (oldobj, oldsymtab)
{
if (oldsymtab->primary != 1)
continue;
oldbv = BLOCKVECTOR (oldsymtab);
oldblock = BLOCKVECTOR_BLOCK (oldbv, STATIC_BLOCK);
if (oldblock != newstatics)
{
oldsym = lookup_block_symbol (oldblock,
SYMBOL_PRINT_NAME (cursym),
SYMBOL_LINKAGE_NAME (cursym), VAR_DOMAIN);
if (oldsym)
break;
}
}
if (!oldsym)
{
oldsym = search_for_coalesced_symbol
(original_objfile, newsym);
if (oldsym == newsym)
oldsym = NULL;
}
if (!oldsym)
continue;
if (TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_FUNC)
{
if (fix_and_continue_debug_flag)
printf_filtered ("DEBUG: fixed up static %s "
"(newaddr 0x%s, oldaddr 0x%s)\n",
SYMBOL_PRINT_NAME (newsym),
paddr_nz (BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (newsym))),
paddr_nz (BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (oldsym))));
redirect_old_function (curfixinfo, newsym, oldsym,
in_active_func (SYMBOL_LINKAGE_NAME (cursym),
curfixinfo->active_functions));
}
}
}
static void
free_objfile_cleanup (void *obj)
{
free_objfile (obj);
}
static void
pre_load_and_check_file (struct fixinfo *cur)
{
bfd *object_bfd;
struct objfile *new_objfile;
struct cleanup *cleanups;
object_bfd = symfile_bfd_open_safe (cur->bundle_filename, 0, GDB_OSABI_UNKNOWN);
new_objfile = symbol_file_add_bfd_safe (object_bfd, 0, 0, 0, 0, 0,
OBJF_SYM_ALL, (CORE_ADDR) NULL, NULL,
NULL);
new_objfile = raise_objfile_load_level (new_objfile);
cleanups = make_cleanup (free_objfile_cleanup, new_objfile);
force_psymtab_expansion (new_objfile, cur->src_filename, cur->src_basename);
cur->active_functions = create_current_threads_list (cur->src_filename);
do_pre_load_checks (cur, new_objfile);
do_cleanups (cleanups);
}
static struct active_threads *
create_current_threads_list (const char *source_filename)
{
struct thread_info *tp;
struct active_threads *i, *head;
struct active_func *k;
struct cleanup *inferior_ptid;
struct ui_out *null_uiout = NULL;
char buf[80];
enum gdb_rc rc;
i = head = NULL;
inferior_ptid = save_inferior_ptid ();
null_uiout = cli_out_new (gdb_null);
if (null_uiout == NULL)
{
error ("Unable to open null uiout in fix-and-continue.c");
}
make_cleanup_ui_out_delete (null_uiout);
for (tp = thread_list; tp; tp = tp->next)
{
snprintf (buf, 79, "%d", tp->num);
rc = gdb_thread_select (null_uiout, buf, 0, 0);
if (((int) rc < 0 && (enum return_reason) rc == RETURN_ERROR) ||
((int) rc >= 0 && rc == GDB_RC_FAIL))
{
continue;
}
k = create_current_active_funcs_list (source_filename);
if (k != NULL)
{
if (head == NULL)
{
i = head = (struct active_threads *) xmalloc
(sizeof (struct active_threads));
}
else
{
i->next = (struct active_threads *) xmalloc
(sizeof (struct active_threads));
i = i->next;
}
i->num = tp->num;
i->active_func_chain = k;
i->pc = read_pc ();
i->next = NULL;
}
}
do_cleanups (inferior_ptid);
return (head);
}
static void
do_pre_load_checks (struct fixinfo *cur, struct objfile *new_objfile)
{
if (cur->original_objfile_filename == NULL ||
cur->canonical_source_filename == NULL)
{
internal_error (__FILE__, __LINE__, "do_pre_load_checks: "
"Original objfile or canonical source filename not set");
}
if (cur->src_filename == NULL || cur->bundle_filename == NULL)
internal_error (__FILE__, __LINE__,
"do_pre_load_checks: src_filename or bundle_filename not set");
check_restrictions_globals (cur, new_objfile);
check_restrictions_statics (cur, new_objfile);
check_restrictions_locals (cur, new_objfile);
}
static void
check_restrictions_globals (struct fixinfo *cur, struct objfile *newobj)
{
struct objfile *oldobj = find_original_object_file (cur);
struct block *oldblock, *newblock;
struct symtab *oldsymtab, *newsymtab;
struct symbol *oldsym, *newsym, *sym;
const char *sym_source_name, *sym_linkage_name;
char *old_type, *new_type;
struct cleanup *wipe;
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (newobj, newsymtab)
{
if (newsymtab->primary != 1)
continue;
struct dict_iterator i;
newblock = BLOCKVECTOR_BLOCK (BLOCKVECTOR (newsymtab), GLOBAL_BLOCK);
ALL_BLOCK_SYMBOLS (newblock, i, sym)
{
sym_source_name = SYMBOL_PRINT_NAME (sym);
sym_linkage_name = SYMBOL_LINKAGE_NAME (sym);
newsym = lookup_block_symbol (newblock, sym_source_name,
sym_linkage_name, VAR_DOMAIN);
oldsym = NULL;
if (newsym && (SYMBOL_CLASS (newsym) != LOC_TYPEDEF))
{
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (oldobj, oldsymtab)
{
oldblock = BLOCKVECTOR_BLOCK
(BLOCKVECTOR (oldsymtab), GLOBAL_BLOCK);
oldsym = lookup_block_symbol (oldblock, sym_source_name,
sym_linkage_name, VAR_DOMAIN);
if (oldsym)
break;
}
}
if (!oldsym)
continue;
if (TYPE_CODE (SYMBOL_TYPE (oldsym)) == TYPE_CODE_FUNC &&
TYPE_CODE (SYMBOL_TYPE (newsym)) != TYPE_CODE_FUNC)
error ("Changing function '%s' to a variable is not supported.",
SYMBOL_PRINT_NAME (oldsym));
if (TYPE_CODE (SYMBOL_TYPE (oldsym)) != TYPE_CODE_FUNC &&
TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_FUNC)
error ("Changing variable '%s' to a function is not supported.",
SYMBOL_PRINT_NAME (oldsym));
if (TYPE_CODE (SYMBOL_TYPE (oldsym)) == TYPE_CODE_FUNC &&
TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_FUNC)
continue;
old_type = type_sprint (SYMBOL_TYPE (oldsym), NULL, 0);
wipe = make_cleanup (xfree, old_type);
new_type = type_sprint (SYMBOL_TYPE (newsym), NULL, 0);
make_cleanup (xfree, new_type);
if (strcmp (old_type, new_type) != 0)
error ("Changing the type of global variable '%s'"
" from '%s' to '%s' is not supported.",
SYMBOL_PRINT_NAME (oldsym), old_type, new_type);
do_cleanups (wipe);
}
}
}
static void
check_restrictions_statics (struct fixinfo *cur, struct objfile *newobj)
{
struct block *newblock;
struct symtab *newsymtab;
struct symbol *oldsym, *newsym, *sym;
const char *sym_source_name, *sym_linkage_name;
struct objfile *original_objfile = find_original_object_file (cur);
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (newobj, newsymtab)
{
if (newsymtab->primary != 1)
continue;
struct dict_iterator i;
newblock = BLOCKVECTOR_BLOCK (BLOCKVECTOR (newsymtab), STATIC_BLOCK);
ALL_BLOCK_SYMBOLS (newblock, i, sym)
{
if (SYMBOL_DOMAIN (sym) != VAR_DOMAIN &&
SYMBOL_DOMAIN (sym) != METHODS_DOMAIN)
continue;
sym_source_name = SYMBOL_PRINT_NAME (sym);
sym_linkage_name = SYMBOL_LINKAGE_NAME (sym);
newsym = lookup_block_symbol (newblock, sym_source_name,
sym_linkage_name, SYMBOL_DOMAIN (sym));
if (newsym == NULL)
error ("No symbol found for '%s'. "
"Could this be a C++ application whose source filenames end in '.c'?",
sym_source_name);
if (SYMBOL_CLASS (newsym) == LOC_CONST)
continue;
if (TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_FUNC)
continue;
if (strncmp (sym_linkage_name, "_OBJC_", 6) == 0)
continue;
oldsym = lookup_symbol (SYMBOL_LINKAGE_NAME (newsym), NULL,
SYMBOL_DOMAIN (newsym), NULL, NULL);
if (oldsym == newsym &&
(SYMBOL_CLASS (newsym) == LOC_STATIC ||
SYMBOL_CLASS (newsym) == LOC_INDIRECT))
{
oldsym = search_for_coalesced_symbol
(original_objfile, newsym);
if (oldsym == newsym || oldsym == NULL)
continue;
}
if (oldsym == NULL)
continue;
if (SYMBOL_CLASS (oldsym) != LOC_CONST &&
SYMBOL_CLASS (oldsym) != LOC_TYPEDEF)
{
char *old_type, *new_type;
struct cleanup *wipe;
if (TYPE_CODE (SYMBOL_TYPE (oldsym)) == TYPE_CODE_ERROR ||
TYPE_CODE (SYMBOL_TYPE (oldsym)) == TYPE_CODE_UNDEF)
{
warning ("Type code for '%s' unresolvable, "
"skipping type change checks.",
SYMBOL_PRINT_NAME (oldsym));
continue;
}
if (TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_ERROR ||
TYPE_CODE (SYMBOL_TYPE (newsym)) == TYPE_CODE_UNDEF)
{
warning ("Type code for '%s' unresolvable, "
"skipping type change checks.",
SYMBOL_PRINT_NAME (newsym));
continue;
}
old_type = type_sprint (SYMBOL_TYPE (oldsym), NULL, 0);
wipe = make_cleanup (xfree, old_type);
new_type = type_sprint (SYMBOL_TYPE (newsym), NULL, 0);
make_cleanup (xfree, new_type);
if (strcmp (old_type, new_type) != 0)
error ("Changing the type of file static variable '%s'"
" from '%s' to '%s' is not supported.",
SYMBOL_PRINT_NAME (oldsym), old_type, new_type);
do_cleanups (wipe);
}
}
}
}
static void
check_restrictions_locals (struct fixinfo *cur, struct objfile *newobj)
{
struct objfile *oldobj = find_original_object_file (cur);
struct block *oldblock, *newblock;
struct symtab *oldsymtab, *newsymtab;
struct blockvector *oldbv, *newbv;
struct symbol *oldsym;
const char *funcname;
int active, i, j;
int foundmatch;
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (newobj, newsymtab)
{
if (newsymtab->primary != 1)
continue;
newbv = BLOCKVECTOR (newsymtab);
for (i = FIRST_LOCAL_BLOCK; i < BLOCKVECTOR_NBLOCKS (newbv); i++)
{
newblock = BLOCKVECTOR_BLOCK (newbv, i);
if (BLOCK_FUNCTION (newblock) == NULL)
continue;
funcname = SYMBOL_LINKAGE_NAME (BLOCK_FUNCTION (newblock));
if (funcname == NULL)
continue;
active = in_active_func (funcname, cur->active_functions);
foundmatch = 0;
ALL_OBJFILE_SYMTABS_INCL_OBSOLETED (oldobj, oldsymtab)
{
if (oldsymtab->primary != 1)
continue;
oldbv = BLOCKVECTOR (oldsymtab);
for (j = FIRST_LOCAL_BLOCK; j < BLOCKVECTOR_NBLOCKS (oldbv); j++)
{
oldblock = BLOCKVECTOR_BLOCK (oldbv, j);
if (BLOCK_FUNCTION (oldblock) != NULL &&
SYMBOL_MATCHES_NATURAL_NAME (BLOCK_FUNCTION (oldblock),
funcname))
{
check_restrictions_function (funcname, active,
oldblock, newblock);
foundmatch = 1;
break;
}
}
if (foundmatch)
break;
}
if (!foundmatch)
{
oldsym = search_for_coalesced_symbol (oldobj,
BLOCK_FUNCTION (newblock));
if (oldsym)
{
oldblock = SYMBOL_BLOCK_VALUE (oldsym);
if (oldblock != newblock)
check_restrictions_function (funcname, active,
oldblock, newblock);
}
}
}
}
}
static void
check_restrictions_function (const char *funcname, int active,
struct block *oldblock, struct block *newblock)
{
int newfunc_args, oldfunc_args;
int newfunc_locals, oldfunc_locals;
struct dict_iterator i, j;
char *old_type_name, *new_type_name;
struct symbol *oldsym, *newsym;
struct cleanup *wipe;
wipe = make_cleanup (null_cleanup, NULL);
old_type_name = type_sprint (SYMBOL_TYPE (BLOCK_FUNCTION (oldblock)), NULL, 0);
make_cleanup (xfree, old_type_name);
new_type_name = type_sprint (SYMBOL_TYPE (BLOCK_FUNCTION (newblock)), NULL, 0);
make_cleanup (xfree, new_type_name);
if (strcmp (old_type_name, new_type_name) != 0)
error ("Function '%s' was changed from returning '%s' to '%s', which is "
"not supported.", funcname, old_type_name, new_type_name);
oldfunc_args = oldfunc_locals = 0;
ALL_BLOCK_SYMBOLS (oldblock, i, oldsym)
{
if (sym_is_argument (oldsym))
oldfunc_args++;
else if (sym_is_local (oldsym))
oldfunc_locals++;
}
newfunc_args = newfunc_locals = 0;
ALL_BLOCK_SYMBOLS (newblock, i, newsym)
{
if (sym_is_argument (newsym))
newfunc_args++;
else if (sym_is_local (newsym))
newfunc_locals++;
}
if (oldfunc_args != newfunc_args)
error ("Changing number of arguments from %d to %d for function '%s' is "
"not supported.", oldfunc_args, newfunc_args, funcname);
if (active && oldfunc_locals != newfunc_locals)
error ("Changing number of local variables from %d to %d for function '%s'"
" while active on the stack is not supported.",
oldfunc_locals, newfunc_locals, funcname);
for (oldsym = dict_iterator_first (BLOCK_DICT (oldblock), &i),
newsym = dict_iterator_first (BLOCK_DICT (newblock), &j);
oldsym && newsym;
oldsym = dict_iterator_next (&i), newsym = dict_iterator_next (&j))
{
old_type_name = type_sprint (SYMBOL_TYPE (oldsym), NULL, 0);
make_cleanup (xfree, old_type_name);
new_type_name = type_sprint (SYMBOL_TYPE (newsym), NULL, 0);
make_cleanup (xfree, new_type_name);
if (sym_is_argument (oldsym) &&
strcmp (old_type_name, new_type_name) != 0)
{
error ("In function '%s', argument '%s' changed from "
"type '%s' to type '%s', which is not supported.",
funcname, SYMBOL_PRINT_NAME (oldsym),
old_type_name, new_type_name);
}
}
do_cleanups (wipe);
}
static int
sym_is_argument (struct symbol *s)
{
return (SYMBOL_CLASS (s) == LOC_ARG ||
SYMBOL_CLASS (s) == LOC_REF_ARG ||
SYMBOL_CLASS (s) == LOC_REGPARM ||
SYMBOL_CLASS (s) == LOC_REGPARM_ADDR ||
SYMBOL_CLASS (s) == LOC_BASEREG_ARG ||
SYMBOL_CLASS (s) == LOC_COMPUTED_ARG);
}
static int
sym_is_local (struct symbol *s)
{
return (SYMBOL_CLASS (s) == LOC_LOCAL ||
SYMBOL_CLASS (s) == LOC_REGISTER ||
SYMBOL_CLASS (s) == LOC_BASEREG ||
SYMBOL_CLASS (s) == LOC_COMPUTED);
}
static void
force_psymtab_expansion (struct objfile *obj, const char *source_fn,
const char *alt_source_fn)
{
struct partial_symtab *ps;
ALL_OBJFILE_PSYMTABS_INCL_OBSOLETED (obj, ps)
if (!strcmp (source_fn, ps->filename))
PSYMTAB_TO_SYMTAB (ps);
else if (ps->fullname != NULL && !strcmp (source_fn, ps->fullname))
PSYMTAB_TO_SYMTAB (ps);
else if (alt_source_fn != NULL && !strcmp (alt_source_fn, ps->filename))
PSYMTAB_TO_SYMTAB (ps);
else if (alt_source_fn != NULL && ps->fullname != NULL &&
!strcmp (alt_source_fn, ps->filename))
PSYMTAB_TO_SYMTAB (ps);
}
static void
expand_all_objfile_psymtabs (struct objfile *obj)
{
struct partial_symtab *pst;
ALL_OBJFILE_PSYMTABS_INCL_OBSOLETED (obj, pst)
PSYMTAB_TO_SYMTAB (pst);
}
int
file_exists_p (const char *filename)
{
struct stat sb;
if (stat (filename, &sb) != 0)
return 0;
if (S_ISREG (sb.st_mode))
return 1;
else
return 0;
}
static void
free_active_threads_struct (struct active_threads *head)
{
struct active_threads *i = head, *j;
struct active_func *k, *l;
while (i != NULL)
{
k = head->active_func_chain;
while (k != NULL)
{
xfree (SYMBOL_LINKAGE_NAME (k->sym));
if (SYMBOL_CPLUS_DEMANGLED_NAME (k->sym))
xfree (SYMBOL_CPLUS_DEMANGLED_NAME (k->sym));
xfree (k->sym);
if (k->file != NULL)
xfree ((void *)k->file);
if (k->dir != NULL)
xfree ((void *)k->dir);
l = k->next;
xfree (k);
k = l;
}
j = i->next;
xfree (i);
i = j;
}
}
static struct active_func *
create_current_active_funcs_list (const char *source_filename)
{
struct active_func * function_chain = NULL;
struct frame_info *fi;
struct symbol *sym;
struct active_func *func;
struct symtab_and_line sal;
for (fi = get_current_frame (); fi != NULL; fi = get_prev_frame (fi))
{
sal = find_pc_line (get_frame_pc (fi), 0);
if (sal.symtab == NULL)
continue;
if ((!strcmp (source_filename, sal.symtab->filename)) ||
(!strcmp (getbasename (source_filename),
getbasename (sal.symtab->filename))))
{
sym = find_pc_function (get_frame_pc (fi));
if (sym != 0)
{
func = xmalloc (sizeof (struct active_func));
func->level = frame_relative_level (fi);
func->line = sal.line;
func->file = xstrdup (sal.symtab->filename);
if (sal.symtab->dirname)
func->dir = xstrdup (sal.symtab->dirname);
else
func->dir = NULL;
func->fp = get_frame_base (fi);
func->addr = get_frame_pc (fi);
func->sym = (struct symbol *)
xmalloc (sizeof (struct symbol));
memcpy (func->sym, sym, sizeof (struct symbol));
SYMBOL_LINKAGE_NAME (func->sym) = xstrdup (SYMBOL_LINKAGE_NAME (sym));
if (SYMBOL_CPLUS_DEMANGLED_NAME(sym))
SYMBOL_CPLUS_DEMANGLED_NAME (func->sym) =
xstrdup (SYMBOL_CPLUS_DEMANGLED_NAME (sym));
if (function_chain == NULL)
func->next = NULL;
else
func->next = function_chain;
function_chain = func;
}
}
}
return (function_chain);
}
static int
in_active_func (const char *name, struct active_threads *threads)
{
struct active_func *func;
for (; threads != NULL; threads = threads->next)
{
for (func = threads->active_func_chain; func != NULL; func = func->next)
{
if (SYMBOL_MATCHES_NATURAL_NAME (func->sym, name))
return 1;
}
}
return 0;
}
static void
redirect_old_function (struct fixinfo *fixinfo, struct symbol *new_sym,
struct symbol *old_sym, int active)
{
CORE_ADDR oldfuncstart, oldfuncend, newfuncstart, fixup_addr;
struct minimal_symbol *msym;
struct obsoletedsym *obsoletedsym;
if (BLOCK_RANGES (SYMBOL_BLOCK_VALUE (old_sym))
|| BLOCK_RANGES (SYMBOL_BLOCK_VALUE (new_sym)))
{
internal_error (__FILE__, __LINE__,
_("Cannot redirect function with non-contiguous address ranges."));
}
oldfuncstart = BLOCK_START (SYMBOL_BLOCK_VALUE (old_sym));
oldfuncend = BLOCK_END (SYMBOL_BLOCK_VALUE (old_sym));
newfuncstart = BLOCK_START (SYMBOL_BLOCK_VALUE (new_sym));
fixup_addr = oldfuncstart;
#if defined (TARGET_I386)
unsigned char buf[6];
uint32_t relative_offset;
buf[0] = 0xe9;
buf[5] = 0xcc;
relative_offset = (uint32_t) newfuncstart - (oldfuncstart + 5);
store_unsigned_integer (buf + 1, 4, relative_offset);
target_write_memory (oldfuncstart, buf, 6);
#endif
SYMBOL_OBSOLETED (old_sym) = 1;
msym = lookup_minimal_symbol_by_pc (oldfuncstart);
if (msym)
MSYMBOL_OBSOLETED (msym) = 1;
obsoletedsym = xmalloc (sizeof (struct obsoletedsym));
obsoletedsym->oldsym = old_sym;
obsoletedsym->newsym = new_sym;
obsoletedsym->oldmsym = msym;
msym = lookup_minimal_symbol_by_pc (newfuncstart);
obsoletedsym->newmsym = msym;
if (fixinfo->most_recent_fix->obsoletedsym == NULL)
obsoletedsym->next = NULL;
else
obsoletedsym->next = fixinfo->most_recent_fix->obsoletedsym;
fixinfo->most_recent_fix->obsoletedsym = obsoletedsym;
}
CORE_ADDR
decode_fix_and_continue_trampoline (CORE_ADDR pc)
{
#if defined (TARGET_I386)
unsigned char buf[6];
uint32_t relative_offset;
target_read_memory (pc, buf, 6);
if (buf[0] != 0xe9)
return 0;
if (buf[5] != 0xcc)
return 0;
relative_offset = extract_unsigned_integer (buf + 1, 4);
pc += 5;
return pc + relative_offset;
#else
return 0;
#endif
}
static void
print_active_functions (struct fixinfo *cur)
{
struct active_threads *th;
struct active_func *fn;
struct cleanup *uiout_cleanup;
if (!ui_out_is_mi_like_p (uiout))
return;
uiout_cleanup =
make_cleanup_ui_out_list_begin_end (uiout, "replaced-functions");
for (th = cur->active_functions; th != NULL; th = th->next)
{
struct cleanup *uiout_one_thread_cleanup;
uiout_one_thread_cleanup =
make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_int (uiout, "thread-id", th->num);
make_cleanup_ui_out_list_begin_end (uiout, "replaced");
for (fn = th->active_func_chain; fn != NULL; fn = fn->next)
{
struct cleanup *uiout_cleanup
= make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
ui_out_field_int (uiout, "level", fn->level);
ui_out_field_core_addr (uiout, "addr", fn->addr);
ui_out_field_core_addr (uiout, "fp", fn->fp);
ui_out_field_string (uiout, "func", SYMBOL_PRINT_NAME (fn->sym));
ui_out_field_string (uiout, "file", fn->file);
ui_out_field_int (uiout, "line", fn->line);
ui_out_field_string (uiout, "dir", fn->dir);
do_cleanups (uiout_cleanup);
}
do_cleanups (uiout_one_thread_cleanup);
}
do_cleanups (uiout_cleanup);
}
void
update_picbase_register (struct symbol *new_fun)
{
#if defined (TARGET_I386)
if (gdbarch_lookup_osabi (exec_bfd) == GDB_OSABI_DARWIN64)
return;
enum i386_regnum pic_base_reg;
CORE_ADDR pic_base_value;
if (i386_find_picbase_setup (BLOCK_START (SYMBOL_BLOCK_VALUE (new_fun)),
&pic_base_value, &pic_base_reg))
{
if (fix_and_continue_debug_flag)
printf_filtered ("DEBUG: updating picbase in register %d to 0x%s\n",
pic_base_reg, paddr_nz (pic_base_value));
write_register (pic_base_reg, pic_base_value);
}
#endif
}
static struct symtab *
find_symtab_by_name (struct objfile *obj, const char *name)
{
struct symtab *s;
struct partial_symtab *ps;
ALL_SYMTABS_INCL_OBSOLETED (obj, s)
if (!strcmp (name, s->filename))
return s;
ALL_PSYMTABS (obj, ps)
if (!strcmp (name, ps->filename))
return (PSYMTAB_TO_SYMTAB (ps));
return NULL;
}
static struct symbol *
search_for_coalesced_symbol (struct objfile *obj, struct symbol *sym)
{
struct minimal_symbol *minsym;
minsym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (sym), 0, obj);
if (minsym)
{
expand_all_objfile_psymtabs (obj);
return (lookup_symbol (SYMBOL_LINKAGE_NAME (sym), NULL,
SYMBOL_DOMAIN (sym), NULL, NULL));
}
return (NULL);
}
static void
restore_language (void *arg)
{
enum language l = (enum language) arg;
set_language (l);
}
static struct cleanup *
set_current_language (const char *filename)
{
enum language save_language;
enum language new_language;
save_language = current_language->la_language;
new_language = deduce_language_from_filename (filename);
if (new_language == save_language)
return (make_cleanup (null_cleanup, 0));
set_language (new_language);
return (make_cleanup (restore_language, (void *) save_language));
}
static void
find_original_object_file_name (struct fixinfo *cur)
{
struct objfile *obj;
struct partial_symtab *ps;
if (cur->original_objfile_filename != NULL &&
cur->canonical_source_filename != NULL)
return;
ALL_PSYMTABS (obj, ps)
if (!strcmp (ps->filename, cur->src_filename) ||
(ps->fullname != NULL && !strcmp (ps->fullname, cur->src_filename)))
{
if (ps->texthigh != 0 &&
(strcmp (ps->objfile->name, cur->bundle_filename) != 0))
{
PSYMTAB_TO_SYMTAB (ps);
cur->original_objfile_filename = xstrdup (obj->name);
cur->canonical_source_filename = cur->src_filename;
return;
}
}
ALL_PSYMTABS (obj, ps)
if (!strcmp (ps->filename, cur->src_basename) ||
(ps->fullname != NULL && !strcmp (ps->fullname, cur->src_basename)))
{
if (ps->texthigh != 0 &&
(strcmp (ps->objfile->name, cur->bundle_filename) != 0))
{
PSYMTAB_TO_SYMTAB (ps);
cur->original_objfile_filename = xstrdup (obj->name);
cur->canonical_source_filename = cur->src_basename;
return;
}
}
cur->original_objfile_filename = NULL;
cur->canonical_source_filename = NULL;
error ("Unable to find original source file %s. "
"Target built without debugging symbols?", cur->src_basename);
}
static struct objfile *
find_original_object_file (struct fixinfo *cur)
{
if (cur->original_objfile_filename == NULL)
error ("find_original_object_file() called with an empty filename!");
return find_objfile_by_name (cur->original_objfile_filename, 1);
}
static struct symtab *
find_original_symtab (struct fixinfo *cur)
{
return PSYMTAB_TO_SYMTAB (find_original_psymtab (cur));
}
static struct partial_symtab *
find_original_psymtab (struct fixinfo *cur)
{
struct objfile *original_objfile;
struct partial_symtab *pst;
original_objfile = find_original_object_file (cur);
if (original_objfile == NULL)
error ("Unable to find original object file!");
ALL_OBJFILE_PSYMTABS_INCL_OBSOLETED (original_objfile, pst)
if (!strcmp (pst->filename, cur->canonical_source_filename))
return pst;
error ("Unable to find original source file '%s'! "
"Target compiled without debug information?",
cur->canonical_source_filename);
}
static struct objfile *
raise_objfile_load_level (struct objfile *obj)
{
const char *name;
struct cleanup *wipe;
if (obj == NULL || obj->symflags == OBJF_SYM_ALL)
return obj;
name = xstrdup (obj->name);
wipe = make_cleanup (xfree, (char *) name);
objfile_set_load_state (obj, OBJF_SYM_ALL, 1);
obj = find_objfile_by_name (name, 1);
do_cleanups (wipe);
return (obj);
}
int
fix_and_continue_supported (void)
{
if (exec_bfd == NULL)
return -1;
if (gdbarch_lookup_osabi (exec_bfd) == GDB_OSABI_DARWIN64)
return 0;
#if defined (TARGET_ARM)
return 0;
#endif
#if defined (TARGET_POWERPC)
return 0;
#endif
return 1;
}
void
_initialize_fix (void)
{
struct cmd_list_element *c;
c = add_com ("fix", class_files, fix_command, "Bring in a fixed objfile.");
set_cmd_completer (c, filename_completer);
add_setshow_boolean_cmd ("fix-and-continue", class_obscure,
&fix_and_continue_debug_flag, _("\
Set if GDB prints debug information while Fix and Continuing."), _("\
Show if GDB prints debug information while Fix and Continuing."), NULL,
NULL, NULL,
&setdebuglist, &showdebuglist);
}