#include "defs.h"
#include "bfdlink.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcore.h"
#include "frame.h"
#include "target.h"
#include "value.h"
#include "symfile.h"
#include "objfiles.h"
#include "source.h"
#include "gdbcmd.h"
#include "breakpoint.h"
#include "language.h"
#include "complaints.h"
#include "demangle.h"
#include "inferior.h"
#include "filenames.h"
#include "gdb-stabs.h"
#include "gdb_obstack.h"
#include "completer.h"
#include "bcache.h"
#include "hashtab.h"
#include "readline/readline.h"
#include "gdb_assert.h"
#include "block.h"
#include "observer.h"
#include "libbfd.h"
#include "objc-lang.h"
#include "exceptions.h"
#include "exec.h"
#include "macosx/macosx-nat-inferior.h"
#include "macosx/macosx-nat-utils.h"
#include "mach-o.h"
#include "osabi.h"
#include <sys/types.h>
#include <fcntl.h>
#include "gdb_string.h"
#include "gdb_stat.h"
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include <libgen.h>
#include <sys/mman.h>
#ifndef TEXT_SECTION_NAME
#define TEXT_SECTION_NAME ".text"
#endif
#ifndef TEXT_SEGMENT_NAME
#define TEXT_SEGMENT_NAME TEXT_SECTION_NAME
#endif
#ifndef DATA_SECTION_NAME
#define DATA_SECTION_NAME ".data"
#endif
#ifndef BSS_SECTION_NAME
#define BSS_SECTION_NAME ".bss"
#endif
#ifdef MACOSX_DYLD
#include "macosx-nat-dyld.h"
#include "macosx-nat-dyld-process.h"
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if HAVE_MMAP
static int mmap_symbol_files_flag = 0;
#endif
int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num);
void (*deprecated_show_load_progress) (const char *section,
unsigned long section_sent,
unsigned long section_size,
unsigned long total_sent,
unsigned long total_size);
void (*deprecated_pre_add_symbol_hook) (const char *);
void (*deprecated_post_add_symbol_hook) (void);
void (*deprecated_target_new_objfile_hook) (struct objfile *);
static void clear_symtab_users_cleanup (void *ignore);
int readnow_symbol_files;
extern void report_transfer_performance (unsigned long, time_t, time_t);
#if 0
static int simple_read_overlay_region_table (void);
static void simple_free_overlay_region_table (void);
#endif
static void set_initial_language (void);
static void load_command (char *, int);
static void symbol_file_add_main_1 (char *args, int from_tty, int flags);
static void add_symbol_file_command (char *, int);
static void add_shared_symbol_files_command (char *, int);
static void reread_separate_symbols (struct objfile *objfile);
static void cashier_psymtab (struct partial_symtab *);
static int compare_psymbols (const void *, const void *);
bfd *symfile_bfd_open (const char *, int mainline, int osabi);
int get_section_index (struct objfile *, char *);
static void find_sym_fns (struct objfile *);
static void decrement_reading_symtab (void *);
static void overlay_invalidate_all (void);
static int overlay_is_mapped (struct obj_section *);
void list_overlays_command (char *, int);
void map_overlay_command (char *, int);
void unmap_overlay_command (char *, int);
static void overlay_auto_command (char *, int);
static void overlay_manual_command (char *, int);
static void overlay_off_command (char *, int);
static void overlay_load_command (char *, int);
static void overlay_command (char *, int);
static void simple_free_overlay_table (void);
static void read_target_long_array (CORE_ADDR, unsigned int *, int);
static int simple_read_overlay_table (void);
static int simple_overlay_update_1 (struct obj_section *);
static void add_filename_language (char *ext, enum language lang);
static void info_ext_lang_command (char *args, int from_tty);
static void add_dsym_command (char *args, int from_tty);
static char *find_separate_debug_file (struct objfile *objfile);
static const char *already_found_debug_file = NULL;
static void init_filename_language_table (void);
void _initialize_symfile (void);
static char *kext_symbol_file_path = NULL;
static struct section_addr_info *
find_kext_loadaddrs_from_kernel (const char *filename,
char **kext_bundle_executable_filename);
static struct objfile *
symbol_file_add_name_with_addrs_or_offsets_using_objfile (struct objfile *in_objfile,
const char *name,
int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int num_offsets,
int mainline, int flags, int symflags,
CORE_ADDR mapaddr, const char *prefix, char *kext_bundle);
static struct sym_fns *symtab_fns = NULL;
#ifdef SYMBOL_RELOADING_DEFAULT
int symbol_reloading = SYMBOL_RELOADING_DEFAULT;
#else
int symbol_reloading = 0;
#endif
static void
show_symbol_reloading (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Dynamic symbol table reloading multiple times in one run is %s.\n"),
value);
}
int auto_solib_add = 1;
int auto_solib_limit;
static int
compare_psymbols (const void *s1p, const void *s2p)
{
struct partial_symbol *const *s1 = s1p;
struct partial_symbol *const *s2 = s2p;
return strcmp_iw_ordered (SYMBOL_SEARCH_NAME (*s1),
SYMBOL_SEARCH_NAME (*s2));
}
void
sort_pst_symbols (struct partial_symtab *pst)
{
qsort (pst->objfile->global_psymbols.list + pst->globals_offset,
pst->n_global_syms, sizeof (struct partial_symbol *),
compare_psymbols);
}
char *
obsavestring (const char *ptr, int size, struct obstack *obstackp)
{
char *p = (char *) obstack_alloc (obstackp, size + 1);
{
const char *p1 = ptr;
char *p2 = p;
const char *end = ptr + size;
while (p1 != end)
*p2++ = *p1++;
}
p[size] = 0;
return p;
}
char *
obconcat (struct obstack *obstackp, const char *s1, const char *s2,
const char *s3)
{
int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
char *val = (char *) obstack_alloc (obstackp, len);
strcpy (val, s1);
strcat (val, s2);
strcat (val, s3);
return val;
}
int currently_reading_symtab = 0;
static void
decrement_reading_symtab (void *dummy)
{
currently_reading_symtab--;
}
struct symtab *
psymtab_to_symtab (struct partial_symtab *pst)
{
static int timer = -1;
if (pst->symtab)
return pst->symtab;
if (!pst->readin)
{
struct cleanup *back_to = make_cleanup (decrement_reading_symtab, NULL);
start_timer (&timer, "psymtab-to-symtab",
pst->fullname ?
pst->fullname : pst->filename);
currently_reading_symtab++;
(*pst->read_symtab) (pst);
do_cleanups (back_to);
}
return pst->symtab;
}
void
find_lowest_section (bfd *abfd, asection *sect, void *obj)
{
asection **lowest = (asection **) obj;
if (0 == (bfd_get_section_flags (abfd, sect) & SEC_LOAD))
return;
if (!*lowest)
*lowest = sect;
else if (bfd_section_vma (abfd, *lowest) > bfd_section_vma (abfd, sect))
*lowest = sect;
else if (bfd_section_vma (abfd, *lowest) == bfd_section_vma (abfd, sect)
&& (bfd_section_size (abfd, (*lowest))
<= bfd_section_size (abfd, sect)))
*lowest = sect;
}
struct section_addr_info *
alloc_section_addr_info (size_t num_sections)
{
struct section_addr_info *sap;
size_t size;
size = (sizeof (struct section_addr_info)
+ sizeof (struct other_sections) * (num_sections - 1));
sap = (struct section_addr_info *) xmalloc (size);
memset (sap, 0, size);
sap->num_sections = num_sections;
return sap;
}
struct section_addr_info *
copy_section_addr_info (struct section_addr_info *addrs)
{
struct section_addr_info *copy
= alloc_section_addr_info (addrs->num_sections);
int i;
copy->num_sections = addrs->num_sections;
copy->addrs_are_offsets = addrs->addrs_are_offsets;
for (i = 0; i < addrs->num_sections; i++)
{
copy->other[i].addr = addrs->other[i].addr;
if (addrs->other[i].name)
copy->other[i].name = xstrdup (addrs->other[i].name);
else
copy->other[i].name = NULL;
copy->other[i].sectindex = addrs->other[i].sectindex;
}
return copy;
}
extern struct section_addr_info *
build_section_addr_info_from_section_table (const struct section_table *start,
const struct section_table *end)
{
struct section_addr_info *sap;
const struct section_table *stp;
int oidx;
sap = alloc_section_addr_info (end - start);
for (stp = start, oidx = 0; stp != end; stp++)
{
if (bfd_get_section_flags (stp->bfd,
stp->the_bfd_section) & (SEC_ALLOC | SEC_LOAD)
&& oidx < end - start)
{
sap->other[oidx].addr = stp->addr;
sap->other[oidx].name
= xstrdup (bfd_section_name (stp->bfd, stp->the_bfd_section));
sap->other[oidx].sectindex = stp->the_bfd_section->index;
oidx++;
}
}
return sap;
}
extern void
free_section_addr_info (struct section_addr_info *sap)
{
int idx;
for (idx = 0; idx < sap->num_sections; idx++)
if (sap->other[idx].name)
xfree (sap->other[idx].name);
xfree (sap);
}
static void
init_objfile_sect_indices (struct objfile *objfile)
{
asection *sect;
struct obj_section *osect;
int i;
i = 0;
objfile->sect_index_text = 0;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
if (strcmp (osect->the_bfd_section->name, TEXT_SEGMENT_NAME) == 0)
{
objfile->sect_index_text = i;
break;
}
i++;
}
i = 0;
objfile->sect_index_data = 0;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
if (strcmp (osect->the_bfd_section->name, DATA_SECTION_NAME) == 0)
{
objfile->sect_index_data = i;
break;
}
i++;
}
i = 0;
objfile->sect_index_bss = 0;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
if (strcmp (osect->the_bfd_section->name, BSS_SECTION_NAME) == 0)
{
objfile->sect_index_bss = i;
break;
}
i++;
}
sect = bfd_get_section_by_name (objfile->obfd, ".rodata");
if (sect)
objfile->sect_index_rodata = sect->index;
for (i = 0; i < objfile->num_sections; i++)
{
if (ANOFFSET (objfile->section_offsets, i) != 0)
{
break;
}
}
if (objfile->flags & OBJF_SEPARATE_DEBUG_FILE || i == objfile->num_sections)
{
if (objfile->sect_index_text == -1)
objfile->sect_index_text = 0;
if (objfile->sect_index_data == -1)
objfile->sect_index_data = 0;
if (objfile->sect_index_bss == -1)
objfile->sect_index_bss = 0;
if (objfile->sect_index_rodata == -1)
objfile->sect_index_rodata = 0;
}
}
struct place_section_arg
{
struct section_offsets *offsets;
CORE_ADDR lowest;
};
void
place_section (bfd *abfd, asection *sect, void *obj)
{
struct place_section_arg *arg = obj;
CORE_ADDR *offsets = arg->offsets->offsets, start_addr;
int done;
if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0)
return;
if (offsets[sect->index] != 0)
return;
do {
asection *cur_sec;
ULONGEST align = 1 << bfd_get_section_alignment (abfd, sect);
start_addr = (arg->lowest + align - 1) & -align;
done = 1;
for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next)
{
int indx = cur_sec->index;
if (cur_sec == sect)
continue;
if ((bfd_get_section_flags (abfd, cur_sec) & SEC_LOAD) == 0)
continue;
if (bfd_section_vma (abfd, cur_sec) != 0)
continue;
if (offsets[indx] == 0)
continue;
if (start_addr + bfd_get_section_size (sect) > offsets[indx]
&& start_addr < offsets[indx] + bfd_get_section_size (cur_sec))
{
start_addr = offsets[indx] + bfd_get_section_size (cur_sec);
start_addr = (start_addr + align - 1) & -align;
done = 0;
continue;
}
}
}
while (!done);
offsets[sect->index] = start_addr;
arg->lowest = start_addr + bfd_get_section_size (sect);
exec_set_section_address (bfd_get_filename (abfd), sect->index, start_addr);
}
void
default_symfile_offsets (struct objfile *objfile,
struct section_addr_info *addrs)
{
int i;
objfile->num_sections = bfd_count_sections (objfile->obfd);
objfile->section_offsets = (struct section_offsets *)
obstack_alloc (&objfile->objfile_obstack,
SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
memset (objfile->section_offsets, 0,
SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
{
struct other_sections *osp ;
osp = &addrs->other[i] ;
if (osp->addr == 0)
continue;
(objfile->section_offsets)->offsets[osp->sectindex] = osp->addr;
}
if ((bfd_get_file_flags (objfile->obfd) & (EXEC_P | DYNAMIC)) == 0)
{
struct place_section_arg arg;
arg.offsets = objfile->section_offsets;
arg.lowest = 0;
bfd_map_over_sections (objfile->obfd, place_section, &arg);
}
init_objfile_sect_indices (objfile);
}
void
syms_from_objfile (struct objfile *objfile,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int num_offsets,
int mainline,
int verbo)
{
struct section_addr_info *local_addr = NULL;
struct cleanup *old_chain;
gdb_assert (! (addrs && offsets));
init_entry_point_info (objfile);
if (objfile->ei.entry_point != ~(CORE_ADDR) 0
&& objfile->ei.entry_point != 0)
{
if (offsets != NULL)
{
struct obj_section *s;
int found = 0;
ALL_OBJFILE_OSECTIONS (objfile, s)
{
if (s->addr <= objfile->ei.entry_point
&& objfile->ei.entry_point < s->endaddr)
{
found = 1;
break;
}
}
if (found)
objfile->ei.entry_point += ANOFFSET (offsets, s->the_bfd_section->index);
}
else if (addrs != NULL)
{
if (addrs->addrs_are_offsets == 1 && addrs->num_sections > 0)
objfile->ei.entry_point += addrs->other[0].addr;
}
}
find_sym_fns (objfile);
if (objfile->sf == NULL)
return;
old_chain = make_cleanup_free_objfile (objfile);
if (! addrs && ! offsets)
{
local_addr
= alloc_section_addr_info (bfd_count_sections (objfile->obfd));
make_cleanup (xfree, local_addr);
addrs = local_addr;
addrs -> addrs_are_offsets = 1;
}
if (mainline)
{
make_cleanup (clear_symtab_users_cleanup, 0 );
if (symfile_objfile != NULL)
{
free_objfile (symfile_objfile);
symfile_objfile = NULL;
#ifdef MACOSX_DYLD
macosx_init_dyld_symfile (symfile_objfile, exec_bfd);
#endif
}
(*objfile->sf->sym_new_init) (objfile);
}
if (addrs)
{
if (mainline)
addrs -> addrs_are_offsets = 1;
if (!addrs->addrs_are_offsets)
{
asection *lower_sect;
asection *sect;
CORE_ADDR lower_offset;
int i;
gdb_assert (addrs->other[0].name);
lower_sect = bfd_get_section_by_name (objfile->obfd, TEXT_SEGMENT_NAME);
if (lower_sect == NULL)
bfd_map_over_sections (objfile->obfd, find_lowest_section,
&lower_sect);
if (lower_sect == NULL)
warning (_("no loadable sections found in added symbol-file %s"),
objfile->name);
else
if ((bfd_get_section_flags (objfile->obfd, lower_sect) & SEC_CODE) == 0)
warning (_("Lowest section in %s is %s at %s"),
objfile->name,
bfd_section_name (objfile->obfd, lower_sect),
paddr (bfd_section_vma (objfile->obfd, lower_sect)));
if (lower_sect != NULL)
lower_offset = bfd_section_vma (objfile->obfd, lower_sect);
else
lower_offset = 0;
for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
{
if (addrs->other[i].addr != 0)
{
sect = bfd_get_section_by_name (objfile->obfd,
addrs->other[i].name);
if (sect)
{
addrs->other[i].addr
-= bfd_section_vma (objfile->obfd, sect);
lower_offset = addrs->other[i].addr;
addrs->other[i].sectindex = sect->index ;
}
else
{
warning (_("section %s not found in %s"),
addrs->other[i].name,
objfile->name);
addrs->other[i].addr = 0;
}
}
else
addrs->other[i].addr = lower_offset;
}
addrs->addrs_are_offsets = 1;
}
}
(*objfile->sf->sym_init) (objfile);
clear_complaints (&symfile_complaints, 1, verbo);
objfile_delete_from_ordered_sections (objfile);
if (addrs)
(*objfile->sf->sym_offsets) (objfile, addrs);
else
{
struct obj_section *osect;
size_t size = SIZEOF_N_SECTION_OFFSETS (num_offsets);
objfile->num_sections = num_offsets;
objfile->section_offsets
= ((struct section_offsets *)
obstack_alloc (&objfile->objfile_obstack, size));
memcpy (objfile->section_offsets, offsets, size);
init_objfile_sect_indices (objfile);
int idx = 0;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
CORE_ADDR offset = objfile_section_offset (objfile, idx);
idx += 1;
osect->addr += offset;
osect->endaddr += offset;
}
}
objfile_add_to_ordered_sections (objfile);
#ifndef DEPRECATED_IBM6000_TARGET
if (addrs)
{
struct obj_section *s;
ALL_OBJFILE_OSECTIONS (objfile, s)
{
CORE_ADDR s_addr = 0;
int i;
for (i = 0;
!s_addr && i < addrs->num_sections && addrs->other[i].name;
i++)
if (strcmp (bfd_section_name (s->objfile->obfd,
s->the_bfd_section),
addrs->other[i].name) == 0)
s_addr = addrs->other[i].addr;
s->addr -= s->offset;
s->addr += s_addr;
s->endaddr -= s->offset;
s->endaddr += s_addr;
s->offset += s_addr;
}
}
#endif
if ((objfile->symflags & ~OBJF_SYM_CONTAINER) & OBJF_SYM_LEVELS_MASK)
(*objfile->sf->sym_read) (objfile, mainline);
TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0;
objfile->flags |= OBJF_SYMS;
discard_cleanups (old_chain);
}
void
new_symfile_objfile (struct objfile *objfile, int mainline, int verbo)
{
if (mainline)
{
symfile_objfile = objfile;
#ifdef MACOSX_DYLD
macosx_init_dyld_symfile (symfile_objfile, exec_bfd);
#endif
breakpoint_re_set (objfile);
clear_symtab_users ();
}
else
{
breakpoint_re_set (objfile);
}
clear_complaints (&symfile_complaints, 0, verbo);
}
static int
check_bfd_for_matching_uuid (bfd *exe_bfd, bfd *dbg_bfd)
{
unsigned char exe_uuid[16];
unsigned char dbg_uuid[16];
if (bfd_mach_o_get_uuid (exe_bfd, exe_uuid, sizeof (exe_uuid)) &&
bfd_mach_o_get_uuid (dbg_bfd, dbg_uuid, sizeof (dbg_uuid)) &&
(memcmp (exe_uuid, dbg_uuid, sizeof (exe_uuid)) == 0))
return 1;
warning (_("UUID mismatch detected between:\n\t%s\n\t%s..."),
exe_bfd->filename, dbg_bfd->filename);
if (ui_out_is_mi_like_p (uiout))
{
struct cleanup *notify_cleanup =
make_cleanup_ui_out_notify_begin_end (uiout, "uuid-mismatch");
ui_out_field_string (uiout, "file", exe_bfd->filename);
ui_out_field_string (uiout, "debug-file",
dbg_bfd->filename);
do_cleanups (notify_cleanup);
}
return 0;
}
static const char *
add_objfile_prefix (struct objfile *objfile, const char* name)
{
char* prefixed_name;
size_t prefixed_name_length;
if (name && name[0] && objfile && objfile->prefix && objfile->prefix[0])
{
prefixed_name_length = strlen (objfile->prefix) + strlen (name) + 1;
prefixed_name = (char*) obstack_alloc (&objfile->objfile_obstack,
prefixed_name_length);
sprintf (prefixed_name, "%s%s", objfile->prefix, name);
return prefixed_name;
}
return name;
}
static struct obj_section *
find_section_for_addr (struct objfile *objfile, CORE_ADDR addr)
{
struct obj_section *curr_osect;
struct obj_section *best_osect = NULL;
ALL_OBJFILE_OSECTIONS (objfile, curr_osect)
{
if (curr_osect->addr <= addr && addr < curr_osect->endaddr)
{
if (best_osect)
{
if ((curr_osect->endaddr - curr_osect->addr) <
(best_osect->endaddr - best_osect->addr))
best_osect = curr_osect;
}
else
best_osect = curr_osect;
}
}
return best_osect;
}
void
append_psymbols_as_msymbols (struct objfile *objfile)
{
int i;
struct obj_section *psym_osect;
CORE_ADDR psym_addr;
const char* psym_linkage_name;
struct objfile *dsym_objfile = objfile->separate_debug_objfile;
struct cleanup *back_to;
int add_prefix = objfile->prefix && objfile->prefix[0];
init_minimal_symbol_collection ();
back_to = make_cleanup_discard_minimal_symbols ();
if (dsym_objfile->global_psymbols.list && dsym_objfile->global_psymbols.next)
{
int symcount = dsym_objfile->global_psymbols.next - dsym_objfile->global_psymbols.list;
for (i = 0; i < symcount; i++)
{
struct partial_symbol *psym = dsym_objfile->global_psymbols.list[i];
psym_osect = NULL;
if (PSYMBOL_DOMAIN (psym) == VAR_DOMAIN
&& PSYMBOL_CLASS (psym) == LOC_BLOCK)
{
psym_addr = SYMBOL_VALUE_ADDRESS (psym);
psym_osect = find_section_for_addr (objfile, psym_addr);
if (psym_osect != NULL)
{
struct minimal_symbol *msym;
msym = lookup_minimal_symbol_by_pc_section_from_objfile (psym_addr,
psym_osect->the_bfd_section,
objfile);
if (msym != NULL
&& SYMBOL_VALUE_ADDRESS (msym) == psym_addr)
continue;
if (add_prefix)
{
psym_linkage_name =
add_objfile_prefix (objfile,
SYMBOL_LINKAGE_NAME (psym));
}
else
psym_linkage_name = SYMBOL_LINKAGE_NAME (psym);
char *armthumb_info = partial_symbol_special_info (dsym_objfile,
psym);
msym = prim_record_minimal_symbol_and_info (psym_linkage_name,
psym_addr,
mst_text,
armthumb_info,
SECT_OFF_TEXT (objfile),
psym_osect->the_bfd_section,
objfile);
}
}
}
}
if (dsym_objfile->static_psymbols.list && dsym_objfile->static_psymbols.next)
{
int symcount = dsym_objfile->static_psymbols.next - dsym_objfile->static_psymbols.list;
for (i = 0; i < symcount; i++)
{
struct partial_symbol *psym = dsym_objfile->static_psymbols.list[i];
if (PSYMBOL_DOMAIN (psym) == VAR_DOMAIN
&& PSYMBOL_CLASS (psym) == LOC_BLOCK)
{
psym_addr = SYMBOL_VALUE_ADDRESS (psym);
psym_osect = find_section_for_addr (objfile, psym_addr);
if (psym_osect != NULL)
{
struct minimal_symbol *msym;
msym = lookup_minimal_symbol_by_pc_section_from_objfile (psym_addr,
psym_osect->the_bfd_section,
objfile);
if (msym != NULL
&& SYMBOL_VALUE_ADDRESS (msym) == psym_addr)
continue;
if (add_prefix)
{
psym_linkage_name =
add_objfile_prefix (objfile,
SYMBOL_LINKAGE_NAME (psym));
}
else
psym_linkage_name = SYMBOL_LINKAGE_NAME (psym);
char *armthumb_info = partial_symbol_special_info (dsym_objfile,
psym);
msym = prim_record_minimal_symbol_and_info (psym_linkage_name,
psym_addr,
mst_file_text,
armthumb_info,
SECT_OFF_TEXT (objfile),
psym_osect->the_bfd_section,
objfile);
}
}
}
}
install_minimal_symbols (objfile);
do_cleanups (back_to);
}
struct dbxread_symloc
{
int ldsymoff;
int ldsymlen;
int symbol_size;
int symbol_offset;
int string_offset;
int file_string_offset;
const char *prefix;
};
#define LDSYMOFF(p) (((struct dbxread_symloc *)((p)->read_symtab_private))->ldsymoff)
#define LDSYMLEN(p) (((struct dbxread_symloc *)((p)->read_symtab_private))->ldsymlen)
#define SYMLOC(p) ((struct dbxread_symloc *)((p)->read_symtab_private))
#define SYMBOL_SIZE(p) (SYMLOC(p)->symbol_size)
#define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset)
#define STRING_OFFSET(p) (SYMLOC(p)->string_offset)
#define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset)
#define SYMBOL_PREFIX(p) (SYMLOC(p)->prefix)
void
replace_psymbols_with_correct_psymbols (struct objfile *exe_obj)
{
struct objfile *dsym_obj = exe_obj->separate_debug_objfile;
struct partial_symtab *exe_pst;
struct partial_symtab *dsym_pst;
dsym_obj->not_loaded_kext_filename = exe_obj->not_loaded_kext_filename;
dsym_obj->psymtabs = NULL;
ALL_OBJFILE_PSYMTABS (exe_obj, exe_pst)
{
struct partial_symbol **psym;
int i;
dsym_pst = start_psymtab_common (dsym_obj, dsym_obj->section_offsets,
exe_pst->filename, exe_pst->textlow,
dsym_obj->global_psymbols.next,
dsym_obj->static_psymbols.next);
dsym_pst->read_symtab_private = (char *)
obstack_alloc (&dsym_obj->objfile_obstack,
sizeof (struct dbxread_symloc));
LDSYMOFF (dsym_pst) = LDSYMOFF (exe_pst);
dsym_pst->read_symtab = dwarf2_kext_psymtab_to_symtab;
SYMBOL_SIZE (dsym_pst) = SYMBOL_SIZE (exe_pst);
SYMBOL_OFFSET (dsym_pst) = SYMBOL_OFFSET (exe_pst);
STRING_OFFSET (dsym_pst) = STRING_OFFSET (exe_pst);
FILE_STRING_OFFSET (dsym_pst) = FILE_STRING_OFFSET (exe_pst);
SYMBOL_PREFIX (dsym_pst) = SYMBOL_PREFIX (exe_pst);
dsym_pst->language = exe_pst->language;
dsym_pst->texthigh = exe_pst->texthigh;
dsym_pst->textlow = exe_pst->textlow;
PSYMTAB_OBSOLETED (dsym_pst) = PSYMTAB_OBSOLETED (exe_pst);
psym = exe_pst->objfile->global_psymbols.list + exe_pst->globals_offset;
for (i = 0; i < exe_pst->n_global_syms; i++, psym++)
{
add_psymbol_to_list (DEPRECATED_SYMBOL_NAME (*psym),
strlen (DEPRECATED_SYMBOL_NAME (*psym)),
SYMBOL_DOMAIN (*psym),
SYMBOL_CLASS (*psym),
&dsym_pst->objfile->global_psymbols,
0,
SYMBOL_VALUE_ADDRESS (*psym),
SYMBOL_LANGUAGE (*psym),
dsym_pst->objfile);
}
dsym_pst->n_global_syms =
dsym_obj->global_psymbols.next -
(dsym_obj->global_psymbols.list + dsym_pst->globals_offset);
psym = exe_pst->objfile->static_psymbols.list + exe_pst->statics_offset;
for (i = 0; i< exe_pst->n_static_syms; i++, psym++)
{
add_psymbol_to_list (DEPRECATED_SYMBOL_NAME (*psym),
strlen (DEPRECATED_SYMBOL_NAME (*psym)),
SYMBOL_DOMAIN (*psym),
SYMBOL_CLASS (*psym),
&dsym_pst->objfile->static_psymbols,
0,
SYMBOL_VALUE_ADDRESS (*psym),
SYMBOL_LANGUAGE (*psym),
dsym_pst->objfile);
}
dsym_pst->n_static_syms =
dsym_obj->static_psymbols.next -
(dsym_obj->static_psymbols.list + dsym_pst->statics_offset);
if (PSYMTAB_OSO_NAME (exe_pst))
PSYMTAB_OSO_NAME (dsym_pst) = xstrdup (PSYMTAB_OSO_NAME (exe_pst));
PSYMTAB_OSO_MTIME (dsym_pst) = PSYMTAB_OSO_MTIME (exe_pst);
}
exe_obj->psymtabs = NULL;
exe_obj->symtabs = NULL;
tell_breakpoints_objfile_changed (dsym_obj);
tell_objc_msgsend_cacher_objfile_changed (dsym_obj);
symtab_clear_cached_lookup_values ();
}
struct objfile *
symbol_file_add_with_addrs_or_offsets_using_objfile (struct objfile *in_objfile,
bfd *abfd, int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int num_offsets,
int mainline, int flags, int symflags,
CORE_ADDR mapaddr, const char *prefix,
char *not_loaded_kext_bundle)
{
struct objfile *objfile;
struct partial_symtab *psymtab;
char *debugfile;
struct section_addr_info *orig_addrs = NULL;
struct cleanup *my_cleanups;
const char *name = bfd_get_filename (abfd);
int using_orig_objfile = (in_objfile != NULL);
my_cleanups = make_cleanup_bfd_close (abfd);
if ((symfile_objfile != NULL)
&& mainline
&& from_tty
&& !query ("Load new symbol table from \"%s\"? ", name))
error (_("Not confirmed."));
if (!using_orig_objfile)
objfile = allocate_objfile (abfd, flags, symflags, mapaddr, prefix);
else
{
allocate_objfile_using_objfile (in_objfile, abfd, flags, symflags,
mapaddr, prefix);
objfile = in_objfile;
}
discard_cleanups (my_cleanups);
objfile->prefix = prefix;
if (not_loaded_kext_bundle)
objfile->not_loaded_kext_filename = xstrdup (not_loaded_kext_bundle);
orig_addrs = alloc_section_addr_info (bfd_count_sections (abfd));
my_cleanups = make_cleanup (xfree, orig_addrs);
if (addrs)
{
orig_addrs = copy_section_addr_info (addrs);
make_cleanup_free_section_addr_info (orig_addrs);
}
if (from_tty || info_verbose)
{
if (deprecated_pre_add_symbol_hook)
deprecated_pre_add_symbol_hook (name);
else
{
printf_unfiltered (_("Reading symbols from %s..."), name);
wrap_here ("");
gdb_flush (gdb_stdout);
}
}
if (!(flags & OBJF_SEPARATE_DEBUG_FILE))
{
debugfile = find_separate_debug_file (objfile);
if (debugfile)
{
struct section_addr_info *addrs_to_use;
struct section_offsets *sym_offsets = NULL;
int num_sym_offsets = 0;
bfd *debug_bfd;
int uuid_matches;
enum gdb_osabi objfile_osabi = GDB_OSABI_UNKNOWN;
if (addrs != NULL)
addrs_to_use = orig_addrs;
else
addrs_to_use = NULL;
#ifdef MACOSX_DYLD
objfile_osabi = macosx_get_osabi_from_dyld_entry (objfile->obfd);
#endif
debug_bfd = symfile_bfd_open_safe (debugfile, mainline, objfile_osabi);
if (debug_bfd == NULL)
{
warning ("Unable to open dSYM file '%s'", debugfile);
}
else
{
if (objfile->not_loaded_kext_filename)
uuid_matches = 1;
else
uuid_matches = check_bfd_for_matching_uuid (objfile->obfd,
debug_bfd);
if (uuid_matches)
{
#ifdef TM_NEXTSTEP
if (not_loaded_kext_bundle == 0)
macho_calculate_offsets_for_dsym (objfile, debug_bfd,
addrs_to_use, offsets, num_offsets,
&sym_offsets, &num_sym_offsets);
addrs_to_use = NULL;
#endif
objfile->separate_debug_objfile
= symbol_file_add_with_addrs_or_offsets_using_objfile
(objfile->separate_debug_objfile,
debug_bfd, from_tty,
addrs_to_use,
sym_offsets, num_sym_offsets, 0,
flags | OBJF_SEPARATE_DEBUG_FILE,
symflags, mapaddr, prefix,
not_loaded_kext_bundle);
objfile->separate_debug_objfile->separate_debug_objfile_backlink
= objfile;
put_objfile_before (objfile->separate_debug_objfile, objfile);
}
else
bfd_close (debug_bfd);
}
xfree (debugfile);
}
}
syms_from_objfile (objfile, addrs, offsets, num_offsets,
mainline, from_tty);
if ((flags & OBJF_READNOW) || readnow_symbol_files)
{
if (from_tty || info_verbose)
{
printf_unfiltered (_("expanding to full symbols..."));
wrap_here ("");
gdb_flush (gdb_stdout);
}
ALL_OBJFILE_PSYMTABS (objfile, psymtab)
{
psymtab_to_symtab (psymtab);
}
}
if (from_tty || info_verbose)
{
if (deprecated_post_add_symbol_hook)
deprecated_post_add_symbol_hook ();
else
{
printf_unfiltered (_("done.\n"));
}
}
gdb_flush (gdb_stdout);
do_cleanups (my_cleanups);
#ifndef MACOSX_DYLD
if (objfile->sf == NULL)
return objfile;
#endif
new_symfile_objfile (objfile, mainline, from_tty);
if (objfile->separate_debug_objfile)
append_psymbols_as_msymbols (objfile);
if (objfile->separate_debug_objfile && objfile->not_loaded_kext_filename)
replace_psymbols_with_correct_psymbols (objfile);
if (deprecated_target_new_objfile_hook)
deprecated_target_new_objfile_hook (objfile);
#if defined (TARGET_ARM)
if (mainline && objfile->obfd &&
(gdbarch_osabi (current_gdbarch) == GDB_OSABI_UNKNOWN || gdbarch_osabi (current_gdbarch) == GDB_OSABI_DARWIN))
{
const char *osabi_name = gdbarch_osabi_name (gdbarch_lookup_osabi_from_bfd (objfile->obfd));
if (osabi_name && strcasecmp (osabi_name, "unknown") != 0)
set_osabi_from_string (osabi_name);
}
#endif
bfd_cache_close_all ();
return (objfile);
}
static struct objfile *
symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int num_offsets,
int mainline, int flags, int symflags,
CORE_ADDR mapaddr, const char *prefix,
char *kext_bundle)
{
return symbol_file_add_with_addrs_or_offsets_using_objfile (NULL, abfd, from_tty, addrs,
offsets, num_offsets,
mainline, flags, symflags,
mapaddr, prefix, kext_bundle);
}
struct objfile *
symbol_file_add_name_with_addrs_or_offsets (const char *name, int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int num_offsets,
int mainline, int flags,
int symflags, CORE_ADDR mapaddr,
const char *prefix,
char *kext_bundle)
{
bfd *abfd;
abfd = symfile_bfd_open (name, mainline, GDB_OSABI_UNKNOWN);
return symbol_file_add_with_addrs_or_offsets
(abfd, from_tty, addrs, offsets, num_offsets, mainline, flags, symflags,
mapaddr, prefix, kext_bundle);
}
static struct objfile *
symbol_file_add_name_with_addrs_or_offsets_using_objfile (struct objfile *in_objfile,
const char *name,
int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int num_offsets,
int mainline, int flags, int symflags,
CORE_ADDR mapaddr, const char *prefix, char *kext_bundle)
{
bfd *abfd;
enum gdb_osabi in_objfile_osabi = GDB_OSABI_UNKNOWN;
#ifdef MACOSX_DYLD
if (in_objfile)
in_objfile_osabi = macosx_get_osabi_from_dyld_entry (in_objfile->obfd);
#endif
abfd = symfile_bfd_open (name, mainline, in_objfile_osabi);
return symbol_file_add_with_addrs_or_offsets_using_objfile
(in_objfile, abfd, from_tty, addrs, offsets, num_offsets, mainline, flags, symflags, mapaddr, prefix, kext_bundle);
}
struct objfile *
symbol_file_add_from_bfd (bfd *abfd, int from_tty,
struct section_addr_info *addrs,
int mainline, int flags)
{
return symbol_file_add_with_addrs_or_offsets (abfd,
from_tty, addrs, 0, 0,
mainline, flags,
0, 0, NULL, 0);
}
struct objfile *
symbol_file_add (const char *name, int from_tty, struct section_addr_info *addrs,
int mainline, int flags)
{
return symbol_file_add_name_with_addrs_or_offsets
(name, from_tty, addrs, 0, 0, mainline, flags, OBJF_SYM_ALL, 0, NULL,
NULL);
}
struct objfile *
symbol_file_add_using_objfile (struct objfile *in_objfile,
const char *name, int from_tty, struct section_addr_info *addrs,
int mainline, int flags)
{
return symbol_file_add_name_with_addrs_or_offsets_using_objfile
(in_objfile, name, from_tty, addrs, 0, 0, mainline, flags, OBJF_SYM_ALL, 0, NULL, NULL);
}
void
symbol_file_add_main (char *args, int from_tty)
{
symbol_file_add_main_1 (args, from_tty, 0);
}
static void
symbol_file_add_main_1 (char *args, int from_tty, int flags)
{
int symflags = OBJF_SYM_ALL;
#ifdef MACOSX_DYLD
struct dyld_objfile_entry e;
dyld_objfile_entry_clear (&e);
e.allocated = 1;
e.load_flag = -1;
e.reason = dyld_reason_executable;
e.text_name = args;
e.text_name_valid = 1;
e.loaded_name = e.text_name;
e.loaded_from_memory = 0;
e.loaded_addr = 0;
e.loaded_addrisoffset = 1;
symflags = dyld_default_load_flag (NULL, &e) | dyld_minimal_load_flag (NULL, &e);
#endif
symbol_file_add_name_with_addrs_or_offsets
(args, from_tty, NULL, 0, 0, 1, flags, symflags, 0, NULL, NULL);
reinit_frame_cache ();
set_initial_language ();
}
void
symbol_file_clear (int from_tty)
{
if ((symfile_objfile != NULL)
&& from_tty
&& !query ("Discard symbol table from `%s'? ",
symfile_objfile->name))
error (_("Not confirmed."));
#ifdef MACOSX_DYLD
if (symfile_objfile != NULL)
{
free_objfile (symfile_objfile);
symfile_objfile = NULL;
macosx_init_dyld_symfile (symfile_objfile, exec_bfd);
}
#else
free_all_objfiles ();
#endif
symtab_clear_cached_lookup_values ();
#if defined(SOLIB_RESTART)
SOLIB_RESTART ();
#endif
symfile_objfile = NULL;
if (from_tty)
printf_unfiltered (_("No symbol file now.\n"));
if (state_change_hook)
state_change_hook (STATE_ACTIVE);
}
#if 0
static char *
get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
{
asection *sect;
bfd_size_type debuglink_size;
unsigned long crc32;
char *contents;
int crc_offset;
sect = bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink");
if (sect == NULL)
return NULL;
debuglink_size = bfd_section_size (objfile->obfd, sect);
contents = xmalloc (debuglink_size);
bfd_get_section_contents (objfile->obfd, sect, contents,
(file_ptr)0, (bfd_size_type)debuglink_size);
crc_offset = strlen (contents) + 1;
crc_offset = (crc_offset + 3) & ~3;
crc32 = bfd_get_32 (objfile->obfd, (bfd_byte *) (contents + crc_offset));
*crc32_out = crc32;
return contents;
}
static int
separate_debug_file_exists (const char *name, unsigned long crc)
{
unsigned long file_crc = 0;
int fd;
char buffer[8*1024];
int count;
fd = open (name, O_RDONLY | O_BINARY);
if (fd < 0)
return 0;
while ((count = read (fd, buffer, sizeof (buffer))) > 0)
file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
close (fd);
return crc == file_crc;
}
#endif
static char *debug_file_directory = NULL;
static void
show_debug_file_directory (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
The directory where separate debug symbols are searched for is \"%s\".\n"),
value);
}
#if ! defined (DEBUG_SUBDIRECTORY)
#define DEBUG_SUBDIRECTORY ".debug"
#endif
#ifdef TM_NEXTSTEP
static char *
find_separate_debug_file (struct objfile *objfile)
{
if (already_found_debug_file != NULL)
return xstrdup (already_found_debug_file);
return macosx_locate_dsym (objfile);
}
#else
static char *
find_separate_debug_file (struct objfile *objfile)
{
char *basename;
char *dir;
char *debugfile;
unsigned long crc32;
int i;
basename = get_debug_link_info (objfile, &crc32);
if (basename == NULL)
return NULL;
dir = xstrdup (objfile->name);
for (i = strlen(dir) - 1; i >= 0; i--)
{
if (IS_DIR_SEPARATOR (dir[i]))
break;
}
gdb_assert (i >= 0 && IS_DIR_SEPARATOR (dir[i]));
dir[i+1] = '\0';
debugfile = alloca (strlen (debug_file_directory) + 1
+ strlen (dir)
+ strlen (DEBUG_SUBDIRECTORY)
+ strlen ("/")
+ strlen (basename)
+ 1);
strcpy (debugfile, dir);
strcat (debugfile, basename);
if (separate_debug_file_exists (debugfile, crc32))
{
xfree (basename);
xfree (dir);
return xstrdup (debugfile);
}
strcpy (debugfile, dir);
strcat (debugfile, DEBUG_SUBDIRECTORY);
strcat (debugfile, "/");
strcat (debugfile, basename);
if (separate_debug_file_exists (debugfile, crc32))
{
xfree (basename);
xfree (dir);
return xstrdup (debugfile);
}
strcpy (debugfile, debug_file_directory);
strcat (debugfile, "/");
strcat (debugfile, dir);
strcat (debugfile, basename);
if (separate_debug_file_exists (debugfile, crc32))
{
xfree (basename);
xfree (dir);
return xstrdup (debugfile);
}
xfree (basename);
xfree (dir);
return NULL;
}
#endif
void
symbol_file_command (char *args, int from_tty)
{
char **argv;
char *name = NULL;
struct cleanup *cleanups;
int flags = OBJF_USERLOADED;
dont_repeat ();
if (args == NULL)
{
symbol_file_clear (from_tty);
}
else
{
if ((argv = buildargv (args)) == NULL)
{
nomem (0);
}
cleanups = make_cleanup_freeargv (argv);
while (*argv != NULL)
{
if (strcmp (*argv, "-readnow") == 0)
flags |= OBJF_READNOW;
else if (**argv == '-')
error (_("unknown option `%s'"), *argv);
else
{
name = *argv;
symbol_file_add_main_1 (name, from_tty, flags);
}
argv++;
}
if (name == NULL)
{
error (_("no symbol file name was specified"));
}
do_cleanups (cleanups);
}
if (state_change_hook)
{
state_change_hook (STATE_INFERIOR_LOADED);
}
}
static void
set_initial_language (void)
{
struct partial_symtab *pst;
enum language lang = language_unknown;
pst = find_main_psymtab ();
if (pst != NULL)
{
if (pst->filename != NULL)
{
lang = deduce_language_from_filename (pst->filename);
}
if (lang == language_unknown)
{
lang = language_c;
}
set_language (lang);
expected_language = current_language;
}
}
bfd *
symfile_bfd_open (const char *name, int mainline, enum gdb_osabi osabi)
{
bfd *sym_bfd = NULL;
int desc;
char *absolute_name = NULL;
name = tilde_expand (name);
desc = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, name, O_RDONLY | O_BINARY,
0, &absolute_name);
#if defined(__GO32__) || defined(_WIN32) || defined (__CYGWIN__)
if (mainline && desc < 0)
{
char *exename = alloca (strlen (name) + 5);
strcat (strcpy (exename, name), ".exe");
desc = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, exename,
O_RDONLY | O_BINARY, 0, &absolute_name);
}
#endif
#ifdef TM_NEXTSTEP
if (desc < 0)
{
char *wrapped_filename = macosx_filename_in_bundle (name, mainline);
if (wrapped_filename != NULL)
{
desc = openp (getenv ("PATH"), 1, wrapped_filename, O_RDONLY | O_BINARY,
0, &absolute_name);
xfree (wrapped_filename);
}
}
#endif
if (desc < 0)
{
make_cleanup (xfree, (char *) name);
perror_with_name (name);
}
xfree ((char *) name);
name = absolute_name;
if (desc > 0)
sym_bfd = bfd_fopen (name, gnutarget, FOPEN_RB, desc);
if (!sym_bfd)
{
close (desc);
make_cleanup (xfree, (char *) name);
error (_("\"%s\": can't open to read symbols: %s."), name,
bfd_errmsg (bfd_get_error ()));
}
sym_bfd->cacheable = 1;
#if HAVE_MMAP
if (mmap_symbol_files_flag)
{
if (!bfd_mmap_file (sym_bfd, (void *) -1))
error ("\"%s\": could not mmap file for read: %s",
name, bfd_errmsg (bfd_get_error ()));
}
#endif
if (bfd_check_format (sym_bfd, bfd_archive))
{
bfd *tmp_bfd;
tmp_bfd = open_bfd_matching_arch (sym_bfd, bfd_object, osabi);
if (tmp_bfd != NULL)
sym_bfd = tmp_bfd;
}
bfd_set_cacheable (sym_bfd, 1);
if (!bfd_check_format (sym_bfd, bfd_object))
{
bfd_close (sym_bfd);
make_cleanup (xfree, (char *) name);
error (_("\"%s\": can't read symbols: %s."), name,
bfd_errmsg (bfd_get_error ()));
}
return (sym_bfd);
}
int
get_section_index (struct objfile *objfile, char *section_name)
{
asection *sect = bfd_get_section_by_name (objfile->obfd, section_name);
if (sect)
return sect->index;
else
return -1;
}
void
add_symtab_fns (struct sym_fns *sf)
{
sf->next = symtab_fns;
symtab_fns = sf;
}
static void
find_sym_fns (struct objfile *objfile)
{
struct sym_fns *sf;
enum bfd_flavour our_flavour = bfd_get_flavour (objfile->obfd);
if (our_flavour == bfd_target_srec_flavour
|| our_flavour == bfd_target_ihex_flavour
|| our_flavour == bfd_target_tekhex_flavour)
return;
for (sf = symtab_fns; sf != NULL; sf = sf->next)
{
if (our_flavour == sf->sym_flavour)
{
objfile->sf = sf;
return;
}
}
error (_("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown."),
bfd_get_target (objfile->obfd));
}
static void
load_command (char *arg, int from_tty)
{
if (arg == NULL)
arg = get_exec_file (1);
target_load (arg, from_tty);
overlay_cache_invalid = 1;
}
static int download_write_size = 512;
static void
show_download_write_size (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
The write size used when downloading a program is %s.\n"),
value);
}
static int validate_download = 0;
static void
add_section_size_callback (bfd *abfd, asection *asec, void *data)
{
bfd_size_type *sum = data;
*sum += bfd_get_section_size (asec);
}
struct load_section_data {
unsigned long load_offset;
unsigned long write_count;
unsigned long data_count;
bfd_size_type total_size;
const char *section_name;
ULONGEST section_sent;
ULONGEST section_size;
CORE_ADDR lma;
gdb_byte *buffer;
};
static void
load_progress (ULONGEST bytes, void *untyped_arg)
{
struct load_section_data *args = untyped_arg;
if (validate_download)
{
gdb_byte *check = xmalloc (bytes);
struct cleanup *verify_cleanups = make_cleanup (xfree, check);
if (target_read_memory (args->lma, check, bytes) != 0)
error (_("Download verify read failed at 0x%s"),
paddr (args->lma));
if (memcmp (args->buffer, check, bytes) != 0)
error (_("Download verify compare failed at 0x%s"),
paddr (args->lma));
do_cleanups (verify_cleanups);
}
args->data_count += bytes;
args->lma += bytes;
args->buffer += bytes;
args->write_count += 1;
args->section_sent += bytes;
if (quit_flag
|| (deprecated_ui_load_progress_hook != NULL
&& deprecated_ui_load_progress_hook (args->section_name,
args->section_sent)))
error (_("Canceled the download"));
if (deprecated_show_load_progress != NULL)
deprecated_show_load_progress (args->section_name,
args->section_sent,
args->section_size,
args->data_count,
args->total_size);
}
static void
load_section_callback (bfd *abfd, asection *asec, void *data)
{
struct load_section_data *args = data;
bfd_size_type size = bfd_get_section_size (asec);
gdb_byte *buffer;
struct cleanup *old_chain;
const char *sect_name = bfd_get_section_name (abfd, asec);
LONGEST transferred;
if ((bfd_get_section_flags (abfd, asec) & SEC_LOAD) == 0)
return;
if (size == 0)
return;
buffer = xmalloc (size);
old_chain = make_cleanup (xfree, buffer);
args->section_name = sect_name;
args->section_sent = 0;
args->section_size = size;
args->lma = bfd_section_lma (abfd, asec) + args->load_offset;
args->buffer = buffer;
ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
sect_name, paddr_nz (size), paddr_nz (args->lma));
bfd_get_section_contents (abfd, asec, buffer, 0, size);
transferred = target_write_with_progress (¤t_target,
TARGET_OBJECT_MEMORY,
NULL, buffer, args->lma,
size, load_progress, args);
if (transferred < size)
error (_("Memory access error while loading section %s."),
sect_name);
do_cleanups (old_chain);
}
void
generic_load (char *args, int from_tty)
{
bfd *loadfile_bfd;
struct timeval start_time, end_time;
char *filename;
struct cleanup *old_cleanups;
char *offptr;
struct load_section_data cbdata;
CORE_ADDR entry;
cbdata.load_offset = 0;
cbdata.write_count = 0;
cbdata.data_count = 0;
cbdata.total_size = 0;
filename = xmalloc (strlen (args) + 1);
old_cleanups = make_cleanup (xfree, filename);
strcpy (filename, args);
offptr = strchr (filename, ' ');
if (offptr != NULL)
{
char *endptr;
cbdata.load_offset = strtoul (offptr, &endptr, 0);
if (offptr == endptr)
error (_("Invalid download offset:%s."), offptr);
*offptr = '\0';
}
else
cbdata.load_offset = 0;
loadfile_bfd = bfd_openr (xstrdup (filename), gnutarget);
if (loadfile_bfd == NULL)
{
perror_with_name (filename);
return;
}
make_cleanup_bfd_close (loadfile_bfd);
if (!bfd_check_format (loadfile_bfd, bfd_object))
{
error (_("\"%s\" is not an object file: %s"), filename,
bfd_errmsg (bfd_get_error ()));
}
bfd_map_over_sections (loadfile_bfd, add_section_size_callback,
(void *) &cbdata.total_size);
gettimeofday (&start_time, NULL);
bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
gettimeofday (&end_time, NULL);
entry = bfd_get_start_address (loadfile_bfd);
ui_out_text (uiout, "Start address ");
ui_out_field_fmt (uiout, "address", "0x%s", paddr_nz (entry));
ui_out_text (uiout, ", load size ");
ui_out_field_fmt (uiout, "load-size", "%lu", cbdata.data_count);
ui_out_text (uiout, "\n");
write_pc (entry);
print_transfer_performance (gdb_stdout, cbdata.data_count,
cbdata.write_count, &start_time, &end_time);
do_cleanups (old_cleanups);
}
void
report_transfer_performance (unsigned long data_count, time_t start_time,
time_t end_time)
{
struct timeval start, end;
start.tv_sec = start_time;
start.tv_usec = 0;
end.tv_sec = end_time;
end.tv_usec = 0;
print_transfer_performance (gdb_stdout, data_count, 0, &start, &end);
}
void
print_transfer_performance (struct ui_file *stream,
unsigned long data_count,
unsigned long write_count,
const struct timeval *start_time,
const struct timeval *end_time)
{
unsigned long time_count;
time_count = (end_time->tv_sec - start_time->tv_sec) * 1000;
time_count += (end_time->tv_usec - start_time->tv_usec) / 1000;
ui_out_text (uiout, "Transfer rate: ");
if (time_count > 0)
{
ui_out_field_fmt (uiout, "transfer-rate", "%lu",
1000 * (data_count * 8) / time_count);
ui_out_text (uiout, " bits/sec");
}
else
{
ui_out_field_fmt (uiout, "transferred-bits", "%lu", (data_count * 8));
ui_out_text (uiout, " bits in <1 sec");
}
if (write_count > 0)
{
ui_out_text (uiout, ", ");
ui_out_field_fmt (uiout, "write-rate", "%lu", data_count / write_count);
ui_out_text (uiout, " bytes/write");
}
ui_out_text (uiout, ".\n");
}
static void
add_symbol_file_command (char *args, int from_tty)
{
char *filename = NULL;
char *address = NULL;
char *prefix = NULL;
char **argv = NULL;
CORE_ADDR mapaddr = 0;
int flags = OBJF_USERLOADED;
int symflags = OBJF_SYM_ALL;
char *arg;
int section_index = 0;
int argcnt = 0;
int sec_num = 0;
int i;
struct objfile *o;
const char *const usage_string =
"usage (%s): add-symbol-file <filename> <text address> [-mapped] [-readnow] [-s <secname> <addr>]*";
struct sect_opt
{
char *name;
char *value;
};
struct section_addr_info *section_addrs;
struct sect_opt *sect_opts = NULL;
size_t num_sect_opts = 0;
struct cleanup *my_cleanups = make_cleanup (null_cleanup, NULL);
num_sect_opts = 16;
sect_opts = (struct sect_opt *) xmalloc (num_sect_opts
* sizeof (struct sect_opt));
dont_repeat ();
if (args == NULL)
error (usage_string, "argument required");
argv = buildargv (args);
if (argv == NULL)
nomem (0);
make_cleanup_freeargv (argv);
argcnt = 0;
for (;;)
{
arg = argv[argcnt++];
if (arg == NULL)
break;
if (*arg == '-')
{
if (strcmp (arg, "-mapaddr") == 0)
{
char *atmp = argv[argcnt++];
if (atmp == NULL)
error (usage_string, "must specify address to -mapaddr");
mapaddr = parse_and_eval_address (atmp);
}
if (strcmp (arg, "-prefix") == 0)
{
char *atmp = argv[argcnt++];
if (atmp == NULL)
error (usage_string, "must specify address to -prefix");
prefix = xstrdup (atmp);
}
else if (strcmp (arg, "-readnow") == 0)
flags |= OBJF_READNOW;
else if (strcmp (arg, "-s") == 0)
{
char *atmp = argv[argcnt++];
if (atmp == NULL)
error (usage_string, "must specify section name to -s");
char *atmp2 = argv[argcnt++];
if (atmp2 == NULL)
error (usage_string, "must specify section address to -s");
if (section_index >= 16)
error (usage_string, "too many sections specified.");
sect_opts[section_index].name = atmp;
sect_opts[section_index].value = atmp2;
section_index++;
}
}
else
{
if (filename == NULL)
{
filename = tilde_expand (arg);
make_cleanup (xfree, filename);
}
else if (address == NULL)
{
address = arg;
}
else
{
error (usage_string, "too many arguments");
}
}
}
if (address != NULL)
{
if (section_index >= 16)
error (usage_string, "too many sections specified.");
sect_opts[section_index].name = TEXT_SEGMENT_NAME;
sect_opts[section_index].value = address;
section_index++;
}
if (filename == NULL)
error ("usage: must specify exactly one filename");
if (strstr (filename, ".dSYM"))
{
if (argcnt == 2)
{
add_dsym_command (args, from_tty);
return;
}
else
{
warning ("add-symbol-file doesn't work on dSYM files, use "
"\"add-dsym\" instead.");
}
}
printf_filtered ("add symbol table from file \"%s\"", filename);
if (section_index > 0)
printf_filtered (" at\n");
else
printf_filtered ("? ");
if (section_index == 0)
{
section_addrs = NULL;
}
else
{
section_addrs = alloc_section_addr_info (section_index);
make_cleanup (xfree, section_addrs);
for (i = 0; i < section_index; i++)
{
CORE_ADDR addr;
char *val = sect_opts[i].value;
char *sec = sect_opts[i].name;
addr = parse_and_eval_address (val);
section_addrs->other[sec_num].name = sec;
section_addrs->other[sec_num].addr = addr;
printf_unfiltered ("\t%s = 0x%s\n",
sec, paddr_nz (addr));
sec_num++;
}
}
if (from_tty && (!query ("%s", "")))
error (_("Not confirmed."));
o = symbol_file_add_name_with_addrs_or_offsets
(filename, from_tty, section_addrs, NULL, 0, 0, flags, symflags,
mapaddr, prefix, NULL);
o->syms_only_objfile = 1;
#ifdef MACOSX_DYLD
update_section_tables ();
#endif
update_current_target ();
re_enable_breakpoints_in_shlibs (0);
reinit_frame_cache ();
do_cleanups (my_cleanups);
}
static void find_kext_files_by_bundle (const char *filename,
char **kextload_symbol_filename,
char **kext_bundle_executable_filename);
static void find_kext_files_by_symfile (const char *filename,
char **kext_bundle_executable_filename);
static void
add_kext_command (char *args, int from_tty)
{
char **argv = NULL;
char *filename;
const char *ext;
struct objfile *o;
int flags = OBJF_USERLOADED;
int symflags = OBJF_SYM_ALL;
char *kextload_symbol_filename;
char *kext_bundle_executable_filename;
struct section_addr_info *section_addrs = NULL;
const char *const usage_string =
"Error: %s\n"
"Usage: add-kext <PATHNAME-OF-KEXT>\n"
"PATHNAME-OF-KEXT is the path to the .kext bundle directory or the .sym\n"
"file output from kextutil/kextcache. If you provide a .kext bundle\n"
"path, the corresponding .dSYM bundle and .sym file must be located in\n"
"the same directory. If you provide a .sym filename, the .dSYM bundle\n"
"and .kext file must be siblings of each other, and they must be in a\n"
"spotlight indexed location or the same directory as the .sym.\n"
"On newer kernels, the .sym file is not required - only the .kext and .dSYM.";
struct cleanup *my_cleanups = make_cleanup (null_cleanup, NULL);
dont_repeat ();
if (args == NULL)
error (usage_string, "argument required");
argv = buildargv (args);
if (argv == NULL)
nomem (0);
make_cleanup_freeargv (argv);
filename = argv[0];
if (filename == NULL)
error (usage_string, "no kext bundle name supplied");
ext = strrchr (filename, '.');
if (!ext)
error (usage_string, "supplied path has no extension");
if (!strncmp (ext, ".kext", strlen (".kext")))
{
find_kext_files_by_bundle (filename, &kextload_symbol_filename,
&kext_bundle_executable_filename);
if ((!kextload_symbol_filename || !file_exists_p (kextload_symbol_filename))
&& lookup_minimal_symbol ("gLoadedKextSummaries", NULL, NULL))
{
section_addrs = find_kext_loadaddrs_from_kernel (filename,
&kext_bundle_executable_filename);
if (section_addrs)
make_cleanup_free_section_addr_info (section_addrs);
}
}
else if (!strncmp (ext, ".sym", strlen (".sym")))
{
find_kext_files_by_symfile (filename, &kext_bundle_executable_filename);
kextload_symbol_filename = xstrdup (filename);
if (kernel_slide != 0 && kernel_slide != INVALID_ADDRESS && section_addrs == NULL)
{
section_addrs = get_section_addrs_of_macho_on_disk (filename);
int i = 0;
for (i = 0; i < section_addrs->num_sections; i++)
section_addrs->other[i].addr += kernel_slide;
}
}
else
error (usage_string, "supplied file must have a .kext or .sym extension");
if (kext_bundle_executable_filename == NULL)
{
const char *bname = strrchr (filename, '/');
if (bname && *bname == '/' && *(bname + 1) != '\0')
bname++;
else
bname = filename;
printf_filtered ("No .kext bundle binary found for %s -- not adding kext.\n\n", bname);
return;
}
if (section_addrs)
{
struct section_offsets *sect_offsets;
int num_offsets;
sect_offsets = convert_sect_addrs_to_offsets_via_on_disk_file
(section_addrs, kext_bundle_executable_filename,
&num_offsets);
o = symbol_file_add_name_with_addrs_or_offsets
(kext_bundle_executable_filename, from_tty, NULL,
sect_offsets, num_offsets, 0, flags, symflags, 0, NULL, NULL);
xfree (sect_offsets);
}
else
{
o = symbol_file_add_name_with_addrs_or_offsets
(kextload_symbol_filename, from_tty, NULL, NULL, 0, 0,
flags, symflags, 0, NULL, kext_bundle_executable_filename);
o->syms_only_objfile = 1;
}
if (bfd_default_compatible (bfd_get_arch_info (o->obfd),
gdbarch_bfd_arch_info (current_gdbarch)) == NULL)
{
warning ("This gdb is expecting %s binaries but %s is %s which is not "
"compatible. gdb will use the .sym file but this is unlikely "
"to be correct.",
gdbarch_bfd_arch_info (current_gdbarch)->printable_name,
o->name, bfd_get_arch_info (o->obfd)->printable_name);
}
#ifdef NM_NEXTSTEP
update_section_tables ();
#endif
update_current_target ();
breakpoint_update ();
reinit_frame_cache ();
do_cleanups (my_cleanups);
}
static void
get_kext_bundle_ident_and_binary_path (const char *filename,
const char **kext_bundle_filename,
char **kext_bundle_executable_filename,
const char **bundle_identifier_name_from_plist)
{
const char *bundle_executable_name_from_plist;
*kext_bundle_filename = macosx_kext_info (filename,
&bundle_executable_name_from_plist,
bundle_identifier_name_from_plist);
if (*kext_bundle_filename == NULL)
error ("Unable to find kext bundle at \"%s\"", filename);
if (bundle_executable_name_from_plist == NULL)
error ("Unable to find CFBundleExecutable in Info.plist");
if (*bundle_identifier_name_from_plist == NULL)
error ("Unable to find CFBundleIdentifier in Info.plist");
char *t = dirname ((char *)*kext_bundle_filename);
if (t == NULL)
error ("dirname on the kext bundle filename failed");
*kext_bundle_executable_filename = xmalloc (strlen (*kext_bundle_filename) +
strlen ("/Contents/MacOS/") +
strlen (bundle_executable_name_from_plist) + 1);
strcpy (*kext_bundle_executable_filename, *kext_bundle_filename);
strcat (*kext_bundle_executable_filename, "/Contents/MacOS/");
strcat (*kext_bundle_executable_filename, bundle_executable_name_from_plist);
if (!file_exists_p (*kext_bundle_executable_filename))
{
char *shallow_bundle_name = xmalloc (strlen (*kext_bundle_filename) + 1 +
strlen (bundle_executable_name_from_plist) + 1);
strcpy (shallow_bundle_name, *kext_bundle_filename);
strcat (shallow_bundle_name, "/");
strcat (shallow_bundle_name, bundle_executable_name_from_plist);
if (file_exists_p (shallow_bundle_name))
{
xfree ((char *) *kext_bundle_executable_filename);
*kext_bundle_executable_filename = shallow_bundle_name;
}
else
{
xfree ((char *) shallow_bundle_name);
}
}
}
static void
find_kext_files_by_bundle (const char *filename,
char **kextload_symbol_filename,
char **kext_bundle_executable_filename)
{
const char *kext_bundle_filename;
const char *bundle_identifier_name_from_plist;
char *kextload_symbol_basename;
get_kext_bundle_ident_and_binary_path (filename, &kext_bundle_filename,
kext_bundle_executable_filename, &bundle_identifier_name_from_plist);
kextload_symbol_basename = xmalloc
(strlen (bundle_identifier_name_from_plist) + strlen (".sym") + 1);
strcpy (kextload_symbol_basename, bundle_identifier_name_from_plist);
strcat (kextload_symbol_basename, ".sym");
char *t = dirname ((char *)kext_bundle_filename);
if (t == NULL)
error ("dirname on the kext bundle filename failed");
if (t[0] == '.' && t[1] == '\0')
{
*kextload_symbol_filename = kextload_symbol_basename;
}
else if (file_exists_p (kextload_symbol_basename))
{
*kextload_symbol_filename = kextload_symbol_basename;
}
else
{
*kextload_symbol_filename = xmalloc (strlen (t) + 1 +
strlen (kextload_symbol_basename) + 1);
strcpy (*kextload_symbol_filename, t);
strcat (*kextload_symbol_filename, "/");
strcat (*kextload_symbol_filename, kextload_symbol_basename);
xfree (kextload_symbol_basename);
}
if (file_exists_p (*kextload_symbol_filename) == 0
&& kext_symbol_file_path != NULL)
{
char *possible_new_name;
possible_new_name = xmalloc (strlen (kext_symbol_file_path) + 1 +
strlen (bundle_identifier_name_from_plist) +
strlen (".sym") + 1);
strcpy (possible_new_name, kext_symbol_file_path);
strcat (possible_new_name, "/");
strcat (possible_new_name, bundle_identifier_name_from_plist);
strcat (possible_new_name, ".sym");
if (file_exists_p (possible_new_name))
{
xfree (*kextload_symbol_filename);
*kextload_symbol_filename = possible_new_name;
}
}
xfree ((char *) bundle_identifier_name_from_plist);
}
static struct section_addr_info *
find_kext_loadaddrs_from_kernel (const char *filename,
char **kext_bundle_executable_filename)
{
const char *bundle_identifier_name_from_plist;
const char *kext_bundle_filename;
get_kext_bundle_ident_and_binary_path (filename, &kext_bundle_filename,
kext_bundle_executable_filename, &bundle_identifier_name_from_plist);
if (bundle_identifier_name_from_plist)
make_cleanup (xfree, bundle_identifier_name_from_plist);
if (kext_bundle_filename)
make_cleanup (xfree, kext_bundle_filename);
uint8_t **kext_uuids = get_binary_file_uuids (*kext_bundle_executable_filename);
if (kext_uuids == NULL)
error ("Unable to find Mach-O LC_UUID load command in file '%s'",
*kext_bundle_executable_filename);
struct cleanup *clean = make_cleanup (free_uuids_array, kext_uuids);
int i = 0;
while (kext_uuids[i] != NULL)
{
if (find_objfile_by_uuid (kext_uuids[i]))
error ("%s has already been added.", filename);
i++;
}
struct section_addr_info *sect_addrs;
sect_addrs = macosx_get_kext_sect_addrs_from_kernel
(*kext_bundle_executable_filename,
kext_uuids,
bundle_identifier_name_from_plist);
if (sect_addrs == NULL)
error ("Unable to find the kext '%s' loaded in this kernel.", filename);
do_cleanups (clean);
return sect_addrs;
}
static void
find_kext_files_by_symfile (const char *filename,
char **kext_bundle_executable_filename)
{
bfd *abfd;
abfd = symfile_bfd_open (filename, 0, GDB_OSABI_UNKNOWN);
if (abfd == NULL)
error ("Can't open kext sym file");
*kext_bundle_executable_filename = macosx_locate_kext_executable_by_symfile (abfd);
if (*kext_bundle_executable_filename == NULL)
{
const char *bname = strrchr (filename, '/');
if (bname && *bname == '/' && *(bname + 1) != '\0')
bname++;
else
bname = filename;
uint8_t uuid[16];
if (bfd_mach_o_get_uuid (abfd, uuid, sizeof (uuid)))
warning ("Can't find .kext bundle for %s (%s)", bname, puuid (uuid));
else
warning ("Can't find .kext bundle for %s", filename);
}
bfd_close (abfd);
}
static void
add_dsym_command (char *args, int from_tty)
{
struct objfile *objfile;
volatile struct gdb_exception e;
char *full_name;
char *dsym_path;
char *objfile_name;
struct cleanup *full_name_cleanup;
struct cleanup *argv_cleanup;
struct stat stat_buf;
char **arg_array;
int i;
if (args == NULL || *args == '\0')
error ("Wrong number of args, should be \"add-dsym <DSYM PATH>\".");
arg_array = buildargv (args);
if (arg_array == NULL)
error ("Unable to build argument vector for add-dsym command.");
argv_cleanup = make_cleanup_freeargv (arg_array);
for (i = 0; arg_array[i] != NULL; i++)
{
full_name = tilde_expand (arg_array[i]);
full_name_cleanup = make_cleanup (xfree, full_name);
if (stat (full_name, &stat_buf) == -1)
{
error ("Error \"%s\" accessing dSYM file \"%s\".",
strerror (errno), full_name);
}
objfile = macosx_find_objfile_matching_dsym_in_bundle (full_name, &dsym_path);
if (!objfile)
{
warning ("Could not find binary to match \"%s\".", full_name);
continue;
}
make_cleanup (xfree, dsym_path);
if (objfile->separate_debug_objfile != NULL)
{
warning ("Trying to add dSYM file to \"%s\" which already has one.",
objfile->name);
goto do_cleanups;
}
objfile_name = xstrdup (objfile->name);
make_cleanup (xfree, objfile_name);
already_found_debug_file = dsym_path;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
objfile->symflags = OBJF_SYM_NONE;
dyld_objfile_set_load_state (objfile, OBJF_SYM_ALL);
}
already_found_debug_file = NULL;
if (e.reason != NO_ERROR)
{
warning ("Could not add dSYM \"%s\" to library \"%s\".",
dsym_path, objfile->name);
goto do_cleanups;
}
make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_text (uiout, "Added dsym \"");
ui_out_field_string (uiout, "dsymfile", full_name);
ui_out_text (uiout, "\" to \"");
ui_out_field_string (uiout, "objfile", objfile_name);
ui_out_text (uiout, "\".\n");
do_cleanups:
do_cleanups (full_name_cleanup);
}
do_cleanups (argv_cleanup);
}
static void
add_shared_symbol_files_command (char *args, int from_tty)
{
#ifdef ADD_SHARED_SYMBOL_FILES
ADD_SHARED_SYMBOL_FILES (args, from_tty);
#else
error (_("This command is not available in this configuration of GDB."));
#endif
}
int
reread_symbols_for_objfile (struct objfile *objfile, long new_modtime,
enum gdb_osabi osabi, struct objfile **next)
{
struct cleanup *old_cleanups;
struct section_offsets *offsets;
int num_offsets;
char *obfd_filename;
int update_exec_bfd = 0;
if (objfile == NULL)
return 0;
if (objfile->separate_debug_objfile_backlink)
return 0;
if (new_modtime == 0 && objfile->obfd != NULL)
{
struct stat buf;
if (stat (objfile->obfd->filename, &buf) != 0)
{
if (objfile->obfd->iostream != NULL)
new_modtime = bfd_get_mtime (objfile->obfd);
else
warning ("Can't find backing file for \"%s\".",
objfile->obfd->filename);
}
else
new_modtime = buf.st_mtime;
}
printf_unfiltered (_("`%s' has changed; re-reading symbols.\n"),
objfile->name);
old_cleanups = make_cleanup_free_objfile (objfile);
make_cleanup (clear_symtab_users_cleanup, 0 );
if (objfile->separate_debug_objfile != NULL)
{
if (next != NULL && objfile->separate_debug_objfile == *next)
*next = objfile_get_next (*next);
free_objfile (objfile->separate_debug_objfile);
objfile->separate_debug_objfile = NULL;
}
tell_breakpoints_objfile_changed (objfile);
tell_objc_msgsend_cacher_objfile_changed (objfile);
symtab_clear_cached_lookup_values ();
objfile_delete_from_ordered_sections (objfile);
obfd_filename = xstrdup (bfd_get_filename (objfile->obfd));
make_cleanup (xfree, obfd_filename);
remove_target_sections (objfile->obfd);
if (exec_bfd &&
(exec_bfd == objfile->obfd ||
strcmp (exec_bfd->filename, objfile->obfd->filename) == 0))
{
update_exec_bfd = 1;
}
if (!bfd_close (objfile->obfd))
error (_("Can't close BFD for %s: %s"), objfile->name,
bfd_errmsg (bfd_get_error ()));
if (update_exec_bfd)
{
if (exec_bfd != objfile->obfd)
{
char *name = xstrdup (bfd_get_filename (exec_bfd));
if (!bfd_close (exec_bfd))
warning (_("cannot close \"%s\": %s"),
name, bfd_errmsg (bfd_get_error ()));
xfree (name);
}
exec_bfd = bfd_openr (xstrdup (obfd_filename), gnutarget);
if (exec_bfd == NULL)
error (_("Can't open %s to read symbols."), objfile->name);
if (bfd_check_format (exec_bfd, bfd_archive))
{
bfd *tmp_bfd;
tmp_bfd = open_bfd_matching_arch (exec_bfd, bfd_object, osabi);
if (tmp_bfd != NULL)
exec_bfd = tmp_bfd;
}
}
objfile->obfd = bfd_openr (xstrdup (obfd_filename), gnutarget);
if (objfile->obfd == NULL)
error (_("Can't open %s to read symbols."), objfile->name);
if (bfd_check_format (objfile->obfd, bfd_archive))
{
bfd *tmp_bfd;
tmp_bfd = open_bfd_matching_arch (objfile->obfd, bfd_object, osabi);
if (tmp_bfd != NULL)
objfile->obfd = tmp_bfd;
}
if (!bfd_check_format (objfile->obfd, bfd_object))
error (_("Can't read symbols from %s: %s."), objfile->name,
bfd_errmsg (bfd_get_error ()));
num_offsets = objfile->num_sections;
offsets = ((struct section_offsets *)
alloca (SIZEOF_N_SECTION_OFFSETS (num_offsets)));
memcpy (offsets, objfile->section_offsets,
SIZEOF_N_SECTION_OFFSETS (num_offsets));
if (objfile->global_psymbols.list)
xfree (objfile->global_psymbols.list);
memset (&objfile->global_psymbols, 0,
sizeof (objfile->global_psymbols));
if (objfile->static_psymbols.list)
xfree (objfile->static_psymbols.list);
memset (&objfile->static_psymbols, 0,
sizeof (objfile->static_psymbols));
bcache_xfree (objfile->psymbol_cache);
objfile->psymbol_cache = bcache_xmalloc (NULL);
bcache_xfree (objfile->macro_cache);
objfile->macro_cache = bcache_xmalloc (NULL);
equivalence_table_delete (objfile);
if (objfile->demangled_names_hash != NULL)
{
htab_delete (objfile->demangled_names_hash);
objfile->demangled_names_hash = NULL;
}
obstack_free (&objfile->objfile_obstack, 0);
objfile->sections = NULL;
objfile->symtabs = NULL;
objfile->psymtabs = NULL;
objfile->free_psymtabs = NULL;
objfile->cp_namespace_symtab = NULL;
objfile->msymbols = NULL;
objfile->deprecated_sym_private = NULL;
objfile->minimal_symbol_count = 0;
memset (&objfile->msymbol_hash, 0,
sizeof (objfile->msymbol_hash));
memset (&objfile->msymbol_demangled_hash, 0,
sizeof (objfile->msymbol_demangled_hash));
objfile->minimal_symbols_demangled = 0;
objfile->fundamental_types = NULL;
clear_objfile_data (objfile);
if (objfile->sf != NULL)
{
(*objfile->sf->sym_finish) (objfile);
}
objfile->md = NULL;
objfile->psymbol_cache = bcache_xmalloc (NULL);
objfile->macro_cache = bcache_xmalloc (NULL);
obstack_init (&objfile->objfile_obstack);
if (build_objfile_section_table (objfile))
{
error (_("Can't find the file sections in `%s': %s"),
objfile->name, bfd_errmsg (bfd_get_error ()));
}
terminate_minimal_symbol_table (objfile);
objfile->section_offsets = (struct section_offsets *)
obstack_alloc (&objfile->objfile_obstack,
SIZEOF_N_SECTION_OFFSETS (num_offsets));
memset (objfile->section_offsets, 0, SIZEOF_N_SECTION_OFFSETS (num_offsets));
objfile->num_sections = num_offsets;
init_entry_point_info (objfile);
objfile_relocate (objfile, offsets);
if (objfile == symfile_objfile)
{
(*objfile->sf->sym_new_init) (objfile);
}
(*objfile->sf->sym_init) (objfile);
clear_complaints (&symfile_complaints, 1, 1);
reread_separate_symbols (objfile);
if ((objfile->symflags & ~OBJF_SYM_CONTAINER) & OBJF_SYM_LEVELS_MASK)
(*objfile->sf->sym_read) (objfile, 0);
objfile->flags |= OBJF_SYMS;
clear_complaints (&symfile_complaints, 0, 1);
reinit_frame_cache ();
discard_cleanups (old_cleanups);
xfree (obfd_filename);
objfile->mtime = new_modtime;
breakpoint_re_set (objfile);
if (objfile == find_libobjc_objfile ())
{
objc_init_trampoline_observer ();
objc_init_runtime_version ();
}
return 1;
}
void
reread_symbols (void)
{
struct objfile *objfile, *next;
long new_modtime;
int num_reread = 0;
ALL_OBJFILES_SAFE (objfile, next)
{
if (objfile->separate_debug_objfile_backlink)
continue;
if (objfile->obfd)
{
int backing_file_missing;
{
struct stat buf;
backing_file_missing = 0;
if (stat (objfile->obfd->filename, &buf) != 0)
{
if (objfile->obfd->iostream != NULL)
new_modtime = bfd_get_mtime (objfile->obfd);
else
backing_file_missing = 1;
}
else
new_modtime = buf.st_mtime;
}
if (backing_file_missing)
{
warning ("Can't find backing file for \"%s\".",
objfile->obfd->filename);
}
else if (new_modtime != objfile->mtime)
{
num_reread += reread_symbols_for_objfile (objfile, new_modtime,
GDB_OSABI_UNKNOWN,
&next);
}
}
}
if (num_reread > 0)
{
clear_symtab_users ();
observer_notify_executable_changed (NULL);
}
}
static void
reread_symbols_command (char *args, int from_tty)
{
reread_symbols ();
}
struct objfile *
find_objfile (const char *name)
{
struct objfile *objfile = NULL;
struct objfile *o, *temp;
ALL_OBJFILES_SAFE (o, temp)
{
if (strcmp (name, o->name) == 0)
{
if (objfile == NULL)
{
objfile = o;
}
else
{
warning ("Multiple object files exist with name \"%s\": choosing first", o->name);
}
}
}
return objfile;
}
static void
remove_symbol_file_command (args, from_tty)
char *args;
int from_tty;
{
char *name = NULL;
struct objfile *objfile = NULL;
dont_repeat ();
if (args == NULL)
{
error ("remove-symbol-file takes a file name");
}
name = tilde_expand (args);
make_cleanup (free, name);
objfile = find_objfile (name);
if (objfile == NULL)
{
error ("unable to locate object file named \"%s\"", args);
}
tell_breakpoints_objfile_changed (objfile);
tell_objc_msgsend_cacher_objfile_changed (objfile);
free_objfile (objfile);
symtab_clear_cached_lookup_values ();
clear_symtab_users ();
reinit_frame_cache ();
}
static void
reread_separate_symbols (struct objfile *objfile)
{
char *debug_file;
debug_file = find_separate_debug_file (objfile);
if (objfile->separate_debug_objfile)
{
if (! debug_file
|| strcmp (debug_file, objfile->separate_debug_objfile->name) != 0)
{
free_objfile (objfile->separate_debug_objfile);
objfile->separate_debug_objfile = NULL;
}
}
if (debug_file && ! objfile->separate_debug_objfile)
{
struct section_offsets *sym_offsets = NULL;
int num_sym_offsets = 0;
bfd *debug_bfd;
int uuid_matches;
enum gdb_osabi objfile_osabi = GDB_OSABI_UNKNOWN;
#ifdef MACOSX_DYLD
objfile_osabi = macosx_get_osabi_from_dyld_entry (objfile->obfd);
#endif
debug_bfd = symfile_bfd_open (debug_file, 0, objfile_osabi);
if (objfile->not_loaded_kext_filename)
uuid_matches = 1;
else
uuid_matches = check_bfd_for_matching_uuid (objfile->obfd, debug_bfd);
if (uuid_matches)
{
#ifdef TM_NEXTSTEP
macho_calculate_offsets_for_dsym (objfile, debug_bfd, NULL,
objfile->section_offsets,
objfile->num_sections,
&sym_offsets, &num_sym_offsets);
#endif
objfile->separate_debug_objfile
= (symbol_file_add_with_addrs_or_offsets
(debug_bfd,
info_verbose,
0,
sym_offsets, num_sym_offsets,
0,
objfile->flags & (OBJF_REORDERED | OBJF_SHARED | OBJF_READNOW
| OBJF_USERLOADED | OBJF_SEPARATE_DEBUG_FILE),
OBJF_SYM_ALL, 0, NULL, 0));
xfree (sym_offsets);
objfile->separate_debug_objfile->separate_debug_objfile_backlink
= objfile;
put_objfile_before (objfile->separate_debug_objfile, objfile);
}
else
bfd_close (debug_bfd);
}
if (debug_file)
xfree (debug_file);
}
typedef struct
{
char *ext;
enum language lang;
}
filename_language;
static filename_language *filename_language_table;
static int fl_table_size, fl_table_next;
static void
add_filename_language (char *ext, enum language lang)
{
if (fl_table_next >= fl_table_size)
{
fl_table_size += 10;
filename_language_table =
xrealloc (filename_language_table,
fl_table_size * sizeof (*filename_language_table));
}
filename_language_table[fl_table_next].ext = xstrdup (ext);
filename_language_table[fl_table_next].lang = lang;
fl_table_next++;
}
static char *ext_args;
static void
show_ext_args (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Mapping between filename extension and source language is \"%s\".\n"),
value);
}
static void
set_ext_lang_command (char *args, int from_tty, struct cmd_list_element *e)
{
int i;
char *cp = ext_args;
enum language lang;
if (*cp != '.')
error (_("'%s': Filename extension must begin with '.'"), ext_args);
while (*cp && !isspace (*cp))
cp++;
if (*cp == '\0')
error (_("'%s': two arguments required -- filename extension and language"),
ext_args);
*cp++ = '\0';
while (*cp && isspace (*cp))
cp++;
if (*cp == '\0')
error (_("'%s': two arguments required -- filename extension and language"),
ext_args);
lang = language_enum (cp);
for (i = 0; i < fl_table_next; i++)
if (0 == strcmp (ext_args, filename_language_table[i].ext))
break;
if (i >= fl_table_next)
{
add_filename_language (ext_args, lang);
}
else
{
xfree (filename_language_table[i].ext);
filename_language_table[i].ext = xstrdup (ext_args);
filename_language_table[i].lang = lang;
}
}
static void
info_ext_lang_command (char *args, int from_tty)
{
int i;
printf_filtered (_("Filename extensions and the languages they represent:"));
printf_filtered ("\n\n");
for (i = 0; i < fl_table_next; i++)
printf_filtered ("\t%s\t- %s\n",
filename_language_table[i].ext,
language_str (filename_language_table[i].lang));
}
static void
init_filename_language_table (void)
{
if (fl_table_size == 0)
{
fl_table_size = 20;
fl_table_next = 0;
filename_language_table =
xmalloc (fl_table_size * sizeof (*filename_language_table));
add_filename_language (".c", language_c);
add_filename_language (".C", language_cplus);
add_filename_language (".cc", language_cplus);
add_filename_language (".cp", language_cplus);
add_filename_language (".cpp", language_cplus);
add_filename_language (".cxx", language_cplus);
add_filename_language (".c++", language_cplus);
add_filename_language (".java", language_java);
add_filename_language (".class", language_java);
add_filename_language (".m", language_objc);
add_filename_language (".mm", language_objcplus);
add_filename_language (".M", language_objcplus);
add_filename_language (".f", language_fortran);
add_filename_language (".F", language_fortran);
add_filename_language (".s", language_asm);
add_filename_language (".S", language_asm);
add_filename_language (".pas", language_pascal);
add_filename_language (".p", language_pascal);
add_filename_language (".pp", language_pascal);
add_filename_language (".adb", language_ada);
add_filename_language (".ads", language_ada);
add_filename_language (".a", language_ada);
add_filename_language (".ada", language_ada);
}
}
enum language
deduce_language_from_filename (const char *filename)
{
int i;
char *cp;
if (filename != NULL)
if ((cp = strrchr (filename, '.')) != NULL)
for (i = 0; i < fl_table_next; i++)
if (strcmp (cp, filename_language_table[i].ext) == 0)
return filename_language_table[i].lang;
return language_unknown;
}
struct symtab *
allocate_symtab (char *filename, struct objfile *objfile)
{
struct symtab *symtab;
symtab = (struct symtab *)
obstack_alloc (&objfile->objfile_obstack, sizeof (struct symtab));
memset (symtab, 0, sizeof (*symtab));
symtab->filename = obsavestring (filename, strlen (filename),
&objfile->objfile_obstack);
symtab->fullname = NULL;
symtab->language = deduce_language_from_filename (filename);
symtab->debugformat = obsavestring ("unknown", 7,
&objfile->objfile_obstack);
SYMTAB_OBSOLETED (symtab) = 50;
symtab->objfile = objfile;
symtab->next = objfile->symtabs;
objfile->symtabs = symtab;
#ifdef INIT_EXTRA_SYMTAB_INFO
INIT_EXTRA_SYMTAB_INFO (symtab);
#endif
return (symtab);
}
struct partial_symtab *
allocate_psymtab (char *filename, struct objfile *objfile)
{
struct partial_symtab *psymtab;
if (objfile->free_psymtabs)
{
psymtab = objfile->free_psymtabs;
objfile->free_psymtabs = psymtab->next;
}
else
psymtab = (struct partial_symtab *)
obstack_alloc (&objfile->objfile_obstack,
sizeof (struct partial_symtab));
memset (psymtab, 0, sizeof (struct partial_symtab));
psymtab->filename = obsavestring (filename, strlen (filename),
&objfile->objfile_obstack);
psymtab->symtab = NULL;
psymtab->objfile = objfile;
psymtab->next = objfile->psymtabs;
objfile->psymtabs = psymtab;
#if 0
{
struct partial_symtab **prev_pst;
psymtab->objfile = objfile;
psymtab->next = NULL;
prev_pst = &(objfile->psymtabs);
while ((*prev_pst) != NULL)
prev_pst = &((*prev_pst)->next);
(*prev_pst) = psymtab;
}
#endif
PSYMTAB_OBSOLETED (psymtab) = 50;
PSYMTAB_OSO_NAME (psymtab) = NULL;
PSYMTAB_OSO_STATICS (psymtab) = NULL;
PSYMTAB_OSO_PST_LIST (psymtab) = NULL;
return (psymtab);
}
void
discard_psymtab (struct partial_symtab *pst)
{
struct partial_symtab **prev_pst;
prev_pst = &(pst->objfile->psymtabs);
while ((*prev_pst) != pst)
prev_pst = &((*prev_pst)->next);
(*prev_pst) = pst->next;
pst->next = pst->objfile->free_psymtabs;
pst->objfile->free_psymtabs = pst;
}
void
clear_symtab_users (void)
{
clear_current_source_symtab_and_line ();
clear_value_history ();
clear_displays ();
clear_internalvars ();
set_default_breakpoint (0, 0, 0, 0);
clear_pc_function_cache ();
if (deprecated_target_new_objfile_hook)
deprecated_target_new_objfile_hook (NULL);
}
static void
clear_symtab_users_cleanup (void *ignore)
{
clear_symtab_users ();
}
#if 0
static void clear_symtab_users_once (void);
static int clear_symtab_users_queued;
static int clear_symtab_users_done;
static void
clear_symtab_users_once (void)
{
if (clear_symtab_users_queued <= clear_symtab_users_done)
return;
clear_symtab_users_done = clear_symtab_users_queued;
clear_symtab_users ();
}
#endif
static void
cashier_psymtab (struct partial_symtab *pst)
{
struct partial_symtab *ps, *pprev = NULL;
int i;
ALL_OBJFILE_PSYMTABS (pst->objfile, ps)
{
if (ps == pst)
break;
pprev = ps;
}
if (ps)
{
if (ps == pst->objfile->psymtabs)
pst->objfile->psymtabs = ps->next;
else
pprev->next = ps->next;
again:
ALL_OBJFILE_PSYMTABS (pst->objfile, ps)
{
for (i = 0; i < ps->number_of_dependencies; i++)
{
if (ps->dependencies[i] == pst)
{
cashier_psymtab (ps);
goto again;
}
}
}
}
}
int
free_named_symtabs (char *name)
{
#if 0
struct symtab *s;
struct symtab *prev;
struct partial_symtab *ps;
struct blockvector *bv;
int blewit = 0;
if (!symbol_reloading)
return 0;
if (name == 0 || *name == '\0')
return 0;
again2:
for (ps = partial_symtab_list; ps; ps = ps->next)
{
if (strcmp (name, ps->filename) == 0)
{
cashier_psymtab (ps);
goto again2;
}
}
for (s = symtab_list; s; s = s->next)
{
if (strcmp (name, s->filename) == 0)
break;
prev = s;
}
if (s)
{
if (s == symtab_list)
symtab_list = s->next;
else
prev->next = s->next;
bv = BLOCKVECTOR (s);
if (BLOCKVECTOR_NBLOCKS (bv) > 2
|| BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK))
|| BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)))
{
complaint (&symfile_complaints, _("Replacing old symbols for `%s'"),
name);
clear_symtab_users_queued++;
make_cleanup (clear_symtab_users_once, 0);
blewit = 1;
}
else
complaint (&symfile_complaints, _("Empty symbol table found for `%s'"),
name);
free_symtab (s);
}
else
{
;
}
return blewit;
#else
return (0);
#endif
}
struct partial_symtab *
start_psymtab_common (struct objfile *objfile,
struct section_offsets *section_offsets, char *filename,
CORE_ADDR textlow, struct partial_symbol **global_syms,
struct partial_symbol **static_syms)
{
struct partial_symtab *psymtab;
psymtab = allocate_psymtab (filename, objfile);
psymtab->section_offsets = section_offsets;
psymtab->textlow = textlow;
psymtab->texthigh = psymtab->textlow;
psymtab->globals_offset = global_syms - objfile->global_psymbols.list;
psymtab->statics_offset = static_syms - objfile->static_psymbols.list;
return (psymtab);
}
const struct partial_symbol *
add_psymbol_to_list (char *name, int namelength, domain_enum domain,
enum address_class class,
struct psymbol_allocation_list *list, long val,
CORE_ADDR coreaddr,
enum language language, struct objfile *objfile)
{
struct partial_symbol *psym;
char *buf = alloca (namelength + 1);
static struct partial_symbol psymbol;
memcpy (buf, name, namelength);
buf[namelength] = '\0';
if (val != 0)
{
SYMBOL_VALUE (&psymbol) = val;
}
else
{
SYMBOL_VALUE_ADDRESS (&psymbol) = coreaddr;
}
SYMBOL_SECTION (&psymbol) = 0;
SYMBOL_LANGUAGE (&psymbol) = language;
PSYMBOL_DOMAIN (&psymbol) = domain;
PSYMBOL_CLASS (&psymbol) = class;
SYMBOL_SET_NAMES (&psymbol, buf, namelength, objfile);
psym = deprecated_bcache (&psymbol, sizeof (struct partial_symbol),
objfile->psymbol_cache);
if (list->next >= list->list + list->size)
{
extend_psymbol_list (list, objfile);
}
*list->next++ = psym;
OBJSTAT (objfile, n_psyms++);
return psym;
}
void
add_psymbol_with_dem_name_to_list (char *name, int namelength, char *dem_name,
int dem_namelength, domain_enum domain,
enum address_class class,
struct psymbol_allocation_list *list, long val,
CORE_ADDR coreaddr,
enum language language,
struct objfile *objfile)
{
struct partial_symbol *psym;
char *buf = alloca (namelength + 1);
static struct partial_symbol psymbol;
memcpy (buf, name, namelength);
buf[namelength] = '\0';
DEPRECATED_SYMBOL_NAME (&psymbol) = deprecated_bcache (buf, namelength + 1,
objfile->psymbol_cache);
buf = alloca (dem_namelength + 1);
memcpy (buf, dem_name, dem_namelength);
buf[dem_namelength] = '\0';
switch (language)
{
case language_c:
case language_cplus:
case language_objcplus:
SYMBOL_CPLUS_DEMANGLED_NAME (&psymbol) =
deprecated_bcache (buf, dem_namelength + 1, objfile->psymbol_cache);
break;
default:
internal_error (__FILE__, __LINE__, "unhandled case");
break;
}
if (val != 0)
{
SYMBOL_VALUE (&psymbol) = val;
}
else
{
SYMBOL_VALUE_ADDRESS (&psymbol) = coreaddr;
}
SYMBOL_SECTION (&psymbol) = 0;
SYMBOL_LANGUAGE (&psymbol) = language;
PSYMBOL_DOMAIN (&psymbol) = domain;
PSYMBOL_CLASS (&psymbol) = class;
SYMBOL_INIT_LANGUAGE_SPECIFIC (&psymbol, language);
psym = deprecated_bcache (&psymbol, sizeof (struct partial_symbol),
objfile->psymbol_cache);
if (list->next >= list->list + list->size)
{
extend_psymbol_list (list, objfile);
}
*list->next++ = psym;
OBJSTAT (objfile, n_psyms++);
}
void
init_psymbol_list (struct objfile *objfile, int total_symbols)
{
if (objfile->global_psymbols.list)
{
xfree (objfile->global_psymbols.list);
}
if (objfile->static_psymbols.list)
{
xfree (objfile->static_psymbols.list);
}
objfile->global_psymbols.size = total_symbols / 10;
objfile->static_psymbols.size = total_symbols / 10;
if (objfile->global_psymbols.size > 0)
{
objfile->global_psymbols.next =
objfile->global_psymbols.list = (struct partial_symbol **)
xmalloc ((objfile->global_psymbols.size
* sizeof (struct partial_symbol *)));
}
if (objfile->static_psymbols.size > 0)
{
objfile->static_psymbols.next =
objfile->static_psymbols.list = (struct partial_symbol **)
xmalloc ((objfile->static_psymbols.size
* sizeof (struct partial_symbol *)));
}
}
enum overlay_debugging_state overlay_debugging = ovly_off;
int overlay_cache_invalid = 0;
static void simple_overlay_update (struct obj_section *);
void (*target_overlay_update) (struct obj_section *) = simple_overlay_update;
int
section_is_overlay (asection *section)
{
if (overlay_debugging)
if (section && section->lma != 0 &&
section->vma != section->lma)
return 1;
return 0;
}
static void
overlay_invalidate_all (void)
{
struct objfile *objfile;
struct obj_section *sect;
ALL_OBJSECTIONS (objfile, sect)
if (section_is_overlay (sect->the_bfd_section))
sect->ovly_mapped = -1;
}
static int
overlay_is_mapped (struct obj_section *osect)
{
if (osect == 0 || !section_is_overlay (osect->the_bfd_section))
return 0;
switch (overlay_debugging)
{
default:
case ovly_off:
return 0;
case ovly_auto:
if (target_overlay_update)
{
if (overlay_cache_invalid)
{
overlay_invalidate_all ();
overlay_cache_invalid = 0;
}
if (osect->ovly_mapped == -1)
(*target_overlay_update) (osect);
}
case ovly_on:
return osect->ovly_mapped == 1;
}
}
int
section_is_mapped (asection *section)
{
struct objfile *objfile;
struct obj_section *osect;
if (overlay_debugging)
if (section && section_is_overlay (section))
ALL_OBJSECTIONS (objfile, osect)
if (osect->the_bfd_section == section)
return overlay_is_mapped (osect);
return 0;
}
CORE_ADDR
pc_in_unmapped_range (CORE_ADDR pc, asection *section)
{
int size;
if (overlay_debugging)
if (section && section_is_overlay (section))
{
size = bfd_get_section_size (section);
if (section->lma <= pc && pc < section->lma + size)
return 1;
}
return 0;
}
CORE_ADDR
pc_in_mapped_range (CORE_ADDR pc, asection *section)
{
int size;
if (overlay_debugging)
if (section && section_is_overlay (section))
{
size = bfd_get_section_size (section);
if (section->vma <= pc && pc < section->vma + size)
return 1;
}
return 0;
}
static int
sections_overlap (asection *a, asection *b)
{
CORE_ADDR a_start = a->vma;
CORE_ADDR a_end = a->vma + bfd_get_section_size (a);
CORE_ADDR b_start = b->vma;
CORE_ADDR b_end = b->vma + bfd_get_section_size (b);
return (a_start < b_end && b_start < a_end);
}
CORE_ADDR
overlay_unmapped_address (CORE_ADDR pc, asection *section)
{
if (overlay_debugging)
if (section && section_is_overlay (section) &&
pc_in_mapped_range (pc, section))
return pc + section->lma - section->vma;
return pc;
}
CORE_ADDR
overlay_mapped_address (CORE_ADDR pc, asection *section)
{
if (overlay_debugging)
if (section && section_is_overlay (section) &&
pc_in_unmapped_range (pc, section))
return pc + section->vma - section->lma;
return pc;
}
CORE_ADDR
symbol_overlayed_address (CORE_ADDR address, asection *section)
{
if (overlay_debugging)
{
if (section == 0)
return address;
if (!section_is_overlay (section))
return address;
if (section_is_mapped (section))
return address;
return overlay_unmapped_address (address, section);
}
return address;
}
asection *
find_pc_overlay (CORE_ADDR pc)
{
struct objfile *objfile;
struct obj_section *osect, *best_match = NULL;
if (pc == last_overlay_section_lookup_pc)
return cached_overlay_section;
last_overlay_section_lookup_pc = pc;
if (overlay_debugging)
ALL_OBJSECTIONS (objfile, osect)
if (section_is_overlay (osect->the_bfd_section))
{
if (pc_in_mapped_range (pc, osect->the_bfd_section))
{
if (overlay_is_mapped (osect))
{
cached_overlay_section = osect->the_bfd_section;
return osect->the_bfd_section;
}
else
best_match = osect;
}
else if (pc_in_unmapped_range (pc, osect->the_bfd_section))
best_match = osect;
}
cached_overlay_section = best_match ? best_match->the_bfd_section : NULL;
return best_match ? best_match->the_bfd_section : NULL;
}
asection *
find_pc_mapped_section (CORE_ADDR pc)
{
struct objfile *objfile;
struct obj_section *osect;
if (pc == last_mapped_section_lookup_pc)
return cached_mapped_section;
last_mapped_section_lookup_pc = pc;
if (overlay_debugging)
ALL_OBJSECTIONS (objfile, osect)
if (pc_in_mapped_range (pc, osect->the_bfd_section) &&
overlay_is_mapped (osect))
{
cached_mapped_section = osect->the_bfd_section;
return osect->the_bfd_section;
}
last_mapped_section_lookup_pc = INVALID_ADDRESS;
cached_mapped_section = NULL;
return NULL;
}
void
list_overlays_command (char *args, int from_tty)
{
int nmapped = 0;
struct objfile *objfile;
struct obj_section *osect;
if (overlay_debugging)
ALL_OBJSECTIONS (objfile, osect)
if (overlay_is_mapped (osect))
{
const char *name;
bfd_vma lma, vma;
int size;
vma = bfd_section_vma (objfile->obfd, osect->the_bfd_section);
lma = bfd_section_lma (objfile->obfd, osect->the_bfd_section);
size = bfd_get_section_size (osect->the_bfd_section);
name = bfd_section_name (objfile->obfd, osect->the_bfd_section);
printf_filtered ("Section %s, loaded at ", name);
deprecated_print_address_numeric (lma, 1, gdb_stdout);
puts_filtered (" - ");
deprecated_print_address_numeric (lma + size, 1, gdb_stdout);
printf_filtered (", mapped at ");
deprecated_print_address_numeric (vma, 1, gdb_stdout);
puts_filtered (" - ");
deprecated_print_address_numeric (vma + size, 1, gdb_stdout);
puts_filtered ("\n");
nmapped++;
}
if (nmapped == 0)
printf_filtered (_("No sections are mapped.\n"));
}
void
map_overlay_command (char *args, int from_tty)
{
struct objfile *objfile, *objfile2;
struct obj_section *sec, *sec2;
asection *bfdsec;
if (!overlay_debugging)
error (_("\
Overlay debugging not enabled. Use either the 'overlay auto' or\n\
the 'overlay manual' command."));
if (args == 0 || *args == 0)
error (_("Argument required: name of an overlay section"));
ALL_OBJSECTIONS (objfile, sec)
if (!strcmp (bfd_section_name (objfile->obfd, sec->the_bfd_section), args))
{
bfdsec = sec->the_bfd_section;
if (!section_is_overlay (bfdsec))
continue;
sec->ovly_mapped = 1;
ALL_OBJSECTIONS (objfile2, sec2)
if (sec2->ovly_mapped
&& sec != sec2
&& sec->the_bfd_section != sec2->the_bfd_section
&& sections_overlap (sec->the_bfd_section,
sec2->the_bfd_section))
{
if (info_verbose)
printf_unfiltered (_("Note: section %s unmapped by overlap\n"),
bfd_section_name (objfile->obfd,
sec2->the_bfd_section));
sec2->ovly_mapped = 0;
}
return;
}
error (_("No overlay section called %s"), args);
}
void
unmap_overlay_command (char *args, int from_tty)
{
struct objfile *objfile;
struct obj_section *sec;
if (!overlay_debugging)
error (_("\
Overlay debugging not enabled. Use either the 'overlay auto' or\n\
the 'overlay manual' command."));
if (args == 0 || *args == 0)
error (_("Argument required: name of an overlay section"));
ALL_OBJSECTIONS (objfile, sec)
if (!strcmp (bfd_section_name (objfile->obfd, sec->the_bfd_section), args))
{
if (!sec->ovly_mapped)
error (_("Section %s is not mapped"), args);
sec->ovly_mapped = 0;
return;
}
error (_("No overlay section called %s"), args);
}
static void
overlay_auto_command (char *args, int from_tty)
{
overlay_debugging = ovly_auto;
enable_overlay_breakpoints ();
if (info_verbose)
printf_unfiltered (_("Automatic overlay debugging enabled."));
}
static void
overlay_manual_command (char *args, int from_tty)
{
overlay_debugging = ovly_on;
disable_overlay_breakpoints ();
if (info_verbose)
printf_unfiltered (_("Overlay debugging enabled."));
}
static void
overlay_off_command (char *args, int from_tty)
{
overlay_debugging = ovly_off;
disable_overlay_breakpoints ();
if (info_verbose)
printf_unfiltered (_("Overlay debugging disabled."));
}
static void
overlay_load_command (char *args, int from_tty)
{
if (target_overlay_update)
(*target_overlay_update) (NULL);
else
error (_("This target does not know how to read its overlay state."));
}
struct cmd_list_element *overlaylist;
static void
overlay_command (char *args, int from_tty)
{
printf_unfiltered
("\"overlay\" must be followed by the name of an overlay command.\n");
help_list (overlaylist, "overlay ", -1, gdb_stdout);
}
static unsigned (*cache_ovly_table)[4] = 0;
#if 0
static unsigned (*cache_ovly_region_table)[3] = 0;
#endif
static unsigned cache_novlys = 0;
#if 0
static unsigned cache_novly_regions = 0;
#endif
static CORE_ADDR cache_ovly_table_base = 0;
#if 0
static CORE_ADDR cache_ovly_region_table_base = 0;
#endif
enum ovly_index
{
VMA, SIZE, LMA, MAPPED
};
#define TARGET_LONG_BYTES (TARGET_LONG_BIT / TARGET_CHAR_BIT)
static void
simple_free_overlay_table (void)
{
if (cache_ovly_table)
xfree (cache_ovly_table);
cache_novlys = 0;
cache_ovly_table = NULL;
cache_ovly_table_base = 0;
}
#if 0
static void
simple_free_overlay_region_table (void)
{
if (cache_ovly_region_table)
xfree (cache_ovly_region_table);
cache_novly_regions = 0;
cache_ovly_region_table = NULL;
cache_ovly_region_table_base = 0;
}
#endif
static void
read_target_long_array (CORE_ADDR memaddr, unsigned int *myaddr, int len)
{
char *buf = alloca (len * TARGET_LONG_BYTES);
int i;
read_memory (memaddr, buf, len * TARGET_LONG_BYTES);
for (i = 0; i < len; i++)
myaddr[i] = extract_unsigned_integer (TARGET_LONG_BYTES * i + buf,
TARGET_LONG_BYTES);
}
static int
simple_read_overlay_table (void)
{
struct minimal_symbol *novlys_msym, *ovly_table_msym;
simple_free_overlay_table ();
novlys_msym = lookup_minimal_symbol ("_novlys", NULL, NULL);
if (! novlys_msym)
{
error (_("Error reading inferior's overlay table: "
"couldn't find `_novlys' variable\n"
"in inferior. Use `overlay manual' mode."));
return 0;
}
ovly_table_msym = lookup_minimal_symbol ("_ovly_table", NULL, NULL);
if (! ovly_table_msym)
{
error (_("Error reading inferior's overlay table: couldn't find "
"`_ovly_table' array\n"
"in inferior. Use `overlay manual' mode."));
return 0;
}
cache_novlys = read_memory_integer (SYMBOL_VALUE_ADDRESS (novlys_msym), 4);
cache_ovly_table
= (void *) xmalloc (cache_novlys * sizeof (*cache_ovly_table));
cache_ovly_table_base = SYMBOL_VALUE_ADDRESS (ovly_table_msym);
read_target_long_array (cache_ovly_table_base,
(int *) cache_ovly_table,
cache_novlys * 4);
return 1;
}
#if 0
static int
simple_read_overlay_region_table (void)
{
struct minimal_symbol *msym;
simple_free_overlay_region_table ();
msym = lookup_minimal_symbol ("_novly_regions", NULL, NULL);
if (msym != NULL)
cache_novly_regions = read_memory_integer (SYMBOL_VALUE_ADDRESS (msym), 4);
else
return 0;
cache_ovly_region_table = (void *) xmalloc (cache_novly_regions * 12);
if (cache_ovly_region_table != NULL)
{
msym = lookup_minimal_symbol ("_ovly_region_table", NULL, NULL);
if (msym != NULL)
{
cache_ovly_region_table_base = SYMBOL_VALUE_ADDRESS (msym);
read_target_long_array (cache_ovly_region_table_base,
(int *) cache_ovly_region_table,
cache_novly_regions * 3);
}
else
return 0;
}
else
return 0;
return 1;
}
#endif
static int
simple_overlay_update_1 (struct obj_section *osect)
{
int i, size;
asection *bsect = osect->the_bfd_section;
size = bfd_get_section_size (osect->the_bfd_section);
for (i = 0; i < cache_novlys; i++)
if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
&& cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
)
{
read_target_long_array (cache_ovly_table_base + i * TARGET_LONG_BYTES,
(int *) cache_ovly_table[i], 4);
if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
&& cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
)
{
osect->ovly_mapped = cache_ovly_table[i][MAPPED];
return 1;
}
else
return 0;
}
return 0;
}
static void
simple_overlay_update (struct obj_section *osect)
{
struct objfile *objfile;
if (osect)
if (cache_ovly_table != NULL)
if (cache_ovly_table_base ==
SYMBOL_VALUE_ADDRESS (lookup_minimal_symbol ("_ovly_table", NULL, NULL)))
if (simple_overlay_update_1 (osect))
return;
if (! simple_read_overlay_table ())
return;
ALL_OBJSECTIONS (objfile, osect)
if (section_is_overlay (osect->the_bfd_section))
{
int i, size;
asection *bsect = osect->the_bfd_section;
size = bfd_get_section_size (bsect);
for (i = 0; i < cache_novlys; i++)
if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
&& cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
)
{
osect->ovly_mapped = cache_ovly_table[i][MAPPED];
break;
}
}
}
static void
symfile_dummy_outputs (bfd *abfd, asection *sectp, void *dummy)
{
sectp->output_section = sectp;
sectp->output_offset = 0;
}
bfd_byte *
symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf)
{
if ((sectp->flags & SEC_RELOC) == 0)
return NULL;
if ((sectp->flags & SEC_DEBUGGING) == 0)
return NULL;
bfd_map_over_sections (abfd, symfile_dummy_outputs, NULL);
return bfd_simple_get_relocated_section_contents (abfd, sectp, buf, NULL);
}
struct symbol_file_info {
bfd *abfd;
int from_tty;
struct section_addr_info *addrs;
struct section_offsets *offsets;
int num_offsets;
int mainline;
int flags;
int symflags;
CORE_ADDR mapaddr;
const char *prefix;
struct objfile *result;
char *kext_bundle;
};
int
symbol_file_add_bfd_helper (void *v)
{
struct symbol_file_info *s = (struct symbol_file_info *) v;
s->result = symbol_file_add_with_addrs_or_offsets
(s->abfd, s->from_tty, s->addrs, s->offsets, s->num_offsets, s->mainline, s->flags,
s->symflags, s->mapaddr, s->prefix, s->kext_bundle);
return 1;
}
struct objfile *
symbol_file_add_bfd_using_objfile (struct objfile *objfile,
bfd *abfd, int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int mainline, int flags, int symflags,
CORE_ADDR mapaddr, const char *prefix)
{
return symbol_file_add_with_addrs_or_offsets_using_objfile (objfile, abfd, from_tty,
addrs, offsets, 0, mainline,
flags, symflags,
mapaddr, prefix, NULL);
}
struct objfile *
symbol_file_add_bfd_safe (bfd *abfd, int from_tty,
struct section_addr_info *addrs,
struct section_offsets *offsets,
int mainline, int flags, int symflags,
CORE_ADDR mapaddr, const char *prefix,
char *kext_bundle)
{
struct symbol_file_info s;
int ret;
s.abfd = abfd;
s.from_tty = from_tty;
s.addrs = addrs;
s.offsets = offsets;
if (offsets)
{
int i;
struct bfd_section *this_sect;
s.num_offsets = 0;
this_sect = abfd->sections;
for (i = 0; i < bfd_count_sections (abfd); i++, this_sect = this_sect->next)
{
if (objfile_keeps_section (abfd, this_sect))
s.num_offsets++;
}
}
else
s.num_offsets = 0;
s.mainline = mainline;
s.flags = flags;
s.symflags = symflags;
s.mapaddr = mapaddr;
s.prefix = prefix;
s.result = NULL;
s.kext_bundle = kext_bundle;
ret = catch_errors
(symbol_file_add_bfd_helper, &s, "unable to load symbol file: ", RETURN_MASK_ALL);
return s.result;
}
struct bfd_file_info {
const char *filename;
int mainline;
enum gdb_osabi osabi;
bfd *result;
};
int
symfile_bfd_open_helper (void *v)
{
struct bfd_file_info *s = (struct bfd_file_info *) v;
s->result = symfile_bfd_open (s->filename, s->mainline, s->osabi);
return 1;
}
bfd *
symfile_bfd_open_safe(const char *filename, int mainline, enum gdb_osabi osabi)
{
struct bfd_file_info s;
int ret;
s.filename = filename;
s.mainline = mainline;
s.osabi = osabi;
s.result = NULL;
ret = catch_errors
(symfile_bfd_open_helper, &s, "unable to open symbol file: ", RETURN_MASK_ALL);
return s.result;
}
struct section_offsets *
convert_sect_addrs_to_offsets_via_on_disk_file (struct section_addr_info *sect_addrs,
const char *file, int *num_offsets)
{
struct section_offsets *sect_offsets;
struct bfd_section *this_sect;
CORE_ADDR slide = INVALID_ADDRESS;
struct cleanup *cleanup;
if (sect_addrs == NULL || file == NULL || !file_exists_p (file))
return NULL;
bfd *abfd = symfile_bfd_open_safe (file, 0, gdbarch_osabi (current_gdbarch));
if (abfd == NULL)
return NULL;
cleanup = make_cleanup_bfd_close (abfd);
sect_offsets = (struct section_offsets *)
xmalloc (SIZEOF_N_SECTION_OFFSETS (abfd->section_count));
int i, cur_section;
for (i = 0; i < abfd->section_count; i++)
sect_offsets->offsets[i] = INVALID_ADDRESS;
*num_offsets = abfd->section_count;
for (i = 0; i < sect_addrs->num_sections; i++)
{
if (sect_addrs->other[i].name == NULL
|| sect_addrs->other[i].name[0] == '\0'
|| sect_addrs->other[i].addr == 0)
continue;
for (this_sect = abfd->sections, cur_section = 0;
this_sect != NULL;
this_sect = this_sect->next, ++cur_section)
{
if (this_sect->name == NULL || this_sect->name[0] == '\0')
continue;
if (strcmp (sect_addrs->other[i].name, this_sect->name) == 0)
{
sect_offsets->offsets[cur_section] =
sect_addrs->other[i].addr - this_sect->vma;
if (slide == INVALID_ADDRESS)
slide = sect_offsets->offsets[cur_section];
}
}
}
if (slide != INVALID_ADDRESS)
for (i = 0; i < abfd->section_count; i++)
if (sect_offsets->offsets[i] == INVALID_ADDRESS)
sect_offsets->offsets[i] = slide;
do_cleanups (cleanup);
return sect_offsets;
}
bfd *
open_bfd_matching_arch (bfd *archive_bfd, bfd_format expected_format,
enum gdb_osabi osabi)
{
bfd *abfd = NULL;
#if defined (TARGET_ARM) && defined (TM_NEXTSTEP)
bfd *fallback = NULL;
enum gdb_osabi fallback_osabi = GDB_OSABI_UNKNOWN;
#ifdef MACOSX_DYLD
if (osabi == GDB_OSABI_UNKNOWN)
osabi = macosx_get_osabi_from_dyld_entry (archive_bfd);
#endif
#ifdef NM_NEXTSTEP
extern enum gdb_osabi arm_host_osabi ();
if (osabi == GDB_OSABI_UNKNOWN)
osabi = arm_host_osabi();
#else
if (osabi == GDB_OSABI_UNKNOWN)
{
osabi = gdbarch_lookup_osabi (archive_bfd);
}
#endif
for (;;)
{
enum gdb_osabi this_osabi;
abfd = bfd_openr_next_archived_file (archive_bfd, abfd);
if (abfd == NULL)
break;
if (!(bfd_check_format (abfd, bfd_object) ||
(bfd_check_format (abfd, bfd_archive))))
continue;
this_osabi = gdbarch_lookup_osabi_from_bfd (abfd);
if (this_osabi == osabi)
return abfd;
else if (fallback_osabi < this_osabi)
{
if (osabi == GDB_OSABI_UNKNOWN || this_osabi < osabi)
{
switch (this_osabi)
{
case GDB_OSABI_DARWIN:
case GDB_OSABI_DARWINV6:
case GDB_OSABI_DARWINV7:
case GDB_OSABI_DARWINV7K:
case GDB_OSABI_DARWINV7F:
case GDB_OSABI_DARWINV7S:
fallback = abfd;
fallback_osabi = this_osabi;
break;
default:
break;
}
}
}
}
return fallback;
#else
osabi = gdbarch_osabi (current_gdbarch);
if ((osabi <= GDB_OSABI_UNKNOWN) || (osabi >= GDB_OSABI_INVALID))
osabi = gdbarch_lookup_osabi (archive_bfd);
for (;;)
{
abfd = bfd_openr_next_archived_file (archive_bfd, abfd);
if (abfd == NULL)
break;
if (! bfd_check_format (abfd, expected_format))
continue;
if (osabi == gdbarch_lookup_osabi_from_bfd (abfd))
{
break;
}
}
return abfd;
#endif
}
void
_initialize_symfile (void)
{
struct cmd_list_element *c;
#if HAVE_MMAP
add_setshow_boolean_cmd ("mmap-symbol-files", class_obscure,
&mmap_symbol_files_flag, _("\
Set if GDB should use mmap() to read from external symbol files."), _("\
Show if GDB should use mmap() to read from external symbol files."), NULL,
NULL, NULL,
&setlist, &showlist);
#endif
c = add_cmd ("reread-symbols", class_files, reread_symbols_command,
"Usage: reread-symbols\n\
Re-load the symbols from all known object files.",
&cmdlist);
c = add_cmd ("remove-symbol-file", class_files, remove_symbol_file_command,
"Usage: remove-symbol-file FILE\n\
Unload the symbols from FILE.",
&cmdlist);
set_cmd_completer (c, filename_completer);
c = add_cmd ("symbol-file", class_files, symbol_file_command, _("\
Load symbol table from executable file FILE.\n\
The `file' command can also load symbol tables, as well as setting the file\n\
to execute."), &cmdlist);
set_cmd_completer (c, filename_completer);
c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command, _("\
Usage: add-symbol-file FILE ADDR [-s <SECT> <SECT_ADDR> -s <SECT> <SECT_ADDR> ...]\n\
Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
ADDR is the starting address of the file's text.\n\
The optional arguments are section-name section-address pairs and\n\
should be specified if the data and bss segments are not contiguous\n\
with the text. SECT is a section name to be loaded at SECT_ADDR."),
&cmdlist);
set_cmd_completer (c, filename_completer);
c = add_cmd ("add-kext", class_files, add_kext_command, _("\
Usage: add-kext KEXTBUNDLE\n\
Load the symbols from KEXTBUNDLE, where KEXTBUNDLE is the bundle directory\n\
including a Contents/Info.plist file. In the same directory you need the\n\
output from kextutil(8) -s/-a/etc which has the addresses where the kext\n\
was loaded in the kernel and you need the .dSYM file in that directory as well.\n"),
&cmdlist);
set_cmd_completer (c, filename_completer);
c = add_cmd ("add-dsym", class_files, add_dsym_command, _("\
Usage: add-dsym DSYM_FILE\n\
Load the symbols from DSYM_FILE, adding them to a library with\n\
the matching UUID."),
&cmdlist);
set_cmd_completer (c, filename_completer);
c = add_cmd ("add-shared-symbol-files", class_files,
add_shared_symbol_files_command, _("\
Load the symbols from shared objects in the dynamic linker's link map."),
&cmdlist);
c = add_alias_cmd ("assf", "add-shared-symbol-files", class_files, 1,
&cmdlist);
c = add_cmd ("load", class_files, load_command, _("\
Dynamically load FILE into the running program, and record its symbols\n\
for access from GDB."), &cmdlist);
set_cmd_completer (c, filename_completer);
add_setshow_boolean_cmd ("symbol-reloading", class_support,
&symbol_reloading, _("\
Set dynamic symbol table reloading multiple times in one run."), _("\
Show dynamic symbol table reloading multiple times in one run."), NULL,
NULL,
show_symbol_reloading,
&setlist, &showlist);
add_prefix_cmd ("overlay", class_support, overlay_command,
_("Commands for debugging overlays."), &overlaylist,
"overlay ", 0, &cmdlist);
add_com_alias ("ovly", "overlay", class_alias, 1);
add_com_alias ("ov", "overlay", class_alias, 1);
add_cmd ("map-overlay", class_support, map_overlay_command,
_("Assert that an overlay section is mapped."), &overlaylist);
add_cmd ("unmap-overlay", class_support, unmap_overlay_command,
_("Assert that an overlay section is unmapped."), &overlaylist);
add_cmd ("list-overlays", class_support, list_overlays_command,
_("List mappings of overlay sections."), &overlaylist);
add_cmd ("manual", class_support, overlay_manual_command,
_("Enable overlay debugging."), &overlaylist);
add_cmd ("off", class_support, overlay_off_command,
_("Disable overlay debugging."), &overlaylist);
add_cmd ("auto", class_support, overlay_auto_command,
_("Enable automatic overlay debugging."), &overlaylist);
add_cmd ("load-target", class_support, overlay_load_command,
_("Read the overlay mapping state from the target."), &overlaylist);
init_filename_language_table ();
add_setshow_string_noescape_cmd ("extension-language", class_files,
&ext_args, _("\
Set mapping between filename extension and source language."), _("\
Show mapping between filename extension and source language."), _("\
Usage: set extension-language .foo bar"),
set_ext_lang_command,
show_ext_args,
&setlist, &showlist);
add_info ("extensions", info_ext_lang_command,
_("All filename extensions associated with a source language."));
add_setshow_integer_cmd ("download-write-size", class_obscure,
&download_write_size, _("\
Set the write size used when downloading a program."), _("\
Show the write size used when downloading a program."), _("\
Only used when downloading a program onto a remote\n\
target. Specify zero, or a negative value, to disable\n\
blocked writes. The actual size of each transfer is also\n\
limited by the size of the target packet and the memory\n\
cache."),
NULL,
show_download_write_size,
&setlist, &showlist);
add_setshow_optional_filename_cmd ("kext-symbol-file-path", class_support,
&kext_symbol_file_path, _("\
Set the directory where kextutil-generated sym files are searched for."), _("\
Show the directory where kextutil-generated sym files are searched for."), _("\
The kextutil-generated sym file is first searched for in the same\n\
directory as the kext bundle, then in the directory specified by \n\
kext-symbol-file-path. A common use would be to have kext-symbol-file-path\n\
set to /tmp and the kextutil-generated .sym files put in /tmp with the kext\n\
bundle and dSYM in another location."),
NULL,
NULL,
&setlist, &showlist);
debug_file_directory = xstrdup (DEBUGDIR);
add_setshow_optional_filename_cmd ("debug-file-directory", class_support,
&debug_file_directory, _("\
Set the directory where separate debug symbols are searched for."), _("\
Show the directory where separate debug symbols are searched for."), _("\
Separate debug symbols are first searched for in the same\n\
directory as the binary, then in the `" DEBUG_SUBDIRECTORY "' subdirectory,\n\
and lastly at the path of the directory of the binary with\n\
the global debug-file directory prepended."),
NULL,
show_debug_file_directory,
&setlist, &showlist);
}