Multi-process (primarily multi-exec) support.
2008-10-14 Stan Shebs <stan@codesourcery.com>
* blockframe.c (get_frame_block): Get inferior from frame.
* block.c (block_for_pc_inf): New function.
* block.h (block_for_pc_inf): Declare.
* symfile.c (find_pc_inf_sect): New function.
* symfile.h (find_pc_inf_sect): Declare.
* symtab.c (find_pc_inf_line): New function.
* symtab.h (find_pc_inf_line): Declare.
* frame.c (struct frame_info) New field inferior.
(fprint_frame_id): Display inferior.
(get_frame_id): Set inferior_num from inferior.
(frame_id_eq): Compare inferiors.
(create_sentinel_frame): Set inferior.
(create_new_frame): Copy inferior from sentinel.
(get_prev_frame_raw): Copy inferior from next frame.
(find_frame_sal): Use find_pc_inf_line.
(get_frame_inferior): New function.
* frame.h (struct frame_id): New field inferior_num.
* breakpoint.c (expand_sals_by_inferiors): Copy section from input
sal to expanded sals.
* symtab.c (expand_line_sal): Ditto.
2008-10-10 Stan Shebs <stan@codesourcery.com>
* remote.c (discard_pending_stop_replies): Initialize prev.
* infrun.c (infrun_thread_stop_requested): Ditto.
2008-10-08 Stan Shebs <stan@codesourcery.com>
* inferior.h (struct inferior): Rename environ field to inf_environ.
* inferior.c (print_inferior): Ditto.
2008-10-01 Stan Shebs <stan@codesourcery.com>
* inferior.h (detach_fork): Declare here...
* linux-fork.h (detach_fork): ...instead of here.
* linux-fork.c (detach_fork): Move to...
* infrun.c (detach_fork): ...here.
* remote.c (detach_fork): Remove decl.
2008-09-30 Stan Shebs <stan@codesourcery.com>
* linespec.c (decode_line_1): Better default for one-exec case.
* remote (remote_start_remote): Use the exec in the one-exec case.
2008-09-29 Stan Shebs <stan@codesourcery.com>
* infcmd.c (attach_command): If only one exec, assume it is the
attached inferior's exec.
(attach_command_post_wait): Set inferior's exec from
the one that was found.
* inf-ptrace.c (inf_ptrace_attach): Only report exec file if
if there is just one present.
(inf_ptrace_detach): Use inferior to get correct exec name.
2008-09-29 Stan Shebs <stan@codesourcery.com>
* inferior.c (print_inferior): Use exec short names, and drop
unused address space display.
2008-09-26 Stan Shebs <stan@codesourcery.com>
* breakpoint.c (should_be_inserted): Test for no inferior.
(clone_breakpoint_location): New function, broken out from...
(update_breakpoint_inferiors): ...here, also tweak conditions
for adding a location.
(insert_breakpoint_location): Don't count non-running inferiors.
(remove_breakpoint): Set tmp_inf.
(print_one_breakpoint_location): Add allflag arg, use to always
show inf.
(print_one_breakpoint): Add allflag arg.
(do_captured_breakpoint_query): Fix caller.
(breakpoint_1): Ditto.
* exec.c (create_exec): Save full pathname as exec name.
(find_exec_by_name): Use find_exec_by_substr.
* fork-child.c (fork_inferior): Warn if exec not found for new
inferior.
2008-09-25 Stan Shebs <stan@codesourcery.com>
* breakpoint.c (should_be_inserted): Don't insert in inferiors
that are not running.
(update_breakpoint_inferiors): New function.
(insert_breakpoints): Call it.
(insert_breakpoint_locations): Don't insert in inferiors that are
not running.
(set_raw_breakpoint_without_location): Set trigger set from
current itset here...
(set_raw_breakpoint): Instead of here. Also add default fillins
for the location's inferior.
(add_location_to_breakpoint): Similarly.
(expand_sals_by_inferiors): New function.
(breakpoint_re_set_one): Call it.
(resolve_sal_pc): Don't set sal inferior.
* breakpoint.h (struct breakpoint): Remove exec field, never used.
* inferior.h (inferior_list): Declare.
* inferior.c (inferior_list): Make public.
(add_inferior_to_itset): Auto-add inferiors after exec's inferior.
(first_inferior_in_set): Check for zero-length vector.
* exec.c (xfer_memory): Use tmp_inf as inferior if set.
* infcmd.c (focus_command): Improve user feedback.
* linespec.c (build_canonical_line_spec): Record exec name as part
of canonical spec.
(symbol_found): Canonicalize specs more.
(decode_indirect): Revert rewrite from 2008-09-14.
(decode_sharp): Use find_exec_by_substr, better error messages.
* minsyms.c (lookup_minimal_symbol_in_exec): New function.
(lookup_minimal_symbol_in_exec_1): New function, body of
lookup_minimal_symbol.
* symtab.h (lookup_minimal_symbol_in_exec): Declare.
* symtab.c (find_function_start_sal): Set inferior to use.
(append_expanded_sal): Return pointer to the new sal.
* remote.c (remote_xfer_memory): Better parms to ptid_build, remove
debug print.
(remote_xfer_partial): Ditto.
2008-09-22 Pedro Alves <pedro@codesourcery.com>
* inferior.c (itset_member): Fix typo.
2008-09-22 Stan Shebs <stan@codesourcery.com>
* inferior.h (current_inf): Remove declaration.
(tmp_inf): Declare.
* inferior.c (current_inf): Remove.
(tmp_inf): New global, hack to bypass passing inferior throughout
target stack.
(print_inferior): Don't report current_inf.
(add_inferior_command): Don't use current_inf.
(name_inferior_command): Use first inferior of current_itset.
(update_itset): Handle NULL case.
(add_inferior_itset): Recursively add all inferiors derived from
an exec if the exec's own inferior is present.
(first_inferior_in_set): New function.
(free_inferior): Comment out until references cleared reliably.
* infcmd.c (focus_command): Don't set current_inf.
(get_inferior_args): Use first_inferior_in_set instead of
current_inf.
(set_inferior_args): Ditto.
(set_inferior_args_vector): Ditto.
(notice_args_set): Ditto.
* breakpoint.c (insert_breakpoint_locations): Remove insertion test
using current_inf, set tmp_inf.
(reattach_breakpoints): Set tmp_inf.
(bpstat_check_breakpoint_conditions): Test trigger set here...
(bpstat_stop_status): ... instead of here.
(bpstat_check_trigger_set): Add special case for exec's own
inferior.
(print_one_breakpoint_location): Also test for multiple inferiors
before displaying location's inferior, flag trigger set with "i/t"
instead of "focus".
(check_duplicates): Pass location's inferior to...
(check_duplicates_for): Add inferior arg and use.
(set_raw_breakpoint): Override sal inferior with one from the
trigger set.
(add_location_to_breakpoint): Ditto.
* remote.c (remote_xfer_memory): Switch inferiors if tmp_inf is
set to something different from inferior_ptid.
(remote_xfer_partial): Ditto.
* top.c (execute_command): Always update the current itset.
2008-09-19 Stan Shebs <stan@codesourcery.com>
* inferior.c (set_inferior_exec): New function.
(set_inferior_exec_command): New command.
* inferior.h: Declare set_inferior_exec.
* fork-child.c (fork_inferior): Set the inferior's exec.
* remote.c (extended_remote_create_inferior_1): Ditto.
gdb/doc/
* gdb.texinfo (Debugging Multiple Programs): Describe set-exec.
2008-09-18 Stan Shebs <stan@codesourcery.com>
* target.c (target_resize_to_sections): Adjust execs' section
tables too.
2008-09-17 Stan Shebs <stan@codesourcery.com>
gdb/doc/
* gdb.texinfo (Invoking GDB): Describe multiple program args.
(File Options): Describe multi-program effects.
(Multiple Programs): New section, multi-program debugging.
(Forks): Rename section from "Processes".
(Specify Location): Describe the #-syntax.
(Variables): Describe the #-syntax.
(Files): Describe add-file and add-exec-file.
(Maintenance Commands): Describe maint print execs.
2008-09-15 Stan Shebs <stan@codesourcery.com>
* exec.c (addr_space_info_command): Don't try to display host address.
2008-09-14 Stan Shebs <stan@codesourcery.com>
* c-exp.y: (yylex): Accept '#' in identifiers.
* linespec.c (decode_sharp): New function.
(decode_line_1): Use it for #-syntax.
(decode_indirect): Rewrite to accept exec arg and iterate over
inferiors.
(struct d_i_data): New struct for inferior iteration.
(decode_indirect_callback): New function.
(decode_variable): Pass in exec, use in symbol lookup.
2008-09-14 Stan Shebs <stan@codesourcery.com>
* breakpoint.h (struct bp_location): Add inferior field instead
of address space field.
* breakpoint.c (insert_breakpoint_locations): Only insert in
appropriate inferior.
(bpstat_check_trigger_set): New function.
(bpstat_stop_status): Call it, check location's inferior also.
(print_one_breakpoint_location): Report location's inferior.
(set_raw_breakpoint): Set location inferior, clear an experiment.
(add_location_to_breakpoint): Ditto.
(expand_line_sal_maybe): Check for non-NULL original function.
(resolve_sal_pc): Set sal inferior.
(clear_command): Be careful to not clear anything twice.
* symtab.h: Update declarations of symbol lookups.
(struct symtab_and_line): Change address space to inferior field.
* symtab.c (init_sal): Clear inferior field.
(append_expanded_sal): Set inferior.
(lookup_symbol_in_language_1): New function.
(lookup_symbol_in_language): Call it.
(lookup_symbol_in_exec_in_language): New function.
(lookup_symbol): Detect #-syntax and find exec to use.
(lookup_symbol_aux): Add exec argument and use it.
(lookup_symbol_aux_symtabs): Ditto.
(lookup_symbol_aux_psymtabs): Ditto.
(basic_lookup_symbol_nonlocal): Ditto.
(lookup_symbol_static): Ditto.
(lookup_symbol_global): Ditto.
* ada-lang.c (cp_lookup_symbol_nonlocal): Ditto.
* cp-support.h (cp_lookup_symbol_nonlocal): Ditto.
* cp-namespace.c (cp_lookup_symbol_nonlocal): Ditto.
* language.h (struct language_defn): Ditto.
* scm-valprint.c (scm_inferior_print): Add exec arg to
lookup_symbol_global.
* source.c (select_source_symtab): Use current_exec.
* addrspace.h (struct addr_space): New field num.
* exec.h (struct exec): New fields sections and sections_end.
* exec.c (exec_file_attach_1): Set them from exec_ops, set
inferior's address space name from exec.
(find_exec_by_substr): New function.
(build_section_table): Don't free old table.
(print_section_info): Use exec's section table.
(next_address_space_num): New global, numbering for address spaces.
(new_address_space): Use it.
(addr_space_info_command): Display it.
* infcmd.c (set_current_exec): Set exec_ops section table.
* inferior.h (update_itset): Declare.
* inferior.c (add_inferior_silent): Set address space.
(print_inferior): Display it.
(number_of_inferiors): New function.
(itset_member): New function.
2008-09-04 Stan Shebs <stan@codesourcery.com>
* corefile.c (close_exec_file): Remove #if 0 block.
(validate_files): Use first_exec instead of exec_bfd.
(get_exec_file): Ditto.
* corelow.c (core_open): Ditto.
* utils.c (string_to_core_addr): Ditto.
* arch-utils.c (gdbarch_update_p): Ditto.
* linux-thread-db.c (enable_thread_event): Ditto.
(thread_db_get_thread_local_address ): Ditto.
* exec.c (find_exec_by_name): Test short name also.
(file_command): Set current exec.
2008-09-03 Stan Shebs <stan@codesourcery.com>
* inferior.c (add_threads_to_itset): Default to including all
of an inferior's threads.
2008-08-31 Stan Shebs <stan@codesourcery.com>
Parsing for i/t sets.
* inferior.h (struct itset_entry): New struct.
(struct itset): Make thread lists be per-inferior, add parse state
variables.
* inferior.c: (add_inferior_command): Add error checking and
confirmation.
(remove_inferior_command): Update for itset restructuring.
(new_itset): Don't pass in dynamic-ness, call parse_itset_spec.
(update_itset): Similarly.
(parse_itset_spec): New, parsing of itset spec.
(parse_itset_list, parse_itset_range, etc): New.
(make_itset_from_spec): Rewrite.
(dump_itset): Rewrite to reflect itset structure.
* infcmd.c (focus_command): Similarly.
2008-08-25 Stan Shebs <stan@codesourcery.com>
First part of multiprocess support.
* Makefile.in (COMMON_OBS): Add inferior.o.
* addrspace.h: New file.
* breakpoints.h (struct bp_location): Add address space field.
(struct breakpoint): Add trigger set and exec fields.
* breakpoints.c (print_one_breakpoint_location): Display trigger
set.
(set_raw_breakpoint): Set trigger set from current itset.
* corefile.c (reopen_exec_file): Rewrite for multiple execs.
(get_exec_file): Add case for current_exec.
* corelow.c (is_core_file): New function.
(core_files_info): Pass additional arg to print_section_info.
* exec.h (struct exec): New struct.
* exec.c (execs): New global.
(exec_bfd_mtime): Remove.
(last_exec_created, current_exec, first_exec): New globals.
(exec_close): Clear all exec objects.
(exec_file_clear): Tweak user message.
(exec_file_add): New function.
(exec_file_attach_1): New function, body of exec_file_attach,
plus new code to handle multiple execs.
(exec_file_attach): Call it.
(exec_file_update): New function.
(create_exec, find_exec_by_name, number_of_execs): New functions.
(exec_file_command): Rephrase query, set current exec.
(add_exec_file_command): New command.
(add_file_command): New command.
(print_section_info): Add exec argument.
(exec_files_info): Rewrite for multiple execs.
(maintenance_print_execs): New function.
(new_address_space): New function.
(addr_space_info_command): New command.
* gdbcore.h (exec_bfd_mtime): Remove decl.
(exec_file_add): Declare.
* infcmd.c: Include exec.h.
(current_itset): New global.
(set_current_exec): New function.
(focus_command): New command.
(get_inferior_args): Maybe get from the current inferior.
(set_inferior_args): Also set in current inferior.
(set_inferior_args_vector): Similarly.
(notice_args_set): Similarly.
(attach_command): Rephrase query.
* inferior.h (struct inferior): New struct.
(struct itset): New struct.
* inferior.c: New file, management of multiple inferiors.
* main.c (captured_main): Rewrite to allow multiple executables,
pids, and corefiles on the command line.
* maint.c (maintenance_info_sections): Rewrite for multiple execs.
* objfiles.h (struct objfile): New field for exec.
(ALL_OBJFILES_FOR_EXEC, ALL_PRIMARY_SYMTABS_FOR_EXEC,
ALL_PSYMTABS_FOR_EXEC): New macros.
* objfiles.c (allocate_objfile): Clear exec field.
* solib.c (clear_solib): Use first_exec instead of exec_bfd.
* source.c (select_source_symtab): Use ALL_OBJFILES_FOR_EXEC.
(find_source_lines): Use mtime from exec.
* symfile.c (syms_from_objfile): Don't clear objfile if multiple
execs.
(new_symfile_objfile): Get objfile's exec from last_exec_created.
(symbol_file_clear): Rephrase messages.
(reread_symbols): Update objfile's exec if necessary.
* symmisc.c (dump_objfile): Dump objfile's exec also.
(maintenance_print_objfiles): Report symfile_objfile.
* symtab.h (struct symtab_and_line): Add address space field.
* symtab.c (find_pc_sect_psymtab): Look for a plausible exec, and
then use it.
(lookup_symbol_aux_symtabs): Use current exec.
(lookup_symbol_aux_symtabs): Ditto.
(basic_lookup_transparent_type): Ditto.
(find_pc_sect_symtab): Ditto.
* target.h (print_section_info): Add arg to decl.
* tui/tui-win.c: Rename "focus" command to "ffocus".
gdb/testsuite:
2008-11-20 Stan Shebs <stan@codesourcery.com>
2008-09-14 Stan Shebs <stan@codesourcery.com>
* gdb.gdb/selftest.exp: Update to reflect current sources.
* Makefile.in (ALL_SUBDIRS): Add gdb.multi.
* configure.ac (AC_OUTPUT): Add gdb.multi/Makefile.
* configure: Regenerate.
* gdb.multi/Makefile.in: New.
* gdb.multi/hello.c, hangout.c, goodbye.c: New source files.
* gdb.multi/base.exp: New file, basic multiprocess tests.
2008-08-25 Stan Shebs <stan@codesourcery.com>
* config/monitor.exp: Match on rephrased message.
* gdb.base/attach.exp: Ditto.
* gdb.base/default.exp: Ditto.
* lib/gdb.exp: Ditto.
+2008-11-20 Stan Shebs <stan@codesourcery.com>
+
+ Multi-process (primarily multi-exec) support.
+
+ 2008-10-14 Stan Shebs <stan@codesourcery.com>
+
+ * blockframe.c (get_frame_block): Get inferior from frame.
+ * block.c (block_for_pc_inf): New function.
+ * block.h (block_for_pc_inf): Declare.
+ * symfile.c (find_pc_inf_sect): New function.
+ * symfile.h (find_pc_inf_sect): Declare.
+ * symtab.c (find_pc_inf_line): New function.
+ * symtab.h (find_pc_inf_line): Declare.
+ * frame.c (struct frame_info) New field inferior.
+ (fprint_frame_id): Display inferior.
+ (get_frame_id): Set inferior_num from inferior.
+ (frame_id_eq): Compare inferiors.
+ (create_sentinel_frame): Set inferior.
+ (create_new_frame): Copy inferior from sentinel.
+ (get_prev_frame_raw): Copy inferior from next frame.
+ (find_frame_sal): Use find_pc_inf_line.
+ (get_frame_inferior): New function.
+ * frame.h (struct frame_id): New field inferior_num.
+
+ * breakpoint.c (expand_sals_by_inferiors): Copy section from input
+ sal to expanded sals.
+ * symtab.c (expand_line_sal): Ditto.
+
+ 2008-10-10 Stan Shebs <stan@codesourcery.com>
+
+ * remote.c (discard_pending_stop_replies): Initialize prev.
+ * infrun.c (infrun_thread_stop_requested): Ditto.
+
+ 2008-10-08 Stan Shebs <stan@codesourcery.com>
+
+ * inferior.h (struct inferior): Rename environ field to inf_environ.
+ * inferior.c (print_inferior): Ditto.
+
+ 2008-10-01 Stan Shebs <stan@codesourcery.com>
+
+ * inferior.h (detach_fork): Declare here...
+ * linux-fork.h (detach_fork): ...instead of here.
+ * linux-fork.c (detach_fork): Move to...
+ * infrun.c (detach_fork): ...here.
+ * remote.c (detach_fork): Remove decl.
+
+ 2008-09-30 Stan Shebs <stan@codesourcery.com>
+
+ * linespec.c (decode_line_1): Better default for one-exec case.
+ * remote (remote_start_remote): Use the exec in the one-exec case.
+
+ 2008-09-29 Stan Shebs <stan@codesourcery.com>
+
+ * infcmd.c (attach_command): If only one exec, assume it is the
+ attached inferior's exec.
+ (attach_command_post_wait): Set inferior's exec from
+ the one that was found.
+ * inf-ptrace.c (inf_ptrace_attach): Only report exec file if
+ if there is just one present.
+ (inf_ptrace_detach): Use inferior to get correct exec name.
+
+ 2008-09-29 Stan Shebs <stan@codesourcery.com>
+
+ * inferior.c (print_inferior): Use exec short names, and drop
+ unused address space display.
+
+ 2008-09-26 Stan Shebs <stan@codesourcery.com>
+
+ * breakpoint.c (should_be_inserted): Test for no inferior.
+ (clone_breakpoint_location): New function, broken out from...
+ (update_breakpoint_inferiors): ...here, also tweak conditions
+ for adding a location.
+ (insert_breakpoint_location): Don't count non-running inferiors.
+ (remove_breakpoint): Set tmp_inf.
+ (print_one_breakpoint_location): Add allflag arg, use to always
+ show inf.
+ (print_one_breakpoint): Add allflag arg.
+ (do_captured_breakpoint_query): Fix caller.
+ (breakpoint_1): Ditto.
+ * exec.c (create_exec): Save full pathname as exec name.
+ (find_exec_by_name): Use find_exec_by_substr.
+ * fork-child.c (fork_inferior): Warn if exec not found for new
+ inferior.
+
+ 2008-09-25 Stan Shebs <stan@codesourcery.com>
+
+ * breakpoint.c (should_be_inserted): Don't insert in inferiors
+ that are not running.
+ (update_breakpoint_inferiors): New function.
+ (insert_breakpoints): Call it.
+ (insert_breakpoint_locations): Don't insert in inferiors that are
+ not running.
+ (set_raw_breakpoint_without_location): Set trigger set from
+ current itset here...
+ (set_raw_breakpoint): Instead of here. Also add default fillins
+ for the location's inferior.
+ (add_location_to_breakpoint): Similarly.
+ (expand_sals_by_inferiors): New function.
+ (breakpoint_re_set_one): Call it.
+ (resolve_sal_pc): Don't set sal inferior.
+ * breakpoint.h (struct breakpoint): Remove exec field, never used.
+ * inferior.h (inferior_list): Declare.
+ * inferior.c (inferior_list): Make public.
+ (add_inferior_to_itset): Auto-add inferiors after exec's inferior.
+ (first_inferior_in_set): Check for zero-length vector.
+ * exec.c (xfer_memory): Use tmp_inf as inferior if set.
+ * infcmd.c (focus_command): Improve user feedback.
+ * linespec.c (build_canonical_line_spec): Record exec name as part
+ of canonical spec.
+ (symbol_found): Canonicalize specs more.
+ (decode_indirect): Revert rewrite from 2008-09-14.
+ (decode_sharp): Use find_exec_by_substr, better error messages.
+ * minsyms.c (lookup_minimal_symbol_in_exec): New function.
+ (lookup_minimal_symbol_in_exec_1): New function, body of
+ lookup_minimal_symbol.
+ * symtab.h (lookup_minimal_symbol_in_exec): Declare.
+ * symtab.c (find_function_start_sal): Set inferior to use.
+ (append_expanded_sal): Return pointer to the new sal.
+ * remote.c (remote_xfer_memory): Better parms to ptid_build, remove
+ debug print.
+ (remote_xfer_partial): Ditto.
+
+ 2008-09-22 Pedro Alves <pedro@codesourcery.com>
+
+ * inferior.c (itset_member): Fix typo.
+
+ 2008-09-22 Stan Shebs <stan@codesourcery.com>
+
+ * inferior.h (current_inf): Remove declaration.
+ (tmp_inf): Declare.
+ * inferior.c (current_inf): Remove.
+ (tmp_inf): New global, hack to bypass passing inferior throughout
+ target stack.
+ (print_inferior): Don't report current_inf.
+ (add_inferior_command): Don't use current_inf.
+ (name_inferior_command): Use first inferior of current_itset.
+ (update_itset): Handle NULL case.
+ (add_inferior_itset): Recursively add all inferiors derived from
+ an exec if the exec's own inferior is present.
+ (first_inferior_in_set): New function.
+ (free_inferior): Comment out until references cleared reliably.
+ * infcmd.c (focus_command): Don't set current_inf.
+ (get_inferior_args): Use first_inferior_in_set instead of
+ current_inf.
+ (set_inferior_args): Ditto.
+ (set_inferior_args_vector): Ditto.
+ (notice_args_set): Ditto.
+ * breakpoint.c (insert_breakpoint_locations): Remove insertion test
+ using current_inf, set tmp_inf.
+ (reattach_breakpoints): Set tmp_inf.
+ (bpstat_check_breakpoint_conditions): Test trigger set here...
+ (bpstat_stop_status): ... instead of here.
+ (bpstat_check_trigger_set): Add special case for exec's own
+ inferior.
+ (print_one_breakpoint_location): Also test for multiple inferiors
+ before displaying location's inferior, flag trigger set with "i/t"
+ instead of "focus".
+ (check_duplicates): Pass location's inferior to...
+ (check_duplicates_for): Add inferior arg and use.
+ (set_raw_breakpoint): Override sal inferior with one from the
+ trigger set.
+ (add_location_to_breakpoint): Ditto.
+ * remote.c (remote_xfer_memory): Switch inferiors if tmp_inf is
+ set to something different from inferior_ptid.
+ (remote_xfer_partial): Ditto.
+ * top.c (execute_command): Always update the current itset.
+
+ 2008-09-19 Stan Shebs <stan@codesourcery.com>
+
+ * inferior.c (set_inferior_exec): New function.
+ (set_inferior_exec_command): New command.
+ * inferior.h: Declare set_inferior_exec.
+ * fork-child.c (fork_inferior): Set the inferior's exec.
+ * remote.c (extended_remote_create_inferior_1): Ditto.
+ gdb/doc/
+ * gdb.texinfo (Debugging Multiple Programs): Describe set-exec.
+
+ 2008-09-18 Stan Shebs <stan@codesourcery.com>
+
+ * target.c (target_resize_to_sections): Adjust execs' section
+ tables too.
+
+ 2008-09-17 Stan Shebs <stan@codesourcery.com>
+
+ gdb/doc/
+ * gdb.texinfo (Invoking GDB): Describe multiple program args.
+ (File Options): Describe multi-program effects.
+ (Multiple Programs): New section, multi-program debugging.
+ (Forks): Rename section from "Processes".
+ (Specify Location): Describe the #-syntax.
+ (Variables): Describe the #-syntax.
+ (Files): Describe add-file and add-exec-file.
+ (Maintenance Commands): Describe maint print execs.
+
+ 2008-09-15 Stan Shebs <stan@codesourcery.com>
+
+ * exec.c (addr_space_info_command): Don't try to display host address.
+
+ 2008-09-14 Stan Shebs <stan@codesourcery.com>
+
+ * c-exp.y: (yylex): Accept '#' in identifiers.
+ * linespec.c (decode_sharp): New function.
+ (decode_line_1): Use it for #-syntax.
+ (decode_indirect): Rewrite to accept exec arg and iterate over
+ inferiors.
+ (struct d_i_data): New struct for inferior iteration.
+ (decode_indirect_callback): New function.
+ (decode_variable): Pass in exec, use in symbol lookup.
+
+ 2008-09-14 Stan Shebs <stan@codesourcery.com>
+
+ * breakpoint.h (struct bp_location): Add inferior field instead
+ of address space field.
+ * breakpoint.c (insert_breakpoint_locations): Only insert in
+ appropriate inferior.
+ (bpstat_check_trigger_set): New function.
+ (bpstat_stop_status): Call it, check location's inferior also.
+ (print_one_breakpoint_location): Report location's inferior.
+ (set_raw_breakpoint): Set location inferior, clear an experiment.
+ (add_location_to_breakpoint): Ditto.
+ (expand_line_sal_maybe): Check for non-NULL original function.
+ (resolve_sal_pc): Set sal inferior.
+ (clear_command): Be careful to not clear anything twice.
+ * symtab.h: Update declarations of symbol lookups.
+ (struct symtab_and_line): Change address space to inferior field.
+ * symtab.c (init_sal): Clear inferior field.
+ (append_expanded_sal): Set inferior.
+ (lookup_symbol_in_language_1): New function.
+ (lookup_symbol_in_language): Call it.
+ (lookup_symbol_in_exec_in_language): New function.
+ (lookup_symbol): Detect #-syntax and find exec to use.
+ (lookup_symbol_aux): Add exec argument and use it.
+ (lookup_symbol_aux_symtabs): Ditto.
+ (lookup_symbol_aux_psymtabs): Ditto.
+ (basic_lookup_symbol_nonlocal): Ditto.
+ (lookup_symbol_static): Ditto.
+ (lookup_symbol_global): Ditto.
+ * ada-lang.c (cp_lookup_symbol_nonlocal): Ditto.
+ * cp-support.h (cp_lookup_symbol_nonlocal): Ditto.
+ * cp-namespace.c (cp_lookup_symbol_nonlocal): Ditto.
+ * language.h (struct language_defn): Ditto.
+ * scm-valprint.c (scm_inferior_print): Add exec arg to
+ lookup_symbol_global.
+ * source.c (select_source_symtab): Use current_exec.
+ * addrspace.h (struct addr_space): New field num.
+ * exec.h (struct exec): New fields sections and sections_end.
+ * exec.c (exec_file_attach_1): Set them from exec_ops, set
+ inferior's address space name from exec.
+ (find_exec_by_substr): New function.
+ (build_section_table): Don't free old table.
+ (print_section_info): Use exec's section table.
+ (next_address_space_num): New global, numbering for address spaces.
+ (new_address_space): Use it.
+ (addr_space_info_command): Display it.
+ * infcmd.c (set_current_exec): Set exec_ops section table.
+ * inferior.h (update_itset): Declare.
+ * inferior.c (add_inferior_silent): Set address space.
+ (print_inferior): Display it.
+ (number_of_inferiors): New function.
+ (itset_member): New function.
+
+ 2008-09-04 Stan Shebs <stan@codesourcery.com>
+
+ * corefile.c (close_exec_file): Remove #if 0 block.
+ (validate_files): Use first_exec instead of exec_bfd.
+ (get_exec_file): Ditto.
+ * corelow.c (core_open): Ditto.
+ * utils.c (string_to_core_addr): Ditto.
+ * arch-utils.c (gdbarch_update_p): Ditto.
+ * linux-thread-db.c (enable_thread_event): Ditto.
+ (thread_db_get_thread_local_address ): Ditto.
+ * exec.c (find_exec_by_name): Test short name also.
+ (file_command): Set current exec.
+
+ 2008-09-03 Stan Shebs <stan@codesourcery.com>
+
+ * inferior.c (add_threads_to_itset): Default to including all
+ of an inferior's threads.
+
+ 2008-08-31 Stan Shebs <stan@codesourcery.com>
+
+ Parsing for i/t sets.
+ * inferior.h (struct itset_entry): New struct.
+ (struct itset): Make thread lists be per-inferior, add parse state
+ variables.
+ * inferior.c: (add_inferior_command): Add error checking and
+ confirmation.
+ (remove_inferior_command): Update for itset restructuring.
+ (new_itset): Don't pass in dynamic-ness, call parse_itset_spec.
+ (update_itset): Similarly.
+ (parse_itset_spec): New, parsing of itset spec.
+ (parse_itset_list, parse_itset_range, etc): New.
+ (make_itset_from_spec): Rewrite.
+ (dump_itset): Rewrite to reflect itset structure.
+ * infcmd.c (focus_command): Similarly.
+
+ 2008-08-25 Stan Shebs <stan@codesourcery.com>
+
+ First part of multiprocess support.
+ * Makefile.in (COMMON_OBS): Add inferior.o.
+ * addrspace.h: New file.
+ * breakpoints.h (struct bp_location): Add address space field.
+ (struct breakpoint): Add trigger set and exec fields.
+ * breakpoints.c (print_one_breakpoint_location): Display trigger
+ set.
+ (set_raw_breakpoint): Set trigger set from current itset.
+ * corefile.c (reopen_exec_file): Rewrite for multiple execs.
+ (get_exec_file): Add case for current_exec.
+ * corelow.c (is_core_file): New function.
+ (core_files_info): Pass additional arg to print_section_info.
+ * exec.h (struct exec): New struct.
+ * exec.c (execs): New global.
+ (exec_bfd_mtime): Remove.
+ (last_exec_created, current_exec, first_exec): New globals.
+ (exec_close): Clear all exec objects.
+ (exec_file_clear): Tweak user message.
+ (exec_file_add): New function.
+ (exec_file_attach_1): New function, body of exec_file_attach,
+ plus new code to handle multiple execs.
+ (exec_file_attach): Call it.
+ (exec_file_update): New function.
+ (create_exec, find_exec_by_name, number_of_execs): New functions.
+ (exec_file_command): Rephrase query, set current exec.
+ (add_exec_file_command): New command.
+ (add_file_command): New command.
+ (print_section_info): Add exec argument.
+ (exec_files_info): Rewrite for multiple execs.
+ (maintenance_print_execs): New function.
+ (new_address_space): New function.
+ (addr_space_info_command): New command.
+ * gdbcore.h (exec_bfd_mtime): Remove decl.
+ (exec_file_add): Declare.
+ * infcmd.c: Include exec.h.
+ (current_itset): New global.
+ (set_current_exec): New function.
+ (focus_command): New command.
+ (get_inferior_args): Maybe get from the current inferior.
+ (set_inferior_args): Also set in current inferior.
+ (set_inferior_args_vector): Similarly.
+ (notice_args_set): Similarly.
+ (attach_command): Rephrase query.
+ * inferior.h (struct inferior): New struct.
+ (struct itset): New struct.
+ * inferior.c: New file, management of multiple inferiors.
+ * main.c (captured_main): Rewrite to allow multiple executables,
+ pids, and corefiles on the command line.
+ * maint.c (maintenance_info_sections): Rewrite for multiple execs.
+ * objfiles.h (struct objfile): New field for exec.
+ (ALL_OBJFILES_FOR_EXEC, ALL_PRIMARY_SYMTABS_FOR_EXEC,
+ ALL_PSYMTABS_FOR_EXEC): New macros.
+ * objfiles.c (allocate_objfile): Clear exec field.
+ * solib.c (clear_solib): Use first_exec instead of exec_bfd.
+ * source.c (select_source_symtab): Use ALL_OBJFILES_FOR_EXEC.
+ (find_source_lines): Use mtime from exec.
+ * symfile.c (syms_from_objfile): Don't clear objfile if multiple
+ execs.
+ (new_symfile_objfile): Get objfile's exec from last_exec_created.
+ (symbol_file_clear): Rephrase messages.
+ (reread_symbols): Update objfile's exec if necessary.
+ * symmisc.c (dump_objfile): Dump objfile's exec also.
+ (maintenance_print_objfiles): Report symfile_objfile.
+ * symtab.h (struct symtab_and_line): Add address space field.
+ * symtab.c (find_pc_sect_psymtab): Look for a plausible exec, and
+ then use it.
+ (lookup_symbol_aux_symtabs): Use current exec.
+ (lookup_symbol_aux_symtabs): Ditto.
+ (basic_lookup_transparent_type): Ditto.
+ (find_pc_sect_symtab): Ditto.
+ * target.h (print_section_info): Add arg to decl.
+ * tui/tui-win.c: Rename "focus" command to "ffocus".
+
2008-11-19 Doug Evans <dje@google.com>
* inferior.h (proceed_to_finish): Delete, unused.
ada_lookup_symbol_nonlocal (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain)
{
if (linkage_name == NULL)
#include "arch-utils.h"
#include "buildsym.h"
#include "gdbcmd.h"
+#include "exec.h"
#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
#include "gdb_string.h"
#include "regcache.h"
struct gdbarch *new_gdbarch;
/* Check for the current file. */
- if (info.abfd == NULL)
- info.abfd = exec_bfd;
+ if (info.abfd == NULL && first_exec && first_exec->ebfd)
+ info.abfd = first_exec->ebfd;
if (info.abfd == NULL)
info.abfd = core_bfd;
pblock, NULL);
}
+/* Given a pc and an inferior, find the block. */
+
+struct block *
+block_for_pc_inf (CORE_ADDR pc, struct inferior *inf)
+{
+ struct blockvector *bl;
+ struct block *b;
+ struct obj_section *section;
+
+ section = find_pc_inf_sect (pc, inf);
+ bl = blockvector_for_pc_sect (pc, section, &b, NULL);
+ if (bl)
+ return b;
+ return 0;
+}
+
/* Return the innermost lexical block containing the specified pc value
in the specified section, or 0 if there is none. */
struct obstack;
struct dictionary;
struct addrmap;
+struct inferior;
/* All of the name-scope contours of the program
are represented by `struct block' objects.
extern struct block *block_for_pc_sect (CORE_ADDR, struct obj_section *);
+extern struct block *block_for_pc_inf (CORE_ADDR, struct inferior *);
+
extern const char *block_scope (const struct block *block);
extern void block_set_scope (struct block *block, const char *scope,
struct block *
get_frame_block (struct frame_info *frame, CORE_ADDR *addr_in_block)
{
+ struct inferior *inf = get_frame_inferior (frame);
const CORE_ADDR pc = get_frame_address_in_block (frame);
if (addr_in_block)
*addr_in_block = pc;
- return block_for_pc (pc);
+ return block_for_pc_inf (pc, inf);
}
CORE_ADDR
#include "gdb_string.h"
#include "demangle.h"
#include "annotate.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "source.h"
#include "mi/mi-common.h"
+static int
+bpstat_check_trigger_set (const struct bp_location *bl, struct inferior *inf,
+ int thread_id);
+
/* Arguments to pass as context to some catch command handlers. */
#define CATCH_PERMANENT ((void *) (uintptr_t) 0)
#define CATCH_TEMPORARY ((void *) (uintptr_t) 1)
struct frame_id saved_frame_id;
struct bp_location *loc;
bpstat bs;
+ struct inferior *inf;
/* We don't free locations. They are stored in
bp_location_chain and update_global_locations will
select_frame (fi);
}
+ inf = get_frame_inferior (get_selected_frame (NULL));
+
if (within_current_scope && reparse)
{
char *s;
for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
;
*tmp = loc;
+ loc->inferior = inf;
loc->address = addr;
loc->length = len;
loc->watchpoint_type = type;
if (!bpt->enabled || bpt->shlib_disabled || bpt->duplicate)
return 0;
+ if (!bpt->inferior || (bpt->inferior && bpt->inferior->pid == 0))
+ return 0;
+
return 1;
}
return 0;
}
+/* Given a location, create and add another location differing only in
+ the inferior. */
+
+void
+clone_breakpoint_location (struct breakpoint *b, struct bp_location *loc,
+ struct inferior *inf)
+{
+ struct bp_location *new_loc, **tmp;
+ struct gdb_exception e;
+
+ new_loc = allocate_bp_location (b, b->type);
+ for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
+ ;
+ *tmp = new_loc;
+ new_loc->requested_address = loc->requested_address;
+ new_loc->address = loc->address;
+ new_loc->length = loc->length;
+ new_loc->inferior = inf;
+ if (b->cond_string)
+ {
+ char *s = b->cond_string;
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ new_loc->cond = parse_exp_1 (&s, block_for_pc_inf (new_loc->address,
+ inf), 0);
+ }
+ if (e.reason < 0)
+ {
+ }
+ }
+ /* Permanent breakpoints will be inserted in every inferior created
+ from the same exec. */
+ if (b->enable_state == bp_permanent)
+ new_loc->inserted = loc->inserted;
+}
+
+/* For the given breakpoint, look for any inferiors that might have
+ appeared and need a breakpoint location to be inserted. */
+
+void
+update_breakpoint_inferiors (struct breakpoint *b)
+{
+ struct bp_location *loc, *loc2;
+ struct inferior *inf;
+
+ update_itset (b->trigger_set);
+
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ if (loc->inferior == NULL
+ || (loc->inferior
+ && loc->inferior->exec
+ && loc->inferior->exec->inferior == loc->inferior))
+ {
+ for (inf = inferior_list; inf; inf = inf->next)
+ {
+ if ((loc->inferior == NULL
+ || inf->exec == loc->inferior->exec)
+ && inf->pid != 0)
+ {
+ int found = 0;
+ for (loc2 = b->loc; loc2; loc2 = loc2->next)
+ {
+ if (inf == loc2->inferior)
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ clone_breakpoint_location (b, loc, inf);
+ }
+ }
+ }
+ }
+}
+
/* Make sure all breakpoints are inserted in inferior.
Throws exception on any error.
A breakpoint that is already inserted won't be inserted
struct breakpoint *bpt;
ALL_BREAKPOINTS (bpt)
+ {
+ update_breakpoint_inferiors (bpt);
+
if (is_hardware_watchpoint (bpt))
update_watchpoint (bpt, 0 /* don't reparse. */);
+ }
update_global_location_list (1);
&& !valid_thread_id (b->owner->thread))
continue;
+ /* Only insert into running inferiors. */
+ if (!b->inferior || b->inferior->pid == 0)
+ continue;
+
+ /* Nasty hack to smuggle the location's inferior down to target bits. */
+ tmp_inf = b->inferior;
val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks, &process_warning,
&hw_breakpoint_error);
+ tmp_inf = NULL;
+
if (val)
error = val;
}
continue;
for (loc = bpt->loc; loc; loc = loc->next)
- if (!loc->inserted)
+ if (!loc->inserted
+ && !(loc->inferior == NULL
+ || (loc->inferior && loc->inferior->pid == 0)))
{
some_failed = 1;
break;
if (b->inserted)
{
b->inserted = 0;
+ /* Nasty hack to smuggle the location's inferior down to
+ target bits. */
+ tmp_inf = b->inferior;
val = insert_bp_location (b, tmp_error_stream,
&dummy1, &dummy2, &dummy3);
+ tmp_inf = NULL;
if (val != 0)
{
do_cleanups (old_chain);
This should not ever happen. */
gdb_assert (b->owner->type != bp_none);
+ /* Nasty hack to smuggle the location's inferior down to target. */
+ tmp_inf = b->inferior;
+
if (b->loc_type == bp_loc_software_breakpoint
|| b->loc_type == bp_loc_hardware_breakpoint)
{
b->inserted = (is == mark_inserted);
}
+ tmp_inf = NULL;
return 0;
}
}
-/* Check conditions (condition proper, frame, thread and ignore count)
- of breakpoint referred to by BS. If we should not stop for this
- breakpoint, set BS->stop to 0. */
+/* Check conditions (condition proper, frame, thread, ignore count,
+ and trigger set) of breakpoint referred to by BS. If we should not
+ stop for this breakpoint, set BS->stop to 0. */
static void
bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
{
{
bs->stop = 0;
}
+ else if (b->trigger_set
+ && !bpstat_check_trigger_set (bl,
+ find_inferior_pid (ptid_get_pid (ptid)),
+ pid_to_thread_id (ptid)))
+ {
+ bs->stop = 0;
+ }
else if (b->ignore_count > 0)
{
b->ignore_count--;
}
}
+/* Test whether this stopping inferior and thread are in the i/t set
+ for this breakpoint. */
+
+static int
+bpstat_check_trigger_set (const struct bp_location *bl, struct inferior *inf,
+ int thread_id)
+{
+ struct breakpoint *b = bl->owner;
+
+ if (!b->trigger_set)
+ return 1;
+
+ update_itset (b->trigger_set);
+
+ if (itset_member (b->trigger_set, inf, thread_id))
+ return 1;
+
+ /* Stop if the location points to the exec's own inferior, and the inferior
+ here was launched from that exec. */
+ if (bl->inferior
+ && bl->inferior->exec
+ && bl->inferior->exec->inferior == bl->inferior
+ && inf->exec == bl->inferior->exec)
+ return 1;
+
+ return 0;
+}
/* Get a bpstat associated with having just stopped at address
BP_ADDR in thread PTID.
if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
continue;
+ /* Any location that is somehow not connected with a running
+ inferior cannot possibly cause a stop. */
+ if (!bl->inferior || bl->inferior->pid == 0)
+ continue;
+
/* For hardware watchpoints, we look only at the first location.
The watchpoint_check function will work on entire expression,
not the individual locations. For read watchopints, the
print_one_breakpoint_location (struct breakpoint *b,
struct bp_location *loc,
int loc_number,
- CORE_ADDR *last_addr)
+ CORE_ADDR *last_addr, int allflag)
{
struct command_line *l;
struct symbol *sym;
if (b->ops != NULL && b->ops->print_one != NULL)
{
- /* Although the print_one can possibly print
- all locations, calling it here is not likely
- to get any nice result. So, make sure there's
- just one location. */
- gdb_assert (b->loc == NULL || b->loc->next == NULL);
+ /* FIXME make this work right for multiple inferiors etc */
b->ops->print_one (b, last_addr);
}
else
break;
}
+ /* For backward compatibility, don't display inferiors unless there
+ are several. */
+ if (number_of_execs () > 1 || number_of_inferiors () > 2 || allflag)
+ {
+ ui_out_text (uiout, " inf ");
+ ui_out_field_int (uiout, "inf",
+ ((loc && loc->inferior) ? loc->inferior->num : 0));
+ }
+
if (!part_of_multiple && b->thread != -1)
{
/* FIXME: This seems to be redundant and lost here; see the
ui_out_field_int (uiout, "thread", b->thread);
}
+ if (!part_of_multiple && b->trigger_set)
+ {
+ ui_out_text (uiout, " i/t [");
+ ui_out_field_string (uiout, "i/t", b->trigger_set->spec);
+ ui_out_text (uiout, "]");
+ }
+
ui_out_text (uiout, "\n");
if (part_of_multiple && frame_id_p (b->frame_id))
static void
print_one_breakpoint (struct breakpoint *b,
- CORE_ADDR *last_addr)
+ CORE_ADDR *last_addr, int allflag)
{
- print_one_breakpoint_location (b, NULL, 0, last_addr);
+ print_one_breakpoint_location (b, NULL, 0, last_addr, allflag);
/* If this breakpoint has custom print function,
it's already printed. Otherwise, print individual
struct bp_location *loc;
int n = 1;
for (loc = b->loc; loc; loc = loc->next, ++n)
- print_one_breakpoint_location (b, loc, n, last_addr);
+ print_one_breakpoint_location (b, loc, n, last_addr, allflag);
}
}
}
{
if (args->bnum == b->number)
{
- print_one_breakpoint (b, &dummy_addr);
+ print_one_breakpoint (b, &dummy_addr, 0);
return GDB_RC_OK;
}
}
/* We only print out user settable breakpoints unless the
allflag is set. */
if (allflag || user_settable_breakpoint (b))
- print_one_breakpoint (b, &last_addr);
+ print_one_breakpoint (b, &last_addr, allflag);
}
do_cleanups (bkpttbl_chain);
that one the official one, and the rest as duplicates. */
static void
-check_duplicates_for (CORE_ADDR address, struct obj_section *section)
+check_duplicates_for (CORE_ADDR address, struct inferior *inf, struct obj_section *section)
{
struct bp_location *b;
int count = 0;
&& b->enabled
&& !b->shlib_disabled
&& b->address == address /* address / overlay match */
+ && b->inferior == inf
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b->owner))
{
&& b->owner->enable_state != bp_call_disabled
&& b->enabled && !b->shlib_disabled
&& b->address == address /* address / overlay match */
+ && b->inferior == inf
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b->owner))
{
return;
for (; bl; bl = bl->next)
- check_duplicates_for (bl->address, bl->section);
+ check_duplicates_for (bl->address, bl->inferior, bl->section);
}
static void
b->language = current_language->la_language;
b->input_radix = input_radix;
b->thread = -1;
+ b->trigger_set = current_itset;
b->enable_state = bp_enabled;
b->next = 0;
b->silent = 0;
{
struct breakpoint *b = set_raw_breakpoint_without_location (bptype);
CORE_ADDR adjusted_address;
+ struct inferior *inf;
/* Adjust the breakpoint's address prior to allocating a location.
Once we call allocate_bp_location(), that mostly uninitialized
b->loc = allocate_bp_location (b, bptype);
b->loc->requested_address = sal.pc;
b->loc->address = adjusted_address;
+ b->loc->inferior = sal.inferior;
+
+ /* Find an inferior in the trigger set. */
+ if (!b->loc->inferior)
+ b->loc->inferior = first_inferior_in_set (b->trigger_set);
+
+ /* Find an inferior from the sal's symtab. */
+ if (!b->loc->inferior
+ && sal.symtab
+ && sal.symtab->objfile
+ && sal.symtab->objfile->exec)
+ b->loc->inferior = sal.symtab->objfile->exec->inferior;
if (sal.symtab == NULL)
b->source_file = NULL;
const struct symtab_and_line *sal)
{
struct bp_location *loc, **tmp;
+ struct inferior *inf;
loc = allocate_bp_location (b, bptype);
for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
loc->requested_address = sal->pc;
loc->address = adjust_breakpoint_address (loc->requested_address,
bptype);
+ loc->inferior = sal->inferior;
+
+ /* Find an inferior in the trigger set. */
+ if (!loc->inferior)
+ loc->inferior = first_inferior_in_set (b->trigger_set);
+
+ /* Find an inferior from the sal's symtab. */
+ if (!loc->inferior
+ && sal->symtab
+ && sal->symtab->objfile
+ && sal->symtab->objfile->exec)
+ loc->inferior = sal->symtab->objfile->exec->inferior;
+
loc->section = sal->section;
set_breakpoint_location_function (loc);
if (find_pc_partial_function (pc, &this_function,
&func_addr, &func_end))
{
- if (this_function &&
- strcmp (this_function, original_function) != 0)
+ if (this_function
+ && original_function
+ && strcmp (this_function, original_function) != 0)
{
remove_sal (&expanded, i);
--i;
return expanded;
}
+extern /*static*/ struct symtab_and_line *
+append_expanded_sal (struct symtabs_and_lines *sal,
+ struct symtab *symtab,
+ int lineno, CORE_ADDR pc);
+
+struct symtabs_and_lines
+expand_sals_by_inferiors (struct symtabs_and_lines sals)
+{
+ struct symtabs_and_lines expanded;
+ struct symtab_and_line sal, *new_sal;
+ struct inferior *sal_inf, *inf;
+ int i;
+
+ expanded.nelts = 0;
+ expanded.sals = NULL;
+
+ for (i = 0; i < sals.nelts; ++i)
+ {
+ sal = sals.sals[i];
+ append_expanded_sal (&expanded, sal.symtab, sal.line, sal.pc);
+ expanded.sals[expanded.nelts-1].section = sal.section;
+ sal_inf = sal.inferior;
+ if (!sal_inf
+ && sal.symtab
+ && sal.symtab->objfile
+ && sal.symtab->objfile->exec)
+ sal_inf = sal.symtab->objfile->exec->inferior;
+ if (sal_inf)
+ {
+ for (inf = inferior_list; inf; inf = inf->next)
+ {
+ if (inf->exec == sal_inf->exec && inf->pid != 0)
+ {
+ new_sal = append_expanded_sal (&expanded, sal.symtab, sal.line, sal.pc);
+ new_sal->section = sal.section;
+ new_sal->inferior = inf;
+ }
+ }
+ }
+ }
+
+ return expanded;
+}
+
/* Add SALS.nelts breakpoints to the breakpoint table. For each
SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
value. COND_STRING, if not NULL, specified the condition to be
}
if (match)
- VEC_safe_push(breakpoint_p, found, b);
+ {
+ struct breakpoint *b2;
+ int already_there = 0;
+ for (ix = 0; VEC_iterate(breakpoint_p, found, ix, b2); ix++)
+ {
+ if (b2 == b)
+ {
+ already_there = 1;
+ break;
+ }
+ }
+ if (!already_there)
+ VEC_safe_push(breakpoint_p, found, b);
+ }
}
}
/* Now go thru the 'found' chain and delete them. */
b->condition_not_parsed = 0;
}
expanded = expand_line_sal_maybe (sals.sals[0]);
+ expanded = expand_sals_by_inferiors (expanded);
update_breakpoint_locations (b, expanded);
xfree (sals.sals);
struct value;
struct block;
+struct exec;
+struct itset;
/* This is the maximum number of bytes a breakpoint instruction can take.
Feel free to increase it. It's just used in a few places to size
than reference counting. */
struct breakpoint *owner;
+ /* The inferior (process etc) of this location. */
+ struct inferior *inferior;
+
/* Conditional. Break only if this expression's value is nonzero.
Unlike string form of condition, which is associated with breakpoint,
this is associated with location, since if breakpoint has several
/* Thread number for thread-specific breakpoint, or -1 if don't care */
int thread;
+ /* Inferior/thread set controlling where this breakpoint will stop. */
+ struct itset *trigger_set;
+
/* Count of the number of times this breakpoint was taken, dumped
with the info, but not used for anything else. Useful for
seeing how many times you hit a break prior to the program
return (STRING);
}
- if (!(c == '_' || c == '$'
+ if (!(c == '_' || c == '$' || c == '#'
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
/* We must have come across a bad character (e.g. ';'). */
error ("Invalid character '%c' in expression.", c);
/* It's a name. See how long it is. */
namelen = 0;
for (c = tokstart[namelen];
- (c == '_' || c == '$' || (c >= '0' && c <= '9')
+ (c == '_' || c == '$' || c == '#' || (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');)
{
/* Template parameter lists are part of the name.
#include "gdbcmd.h"
#include "bfd.h"
#include "target.h"
+#include "exec.h"
#include "gdbcore.h"
#include "dis-asm.h"
#include "gdb_stat.h"
void
close_exec_file (void)
{
-#if 0 /* FIXME */
- if (exec_bfd)
- bfd_tempclose (exec_bfd);
-#endif
}
void
reopen_exec_file (void)
{
-#if 0 /* FIXME */
- if (exec_bfd)
- bfd_reopen (exec_bfd);
-#else
char *filename;
int res;
struct stat st;
- long mtime;
+ int ix;
+ struct exec *exec;
- /* Don't do anything if there isn't an exec file. */
- if (exec_bfd == NULL)
+ if (!execs)
return;
- /* If the timestamp of the exec file has changed, reopen it. */
- filename = xstrdup (bfd_get_filename (exec_bfd));
- make_cleanup (xfree, filename);
- res = stat (filename, &st);
-
- if (exec_bfd_mtime && exec_bfd_mtime != st.st_mtime)
- exec_file_attach (filename, 0);
- else
- /* If we accessed the file since last opening it, close it now;
- this stops GDB from holding the executable open after it
- exits. */
- bfd_cache_close_all ();
-#endif
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ {
+ /* If the timestamp of the exec file has changed, reopen it. */
+ filename = xstrdup (exec->name);
+ make_cleanup (xfree, filename);
+ res = stat (filename, &st);
+
+ if (exec->ebfd_mtime && exec->ebfd_mtime != st.st_mtime)
+ exec_file_update (exec);
+ else
+ /* If we accessed the file since last opening it, close it now;
+ this stops GDB from holding the executable open after it
+ exits. */
+ bfd_cache_close_all ();
+ }
}
\f
/* If we have both a core file and an exec file,
void
validate_files (void)
{
- if (exec_bfd && core_bfd)
+ if (first_exec && first_exec->ebfd && core_bfd)
{
- if (!core_file_matches_executable_p (core_bfd, exec_bfd))
+ if (!core_file_matches_executable_p (core_bfd, first_exec->ebfd))
warning (_("core file may not match specified executable file."));
- else if (bfd_get_mtime (exec_bfd) > bfd_get_mtime (core_bfd))
+ else if (bfd_get_mtime (first_exec->ebfd) > bfd_get_mtime (core_bfd))
warning (_("exec file is newer than core file."));
}
}
char *
get_exec_file (int err)
{
- if (exec_bfd)
- return bfd_get_filename (exec_bfd);
+ /* This function needs to go away, or return a list of execs, but in
+ the meantime, returning the filename from the current exec is a
+ minimal approximation. */
+ if (current_exec)
+ return bfd_get_filename (current_exec->ebfd);
+ if (first_exec && first_exec->ebfd)
+ return bfd_get_filename (first_exec->ebfd);
if (!err)
return NULL;
core_file_fns = cf;
}
+int
+is_core_file (char *filename)
+{
+ const char *p;
+ int siggy;
+ struct cleanup *old_chain;
+ char *temp;
+ bfd *temp_bfd;
+ int scratch_chan;
+ int flags;
+
+ if (!filename)
+ return 0;
+
+ filename = tilde_expand (filename);
+ if (!IS_ABSOLUTE_PATH(filename))
+ {
+ temp = concat (current_directory, "/", filename, (char *)NULL);
+ xfree (filename);
+ filename = temp;
+ }
+
+ old_chain = make_cleanup (xfree, filename);
+
+ flags = O_BINARY | O_LARGEFILE;
+ if (write_files)
+ flags |= O_RDWR;
+ else
+ flags |= O_RDONLY;
+ scratch_chan = open (filename, flags, 0);
+ if (scratch_chan < 0)
+ perror_with_name (filename);
+
+ temp_bfd = bfd_fopen (filename, gnutarget,
+ write_files ? FOPEN_RUB : FOPEN_RB,
+ scratch_chan);
+ if (temp_bfd == NULL)
+ perror_with_name (filename);
+
+ if (!bfd_check_format (temp_bfd, bfd_core) &&
+ !gdb_check_format (temp_bfd))
+ {
+ /* Do it after the err msg */
+ /* FIXME: should be checking for errors from bfd_close (for one thing,
+ on error it does not free all the storage associated with the
+ bfd). */
+ make_cleanup_bfd_close (temp_bfd);
+ return 0;
+ }
+
+ make_cleanup_bfd_close (temp_bfd);
+ return 1;
+}
+
/* The default function that core file handlers can use to examine a
core file BFD and decide whether or not to accept the job of
reading the core file. */
core file. We don't do this unconditionally since an exec file
typically contains more information that helps us determine the
architecture than a core file. */
- if (!exec_bfd)
+ if (!(first_exec && first_exec->ebfd))
set_gdbarch_from_file (core_bfd);
push_target (&core_ops);
static void
core_files_info (struct target_ops *t)
{
- print_section_info (t, core_bfd);
+ print_section_info (t, core_bfd, NULL);
}
\f
static LONGEST
cp_lookup_symbol_nonlocal (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain)
{
return lookup_namespace_scope (name, linkage_name, block, domain,
{
struct symbol *sym = NULL;
- sym = lookup_symbol_static (name, linkage_name, block, domain);
+ sym = lookup_symbol_static (name, linkage_name, block, NULL, domain);
if (sym != NULL)
return sym;
}
else
{
- sym = lookup_symbol_global (name, linkage_name, block, domain);
+ sym = lookup_symbol_global (name, linkage_name, block, NULL, domain);
}
if (sym != NULL)
struct objfile;
struct type;
struct demangle_component;
+struct exec;
/* This struct is designed to store data from using directives. It
says that names from namespace INNER should be visible within
extern struct symbol *cp_lookup_symbol_nonlocal (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain);
extern struct symbol *cp_lookup_symbol_namespace (const char *namespace,
This will cause @code{@value{GDBP}} to debug @code{gcc}, and to set
@code{gcc}'s command-line arguments (@pxref{Arguments}) to @samp{-O2 -c foo.c}.
+To debug several programs at the same time, you can supply several
+program names on the command line:
+
+@smallexample
+@value{GDBP} @var{program1} @var{program2} @var{program3}
+@end smallexample
+
+You can supply pids and corefiles as well; @value{GDBN} assumes each
+such argument applies to the program immediately preceding. So in this
+example:
+
+@smallexample
+@value{GDBP} @var{program1} @var{pid1} @var{program2} @var{program3} @var{pid3}
+@end smallexample
+
+@noindent
+attaches to processes with @var{pid1} and @var{pid3}, and also
+prepares to debug @var{program2}.
+
You can run @code{@value{GDBP}} without printing the front material, which describes
@value{GDBN}'s non-warranty, by specifying @code{-silent}:
@node File Options
@subsection Choosing Files
+@c reword the following to explain the multiprocess argument case better.
When @value{GDBN} starts, it reads any arguments other than options as
-specifying an executable file and core file (or process ID). This is
-the same as if the arguments were specified by the @samp{-se} and
+specifying executable files, core files, or process IDs. This is
+similar to if the arguments were specified by the @samp{-se} and
@samp{-c} (or @samp{-p}) options respectively. (@value{GDBN} reads the
first argument that does not have an associated option flag as
equivalent to the @samp{-se} option followed by that argument; and the
@itemx -s @var{file}
@cindex @code{--symbols}
@cindex @code{-s}
-Read symbol table from file @var{file}.
+Read symbol table from file @var{file}. This option overrides
+multiple files on the command line, replacing them with just this one
+file.
@item -exec @var{file}
@itemx -e @var{file}
@cindex @code{--exec}
@cindex @code{-e}
-Use file @var{file} as the executable file to execute when appropriate,
-and for examining pure data in conjunction with a core dump.
+Use file @var{file} as the executable file to execute when
+appropriate, and for examining pure data in conjunction with a core
+dump. This option overrides multiple files on the command line,
+replacing them with just this one file.
@item -se @var{file}
@cindex @code{--se}
Read symbol table from file @var{file} and use it as the executable
-file.
+file. This open overrides multiple files on the command line,
+replacing them with just the one file.
@item -core @var{file}
@itemx -c @var{file}
* Attach:: Debugging an already-running process
* Kill Process:: Killing the child process
-* Inferiors:: Debugging multiple inferiors
+* Multiple Programs:: Debugging multiple programs
* Threads:: Debugging programs with multiple threads
-* Processes:: Debugging programs with multiple processes
+* Forks:: Debugging forks
* Checkpoint/Restart:: Setting a @emph{bookmark} to return to later
@end menu
process continue running, you may use the @code{continue} command after
attaching @value{GDBN} to the process.
+@c how does attach know to add vs replace?
+
@table @code
@kindex detach
@item detach
@code{set confirm} command (@pxref{Messages/Warnings, ,Optional Warnings and
Messages}).
+In the multi-process case, @code{detach} detaches from all inferiors
+in the current i/t set.
+
@node Kill Process
@section Killing the Child Process
inferiors have started, exited or have been detached.
@end table
+In the multi-process case, @code{kill} kills all inferiors in the
+current i/t set.
+
+@node Multiple Programs
+@section Debugging Multiple Programs
+
+@value{GDBN} lets you run and debug multiple programs in a single
+session. In addition, @value{GDBN} on some systems may let you run
+several programs simultaneously (otherwise you have to exit from one
+before starting another). In the most general case, you can have
+multiple threads of execution in each of multiple processes, launched
+from multiple executables.
+
+You can get multiple executables into a debugging session by either
+supplying them as several arguments on @value{GDBN}'s command line, or
+via the @code{add-file} command.
+
+Many commands will work the same with multiple programs as with a
+single program: @code{print myglobal} will simply display the value of
+@code{myglobal}. However, if several of the programs have variables
+named @var{myglobal}, things can get very confusing, and it gets worse
+if multiple running processes have been launched from the same
+executable.
+
+@cindex inferior
+To keep everything straight, @value{GDBN} represents the state of each
+program execution with an object called an @dfn{inferior}. An inferior
+typically corresponds to a process, but is more general and applies
+also to targets that don't have processes. Inferiors may be created
+before a process runs, and may (in future) be retained after a process
+exits. Each run of an executable creates a new inferior, as does each
+attachment to an existing process. Inferiors have unique identifiers
+that are different from process ids, and may optionally be named as
+well. Usually each inferior will also have its own distinct address
+space, although some embedded targets may have several inferiors
+running in different parts of a single space.
+
+Each inferior may in turn have multiple threads running in it.
+
+@cindex inferior/thread set
+@cindex i/t set
+@cindex itset
+Since there may be very many inferiors, we introduce the
+@dfn{inferior/thread set}, also written as @dfn{i/t set} or
+@dfn{itset} for short. An i/t set consists of a set of inferiors, and
+for each inferior, a set of threads. Inferior/thread sets have a specification
+defining the members, normally delimited by square brackets (although
+the brackets may omitted in some contexts). The basic syntax takes the
+form @code{[@var{inf}.@var{thr}]}, where both @var{inf} and @var{thr}
+may be wildcarded with @code{*}, indicating that the set is to include
+all inferiors or all threads. In addition, the syntax includes
+provisions for ranges and unions, and special keywords for
+commonly-used sets.
+
+@cindex focus
+@cindex current i/t set
+One of the most important uses for i/t sets is to set the @dfn{focus},
+which is the i/t set to which commands apply by default:
+
+@table @code
+@kindex focus
+@item focus @var{i/t-set}
+Set the current focus to @var{i/t-set}. Subsequent commands will take
+this set as the collection of inferiors and/or threads on which to
+operate.
+@end table
+
+For instance, @code{focus hello} sets the focus to be on the program
+@code{hello}, while @code{focus 6} sets commands to use inferior 6 by
+default.
+
+Another way to refer to symbols or sources of a particular executable
+is to prefix them with the name of the executable, delimited with
+@code{#}-signs. For instance @code{#myprog#myglobal} is the version of
+the symbol @code{myglobal} in the executable @code{myprog}, and
+@code{#server#main.c:101} is line 101 of @file{main.c} in the program
+named @code{server}.
+
+@cindex create inferiors
+In many cases it will suffice to simply say @code{run} for each
+executable. But you may wish to prepare to run several inferiors all
+launched from the same executable. The commands @code{add-inferior}
+and @code{remove-inferior} let you manage the list of inferiors to be
+run.
+
+@table @code
+@kindex add-inferior
+@item add-inferior @var{exec} [ -copies @var{n} ] [ -name @var{basename} ]
+Adds @var{n} inferiors to be run using @var{exec} as the
+executable. @var{n} defaults to 1. The inferiors will be unnamed; to
+give them names, specify @var{basename}, which will be suffixed with
+consecutive numbers.
+
+@kindex remove-inferior
+@item remove-inferior @var{i/t-set}
+Removes any inferior belonging to @var{i/t-set}. The inferiors
+corresponding to executables will not be removed.
+
+@kindex name-inferior
+@item name-inferior @var{old-name-or-id} @var{new-name}
+Sets the name of the inferior found as @var{old-name-or-id} to @var{new-name}.
+
+@kindex set-exec
+@item set-exec @var{i/t-set} @var{exec}
+Sets the executable of every inferior in @var{i/t-set} to the one
+named by @var{exec}. @value{GDBN} is usually able to determine the
+executable used to start up an inferior, but in some situations (such
+as attaching to a process) there is no way to know for sure; use this
+command to set the executable correctly. The executable must have
+already been supplied to @value{GDBN}.
+
+@kindex info inferiors
+@item info inferiors
+Print a list of all inferiors currently being managed by @value{GDBN}.
+
+@end table
+
+One of the uses of explicit inferiors is to set different arguments
+for each of them before running. Commands such as @code{set args}
+apply to every inferior in the current i/t set, so one can do setups
+like this:
+
+@smallexample
+(@value{GDBP}) add-inferior myprog -copies 4 -name instance
+(@value{GDBP}) focus instance1
+(@value{GDBP}) set args a b c
+(@value{GDBP}) focus instance2
+(@value{GDBP}) set args d e f
+(@value{GDBP}) focus all
+(@value{GDBP}) run
+@end smallexample
+
+@noindent
+which will results in four inferiors running, with two of them getting
+the argument lists @code{a b c} and @code{d e f}, and the other two
+having been started without any arguments being passed.
+
+To be informed of inferior creation during running, set the
+@code{inferior-events} variable:
+
+@table @code
+@kindex set print inferior-events
+@cindex print messages on inferior start and exit
+@item set print inferior-events
+@itemx set print inferior-events on
+@itemx set print inferior-events off
+The @code{set print inferior-events} command allows you to enable or
+disable printing of messages when @value{GDBN} notices that new
+inferiors have started or that inferiors have exited or have been
+detached. By default, these messages will not be printed.
+
+@kindex show print inferior-events
+@item show print inferior-events
+Show whether messages will be printed when @value{GDBN} detects that
+inferiors have started, exited or have been detached.
+@end table
+
+@subsection Inferior/Thread Sets
+
+The inferior/thread set is a compact way to refer to groups of
+inferiors and threads. Its syntax is as follows:
+
+@table @code
+@item @var{itset-spec} @expansion{}
+@code{"[" @var{raw-itset-spec} "]"}
+
+@item @var{raw-itset-spec} @expansion{}
+@code{[ "!" ] @var{itset-list}}
+
+@item @var{itset-list} @expansion{}
+@code{@var{itset-range} ( "," @var{itset-list} )* }
+
+@item @var{itset-range} @expansion{}
+@code{@var{itset-pair} [ ":" @var{itset-pair} ] }
+
+@item @var{itset-pair} @expansion{}
+@code{[ @var{inferior-spec} ] [ "." @var{thread-spec} ] }
+
+@item @var{inferior-spec} @expansion{}
+@code{@var{number} | @var{name} | "*" | "all" }
+
+@item @var{thread-spec} @expansion{}
+@code{@var{number} | "*" }
+
+@end table
+
+@code{!} preceding a spec indicates a ``static'' i/t set, in which the
+membership is decided when the i/t set is first mentioned, and does
+not change thereafter. (Note that a static set may become empty
+without warning, if all of its inferiors or threads exit.) A dynamic
+set updates its membership so as to be current whenever it is used.
+
+The range specification @code{:} calls for the inclusion of every
+inferior and/or thread whose id falls in a numeric range. For
+instance, @code{[3.4:5.6]} includes inferiors 3, 4, and 5, but only
+the threads numbered 4, 5, or 6 in those inferiors.
+
+The basic @code{@var{inferior}.@var{thread}} syntax allows for
+wildcards and missing components, so both @code{[45.*]} and
+@code{[45]} refer to every thread of inferior 45, while @code{[*.*]}
+and @code{[*]} include every thread of every inferior.
+
+Some examples:
+
+@table @code
+@item [myinf.4:myinf.10]
+Threads 4 through 6 of inferior @code{myinf}.
+
+@item [1]
+The first inferior.
+
+@item [!1:5]
+A static set of the first five inferiors.
+
+@item [myinf,4.7,5.6:5.99]
+A set of three inferiors (@code{myinf}, 4, and 6), plus thread 7 of
+inferior 4, and threads 5 through 99 of inferior 6.
+
+@end table
+
@node Threads
@section Debugging Programs with Multiple Threads
@xref{Set Watchpoints,,Setting Watchpoints}, for information about
watchpoints in programs with multiple threads.
-@node Processes
-@section Debugging Programs with Multiple Processes
+@node Forks
+@section Debugging Forks
-@cindex fork, debugging programs which call
@cindex multiple processes
@cindex processes, multiple
+@cindex fork, debugging programs which call
On most systems, @value{GDBN} has no special support for debugging
programs which create additional processes using the @code{fork}
function. When a program forks, @value{GDBN} will continue to debug the
As described in the preceding table.
@end table
+In the case of multiple executables, if the location is ambiguous
+between the several programs, the sources to use will be gotten from
+the first executable in the current i/t set.
+
@node Specify Location
@section Specifying a Location
@cindex specifying location
@end table
+Any of these forms may be prefixed with @code{#@var{exec}#}, where
+@var{exec} is the name of any executable that has been given to
+@value{GDBN}. So if @value{GDBN} was started with @code{gdb prog1
+prog2}, then @code{list #prog2#main.c:10} will list the source code
+around line 10 of @file{main.c} in @code{prog2}. The name of the
+executable may be either the file name proper, or a pathname with
+which the executable was specified to @value{GDBN}; the latter may be
+useful if there are several executables with the same file name.
@node Edit
@section Editing Source Files
@samp{::} allows you to specify a variable in terms of the file or
function where it is defined. @xref{Variables, ,Program Variables}.
+@item #
+@samp{#} allows you to specify a variable in terms of the program
+where it is defined. @xref{Variables, ,Program Variables}.
+
@cindex @{@var{type}@}
@cindex type casting memory
@cindex memory, viewing as typed object
@c FIXME: Um, so what happens in one of those rare cases where it's in
@c conflict?? --mew
+@cindex sharp, context for variables/functions
+@cindex @code{#}, context for variables/functions
+Similarly, when working with multiple programs in a session, you may
+find symbols that have definitions in several different programs. You
+can specify a particular executable by prefixing the symbol with the
+executable's name, delimited by @samp{#}:
+
+@smallexample
+#@var{exec}#@var{variable}
+@end smallexample
+
+@var{exec} may be either just the file name, or the pathname by which
+the executable was supplied to @value{GDBN} originally.
+
+The value of the #-qualified symbol is a normal value, available for other
+operations, for instance arithmetic:
+
+@smallexample
+(@value{GDBP}) print #client#sent_size - #server#rcvd_size
+$45 = 16
+@end smallexample
+
@cindex wrong values
@cindex variable values, wrong
@cindex function entry/exit, wrong values of variables
Program}). In these situations the @value{GDBN} commands to specify
new files are useful.
+@value{GDBN} is capable of working with multiple programs at once, so
+you have the option of adding executables instead of replacing them,
+using commands such as @code{add-file}. While this can be useful, for
+instance to debug both client and server programs from the same
+@value{GDBN}, it can also be confusing to have several functions named
+@code{main}, several globals with the same name but different values,
+and so forth. You may wish to try using @value{GDBN} each way before
+deciding which is the better approach.
+
@table @code
@cindex executable file
@kindex file
@code{file} with no argument makes @value{GDBN} discard any information it
has on both executable file and the symbol table.
+@item add-file @var{filename}
+Add @var{filename} to the set of programs being debugged. As with
+@code{file}, the given file is both used as an executable and as a
+source of symbols. Each distinct file is added only once (as decided
+by pathname; @value{GDBN} considers files with different full paths to
+be different, even if they are byte-wise identical.)
+
@kindex exec-file
@item exec-file @r{[} @var{filename} @r{]}
Specify that the program to be run (but not the symbol table) is found
-in @var{filename}. @value{GDBN} searches the environment variable @code{PATH}
-if necessary to locate your program. Omitting @var{filename} means to
-discard information on the executable file.
+in @var{filename}. @value{GDBN} searches the environment variable
+@code{PATH} if necessary to locate your program. Omitting
+@var{filename} means to discard information on the executable file.
+With or without an argument, if there are multiple executables, all
+will be discarded.
+
+@item add-exec-file @var{filename}
+Add @var{filename} to the set of executables that may be run.
@kindex symbol-file
@item symbol-file @r{[} @var{filename} @r{]}
@kindex info target
@item info files
@itemx info target
-@code{info files} and @code{info target} are synonymous; both print the
-current target (@pxref{Targets, ,Specifying a Debugging Target}),
-including the names of the executable and core dump files currently in
-use by @value{GDBN}, and the files from which symbols were loaded. The
-command @code{help target} lists all possible targets rather than
-current ones.
+@code{info files} and @code{info target} are synonymous; both print
+the current target (@pxref{Targets, ,Specifying a Debugging Target}),
+including the names of all the executables and core dump files
+currently in use by @value{GDBN}, and the files from which symbols
+were loaded. The command @code{help target} lists all possible
+targets rather than current ones.
@kindex maint info sections
@item maint info sections
@item flushregs
This command forces @value{GDBN} to flush its internal register cache.
+@kindex maint print execs
+@cindex info for known executables
+@item maint print execs
+Print a dump of all known executables.
+
@kindex maint print objfiles
@cindex info for known object files
@item maint print objfiles
#include "exec.h"
#include "observer.h"
#include "arch-utils.h"
+#include "vec.h"
#include <fcntl.h>
#include "readline/readline.h"
static void exec_close (int);
+static void exec_file_command (char *, int);
+
static void file_command (char *, int);
+static void add_file_command (char *, int);
+
static void set_section_command (char *, int);
static void exec_files_info (struct target_ops *);
struct target_ops exec_ops;
+/* The vector of all executables in use. */
+
+VEC(exec_p) *execs = NULL;
+
/* The Binary File Descriptor handle for the executable file. */
bfd *exec_bfd = NULL;
-long exec_bfd_mtime = 0;
+
+struct exec *last_exec_created;
+
+struct exec *current_exec;
+
+struct exec *first_exec;
/* Whether to open exec and core files read-only or read-write. */
{
int need_symtab_cleanup = 0;
struct vmap *vp, *nxt;
+ int ix;
+ struct exec *ex;
for (nxt = vmap; nxt != NULL;)
{
vmap = NULL;
+ /* Clear all the exec objects. */
+ if (execs)
+ {
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, ex); ++ix)
+ {
+ /* We don't free objfiles because other code does it. */
+ if (ex->inferior)
+ delete_inferior (ex->inferior->pid);
+ }
+#if 0
+ VEC_block_remove (exec_p, execs, 0, VEC_length (exec_p, execs));
+#endif
+ execs = NULL;
+ first_exec = NULL;
+ current_exec = NULL;
+ }
+
if (exec_bfd)
{
char *name = bfd_get_filename (exec_bfd);
name, bfd_errmsg (bfd_get_error ()));
xfree (name);
exec_bfd = NULL;
- exec_bfd_mtime = 0;
}
if (exec_ops.to_sections)
unpush_target (&exec_ops);
if (from_tty)
- printf_unfiltered (_("No executable file now.\n"));
+ printf_unfiltered (_("No executable files now.\n"));
}
-/* Process the first arg in ARGS as the new exec file.
+/* Process the first arg in ARGS as a new exec file.
This function is intended to be behave essentially the same
as exec_file_command, except that the latter will detect when
ARGS is assumed to be the filename. */
+void exec_file_attach_1 (char *filename, int from_tty);
+
void
exec_file_attach (char *filename, int from_tty)
{
- /* Remove any previous exec file. */
+ /* (should clear all existing execs?) */
unpush_target (&exec_ops);
+ exec_file_attach_1 (filename, from_tty);
+}
+
+void
+exec_file_add (char *filename, int from_tty)
+{
+ struct exec *exec;
+
+ /* We don't want more than one of each executable. */
+ exec = find_exec_by_name (filename);
+ if (exec)
+ {
+ printf_unfiltered (_("Exec '%s' is already present.\n"), filename);
+ return;
+ }
+
+ exec_file_attach_1 (filename, from_tty);
+}
+
+void
+exec_file_attach_1 (char *filename, int from_tty)
+{
+ struct exec *exec = NULL;
+
/* Now open and digest the file the user requested, if any. */
if (!filename)
{
if (from_tty)
- printf_unfiltered (_("No executable file now.\n"));
+ printf_unfiltered (_("No executable files now.\n"));
set_gdbarch_from_file (NULL);
}
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
- exec_bfd_mtime = bfd_get_mtime (exec_bfd);
-
validate_files ();
set_gdbarch_from_file (exec_bfd);
- push_target (&exec_ops);
+ /* If this is the first exec, then we need to set up the target
+ vector. We don't need to do it for subsequent execs
+ however. */
+ if (execs == NULL)
+ push_target (&exec_ops);
+
+ exec = create_exec (filename, exec_bfd, bfd_get_mtime (exec_bfd));
+
+ exec->sections = exec_ops.to_sections;
+ exec->sections_end = exec_ops.to_sections_end;
+
+ if (number_of_execs () == 1)
+ {
+ first_exec = exec;
+
+ if (symfile_objfile
+ && symfile_objfile->exec == NULL)
+ {
+ symfile_objfile->exec = exec;
+ exec->objfile = symfile_objfile;
+ }
+ else
+ {
+ struct objfile *ofile;
+
+ ALL_OBJFILES (ofile)
+ {
+ if (ofile->name
+ && strcmp (ofile->name, exec->name) == 0)
+ {
+ ofile->exec = exec;
+ exec->objfile = ofile;
+ }
+ }
+ }
+ }
/* Tell display code (if any) about the changed file name. */
if (deprecated_exec_file_display_hook)
observer_notify_executable_changed ();
}
+void
+exec_file_update (struct exec *exec)
+{
+ char *filename;
+
+ filename = exec->name;
+
+ {
+ char *scratch_pathname;
+ int scratch_chan;
+
+ scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename,
+ write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0,
+ &scratch_pathname);
+#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__)
+ if (scratch_chan < 0)
+ {
+ char *exename = alloca (strlen (filename) + 5);
+ strcat (strcpy (exename, filename), ".exe");
+ scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, exename,
+ write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0,
+ &scratch_pathname);
+ }
+#endif
+ if (scratch_chan < 0)
+ perror_with_name (filename);
+ exec->ebfd = bfd_fopen (scratch_pathname, gnutarget,
+ write_files ? FOPEN_RUB : FOPEN_RB,
+ scratch_chan);
+
+ if (!exec->ebfd)
+ error (_("\"%s\": could not open as an executable file: %s"),
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+
+ /* At this point, scratch_pathname and exec->ebfd->name both point to the
+ same malloc'd string. However exec_close() will attempt to free it
+ via the exec->ebfd->name pointer, so we need to make another copy and
+ leave exec->ebfd as the new owner of the original copy. */
+ scratch_pathname = xstrdup (scratch_pathname);
+ make_cleanup (xfree, scratch_pathname);
+
+ if (!bfd_check_format (exec->ebfd, bfd_object))
+ {
+ /* Make sure to close exec->ebfd, or else "run" might try to use
+ it. */
+ exec_close (0);
+ error (_("\"%s\": not in executable format: %s"),
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* FIXME - This should only be run for RS6000, but the ifdef is a poor
+ way to accomplish. */
+#ifdef DEPRECATED_IBM6000_TARGET
+ /* Setup initial vmap. */
+
+ map_vmap (exec->ebfd, 0);
+ if (vmap == NULL)
+ {
+ /* Make sure to close exec->ebfd, or else "run" might try to use
+ it. */
+ exec_close (0);
+ error (_("\"%s\": can't find the file sections: %s"),
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+#endif /* DEPRECATED_IBM6000_TARGET */
+
+ if (build_section_table (exec->ebfd, &(exec->sections),
+ &(exec->sections_end)))
+ {
+ /* Make sure to close exec->ebfd, or else "run" might try to use
+ it. */
+ exec_close (0);
+ error (_("\"%s\": can't find the file sections: %s"),
+ scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ }
+
+ exec->ebfd_mtime = bfd_get_mtime (exec_bfd);
+
+ validate_files ();
+
+ set_gdbarch_from_file (exec->ebfd);
+
+ /* Tell display code (if any) about the changed file name. */
+ if (deprecated_exec_file_display_hook)
+ (*deprecated_exec_file_display_hook) (filename);
+ }
+
+ observer_notify_executable_changed ();
+}
+
+/* Create an exec object representing the given executable. */
+
+struct exec *
+create_exec (char *filename, bfd *abfd, long mtime)
+{
+ struct exec *exec;
+ struct inferior *inf;
+
+ exec = (struct exec *) xmalloc (sizeof (struct exec));
+
+ /* Save the full pathname in the exec object. This may be
+ user-unfriendly at times, since the short name may be
+ ambiguous. Alternatively, when searching for a matching exec,
+ allow any partial path supplied by the user. */
+ filename = bfd_get_filename (abfd);
+
+ exec->name = savestring (filename, strlen (filename));
+ exec->shortname = (char *) lbasename (exec->name);
+ exec->ebfd = abfd;
+ exec->ebfd_mtime = mtime;
+ exec->objfile = NULL;
+
+ /* Add it to the vector of execs. */
+ VEC_safe_push (exec_p, execs, exec);
+
+ inf = add_inferior_silent (0);
+ inf->exec = exec;
+ /* Need to ensure unique name? */
+ inf->name = exec->shortname;
+ exec->inferior = inf;
+
+ last_exec_created = exec;
+
+ return exec;
+}
+
+struct exec *
+find_exec_by_name (char *name)
+{
+ return find_exec_by_substr (name, name + strlen (name));
+}
+
+struct exec *
+find_exec_by_substr (char *name, char *name_end)
+{
+ int len, ix;
+ struct exec *exec;
+
+ if (!execs)
+ return NULL;
+
+ len = name_end - name;
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ {
+ if (strncmp (exec->name, name, len) == 0 && strlen (exec->name) == len)
+ return exec;
+ }
+
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ {
+ if (strncmp (exec->shortname, name, len) == 0 && strlen (exec->shortname) == len)
+ return exec;
+ }
+
+ return NULL;
+}
+
+int
+number_of_execs ()
+{
+ return VEC_length (exec_p, execs);
+}
+
/* Process the first arg in ARGS as the new exec file.
Note that we have to explicitly ignore additional args, since we can
char *filename;
if (from_tty && target_has_execution
- && !query (_("A program is being debugged already.\n"
- "Are you sure you want to change the file? ")))
- error (_("File not changed."));
+ && !((number_of_execs () > 1)
+ ? query (_("%d programs are being debugged already.\n"
+ "Are you sure you want to change the file? "),
+ number_of_execs ())
+ : query (_("A program is being debugged already.\n"
+ "Are you sure you want to change the file? "))))
+ error (_("File(s) not changed."));
if (args)
{
}
else
exec_file_attach (NULL, from_tty);
+
+ if (number_of_execs () == 1)
+ set_current_exec (first_exec);
+}
+
+static void
+add_exec_file_command (char *args, int from_tty)
+{
+ char **argv;
+ char *filename;
+
+ if (args)
+ {
+ /* Scan through the args and pick up the first non option arg
+ as the filename. */
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ nomem (0);
+
+ make_cleanup_freeargv (argv);
+
+ for (; (*argv != NULL) && (**argv == '-'); argv++)
+ {;
+ }
+ if (*argv == NULL)
+ error (_("No executable file name was specified"));
+
+ filename = tilde_expand (*argv);
+ make_cleanup (xfree, filename);
+
+ /* Warn even before starting execution, most users only want to
+ debug a single program at a time. */
+ if (from_tty
+ && number_of_execs () == 1
+ && !query (_("A program is being debugged already.\n"
+ "Are you sure you want to add another executable file? ")))
+ error (_("File not added."));
+
+ exec_file_add (filename, from_tty);
+ }
+ else
+ error (_("No executable file name was specified"));
}
/* Set both the exec file and the symbol file, in one command.
the exec file, but that's rough. */
exec_file_command (arg, from_tty);
symbol_file_command (arg, from_tty);
+ if (number_of_execs () == 1)
+ set_current_exec (first_exec);
+ if (deprecated_file_changed_hook)
+ deprecated_file_changed_hook (arg);
+}
+
+/* Add the given file as both exec and symbol file. */
+
+static void
+add_file_command (char *arg, int from_tty)
+{
+ /* FIXME, if we lose on reading the symbol file, we should revert
+ the exec file, but that's rough. */
+ add_exec_file_command (arg, from_tty);
+ /* Note that symbol_file_command is intrinsically additive. */
+ symbol_file_command (arg, from_tty);
if (deprecated_file_changed_hook)
deprecated_file_changed_hook (arg);
}
unsigned count;
count = bfd_count_sections (some_bfd);
+ /* This function is reused in ways that make it hard to tell when
+ the old one should be discarded, allow this leak until callers
+ are cleaned up. */
+#if 0
if (*start)
xfree (* start);
+#endif
*start = (struct section_table *) xmalloc (count * sizeof (**start));
*end = *start;
bfd_map_over_sections (some_bfd, add_to_section_table, (char *) end);
struct mem_attrib *attrib, struct target_ops *target)
{
int res;
- struct section_table *p;
+ struct section_table *p, *sections, *sections_end;
CORE_ADDR nextsectaddr, memend;
struct obj_section *section = NULL;
if (len <= 0)
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
+ sections = target->to_sections;
+ sections_end = target->to_sections_end;
+ if (tmp_inf && current_exec && tmp_inf->exec != current_exec)
+ {
+ sections = tmp_inf->exec->sections;
+ sections_end = tmp_inf->exec->sections_end;
+ }
+
if (overlay_debugging)
{
section = find_pc_overlay (memaddr);
memend = memaddr + len;
nextsectaddr = memend;
- for (p = target->to_sections; p < target->to_sections_end; p++)
+ for (p = sections; p < sections_end; p++)
{
if (overlay_debugging && section
&& strcmp (section->the_bfd_section->name,
\f
void
-print_section_info (struct target_ops *t, bfd *abfd)
+print_section_info (struct target_ops *t, bfd *abfd, struct exec *exec)
{
- struct section_table *p;
+ struct section_table *sections, *sections_end, *p;
/* FIXME: 16 is not wide enough when gdbarch_addr_bit > 64. */
int wid = gdbarch_addr_bit (gdbarch_from_bfd (abfd)) <= 32 ? 8 : 16;
+ if (exec)
+ {
+ sections = exec->sections;
+ sections_end = exec->sections_end;
+ }
+ else
+ {
+ sections = t->to_sections;
+ sections_end = t->to_sections_end;
+ }
+
printf_filtered ("\t`%s', ", bfd_get_filename (abfd));
wrap_here (" ");
printf_filtered (_("file type %s.\n"), bfd_get_target (abfd));
- if (abfd == exec_bfd)
+ if (exec && abfd == exec->ebfd)
printf_filtered (_("\tEntry point: %s\n"),
paddress (bfd_get_start_address (abfd)));
- for (p = t->to_sections; p < t->to_sections_end; p++)
+ for (p = sections; p < sections_end; p++)
{
printf_filtered ("\t%s", hex_string_custom (p->addr, wid));
printf_filtered (" - %s", hex_string_custom (p->endaddr, wid));
static void
exec_files_info (struct target_ops *t)
{
- print_section_info (t, exec_bfd);
+ struct exec *exec;
+ int ix;
+
+ /* Quick summary of the execs present. Only do in the multiprogram
+ case, for compatibility and simplicity. */
+ if (number_of_execs () > 1)
+ {
+ printf_filtered (_(" Executables:\n"));
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ printf_filtered (_(" %s `%s'\n"),
+ (exec == current_exec ? "*" : " "), exec->name);
+ printf_filtered (_(" Sections:\n"));
+ }
+
+ /* Now dump all the section info. */
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ print_section_info (t, exec->ebfd, exec);
if (vmap)
{
}
}
+/* The maintenance command for execs displays more detail data, such
+ as host addresses for objects. */
+
+void
+maintenance_print_execs (char *ignore, int from_tty)
+{
+ struct exec *exec;
+ int ix;
+
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ {
+ printf_filtered ("Executable %s: exec at ", exec->name);
+ gdb_print_host_address (exec, gdb_stdout);
+ printf_filtered (", objfile at ");
+ gdb_print_host_address (exec->objfile, gdb_stdout);
+ printf_filtered (", bfd at ");
+ gdb_print_host_address (exec->ebfd, gdb_stdout);
+ printf_filtered (", inf %d at ",
+ (exec->inferior ? exec->inferior->num : -1));
+ gdb_print_host_address (exec->inferior, gdb_stdout);
+ printf_filtered ("\n");
+ }
+ printf_filtered ("Current exec is %s, at ",
+ (current_exec ? current_exec->name : "(null)"));
+ gdb_print_host_address (current_exec, gdb_stdout);
+ printf_filtered ("\n");
+ printf_filtered ("First exec is %s, at ",
+ (first_exec ? first_exec->name : "(null)"));
+ gdb_print_host_address (first_exec, gdb_stdout);
+ printf_filtered ("\n");
+}
+
+
static void
set_section_command (char *args, int from_tty)
{
($PATH) is searched for a command of that name.\n\
No arg means to have no executable file and no symbols."), &cmdlist);
set_cmd_completer (c, filename_completer);
+ c = add_cmd ("add-file", class_files, add_file_command, _("\
+Add FILE to the programs being debugged.\n\
+It is read for its symbols, for getting the contents of pure memory,\n\
+and it is the program executed when you use the `run' command.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+($PATH) is searched for a command of that name."), &cmdlist);
+ set_cmd_completer (c, filename_completer);
}
c = add_cmd ("exec-file", class_files, exec_file_command, _("\
No arg means have no executable file."), &cmdlist);
set_cmd_completer (c, filename_completer);
+ c = add_cmd ("add-exec-file", class_files, add_exec_file_command, _("\
+Use FILE as program for getting contents of pure memory.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+is searched for a command of that name."), &cmdlist);
+ set_cmd_completer (c, filename_completer);
+
add_com ("section", class_files, set_section_command, _("\
Change the base address of section SECTION of the exec file to ADDR.\n\
This can be used if the exec file does not contain section addresses,\n\
#define EXEC_H
#include "target.h"
+#include "vec.h"
struct section_table;
struct target_ops;
struct bfd;
+struct objfile;
+struct inferior;
extern struct target_ops exec_ops;
+/* This object represents an executable program. GDB can handle
+ arbitrarily many, although the traditional debugging scenario just
+ involves one. An executable always has a BFD managing the file
+ itself, but may or may not have an associated symbol table. */
+
+struct exec
+ {
+ /* The full name of the executable. */
+ char *name;
+
+ /* An abbreviated name, typically formed by pruning the directory
+ from the full name. */
+ char *shortname;
+
+ /* The BFD for this executable. */
+ bfd *ebfd;
+
+ /* The main objfile for this executable. */
+ struct objfile *objfile;
+
+ /* The last-modified time, from when the exec was brought in. */
+ long ebfd_mtime;
+
+ /* The "proto-inferior" that we use when setting things up. */
+ struct inferior *inferior;
+
+ /* Pointers to section table for this executable. */
+ struct section_table *sections;
+ struct section_table *sections_end;
+ };
+
+typedef struct exec *exec_p;
+DEF_VEC_P(exec_p);
+
+extern VEC(exec_p) *execs;
+
+extern struct exec *current_exec;
+
+extern struct exec *first_exec;
+
/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
Returns 0 if OK, 1 on error. */
/* Set the loaded address of a section. */
extern void exec_set_section_address (const char *, int, CORE_ADDR);
+/* Return the first exec whose name matches the given string. */
+extern struct exec *find_exec_by_name (char *name);
+
+/* Return the first exec whose name matches the chars between the
+ given bounds. */
+extern struct exec *find_exec_by_substr (char *name, char *name_end);
+
+/* Return the number of executables present. */
+extern int number_of_execs ();
+
+extern void exec_file_update (struct exec *exec);
+
+extern struct exec *create_exec (char *filename, bfd *abfd, long mtime);
+
+extern void set_current_exec (struct exec *exec);
+
+extern void maintenance_print_execs (char *, int);
+
#endif
#include "defs.h"
#include "gdb_string.h"
#include "frame.h" /* required by inferior.h */
+#include "exec.h"
#include "inferior.h"
#include "target.h"
#include "gdb_wait.h"
#include "gdbcmd.h"
#include "solib.h"
+extern int detach_fork;
+
#include <signal.h>
/* This just gets used as a default if we can't find SHELL. */
int shell = 0;
static char **argv;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ struct inferior *inf;
+ struct exec *exec;
/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
init_thread_list ();
- add_inferior (pid);
+ inf = add_inferior (pid);
+
+ exec = find_exec_by_name (exec_file_arg);
+
+ if (exec)
+ set_inferior_exec (inf, exec);
+ else
+ warning (_("Could not find exec for \"%s\", breakpoints will not work"),
+ exec_file_arg);
/* Needed for wait_for_inferior stuff below. */
inferior_ptid = pid_to_ptid (pid);
moment leave this as speculation. */
int level;
+ struct inferior *inferior;
+
/* The frame's low-level unwinder and corresponding cache. The
low-level unwinder is responsible for unwinding register values
for the previous frame. The low-level unwind methods are
fprint_field (file, "code", id.code_addr_p, id.code_addr);
fprintf_unfiltered (file, ",");
fprint_field (file, "special", id.special_addr_p, id.special_addr);
+ fprintf_unfiltered (file, ",inf=%d", id.inferior_num);
fprintf_unfiltered (file, "}");
}
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
/* Find THIS frame's ID. */
fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+ if (fi->inferior)
+ fi->this_id.value.inferior_num = fi->inferior->num;
fi->this_id.p = 1;
if (frame_debug)
{
else if (l.special_addr == r.special_addr)
/* Frames are equal. */
eq = 1;
+ else if (l.inferior_num != r.inferior_num)
+ /* If the inferiors are different, the frames are different. */
+ eq = 0;
else
/* No luck. */
eq = 0;
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
frame->level = -1;
+ /* Frame inferiors will all inherit from the sentinel's inferior.
+ In future we may want to set this from a parameter. */
+ frame->inferior = current_inferior ();
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
fi->next = create_sentinel_frame (get_current_regcache ());
+ fi->inferior = fi->next->inferior;
+
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
+ prev_frame->inferior = this_frame->inferior;
+
/* Don't yet compute ->unwind (and hence ->type). It is computed
on-demand in get_frame_type, frame_register_unwind, and
get_frame_id. */
void
find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
{
- (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
+ (*sal) = find_pc_inf_line (get_frame_pc (frame), get_frame_inferior (frame), pc_notcurrent (frame));
}
/* Per "frame.h", return the ``address'' of the frame. Code should
frame->this_id.value.stack_addr = base;
}
+struct inferior *
+get_frame_inferior (struct frame_info *frame)
+{
+ return frame->inferior;
+}
+
/* Memory access methods. */
void
unsigned int stack_addr_p : 1;
unsigned int code_addr_p : 1;
unsigned int special_addr_p : 1;
+
+ /* The frame's inferior. This field is always valid, but since no
+ inferiors have an ID of zero, a zero value here indicates that
+ the frame is not associated with any inferior. */
+ int inferior_num;
};
/* Methods for constructing and comparing Frame IDs. */
extern enum frame_type get_frame_type (struct frame_info *);
+extern struct inferior *get_frame_inferior (struct frame_info *);
+
/* For frames where we can not unwind further, describe why. */
enum unwind_stop_reason
extern bfd *core_bfd;
extern bfd *exec_bfd;
-/* The mtime when we last opened exec_bfd. */
-extern long exec_bfd_mtime;
-
/* Whether to open exec and core files read-only or read-write. */
extern int write_files;
extern void exec_file_attach (char *filename, int from_tty);
+extern void exec_file_add (char *filename, int from_tty);
+
extern void exec_file_clear (int from_tty);
extern void validate_files (void);
#include "defs.h"
#include "command.h"
+#include "exec.h"
#include "inferior.h"
#include "inflow.h"
#include "gdbcore.h"
{
exec_file = get_exec_file (0);
- if (exec_file)
+ if (exec_file && number_of_execs () == 1)
printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
target_pid_to_str (pid_to_ptid (pid)));
else
if (from_tty)
{
- char *exec_file = get_exec_file (0);
- if (exec_file == 0)
- exec_file = "";
- printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
- target_pid_to_str (pid_to_ptid (pid)));
+ struct inferior *inf = find_inferior_pid (pid);
+ if (inf && inf->exec)
+ printf_unfiltered (_("Detaching from program: %s, %s\n"),
+ inf->exec->name,
+ target_pid_to_str (pid_to_ptid (pid)));
+ else
+ printf_unfiltered (_("Detaching from %s\n"),
+ target_pid_to_str (pid_to_ptid (pid)));
gdb_flush (gdb_stdout);
}
if (args)
#include "gdbcore.h"
#include "target.h"
#include "language.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "completer.h"
#include "gdbthread.h"
#include "valprint.h"
+struct inferior *current_inf;
+
/* Functions exported for general use, in inferior.h: */
void all_registers_info (char *, int);
int suppress_resume_observer = 0;
/* When set, normal_stop will not call the normal_stop observer. */
int suppress_stop_observer = 0;
-\f
+
+struct itset *current_itset = NULL;
+
+void
+set_current_exec (struct exec *exec)
+{
+ current_exec = exec;
+ /* As a transitional step, copy exec properties into old crufty globals. */
+ exec_bfd = current_exec->ebfd;
+ exec_ops.to_sections = current_exec->sections;
+ exec_ops.to_sections_end = current_exec->sections_end;
+ symfile_objfile = current_exec->objfile;
+ clear_symtab_users ();
+}
+
+void
+focus_command (char *spec, int from_tty)
+{
+ struct itset *itset;
+ struct itset_entry *entry;
+ struct inferior *inf;
+ int ix;
+
+ if (!spec)
+ {
+ if (current_itset)
+ printf_filtered ("Focus is [%s]", current_itset->spec);
+ else
+ printf_filtered ("No focus has been set.");
+ if (current_exec)
+ printf_filtered (" (current exec is %s)", current_exec->name);
+ else
+ printf_filtered (" (no current exec)");
+ printf_filtered ("\n");
+ return;
+ }
+
+ itset = make_itset_from_spec (spec);
+
+ if (itset_is_empty (itset))
+ {
+ error ("Cannot focus on an empty set, focus is unchanged");
+ return;
+ }
+
+ current_itset = itset;
+
+ /* For now, set a current exec from the first element of the focus
+ set. */
+ entry = VEC_index (itset_entry, itset->inferiors, 0);
+ inf = entry->inferior;
+ if (VEC_length (itset_entry, itset->inferiors) > 1)
+ warning ("%d inferiors in the current i/t set, using inf %d to get current exec",
+ VEC_length (itset_entry, itset->inferiors), inf->num);
+ if (inf->exec)
+ set_current_exec (inf->exec);
+ /* (find first live thread?) */
+ if (VEC_length (thread_p, entry->threads) > 1)
+ warning ("%d threads for inferior %d in the current i/t set, switching to first",
+ VEC_length (thread_p, entry->threads), inf->num);
+ if (VEC_length (thread_p, entry->threads) > 0)
+ switch_to_thread ((VEC_index (thread_p, entry->threads, 0))->ptid);
+
+ /* Confirm the choice of focus. */
+ printf_filtered ("New focus: ");
+ dump_itset (current_itset);
+ if (current_exec)
+ printf_filtered ("Current exec is %s.\n", current_exec->name);
+ else
+ printf_filtered ("No current exec.\n");
+}
+
/* Accessor routines. */
void
char *
get_inferior_args (void)
{
+ struct inferior *inf;
+
+ inf = first_inferior_in_set (current_itset);
+ if (inf)
+ {
+ inferior_args = inf->args;
+ inferior_argc = inf->argc;
+ inferior_argv = inf->argv;
+ }
+
if (inferior_argc != 0)
{
char *n, *old;
set_inferior_args (char *newargs)
{
char *saved_args = inferior_args;
+ struct inferior *inf;
inferior_args = newargs;
inferior_argc = 0;
inferior_argv = 0;
+ inf = first_inferior_in_set (current_itset);
+ if (inf)
+ {
+ inf->args = newargs;
+ inf->argc = 0;
+ inf->argv = 0;
+ }
+
return saved_args;
}
void
set_inferior_args_vector (int argc, char **argv)
{
+ struct inferior *inf;
+
inferior_argc = argc;
inferior_argv = argv;
+
+ inf = first_inferior_in_set (current_itset);
+ if (inf)
+ {
+ inf->argc = argc;
+ inf->argv = argv;
+ }
+
}
/* Notice when `set args' is run. */
static void
notice_args_set (char *args, int from_tty, struct cmd_list_element *c)
{
+ struct inferior *inf;
+
inferior_argc = 0;
inferior_argv = 0;
+
+ inf = first_inferior_in_set (current_itset);
+ if (inf)
+ {
+ inf->args = xstrdup (inferior_args);
+ inf->argc = 0;
+ inf->argv = 0;
+ }
}
/* Notice when `show args' is run. */
char *exec_file;
char *full_exec_path = NULL;
struct inferior *inferior;
+ struct exec *exec;
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
;
else if (target_has_execution)
{
- if (query ("A program is being debugged already. Kill it? "))
+ if ((number_of_execs () > 1)
+ ? query ("%d programs are being debugged already. Kill them? ",
+ number_of_execs ())
+ : query ("A program is being debugged already. Kill it? "))
target_kill ();
else
error (_("Not killed."));
}
attach_command_post_wait (args, from_tty, async_exec);
+
+ /* As a heuristic, if there is no exec assigned to the attached
+ inferior, but only one exec known to GDB, guess that it is the
+ exec for the the process just attached. (If GDB has guessed
+ wrong, it will be up to the user to use set-exec to fix
+ matters.) */
+ {
+ struct inferior *inferior = current_inferior ();
+
+ if (!inferior->exec && number_of_execs () == 1)
+ set_inferior_exec (inferior, first_exec);
+ }
+
discard_cleanups (back_to);
}
{
struct cmd_list_element *c = NULL;
+ add_com ("focus", no_class, focus_command, _("\
+Change the set of current inferiors/threads."));
+
/* add the filename of the terminal connected to inferior I/O */
add_setshow_filename_cmd ("inferior-tty", class_run,
&inferior_io_terminal, _("\
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "exec.h"
#include "inferior.h"
#include "target.h"
#include "command.h"
void _initialize_inferiors (void);
-static struct inferior *inferior_list = NULL;
+/*static*/ struct inferior *inferior_list = NULL;
static int highest_inferior_num;
+struct inferior *tmp_inf;
+
/* Print notices on inferior events (attach, detach, etc.), set with
`set print inferior-events'. */
static int print_inferior_events = 0;
+/* Commands with a prefix of `inferiors'. */
+extern struct cmd_list_element *inferior_cmd_list;
+
+struct inferior *find_inferior_id (int num);
+static void info_inferiors_command (char *, int);
+
struct inferior*
current_inferior (void)
{
static void
free_inferior (struct inferior *inf)
{
+ /* FIXME: We can't safely free inferior data until all refs to it
+ have been removed, such as from breakpoint locations etc. */
+#if 0
discard_all_inferior_continuations (inf);
xfree (inf->private);
xfree (inf);
+#endif
}
+/* TODO: I'm not calling this anywhere. If we stick with the one
+ target vector fits all inferiors notion, maybe this should be
+ called when the target is pushed on the stack. */
void
init_inferior_list (void)
{
memset (inf, 0, sizeof (*inf));
inf->pid = pid;
- inf->stop_soon = NO_STOP_QUIETLY;
-
inf->num = ++highest_inferior_num;
inf->next = inferior_list;
inferior_list = inf;
}
}
-static struct inferior *
+struct inferior *
find_inferior_id (int num)
{
struct inferior *inf;
return NULL;
}
+/* Find a inferior by matching PID. */
struct inferior *
find_inferior_pid (int pid)
{
return NULL;
}
+struct inferior *
+find_inferior_by_name (char *name)
+{
+ struct inferior *inf;
+
+ for (inf = inferior_list; inf; inf = inf->next)
+ if (inf->name && strcmp (inf->name, name) == 0)
+ return inf;
+
+ return NULL;
+}
+
struct inferior *
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
void *data)
return inferior_list != NULL;
}
+int
+number_of_inferiors (void)
+{
+ struct inferior *inf;
+ int rslt = 0;
+
+ for (inf = inferior_list; inf; inf = inf->next)
+ ++rslt;
+ return rslt;
+}
+
+
/* Prints the list of inferiors and their details on UIOUT. This is a
version of 'info_inferior_command' suitable for use from MI.
print_inferior (struct ui_out *uiout, int requested_inferior)
{
struct inferior *inf;
+ char *extra_info;
struct cleanup *old_chain;
old_chain = make_cleanup_ui_out_list_begin_end (uiout, "inferiors");
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- if (inf->pid == ptid_get_pid (inferior_ptid))
+ if (inf->pid > 0 && inf->pid == PIDGET (inferior_ptid))
ui_out_text (uiout, "* ");
else
ui_out_text (uiout, " ");
ui_out_field_int (uiout, "id", inf->num);
ui_out_text (uiout, " ");
ui_out_field_int (uiout, "target-id", inf->pid);
-
+ if (inf->name)
+ {
+ ui_out_text (uiout, " #");
+ ui_out_field_string (uiout, "name", inf->name);
+ ui_out_text (uiout, "#");
+ }
+ if (inf->exec)
+ {
+ ui_out_text (uiout, " ");
+ /* Use short names for execs, except for exec's own
+ inferior. */
+ ui_out_field_string (uiout, "exec",
+ (inf->exec->inferior == inf
+ ? inf->exec->name
+ : inf->exec->shortname));
+ if (inf->args)
+ {
+ ui_out_text (uiout, " ");
+ ui_out_field_string (uiout, "args", inf->args);
+ }
+ if (inf->inf_environ)
+ {
+ ui_out_text (uiout, " ");
+ ui_out_field_string (uiout, "environ", "env=X");
+ }
+ if (inf->io_terminal)
+ {
+ ui_out_text (uiout, " ");
+ ui_out_field_string (uiout, "io_terminal", "term=Y");
+ }
+ }
+#if 0
+ extra_info = target_extra_inferior_info (inf);
+ if (extra_info)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "details", extra_info);
+ ui_out_text (uiout, ")");
+ }
+#endif
ui_out_text (uiout, "\n");
do_cleanups (chain2);
}
fprintf_filtered (file, _("Printing of inferior events is %s.\n"), value);
}
+void
+add_inferior_command (char *args, int from_tty)
+{
+ struct exec *ex = NULL;
+ struct inferior *inf;
+ int i, copies = 1;
+ char *namebase = "", *namebuf;
+ char **argv;
+
+ if (args)
+ {
+ argv = buildargv (args);
+ for (; *argv != NULL; argv++)
+ {
+ if (**argv == '-')
+ {
+ if (strcmp (*argv, "-copies") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -copies");
+ copies = strtol (*argv, NULL, 10);
+ }
+ else if (strcmp (*argv, "-name") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -name");
+ namebase = xstrdup (*argv);
+ }
+ }
+ else
+ {
+ ex = find_exec_by_name (*argv);
+ if (!ex)
+ {
+ printf_unfiltered ("No exec found named '%s'\n", *argv);
+ /* Should ask whether to continue. */
+ }
+ }
+ }
+ }
+
+ if (ex)
+ ;
+ else if (current_exec)
+ ex = current_exec;
+
+ for (i = 0; i < copies; ++i)
+ {
+ inf = add_inferior (0);
+ inf->exec = ex;
+ inf->removable = 1;
+ namebuf = (char *) xmalloc (strlen (namebase) + 10);
+ sprintf (namebuf, "%s%d", namebase, inf->num);
+ set_inferior_name (inf, namebuf);
+ /* Should flag as not having run yet. */
+ }
+
+ printf_filtered ("%d inferiors added.\n", copies);
+}
+
+void
+remove_inferior_command (char *args, int from_tty)
+{
+ struct itset *itset;
+ struct itset_entry *entry;
+ struct inferior *inf;
+ int ix;
+
+ itset = make_itset_from_spec (args);
+
+ dump_itset (itset);
+
+ for (ix = 0; VEC_iterate (itset_entry, itset->inferiors, ix, entry); ++ix)
+ {
+#if 0
+ if (entry->inferior->removable)
+ delete_inferior (entry->inferior);
+ /* (should remove threads?) */
+#endif
+ }
+}
+
+void
+set_inferior_name (struct inferior *inf, char *name)
+{
+ inf->name = name;
+}
+
+void
+name_inferior_command (char *args, int from_tty)
+{
+ char *oldname, *newname;
+ struct inferior *inf;
+
+ if (args == NULL)
+ return;
+
+ while (*args == ' ' || *args == '\t')
+ args++;
+ oldname = args;
+ while (*args && !(*args == ' ' || *args == '\t'))
+ args++;
+ oldname = savestring (oldname, args - oldname);
+ while (*args == ' ' || *args == '\t')
+ args++;
+ if (*args)
+ {
+ inf = find_inferior_by_name (oldname);
+ newname = args;
+ while (*args && !(*args == ' ' || *args == '\t'))
+ args++;
+ newname = savestring (newname, args - newname);
+ }
+ else
+ {
+ /* One-argument case. */
+ inf = first_inferior_in_set (current_itset);
+ newname = oldname;
+ }
+ if (!inf)
+ {
+ printf_unfiltered("No inferior '%s' to rename.\n", oldname);
+ return;
+ }
+ printf_unfiltered("Rename '%s' to '%s'\n", inf->name, newname);
+ set_inferior_name (inf, newname);
+ printf_unfiltered("Inferior %d now named '%s'\n", inf->num, inf->name);
+}
+
+void
+set_inferior_exec (struct inferior *inf, struct exec *exec)
+{
+ inf->exec = exec;
+}
+
+/* set-exec ITSET EXEC
+ Set the inferiors found in ITSET to have the executable EXEC. Since
+ this command is primarily useful to repairing cases where GDB can't
+ do the right thing on its own, we only do minimal error checking,
+ and it is possible to overwrite a valid executable with one whose
+ addresses don't match up with the inferior. */
+
+void
+set_inferior_exec_command (char *args, int from_tty)
+{
+ struct exec *exec, *old_exec;
+ struct inferior *inf;
+ struct itset *itset;
+ struct itset_entry *entry;
+ char **argv, *itset_spec = NULL, *exec_name = NULL;
+ int ix;
+
+ if (!args)
+ return;
+
+ argv = buildargv (args);
+ itset_spec = *argv++;
+ if (!itset_spec)
+ error ("No i/t set supplied");
+ exec_name = *argv++;
+ if (!exec_name)
+ error ("No executable name supplied");
+ if (*argv)
+ warning ("Extra arguments ignored");
+
+ itset = make_itset_from_spec (itset_spec);
+ if (itset_is_empty (itset))
+ error ("No inferiors in [%s]", itset_spec);
+
+ exec = find_exec_by_name (exec_name);
+ if (!exec)
+ error ("No exec named `%s'", exec_name);
+
+ for (ix = 0; VEC_iterate (itset_entry, itset->inferiors, ix, entry); ++ix)
+ {
+ inf = entry->inferior;
+ old_exec = inf->exec;
+ if (exec == old_exec)
+ continue;
+ /* Don't touch the exec's own inferior. */
+ if (old_exec && inf == old_exec->inferior)
+ continue;
+ set_inferior_exec (inf, exec);
+ if (old_exec)
+ printf_filtered ("Inferior %d exec changed from `%s' to `%s'.\n",
+ inf->num, old_exec->name, exec->name);
+ else
+ printf_filtered ("Inferior %d now has exec `%s'.\n",
+ inf->num, exec->name);
+ }
+
+ /* should free itset here? */
+}
+
+/* Inferior/thread sets. */
+
+struct itid_pair { char *infspec; char *tidspec; };
+
+extern void parse_itset_spec (struct itset *itset);
+extern void parse_itset_list (struct itset *itset);
+extern void parse_itset_range (struct itset *itset);
+extern struct itid_pair parse_itset_itid (struct itset *itset);
+extern char *parse_itset_iid (struct itset *itset);
+extern char *parse_itset_tid (struct itset *itset);
+extern void get_inferior_or_pid (char *spec, struct inferior **infp, int *pidp);
+extern void add_inferior_to_itset (struct itset *itset, struct inferior *inf,
+ char *lo_tidspec, char *hi_tidspec);
+extern void add_threads_to_itset (struct itset_entry *entry,
+ char *lo_tidspec, char *hi_tidspec);
+
+
+/* Create a new i/t set, doing a test parse to check syntax. */
+
+struct itset *
+new_itset (char *spec)
+{
+ struct itset *itset;
+
+ /* We must have a specification to work with. */
+ if (!spec)
+ return NULL;
+
+ /* FIXME need to dispose of these properly */
+ itset = (struct itset *) xmalloc (sizeof (struct itset));
+
+ itset->name = NULL;
+ itset->spec = xstrdup (spec);
+ itset->dynamic = 1;
+ itset->inferiors = NULL;
+
+ /* Do a first test parse to check syntax. */
+ itset->parsed = 0;
+ itset->parse_errors = 0;
+ parse_itset_spec (itset);
+ itset->parsed = 1;
+
+ /* Do a second time to get in all the semantic actions, aka adding
+ items to vectors. */
+ if (!itset->parse_errors)
+ parse_itset_spec (itset);
+
+ return itset;
+}
+
+void
+update_itset (struct itset *itset)
+{
+ if (!itset)
+ return;
+
+ /* Don't touch static itsets. */
+ if (!itset->dynamic)
+ return;
+
+ /* If the spec has a syntax error, don't try to work with it. */
+ if (itset->parse_errors)
+ return;
+
+ /* Clear the vectors in preparation. */
+ /* FIXME clear thread subvectors too */
+ VEC_truncate (itset_entry, itset->inferiors, 0);
+ parse_itset_spec (itset);
+}
+
+void
+parse_itset_spec (struct itset *itset)
+{
+ itset->parse_head = itset->spec;
+
+ if (*(itset->parse_head) == '!')
+ {
+ ++(itset->parse_head);
+ if (itset->parsed && !itset->parse_errors)
+ itset->dynamic = 0;
+ }
+
+ parse_itset_list (itset);
+}
+
+void
+parse_itset_list (struct itset *itset)
+{
+ /* This is the empty set case. */
+ if (*(itset->parse_head) == '\0')
+ return;
+
+ parse_itset_range (itset);
+ while (*itset->parse_head == ',')
+ {
+ ++(itset->parse_head);
+ parse_itset_range (itset);
+ }
+}
+
+void
+parse_itset_range (struct itset *itset)
+{
+ struct itid_pair lopair, hipair;
+ struct inferior *lo_inf, *hi_inf, *inf;
+ int lo_pid, hi_pid;
+ struct itset_entry *entry;
+
+ hipair.infspec = hipair.tidspec = NULL;
+
+ lopair = parse_itset_itid (itset);
+ if (*(itset->parse_head) == ':')
+ {
+ ++(itset->parse_head);
+ hipair = parse_itset_itid (itset);
+ }
+ if (itset->parsed && !itset->parse_errors)
+ {
+ if (strcmp (lopair.infspec, "all") == 0
+ || strcmp (lopair.infspec, "*") == 0
+ || (hipair.infspec && strcmp (hipair.infspec, "*") == 0))
+ {
+ /* Wildcards override everything else. We need to do the
+ addition incrementally, in case it's supplementing a
+ previous spec; for instance, "2.3,*.5" should add the 3rd
+ thread of inferior 2 and threads 5 of all inferiors. */
+ for (inf = inferior_list; inf; inf = inf->next)
+ add_inferior_to_itset (itset, inf, lopair.tidspec, hipair.tidspec);
+ }
+ else
+ {
+ get_inferior_or_pid (lopair.infspec, &lo_inf, &lo_pid);
+ if (hipair.infspec)
+ {
+ get_inferior_or_pid (hipair.infspec, &hi_inf, &hi_pid);
+ /* This is a hack to use raw id's for range. */
+ if (lo_inf && lo_inf->pid == 0 && hi_inf && hi_inf->pid == 0)
+ {
+ for (inf = inferior_list; inf; inf = inf->next)
+ if (inf->num >= lo_inf->num && inf->num <= hi_inf->num)
+ add_inferior_to_itset (itset, inf,
+ lopair.tidspec, hipair.tidspec);
+ return;
+ }
+ /* Find every inferior in the range of the two supplied
+ pids. */
+ if (lo_pid >= 0 && hi_pid >= 0)
+ {
+ for (inf = inferior_list; inf; inf = inf->next)
+ if (inf->pid >= lo_pid && inf->pid <= hi_pid)
+ add_inferior_to_itset (itset, inf,
+ lopair.tidspec, hipair.tidspec);
+ }
+ /* (else error?) */
+ }
+ else
+ {
+ /* Only the low part of a range is found, just add the
+ one inferior. */
+ if (lo_inf)
+ add_inferior_to_itset (itset, lo_inf,
+ lopair.tidspec, hipair.tidspec);
+ /* (else error?) */
+ }
+ }
+ }
+}
+
+/* Given a spec string, find a name or number plausibly representing
+ an inferior name or a process pid. */
+
+void
+get_inferior_or_pid (char *spec, struct inferior **infp, int *pidp)
+{
+ struct inferior *inf;
+ int num;
+ char *endspec;
+
+ *infp = NULL;
+ *pidp = -1;
+ /* Look for an inferior with a matching name. Note that we
+ want to allow names with leading digits. */
+ for (inf = inferior_list; inf; inf = inf->next)
+ {
+ if (inf->name && strcmp (spec, inf->name) == 0)
+ {
+ *infp = inf;
+ *pidp = inf->pid;
+ return;
+ }
+ }
+ num = strtol (spec, &endspec, 10);
+ if (*endspec != '\0')
+ {
+ /* (should error?) */
+ return;
+ }
+ *infp = find_inferior_pid (num);
+ if (*infp)
+ {
+ *pidp = (*infp)->pid;
+ return;
+ }
+ /* Hack fallback that look at raw inferior id. */
+ *infp = find_inferior_id (num);
+ if (*infp)
+ {
+ *pidp = (*infp)->pid;
+ return;
+ }
+ /* Assume number is being used as a range bound, don't insist that
+ it correspond to an actual inferior. */
+ *pidp = num;
+}
+
+void
+add_inferior_to_itset (struct itset *itset, struct inferior *inf,
+ char *lo_tidspec, char *hi_tidspec)
+{
+ struct inferior *inf2;
+ struct itset_entry new_entry, *entry;
+ int ix, found = 0;
+
+ /* Only add one copy of each inferior to the set. */
+ /* FIXME: this will be a performance problem when we have thousands
+ of inferiors. */
+ for (ix = 0; VEC_iterate (itset_entry, itset->inferiors, ix, entry); ++ix)
+ if (inf == entry->inferior)
+ {
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ {
+ new_entry.inferior = inf;
+ new_entry.threads = NULL;
+ entry = VEC_safe_push (itset_entry, itset->inferiors, &new_entry);
+ }
+
+ add_threads_to_itset (entry, lo_tidspec, hi_tidspec);
+
+ /* The inclusion of an exec's own inferior directs the addition of
+ all inferiors derived from that exec. */
+ if (inf->exec && inf->exec->inferior == inf)
+ {
+ for (inf2 = inferior_list; inf2; inf2 = inf2->next)
+ {
+ if (inf2 != inf && inf2->exec == inf->exec)
+ add_inferior_to_itset (itset, inf2, lo_tidspec, hi_tidspec);
+ }
+ }
+}
+
+/* Encapsulation for data passed to thread callback. */
+
+struct addbits
+{
+ struct itset_entry *entry;
+ int lo, hi;
+};
+
+static int
+itset_add_thread_callback (struct thread_info *thread, void *data)
+{
+ struct addbits *addbits = data;
+ struct itset_entry *entry;
+ struct thread_info *thr;
+ int ix;
+
+ entry = addbits->entry;
+ if ((thread->ptid.pid == entry->inferior->pid)
+ && (addbits->lo < 0
+ || (thread->num >= addbits->lo && thread->num <= addbits->hi)))
+ {
+ /* Skip adding dups of thread info. */
+ for (ix = 0; VEC_iterate (thread_p, entry->threads, ix, thr); ++ix)
+ if (thread == thr)
+ return 0;
+ VEC_safe_push (thread_p, entry->threads, thread);
+ }
+ return 0;
+}
+
+void
+add_threads_to_itset (struct itset_entry *entry,
+ char *lo_tidspec, char *hi_tidspec)
+{
+ struct addbits data;
+ int lo_tid, hi_tid;
+ char *endspec;
+
+ /* Treat a missing thread spec as equivalent to '*'. */
+ if (!lo_tidspec)
+ lo_tidspec = "*";
+
+ data.entry = entry;
+ if (strcmp (lo_tidspec, "*") == 0
+ || (hi_tidspec && strcmp (hi_tidspec, "*") == 0))
+ {
+ data.lo = data.hi = -1;
+ }
+ else
+ {
+ data.lo = strtol (lo_tidspec, &endspec, 10);
+ data.hi = data.lo;
+ if (hi_tidspec)
+ data.hi = strtol (hi_tidspec, &endspec, 10);
+ /* (should detect non-empty endspec and warn) */
+ }
+ iterate_over_threads (itset_add_thread_callback, &data);
+}
+
+/* Parse an inferior.thread pair and return it as a two-element struct. */
+
+struct itid_pair
+parse_itset_itid (struct itset *itset)
+{
+ struct itid_pair rslt;
+
+ rslt.infspec = parse_itset_iid (itset);
+ rslt.tidspec = NULL;
+ if (*(itset->parse_head) == '.')
+ {
+ ++(itset->parse_head);
+ rslt.tidspec = parse_itset_tid (itset);
+ }
+ return rslt;
+}
+
+/* Recognize an inferior id, which can be just about anything; not
+ much to do here, pass it back up for semantic analysis. */
+
+char *
+parse_itset_iid (struct itset *itset)
+{
+ char *endpos = itset->parse_head;
+ char *term;
+
+ while (strchr ("],:.", *endpos) == NULL)
+ ++endpos;
+ /* FIXME arrange to discard */
+ term = savestring (itset->parse_head, endpos - itset->parse_head);
+ itset->parse_head = endpos;
+
+ return term;
+}
+
+/* Parse a thread id, which may be a decimal number or "*". */
+
+char *
+parse_itset_tid (struct itset *itset)
+{
+ char *endpos = itset->parse_head;
+ char *term, *endterm;
+
+ while (strchr ("],:.", *endpos) == NULL)
+ ++endpos;
+ /* FIXME arrange to discard */
+ term = savestring (itset->parse_head, endpos - itset->parse_head);
+ itset->parse_head = endpos;
+ if (strcmp (term, "*") == 0)
+ return term;
+ else
+ {
+ strtol (term, &endterm, 10);
+ if (*endterm == '\0')
+ return term;
+ else
+ {
+ warning ("'%s' is not a valid thread id\n", term);
+ itset->parse_errors = 1;
+ return NULL;
+ }
+ }
+}
+
+struct itset *
+make_itset_from_spec (char *spec)
+{
+ int len;
+ struct itset *itset;
+
+ /* Canonicalize by removing brackets. */
+ if (spec[0] == '[')
+ ++spec;
+ len = strlen (spec);
+ if (spec[len - 1] == ']')
+ --len;
+ /* FIXME arrange to discard later */
+ spec = savestring (spec, len);
+
+ itset = new_itset (spec);
+
+ return itset;
+}
+
+int
+itset_is_empty (struct itset *itset)
+{
+ return (itset == NULL || VEC_length (itset_entry, itset->inferiors) == 0);
+}
+
+/* See if a given inferior and thread is in the i/t set. */
+
+int
+itset_member (struct itset *itset, struct inferior *inf, int thread_id)
+{
+ struct itset_entry *entry;
+ struct thread_info *thr;
+ int ix, iy;
+
+ /* FIXME: this will be a performance problem when we have thousands
+ of inferiors. */
+ for (ix = 0; VEC_iterate (itset_entry, itset->inferiors, ix, entry); ++ix)
+ if (inf == entry->inferior)
+ {
+ for (iy = 0; VEC_iterate (thread_p, entry->threads, iy, thr); ++ix)
+ if (thread_id == thr->num)
+ return 1;
+ }
+ return 0;
+}
+
+/* Return the first inferior found in the i/t set. */
+
+struct inferior *
+first_inferior_in_set (struct itset *itset)
+{
+ struct itset_entry *entry;
+
+ if (!itset
+ || !itset->inferiors
+ || VEC_length (itset_entry, itset->inferiors) == 0)
+ return NULL;
+
+ entry = VEC_index (itset_entry, itset->inferiors, 0);
+
+ if (!entry)
+ return NULL;
+
+ return entry->inferior;
+}
+
+/* Debugging dump for i/t sets. */
+
+void
+dump_itset (struct itset *itset)
+{
+ struct itset_entry *entry;
+ struct inferior *inf;
+ struct thread_info *thr;
+ int ix, iy;
+
+ if (!itset)
+ {
+ printf_unfiltered ("null itset\n");
+ return;
+ }
+
+ printf_unfiltered ("i/t set specified as '%s' (%s)",
+ itset->spec, (itset->dynamic ? "dynamic" : "static"));
+
+ printf_unfiltered (" {%di", VEC_length (itset_entry, itset->inferiors));
+ for (ix = 0; VEC_iterate (itset_entry, itset->inferiors, ix, entry); ++ix)
+ {
+ printf_unfiltered (",%d", entry->inferior->num);
+ printf_unfiltered (".{%dt", VEC_length (thread_p, entry->threads));
+ for (iy = 0; VEC_iterate (thread_p, entry->threads, iy, thr); ++iy)
+ printf_unfiltered (",%d", thr->num);
+ printf_unfiltered ("}");
+ }
+ printf_unfiltered ("}");
+ printf_unfiltered ("\n");
+}
+
void
_initialize_inferiors (void)
{
- add_info ("inferiors", info_inferiors_command,
- _("IDs of currently known inferiors."));
+ add_com ("add-inferior", no_class, add_inferior_command, _("\
+Add more inferiors to be run for EXEC."));
+
+ add_com ("remove-inferior", no_class, remove_inferior_command, _("\
+Remove the inferiors in ITSET."));
+
+ add_com ("name-inferior", no_class, name_inferior_command, _("\
+Change the name of inferior OLDNAME to NEWNAME."));
+
+ add_com ("set-exec", no_class, set_inferior_exec_command, _("\
+Change the exec of inferiors in ITSET to EXECNAME"));
+
+ add_info ("inferiors", info_inferiors_command, _("\
+Info about currently known inferiors."));
add_setshow_boolean_cmd ("inferior-events", no_class,
&print_inferior_events, _("\
struct gdbarch;
struct regcache;
struct ui_out;
+struct gdb_environ;
/* For bpstat. */
#include "breakpoint.h"
/* For struct frame_id. */
#include "frame.h"
+struct exec;
+
/* Structure in which to save the status of the inferior. Create/Save
through "save_inferior_status", restore through
"restore_inferior_status".
the ptid_t.pid member of threads of this inferior. */
int pid;
+ char *name;
+
+ /* Nonzero if this inferior can be removed by the user. */
+ int removable;
+
+ struct exec *exec;
+
+ char *args;
+ int argc;
+ char **argv;
+
+ struct gdb_environ *inf_environ;
+
+ char *io_terminal;
+
/* See the definition of stop_kind above. */
enum stop_kind stop_soon;
struct private_inferior *private;
};
+typedef struct inferior *inferior_p;
+DEF_VEC_P(inferior_p);
+
+/* Scratchpad used to smuggle an inferior down to targets. */
+extern struct inferior *tmp_inf;
+
+typedef struct thread_info *thread_p;
+DEF_VEC_P(thread_p);
+
+/* This struct is one entry in the i/t set's vectors of inferiors and
+ their associated threads. */
+
+struct itset_entry
+{
+ /* The inferior for this entry. */
+ struct inferior *inferior;
+
+ /* The vector of threads belonging to this inferior. */
+ VEC(thread_p) *threads;
+};
+
+typedef struct itset_entry itset_entry;
+DEF_VEC_O(itset_entry);
+
+/* An inferior/thread set, or itset for short, is a collection of
+ inferiors (running or not) and threads associated with those
+ inferiors. Itsets are used for various things, including to
+ restrict the effects of commands to only particular programs,
+ processes, or threads, and to set context and defaults for the
+ user. The syntax for itsets includes wildcards, range matching, and
+ lists, so that users can more easily choose the membership of a
+ set. For instance, "[4.*,5.6:5.9]" specifies all threads of process
+ 4, and any threads with a number between 6 and 9, inclusive, in
+ process 5. */
+
+struct itset
+{
+ /* A user-assigned name for the set. This will be NULL for unnamed
+ sets. */
+ char *name;
+
+ /* True if the set is to be constructed on-the-fly. */
+ int dynamic;
+
+ /* Instructions for construction of an itset. */
+ char *spec;
+
+ /* The vector of inferiors belonging to this set. */
+ VEC(itset_entry) *inferiors;
+
+ /* Pointer to the location of the next char in the spec string
+ during parsing. */
+ char *parse_head;
+
+ /* Set to 1 when the spec has been parsed. */
+ int parsed;
+
+ /* Any parse failures set this to 1. */
+ int parse_errors;
+};
+
/* Create an empty inferior list, or empty the existing one. */
extern void init_inferior_list (void);
/* Returns true if the inferior list is not empty. */
extern int have_inferiors (void);
+extern int have_real_inferiors (void);
+
+extern int number_of_inferiors (void);
+
+extern int number_of_inferiors (void);
+
/* Return a pointer to the current inferior. It is an error to call
this if there is no current inferior. */
extern struct inferior *current_inferior (void);
+extern void set_inferior_name (struct inferior *inf, char *name);
+
+extern void set_inferior_exec (struct inferior *inf, struct exec *exec);
+
+extern void set_inferior_exec (struct inferior *inf, struct exec *exec);
+
+/* Itset definitions. */
+
+extern struct itset *current_itset;
+
+extern struct itset *new_itset (char *spec);
+
+extern struct itset *make_itset_from_spec (char *spec);
+
+extern void update_itset (struct itset *itset);
+
+extern int itset_is_empty (struct itset *itset);
+
+extern int itset_member (struct itset *itset, struct inferior *inf, int thread_id);
+
+extern struct inferior *first_inferior_in_set (struct itset *itset);
+
+extern struct inferior *first_inferior_in_set (struct itset *itset);
+
+extern void dump_itset (struct itset *itset);
+
+extern struct inferior *inferior_list;
+
+extern struct inferior *inferior_list;
+
#endif /* !defined (INFERIOR_H) */
}
pending_follow;
+int detach_fork = 1; /* Default behavior is to detach
+ newly forked processes (legacy). */
+
static const char follow_fork_mode_child[] = "child";
static const char follow_fork_mode_parent[] = "parent";
struct expression;
struct ui_file;
struct value_print_options;
+struct exec;
#define MAX_FORTRAN_DIMS 7 /* Maximum number of F77 array dims */
struct symbol *(*la_lookup_symbol_nonlocal) (const char *,
const char *,
const struct block *,
+ const struct exec *,
const domain_enum);
/* Find the definition of the type with the given name. */
#include "symtab.h"
#include "frame.h"
#include "command.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "source.h"
+#include "inferior.h"
#include "demangle.h"
#include "value.h"
#include "completer.h"
static void set_flags (char *arg, int *is_quoted, char **paren_pointer);
+extern struct exec *decode_sharp (char **argptr);
+
static struct symtabs_and_lines decode_indirect (char **argptr);
static char *locate_first_half (char **argptr, int *is_quote_enclosed);
int funfirstline,
char ***canonical,
struct symtab *file_symtab,
+ struct exec *exec,
int *not_found_ptr);
static struct
char **canonical_arr;
char *canonical_name;
char *filename;
+ char *exec_name;
+ int exec_space;
+
struct symtab *s = sal->symtab;
if (s == (struct symtab *) NULL
canonical_arr = (char **) xmalloc (sizeof (char *));
*canonical = canonical_arr;
+ /* Maybe add the exec's name to the front of the canonical name. */
+ exec_name = NULL;
+ exec_space = 0;
+ if (number_of_execs () > 1
+ && s->objfile
+ && s->objfile->exec)
+ {
+ exec_name = s->objfile->exec->shortname;
+ exec_space = strlen (exec_name) + 2;
+ }
+
filename = s->filename;
if (symname != NULL)
{
- canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2);
- sprintf (canonical_name, "%s:%s", filename, symname);
+ canonical_name = xmalloc (exec_space + strlen (filename) + strlen (symname) + 2);
+ if (exec_name)
+ sprintf (canonical_name, "#%s#", exec_name);
+ sprintf (canonical_name + exec_space, "%s:%s", filename, symname);
}
else
{
- canonical_name = xmalloc (strlen (filename) + 30);
- sprintf (canonical_name, "%s:%d", filename, sal->line);
+ canonical_name = xmalloc (exec_space + strlen (filename) + 30);
+ if (exec_name)
+ sprintf (canonical_name, "#%s#", exec_name);
+ sprintf (canonical_name + exec_space, "%s:%d", filename, sal->line);
}
canonical_arr[0] = canonical_name;
}
char *q;
/* If a file name is specified, this is its symtab. */
struct symtab *file_symtab = NULL;
-
+ struct exec *exec;
char *copy;
/* This is NULL if there are no parens in *ARGPTR, or a pointer to
the closing parenthesis if there are parens. */
/* Defaults have defaults. */
initialize_defaults (&default_symtab, &default_line);
-
+
+ /* Start with a plausible default for the executable. */
+ exec = (number_of_execs () > 1 ? current_exec : NULL);
+
+ if (**argptr == '#')
+ exec = decode_sharp (argptr);
+
/* See if arg is *PC. */
if (**argptr == '*')
If file specified, use that file's per-file block to start with. */
return decode_variable (copy, funfirstline, canonical,
- file_symtab, not_found_ptr);
+ file_symtab, exec, not_found_ptr);
}
\f
\f
+/* The #-sign introduces a specification of an executable. */
+
+struct exec *
+decode_sharp (char **argptr)
+{
+ char *exec_spec, *spec_end;
+ struct exec *exec = NULL;
+
+ /* Skip over the '#'. */
+ (*argptr)++;
+ exec_spec = *argptr;
+ spec_end = strchr (exec_spec, '#');
+ if (!spec_end)
+ error (_("Unmatched '#'."));
+ exec = find_exec_by_substr (exec_spec, spec_end);
+ if (!exec)
+ {
+ char *name = savestring (exec_spec, spec_end - exec_spec);
+ error (_("No exec named `%s'"), name);
+ }
+ *argptr = spec_end + 1;
+ return exec;
+}
+
/* Decode arg of the form *PC. */
static struct symtabs_and_lines
{
struct symtabs_and_lines values;
CORE_ADDR pc;
-
+
(*argptr)++;
pc = parse_and_eval_address_1 (argptr);
static struct symtabs_and_lines
decode_variable (char *copy, int funfirstline, char ***canonical,
- struct symtab *file_symtab, int *not_found_ptr)
+ struct symtab *file_symtab, struct exec *exec, int *not_found_ptr)
{
struct symbol *sym;
struct minimal_symbol *msymbol;
- sym = lookup_symbol (copy,
+ sym = lookup_symbol_in_exec (copy,
(file_symtab
? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
STATIC_BLOCK)
: get_selected_block (0)),
+ exec,
VAR_DOMAIN, 0);
if (sym != NULL)
return symbol_found (funfirstline, canonical, copy, sym, file_symtab);
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ msymbol = lookup_minimal_symbol_in_exec (copy, NULL, exec);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
{
struct blockvector *bv = BLOCKVECTOR (SYMBOL_SYMTAB (sym));
struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
- if (lookup_block_symbol (b, copy, NULL, VAR_DOMAIN) != NULL)
- build_canonical_line_spec (values.sals, copy, canonical);
+ if (lookup_block_symbol (b, copy, NULL, VAR_DOMAIN) != NULL
+ || number_of_execs () > 1)
+ {
+ build_canonical_line_spec (values.sals, copy, canonical);
+ }
}
+ else if (number_of_execs () > 1)
+ build_canonical_line_spec (values.sals, copy, canonical);
return values;
}
else
memset (&values.sals[0], 0, sizeof (values.sals[0]));
values.sals[0].symtab = SYMBOL_SYMTAB (sym);
values.sals[0].line = SYMBOL_LINE (sym);
+ if (number_of_execs () > 1)
+ build_canonical_line_spec (values.sals, copy, canonical);
return values;
}
else
#include "gdb_dirent.h"
#include <ctype.h>
+extern int detach_fork;
+
struct fork_info *fork_list;
static int highest_fork_num;
/* Prevent warning from -Wmissing-prototypes. */
extern void _initialize_linux_fork (void);
-int detach_fork = 1; /* Default behavior is to detach
- newly forked processes (legacy). */
-
/* Fork list data structure: */
struct fork_info
{
struct fork_info *fork_list;
-extern int detach_fork;
-
#include "event-loop.h"
#include "event-top.h"
+extern int detach_fork;
+
#ifdef HAVE_PERSONALITY
# include <sys/personality.h>
# if !HAVE_DECL_ADDR_NO_RANDOMIZE
struct target_waitstatus last_status;
int has_vforked;
int parent_pid, child_pid;
+ struct inferior *child_inf, *parent_inf;
+ struct exec *parent_exec = NULL;
if (target_can_async_p ())
target_async (NULL, 0);
parent_pid = ptid_get_pid (last_ptid);
child_pid = PIDGET (last_status.value.related_pid);
+ parent_inf = find_inferior_pid (parent_pid);
+ if (parent_inf)
+ parent_exec = parent_inf->exec;
+
if (! follow_child)
{
/* We're already attached to the parent, by default. */
struct fork_info *fp;
/* Add process to GDB's tables. */
- add_inferior (child_pid);
+ child_inf = add_inferior (child_pid);
+
+ set_inferior_exec (child_inf, parent_exec);
/* Retain child fork in ptrace (stopped) state. */
fp = find_fork_pid (child_pid);
target_detach (NULL, 0);
inferior_ptid = ptid_build (child_pid, child_pid, 0);
- add_inferior (child_pid);
+ child_inf = add_inferior (child_pid);
+
+ set_inferior_exec (child_inf, parent_exec);
/* Reinstall ourselves, since we might have been removed in
target_detach (which does other necessary cleanup). */
#include "bfd.h"
#include "exceptions.h"
#include "gdbthread.h"
+#include "exec.h"
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
return err;
/* Set up the breakpoint. */
- gdb_assert (exec_bfd);
+ gdb_assert (first_exec && first_exec->ebfd);
(*bp) = (gdbarch_convert_from_func_ptr_addr
(current_gdbarch,
/* Do proper sign extension for the target. */
- (bfd_get_sign_extend_vma (exec_bfd) > 0
+ (bfd_get_sign_extend_vma (first_exec->ebfd) > 0
? (CORE_ADDR) (intptr_t) notify.u.bptaddr
: (CORE_ADDR) (uintptr_t) notify.u.bptaddr),
¤t_target));
/* Cast assuming host == target. Joy. */
/* Do proper sign extension for the target. */
- gdb_assert (exec_bfd);
- return (bfd_get_sign_extend_vma (exec_bfd) > 0
+ gdb_assert (first_exec && first_exec->ebfd);
+ return (bfd_get_sign_extend_vma (first_exec->ebfd) > 0
? (CORE_ADDR) (intptr_t) address
: (CORE_ADDR) (uintptr_t) address);
}
#include "top.h"
#include "target.h"
#include "inferior.h"
+#include "exec.h"
+extern struct exec *last_exec_created;
#include "symfile.h"
#include "gdbcore.h"
-
+extern int is_core_file (char *filename);
#include "exceptions.h"
#include "getopt.h"
char *execarg = NULL;
char *pidarg = NULL;
char *corearg = NULL;
- char *pid_or_core_arg = NULL;
char *cdarg = NULL;
char *ttyarg = NULL;
+ char **miscargs = NULL;
+ int nmisc = 0;
/* These are static so that we can take their address in an initializer. */
static int print_help;
dirsize = 1;
dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg));
ndir = 0;
+ miscargs = (char **) xmalloc (argc * sizeof (char *));
+ nmisc = 0;
quit_flag = 0;
line = (char *) xmalloc (linesize);
}
else
{
- /* OK, that's all the options. */
-
- /* The first argument, if specified, is the name of the
- executable. */
- if (optind < argc)
+ /* OK, that's all the options. The remaining arguments will be
+ a mix of execnames, pids, and corefiles. */
+ while (optind < argc)
{
- symarg = argv[optind];
- execarg = argv[optind];
+ miscargs[nmisc++] = argv[optind];
optind++;
}
-
- /* If the user hasn't already specified a PID or the name of a
- core file, then a second optional argument is allowed. If
- present, this argument should be interpreted as either a
- PID or a core file, whichever works. */
- if (pidarg == NULL && corearg == NULL && optind < argc)
- {
- pid_or_core_arg = argv[optind];
- optind++;
- }
-
- /* Any argument left on the command line is unexpected and
- will be ignored. Inform the user. */
- if (optind < argc)
- fprintf_unfiltered (gdb_stderr, _("\
-Excess command line arguments ignored. (%s%s)\n"),
- argv[optind],
- (optind == argc - 1) ? "" : " ...");
}
if (batch)
quiet = 1;
catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL);
}
+ last_exec_created = NULL;
+
if (corearg && pidarg)
error (_("\
Can't attach to process and specify a core file at the same time."));
else if (pidarg != NULL)
catch_command_errors (attach_command, pidarg,
!batch, RETURN_MASK_ALL);
- else if (pid_or_core_arg)
- {
- /* The user specified 'gdb program pid' or gdb program core'.
- If pid_or_core_arg's first character is a digit, try attach
- first and then corefile. Otherwise try just corefile. */
- if (isdigit (pid_or_core_arg[0]))
- {
- if (catch_command_errors (attach_command, pid_or_core_arg,
- !batch, RETURN_MASK_ALL) == 0)
- catch_command_errors (core_file_command, pid_or_core_arg,
- !batch, RETURN_MASK_ALL);
- }
- else /* Can't be a pid, better be a corefile. */
- catch_command_errors (core_file_command, pid_or_core_arg,
- !batch, RETURN_MASK_ALL);
- }
+ /* Handle random mixes of executables, corefiles, and pids. */
+ {
+ int require_exec = 1;
+ for (i = 0; i < nmisc; ++i)
+ {
+ if (!require_exec)
+ {
+ /* Digits might indicate a pid to attach to, so try that. */
+ if (pidarg == NULL
+ && isdigit (*(miscargs[i]))
+ && (catch_command_errors (attach_command, miscargs[i],
+ !batch, RETURN_MASK_ALL)))
+ {
+ require_exec = 1;
+ continue;
+ }
+ /* OK, then maybe it's a corefile. */
+ else if (corearg == NULL
+ && is_core_file (miscargs[i])
+ && catch_command_errors (core_file_command, miscargs[i],
+ 0, RETURN_MASK_ALL))
+ {
+ require_exec = 1;
+ continue;
+ }
+ /* Presumably it's yet another executable, drop through. */
+ else
+ require_exec = 1;
+ }
+ if (require_exec)
+ {
+ if (catch_command_errors (exec_file_add, miscargs[i], !batch,
+ RETURN_MASK_ALL))
+ catch_command_errors (symbol_file_add_main, miscargs[i], 0,
+ RETURN_MASK_ALL);
+ last_exec_created = NULL;
+ /* The executable may be followed by anything. */
+ require_exec = 0;
+ }
+ }
+ }
if (ttyarg != NULL)
catch_command_errors (tty_command, ttyarg, !batch, RETURN_MASK_ALL);
#include "gdbcore.h"
#include "expression.h" /* For language.h */
#include "language.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "value.h"
static void
maintenance_info_sections (char *arg, int from_tty)
{
- if (exec_bfd)
+ int allobj;
+ struct exec *exec;
+ int ix;
+
+ allobj = (arg && *arg && match_substring (arg, "ALLOBJ"));
+
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
{
printf_filtered (_("Exec file:\n"));
- printf_filtered (" `%s', ", bfd_get_filename (exec_bfd));
+ printf_filtered (" `%s', ", exec->name);
wrap_here (" ");
- printf_filtered (_("file type %s.\n"), bfd_get_target (exec_bfd));
- if (arg && *arg && match_substring (arg, "ALLOBJ"))
- {
- struct objfile *ofile;
- struct obj_section *osect;
-
- /* Only this function cares about the 'ALLOBJ' argument;
- if 'ALLOBJ' is the only argument, discard it rather than
- passing it down to print_objfile_section_info (which
- wouldn't know how to handle it). */
- if (strcmp (arg, "ALLOBJ") == 0)
- arg = NULL;
+ printf_filtered (_("file type %s.\n"), bfd_get_target (exec->ebfd));
+ if (!allobj)
+ bfd_map_over_sections (exec->ebfd, print_bfd_section_info, arg);
+ }
- ALL_OBJFILES (ofile)
+ if (allobj)
+ {
+ struct objfile *ofile;
+ struct obj_section *osect;
+
+ /* Only this function cares about the 'ALLOBJ' argument;
+ if 'ALLOBJ' is the only argument, discard it rather than
+ passing it down to print_objfile_section_info (which
+ wouldn't know how to handle it). */
+
+ if (strcmp (arg, "ALLOBJ") == 0)
+ arg = NULL;
+
+ ALL_OBJFILES (ofile)
+ {
+ printf_filtered (_(" Object file: %s\n"),
+ bfd_get_filename (ofile->obfd));
+ ALL_OBJFILE_OSECTIONS (ofile, osect)
{
- printf_filtered (_(" Object file: %s\n"),
- bfd_get_filename (ofile->obfd));
- ALL_OBJFILE_OSECTIONS (ofile, osect)
- {
- print_objfile_section_info (ofile->obfd, osect, arg);
- }
+ print_objfile_section_info (ofile->obfd, osect, arg);
}
}
- else
- bfd_map_over_sections (exec_bfd, print_bfd_section_info, arg);
}
if (core_bfd)
_("Print dump of current object file definitions."),
&maintenanceprintlist);
+ add_cmd ("execs", class_maintenance, maintenance_print_execs,
+ _("Print dump of current executable file definitions."),
+ &maintenanceprintlist);
+
add_cmd ("symtabs", class_maintenance, maintenance_info_symtabs, _("\
List the full symbol tables for all object files.\n\
This does not include information about individual symbols, blocks, or\n\
Obviously, there must be distinct mangled names for each of these,
but the demangled names are all the same: S::S or S::~S. */
+extern struct minimal_symbol *lookup_minimal_symbol_in_exec_1 (const char *name,
+ const char *sfile,
+ struct objfile *objf,
+ struct exec *exec);
+
struct minimal_symbol *
lookup_minimal_symbol (const char *name, const char *sfile,
struct objfile *objf)
+{
+ return lookup_minimal_symbol_in_exec_1 (name, sfile, objf, NULL);
+}
+
+struct minimal_symbol *
+lookup_minimal_symbol_in_exec (const char *name, const char *sfile,
+ struct exec *exec)
+{
+ return lookup_minimal_symbol_in_exec_1 (name, sfile, NULL, exec);
+}
+
+struct minimal_symbol *
+lookup_minimal_symbol_in_exec_1 (const char *name, const char *sfile,
+ struct objfile *objf, struct exec *exec)
{
struct objfile *objfile;
struct minimal_symbol *msymbol;
objfile != NULL && found_symbol == NULL;
objfile = objfile->next)
{
+ /* If an exec is specified, limit to objfiles associated with it. */
+ if (exec != NULL && exec != objfile->exec)
+ continue;
+
if (objf == NULL || objf == objfile
|| objf->separate_debug_objfile == objfile)
{
objfile->name = xstrdup ("<<anonymous objfile>>");
}
+ objfile->exec = NULL;
+
/* Initialize the section indexes for this objfile, so that we can
later detect if they are used w/o being properly assigned to. */
#include "gdb_obstack.h" /* For obstack internals. */
#include "symfile.h" /* For struct psymbol_allocation_list */
+#include "vec.h"
struct bcache;
struct htab;
struct symtab;
struct objfile_data;
+struct exec;
/* This structure maintains information on a per-objfile basis about the
"entry point" of the objfile, and the scope within which the entry point
unsigned short flags;
+ /* The executable associated with this objfile, if known. */
+
+ struct exec *exec;
+
/* Each objfile points to a linked list of symtabs derived from this file,
one symtab structure for each compilation unit (source file). Each link
in the symtab list contains a backpointer to this objfile. */
extern struct objfile *symfile_objfile;
+typedef struct objfile *objfile_p;
+DEF_VEC_P(objfile_p);
+
/* The object file that contains the runtime common minimal symbols
for SunOS4. Note that this objfile has no associated BFD. */
(obj) != NULL? ((nxt)=(obj)->next,1) :0; \
(obj) = (nxt))
+#define ALL_OBJFILES_FOR_EXEC(obj,ex) \
+ for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next) \
+ if ((ex) == NULL || (obj)->exec == NULL || (obj)->exec == (ex))
+
/* Traverse all symtabs in one objfile. */
#define ALL_OBJFILE_SYMTABS(objfile, s) \
ALL_OBJFILE_SYMTABS (objfile, s) \
if ((s)->primary)
+#define ALL_PRIMARY_SYMTABS_FOR_EXEC(objfile, ex, s) \
+ ALL_OBJFILES_FOR_EXEC (objfile, ex) \
+ ALL_OBJFILE_SYMTABS (objfile, s) \
+ if ((s)->primary)
+
/* Traverse all psymtabs in all objfiles. */
#define ALL_PSYMTABS(objfile, p) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)
+#define ALL_PSYMTABS_FOR_EXEC(objfile, ex, p) \
+ ALL_OBJFILES_FOR_EXEC (objfile, ex) \
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+
/* Traverse all minimal symbols in all objfiles. */
#define ALL_MSYMBOLS(objfile, m) \
#include "gdb_string.h"
#include <ctype.h>
#include <fcntl.h>
+#include "exec.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
struct start_remote_args *args = opaque;
struct remote_state *rs = get_remote_state ();
struct packet_config *noack_config;
+ struct inferior *inf;
char *wait_status = NULL;
immediate_quit++; /* Allow user to interrupt it. */
{
int res;
- set_general_thread (inferior_ptid);
+ if (tmp_inf && tmp_inf->pid != ptid_get_pid (inferior_ptid))
+ {
+ ptid_t tmp_ptid;
+ tmp_ptid = ptid_build (tmp_inf->pid, 0, 0);
+ set_general_thread (tmp_ptid);
+ }
+ else
+ set_general_thread (inferior_ptid);
if (should_write)
res = remote_write_bytes (mem_addr, buffer, mem_len);
extended_remote_create_inferior_1 (char *exec_file, char *args,
char **env, int from_tty)
{
+ struct inferior *inf;
+
/* If running asynchronously, register the target file descriptor
with the event loop. */
if (target_can_async_p ())
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
- add_inferior (ptid_get_pid (inferior_ptid));
+ inf = add_inferior (ptid_get_pid (inferior_ptid));
+
+ set_inferior_exec (inf, find_exec_by_name (exec_file));
+
add_thread_silent (inferior_ptid);
target_mark_running (&extended_remote_ops);
char *p2;
char query_type;
- set_general_thread (inferior_ptid);
+
+ if (tmp_inf && tmp_inf->pid != ptid_get_pid (inferior_ptid))
+ {
+ ptid_t tmp_ptid;
+ tmp_ptid = ptid_build (tmp_inf->pid, 0, 0);
+ set_general_thread (tmp_ptid);
+ }
+ else
+ set_general_thread (inferior_ptid);
rs = get_remote_state ();
{
/* XXX: Should we cache these symbols? */
gdb_output_sym =
- lookup_symbol_global ("gdb_output", NULL, NULL, VAR_DOMAIN);
+ lookup_symbol_global ("gdb_output", NULL, NULL, NULL, VAR_DOMAIN);
gdb_output_len_sym =
- lookup_symbol_global ("gdb_output_length", NULL, NULL, VAR_DOMAIN);
+ lookup_symbol_global ("gdb_output_length", NULL, NULL, NULL, VAR_DOMAIN);
if ((gdb_output_sym == NULL) || (gdb_output_len_sym == NULL))
ret = -1;
around to it.
So: disable breakpoints only if we're using ELF shared libs. */
- if (exec_bfd != NULL
- && bfd_get_flavour (exec_bfd) != bfd_target_aout_flavour)
+ if (first_exec != NULL
+ && bfd_get_flavour (first_exec->ebfd) != bfd_target_aout_flavour)
disable_breakpoints_in_shlibs ();
while (so_list_head)
#include <fcntl.h>
#include "gdbcore.h"
#include "gdb_regex.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "annotate.h"
/* Make the default place to list be the function `main'
if one exists. */
- if (lookup_symbol (main_name (), 0, VAR_DOMAIN, 0))
+ if (lookup_symbol_in_exec (main_name (), 0, current_exec, VAR_DOMAIN, 0))
{
sals = decode_line_spec (main_name (), 1);
sal = sals.sals[0];
current_source_line = 1;
- for (ofp = object_files; ofp != NULL; ofp = ofp->next)
+ ALL_OBJFILES_FOR_EXEC (ofp, current_exec)
{
for (s = ofp->symtabs; s; s = s->next)
{
/* How about the partial symbol tables? */
- for (ofp = object_files; ofp != NULL; ofp = ofp->next)
+ ALL_OBJFILES_FOR_EXEC (ofp, current_exec)
{
for (ps = ofp->psymtabs; ps != NULL; ps = ps->next)
{
if (s->objfile && s->objfile->obfd)
mtime = s->objfile->mtime;
- else if (exec_bfd)
- mtime = exec_bfd_mtime;
+ else if (s->objfile && s->objfile->exec)
+ mtime = s->objfile->exec->ebfd_mtime;
if (mtime && mtime < st.st_mtime)
warning (_("Source file is more recent than executable."));
#include "block.h"
#include "observer.h"
#include "exec.h"
+extern struct exec *last_exec_created;
#include "parser-defs.h"
#include "varobj.h"
#include "elf-bfd.h"
make_cleanup (clear_symtab_users_cleanup, 0 /*ignore*/);
/* Since no error yet, throw away the old symbol table. */
-
- if (symfile_objfile != NULL)
+ /* (But not in the multiprocess case.) */
+ if (symfile_objfile != NULL && number_of_execs () <= 1)
{
free_objfile (symfile_objfile);
symfile_objfile = NULL;
/* OK, make it the "real" symbol file. */
symfile_objfile = objfile;
+ /* Use the exec object smuggled through this global (a
+ workaround due to the inability of command processing in
+ main.c to pass additional arguments). */
+ if (last_exec_created)
+ {
+ last_exec_created->objfile = objfile;
+ objfile->exec = last_exec_created;
+ last_exec_created = NULL;
+ }
+
clear_symtab_users ();
}
else
{
if ((have_full_symbols () || have_partial_symbols ())
&& from_tty
- && (symfile_objfile
- ? !query (_("Discard symbol table from `%s'? "),
- symfile_objfile->name)
- : !query (_("Discard symbol table? "))))
+ && !query (_("Discard all symbol tables? ")))
error (_("Not confirmed."));
free_all_objfiles ();
symfile_objfile = NULL;
if (from_tty)
- printf_unfiltered (_("No symbol file now.\n"));
+ printf_unfiltered (_("No symbol files now.\n"));
}
struct build_id
/* We need to do this whenever any symbols go away. */
make_cleanup (clear_symtab_users_cleanup, 0 /*ignore*/);
- if (exec_bfd != NULL && strcmp (bfd_get_filename (objfile->obfd),
- bfd_get_filename (exec_bfd)) == 0)
- {
- /* Reload EXEC_BFD without asking anything. */
-
- exec_file_attach (bfd_get_filename (objfile->obfd), 0);
- }
+ /* If this objfile is also one of our executables,
+ update that. */
+ if (objfile->exec
+ && objfile->exec->objfile == objfile)
+ exec_file_update (objfile->exec);
/* Clean up any state BFD has sitting around. We don't need
to close the descriptor but BFD lacks a way of closing the
}
}
+/* Given a pc and inferior, return a section. */
+
+struct obj_section *
+find_pc_inf_sect (CORE_ADDR pc, struct inferior *inf)
+{
+ struct objfile *objfile;
+ struct obj_section *osect;
+ asection *section;
+ int size;
+
+ ALL_OBJSECTIONS (objfile, osect)
+ {
+ if (!inf || objfile->exec == inf->exec)
+ {
+ section = osect->the_bfd_section;
+ if (section)
+ {
+ size = bfd_get_section_size (section);
+ if (section->vma <= pc && pc < section->vma + size)
+ return osect;
+ }
+ }
+ }
+ return NULL;
+}
+
/* OVERLAYS:
The following code implements an abstraction for debugging overlay sections.
extern int get_section_index (struct objfile *, char *);
+extern struct obj_section *find_pc_inf_sect (CORE_ADDR, struct inferior *);
+
/* Utility functions for overlay sections: */
extern enum overlay_debugging_state
{
#include "symtab.h"
#include "gdbtypes.h"
#include "bfd.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "breakpoint.h"
gdb_print_host_address (objfile, gdb_stdout);
printf_filtered (", bfd at ");
gdb_print_host_address (objfile->obfd, gdb_stdout);
- printf_filtered (", %d minsyms\n\n",
+ printf_filtered (", %d minsyms\n",
objfile->minimal_symbol_count);
+ if (objfile->exec)
+ printf_filtered (" Exec file %s", objfile->exec->name);
+ else
+ printf_filtered (" (No exec file)");
+ printf_filtered ("\n\n");
if (objfile->psymtabs)
{
immediate_quit++;
ALL_OBJFILES (objfile)
dump_objfile (objfile);
+ printf_filtered ("Symfile_objfile is %s, at ",
+ (symfile_objfile ? symfile_objfile->name : "(null)"));
+ gdb_print_host_address (symfile_objfile, gdb_stdout);
+ printf_filtered ("\n");
immediate_quit--;
}
#include "value.h"
#include "symfile.h"
#include "objfiles.h"
+#include "exec.h"
#include "gdbcmd.h"
#include "call-cmds.h"
#include "gdb_regex.h"
static struct symbol *lookup_symbol_aux (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain,
enum language language,
int *is_a_field_of_this);
struct symbol *lookup_symbol_aux_symtabs (int block_index,
const char *name,
const char *linkage_name,
+ const struct exec *exec,
const domain_enum domain);
static
struct symbol *lookup_symbol_aux_psymtabs (int block_index,
const char *name,
const char *linkage_name,
+ const struct exec *exec,
const domain_enum domain);
static int file_matches (char *, char **, int);
sal->line = 0;
sal->pc = 0;
sal->end = 0;
+ sal->inferior = NULL;
sal->explicit_pc = 0;
sal->explicit_line = 0;
}
find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
{
struct objfile *objfile;
+ struct exec *exec;
struct minimal_symbol *msymbol;
/* If we know that this is not a text address, return failure. This is
/* Try just the PSYMTABS_ADDRMAP mapping first as it has better granularity
than the later used TEXTLOW/TEXTHIGH one. */
+ exec = NULL;
+#if 0
+ if (section)
+ {
+ int ix;
+ struct exec *ex;
+ for (ix = 0; VEC_iterate(exec_p, execs, ix, ex); ++ix)
+ if (strcmp (section->owner->filename, ex->ebfd->filename) == 0)
+ {
+ exec = ex;
+ break;
+ }
+ }
+#endif
- ALL_OBJFILES (objfile)
+ ALL_OBJFILES_FOR_EXEC (objfile, exec)
if (objfile->psymtabs_addrmap != NULL)
{
struct partial_symtab *pst;
present for non-DWARF2 debug infos not supporting PSYMTABS_ADDRMAP in GDB
so far. */
- ALL_OBJFILES (objfile)
+ ALL_OBJFILES_FOR_EXEC (objfile, exec)
{
struct partial_symtab *pst;
variable and thus can probably assume it will never hit the C++
code). */
+extern struct symbol *
+lookup_symbol_in_language_1 (const char *name, const struct block *block,
+ const struct exec *exec,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this);
+
struct symbol *
lookup_symbol_in_language (const char *name, const struct block *block,
const domain_enum domain, enum language lang,
int *is_a_field_of_this)
+{
+ return lookup_symbol_in_language_1 (name, block, current_exec, domain, lang,
+ is_a_field_of_this);
+}
+
+struct symbol *
+lookup_symbol_in_exec_in_language (const char *name, const struct block *block,
+ const struct exec *exec,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
+{
+ return lookup_symbol_in_language_1 (name, block, exec, domain, lang,
+ is_a_field_of_this);
+}
+
+struct symbol *
+lookup_symbol_in_language_1 (const char *name, const struct block *block,
+ const struct exec *exec,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
{
char *demangled_name = NULL;
const char *modified_name = NULL;
modified_name = copy;
}
- returnval = lookup_symbol_aux (modified_name, mangled_name, block,
+ returnval = lookup_symbol_aux (modified_name, mangled_name, block, exec,
domain, lang, is_a_field_of_this);
if (needtofreename)
xfree (demangled_name);
lookup_symbol (const char *name, const struct block *block,
domain_enum domain, int *is_a_field_of_this)
{
+ if (*name == '#')
+ {
+ char *name2 = strchr (name + 1, '#');
+ struct exec *exec = current_exec;
+
+ if (name2)
+ {
+ exec = find_exec_by_substr (((char *) name) + 1, name2);
+ return lookup_symbol_in_exec_in_language (name2 + 1, block, exec, domain,
+ current_language->la_language,
+ is_a_field_of_this);
+ }
+ }
+
return lookup_symbol_in_language (name, block, domain,
current_language->la_language,
is_a_field_of_this);
}
+struct symbol *
+lookup_symbol_in_exec (const char *name, const struct block *block,
+ const struct exec *exec,
+ domain_enum domain, int *is_a_field_of_this)
+{
+ return lookup_symbol_in_exec_in_language (name, block, exec, domain,
+ current_language->la_language,
+ is_a_field_of_this);
+}
+
/* Behave like lookup_symbol except that NAME is the natural name
of the symbol that we're looking for and, if LINKAGE_NAME is
non-NULL, ensure that the symbol's linkage name matches as
static struct symbol *
lookup_symbol_aux (const char *name, const char *linkage_name,
- const struct block *block, const domain_enum domain,
+ const struct block *block, const struct exec *exec,
+ const domain_enum domain,
enum language language, int *is_a_field_of_this)
{
struct symbol *sym;
/* Now do whatever is appropriate for LANGUAGE to look
up static and global variables. */
- sym = langdef->la_lookup_symbol_nonlocal (name, linkage_name, block, domain);
+ sym = langdef->la_lookup_symbol_nonlocal (name, linkage_name, block, exec, domain);
if (sym != NULL)
return sym;
desired name as a file-level static, then do psymtab-to-symtab
conversion on the fly and return the found symbol. */
- sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, linkage_name, domain);
+ sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, linkage_name, exec, domain);
if (sym != NULL)
return sym;
- sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, linkage_name, domain);
+ sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, linkage_name, exec, domain);
if (sym != NULL)
return sym;
static struct symbol *
lookup_symbol_aux_symtabs (int block_index,
const char *name, const char *linkage_name,
+ const struct exec *exec,
const domain_enum domain)
{
struct symbol *sym;
const struct block *block;
struct symtab *s;
- ALL_PRIMARY_SYMTABS (objfile, s)
+ ALL_PRIMARY_SYMTABS_FOR_EXEC (objfile, exec, s)
{
bv = BLOCKVECTOR (s);
block = BLOCKVECTOR_BLOCK (bv, block_index);
static struct symbol *
lookup_symbol_aux_psymtabs (int block_index, const char *name,
const char *linkage_name,
+ const struct exec *exec,
const domain_enum domain)
{
struct symbol *sym;
struct symtab *s;
const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0);
- ALL_PSYMTABS (objfile, ps)
+ ALL_PSYMTABS_FOR_EXEC (objfile, exec, ps)
{
if (!ps->readin
&& lookup_partial_symbol (ps, name, linkage_name,
basic_lookup_symbol_nonlocal (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain)
{
struct symbol *sym;
than that one, so I don't think we should worry about that for
now. */
- sym = lookup_symbol_static (name, linkage_name, block, domain);
+ sym = lookup_symbol_static (name, linkage_name, block, exec, domain);
if (sym != NULL)
return sym;
- return lookup_symbol_global (name, linkage_name, block, domain);
+ return lookup_symbol_global (name, linkage_name, block, exec, domain);
}
/* Lookup a symbol in the static block associated to BLOCK, if there
lookup_symbol_static (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain)
{
const struct block *static_block = block_static_block (block);
lookup_symbol_global (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain)
{
struct symbol *sym = NULL;
if (sym != NULL)
return sym;
- sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, linkage_name, domain);
+ sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, linkage_name, exec, domain);
if (sym != NULL)
return sym;
- return lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, linkage_name, domain);
+ return lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, linkage_name, exec, domain);
}
int
of the desired name as a global, then do psymtab-to-symtab
conversion on the fly and return the found symbol. */
- ALL_PRIMARY_SYMTABS (objfile, s)
+ ALL_PRIMARY_SYMTABS_FOR_EXEC (objfile, current_exec, s)
{
bv = BLOCKVECTOR (s);
block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
conversion on the fly and return the found symbol.
*/
- ALL_PRIMARY_SYMTABS (objfile, s)
+ ALL_PRIMARY_SYMTABS_FOR_EXEC (objfile, current_exec, s)
{
bv = BLOCKVECTOR (s);
block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
struct symtab *best_s = NULL;
struct partial_symtab *ps;
struct objfile *objfile;
+ struct exec *exec;
CORE_ADDR distance = 0;
struct minimal_symbol *msymbol;
It also happens for objfiles that have their functions reordered.
For these, the symtab we are looking for is not necessarily read in. */
- ALL_PRIMARY_SYMTABS (objfile, s)
+ exec = NULL;
+#if 0
+ if (section)
+ {
+ int ix;
+ struct exec *ex;
+ for (ix = 0; VEC_iterate(exec_p, execs, ix, ex); ++ix)
+ if (strcmp (section->owner->filename, ex->ebfd->filename) == 0)
+ {
+ exec = ex;
+ break;
+ }
+ }
+#endif
+
+ ALL_PRIMARY_SYMTABS_FOR_EXEC (objfile, exec, s)
{
bv = BLOCKVECTOR (s);
b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
return val;
}
+struct symtab_and_line
+find_pc_inf_line (CORE_ADDR pc, struct inferior *inf, int notcurrent)
+{
+ struct objfile *objfile;
+ struct obj_section *osect;
+ asection *section;
+ int size;
+ struct symtab_and_line sal;
+
+ if (!inf || number_of_execs () <= 1)
+ return find_pc_line (pc, notcurrent);
+
+ ALL_OBJSECTIONS (objfile, osect)
+ {
+ if (objfile->exec == inf->exec)
+ {
+ section = osect->the_bfd_section;
+ if (section)
+ {
+ size = bfd_get_section_size (section);
+ if (section->vma <= pc && pc < section->vma + size)
+ {
+ sal = find_pc_sect_line (pc, osect, notcurrent);
+ sal.inferior = inf;
+ return sal;
+ }
+ }
+ }
+ }
+ return find_pc_line (pc, notcurrent);
+}
+
/* Backward compatibility (no section) */
struct symtab_and_line
fixup_symbol_section (sym, objfile);
if (funfirstline)
{
+ tmp_inf = ((objfile && objfile->exec) ? objfile->exec->inferior : NULL);
/* Skip "first line" of function (which is actually its prologue). */
pc = find_function_start_pc (gdbarch, pc, SYMBOL_OBJ_SECTION (sym));
+ tmp_inf = NULL;
}
sal = find_pc_sect_line (pc, SYMBOL_OBJ_SECTION (sym), 0);
/* Helper to expand_line_sal below. Appends new sal to SAL,
initializing it from SYMTAB, LINENO and PC. */
-static void
+/*static*/ struct symtab_and_line *
append_expanded_sal (struct symtabs_and_lines *sal,
struct symtab *symtab,
int lineno, CORE_ADDR pc)
{
- CORE_ADDR func_addr, func_end;
+ struct symtab_and_line *new_sal;
sal->sals = xrealloc (sal->sals,
sizeof (sal->sals[0])
* (sal->nelts + 1));
- init_sal (sal->sals + sal->nelts);
- sal->sals[sal->nelts].symtab = symtab;
- sal->sals[sal->nelts].section = NULL;
- sal->sals[sal->nelts].end = 0;
- sal->sals[sal->nelts].line = lineno;
- sal->sals[sal->nelts].pc = pc;
+ new_sal = sal->sals + sal->nelts;
+ init_sal (new_sal);
+ new_sal->symtab = symtab;
+ new_sal->section = NULL;
+ new_sal->end = 0;
+ new_sal->line = lineno;
+ new_sal->pc = pc;
++sal->nelts;
+ return new_sal;
}
/* Compute a set of all sals in
{
exact = 1;
append_expanded_sal (&ret, symtab, lineno, item->pc);
+ ret.sals[ret.nelts-1].section = sal.section;
}
else if (!exact && item->line > lineno
&& (best_item == NULL || item->line < best_item->line))
for (i = 0; i < ret.nelts; ++i)
{
filter[i] = 1;
- blocks[i] = block_for_pc (ret.sals[i].pc);
+ blocks[i] = block_for_pc_sect (ret.sals[i].pc, ret.sals[i].section);
}
for (i = 0; i < ret.nelts; ++i)
struct blockvector;
struct axs_value;
struct agent_expr;
+struct exec;
+struct inferior;
/* Some of the structures in this file are space critical.
The space-critical structures are:
enum language,
int *);
+extern struct symbol *lookup_symbol_in_exec_in_language (const char *,
+ const struct block *,
+ const struct exec *,
+ const domain_enum,
+ enum language,
+ int *);
+
/* lookup a symbol by name (optional block, optional symtab)
in the current language */
extern struct symbol *lookup_symbol (const char *, const struct block *,
const domain_enum, int *);
+extern struct symbol *lookup_symbol_in_exec (const char *, const struct block *,
+ const struct exec *,
+ const domain_enum, int *);
+
/* A default version of lookup_symbol_nonlocal for use by languages
that can't think of anything better to do. */
extern struct symbol *basic_lookup_symbol_nonlocal (const char *,
const char *,
const struct block *,
+ const struct exec *,
const domain_enum);
/* Some helper functions for languages that need to write their own
extern struct symbol *lookup_symbol_static (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain);
/* Lookup a symbol in all files' global blocks (searching psymtabs if
extern struct symbol *lookup_symbol_global (const char *name,
const char *linkage_name,
const struct block *block,
+ const struct exec *exec,
const domain_enum domain);
/* Lookup a symbol within the block BLOCK. This, unlike
const char *,
struct objfile *);
+extern struct minimal_symbol *lookup_minimal_symbol_in_exec (const char *,
+ const char *,
+ struct exec *);
+
extern struct minimal_symbol *lookup_minimal_symbol_text (const char *,
struct objfile *);
CORE_ADDR pc;
CORE_ADDR end;
+ struct inferior *inferior;
int explicit_pc;
int explicit_line;
};
extern struct symtab_and_line find_pc_sect_line (CORE_ADDR,
struct obj_section *, int);
+extern struct symtab_and_line find_pc_inf_line (CORE_ADDR, struct inferior *, int);
+
/* Given a symtab and line number, return the pc there. */
extern int find_line_pc (struct symtab *, int, CORE_ADDR *);
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
+#include "exec.h"
#include "objfiles.h"
#include "gdb_wait.h"
#include "dcache.h"
struct target_ops **t;
struct section_table *old_value;
int old_count;
+ struct exec *exec;
+ int ix;
old_value = target->to_sections;
current_target.to_sections = target->to_sections;
current_target.to_sections_end = target->to_sections_end;
}
+
+ for (ix = 0; VEC_iterate (exec_p, execs, ix, exec); ++ix)
+ {
+ if (exec->sections == old_value)
+ {
+ exec->sections = target->to_sections;
+ exec->sections_end = target->to_sections_end;
+ }
+ }
}
return old_count;
#if !defined (TARGET_H)
#define TARGET_H
+struct exec;
struct objfile;
struct ui_file;
struct mem_attrib;
/* From exec.c */
-extern void print_section_info (struct target_ops *, bfd *);
+extern void print_section_info (struct target_ops *, bfd *, struct exec *);
/* Print a line about the current target. */
+2008-11-20 Stan Shebs <stan@codesourcery.com>
+
+ 2008-09-14 Stan Shebs <stan@codesourcery.com>
+
+ * gdb.gdb/selftest.exp: Update to reflect current sources.
+ * Makefile.in (ALL_SUBDIRS): Add gdb.multi.
+ * configure.ac (AC_OUTPUT): Add gdb.multi/Makefile.
+ * configure: Regenerate.
+
+ * gdb.multi/Makefile.in: New.
+ * gdb.multi/hello.c, hangout.c, goodbye.c: New source files.
+ * gdb.multi/base.exp: New file, basic multiprocess tests.
+
+ 2008-08-25 Stan Shebs <stan@codesourcery.com>
+
+ * config/monitor.exp: Match on rephrased message.
+ * gdb.base/attach.exp: Ditto.
+ * gdb.base/default.exp: Ditto.
+ * lib/gdb.exp: Ditto.
+
2008-11-18 Thiago Jung Bauermann <bauerman@br.ibm.com>
* gdb.arch/ppc-dfp.exp: New file.
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cp gdb.disasm \
gdb.dwarf2 \
- gdb.fortran gdb.server gdb.java gdb.mi \
+ gdb.fortran gdb.server gdb.java gdb.mi gdb.multi \
gdb.objc gdb.opt gdb.pascal gdb.python gdb.threads gdb.trace \
gdb.xml \
$(SUBDIRS)
}
proc gdb_target_exec { } {
- gdb_test "target exec" "No executable file now." "" ".*Kill it.*y or n.*" "y"
+ gdb_test "target exec" "No executable files now." "" ".*Kill it.*y or n.*" "y"
}
#
- ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.multi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
"gdb.server/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.server/Makefile" ;;
"gdb.java/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.java/Makefile" ;;
"gdb.mi/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.mi/Makefile" ;;
+ "gdb.multi/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.multi/Makefile" ;;
"gdb.modula2/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.modula2/Makefile" ;;
"gdb.objc/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.objc/Makefile" ;;
"gdb.opt/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.opt/Makefile" ;;
gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile \
gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile \
gdb.fortran/Makefile gdb.server/Makefile \
- gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile \
+ gdb.java/Makefile gdb.mi/Makefile gdb.multi/Makefile \
+ gdb.modula2/Makefile \
gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
gdb.python/Makefile \
gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile])
set timeout 15
set test "attach1, purging symbols after detach"
gdb_test_multiple "file" "$test" {
- -re "No executable file now.*Discard symbol table.*y or n. $" {
- gdb_test "y" "No symbol file now." "$test"
+ -re "No executable files now.*Discard all symbol tables.*y or n. $" {
+ gdb_test "y" "No symbol files now." "$test"
}
}
set timeout $old_timeout
set test "before attach3, flush symbols"
gdb_test_multiple "symbol" "$test" {
- -re "Discard symbol table from.*y or n. $" {
- gdb_test "y" "No symbol file now." \
+ -re "Discard all symbol tables.*y or n. $" {
+ gdb_test "y" "No symbol files now." \
"$test"
}
- -re "No symbol file now.*$gdb_prompt $" {
+ -re "No symbol files now.*$gdb_prompt $" {
pass "$test"
}
}
- gdb_test "exec" "No executable file now." \
+ gdb_test "exec" "No executable files now." \
"before attach3, flush exec"
gdb_test "attach $testpid" \
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
+set prev_timeout $timeout
+set timeout 600
+verbose "Timeout now 600 sec.\n"
global gdb_prompt
#
remote_exec build "rm -f pi.txt"
+
+# Restore old timeout
+set timeout $prev_timeout
+verbose "Timeout now $timeout sec.\n"
#test exec-file
send_gdb "exec-file\n"
gdb_expect {
- -re "No executable file now..*$gdb_prompt $" {
+ -re "No executable files now..*$gdb_prompt $" {
pass "exec-file"
}
-re "exec-file.*A program is being debugged already. Kill it. .y or n.*$" {
#test file
send_gdb "file\n"
gdb_expect {
- -re "No executable file now..*$gdb_prompt $"\
+ -re "No executable files now..*$gdb_prompt $"\
{ pass "file" }
-re ".*A program is being debugged already. Kill it. .y or n.*$" {
send_gdb "n\n"
#test target exec
send_gdb "target exec\n"
gdb_expect {
- -re "No executable file now..*$gdb_prompt $"\
+ -re "No executable files now..*$gdb_prompt $"\
{ pass "target exec" }
-re ".*A program is being debugged already. Kill it. .y or n.*$" {
send_gdb "n\n"
set description "step over corearg initialization"
set command "step"
}
- -re ".*pid_or_core_arg = NULL.*$gdb_prompt $" {
- set description "step over pid_or_core_arg initialization"
- set command "step"
- }
-re ".*cdarg = NULL.*$gdb_prompt $" {
set description "step over cdarg initialization"
set command "step"
set description "step over ttyarg initialization"
set command "step"
}
+ -re ".*miscargs = NULL.*$gdb_prompt $" {
+ set description "step over miscargs initialization"
+ set command "step"
+ }
+ -re ".*nmisc = 0.*$gdb_prompt $" {
+ set description "step over nmisc initialization"
+ set command "step"
+ }
-re ".*time_at_startup = get_run_time.*$gdb_prompt $" {
set description "next over get_run_time and everything it calls"
set command "next"
global gdb_prompt
send_gdb "file\n"
gdb_expect 60 {
- -re "No executable file now\[^\r\n\]*\[\r\n\]" { exp_continue }
- -re "No symbol file now\[^\r\n\]*\[\r\n\]" { exp_continue }
+ -re "No executable files now\[^\r\n\]*\[\r\n\]" { exp_continue }
+ -re "No symbol files now\[^\r\n\]*\[\r\n\]" { exp_continue }
-re "A program is being debugged already..*Kill it.*y or n. $"\
{ send_gdb "y\n"
verbose "\t\tKilling previous program being debugged"
exp_continue
}
- -re "Discard symbol table from .*y or n.*$" {
+ -re "Discard all symbol tables.*y or n.*$" {
send_gdb "y\n"
exp_continue
}
*(p + 1) = '\0';
}
+ /* Make sure the current i/t set is actually current and
+ accurate. */
+ update_itset (current_itset);
+
/* If this command has been pre-hooked, run the hook first. */
execute_cmd_pre_hook (c);
add_com_alias ("wh", "winheight", class_tui, 0);
add_info ("win", tui_all_windows_info,
_("List of all displayed windows.\n"));
- add_com ("focus", class_tui, tui_set_focus_command, _("\
+ add_com ("ffocus", class_tui, tui_set_focus_command, _("\
Set focus to named window or next/prev window.\n\
Usage: focus {<win> | next | prev}\n\
Valid Window names are:\n\
#include "charset.h"
#include "annotate.h"
#include "filenames.h"
+#include "exec.h"
#include "symfile.h"
#include "gdb_obstack.h"
#include "gdbcore.h"
be determined by the target architecture, not by the object
file. */
if (i - 2 == addr_bit / 4
- && exec_bfd
- && bfd_get_sign_extend_vma (exec_bfd))
+ && first_exec
+ && bfd_get_sign_extend_vma (first_exec->ebfd))
addr = (addr ^ ((CORE_ADDR) 1 << (addr_bit - 1)))
- ((CORE_ADDR) 1 << (addr_bit - 1));
}