aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Shebs <shebs@codesourcery.com>2008-11-21 02:31:59 +0000
committerStan Shebs <shebs@codesourcery.com>2008-11-21 02:31:59 +0000
commitcbbe31a0e22b6b191f458ff48ece7bcbd471297d (patch)
treefe13247479f02b5b512d0367c89146379864578c
parentb4812cfe4dc394392e47e0489f38521da4a0b7ce (diff)
downloadfsf-binutils-gdb-cbbe31a0e22b6b191f458ff48ece7bcbd471297d.zip
fsf-binutils-gdb-cbbe31a0e22b6b191f458ff48ece7bcbd471297d.tar.gz
fsf-binutils-gdb-cbbe31a0e22b6b191f458ff48ece7bcbd471297d.tar.bz2
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". 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.
-rw-r--r--gdb/ChangeLog371
-rw-r--r--gdb/ada-lang.c1
-rw-r--r--gdb/arch-utils.c5
-rw-r--r--gdb/block.c16
-rw-r--r--gdb/block.h3
-rw-r--r--gdb/blockframe.c3
-rw-r--r--gdb/breakpoint.c291
-rw-r--r--gdb/breakpoint.h8
-rw-r--r--gdb/c-exp.y4
-rw-r--r--gdb/corefile.c58
-rw-r--r--gdb/corelow.c58
-rw-r--r--gdb/cp-namespace.c5
-rw-r--r--gdb/cp-support.h2
-rw-r--r--gdb/doc/gdb.texinfo354
-rw-r--r--gdb/exec.c441
-rw-r--r--gdb/exec.h61
-rw-r--r--gdb/fork-child.c15
-rw-r--r--gdb/frame.c23
-rw-r--r--gdb/frame.h7
-rw-r--r--gdb/gdbcore.h5
-rw-r--r--gdb/inf-ptrace.c16
-rw-r--r--gdb/infcmd.c137
-rw-r--r--gdb/inferior.c779
-rw-r--r--gdb/inferior.h115
-rw-r--r--gdb/infrun.c3
-rw-r--r--gdb/language.h2
-rw-r--r--gdb/linespec.c87
-rw-r--r--gdb/linux-fork.c5
-rw-r--r--gdb/linux-fork.h2
-rw-r--r--gdb/linux-nat.c16
-rw-r--r--gdb/linux-thread-db.c9
-rw-r--r--gdb/main.c97
-rw-r--r--gdb/maint.c59
-rw-r--r--gdb/minsyms.c23
-rw-r--r--gdb/objfiles.c2
-rw-r--r--gdb/objfiles.h22
-rw-r--r--gdb/remote.c28
-rw-r--r--gdb/scm-valprint.c4
-rw-r--r--gdb/solib.c4
-rw-r--r--gdb/source.c11
-rw-r--r--gdb/symfile.c60
-rw-r--r--gdb/symfile.h2
-rw-r--r--gdb/symmisc.c12
-rw-r--r--gdb/symtab.c179
-rw-r--r--gdb/symtab.h23
-rw-r--r--gdb/target.c12
-rw-r--r--gdb/target.h3
-rw-r--r--gdb/testsuite/ChangeLog20
-rw-r--r--gdb/testsuite/Makefile.in2
-rw-r--r--gdb/testsuite/config/monitor.exp2
-rwxr-xr-xgdb/testsuite/configure3
-rw-r--r--gdb/testsuite/configure.ac3
-rw-r--r--gdb/testsuite/gdb.base/attach.exp12
-rw-r--r--gdb/testsuite/gdb.base/checkpoint.exp7
-rw-r--r--gdb/testsuite/gdb.base/default.exp6
-rw-r--r--gdb/testsuite/gdb.gdb/selftest.exp12
-rw-r--r--gdb/testsuite/lib/gdb.exp6
-rw-r--r--gdb/top.c4
-rw-r--r--gdb/tui/tui-win.c2
-rw-r--r--gdb/utils.c5
60 files changed, 3243 insertions, 284 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4eabe76..35d6390 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,374 @@
+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.
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 2ccba78..f92d23b 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -4871,6 +4871,7 @@ static struct symbol *
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)
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index 3014558..439c48b 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -23,6 +23,7 @@
#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"
@@ -469,8 +470,8 @@ gdbarch_update_p (struct gdbarch_info info)
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;
diff --git a/gdb/block.c b/gdb/block.c
index 58dcf72..640beb6 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -149,6 +149,22 @@ blockvector_for_pc (CORE_ADDR pc, struct block **pblock)
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. */
diff --git a/gdb/block.h b/gdb/block.h
index af4d056..9f81477 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -29,6 +29,7 @@ struct using_direct;
struct obstack;
struct dictionary;
struct addrmap;
+struct inferior;
/* All of the name-scope contours of the program
are represented by `struct block' objects.
@@ -147,6 +148,8 @@ extern struct block *block_for_pc (CORE_ADDR);
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,
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 5e2020d..ec98233 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -60,12 +60,13 @@ void _initialize_blockframe (void);
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
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 847dbdd..24fa293 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -38,6 +38,7 @@
#include "gdb_string.h"
#include "demangle.h"
#include "annotate.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "source.h"
@@ -60,6 +61,10 @@
#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)
@@ -823,6 +828,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
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
@@ -852,6 +858,8 @@ update_watchpoint (struct breakpoint *b, int reparse)
select_frame (fi);
}
+ inf = get_frame_inferior (get_selected_frame (NULL));
+
if (within_current_scope && reparse)
{
char *s;
@@ -928,6 +936,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
;
*tmp = loc;
+ loc->inferior = inf;
loc->address = addr;
loc->length = len;
loc->watchpoint_type = type;
@@ -979,6 +988,9 @@ should_be_inserted (struct bp_location *bpt)
if (!bpt->enabled || bpt->shlib_disabled || bpt->duplicate)
return 0;
+ if (!bpt->inferior || (bpt->inferior && bpt->inferior->pid == 0))
+ return 0;
+
return 1;
}
@@ -1195,6 +1207,83 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
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
@@ -1205,8 +1294,12 @@ insert_breakpoints (void)
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);
@@ -1254,9 +1347,17 @@ insert_breakpoint_locations (void)
&& !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;
}
@@ -1278,7 +1379,9 @@ insert_breakpoint_locations (void)
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;
@@ -1370,8 +1473,12 @@ reattach_breakpoints (int pid)
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);
@@ -1527,6 +1634,9 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is)
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)
{
@@ -1624,6 +1734,7 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is)
b->inserted = (is == mark_inserted);
}
+ tmp_inf = NULL;
return 0;
}
@@ -2814,9 +2925,9 @@ bpstat_check_watchpoint (bpstat bs)
}
-/* 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)
{
@@ -2858,6 +2969,13 @@ 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--;
@@ -2870,6 +2988,33 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
}
}
+/* 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.
@@ -2908,6 +3053,11 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t 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
@@ -3317,7 +3467,7 @@ static void
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;
@@ -3432,11 +3582,7 @@ print_one_breakpoint_location (struct breakpoint *b,
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
@@ -3491,6 +3637,15 @@ print_one_breakpoint_location (struct breakpoint *b,
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
@@ -3499,6 +3654,13 @@ print_one_breakpoint_location (struct breakpoint *b,
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))
@@ -3583,9 +3745,9 @@ print_one_breakpoint_location (struct breakpoint *b,
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
@@ -3608,7 +3770,7 @@ print_one_breakpoint (struct breakpoint *b,
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);
}
}
}
@@ -3629,7 +3791,7 @@ do_captured_breakpoint_query (struct ui_out *uiout, void *data)
{
if (args->bnum == b->number)
{
- print_one_breakpoint (b, &dummy_addr);
+ print_one_breakpoint (b, &dummy_addr, 0);
return GDB_RC_OK;
}
}
@@ -3736,7 +3898,7 @@ breakpoint_1 (int bnum, int allflag)
/* 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);
@@ -3888,7 +4050,7 @@ breakpoint_address_is_meaningful (struct breakpoint *bpt)
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;
@@ -3900,6 +4062,7 @@ check_duplicates_for (CORE_ADDR address, struct obj_section *section)
&& 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))
{
@@ -3934,6 +4097,7 @@ check_duplicates_for (CORE_ADDR address, struct obj_section *section)
&& 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))
{
@@ -3957,7 +4121,7 @@ check_duplicates (struct breakpoint *bpt)
return;
for (; bl; bl = bl->next)
- check_duplicates_for (bl->address, bl->section);
+ check_duplicates_for (bl->address, bl->inferior, bl->section);
}
static void
@@ -4093,6 +4257,7 @@ set_raw_breakpoint_without_location (enum bptype bptype)
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;
@@ -4154,6 +4319,7 @@ set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
{
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
@@ -4166,6 +4332,18 @@ set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
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;
@@ -4993,6 +5171,7 @@ add_location_to_breakpoint (struct breakpoint *b, enum bptype bptype,
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))
@@ -5001,6 +5180,19 @@ add_location_to_breakpoint (struct breakpoint *b, enum bptype bptype,
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);
@@ -5183,8 +5375,9 @@ expand_line_sal_maybe (struct symtab_and_line sal)
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;
@@ -5233,6 +5426,50 @@ expand_line_sal_maybe (struct symtab_and_line sal)
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
@@ -6750,7 +6987,20 @@ clear_command (char *arg, int from_tty)
}
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. */
@@ -7390,6 +7640,7 @@ breakpoint_re_set_one (void *bint)
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);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index cff6c3f..800260e 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -26,6 +26,8 @@
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
@@ -221,6 +223,9 @@ struct bp_location
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
@@ -426,6 +431,9 @@ struct breakpoint
/* 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
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 153e2be..44a1896 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1714,7 +1714,7 @@ yylex ()
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);
@@ -1722,7 +1722,7 @@ yylex ()
/* 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.
diff --git a/gdb/corefile.c b/gdb/corefile.c
index af2d1a3..1d60087 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -29,6 +29,7 @@
#include "gdbcmd.h"
#include "bfd.h"
#include "target.h"
+#include "exec.h"
#include "gdbcore.h"
#include "dis-asm.h"
#include "gdb_stat.h"
@@ -135,41 +136,35 @@ specify_exec_file_hook (void (*hook) (char *))
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 ();
+ }
}
/* If we have both a core file and an exec file,
@@ -178,11 +173,11 @@ reopen_exec_file (void)
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."));
}
}
@@ -194,8 +189,13 @@ validate_files (void)
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;
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 35c998c..b5d8a4c 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -108,6 +108,60 @@ deprecated_add_core_fns (struct core_fns *cf)
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. */
@@ -352,7 +406,7 @@ core_open (char *filename, int from_tty)
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);
@@ -539,7 +593,7 @@ get_core_registers (struct regcache *regcache, int regno)
static void
core_files_info (struct target_ops *t)
{
- print_section_info (t, core_bfd);
+ print_section_info (t, core_bfd, NULL);
}
static LONGEST
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index 4b45f6c..16764b8 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -297,6 +297,7 @@ 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)
{
return lookup_namespace_scope (name, linkage_name, block, domain,
@@ -429,7 +430,7 @@ lookup_symbol_file (const char *name,
{
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;
@@ -447,7 +448,7 @@ lookup_symbol_file (const char *name,
}
else
{
- sym = lookup_symbol_global (name, linkage_name, block, domain);
+ sym = lookup_symbol_global (name, linkage_name, block, NULL, domain);
}
if (sym != NULL)
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index a004783b..cf0dd59 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -35,6 +35,7 @@ struct block;
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
@@ -96,6 +97,7 @@ extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol);
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,
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index aef5308..75d3af6 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -864,6 +864,25 @@ option processing.
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}:
@@ -900,9 +919,10 @@ in sequential order. The order makes a difference when the
@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
@@ -933,19 +953,24 @@ than @samp{-}, though we illustrate the more usual convention.)
@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}
@@ -1786,9 +1811,9 @@ kill a child process.
* 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
@@ -2312,6 +2337,8 @@ can step and continue; you can modify storage. If you would rather the
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
@@ -2331,6 +2358,9 @@ things; you can control whether or not you need to confirm by using the
@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
@@ -2402,6 +2432,226 @@ Show whether messages will be printed when @value{GDBN} detects that
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
@@ -2646,12 +2896,12 @@ 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
@@ -5504,6 +5754,10 @@ Print lines just before the lines last printed.
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
@@ -5584,6 +5838,14 @@ functions with identical names in different source files.
@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
@@ -6117,6 +6379,10 @@ to programming languages:
@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
@@ -6290,6 +6556,28 @@ scope resolution operator in @value{GDBN} expressions.
@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
@@ -12567,6 +12855,15 @@ via @code{gdbserver} (@pxref{Server, file, Using the @code{gdbserver}
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
@@ -12595,12 +12892,24 @@ the wrong place. But this feature is still handy from time to time.
@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{]}
@@ -12779,12 +13088,12 @@ their addresses.
@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
@@ -24481,6 +24790,11 @@ The register groups info looks like this:
@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
diff --git a/gdb/exec.c b/gdb/exec.c
index 92450e6..cf4e844 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -32,6 +32,7 @@
#include "exec.h"
#include "observer.h"
#include "arch-utils.h"
+#include "vec.h"
#include <fcntl.h>
#include "readline/readline.h"
@@ -52,8 +53,12 @@ void (*deprecated_file_changed_hook) (char *);
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 *);
@@ -66,10 +71,19 @@ void _initialize_exec (void);
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. */
@@ -97,6 +111,8 @@ exec_close (int quitting)
{
int need_symtab_cleanup = 0;
struct vmap *vp, *nxt;
+ int ix;
+ struct exec *ex;
for (nxt = vmap; nxt != NULL;)
{
@@ -128,6 +144,23 @@ exec_close (int quitting)
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);
@@ -137,7 +170,6 @@ exec_close (int quitting)
name, bfd_errmsg (bfd_get_error ()));
xfree (name);
exec_bfd = NULL;
- exec_bfd_mtime = 0;
}
if (exec_ops.to_sections)
@@ -155,10 +187,10 @@ exec_file_clear (int from_tty)
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
@@ -177,18 +209,44 @@ exec_file_clear (int from_tty)
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);
}
@@ -265,13 +323,46 @@ exec_file_attach (char *filename, int from_tty)
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)
@@ -281,6 +372,169 @@ exec_file_attach (char *filename, int from_tty)
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
@@ -296,9 +550,13 @@ exec_file_command (char *args, int from_tty)
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)
{
@@ -320,6 +578,49 @@ exec_file_command (char *args, int from_tty)
}
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.
@@ -333,6 +634,22 @@ file_command (char *arg, int from_tty)
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);
}
@@ -375,8 +692,13 @@ build_section_table (struct bfd *some_bfd, struct section_table **start,
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);
@@ -464,13 +786,21 @@ xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
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);
@@ -481,7 +811,7 @@ xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
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,
@@ -534,19 +864,30 @@ xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
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));
@@ -570,7 +911,23 @@ print_section_info (struct target_ops *t, bfd *abfd)
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)
{
@@ -597,6 +954,39 @@ exec_files_info (struct target_ops *t)
}
}
+/* 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)
{
@@ -721,6 +1111,13 @@ If FILE cannot be found as specified, your execution directory path\n\
($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, _("\
@@ -730,6 +1127,12 @@ is searched for a command of that name.\n\
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\
diff --git a/gdb/exec.h b/gdb/exec.h
index 3b19d15..9dcc02d 100644
--- a/gdb/exec.h
+++ b/gdb/exec.h
@@ -21,13 +21,56 @@
#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. */
@@ -37,4 +80,22 @@ extern int build_section_table (struct bfd *, struct section_table **,
/* 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
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 75b9d4e..5325d36 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -23,6 +23,7 @@
#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"
@@ -34,6 +35,8 @@
#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. */
@@ -138,6 +141,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
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. */
@@ -394,7 +399,15 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
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);
diff --git a/gdb/frame.c b/gdb/frame.c
index a877494..dfd6b2b 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -67,6 +67,8 @@ struct frame_info
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
@@ -173,6 +175,7 @@ fprint_frame_id (struct ui_file *file, struct frame_id id)
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, "}");
}
@@ -259,6 +262,8 @@ get_frame_id (struct frame_info *fi)
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)
{
@@ -354,6 +359,9 @@ frame_id_eq (struct frame_id l, struct frame_id r)
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;
@@ -900,6 +908,9 @@ create_sentinel_frame (struct regcache *regcache)
{
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. */
@@ -1103,6 +1114,8 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
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);
@@ -1356,6 +1369,8 @@ get_prev_frame_1 (struct frame_info *this_frame)
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. */
@@ -1648,7 +1663,7 @@ pc_notcurrent (struct frame_info *frame)
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
@@ -1761,6 +1776,12 @@ deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
frame->this_id.value.stack_addr = base;
}
+struct inferior *
+get_frame_inferior (struct frame_info *frame)
+{
+ return frame->inferior;
+}
+
/* Memory access methods. */
void
diff --git a/gdb/frame.h b/gdb/frame.h
index 231aa32..90e7098 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -122,6 +122,11 @@ struct frame_id
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. */
@@ -369,6 +374,8 @@ extern int frame_relative_level (struct frame_info *fi);
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
diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h
index 6d8d2eb..15a0527 100644
--- a/gdb/gdbcore.h
+++ b/gdb/gdbcore.h
@@ -104,9 +104,6 @@ extern void specify_exec_file_hook (void (*hook) (char *filename));
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;
@@ -115,6 +112,8 @@ extern void core_file_command (char *filename, int from_tty);
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);
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index bf3d0a8..eed454f 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -21,6 +21,7 @@
#include "defs.h"
#include "command.h"
+#include "exec.h"
#include "inferior.h"
#include "inflow.h"
#include "gdbcore.h"
@@ -225,7 +226,7 @@ inf_ptrace_attach (struct target_ops *ops, char *args, int from_tty)
{
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
@@ -284,11 +285,14 @@ inf_ptrace_detach (struct target_ops *ops, char *args, int from_tty)
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)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 810b3b7..a9bfd3e 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -33,6 +33,7 @@
#include "gdbcore.h"
#include "target.h"
#include "language.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "completer.h"
@@ -53,6 +54,8 @@
#include "gdbthread.h"
#include "valprint.h"
+struct inferior *current_inf;
+
/* Functions exported for general use, in inferior.h: */
void all_registers_info (char *, int);
@@ -171,7 +174,78 @@ struct gdb_environ *inferior_environ;
int suppress_resume_observer = 0;
/* When set, normal_stop will not call the normal_stop observer. */
int suppress_stop_observer = 0;
-
+
+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
@@ -195,6 +269,16 @@ get_inferior_io_terminal (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;
@@ -215,27 +299,56 @@ char *
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. */
@@ -2115,6 +2228,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
char *exec_file;
char *full_exec_path = NULL;
struct inferior *inferior;
+ struct exec *exec;
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
@@ -2238,7 +2352,10 @@ attach_command (char *args, int from_tty)
;
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."));
@@ -2328,6 +2445,19 @@ attach_command (char *args, int from_tty)
}
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);
}
@@ -2478,6 +2608,9 @@ _initialize_infcmd (void)
{
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, _("\
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 24f8fa6..b2a8bf6 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -18,6 +18,7 @@
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"
@@ -28,13 +29,21 @@
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)
{
@@ -46,11 +55,18 @@ 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)
{
@@ -78,8 +94,6 @@ add_inferior_silent (int pid)
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;
@@ -190,7 +204,7 @@ discard_all_inferiors (void)
}
}
-static struct inferior *
+struct inferior *
find_inferior_id (int num)
{
struct inferior *inf;
@@ -202,6 +216,7 @@ find_inferior_id (int num)
return NULL;
}
+/* Find a inferior by matching PID. */
struct inferior *
find_inferior_pid (int pid)
{
@@ -215,6 +230,18 @@ find_inferior_pid (int pid)
}
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)
{
@@ -282,6 +309,18 @@ have_inferiors (void)
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.
@@ -291,6 +330,7 @@ void
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");
@@ -304,7 +344,7 @@ print_inferior (struct ui_out *uiout, int requested_inferior)
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, " ");
@@ -312,7 +352,46 @@ print_inferior (struct ui_out *uiout, int requested_inferior)
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);
}
@@ -337,10 +416,694 @@ show_print_inferior_events (struct ui_file *file, int from_tty,
}
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, _("\
diff --git a/gdb/inferior.h b/gdb/inferior.h
index aa582cb..6b49bfc 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -30,6 +30,7 @@ struct type;
struct gdbarch;
struct regcache;
struct ui_out;
+struct gdb_environ;
/* For bpstat. */
#include "breakpoint.h"
@@ -40,6 +41,8 @@ struct ui_out;
/* 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".
@@ -414,6 +417,21 @@ struct inferior
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;
@@ -430,6 +448,67 @@ struct inferior
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);
@@ -497,8 +576,44 @@ extern void print_inferior (struct ui_out *uiout, int requested_inferior);
/* 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) */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index f218fa0..a459c97 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -272,6 +272,9 @@ static struct
}
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";
diff --git a/gdb/language.h b/gdb/language.h
index c92c57c..64cf27f 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -31,6 +31,7 @@ struct frame_info;
struct expression;
struct ui_file;
struct value_print_options;
+struct exec;
#define MAX_FORTRAN_DIMS 7 /* Maximum number of F77 array dims */
@@ -238,6 +239,7 @@ struct language_defn
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. */
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 8020cb5..38c8d5f 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -23,9 +23,11 @@
#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"
@@ -51,6 +53,8 @@ static void initialize_defaults (struct symtab **default_symtab,
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);
@@ -129,6 +133,7 @@ static struct symtabs_and_lines decode_variable (char *copy,
int funfirstline,
char ***canonical,
struct symtab *file_symtab,
+ struct exec *exec,
int *not_found_ptr);
static struct
@@ -393,6 +398,9 @@ build_canonical_line_spec (struct symtab_and_line *sal, char *symname,
char **canonical_arr;
char *canonical_name;
char *filename;
+ char *exec_name;
+ int exec_space;
+
struct symtab *s = sal->symtab;
if (s == (struct symtab *) NULL
@@ -403,16 +411,31 @@ build_canonical_line_spec (struct symtab_and_line *sal, char *symname,
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;
}
@@ -688,7 +711,7 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
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. */
@@ -707,7 +730,13 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
/* 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 == '*')
@@ -876,7 +905,7 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
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);
}
@@ -964,6 +993,30 @@ set_flags (char *arg, int *is_quoted, char **paren_pointer)
+/* 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
@@ -971,7 +1024,7 @@ decode_indirect (char **argptr)
{
struct symtabs_and_lines values;
CORE_ADDR pc;
-
+
(*argptr)++;
pc = parse_and_eval_address_1 (argptr);
@@ -1740,23 +1793,24 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
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);
@@ -1805,9 +1859,14 @@ symbol_found (int funfirstline, char ***canonical, char *copy,
{
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
@@ -1823,6 +1882,8 @@ symbol_found (int funfirstline, char ***canonical, char *copy,
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
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index f80fe5f..498db30 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -34,15 +34,14 @@
#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
{
diff --git a/gdb/linux-fork.h b/gdb/linux-fork.h
index cea1fc9..227ebb3 100644
--- a/gdb/linux-fork.h
+++ b/gdb/linux-fork.h
@@ -27,5 +27,3 @@ extern int forks_exist_p (void);
struct fork_info *fork_list;
-extern int detach_fork;
-
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 913bfec..6400dc3 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -50,6 +50,8 @@
#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
@@ -688,6 +690,8 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
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);
@@ -699,6 +703,10 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
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. */
@@ -728,7 +736,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
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);
@@ -858,7 +868,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
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). */
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 5f98e99..02bc103 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -28,6 +28,7 @@
#include "bfd.h"
#include "exceptions.h"
#include "gdbthread.h"
+#include "exec.h"
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
@@ -474,11 +475,11 @@ enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
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),
&current_target));
@@ -1130,8 +1131,8 @@ thread_db_get_thread_local_address (ptid_t ptid,
/* 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);
}
diff --git a/gdb/main.c b/gdb/main.c
index 15a6558..8f4fd7f 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -23,9 +23,11 @@
#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"
@@ -128,9 +130,10 @@ captured_main (void *data)
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;
@@ -182,6 +185,8 @@ captured_main (void *data)
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);
@@ -566,34 +571,13 @@ extern int gdbtk_test (char *);
}
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;
@@ -735,6 +719,8 @@ Excess command line arguments ignored. (%s%s)\n"),
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."));
@@ -745,23 +731,48 @@ 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);
diff --git a/gdb/maint.c b/gdb/maint.c
index c46bdc0..4d8c7f9 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -32,6 +32,7 @@
#include "gdbcore.h"
#include "expression.h" /* For language.h */
#include "language.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "value.h"
@@ -359,36 +360,44 @@ print_objfile_section_info (bfd *abfd,
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)
@@ -843,6 +852,10 @@ If a SOURCE file is specified, dump only that file's partial symbols."),
_("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\
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index f020cb5..9ebf9c2 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -174,10 +174,29 @@ msymbol_objfile (struct minimal_symbol *sym)
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;
struct minimal_symbol *found_symbol = NULL;
@@ -198,6 +217,10 @@ lookup_minimal_symbol (const char *name, const char *sfile,
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)
{
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index d0aee52..9e935dd 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -201,6 +201,8 @@ allocate_objfile (bfd *abfd, int flags)
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. */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index fe42f54..e9f4255 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -23,11 +23,13 @@
#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
@@ -200,6 +202,10 @@ struct objfile
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. */
@@ -419,6 +425,9 @@ struct 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. */
@@ -515,6 +524,10 @@ extern void *objfile_data (struct objfile *objfile,
(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) \
@@ -544,12 +557,21 @@ extern void *objfile_data (struct objfile *objfile,
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) \
diff --git a/gdb/remote.c b/gdb/remote.c
index 4580c77..47eb982 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -25,6 +25,7 @@
#include "gdb_string.h"
#include <ctype.h>
#include <fcntl.h>
+#include "exec.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
@@ -2505,6 +2506,7 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
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. */
@@ -5680,7 +5682,14 @@ remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len,
{
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);
@@ -6661,6 +6670,8 @@ static void
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 ())
@@ -6692,7 +6703,10 @@ extended_remote_create_inferior_1 (char *exec_file, char *args,
/* 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);
@@ -7249,7 +7263,15 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
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 ();
diff --git a/gdb/scm-valprint.c b/gdb/scm-valprint.c
index 006f280..033d3de 100644
--- a/gdb/scm-valprint.c
+++ b/gdb/scm-valprint.c
@@ -63,9 +63,9 @@ scm_inferior_print (LONGEST value, struct ui_file *stream,
{
/* 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;
diff --git a/gdb/solib.c b/gdb/solib.c
index d04a907..aa70931 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -866,8 +866,8 @@ clear_solib (void)
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)
diff --git a/gdb/source.c b/gdb/source.c
index c41c193..f23b07b 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -35,6 +35,7 @@
#include <fcntl.h>
#include "gdbcore.h"
#include "gdb_regex.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "annotate.h"
@@ -239,7 +240,7 @@ select_source_symtab (struct symtab *s)
/* 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];
@@ -255,7 +256,7 @@ select_source_symtab (struct symtab *s)
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)
{
@@ -271,7 +272,7 @@ select_source_symtab (struct symtab *s)
/* 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)
{
@@ -1125,8 +1126,8 @@ find_source_lines (struct symtab *s, int desc)
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."));
diff --git a/gdb/symfile.c b/gdb/symfile.c
index d9aff2f..7e2b568 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -49,6 +49,7 @@
#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"
@@ -790,8 +791,8 @@ syms_from_objfile (struct objfile *objfile,
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;
@@ -917,6 +918,16 @@ new_symfile_objfile (struct objfile *objfile, int mainline, int verbo)
/* 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
@@ -1149,10 +1160,7 @@ symbol_file_clear (int from_tty)
{
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 ();
@@ -1164,7 +1172,7 @@ symbol_file_clear (int from_tty)
symfile_objfile = NULL;
if (from_tty)
- printf_unfiltered (_("No symbol file now.\n"));
+ printf_unfiltered (_("No symbol files now.\n"));
}
struct build_id
@@ -2303,13 +2311,11 @@ reread_symbols (void)
/* 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
@@ -3196,6 +3202,32 @@ init_psymbol_list (struct objfile *objfile, int total_symbols)
}
}
+/* 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.
diff --git a/gdb/symfile.h b/gdb/symfile.h
index f0087d0..b74572b 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -309,6 +309,8 @@ extern bfd *symfile_bfd_open (char *);
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
{
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index ae52448..0169eae 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -23,6 +23,7 @@
#include "symtab.h"
#include "gdbtypes.h"
#include "bfd.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "breakpoint.h"
@@ -213,8 +214,13 @@ dump_objfile (struct objfile *objfile)
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)
{
@@ -916,6 +922,10 @@ maintenance_print_objfiles (char *ignore, int from_tty)
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--;
}
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 3af3e8a..1631188 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -28,6 +28,7 @@
#include "value.h"
#include "symfile.h"
#include "objfiles.h"
+#include "exec.h"
#include "gdbcmd.h"
#include "call-cmds.h"
#include "gdb_regex.h"
@@ -86,6 +87,7 @@ char *operator_chars (char *p, char **end);
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);
@@ -100,12 +102,14 @@ 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);
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);
@@ -697,6 +701,7 @@ init_sal (struct symtab_and_line *sal)
sal->line = 0;
sal->pc = 0;
sal->end = 0;
+ sal->inferior = NULL;
sal->explicit_pc = 0;
sal->explicit_line = 0;
}
@@ -852,6 +857,7 @@ struct partial_symtab *
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
@@ -868,8 +874,22 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
/* 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;
@@ -909,7 +929,7 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
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;
@@ -1189,11 +1209,37 @@ fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile)
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;
const char *mangled_name = NULL;
@@ -1239,7 +1285,7 @@ lookup_symbol_in_language (const char *name, const struct block *block,
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);
@@ -1254,11 +1300,35 @@ struct symbol *
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
@@ -1266,7 +1336,8 @@ lookup_symbol (const char *name, const struct block *block,
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;
@@ -1331,7 +1402,7 @@ lookup_symbol_aux (const char *name, const char *linkage_name,
/* 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;
@@ -1341,11 +1412,11 @@ lookup_symbol_aux (const char *name, const char *linkage_name,
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;
@@ -1479,6 +1550,7 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile,
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;
@@ -1487,7 +1559,7 @@ lookup_symbol_aux_symtabs (int block_index,
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);
@@ -1510,6 +1582,7 @@ lookup_symbol_aux_symtabs (int 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;
@@ -1520,7 +1593,7 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name,
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,
@@ -1567,6 +1640,7 @@ struct symbol *
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;
@@ -1599,11 +1673,11 @@ basic_lookup_symbol_nonlocal (const char *name,
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
@@ -1613,6 +1687,7 @@ struct symbol *
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);
@@ -1630,6 +1705,7 @@ struct symbol *
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;
@@ -1642,11 +1718,11 @@ lookup_symbol_global (const char *name,
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
@@ -1794,7 +1870,7 @@ basic_lookup_transparent_type (const char *name)
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);
@@ -1842,7 +1918,7 @@ basic_lookup_transparent_type (const char *name)
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);
@@ -1983,6 +2059,7 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
struct symtab *best_s = NULL;
struct partial_symtab *ps;
struct objfile *objfile;
+ struct exec *exec;
CORE_ADDR distance = 0;
struct minimal_symbol *msymbol;
@@ -2015,7 +2092,22 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
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);
@@ -2335,6 +2427,38 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
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
@@ -2607,8 +2731,10 @@ find_function_start_sal (struct symbol *sym, int funfirstline)
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);
@@ -4420,23 +4546,25 @@ symtab_observer_executable_changed (void)
/* 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
@@ -4519,6 +4647,7 @@ expand_line_sal (struct symtab_and_line sal)
{
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))
@@ -4548,7 +4677,7 @@ expand_line_sal (struct symtab_and_line sal)
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)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index a1dee4f..cf60f20 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -32,6 +32,8 @@ struct block;
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:
@@ -945,18 +947,30 @@ extern struct symbol *lookup_symbol_in_language (const char *,
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
@@ -968,6 +982,7 @@ extern struct symbol *basic_lookup_symbol_nonlocal (const char *,
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
@@ -976,6 +991,7 @@ extern struct symbol *lookup_symbol_static (const char *name,
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
@@ -1103,6 +1119,10 @@ extern struct minimal_symbol *lookup_minimal_symbol (const char *,
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 *);
@@ -1144,6 +1164,7 @@ struct symtab_and_line
CORE_ADDR pc;
CORE_ADDR end;
+ struct inferior *inferior;
int explicit_pc;
int explicit_line;
};
@@ -1182,6 +1203,8 @@ extern struct symtab_and_line find_pc_line (CORE_ADDR, int);
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 *);
diff --git a/gdb/target.c b/gdb/target.c
index 3901ee7..4a5905c 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -30,6 +30,7 @@
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
+#include "exec.h"
#include "objfiles.h"
#include "gdb_wait.h"
#include "dcache.h"
@@ -2268,6 +2269,8 @@ target_resize_to_sections (struct target_ops *target, int num_added)
struct target_ops **t;
struct section_table *old_value;
int old_count;
+ struct exec *exec;
+ int ix;
old_value = target->to_sections;
@@ -2307,6 +2310,15 @@ target_resize_to_sections (struct target_ops *target, int num_added)
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;
diff --git a/gdb/target.h b/gdb/target.h
index 05b681d..ade81cb 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -24,6 +24,7 @@
#if !defined (TARGET_H)
#define TARGET_H
+struct exec;
struct objfile;
struct ui_file;
struct mem_attrib;
@@ -733,7 +734,7 @@ extern int inferior_has_execd (ptid_t pid, char **execd_pathname);
/* 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. */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index a737872..947e5fe 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,23 @@
+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.
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index 11fc26e..a3d683f 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
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)
diff --git a/gdb/testsuite/config/monitor.exp b/gdb/testsuite/config/monitor.exp
index 4e13b0c..60257be 100644
--- a/gdb/testsuite/config/monitor.exp
+++ b/gdb/testsuite/config/monitor.exp
@@ -123,7 +123,7 @@ proc gdb_target_monitor { exec_file } {
}
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"
}
#
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index ef35b13..3350eb4 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3131,7 +3131,7 @@ done
- 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
@@ -3694,6 +3694,7 @@ do
"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" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 3d8fae4..a9065f1 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -115,7 +115,8 @@ AC_OUTPUT([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])
diff --git a/gdb/testsuite/gdb.base/attach.exp b/gdb/testsuite/gdb.base/attach.exp
index 4529715..b4c290e 100644
--- a/gdb/testsuite/gdb.base/attach.exp
+++ b/gdb/testsuite/gdb.base/attach.exp
@@ -205,8 +205,8 @@ proc do_attach_tests {} {
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
@@ -297,16 +297,16 @@ proc do_attach_tests {} {
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" \
diff --git a/gdb/testsuite/gdb.base/checkpoint.exp b/gdb/testsuite/gdb.base/checkpoint.exp
index c041e13..944e66e 100644
--- a/gdb/testsuite/gdb.base/checkpoint.exp
+++ b/gdb/testsuite/gdb.base/checkpoint.exp
@@ -46,6 +46,9 @@ gdb_exit
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
@@ -383,3 +386,7 @@ gdb_test "kill" "" "kill all one" \
#
remote_exec build "rm -f pi.txt"
+
+# Restore old timeout
+set timeout $prev_timeout
+verbose "Timeout now $timeout sec.\n"
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index 5cae742..3d18a29 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -209,7 +209,7 @@ gdb_test "enable" "" "enable"
#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.*$" {
@@ -234,7 +234,7 @@ gdb_test "fg" "The program is not being run." "fg"
#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"
@@ -712,7 +712,7 @@ gdb_expect {
#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"
diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp
index 4abe21a..6ef7388 100644
--- a/gdb/testsuite/gdb.gdb/selftest.exp
+++ b/gdb/testsuite/gdb.gdb/selftest.exp
@@ -83,10 +83,6 @@ proc do_steps_and_nexts {} {
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"
@@ -95,6 +91,14 @@ proc do_steps_and_nexts {} {
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"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 72448cd..43ba08a 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -135,14 +135,14 @@ proc gdb_unload {} {
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
}
diff --git a/gdb/top.c b/gdb/top.c
index d0ba466..c77ba97 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -439,6 +439,10 @@ Cannot execute this command without a live selected thread. See `help thread'."
*(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);
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index f956882..6119df2 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -384,7 +384,7 @@ regs : the register display\n"));
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\
diff --git a/gdb/utils.c b/gdb/utils.c
index d14009f..bd2ebeb 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -51,6 +51,7 @@
#include "charset.h"
#include "annotate.h"
#include "filenames.h"
+#include "exec.h"
#include "symfile.h"
#include "gdb_obstack.h"
#include "gdbcore.h"
@@ -3044,8 +3045,8 @@ string_to_core_addr (const char *my_string)
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));
}