2009-10-19 Pedro Alves <pedro@codesourcery.com>

Stan Shebs	<stan@codesourcery.com>

	Add base multi-executable/process support to GDB.

	gdb/
	* Makefile.in (SFILES): Add progspace.c.
	(COMMON_OBS): Add progspace.o.
	* progspace.h: New.
	* progspace.c: New.

	* breakpoint.h (struct bp_target_info) <placed_address_space>: New
	field.
	(struct bp_location) <pspace>: New field.
	(struct breakpoint) <pspace>: New field.
	(bpstat_stop_status, breakpoint_here_p)
	(moribund_breakpoint_here_p, breakpoint_inserted_here_p)
	(regular_breakpoint_inserted_here_p)
	(software_breakpoint_inserted_here_p, breakpoint_thread_match)
	(set_default_breakpoint): Adjust prototypes.
	(remove_breakpoints_pid, breakpoint_program_space_exit): Declare.
	(insert_single_step_breakpoint, deprecated_insert_raw_breakpoint):
	Adjust prototypes.
	* breakpoint.c (executing_startup): Delete.
	(default_breakpoint_sspace): New.
	(breakpoint_restore_shadows): Skip if the address space doesn't
	match.
	(update_watchpoint): Record the frame's program space in the
	breakpoint location.
	(insert_bp_location): Record the address space in target_info.
	Adjust to pass the symbol space to solib_name_from_address.
	(breakpoint_program_space_exit): New.
	(insert_breakpoint_locations): Switch the symbol space and thread
	when inserting breakpoints.  Don't insert breakpoints in a vfork
	parent waiting for vfork done if we're not attached to the vfork
	child.
	(remove_breakpoints_pid): New.
	(reattach_breakpoints): Switch to a thread of PID.  Ignore
	breakpoints of other symbol spaces.
	(create_internal_breakpoint): Store the symbol space in the sal.
	(create_longjmp_master_breakpoint): Iterate over all symbol
	spaces.
	(update_breakpoints_after_exec): Ignore breakpoints for other
	symbol spaces.
	(remove_breakpoint): Rename to ...
	(remove_breakpoint_1): ... this.  Pass the breakpoints symbol
	space to solib_name_from_address.
	(remove_breakpoint): New.
	(mark_breakpoints_out): Ignore breakpoints from other symbol
	spaces.
	(breakpoint_init_inferior): Ditto.
	(breakpoint_here_p): Add an address space argument and adjust to
	use breakpoint_address_match.
	(moribund_breakpoint_here_p): Ditto.
	(regular_breakpoint_inserted_here_p): Ditto.
	(breakpoint_inserted_here_p): Ditto.
	(software_breakpoint_inserted_here_p): Ditto.
	(breakpoint_thread_match): Ditto.
	(bpstat_check_location): Ditto.
	(bpstat_stop_status): Ditto.
	(print_breakpoint_location): If there's a location to print,
	switch the current symbol space.
	(print_one_breakpoint_location): Add `allflag' argument.
	(print_one_breakpoint): Ditto.	Adjust.
	(do_captured_breakpoint_query): Adjust.
	(breakpoint_1): Adjust.
	(breakpoint_has_pc): Also match the symbol space.
	(describe_other_breakpoints): Add a symbol space argument and
	adjust.
	(set_default_breakpoint): Add a symbol space argument.	Set
	default_breakpoint_sspace.
	(breakpoint_address_match): New.
	(check_duplicates_for): Add an address space argument, and adjust.
	(set_raw_breakpoint): Record the symbol space in the location and
	in the breakpoint.
	(set_longjmp_breakpoint): Skip longjmp master breakpoints from
	other symbol spaces.
	(remove_thread_event_breakpoints, remove_solib_event_breakpoints)
	(disable_breakpoints_in_shlibs): Skip breakpoints from other
	symbol spaces.
	(disable_breakpoints_in_unloaded_shlib): Match symbol spaces.
	(create_catchpoint): Set the symbol space in the sal.
	(disable_breakpoints_before_startup): Skip breakpoints from other
	symbol spaces.	Set executing_startup in the current symbol space.
	(enable_breakpoints_after_startup): Clear executing_startup in the
	current symbol space.  Skip breakpoints from other symbol spaces.
	(clone_momentary_breakpoint): Also copy the symbol space.
	(add_location_to_breakpoint): Set the location's symbol space.
	(bp_loc_is_permanent): Switch thread and symbol space.
	(create_breakpoint): Adjust.
	(expand_line_sal_maybe): Expand comment to mention symbol spaces.
	Switch thread and symbol space when reading memory.
	(parse_breakpoint_sals): Set the symbol space in the sal.
	(break_command_really): Ditto.
	(skip_prologue_sal): Switch and space.
	(resolve_sal_pc): Ditto.
	(watch_command_1): Record the symbol space in the sal.
	(create_ada_exception_breakpoint): Adjust.
	(clear_command): Adjust.  Match symbol spaces.
	(update_global_location_list): Use breakpoint_address_match.
	(breakpoint_re_set_one): Switch thread and space.
	(breakpoint_re_set): Save symbol space.
	(breakpoint_re_set_thread): Also reset the symbol space.
	(deprecated_insert_raw_breakpoint): Add an address space argument.
	Adjust.
	(insert_single_step_breakpoint): Ditto.
	(single_step_breakpoint_inserted_here_p): Ditto.
	(clear_syscall_counts): New.
	(_initialize_breakpoint): Install it as inferior_exit observer.

	* exec.h: Include "progspace.h".
	(exec_bfd, exec_bfd_mtime): New defines.
	(exec_close): Declare.
	* exec.c: Include "gdbthread.h" and "progspace.h".
	(exec_bfd, exec_bfd_mtime, current_target_sections_1): Delete.
	(using_exec_ops): New.
	(exec_close_1): Rename to exec_close, and make public.
	(exec_close): Rename to exec_close_1, and adjust all callers.  Add
	description.  Remove target sections and close executables from
	all program spaces.
	(exec_file_attach): Add comment.
	(add_target_sections): Check on `using_exec_ops' to check if the
	target should be pushed.
	(remove_target_sections): Only unpush the target if there are no
	more target sections in any symbol space.
	* gdbcore.h: Include "exec.h".
	(exec_bfd, exec_bfd_mtime): Remove declarations.

	* frame.h (get_frame_program_space, get_frame_address_space)
	(frame_unwind_program_space): Declare.
	* frame.c (struct frame_info) <pspace, aspace>: New fields.
	(create_sentinel_frame): Add program space argument.  Set the
	pspace and aspace fields of the frame object.
	(get_current_frame, create_new_frame): Adjust.
	(get_frame_program_space): New.
	(frame_unwind_program_space): New.
	(get_frame_address_space): New.
	* stack.c (print_frame_info): Adjust.
	(print_frame): Use the frame's program space.

	* gdbthread.h (any_live_thread_of_process): Declare.
	* thread.c (any_live_thread_of_process): New.
	(switch_to_thread): Switch the program space as well.
	(restore_selected_frame): Don't warn if trying to restore frame
	level 0.

	* inferior.h: Include "progspace.h".
	(detach_fork): Declare.
	(struct inferior) <removable, aspace, pspace>
	<vfork_parent, vfork_child, pending_detach>
	<waiting_for_vfork_done>: New fields.
	<terminal_info>: Remove field.
	<data, num_data>: New fields.
	(register_inferior_data, register_inferior_data_with_cleanup)
	(clear_inferior_data, set_inferior_data, inferior_data): Declare.
	(exit_inferior, exit_inferior_silent, exit_inferior_num_silent)
	(inferior_appeared): Declare.
	(find_inferior_pid): Typo.
	(find_inferior_id, find_inferior_for_program_space): Declare.
	(set_current_inferior, save_current_inferior, prune_inferiors)
	(number_of_inferiors): Declare.
	(inferior_list): Declare.
	* inferior.c: Include "gdbcore.h" and "symfile.h".
	(inferior_list): Make public.
	(delete_inferior_1): Always delete thread silently.
	(find_inferior_id): Make public.
	(current_inferior_): New.
	(current_inferior): Use it.
	(set_current_inferior): New.
	(restore_inferior): New.
	(save_current_inferior): New.
	(free_inferior): Free the per-inferior data.
	(add_inferior_silent): Allocate per-inferior data.
	Call inferior_appeared.
	(delete_threads_of_inferior): New.
	(delete_inferior_1): Adjust interface to take an inferior pointer.
	(delete_inferior): Adjust.
	(delete_inferior_silent): Adjust.
	(exit_inferior_1): New.
	(exit_inferior): New.
	(exit_inferior_silent): New.
	(exit_inferior_num_silent): New.
	(detach_inferior): Adjust.
	(inferior_appeared): New.
	(discard_all_inferiors): Adjust.
	(find_inferior_id): Make public.  Assert pid is not zero.
	(find_inferior_for_program_space): New.
	(have_inferiors): Check if we have any inferior with pid not zero.
	(have_live_inferiors): Go over all pushed targets looking for
	process_stratum.
	(prune_inferiors): New.
	(number_of_inferiors): New.
	(print_inferior): Add executable column.  Print vfork parent/child
	relationships.
	(inferior_command): Adjust to cope with not running inferiors.
	(remove_inferior_command): New.
	(add_inferior_command): New.
	(clone_inferior_command): New.
	(struct inferior_data): New.
	(struct inferior_data_registration): New.
	(struct inferior_data_registry): New.
	(inferior_data_registry): New.
	(register_inferior_data_with_cleanup): New.
	(register_inferior_data): New.
	(inferior_alloc_data): New.
	(inferior_free_data): New.
	(clear_inferior_data): New.
	(set_inferior_data): New.
	(inferior_data): New.
	(initialize_inferiors): New.
	(_initialize_inferiors): Register "add-inferior",
	"remove-inferior" and "clone-inferior" commands.

	* objfiles.h: Include "progspace.h".
	(struct objfile) <pspace>: New field.
	(symfile_objfile, object_files): Don't declare.
	(ALL_PSPACE_OBJFILES): New.
	(ALL_PSPACE_OBJFILES_SAFE): New.
	(ALL_OBJFILES, ALL_OBJFILES_SAFE): Adjust.
	(ALL_PSPACE_SYMTABS): New.
	(ALL_PRIMARY_SYMTABS): Adjust.
	(ALL_PSPACE_PRIMARY_SYMTABS): New.
	(ALL_PSYMTABS): Adjust.
	(ALL_PSPACE_PSYMTABS): New.
	* objfiles.c (object_files, symfile_objfile): Delete.
	(struct objfile_sspace_info): New.
	(objfiles_pspace_data): New.
	(objfiles_pspace_data_cleanup): New.
	(get_objfile_pspace_data): New.
	(objfiles_changed_p): Delete.
	(allocate_objfile): Set the objfile's program space.  Adjust to
	reference objfiles_changed_p in pspace data.
	(free_objfile): Adjust to reference objfiles_changed_p in pspace
	data.
	(objfile_relocate): Ditto.
	(update_section_map): Add pspace argument.  Adjust to iterate over
	objfiles in the passed in pspace.
	(find_pc_section): Delete sections and num_sections statics.
	Adjust to refer to program space's objfiles_changed_p.	Adjust to
	refer to sections and num_sections store in the objfile's pspace
	data.
	(objfiles_changed): Adjust to reference objfiles_changed_p in
	pspace data.
	(_initialize_objfiles): New.
	* linespec.c (decode_all_digits, decode_dollar): Set the sal's
	program space.
	* source.c (current_source_pspace): New.
	(get_current_source_symtab_and_line): Set the sal's program space.
	(set_current_source_symtab_and_line): Set current_source_pspace.
	(select_source_symtab): Ditto.	Use ALL_OBJFILES.
	(forget_cached_source_info): Iterate over all program spaces.
	* symfile.c (clear_symtab_users): Adjust.
	* symmisc.c (print_symbol_bcache_statistics): Iterate over all
	program spaces.
	(print_objfile_statistics): Ditto.
	(maintenance_print_msymbols): Ditto.
	(maintenance_print_objfiles): Ditto.
	(maintenance_info_symtabs): Ditto.
	(maintenance_info_psymtabs): Ditto.
	* symtab.h (SYMTAB_PSPACE): New.
	(struct symtab_and_line) <pspace>: New field.
	* symtab.c (init_sal): Clear the sal's program space.
	(find_pc_sect_symtab): Set the sal's program space.  Switch thread
	and space.
	(append_expanded_sal): Add program space argument.  Iterate over
	all program spaces.
	(expand_line_sal): Iterate over all program spaces.  Switch
	program space.

	* target.h (enum target_waitkind) <TARGET_WAITKIND_VFORK_DONE>: New.
	(struct target_ops) <to_thread_address_space>: New field.
	(target_thread_address_space): Define.
	* target.c (target_detach): Only remove breakpoints from the
	inferior we're detaching.
	(target_thread_address_space): New.

	* defs.h (initialize_progspace): Declare.
	* top.c (gdb_init): Call it.

	* solist.h (struct so_list) <sspace>: New field.
	* solib.h (struct program_space): Forward declare.
	(solib_name_from_address): Adjust prototype.
	* solib.c (so_list_head): Replace with a macro referencing the
	program space.
	(update_solib_list): Set the so's program space.
	(solib_name_from_address): Add a program space argument and adjust.

	* solib-svr4.c (struct svr4_info) <pid>: Delete field.
	<interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low>
	<interp_plt_sect_high>: New fields.
	(svr4_info_p, svr4_info): Delete.
	(solib_svr4_sspace_data): New.
	(get_svr4_info): Rewrite.
	(svr4_sspace_data_cleanup): New.
	(open_symbol_file_object): Adjust.
	(svr4_default_sos): Adjust.
	(svr4_fetch_objfile_link_map): Adjust.
	(interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low)
	(interp_plt_sect_high): Delete.
	(svr4_in_dynsym_resolve_code): Adjust.
	(enable_break): Adjust.
	(svr4_clear_solib): Revert bit that removed the svr4_info here,
	and reinstate clearing debug_base, debug_loader_offset_p,
	debug_loader_offset and debug_loader_name.
	(_initialize_svr4_solib): Register solib_svr4_pspace_data.  Don't
	install an inferior_exit observer anymore.

	* printcmd.c (struct display) <pspace>: New field.
	(display_command): Set the display's sspace.
	(do_one_display): Match the display's sspace.
	(display_uses_solib_p): Ditto.

	* linux-fork.c (detach_fork): Moved to infrun.c.
	(_initialize_linux_fork): Moved "detach-on-fork" command to
	infrun.c.
	* infrun.c (detach_fork): Moved from linux-fork.c.
	(proceed_after_vfork_done): New.
	(handle_vfork_child_exec_or_exit): New.
	(follow_exec_mode_replace, follow_exec_mode_keep)
	(follow_exec_mode_names, follow_exec_mode_string)
	(show_follow_exec_mode_string): New.
	(follow_exec): New.  Reinstate the mark_breakpoints_out call.
	Remove shared libraries before attaching new executable.  If user
	wants to keep the inferior, keep it.
	(displaced_step_fixup): Adjust to pass an address space to the
	breakpoints module.
	(resume): Ditto.
	(clear_proceed_status): In all-stop mode, always clear the proceed
	status of all threads.
	(prepare_to_proceed): Adjust to pass an address space to the
	breakpoints module.
	(proceed): Ditto.
	(adjust_pc_after_break): Ditto.
	(handle_inferior_event): When handling a process exit, switch the
	program space to the inferior's that had exited.  Call
	handle_vfork_child_exec_or_exit.  Adjust to pass an address space
	to the breakpoints module.  In non-stop mode, when following a
	fork and detach-fork is off, also resume the other branch.  Handle
	TARGET_WAITKIND_VFORK_DONE.  Set the program space in sals.
	(normal_stop): Prune inferiors.
	(_initialize_infrun): Install the new "follow-exec-mode" command.
	"detach-on-fork" moved here.

	* regcache.h (get_regcache_aspace): Declare.
	* regcache.c (struct regcache) <aspace>: New field.
	(regcache_xmalloc): Clear the aspace.
	(get_regcache_aspace): New.
	(regcache_cpy): Copy the aspace field.
	(regcache_cpy_no_passthrough): Ditto.
	(get_thread_regcache): Fetch the thread's address space from the
	target, and store it in the regcache.

	* infcall.c (call_function_by_hand): Set the sal's pspace.

	* arch-utils.c (default_has_shared_address_space): New.
	* arch-utils.h (default_has_shared_address_space): Declare.

	* gdbarch.sh (has_shared_address_space): New.
	* gdbarch.h, gdbarch.c: Regenerate.

	* linux-tdep.c: Include auxv.h, target.h, elf/common.h.
	(linux_has_shared_address_space): New.
	(_initialize_linux_tdep): Declare.

	* arm-tdep.c (arm_software_single_step): Pass the frame's address
	space to insert_single_step_breakpoint.
	* arm-linux-tdep.c (arm_linux_software_single_step): Pass the
	frame's pspace to breakpoint functions.
	* cris-tdep.c (crisv32_single_step_through_delay): Ditto.
	(cris_software_single_step): Ditto.
	* mips-tdep.c (deal_with_atomic_sequence): Add frame argument.
	Pass the frame's pspace to breakpoint functions.
	(mips_software_single_step): Adjust.
	(mips_single_step_through_delay): Adjust.
	* rs6000-aix-tdep.c (rs6000_software_single_step): Adjust.
	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Adjust.
	* solib-irix.c (enable_break): Adjust to pass the current frame's
	address space to breakpoint functions.
	* sparc-tdep.c (sparc_software_single_step): Ditto.
	* spu-tdep.c (spu_software_single_step): Ditto.
	* alpha-tdep.c (alpha_software_single_step): Ditto.
	* record.c (record_wait): Adjust to pass an address space to the
	breakpoints module.

	* fork-child.c (fork_inferior): Set the new inferior's program and
	address spaces.
	* inf-ptrace.c (inf_ptrace_follow_fork): Copy the parent's program
	and address spaces.
	(inf_ptrace_attach): Set the inferior's program and address spaces.
	* linux-nat.c: Include "solib.h".
	(linux_child_follow_fork): Manage parent and child's program and
	address spaces.	 Clone the parent's program space if necessary.
	Don't wait for the vfork to be done here.  Refuse to resume if
	following the vfork parent while leaving the child stopped.
	(resume_callback): Don't resume a vfork parent.
	(linux_nat_resume): Also check for pending events in the
	lp->waitstatus field.
	(linux_handle_extended_wait): Report TARGET_WAITKIND_VFORK_DONE
	events to the core.
	(stop_wait_callback): Don't wait for SIGSTOP on vfork parents.
	(cancel_breakpoint): Adjust.
	* linux-thread-db.c (thread_db_wait): Don't remove thread event
	breakpoints here.
	(thread_db_mourn_inferior): Don't mark breakpoints out here.
	Remove thread event breakpoints after mourning.
	* corelow.c: Include progspace.h.
	(core_open): Set the inferior's program and address spaces.
	* remote.c (remote_add_inferior): Set the new inferior's program
	and address spaces.
	(remote_start_remote): Update address spaces.
	(extended_remote_create_inferior_1): Don't init the thread list if
	we already debugging other inferiors.
	* darwin-nat.c (darwin_attach): Set the new inferior's program and
	address spaces.
	* gnu-nat.c (gnu_attach): Ditto.
	* go32-nat.c (go32_create_inferior): Ditto.
	* inf-ttrace.c (inf_ttrace_follow_fork, inf_ttrace_attach): Ditto.
	* monitor.c (monitor_open): Ditto.
	* nto-procfs.c (procfs_attach, procfs_create_inferior): Ditto.
	* procfs.c (do_attach): Ditto.
	* windows-nat.c (do_initial_windows_stuff): Ditto.

	* inflow.c (inferior_process_group)
	(terminal_init_inferior_with_pgrp, terminal_inferior,
	(terminal_ours_1, inflow_inferior_exit, copy_terminal_info)
	(child_terminal_info, new_tty_postfork, set_sigint_trap): Adjust
	to use per-inferior data instead of inferior->terminal_info.
	(inflow_inferior_data): New.
	(inflow_new_inferior): Delete.
	(inflow_inferior_data_cleanup): New.
	(get_inflow_inferior_data): New.

	* mi/mi-interp.c (mi_new_inferior): Rename to...
	(mi_inferior_appeared): ... this.
	(mi_interpreter_init): Adjust.

	* tui/tui-disasm.c: Include "progspace.h".
	(tui_set_disassem_content): Pass an address space to
	breakpoint_here_p.

	* NEWS: Mention multi-program debugging support.  Mention new
	commands "add-inferior", "clone-inferior", "remove-inferior",
	"maint info program-spaces", and new option "set
	follow-exec-mode".

2009-10-19  Pedro Alves	 <pedro@codesourcery.com>
	    Stan Shebs	<stan@codesourcery.com>

	gdb/doc/
	* observer.texi (new_inferior): Rename to...
	(inferior_appeared): ... this.

2009-10-19  Pedro Alves	 <pedro@codesourcery.com>
	    Stan Shebs	<stan@codesourcery.com>

	gdb/testsuite/
	* gdb.base/foll-vfork.exp: Adjust to spell out "follow-fork".
	* gdb.base/foll-exec.exp: Adjust to expect a process id before
	"Executing new program".
	* gdb.base/foll-fork.exp: Adjust to spell out "follow-fork".
	* gdb.base/multi-forks.exp: Ditto.  Adjust to the inferior being
	left listed after having been killed.
	* gdb.base/attach.exp: Adjust to spell out "symbol-file".
	* gdb.base/maint.exp: Adjust test.

	* Makefile.in (ALL_SUBDIRS): Add gdb.multi.
	* gdb.multi/Makefile.in: New.
	* gdb.multi/base.exp: New.
	* gdb.multi/goodbye.c: New.
	* gdb.multi/hangout.c: New.
	* gdb.multi/hello.c: New.
	* gdb.multi/bkpt-multi-exec.c: New.
	* gdb.multi/bkpt-multi-exec.exp: New.
	* gdb.multi/crashme.c: New.

2009-10-19  Pedro Alves	 <pedro@codesourcery.com>
	    Stan Shebs	<stan@codesourcery.com>

	gdb/doc/
	* gdb.texinfo (Inferiors): Rename node to ...
	(Inferiors and Programs): ... this.  Mention running multiple
	programs in the same debug session.
	<info inferiors>: Mention the new 'Executable' column if "info
	inferiors".  Update examples.  Document the "add-inferior",
	"clone-inferior", "remove-inferior" and "maint info
	program-spaces" commands.
	(Process): Rename node to...
	(Forks): ... this.  Document "set|show follow-exec-mode".
This commit is contained in:
Pedro Alves 2009-10-19 09:51:43 +00:00
parent 8dcb1aa7ca
commit 6c95b8df7f
87 changed files with 4409 additions and 812 deletions

View File

@ -1,3 +1,447 @@
2009-10-19 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
Add base multi-executable/process support to GDB.
* Makefile.in (SFILES): Add progspace.c.
(COMMON_OBS): Add progspace.o.
* progspace.h: New.
* progspace.c: New.
* breakpoint.h (struct bp_target_info) <placed_address_space>: New
field.
(struct bp_location) <pspace>: New field.
(struct breakpoint) <pspace>: New field.
(bpstat_stop_status, breakpoint_here_p)
(moribund_breakpoint_here_p, breakpoint_inserted_here_p)
(regular_breakpoint_inserted_here_p)
(software_breakpoint_inserted_here_p, breakpoint_thread_match)
(set_default_breakpoint): Adjust prototypes.
(remove_breakpoints_pid, breakpoint_program_space_exit): Declare.
(insert_single_step_breakpoint, deprecated_insert_raw_breakpoint):
Adjust prototypes.
* breakpoint.c (executing_startup): Delete.
(default_breakpoint_sspace): New.
(breakpoint_restore_shadows): Skip if the address space doesn't
match.
(update_watchpoint): Record the frame's program space in the
breakpoint location.
(insert_bp_location): Record the address space in target_info.
Adjust to pass the symbol space to solib_name_from_address.
(breakpoint_program_space_exit): New.
(insert_breakpoint_locations): Switch the symbol space and thread
when inserting breakpoints. Don't insert breakpoints in a vfork
parent waiting for vfork done if we're not attached to the vfork
child.
(remove_breakpoints_pid): New.
(reattach_breakpoints): Switch to a thread of PID. Ignore
breakpoints of other symbol spaces.
(create_internal_breakpoint): Store the symbol space in the sal.
(create_longjmp_master_breakpoint): Iterate over all symbol
spaces.
(update_breakpoints_after_exec): Ignore breakpoints for other
symbol spaces.
(remove_breakpoint): Rename to ...
(remove_breakpoint_1): ... this. Pass the breakpoints symbol
space to solib_name_from_address.
(remove_breakpoint): New.
(mark_breakpoints_out): Ignore breakpoints from other symbol
spaces.
(breakpoint_init_inferior): Ditto.
(breakpoint_here_p): Add an address space argument and adjust to
use breakpoint_address_match.
(moribund_breakpoint_here_p): Ditto.
(regular_breakpoint_inserted_here_p): Ditto.
(breakpoint_inserted_here_p): Ditto.
(software_breakpoint_inserted_here_p): Ditto.
(breakpoint_thread_match): Ditto.
(bpstat_check_location): Ditto.
(bpstat_stop_status): Ditto.
(print_breakpoint_location): If there's a location to print,
switch the current symbol space.
(print_one_breakpoint_location): Add `allflag' argument.
(print_one_breakpoint): Ditto. Adjust.
(do_captured_breakpoint_query): Adjust.
(breakpoint_1): Adjust.
(breakpoint_has_pc): Also match the symbol space.
(describe_other_breakpoints): Add a symbol space argument and
adjust.
(set_default_breakpoint): Add a symbol space argument. Set
default_breakpoint_sspace.
(breakpoint_address_match): New.
(check_duplicates_for): Add an address space argument, and adjust.
(set_raw_breakpoint): Record the symbol space in the location and
in the breakpoint.
(set_longjmp_breakpoint): Skip longjmp master breakpoints from
other symbol spaces.
(remove_thread_event_breakpoints, remove_solib_event_breakpoints)
(disable_breakpoints_in_shlibs): Skip breakpoints from other
symbol spaces.
(disable_breakpoints_in_unloaded_shlib): Match symbol spaces.
(create_catchpoint): Set the symbol space in the sal.
(disable_breakpoints_before_startup): Skip breakpoints from other
symbol spaces. Set executing_startup in the current symbol space.
(enable_breakpoints_after_startup): Clear executing_startup in the
current symbol space. Skip breakpoints from other symbol spaces.
(clone_momentary_breakpoint): Also copy the symbol space.
(add_location_to_breakpoint): Set the location's symbol space.
(bp_loc_is_permanent): Switch thread and symbol space.
(create_breakpoint): Adjust.
(expand_line_sal_maybe): Expand comment to mention symbol spaces.
Switch thread and symbol space when reading memory.
(parse_breakpoint_sals): Set the symbol space in the sal.
(break_command_really): Ditto.
(skip_prologue_sal): Switch and space.
(resolve_sal_pc): Ditto.
(watch_command_1): Record the symbol space in the sal.
(create_ada_exception_breakpoint): Adjust.
(clear_command): Adjust. Match symbol spaces.
(update_global_location_list): Use breakpoint_address_match.
(breakpoint_re_set_one): Switch thread and space.
(breakpoint_re_set): Save symbol space.
(breakpoint_re_set_thread): Also reset the symbol space.
(deprecated_insert_raw_breakpoint): Add an address space argument.
Adjust.
(insert_single_step_breakpoint): Ditto.
(single_step_breakpoint_inserted_here_p): Ditto.
(clear_syscall_counts): New.
(_initialize_breakpoint): Install it as inferior_exit observer.
* exec.h: Include "progspace.h".
(exec_bfd, exec_bfd_mtime): New defines.
(exec_close): Declare.
* exec.c: Include "gdbthread.h" and "progspace.h".
(exec_bfd, exec_bfd_mtime, current_target_sections_1): Delete.
(using_exec_ops): New.
(exec_close_1): Rename to exec_close, and make public.
(exec_close): Rename to exec_close_1, and adjust all callers. Add
description. Remove target sections and close executables from
all program spaces.
(exec_file_attach): Add comment.
(add_target_sections): Check on `using_exec_ops' to check if the
target should be pushed.
(remove_target_sections): Only unpush the target if there are no
more target sections in any symbol space.
* gdbcore.h: Include "exec.h".
(exec_bfd, exec_bfd_mtime): Remove declarations.
* frame.h (get_frame_program_space, get_frame_address_space)
(frame_unwind_program_space): Declare.
* frame.c (struct frame_info) <pspace, aspace>: New fields.
(create_sentinel_frame): Add program space argument. Set the
pspace and aspace fields of the frame object.
(get_current_frame, create_new_frame): Adjust.
(get_frame_program_space): New.
(frame_unwind_program_space): New.
(get_frame_address_space): New.
* stack.c (print_frame_info): Adjust.
(print_frame): Use the frame's program space.
* gdbthread.h (any_live_thread_of_process): Declare.
* thread.c (any_live_thread_of_process): New.
(switch_to_thread): Switch the program space as well.
(restore_selected_frame): Don't warn if trying to restore frame
level 0.
* inferior.h: Include "progspace.h".
(detach_fork): Declare.
(struct inferior) <removable, aspace, pspace>
<vfork_parent, vfork_child, pending_detach>
<waiting_for_vfork_done>: New fields.
<terminal_info>: Remove field.
<data, num_data>: New fields.
(register_inferior_data, register_inferior_data_with_cleanup)
(clear_inferior_data, set_inferior_data, inferior_data): Declare.
(exit_inferior, exit_inferior_silent, exit_inferior_num_silent)
(inferior_appeared): Declare.
(find_inferior_pid): Typo.
(find_inferior_id, find_inferior_for_program_space): Declare.
(set_current_inferior, save_current_inferior, prune_inferiors)
(number_of_inferiors): Declare.
(inferior_list): Declare.
* inferior.c: Include "gdbcore.h" and "symfile.h".
(inferior_list): Make public.
(delete_inferior_1): Always delete thread silently.
(find_inferior_id): Make public.
(current_inferior_): New.
(current_inferior): Use it.
(set_current_inferior): New.
(restore_inferior): New.
(save_current_inferior): New.
(free_inferior): Free the per-inferior data.
(add_inferior_silent): Allocate per-inferior data.
Call inferior_appeared.
(delete_threads_of_inferior): New.
(delete_inferior_1): Adjust interface to take an inferior pointer.
(delete_inferior): Adjust.
(delete_inferior_silent): Adjust.
(exit_inferior_1): New.
(exit_inferior): New.
(exit_inferior_silent): New.
(exit_inferior_num_silent): New.
(detach_inferior): Adjust.
(inferior_appeared): New.
(discard_all_inferiors): Adjust.
(find_inferior_id): Make public. Assert pid is not zero.
(find_inferior_for_program_space): New.
(have_inferiors): Check if we have any inferior with pid not zero.
(have_live_inferiors): Go over all pushed targets looking for
process_stratum.
(prune_inferiors): New.
(number_of_inferiors): New.
(print_inferior): Add executable column. Print vfork parent/child
relationships.
(inferior_command): Adjust to cope with not running inferiors.
(remove_inferior_command): New.
(add_inferior_command): New.
(clone_inferior_command): New.
(struct inferior_data): New.
(struct inferior_data_registration): New.
(struct inferior_data_registry): New.
(inferior_data_registry): New.
(register_inferior_data_with_cleanup): New.
(register_inferior_data): New.
(inferior_alloc_data): New.
(inferior_free_data): New.
(clear_inferior_data): New.
(set_inferior_data): New.
(inferior_data): New.
(initialize_inferiors): New.
(_initialize_inferiors): Register "add-inferior",
"remove-inferior" and "clone-inferior" commands.
* objfiles.h: Include "progspace.h".
(struct objfile) <pspace>: New field.
(symfile_objfile, object_files): Don't declare.
(ALL_PSPACE_OBJFILES): New.
(ALL_PSPACE_OBJFILES_SAFE): New.
(ALL_OBJFILES, ALL_OBJFILES_SAFE): Adjust.
(ALL_PSPACE_SYMTABS): New.
(ALL_PRIMARY_SYMTABS): Adjust.
(ALL_PSPACE_PRIMARY_SYMTABS): New.
(ALL_PSYMTABS): Adjust.
(ALL_PSPACE_PSYMTABS): New.
* objfiles.c (object_files, symfile_objfile): Delete.
(struct objfile_sspace_info): New.
(objfiles_pspace_data): New.
(objfiles_pspace_data_cleanup): New.
(get_objfile_pspace_data): New.
(objfiles_changed_p): Delete.
(allocate_objfile): Set the objfile's program space. Adjust to
reference objfiles_changed_p in pspace data.
(free_objfile): Adjust to reference objfiles_changed_p in pspace
data.
(objfile_relocate): Ditto.
(update_section_map): Add pspace argument. Adjust to iterate over
objfiles in the passed in pspace.
(find_pc_section): Delete sections and num_sections statics.
Adjust to refer to program space's objfiles_changed_p. Adjust to
refer to sections and num_sections store in the objfile's pspace
data.
(objfiles_changed): Adjust to reference objfiles_changed_p in
pspace data.
(_initialize_objfiles): New.
* linespec.c (decode_all_digits, decode_dollar): Set the sal's
program space.
* source.c (current_source_pspace): New.
(get_current_source_symtab_and_line): Set the sal's program space.
(set_current_source_symtab_and_line): Set current_source_pspace.
(select_source_symtab): Ditto. Use ALL_OBJFILES.
(forget_cached_source_info): Iterate over all program spaces.
* symfile.c (clear_symtab_users): Adjust.
* symmisc.c (print_symbol_bcache_statistics): Iterate over all
program spaces.
(print_objfile_statistics): Ditto.
(maintenance_print_msymbols): Ditto.
(maintenance_print_objfiles): Ditto.
(maintenance_info_symtabs): Ditto.
(maintenance_info_psymtabs): Ditto.
* symtab.h (SYMTAB_PSPACE): New.
(struct symtab_and_line) <pspace>: New field.
* symtab.c (init_sal): Clear the sal's program space.
(find_pc_sect_symtab): Set the sal's program space. Switch thread
and space.
(append_expanded_sal): Add program space argument. Iterate over
all program spaces.
(expand_line_sal): Iterate over all program spaces. Switch
program space.
* target.h (enum target_waitkind) <TARGET_WAITKIND_VFORK_DONE>: New.
(struct target_ops) <to_thread_address_space>: New field.
(target_thread_address_space): Define.
* target.c (target_detach): Only remove breakpoints from the
inferior we're detaching.
(target_thread_address_space): New.
* defs.h (initialize_progspace): Declare.
* top.c (gdb_init): Call it.
* solist.h (struct so_list) <sspace>: New field.
* solib.h (struct program_space): Forward declare.
(solib_name_from_address): Adjust prototype.
* solib.c (so_list_head): Replace with a macro referencing the
program space.
(update_solib_list): Set the so's program space.
(solib_name_from_address): Add a program space argument and adjust.
* solib-svr4.c (struct svr4_info) <pid>: Delete field.
<interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low>
<interp_plt_sect_high>: New fields.
(svr4_info_p, svr4_info): Delete.
(solib_svr4_sspace_data): New.
(get_svr4_info): Rewrite.
(svr4_sspace_data_cleanup): New.
(open_symbol_file_object): Adjust.
(svr4_default_sos): Adjust.
(svr4_fetch_objfile_link_map): Adjust.
(interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low)
(interp_plt_sect_high): Delete.
(svr4_in_dynsym_resolve_code): Adjust.
(enable_break): Adjust.
(svr4_clear_solib): Revert bit that removed the svr4_info here,
and reinstate clearing debug_base, debug_loader_offset_p,
debug_loader_offset and debug_loader_name.
(_initialize_svr4_solib): Register solib_svr4_pspace_data. Don't
install an inferior_exit observer anymore.
* printcmd.c (struct display) <pspace>: New field.
(display_command): Set the display's sspace.
(do_one_display): Match the display's sspace.
(display_uses_solib_p): Ditto.
* linux-fork.c (detach_fork): Moved to infrun.c.
(_initialize_linux_fork): Moved "detach-on-fork" command to
infrun.c.
* infrun.c (detach_fork): Moved from linux-fork.c.
(proceed_after_vfork_done): New.
(handle_vfork_child_exec_or_exit): New.
(follow_exec_mode_replace, follow_exec_mode_keep)
(follow_exec_mode_names, follow_exec_mode_string)
(show_follow_exec_mode_string): New.
(follow_exec): New. Reinstate the mark_breakpoints_out call.
Remove shared libraries before attaching new executable. If user
wants to keep the inferior, keep it.
(displaced_step_fixup): Adjust to pass an address space to the
breakpoints module.
(resume): Ditto.
(clear_proceed_status): In all-stop mode, always clear the proceed
status of all threads.
(prepare_to_proceed): Adjust to pass an address space to the
breakpoints module.
(proceed): Ditto.
(adjust_pc_after_break): Ditto.
(handle_inferior_event): When handling a process exit, switch the
program space to the inferior's that had exited. Call
handle_vfork_child_exec_or_exit. Adjust to pass an address space
to the breakpoints module. In non-stop mode, when following a
fork and detach-fork is off, also resume the other branch. Handle
TARGET_WAITKIND_VFORK_DONE. Set the program space in sals.
(normal_stop): Prune inferiors.
(_initialize_infrun): Install the new "follow-exec-mode" command.
"detach-on-fork" moved here.
* regcache.h (get_regcache_aspace): Declare.
* regcache.c (struct regcache) <aspace>: New field.
(regcache_xmalloc): Clear the aspace.
(get_regcache_aspace): New.
(regcache_cpy): Copy the aspace field.
(regcache_cpy_no_passthrough): Ditto.
(get_thread_regcache): Fetch the thread's address space from the
target, and store it in the regcache.
* infcall.c (call_function_by_hand): Set the sal's pspace.
* arch-utils.c (default_has_shared_address_space): New.
* arch-utils.h (default_has_shared_address_space): Declare.
* gdbarch.sh (has_shared_address_space): New.
* gdbarch.h, gdbarch.c: Regenerate.
* linux-tdep.c: Include auxv.h, target.h, elf/common.h.
(linux_has_shared_address_space): New.
(_initialize_linux_tdep): Declare.
* arm-tdep.c (arm_software_single_step): Pass the frame's address
space to insert_single_step_breakpoint.
* arm-linux-tdep.c (arm_linux_software_single_step): Pass the
frame's pspace to breakpoint functions.
* cris-tdep.c (crisv32_single_step_through_delay): Ditto.
(cris_software_single_step): Ditto.
* mips-tdep.c (deal_with_atomic_sequence): Add frame argument.
Pass the frame's pspace to breakpoint functions.
(mips_software_single_step): Adjust.
(mips_single_step_through_delay): Adjust.
* rs6000-aix-tdep.c (rs6000_software_single_step): Adjust.
* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Adjust.
* solib-irix.c (enable_break): Adjust to pass the current frame's
address space to breakpoint functions.
* sparc-tdep.c (sparc_software_single_step): Ditto.
* spu-tdep.c (spu_software_single_step): Ditto.
* alpha-tdep.c (alpha_software_single_step): Ditto.
* record.c (record_wait): Adjust to pass an address space to the
breakpoints module.
* fork-child.c (fork_inferior): Set the new inferior's program and
address spaces.
* inf-ptrace.c (inf_ptrace_follow_fork): Copy the parent's program
and address spaces.
(inf_ptrace_attach): Set the inferior's program and address spaces.
* linux-nat.c: Include "solib.h".
(linux_child_follow_fork): Manage parent and child's program and
address spaces. Clone the parent's program space if necessary.
Don't wait for the vfork to be done here. Refuse to resume if
following the vfork parent while leaving the child stopped.
(resume_callback): Don't resume a vfork parent.
(linux_nat_resume): Also check for pending events in the
lp->waitstatus field.
(linux_handle_extended_wait): Report TARGET_WAITKIND_VFORK_DONE
events to the core.
(stop_wait_callback): Don't wait for SIGSTOP on vfork parents.
(cancel_breakpoint): Adjust.
* linux-thread-db.c (thread_db_wait): Don't remove thread event
breakpoints here.
(thread_db_mourn_inferior): Don't mark breakpoints out here.
Remove thread event breakpoints after mourning.
* corelow.c: Include progspace.h.
(core_open): Set the inferior's program and address spaces.
* remote.c (remote_add_inferior): Set the new inferior's program
and address spaces.
(remote_start_remote): Update address spaces.
(extended_remote_create_inferior_1): Don't init the thread list if
we already debugging other inferiors.
* darwin-nat.c (darwin_attach): Set the new inferior's program and
address spaces.
* gnu-nat.c (gnu_attach): Ditto.
* go32-nat.c (go32_create_inferior): Ditto.
* inf-ttrace.c (inf_ttrace_follow_fork, inf_ttrace_attach): Ditto.
* monitor.c (monitor_open): Ditto.
* nto-procfs.c (procfs_attach, procfs_create_inferior): Ditto.
* procfs.c (do_attach): Ditto.
* windows-nat.c (do_initial_windows_stuff): Ditto.
* inflow.c (inferior_process_group)
(terminal_init_inferior_with_pgrp, terminal_inferior,
(terminal_ours_1, inflow_inferior_exit, copy_terminal_info)
(child_terminal_info, new_tty_postfork, set_sigint_trap): Adjust
to use per-inferior data instead of inferior->terminal_info.
(inflow_inferior_data): New.
(inflow_new_inferior): Delete.
(inflow_inferior_data_cleanup): New.
(get_inflow_inferior_data): New.
* mi/mi-interp.c (mi_new_inferior): Rename to...
(mi_inferior_appeared): ... this.
(mi_interpreter_init): Adjust.
* tui/tui-disasm.c: Include "progspace.h".
(tui_set_disassem_content): Pass an address space to
breakpoint_here_p.
* NEWS: Mention multi-program debugging support. Mention new
commands "add-inferior", "clone-inferior", "remove-inferior",
"maint info program-spaces", and new option "set
follow-exec-mode".
2009-10-19 Don Lee <don.lee@sunplusct.com>
* score-tdep.c: Delete dead codes.

View File

@ -661,6 +661,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
objc-exp.y objc-lang.c \
objfiles.c osabi.c observer.c osdata.c \
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
progspace.c \
prologue-value.c \
regcache.c reggroups.c remote.c remote-fileio.c reverse.c \
scm-exp.c scm-lang.c scm-valprint.c \
@ -834,7 +835,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
prologue-value.o memory-map.o xml-support.o xml-syscall.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o record.o \
jit.o
jit.o progspace.o
# Definitions for the syscall's XML files and dir
XML_SYSCALLS_DIR = syscalls/

View File

@ -11,6 +11,40 @@ Xilinx MicroBlaze microblaze-*-*
Xilinx MicroBlaze microblaze
* Multi-program debugging.
GDB now has support for multi-program (a.k.a. multi-executable or
multi-exec) debugging. This allows for debugging multiple inferiors
simultaneously each running a different program under the same GDB
session. See "Debugging Multiple Inferiors and Programs" in the
manual for more information. This implied some user visible changes
in the multi-inferior support. For example, "info inferiors" now
lists inferiors that are not running yet or that have exited
already. See also "New commands" and "New options" below.
* New commands (for set/show, see "New options" below)
add-inferior [-copies <N>] [-exec <FILENAME>]
Add a new inferior.
clone-inferior [-copies <N>] [ID]
Make a new inferior ready to execute the same program another
inferior has loaded.
remove-inferior ID
Remove an inferior.
maint info program-spaces
List the program spaces loaded into GDB.
* New options
set follow-exec-mode new|same
show follow-exec-mode
Control whether GDB reuses the same inferior across an exec call or
creates a new one. This is useful to be able to restart the old
executable after the inferior having done an exec call.
*** Changes in GDB 7.0
* GDB now has an interface for JIT compilation. Applications that

View File

@ -1489,12 +1489,13 @@ int
alpha_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR pc, next_pc;
pc = get_frame_pc (frame);
next_pc = alpha_next_pc (frame, pc);
insert_single_step_breakpoint (gdbarch, next_pc);
insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}

View File

@ -757,6 +757,14 @@ get_current_arch (void)
return target_gdbarch;
}
int
default_has_shared_address_space (struct gdbarch *gdbarch)
{
/* Simply say no. In most unix-like targets each inferior/process
has its own address space. */
return 0;
}
/* */
extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */

View File

@ -153,4 +153,6 @@ extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);
routines to determine the architecture to execute a command in. */
extern struct gdbarch *get_current_arch (void);
extern int default_has_shared_address_space (struct gdbarch *);
#endif

View File

@ -586,6 +586,7 @@ static int
arm_linux_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
/* The Linux kernel offers some user-mode helpers in a high page. We can
@ -596,7 +597,7 @@ arm_linux_software_single_step (struct frame_info *frame)
if (next_pc > 0xffff0000)
next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
insert_single_step_breakpoint (gdbarch, next_pc);
insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}

View File

@ -2792,13 +2792,14 @@ int
arm_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
/* NOTE: This may insert the wrong breakpoint instruction when
single-stepping over a mode-changing instruction, if the
CPSR heuristics are used. */
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
insert_single_step_breakpoint (gdbarch, next_pc);
insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -176,6 +176,9 @@ enum target_hw_bp_type
struct bp_target_info
{
/* Address space at which the breakpoint was placed. */
struct address_space *placed_address_space;
/* Address at which the breakpoint was placed. This is normally the
same as ADDRESS from the bp_location, except when adjustment
happens in gdbarch_breakpoint_from_pc. The most common form of
@ -272,6 +275,14 @@ struct bp_location
different from the breakpoint architecture. */
struct gdbarch *gdbarch;
/* The program space associated with this breakpoint location
address. Note that an address space may be represented in more
than one program space (e.g. each uClinux program will be given
its own program space, but there will only be one address space
for all of them), but we must not insert more than one location
at the same address in the same address space. */
struct program_space *pspace;
/* Note that zero is a perfectly valid code address on some platforms
(for example, the mn10200 (OBSOLETE) and mn10300 simulators). NULL
is not a special value for this field. Valid for all types except
@ -409,6 +420,9 @@ struct breakpoint
equals this. */
struct frame_id frame_id;
/* The program space used to set the breakpoint. */
struct program_space *pspace;
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
/* Architecture we used to set the breakpoint. */
@ -520,7 +534,8 @@ extern void bpstat_clear (bpstat *);
is part of the bpstat is copied as well. */
extern bpstat bpstat_copy (bpstat);
extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
extern bpstat bpstat_stop_status (struct address_space *aspace,
CORE_ADDR pc, ptid_t ptid);
/* This bpstat_what stuff tells wait_for_inferior what to do with a
breakpoint (a challenging task). */
@ -707,17 +722,17 @@ enum breakpoint_here
/* Prototypes for breakpoint-related functions. */
extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
extern enum breakpoint_here breakpoint_here_p (struct address_space *, CORE_ADDR);
extern int moribund_breakpoint_here_p (CORE_ADDR);
extern int moribund_breakpoint_here_p (struct address_space *, CORE_ADDR);
extern int breakpoint_inserted_here_p (CORE_ADDR);
extern int breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);
extern int regular_breakpoint_inserted_here_p (CORE_ADDR);
extern int regular_breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);
extern int software_breakpoint_inserted_here_p (CORE_ADDR);
extern int software_breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);
extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
extern int breakpoint_thread_match (struct address_space *, CORE_ADDR, ptid_t);
extern void until_break_command (char *, int, int);
@ -735,7 +750,8 @@ extern struct breakpoint *clone_momentary_breakpoint (struct breakpoint *bpkt);
extern void set_ignore_count (int, int, int);
extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
extern void set_default_breakpoint (int, struct program_space *,
CORE_ADDR, struct symtab *, int);
extern void breakpoint_init_inferior (enum inf_context);
@ -766,6 +782,8 @@ extern void insert_breakpoints (void);
extern int remove_breakpoints (void);
extern int remove_breakpoints_pid (int pid);
/* This function can be used to physically insert eventpoints from the
specified traced inferior process, without modifying the breakpoint
package's state. This can be useful for those targets which support
@ -801,6 +819,11 @@ extern void update_breakpoints_after_exec (void);
inferior_ptid. */
extern int detach_breakpoints (int);
/* This function is called when program space PSPACE is about to be
deleted. It takes care of updating breakpoints to not reference
this PSPACE anymore. */
extern void breakpoint_program_space_exit (struct program_space *pspace);
extern void set_longjmp_breakpoint (int thread);
extern void delete_longjmp_breakpoint (int thread);
@ -909,13 +932,15 @@ extern int remove_hw_watchpoints (void);
/* Manage a software single step breakpoint (or two). Insert may be called
twice before remove is called. */
extern void insert_single_step_breakpoint (struct gdbarch *, CORE_ADDR);
extern void insert_single_step_breakpoint (struct gdbarch *,
struct address_space *, CORE_ADDR);
extern void remove_single_step_breakpoints (void);
/* Manage manual breakpoints, separate from the normal chain of
breakpoints. These functions are used in murky target-specific
ways. Please do not add more uses! */
extern void *deprecated_insert_raw_breakpoint (struct gdbarch *, CORE_ADDR);
extern void *deprecated_insert_raw_breakpoint (struct gdbarch *,
struct address_space *, CORE_ADDR);
extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *);
/* Check if any hardware watchpoints have triggered, according to the

View File

@ -45,6 +45,7 @@
#include "exceptions.h"
#include "solib.h"
#include "filenames.h"
#include "progspace.h"
#ifndef O_LARGEFILE
@ -208,7 +209,7 @@ core_close (int quitting)
{
int pid = ptid_get_pid (inferior_ptid);
inferior_ptid = null_ptid; /* Avoid confusion from thread stuff */
delete_inferior_silent (pid);
exit_inferior_silent (pid);
/* Clear out solib state while the bfd is still open. See
comments in clear_solib in solib.c. */
@ -275,8 +276,8 @@ add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg)
lwpid = core_tid;
}
if (!in_inferior_list (pid))
add_inferior_silent (pid);
if (current_inferior ()->pid == 0)
inferior_appeared (current_inferior (), pid);
ptid = ptid_build (pid, lwpid, 0);
@ -302,6 +303,7 @@ core_open (char *filename, int from_tty)
int scratch_chan;
int flags;
int corelow_pid = CORELOW_PID;
struct inferior *inf;
target_preopen (from_tty);
if (!filename)

View File

@ -471,7 +471,7 @@ crisv32_single_step_through_delay (struct gdbarch *gdbarch,
{
/* In delay slot - check if there's a breakpoint at the preceding
instruction. */
if (breakpoint_here_p (erp & ~0x1))
if (breakpoint_here_p (get_frame_address_space (this_frame), erp & ~0x1))
ret = 1;
}
return ret;
@ -2132,6 +2132,7 @@ static int
cris_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
inst_env_type inst_env;
/* Analyse the present instruction environment and insert
@ -2149,13 +2150,14 @@ cris_software_single_step (struct frame_info *frame)
and possibly another one for a branch, jump, etc. */
CORE_ADDR next_pc
= (CORE_ADDR) inst_env.reg[gdbarch_pc_regnum (gdbarch)];
insert_single_step_breakpoint (gdbarch, next_pc);
insert_single_step_breakpoint (gdbarch, aspace, next_pc);
if (inst_env.branch_found
&& (CORE_ADDR) inst_env.branch_break_address != next_pc)
{
CORE_ADDR branch_target_address
= (CORE_ADDR) inst_env.branch_break_address;
insert_single_step_breakpoint (gdbarch, branch_target_address);
insert_single_step_breakpoint (gdbarch,
aspace, branch_target_address);
}
}

View File

@ -1543,8 +1543,10 @@ darwin_attach (struct target_ops *ops, char *args, int from_tty)
pid, safe_strerror (errno), errno);
inferior_ptid = pid_to_ptid (pid);
inf = add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
inf->attach_flag = 1;
/* Always add a main thread. */
add_thread_silent (inferior_ptid);

View File

@ -1218,4 +1218,9 @@ extern ULONGEST align_down (ULONGEST v, int n);
void *hashtab_obstack_allocate (void *data, size_t size, size_t count);
void dummy_obstack_deallocate (void *object, void *data);
/* From progspace.c */
extern void initialize_progspace (void);
extern void initialize_inferiors (void);
#endif /* #ifndef DEFS_H */

View File

@ -1,3 +1,19 @@
2009-10-19 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
* observer.texi (new_inferior): Rename to...
(inferior_appeared): ... this.
* gdb.texinfo (Inferiors): Rename node to ...
(Inferiors and Programs): ... this. Mention running multiple
programs in the same debug session.
<info inferiors>: Mention the new 'Executable' column if "info
inferiors". Update examples. Document the "add-inferior",
"clone-inferior", "remove-inferior" and "maint info
program-spaces" commands.
(Process): Rename node to...
(Forks): ... this. Document "set|show follow-exec-mode".
2009-10-11 Michael Snyder <msnyder@vmware.com>
* gdb.texinfo (ReverseStep): Show default as "unsupported".

View File

@ -1794,9 +1794,9 @@ kill a child process.
* Attach:: Debugging an already-running process
* Kill Process:: Killing the child process
* Inferiors:: Debugging multiple inferiors
* Inferiors and Programs:: Debugging multiple inferiors and 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
@ -2349,30 +2349,30 @@ next type @code{run}, @value{GDBN} notices that the file has changed, and
reads the symbol table again (while trying to preserve your current
breakpoint settings).
@node Inferiors
@section Debugging Multiple Inferiors
@node Inferiors and Programs
@section Debugging Multiple Inferiors and Programs
Some @value{GDBN} targets are able to run multiple processes created
from a single executable. This can happen, for instance, with an
embedded system reporting back several processes via the remote
protocol.
@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.
@cindex inferior
@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 do not
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.
may be retained after a process exits. Inferiors have unique
identifiers that are different from process ids. 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 address space. Each inferior may in turn have multiple
threads running in it.
Each inferior may in turn have multiple threads running in it.
To find out what inferiors exist at any moment, use @code{info inferiors}:
To find out what inferiors exist at any moment, use @w{@code{info
inferiors}}:
@table @code
@kindex info inferiors
@ -2387,6 +2387,10 @@ the inferior number assigned by @value{GDBN}
@item
the target system's inferior identifier
@item
the name of the executable the inferior is running.
@end enumerate
@noindent
@ -2399,9 +2403,9 @@ For example,
@smallexample
(@value{GDBP}) info inferiors
Num Description
* 1 process 2307
2 process 3401
Num Description Executable
2 process 2307 hello
* 1 process 3401 goodbye
@end smallexample
To switch focus between inferiors, use the @code{inferior} command:
@ -2414,9 +2418,57 @@ Make inferior number @var{infno} the current inferior. The argument
in the first field of the @samp{info inferiors} display.
@end table
To quit debugging one of the inferiors, you can either detach from it
by using the @w{@code{detach inferior}} command (allowing it to run
independently), or kill it using the @w{@code{kill inferior}} command:
You can get multiple executables into a debugging session via the
@code{add-inferior} and @w{@code{clone-inferior}} commands. On some
systems @value{GDBN} can add inferiors to the debug session
automatically by following calls to @code{fork} and @code{exec}. To
remove inferiors from the debugging session use the
@w{@code{remove-inferior}} command.
@table @code
@kindex add-inferior
@item add-inferior [ -copies @var{n} ] [ -exec @var{executable} ]
Adds @var{n} inferiors to be run using @var{executable} as the
executable. @var{n} defaults to 1. If no executable is specified,
the inferiors begins empty, with no program. You can still assign or
change the program assigned to the inferior at any time by using the
@code{file} command with the executable name as its argument.
@kindex clone-inferior
@item clone-inferior [ -copies @var{n} ] [ @var{infno} ]
Adds @var{n} inferiors ready to execute the same program as inferior
@var{infno}. @var{n} defaults to 1. @var{infno} defaults to the
number of the current inferior. This is a convenient command when you
want to run another instance of the inferior you are debugging.
@smallexample
(@value{GDBP}) info inferiors
Num Description Executable
* 1 process 29964 helloworld
(@value{GDBP}) clone-inferior
Added inferior 2.
1 inferiors added.
(@value{GDBP}) info inferiors
Num Description Executable
2 <null> helloworld
* 1 process 29964 helloworld
@end smallexample
You can now simply switch focus to inferior 2 and run it.
@kindex remove-inferior
@item remove-inferior @var{infno}
Removes the inferior @var{infno}. It is not possible to remove an
inferior that is running with this command. For those, use the
@code{kill} or @code{detach} command first.
@end table
To quit debugging one of the running inferiors that is not the current
inferior, you can either detach from it by using the @w{@code{detach
inferior}} command (allowing it to run independently), or kill it
using the @w{@code{kill inferior}} command:
@table @code
@kindex detach inferior @var{infno}
@ -2430,6 +2482,12 @@ Kill the inferior identified by @value{GDBN} inferior number
@var{infno}, and remove it from the inferior list.
@end table
After the successful completion of a command such as @code{detach},
@code{detach inferior}, @code{kill} or @code{kill inferior}, or after
a normal process exit, the inferior is still valid and listed with
@code{info inferiors}, ready to be restarted.
To be notified when inferiors are started or exit under @value{GDBN}'s
control use @w{@code{set print inferior-events}}:
@ -2450,6 +2508,67 @@ Show whether messages will be printed when @value{GDBN} detects that
inferiors have started, exited or have been detached.
@end table
Many commands will work the same with multiple programs as with a
single program: e.g., @code{print myglobal} will simply display the
value of @code{myglobal} in the current inferior.
Occasionaly, when debugging @value{GDBN} itself, it may be useful to
get more info about the relationship of inferiors, programs, address
spaces in a debug session. You can do that with the @w{@code{maint
info program-spaces}} command.
@table @code
@kindex maint info program-spaces
@item maint info program-spaces
Print a list of all program spaces currently being managed by
@value{GDBN}.
@value{GDBN} displays for each program space (in this order):
@enumerate
@item
the program space number assigned by @value{GDBN}
@item
the name of the executable loaded into the program space, with e.g.,
the @code{file} command.
@end enumerate
@noindent
An asterisk @samp{*} preceding the @value{GDBN} program space number
indicates the current program space.
In addition, below each program space line, @value{GDBN} prints extra
information that isn't suitable to display in tabular form. For
example, the list of inferiors bound to the program space.
@smallexample
(@value{GDBP}) maint info program-spaces
Id Executable
2 goodbye
Bound inferiors: ID 1 (process 21561)
* 1 hello
@end smallexample
Here we can see that no inferior is running the program @code{hello},
while @code{process 21561} is running the program @code{goodbye}. On
some targets, it is possible that multiple inferiors are bound to the
same program space. The most common example is that of debugging both
the parent and child processes of a @code{vfork} call. For example,
@smallexample
(@value{GDBP}) maint info program-spaces
Id Executable
* 1 vfork-test
Bound inferiors: ID 2 (process 18050), ID 1 (process 18045)
@end smallexample
Here, both inferior 2 and inferior 1 are running in the same program
space as a result of inferior 1 having executed a @code{vfork} call.
@end table
@node Threads
@section Debugging Programs with Multiple Threads
@ -2729,8 +2848,8 @@ only on some platforms.
Display current libthread_db search path.
@end table
@node Processes
@section Debugging Programs with Multiple Processes
@node Forks
@section Debugging Forks
@cindex fork, debugging programs which call
@cindex multiple processes
@ -2821,13 +2940,14 @@ If you choose to set @samp{detach-on-fork} mode off, then @value{GDBN}
will retain control of all forked processes (including nested forks).
You can list the forked processes under the control of @value{GDBN} by
using the @w{@code{info inferiors}} command, and switch from one fork
to another by using the @code{inferior} command (@pxref{Inferiors,
,Debugging Multiple Inferiors}).
to another by using the @code{inferior} command (@pxref{Inferiors and
Programs, ,Debugging Multiple Inferiors and Programs}).
To quit debugging one of the forked processes, you can either detach
from it by using the @w{@code{detach inferior}} command (allowing it
to run independently), or kill it using the @w{@code{kill inferior}}
command. @xref{Inferiors, ,Debugging Multiple Inferiors}.
command. @xref{Inferiors and Programs, ,Debugging Multiple Inferiors
and Programs}.
If you ask to debug a child process and a @code{vfork} is followed by an
@code{exec}, @value{GDBN} executes the new target up to the first
@ -2839,9 +2959,68 @@ On some systems, when a child process is spawned by @code{vfork}, you
cannot debug the child or parent until an @code{exec} call completes.
If you issue a @code{run} command to @value{GDBN} after an @code{exec}
call executes, the new target restarts. To restart the parent process,
use the @code{file} command with the parent executable name as its
argument.
call executes, the new target restarts. To restart the parent
process, use the @code{file} command with the parent executable name
as its argument. By default, after an @code{exec} call executes,
@value{GDBN} discards the symbols of the previous executable image.
You can change this behaviour with the @w{@code{set follow-exec-mode}}
command.
@table @code
@kindex set follow-exec-mode
@item set follow-exec-mode @var{mode}
Set debugger response to a program call of @code{exec}. An
@code{exec} call replaces the program image of a process.
@code{follow-exec-mode} can be:
@table @code
@item new
@value{GDBN} creates a new inferior and rebinds the process to this
new inferior. The program the process was running before the
@code{exec} call can be restarted afterwards by restarting the
original inferior.
For example:
@smallexample
(@value{GDBP}) info inferiors
(gdb) info inferior
Id Description Executable
* 1 <null> prog1
(@value{GDBP}) run
process 12020 is executing new program: prog2
Program exited normally.
(@value{GDBP}) info inferiors
Id Description Executable
* 2 <null> prog2
1 <null> prog1
@end smallexample
@item same
@value{GDBN} keeps the process bound to the same inferior. The new
executable image replaces the previous executable loaded in the
inferior. Restarting the inferior after the @code{exec} call, with
e.g., the @code{run} command, restarts the executable the process was
running after the @code{exec} call. This is the default mode.
For example:
@smallexample
(@value{GDBP}) info inferiors
Id Description Executable
* 1 <null> prog1
(@value{GDBP}) run
process 12020 is executing new program: prog2
Program exited normally.
(@value{GDBP}) info inferiors
Id Description Executable
* 1 <null> prog2
@end smallexample
@end table
@end table
You can use the @code{catch} command to make @value{GDBN} stop whenever
a @code{fork}, @code{vfork}, or @code{exec} call is made. @xref{Set

View File

@ -199,7 +199,7 @@ The thread's ptid has changed. The @var{old_ptid} parameter specifies
the old value, and @var{new_ptid} specifies the new value.
@end deftypefun
@deftypefun void new_inferior (int @var{pid})
@deftypefun void inferior_appeared (int @var{pid})
@value{GDBN} has attached to a new inferior identified by @var{pid}.
@end deftypefun

View File

@ -32,6 +32,8 @@
#include "exec.h"
#include "observer.h"
#include "arch-utils.h"
#include "gdbthread.h"
#include "progspace.h"
#include <fcntl.h>
#include "readline/readline.h"
@ -50,8 +52,6 @@ void (*deprecated_file_changed_hook) (char *);
/* Prototypes for local functions */
static void exec_close (int);
static void file_command (char *, int);
static void set_section_command (char *, int);
@ -66,20 +66,8 @@ void _initialize_exec (void);
struct target_ops exec_ops;
/* The Binary File Descriptor handle for the executable file. */
bfd *exec_bfd = NULL;
long exec_bfd_mtime = 0;
/* GDB currently only supports a single symbol/address space for the
whole debug session. When that limitation is lifted, this global
goes away. */
static struct target_section_table current_target_sections_1;
/* The set of target sections matching the sections mapped into the
current inferior's address space. */
static struct target_section_table *current_target_sections
= &current_target_sections_1;
/* True if the exec target is pushed on the stack. */
static int using_exec_ops;
/* Whether to open exec and core files read-only or read-write. */
@ -105,8 +93,8 @@ exec_open (char *args, int from_tty)
/* Close and clear exec_bfd. If we end up with no target sections to
read memory from, this unpushes the exec_ops target. */
static void
exec_close_1 (void)
void
exec_close (void)
{
if (exec_bfd)
{
@ -127,12 +115,17 @@ exec_close_1 (void)
}
}
/* This is the target_close implementation. Clears all target
sections and closes all executable bfds from all program spaces. */
static void
exec_close (int quitting)
exec_close_1 (int quitting)
{
int need_symtab_cleanup = 0;
struct vmap *vp, *nxt;
using_exec_ops = 0;
for (nxt = vmap; nxt != NULL;)
{
vp = nxt;
@ -163,20 +156,32 @@ exec_close (int quitting)
vmap = NULL;
/* Delete all target sections. */
resize_section_table
(current_target_sections,
-resize_section_table (current_target_sections, 0));
{
struct program_space *ss;
struct cleanup *old_chain;
/* Remove exec file. */
exec_close_1 ();
old_chain = save_current_program_space ();
ALL_PSPACES (ss)
{
set_current_program_space (ss);
/* Delete all target sections. */
resize_section_table
(current_target_sections,
-resize_section_table (current_target_sections, 0));
exec_close ();
}
do_cleanups (old_chain);
}
}
void
exec_file_clear (int from_tty)
{
/* Remove exec file. */
exec_close_1 ();
exec_close ();
if (from_tty)
printf_unfiltered (_("No executable file now.\n"));
@ -203,7 +208,7 @@ void
exec_file_attach (char *filename, int from_tty)
{
/* Remove any previous exec file. */
exec_close_1 ();
exec_close ();
/* Now open and digest the file the user requested, if any. */
@ -258,7 +263,7 @@ exec_file_attach (char *filename, int from_tty)
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
exec_close_1 ();
exec_close ();
error (_("\"%s\": not in executable format: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
@ -273,7 +278,7 @@ exec_file_attach (char *filename, int from_tty)
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
exec_close_1 ();
exec_close ();
error (_("\"%s\": can't find the file sections: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
@ -283,7 +288,7 @@ exec_file_attach (char *filename, int from_tty)
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
exec_close_1 ();
exec_close ();
error (_("\"%s\": can't find the file sections: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
@ -295,7 +300,8 @@ exec_file_attach (char *filename, int from_tty)
set_gdbarch_from_file (exec_bfd);
/* Add the executable's sections to the current address spaces'
list of sections. */
list of sections. This possibly pushes the exec_ops
target. */
add_target_sections (sections, sections_end);
xfree (sections);
@ -465,8 +471,11 @@ add_target_sections (struct target_section *sections,
/* If these are the first file sections we can provide memory
from, push the file_stratum target. */
if (space == 0)
push_target (&exec_ops);
if (!using_exec_ops)
{
using_exec_ops = 1;
push_target (&exec_ops);
}
}
}
@ -499,7 +508,16 @@ remove_target_sections (bfd *abfd)
/* If we don't have any more sections to read memory from,
remove the file_stratum target from the stack. */
if (old_count + (dest - src) == 0)
unpush_target (&exec_ops);
{
struct program_space *pspace;
ALL_PSPACES (pspace)
if (pspace->target_sections.sections
!= pspace->target_sections.sections_end)
return;
unpush_target (&exec_ops);
}
}
}
@ -817,7 +835,7 @@ init_exec_ops (void)
exec_ops.to_doc = "Use an executable file as a target.\n\
Specify the filename of the executable file.";
exec_ops.to_open = exec_open;
exec_ops.to_close = exec_close;
exec_ops.to_close = exec_close_1;
exec_ops.to_attach = find_default_attach;
exec_ops.to_xfer_partial = exec_xfer_partial;
exec_ops.to_get_section_table = exec_get_section_table;

View File

@ -21,6 +21,7 @@
#define EXEC_H
#include "target.h"
#include "progspace.h"
struct target_section;
struct target_ops;
@ -28,6 +29,9 @@ struct bfd;
extern struct target_ops exec_ops;
#define exec_bfd current_program_space->ebfd
#define exec_bfd_mtime current_program_space->ebfd_mtime
/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
Returns 0 if OK, 1 on error. */
@ -82,5 +86,6 @@ extern void add_target_sections (struct target_section *sections,
extern void print_section_info (struct target_section_table *table,
bfd *abfd);
extern void exec_close (void);
#endif

View File

@ -138,6 +138,7 @@ 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;
/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
@ -395,7 +396,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
if (!have_inferiors ())
init_thread_list ();
add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
/* Needed for wait_for_inferior stuff below. */
inferior_ptid = pid_to_ptid (pid);

View File

@ -70,6 +70,12 @@ struct frame_info
moment leave this as speculation. */
int level;
/* The frame's program space. */
struct program_space *pspace;
/* The frame's address space. */
struct address_space *aspace;
/* 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
@ -1059,10 +1065,12 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
/* Create a sentinel frame. */
static struct frame_info *
create_sentinel_frame (struct regcache *regcache)
create_sentinel_frame (struct program_space *pspace, struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
frame->level = -1;
frame->pspace = pspace;
frame->aspace = get_regcache_aspace (regcache);
/* 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. */
@ -1144,7 +1152,7 @@ get_current_frame (void)
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
create_sentinel_frame (get_current_regcache ());
create_sentinel_frame (current_program_space, get_current_regcache ());
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
RETURN_MASK_ERROR) != 0)
{
@ -1275,7 +1283,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
fi->next = create_sentinel_frame (get_current_regcache ());
fi->next = create_sentinel_frame (current_program_space, get_current_regcache ());
/* Set/update this frame's cached PC value, found in the next frame.
Do this before looking for this frame's unwinder. A sniffer is
@ -1284,6 +1292,10 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
fi->next->prev_pc.value = pc;
fi->next->prev_pc.p = 1;
/* We currently assume that frame chain's can't cross spaces. */
fi->pspace = fi->next->pspace;
fi->aspace = fi->next->aspace;
/* 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);
@ -1557,6 +1569,11 @@ get_prev_frame_raw (struct frame_info *this_frame)
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
/* For now, assume we don't have frame chains crossing address
spaces. */
prev_frame->pspace = this_frame->pspace;
prev_frame->aspace = this_frame->aspace;
/* Don't yet compute ->unwind (and hence ->type). It is computed
on-demand in get_frame_type, frame_register_unwind, and
get_frame_id. */
@ -1939,6 +1956,29 @@ get_frame_type (struct frame_info *frame)
return frame->unwind->type;
}
struct program_space *
get_frame_program_space (struct frame_info *frame)
{
return frame->pspace;
}
struct program_space *
frame_unwind_program_space (struct frame_info *this_frame)
{
gdb_assert (this_frame);
/* This is really a placeholder to keep the API consistent --- we
assume for now that we don't have frame chains crossing
spaces. */
return this_frame->pspace;
}
struct address_space *
get_frame_address_space (struct frame_info *frame)
{
return frame->aspace;
}
/* Memory access methods. */
void

View File

@ -406,6 +406,15 @@ extern int frame_relative_level (struct frame_info *fi);
extern enum frame_type get_frame_type (struct frame_info *);
/* Return the frame's program space. */
extern struct program_space *get_frame_program_space (struct frame_info *);
/* Unwind THIS frame's program space from the NEXT frame. */
extern struct program_space *frame_unwind_program_space (struct frame_info *);
/* Return the frame's address space. */
extern struct address_space *get_frame_address_space (struct frame_info *);
/* For frames where we can not unwind further, describe why. */
enum unwind_stop_reason

View File

@ -249,6 +249,7 @@ struct gdbarch
gdbarch_get_syscall_number_ftype *get_syscall_number;
int has_global_solist;
int has_global_breakpoints;
gdbarch_has_shared_address_space_ftype *has_shared_address_space;
};
@ -389,6 +390,7 @@ struct gdbarch startup_gdbarch =
0, /* get_syscall_number */
0, /* has_global_solist */
0, /* has_global_breakpoints */
default_has_shared_address_space, /* has_shared_address_space */
/* startup_gdbarch() */
};
@ -472,6 +474,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->displaced_step_location = NULL;
gdbarch->target_signal_from_host = default_target_signal_from_host;
gdbarch->target_signal_to_host = default_target_signal_to_host;
gdbarch->has_shared_address_space = default_has_shared_address_space;
/* gdbarch_alloc() */
return gdbarch;
@ -649,6 +652,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of get_syscall_number, has predicate */
/* Skip verify of has_global_solist, invalid_p == 0 */
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
/* Skip verify of has_shared_address_space, invalid_p == 0 */
buf = ui_file_xstrdup (log, &length);
make_cleanup (xfree, buf);
if (length > 0)
@ -890,6 +894,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
"gdbarch_dump: has_shared_address_space = <%s>\n",
host_address_to_string (gdbarch->has_shared_address_space));
fprintf_unfiltered (file,
"gdbarch_dump: have_nonsteppable_watchpoint = %s\n",
plongest (gdbarch->have_nonsteppable_watchpoint));
@ -3504,6 +3511,23 @@ set_gdbarch_has_global_breakpoints (struct gdbarch *gdbarch,
gdbarch->has_global_breakpoints = has_global_breakpoints;
}
int
gdbarch_has_shared_address_space (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->has_shared_address_space != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_has_shared_address_space called\n");
return gdbarch->has_shared_address_space (gdbarch);
}
void
set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch,
gdbarch_has_shared_address_space_ftype has_shared_address_space)
{
gdbarch->has_shared_address_space = has_shared_address_space;
}
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */

View File

@ -903,6 +903,12 @@ extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_glob
extern int gdbarch_has_global_breakpoints (struct gdbarch *gdbarch);
extern void set_gdbarch_has_global_breakpoints (struct gdbarch *gdbarch, int has_global_breakpoints);
/* True if inferiors share an address space (e.g., uClinux). */
typedef int (gdbarch_has_shared_address_space_ftype) (struct gdbarch *gdbarch);
extern int gdbarch_has_shared_address_space (struct gdbarch *gdbarch);
extern void set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch, gdbarch_has_shared_address_space_ftype *has_shared_address_space);
/* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1)

View File

@ -756,6 +756,9 @@ v:int:has_global_solist:::0:0::0
# visible to all address spaces automatically. For such cases,
# this property should be set to true.
v:int:has_global_breakpoints:::0:0::0
# True if inferiors share an address space (e.g., uClinux).
m:int:has_shared_address_space:void:::default_has_shared_address_space::0
EOF
}

View File

@ -28,6 +28,7 @@ struct type;
struct regcache;
#include "bfd.h"
#include "exec.h"
/* Return the name of the executable file as a string.
ERR nonzero means get error if there is none specified;
@ -103,13 +104,9 @@ extern void (*deprecated_file_changed_hook) (char *filename);
extern void specify_exec_file_hook (void (*hook) (char *filename));
/* Binary File Diddlers for the exec and core files. */
/* Binary File Diddler for the core file. */
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. */

View File

@ -246,6 +246,10 @@ struct thread_info *first_thread_of_process (int pid);
/* Returns any thread of process PID. */
extern struct thread_info *any_thread_of_process (int pid);
/* Returns any non-exited thread of process PID, giving preference for
already stopped threads. */
extern struct thread_info *any_live_thread_of_process (int pid);
/* Change the ptid of thread OLD_PTID to NEW_PTID. */
void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);

View File

@ -2166,7 +2166,8 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty)
push_target (ops);
inferior = add_inferior (pid);
inferior = current_inferior ();
inferior_appeared (inferior, pid);
inferior->attach_flag = 1;
inf_update_procs (inf);

View File

@ -649,6 +649,7 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
char *cmdline;
char **env_save = environ;
size_t cmdlen;
struct inferior *inf;
/* If no exec file handed to us, get it from the exec-file command -- with
a good, common error message if none is specified. */
@ -714,7 +715,8 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
#endif
inferior_ptid = pid_to_ptid (SOME_PID);
add_inferior_silent (SOME_PID);
inf = current_inferior ();
inferior_appeared_silent (inf, SOME_PID);
push_target (&go32_ops);

View File

@ -67,6 +67,8 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
child_inf = add_inferior (fpid);
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);
inf->pspace = parent_inf->pspace;
inf->pspace = parent_inf->aspace;
/* Before detaching from the parent, remove all breakpoints from
it. */
@ -223,10 +225,10 @@ inf_ptrace_attach (struct target_ops *ops, char *args, int from_tty)
error (_("This system does not support attaching to a process"));
#endif
inferior_ptid = pid_to_ptid (pid);
inf = add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
inf->attach_flag = 1;
inferior_ptid = pid_to_ptid (pid);
/* Always add a main thread. If some target extends the ptrace
target, it should decorate the ptid later with more info. */

View File

@ -453,6 +453,8 @@ inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
inferior_ptid = ptid_build (fpid, flwpid, 0);
inf = add_inferior (fpid);
inf->attach_flag = parent_inf->attach_flag;
inf->pspace = parent_inf->pspace;
inf->aspace = parent_inf->aspace;
copy_terminal_info (inf, parent_inf);
detach_breakpoints (pid);
@ -725,7 +727,8 @@ inf_ttrace_attach (struct target_ops *ops, char *args, int from_tty)
if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
perror_with_name (("ttrace"));
inf = add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
inf->attach_flag = 1;
/* Set the initial event mask. */

View File

@ -731,6 +731,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
struct breakpoint *bpt;
struct symtab_and_line sal;
init_sal (&sal); /* initialize to zeroes */
sal.pspace = current_program_space;
sal.pc = bp_addr;
sal.section = find_pc_overlay (sal.pc);
/* Sanity. The exact same SP value is returned by

View File

@ -1515,14 +1515,13 @@ finish_forward (struct symbol *function, struct frame_info *frame)
old_chain = make_cleanup_delete_breakpoint (breakpoint);
tp->proceed_to_finish = 1; /* We want stop_registers, please... */
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
cargs = xmalloc (sizeof (*cargs));
cargs->breakpoint = breakpoint;
cargs->function = function;
add_continuation (tp, finish_command_continuation, cargs,
finish_command_continuation_free_arg);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
discard_cleanups (old_chain);
if (!target_can_async_p ())

View File

@ -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"
@ -26,28 +27,66 @@
#include "ui-out.h"
#include "observer.h"
#include "gdbthread.h"
#include "gdbcore.h"
#include "symfile.h"
void _initialize_inferiors (void);
static struct inferior *inferior_list = NULL;
static void inferior_alloc_data (struct inferior *inf);
static void inferior_free_data (struct inferior *inf);
struct inferior *inferior_list = NULL;
static int highest_inferior_num;
/* Print notices on inferior events (attach, detach, etc.), set with
`set print inferior-events'. */
static int print_inferior_events = 0;
/* The Current Inferior. */
static struct inferior *current_inferior_ = NULL;
struct inferior*
current_inferior (void)
{
struct inferior *inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
gdb_assert (inf);
return inf;
return current_inferior_;
}
void
set_current_inferior (struct inferior *inf)
{
/* There's always an inferior. */
gdb_assert (inf != NULL);
current_inferior_ = inf;
}
/* A cleanups callback, helper for save_current_program_space
below. */
static void
restore_inferior (void *arg)
{
struct inferior *saved_inferior = arg;
set_current_inferior (saved_inferior);
}
/* Save the current program space so that it may be restored by a later
call to do_cleanups. Returns the struct cleanup pointer needed for
later doing the cleanup. */
struct cleanup *
save_current_inferior (void)
{
struct cleanup *old_chain = make_cleanup (restore_inferior,
current_inferior_);
return old_chain;
}
static void
free_inferior (struct inferior *inf)
{
discard_all_inferior_continuations (inf);
inferior_free_data (inf);
xfree (inf->private);
xfree (inf);
}
@ -85,7 +124,10 @@ add_inferior_silent (int pid)
inf->next = inferior_list;
inferior_list = inf;
observer_notify_new_inferior (pid);
inferior_alloc_data (inf);
if (pid != 0)
inferior_appeared (inf, pid);
return inf;
}
@ -123,17 +165,13 @@ delete_thread_of_inferior (struct thread_info *tp, void *data)
return 0;
}
/* If SILENT then be quiet -- don't announce a inferior death, or the
exit of its threads. */
static void
delete_inferior_1 (int pid, int silent)
void
delete_threads_of_inferior (int pid)
{
struct inferior *inf, *infprev;
struct delete_thread_of_inferior_arg arg = { pid, silent };
struct inferior *inf;
struct delete_thread_of_inferior_arg arg;
infprev = NULL;
for (inf = inferior_list; inf; infprev = inf, inf = inf->next)
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid == pid)
break;
@ -141,14 +179,34 @@ delete_inferior_1 (int pid, int silent)
return;
arg.pid = pid;
arg.silent = 1;
iterate_over_threads (delete_thread_of_inferior, &arg);
}
/* If SILENT then be quiet -- don't announce a inferior death, or the
exit of its threads. */
static void
delete_inferior_1 (struct inferior *todel, int silent)
{
struct inferior *inf, *infprev;
struct delete_thread_of_inferior_arg arg;
infprev = NULL;
for (inf = inferior_list; inf; infprev = inf, inf = inf->next)
if (inf == todel)
break;
if (!inf)
return;
arg.pid = inf->pid;
arg.silent = silent;
iterate_over_threads (delete_thread_of_inferior, &arg);
/* Notify the observers before removing the inferior from the list,
so that the observers have a change to look it up. */
observer_notify_inferior_exit (pid);
if (infprev)
infprev->next = inf->next;
else
@ -160,7 +218,9 @@ delete_inferior_1 (int pid, int silent)
void
delete_inferior (int pid)
{
delete_inferior_1 (pid, 0);
struct inferior *inf = find_inferior_pid (pid);
delete_inferior_1 (inf, 0);
if (print_inferior_events)
printf_unfiltered (_("[Inferior %d exited]\n"), pid);
@ -169,31 +229,101 @@ delete_inferior (int pid)
void
delete_inferior_silent (int pid)
{
delete_inferior_1 (pid, 1);
struct inferior *inf = find_inferior_pid (pid);
delete_inferior_1 (inf, 1);
}
/* If SILENT then be quiet -- don't announce a inferior exit, or the
exit of its threads. */
static void
exit_inferior_1 (struct inferior *inftoex, int silent)
{
struct inferior *inf;
struct delete_thread_of_inferior_arg arg;
for (inf = inferior_list; inf; inf = inf->next)
if (inf == inftoex)
break;
if (!inf)
return;
arg.pid = inf->pid;
arg.silent = silent;
iterate_over_threads (delete_thread_of_inferior, &arg);
/* Notify the observers before removing the inferior from the list,
so that the observers have a chance to look it up. */
observer_notify_inferior_exit (inf->pid);
inf->pid = 0;
if (inf->vfork_parent != NULL)
{
inf->vfork_parent->vfork_child = NULL;
inf->vfork_parent = NULL;
}
}
void
exit_inferior (int pid)
{
struct inferior *inf = find_inferior_pid (pid);
exit_inferior_1 (inf, 0);
if (print_inferior_events)
printf_unfiltered (_("[Inferior %d exited]\n"), pid);
}
void
exit_inferior_silent (int pid)
{
struct inferior *inf = find_inferior_pid (pid);
exit_inferior_1 (inf, 1);
}
void
exit_inferior_num_silent (int num)
{
struct inferior *inf = find_inferior_id (num);
exit_inferior_1 (inf, 1);
}
void
detach_inferior (int pid)
{
delete_inferior_1 (pid, 1);
struct inferior *inf = find_inferior_pid (pid);
exit_inferior_1 (inf, 1);
if (print_inferior_events)
printf_unfiltered (_("[Inferior %d detached]\n"), pid);
}
void
inferior_appeared (struct inferior *inf, int pid)
{
inf->pid = pid;
observer_notify_inferior_appeared (pid);
}
void
discard_all_inferiors (void)
{
struct inferior *inf, *infnext;
struct inferior *inf;
for (inf = inferior_list; inf; inf = infnext)
for (inf = inferior_list; inf; inf = inf->next)
{
infnext = inf->next;
delete_inferior_silent (inf->pid);
if (inf->pid != 0)
exit_inferior_silent (inf->pid);
}
}
static struct inferior *
struct inferior *
find_inferior_id (int num)
{
struct inferior *inf;
@ -210,6 +340,11 @@ find_inferior_pid (int pid)
{
struct inferior *inf;
/* Looking for inferior pid == 0 is always wrong, and indicative of
a bug somewhere else. There may be more than one with pid == 0,
for instance. */
gdb_assert (pid != 0);
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid == pid)
return inf;
@ -217,6 +352,22 @@ find_inferior_pid (int pid)
return NULL;
}
/* Find an inferior bound to PSPACE. */
struct inferior *
find_inferior_for_program_space (struct program_space *pspace)
{
struct inferior *inf;
for (inf = inferior_list; inf != NULL; inf = inf->next)
{
if (inf->pspace == pspace)
return inf;
}
return NULL;
}
struct inferior *
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
void *data)
@ -282,15 +433,72 @@ in_inferior_list (int pid)
int
have_inferiors (void)
{
return inferior_list != NULL;
struct inferior *inf;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid != 0)
return 1;
return 0;
}
int
have_live_inferiors (void)
{
struct target_ops *t;
/* The check on stratum suffices, as GDB doesn't currently support
multiple target interfaces. */
return (current_target.to_stratum >= process_stratum && have_inferiors ());
if (have_inferiors ())
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_stratum == process_stratum)
return 1;
return 0;
}
/* Prune away automatically added program spaces that aren't required
anymore. */
void
prune_inferiors (void)
{
struct inferior *ss, **ss_link;
struct inferior *current = current_inferior ();
ss = inferior_list;
ss_link = &inferior_list;
while (ss)
{
if (ss == current
|| !ss->removable
|| ss->pid != 0)
{
ss_link = &ss->next;
ss = *ss_link;
continue;
}
*ss_link = ss->next;
delete_inferior_1 (ss, 1);
ss = *ss_link;
}
prune_program_spaces ();
}
/* Simply returns the count of inferiors. */
int
number_of_inferiors (void)
{
struct inferior *inf;
int count = 0;
for (inf = inferior_list; inf != NULL; inf = inf->next)
count++;
return count;
}
/* Prints the list of inferiors and their details on UIOUT. This is a
@ -322,13 +530,14 @@ print_inferior (struct ui_out *uiout, int requested_inferior)
return;
}
old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, inf_count,
old_chain = make_cleanup_ui_out_table_begin_end (uiout, 4, inf_count,
"inferiors");
ui_out_table_header (uiout, 1, ui_left, "current", "");
ui_out_table_header (uiout, 4, ui_left, "number", "Num");
ui_out_table_header (uiout, 17, ui_left, "target-id", "Description");
ui_out_table_body (uiout);
ui_out_table_header (uiout, 17, ui_left, "exec", "Executable");
ui_out_table_body (uiout);
for (inf = inferior_list; inf; inf = inf->next)
{
struct cleanup *chain2;
@ -338,24 +547,43 @@ 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 == current_inferior ())
ui_out_field_string (uiout, "current", "*");
else
ui_out_field_skip (uiout, "current");
ui_out_field_int (uiout, "number", inf->num);
ui_out_field_string (uiout, "target-id",
target_pid_to_str (pid_to_ptid (inf->pid)));
if (inf->pid)
ui_out_field_string (uiout, "target-id",
target_pid_to_str (pid_to_ptid (inf->pid)));
else
ui_out_field_string (uiout, "target-id", "<null>");
if (inf->pspace->ebfd)
ui_out_field_string (uiout, "exec",
bfd_get_filename (inf->pspace->ebfd));
else
ui_out_field_skip (uiout, "exec");
/* Print extra info that isn't really fit to always present in
tabular form. Currently we print the vfork parent/child
relationships, if any. */
if (inf->vfork_parent)
{
ui_out_text (uiout, _("\n\tis vfork child of inferior "));
ui_out_field_int (uiout, "vfork-parent", inf->vfork_parent->num);
}
if (inf->vfork_child)
{
ui_out_text (uiout, _("\n\tis vfork parent of inferior "));
ui_out_field_int (uiout, "vfork-child", inf->vfork_child->num);
}
ui_out_text (uiout, "\n");
do_cleanups (chain2);
}
if (inferior_list
&& ptid_equal (inferior_ptid, null_ptid))
ui_out_message (uiout, 0, "\n\
No selected inferior/thread. See `help thread' or `help inferior'.\n");
do_cleanups (old_chain);
}
@ -414,36 +642,52 @@ kill_inferior_command (char *args, int from_tty)
static void
inferior_command (char *args, int from_tty)
{
int num, pid;
if (!have_inferiors ())
error (_("No inferiors"));
struct inferior *inf;
int num;
num = parse_and_eval_long (args);
if (!valid_gdb_inferior_id (num))
inf = find_inferior_id (num);
if (inf == NULL)
error (_("Inferior ID %d not known."), num);
pid = gdb_inferior_id_to_pid (num);
printf_filtered (_("[Switching to inferior %d [%s] (%s)]\n"),
inf->num,
target_pid_to_str (pid_to_ptid (inf->pid)),
(inf->pspace->ebfd
? bfd_get_filename (inf->pspace->ebfd)
: _("<noexec>")));
if (pid != ptid_get_pid (inferior_ptid))
if (inf->pid != 0)
{
struct thread_info *tp;
if (inf->pid != ptid_get_pid (inferior_ptid))
{
struct thread_info *tp;
tp = any_thread_of_process (pid);
if (!tp)
error (_("Inferior has no threads."));
tp = any_thread_of_process (inf->pid);
if (!tp)
error (_("Inferior has no threads."));
switch_to_thread (tp->ptid);
switch_to_thread (tp->ptid);
}
printf_filtered (_("[Switching to thread %d (%s)] "),
pid_to_thread_id (inferior_ptid),
target_pid_to_str (inferior_ptid));
}
else
{
struct inferior *inf;
inf = find_inferior_id (num);
set_current_inferior (inf);
switch_to_thread (null_ptid);
set_current_program_space (inf->pspace);
}
printf_filtered (_("[Switching to thread %d (%s)] "),
pid_to_thread_id (inferior_ptid),
target_pid_to_str (inferior_ptid));
if (is_running (inferior_ptid))
if (inf->pid != 0 && is_running (inferior_ptid))
ui_out_text (uiout, "(running)\n");
else
else if (inf->pid != 0)
{
ui_out_text (uiout, "\n");
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
@ -467,6 +711,184 @@ info_inferiors_command (char *args, int from_tty)
print_inferior (uiout, requested);
}
/* remove-inferior ID */
void
remove_inferior_command (char *args, int from_tty)
{
int num;
struct inferior *inf;
num = parse_and_eval_long (args);
inf = find_inferior_id (num);
if (inf == NULL)
error (_("Inferior ID %d not known."), num);
if (inf == current_inferior ())
error (_("Can not remove current symbol inferior."));
delete_inferior_1 (inf, 1);
}
/* add-inferior [-copies N] [-exec FILENAME] */
void
add_inferior_command (char *args, int from_tty)
{
int i, copies = 1;
char *exec = NULL;
char **argv;
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
if (args)
{
argv = gdb_buildargv (args);
make_cleanup_freeargv (argv);
for (; *argv != NULL; argv++)
{
if (**argv == '-')
{
if (strcmp (*argv, "-copies") == 0)
{
++argv;
if (!*argv)
error (_("No argument to -copies"));
copies = parse_and_eval_long (*argv);
}
else if (strcmp (*argv, "-exec") == 0)
{
++argv;
if (!*argv)
error (_("No argument to -exec"));
exec = *argv;
}
}
else
error (_("Invalid argument"));
}
}
save_current_space_and_thread ();
for (i = 0; i < copies; ++i)
{
struct address_space *aspace;
struct program_space *pspace;
struct inferior *inf;
/* If all inferiors share an address space on this system, this
doesn't really return a new address space; otherwise, it
really does. */
aspace = maybe_new_address_space ();
pspace = add_program_space (aspace);
inf = add_inferior (0);
inf->pspace = pspace;
inf->aspace = pspace->aspace;
printf_filtered (_("Added inferior %d\n"), inf->num);
if (exec != NULL)
{
/* Switch over temporarily, while reading executable and
symbols.q */
set_current_program_space (pspace);
set_current_inferior (inf);
switch_to_thread (null_ptid);
exec_file_attach (exec, from_tty);
symbol_file_add_main (exec, from_tty);
}
}
do_cleanups (old_chain);
}
/* clone-inferior [-copies N] [ID] */
void
clone_inferior_command (char *args, int from_tty)
{
int i, copies = 1;
char **argv;
struct inferior *orginf = NULL;
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
if (args)
{
argv = gdb_buildargv (args);
make_cleanup_freeargv (argv);
for (; *argv != NULL; argv++)
{
if (**argv == '-')
{
if (strcmp (*argv, "-copies") == 0)
{
++argv;
if (!*argv)
error (_("No argument to -copies"));
copies = parse_and_eval_long (*argv);
if (copies < 0)
error (_("Invalid copies number"));
}
}
else
{
if (orginf == NULL)
{
int num;
/* The first non-option (-) argument specified the
program space ID. */
num = parse_and_eval_long (*argv);
orginf = find_inferior_id (num);
if (orginf == NULL)
error (_("Inferior ID %d not known."), num);
continue;
}
else
error (_("Invalid argument"));
}
}
}
/* If no inferior id was specified, then the user wants to clone the
current inferior. */
if (orginf == NULL)
orginf = current_inferior ();
save_current_space_and_thread ();
for (i = 0; i < copies; ++i)
{
struct address_space *aspace;
struct program_space *pspace;
struct inferior *inf;
/* If all inferiors share an address space on this system, this
doesn't really return a new address space; otherwise, it
really does. */
aspace = maybe_new_address_space ();
pspace = add_program_space (aspace);
inf = add_inferior (0);
inf->pspace = pspace;
inf->aspace = pspace->aspace;
printf_filtered (_("Added inferior %d.\n"), inf->num);
set_current_inferior (inf);
switch_to_thread (null_ptid);
clone_program_space (pspace, orginf->pspace);
}
do_cleanups (old_chain);
}
/* Print notices when new inferiors are created and die. */
static void
show_print_inferior_events (struct ui_file *file, int from_tty,
@ -475,19 +897,141 @@ show_print_inferior_events (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("Printing of inferior events is %s.\n"), value);
}
void
_initialize_inferiors (void)
/* Keep a registry of per-inferior data-pointers required by other GDB
modules. */
struct inferior_data
{
unsigned index;
void (*cleanup) (struct inferior *, void *);
};
struct inferior_data_registration
{
struct inferior_data *data;
struct inferior_data_registration *next;
};
struct inferior_data_registry
{
struct inferior_data_registration *registrations;
unsigned num_registrations;
};
static struct inferior_data_registry inferior_data_registry
= { NULL, 0 };
const struct inferior_data *
register_inferior_data_with_cleanup
(void (*cleanup) (struct inferior *, void *))
{
struct inferior_data_registration **curr;
/* Append new registration. */
for (curr = &inferior_data_registry.registrations;
*curr != NULL; curr = &(*curr)->next);
*curr = XMALLOC (struct inferior_data_registration);
(*curr)->next = NULL;
(*curr)->data = XMALLOC (struct inferior_data);
(*curr)->data->index = inferior_data_registry.num_registrations++;
(*curr)->data->cleanup = cleanup;
return (*curr)->data;
}
const struct inferior_data *
register_inferior_data (void)
{
return register_inferior_data_with_cleanup (NULL);
}
static void
inferior_alloc_data (struct inferior *inf)
{
gdb_assert (inf->data == NULL);
inf->num_data = inferior_data_registry.num_registrations;
inf->data = XCALLOC (inf->num_data, void *);
}
static void
inferior_free_data (struct inferior *inf)
{
gdb_assert (inf->data != NULL);
clear_inferior_data (inf);
xfree (inf->data);
inf->data = NULL;
}
void
clear_inferior_data (struct inferior *inf)
{
struct inferior_data_registration *registration;
int i;
gdb_assert (inf->data != NULL);
for (registration = inferior_data_registry.registrations, i = 0;
i < inf->num_data;
registration = registration->next, i++)
if (inf->data[i] != NULL && registration->data->cleanup)
registration->data->cleanup (inf, inf->data[i]);
memset (inf->data, 0, inf->num_data * sizeof (void *));
}
void
set_inferior_data (struct inferior *inf,
const struct inferior_data *data,
void *value)
{
gdb_assert (data->index < inf->num_data);
inf->data[data->index] = value;
}
void *
inferior_data (struct inferior *inf, const struct inferior_data *data)
{
gdb_assert (data->index < inf->num_data);
return inf->data[data->index];
}
void
initialize_inferiors (void)
{
/* There's always one inferior. Note that this function isn't an
automatic _initialize_foo function, since other _initialize_foo
routines may need to install their per-inferior data keys. We
can only allocate an inferior when all those modules have done
that. Do this after initialize_progspace, due to the
current_program_space reference. */
current_inferior_ = add_inferior (0);
current_inferior_->pspace = current_program_space;
current_inferior_->aspace = current_program_space->aspace;
add_info ("inferiors", info_inferiors_command,
_("IDs of currently known inferiors."));
add_setshow_boolean_cmd ("inferior-events", no_class,
&print_inferior_events, _("\
Set printing of inferior events (e.g., inferior start and exit)."), _("\
Show printing of inferior events (e.g., inferior start and exit)."), NULL,
NULL,
show_print_inferior_events,
&setprintlist, &showprintlist);
add_com ("add-inferior", no_class, add_inferior_command, _("\
Add a new inferior.\n\
Usage: add-inferior [-copies <N>] [-exec <FILENAME>]\n\
N is the optional number of inferior to add, default is 1.\n\
FILENAME is the file name of the executable to use\n\
as main program."));
add_com ("remove-inferior", no_class, remove_inferior_command, _("\
Remove inferior ID.\n\
Usage: remove-inferior ID"));
add_com ("clone-inferior", no_class, clone_inferior_command, _("\
Clone inferior ID.\n\
Usage: clone-inferior [-copies <N>] [ID]\n\
Add N copies of inferior ID. The new inferior has the same\n\
executable loaded as the copied inferior. If -copies is not specified,\n\
adds 1 copy. If ID is not specified, it is the current inferior\n\
that is cloned."));
add_cmd ("inferior", class_run, detach_inferior_command, _("\
Detach from inferior ID."),
@ -501,4 +1045,13 @@ Kill inferior ID."),
Use this command to switch between inferiors.\n\
The new inferior ID must be currently known."),
&cmdlist);
add_setshow_boolean_cmd ("inferior-events", no_class,
&print_inferior_events, _("\
Set printing of inferior events (e.g., inferior start and exit)."), _("\
Show printing of inferior events (e.g., inferior start and exit)."), NULL,
NULL,
show_print_inferior_events,
&setprintlist, &showprintlist);
}

View File

@ -41,6 +41,8 @@ struct terminal_info;
/* For struct frame_id. */
#include "frame.h"
#include "progspace.h"
/* Two structures are used to record inferior state.
inferior_thread_state contains state about the program itself like its
@ -149,6 +151,11 @@ extern int step_stop_if_no_debug;
are kept running freely. */
extern int non_stop;
/* If set (default), when following a fork, GDB will detach from one
the fork branches, child or parent. Exactly which branch is
detached depends on 'set follow-fork-mode' setting. */
extern int detach_fork;
extern void generic_mourn_inferior (void);
extern void terminal_save_ours (void);
@ -408,6 +415,18 @@ struct inferior
the ptid_t.pid member of threads of this inferior. */
int pid;
/* True if this was an auto-created inferior, e.g. created from
following a fork; false, if this inferior was manually added by
the user, and we should not attempt to prune it
automatically. */
int removable;
/* The address space bound to this inferior. */
struct address_space *aspace;
/* The program space bound to this inferior. */
struct program_space *pspace;
/* See the definition of stop_kind above. */
enum stop_kind stop_soon;
@ -415,14 +434,30 @@ struct inferior
forked. */
int attach_flag;
/* If this inferior is a vfork child, then this is the pointer to
its vfork parent, if GDB is still attached to it. */
struct inferior *vfork_parent;
/* If this process is a vfork parent, this is the pointer to the
child. Since a vfork parent is left frozen by the kernel until
the child execs or exits, a process can only have one vfork child
at a given time. */
struct inferior *vfork_child;
/* True if this inferior should be detached when it's vfork sibling
exits or execs. */
int pending_detach;
/* True if this inferior is a vfork parent waiting for a vfork child
not under our control to be done with the shared memory region,
either by exiting or execing. */
int waiting_for_vfork_done;
/* What is left to do for an execution command after any thread of
this inferior stops. For continuations associated with a
specific thread, see `struct thread_info'. */
struct continuation *continuations;
/* Terminal info and state managed by inflow.c. */
struct terminal_info *terminal_info;
/* Private data used by the target vector implementation. */
struct private_inferior *private;
@ -439,8 +474,24 @@ struct inferior
/* This counts all syscall catch requests, so we can readily determine
if any catching is necessary. */
int total_syscalls_count;
/* Per inferior data-pointers required by other GDB modules. */
void **data;
unsigned num_data;
};
/* Keep a registry of per-inferior data-pointers required by other GDB
modules. */
extern const struct inferior_data *register_inferior_data (void);
extern const struct inferior_data *register_inferior_data_with_cleanup
(void (*cleanup) (struct inferior *, void *));
extern void clear_inferior_data (struct inferior *inf);
extern void set_inferior_data (struct inferior *inf,
const struct inferior_data *data, void *value);
extern void *inferior_data (struct inferior *inf,
const struct inferior_data *data);
/* Create an empty inferior list, or empty the existing one. */
extern void init_inferior_list (void);
@ -464,6 +515,14 @@ extern void delete_inferior_silent (int pid);
/* Delete an existing inferior list entry, due to inferior detaching. */
extern void detach_inferior (int pid);
extern void exit_inferior (int pid);
extern void exit_inferior_silent (int pid);
extern void exit_inferior_num_silent (int num);
extern void inferior_appeared (struct inferior *inf, int pid);
/* Get rid of all inferiors. */
extern void discard_all_inferiors (void);
@ -482,9 +541,16 @@ extern int in_inferior_list (int pid);
not the system's). */
extern int valid_gdb_inferior_id (int num);
/* Search function to lookup a inferior by target 'pid'. */
/* Search function to lookup an inferior by target 'pid'. */
extern struct inferior *find_inferior_pid (int pid);
/* Search function to lookup an inferior by GDB 'num'. */
extern struct inferior *find_inferior_id (int num);
/* Find an inferior bound to PSPACE. */
extern struct inferior *
find_inferior_for_program_space (struct program_space *pspace);
/* Inferior iterator function.
Calls a callback function once for each inferior, so long as the
@ -516,4 +582,16 @@ extern int have_live_inferiors (void);
this if there is no current inferior. */
extern struct inferior *current_inferior (void);
extern void set_current_inferior (struct inferior *);
extern struct cleanup *save_current_inferior (void);
extern struct inferior *inferior_list;
/* Prune away automatically added inferiors that aren't required
anymore. */
extern void prune_inferiors (void);
extern int number_of_inferiors (void);
#endif /* !defined (INFERIOR_H) */

View File

@ -86,6 +86,8 @@ struct terminal_info
unimportant. */
static struct terminal_info our_terminal_info;
static struct terminal_info *get_inflow_inferior_data (struct inferior *);
#ifdef PROCESS_GROUP_TYPE
/* Return the process group of the current inferior. */
@ -93,7 +95,7 @@ static struct terminal_info our_terminal_info;
PROCESS_GROUP_TYPE
inferior_process_group (void)
{
return current_inferior ()->terminal_info->process_group;
return get_inflow_inferior_data (current_inferior ())->process_group;
}
#endif
@ -201,15 +203,15 @@ terminal_init_inferior_with_pgrp (int pgrp)
if (gdb_has_a_terminal ())
{
struct inferior *inf = current_inferior ();
struct terminal_info *tinfo = get_inflow_inferior_data (inf);
/* We could just as well copy our_ttystate (if we felt like
adding a new function serial_copy_tty_state()). */
xfree (inf->terminal_info->ttystate);
inf->terminal_info->ttystate
= serial_get_tty_state (stdin_serial);
xfree (tinfo->ttystate);
tinfo->ttystate = serial_get_tty_state (stdin_serial);
#ifdef PROCESS_GROUP_TYPE
inf->terminal_info->process_group = pgrp;
tinfo->process_group = pgrp;
#endif
/* Make sure that next time we call terminal_inferior (which will be
@ -256,15 +258,17 @@ void
terminal_inferior (void)
{
struct inferior *inf;
struct terminal_info *tinfo;
if (!terminal_is_ours)
return;
inf = current_inferior ();
tinfo = get_inflow_inferior_data (inf);
if (gdb_has_a_terminal ()
&& inf->terminal_info->ttystate != NULL
&& inf->terminal_info->run_terminal == NULL)
&& tinfo->ttystate != NULL
&& tinfo->run_terminal == NULL)
{
int result;
@ -272,8 +276,8 @@ terminal_inferior (void)
/* Is there a reason this is being done twice? It happens both
places we use F_SETFL, so I'm inclined to think perhaps there
is some reason, however perverse. Perhaps not though... */
result = fcntl (0, F_SETFL, inf->terminal_info->tflags);
result = fcntl (0, F_SETFL, inf->terminal_info->tflags);
result = fcntl (0, F_SETFL, tinfo->tflags);
result = fcntl (0, F_SETFL, tinfo->tflags);
OOPSY ("fcntl F_SETFL");
#endif
@ -281,7 +285,7 @@ terminal_inferior (void)
terminal_ours, we will not change in our out of raw mode with
this call, so we don't flush any input. */
result = serial_set_tty_state (stdin_serial,
inf->terminal_info->ttystate);
tinfo->ttystate);
OOPSY ("setting tty state");
if (!job_control)
@ -307,13 +311,13 @@ terminal_inferior (void)
if (job_control)
{
#ifdef HAVE_TERMIOS
result = tcsetpgrp (0, inf->terminal_info->process_group);
result = tcsetpgrp (0, tinfo->process_group);
if (!inf->attach_flag)
OOPSY ("tcsetpgrp");
#endif
#ifdef HAVE_SGTTY
result = ioctl (0, TIOCSPGRP, &inf->terminal_info->process_group);
result = ioctl (0, TIOCSPGRP, &tinfo->process_group);
if (!inf->attach_flag)
OOPSY ("TIOCSPGRP");
#endif
@ -355,6 +359,7 @@ static void
terminal_ours_1 (int output_only)
{
struct inferior *inf;
struct terminal_info *tinfo;
if (terminal_is_ours)
return;
@ -367,8 +372,9 @@ terminal_ours_1 (int output_only)
avoids attempting all the ioctl's when running in batch. */
inf = current_inferior ();
tinfo = get_inflow_inferior_data (inf);
if (inf->terminal_info->run_terminal != NULL || gdb_has_a_terminal () == 0)
if (tinfo->run_terminal != NULL || gdb_has_a_terminal () == 0)
return;
{
@ -384,15 +390,15 @@ terminal_ours_1 (int output_only)
osigttou = (void (*)()) signal (SIGTTOU, SIG_IGN);
#endif
xfree (inf->terminal_info->ttystate);
inf->terminal_info->ttystate = serial_get_tty_state (stdin_serial);
xfree (tinfo->ttystate);
tinfo->ttystate = serial_get_tty_state (stdin_serial);
#ifdef PROCESS_GROUP_TYPE
if (!inf->attach_flag)
/* If setpgrp failed in terminal_inferior, this would give us
our process group instead of the inferior's. See
terminal_inferior for details. */
inf->terminal_info->process_group = gdb_getpgrp ();
tinfo->process_group = gdb_getpgrp ();
#endif
/* Here we used to set ICANON in our ttystate, but I believe this
@ -410,7 +416,7 @@ terminal_ours_1 (int output_only)
*/
serial_noflush_set_tty_state (stdin_serial, our_terminal_info.ttystate,
inf->terminal_info->ttystate);
tinfo->ttystate);
if (job_control)
{
@ -446,7 +452,7 @@ terminal_ours_1 (int output_only)
}
#ifdef F_GETFL
inf->terminal_info->tflags = fcntl (0, F_GETFL, 0);
tinfo->tflags = fcntl (0, F_GETFL, 0);
/* Is there a reason this is being done twice? It happens both
places we use F_SETFL, so I'm inclined to think perhaps there
@ -457,18 +463,38 @@ terminal_ours_1 (int output_only)
}
}
/* This is a "new_inferior" observer. It's business is to allocate
the TERMINAL_INFO member of the inferior structure. This field is
private to inflow.c, and its type is opaque to the rest of GDB.
PID is the target pid of the inferior that has just been added to
the inferior list. */
/* Per-inferior data key. */
static const struct inferior_data *inflow_inferior_data;
static void
inflow_new_inferior (int pid)
inflow_inferior_data_cleanup (struct inferior *inf, void *arg)
{
struct inferior *inf = find_inferior_pid (pid);
struct terminal_info *info;
inf->terminal_info = XZALLOC (struct terminal_info);
info = inferior_data (inf, inflow_inferior_data);
if (info != NULL)
{
xfree (info->run_terminal);
xfree (info);
}
}
/* Get the current svr4 data. If none is found yet, add it now. This
function always returns a valid object. */
static struct terminal_info *
get_inflow_inferior_data (struct inferior *inf)
{
struct terminal_info *info;
info = inferior_data (inf, inflow_inferior_data);
if (info == NULL)
{
info = XZALLOC (struct terminal_info);
set_inferior_data (inf, inflow_inferior_data, info);
}
return info;
}
/* This is a "inferior_exit" observer. Releases the TERMINAL_INFO member
@ -481,19 +507,28 @@ static void
inflow_inferior_exit (int pid)
{
struct inferior *inf = find_inferior_pid (pid);
struct terminal_info *info;
xfree (inf->terminal_info->run_terminal);
xfree (inf->terminal_info);
inf->terminal_info = NULL;
info = inferior_data (inf, inflow_inferior_data);
if (info != NULL)
{
xfree (info->run_terminal);
xfree (info);
set_inferior_data (inf, inflow_inferior_data, NULL);
}
}
void
copy_terminal_info (struct inferior *to, struct inferior *from)
{
*to->terminal_info = *from->terminal_info;
if (from->terminal_info->run_terminal)
to->terminal_info->run_terminal
= xstrdup (from->terminal_info->run_terminal);
struct terminal_info *tinfo_to, *tinfo_from;
tinfo_to = get_inflow_inferior_data (to);
tinfo_from = get_inflow_inferior_data (from);
*tinfo_to = *tinfo_from;
if (tinfo_from->run_terminal)
tinfo_to->run_terminal
= xstrdup (tinfo_from->run_terminal);
}
void
@ -506,6 +541,7 @@ void
child_terminal_info (char *args, int from_tty)
{
struct inferior *inf;
struct terminal_info *tinfo;
if (!gdb_has_a_terminal ())
{
@ -517,6 +553,7 @@ child_terminal_info (char *args, int from_tty)
return;
inf = current_inferior ();
tinfo = get_inflow_inferior_data (inf);
printf_filtered (_("Inferior's terminal status (currently saved by GDB):\n"));
@ -524,7 +561,7 @@ child_terminal_info (char *args, int from_tty)
{
int flags;
flags = inf->terminal_info->tflags;
flags = tinfo->tflags;
printf_filtered ("File descriptor flags = ");
@ -577,13 +614,10 @@ child_terminal_info (char *args, int from_tty)
}
#ifdef PROCESS_GROUP_TYPE
printf_filtered ("Process group = %d\n",
(int) inf->terminal_info->process_group);
printf_filtered ("Process group = %d\n", (int) tinfo->process_group);
#endif
serial_print_tty_state (stdin_serial,
inf->terminal_info->ttystate,
gdb_stdout);
serial_print_tty_state (stdin_serial, tinfo->ttystate, gdb_stdout);
}
/* NEW_TTY_PREFORK is called before forking a new child process,
@ -687,8 +721,12 @@ new_tty_postfork (void)
are sharing a tty. */
if (inferior_thisrun_terminal)
current_inferior ()->terminal_info->run_terminal
= xstrdup (inferior_thisrun_terminal);
{
struct inferior *inf = current_inferior ();
struct terminal_info *tinfo = get_inflow_inferior_data (inf);
tinfo->run_terminal = xstrdup (inferior_thisrun_terminal);
}
inferior_thisrun_terminal = NULL;
}
@ -712,7 +750,9 @@ void
set_sigint_trap (void)
{
struct inferior *inf = current_inferior ();
if (inf->attach_flag || inf->terminal_info->run_terminal)
struct terminal_info *tinfo = get_inflow_inferior_data (inf);
if (inf->attach_flag || tinfo->run_terminal)
{
osig = (void (*)()) signal (SIGINT, pass_signal);
osig_set = 1;
@ -841,6 +881,8 @@ _initialize_inflow (void)
#endif /* TIOCGPGRP */
#endif /* sgtty */
observer_attach_new_inferior (inflow_new_inferior);
observer_attach_inferior_exit (inflow_inferior_exit);
inflow_inferior_data
= register_inferior_data_with_cleanup (inflow_inferior_data_cleanup);
}

View File

@ -109,6 +109,9 @@ int sync_execution = 0;
static ptid_t previous_inferior_ptid;
/* Default behavior is to detach newly forked processes (legacy). */
int detach_fork = 1;
int debug_displaced = 0;
static void
show_debug_displaced (struct ui_file *file, int from_tty,
@ -461,6 +464,198 @@ follow_inferior_reset_breakpoints (void)
insert_breakpoints ();
}
/* The child has exited or execed: resume threads of the parent the
user wanted to be executing. */
static int
proceed_after_vfork_done (struct thread_info *thread,
void *arg)
{
int pid = * (int *) arg;
if (ptid_get_pid (thread->ptid) == pid
&& is_running (thread->ptid)
&& !is_executing (thread->ptid)
&& !thread->stop_requested
&& thread->stop_signal == TARGET_SIGNAL_0)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: resuming vfork parent thread %s\n",
target_pid_to_str (thread->ptid));
switch_to_thread (thread->ptid);
clear_proceed_status ();
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
}
return 0;
}
/* Called whenever we notice an exec or exit event, to handle
detaching or resuming a vfork parent. */
static void
handle_vfork_child_exec_or_exit (int exec)
{
struct inferior *inf = current_inferior ();
if (inf->vfork_parent)
{
int resume_parent = -1;
/* This exec or exit marks the end of the shared memory region
between the parent and the child. If the user wanted to
detach from the parent, now is the time. */
if (inf->vfork_parent->pending_detach)
{
struct thread_info *tp;
struct cleanup *old_chain;
struct program_space *pspace;
struct address_space *aspace;
/* follow-fork child, detach-on-fork on */
old_chain = make_cleanup_restore_current_thread ();
/* We're letting loose of the parent. */
tp = any_live_thread_of_process (inf->vfork_parent->pid);
switch_to_thread (tp->ptid);
/* We're about to detach from the parent, which implicitly
removes breakpoints from its address space. There's a
catch here: we want to reuse the spaces for the child,
but, parent/child are still sharing the pspace at this
point, although the exec in reality makes the kernel give
the child a fresh set of new pages. The problem here is
that the breakpoints module being unaware of this, would
likely chose the child process to write to the parent
address space. Swapping the child temporarily away from
the spaces has the desired effect. Yes, this is "sort
of" a hack. */
pspace = inf->pspace;
aspace = inf->aspace;
inf->aspace = NULL;
inf->pspace = NULL;
if (debug_infrun || info_verbose)
{
target_terminal_ours ();
if (exec)
fprintf_filtered (gdb_stdlog,
"Detaching vfork parent process %d after child exec.\n",
inf->vfork_parent->pid);
else
fprintf_filtered (gdb_stdlog,
"Detaching vfork parent process %d after child exit.\n",
inf->vfork_parent->pid);
}
target_detach (NULL, 0);
/* Put it back. */
inf->pspace = pspace;
inf->aspace = aspace;
do_cleanups (old_chain);
}
else if (exec)
{
/* We're staying attached to the parent, so, really give the
child a new address space. */
inf->pspace = add_program_space (maybe_new_address_space ());
inf->aspace = inf->pspace->aspace;
inf->removable = 1;
set_current_program_space (inf->pspace);
resume_parent = inf->vfork_parent->pid;
/* Break the bonds. */
inf->vfork_parent->vfork_child = NULL;
}
else
{
struct cleanup *old_chain;
struct program_space *pspace;
/* If this is a vfork child exiting, then the pspace and
aspaces were shared with the parent. Since we're
reporting the process exit, we'll be mourning all that is
found in the address space, and switching to null_ptid,
preparing to start a new inferior. But, since we don't
want to clobber the parent's address/program spaces, we
go ahead and create a new one for this exiting
inferior. */
/* Switch to null_ptid, so that clone_program_space doesn't want
to read the selected frame of a dead process. */
old_chain = save_inferior_ptid ();
inferior_ptid = null_ptid;
/* This inferior is dead, so avoid giving the breakpoints
module the option to write through to it (cloning a
program space resets breakpoints). */
inf->aspace = NULL;
inf->pspace = NULL;
pspace = add_program_space (maybe_new_address_space ());
set_current_program_space (pspace);
inf->removable = 1;
clone_program_space (pspace, inf->vfork_parent->pspace);
inf->pspace = pspace;
inf->aspace = pspace->aspace;
/* Put back inferior_ptid. We'll continue mourning this
inferior. */
do_cleanups (old_chain);
resume_parent = inf->vfork_parent->pid;
/* Break the bonds. */
inf->vfork_parent->vfork_child = NULL;
}
inf->vfork_parent = NULL;
gdb_assert (current_program_space == inf->pspace);
if (non_stop && resume_parent != -1)
{
/* If the user wanted the parent to be running, let it go
free now. */
struct cleanup *old_chain = make_cleanup_restore_current_thread ();
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: resuming vfork parent process %d\n",
resume_parent);
iterate_over_threads (proceed_after_vfork_done, &resume_parent);
do_cleanups (old_chain);
}
}
}
/* Enum strings for "set|show displaced-stepping". */
static const char follow_exec_mode_new[] = "new";
static const char follow_exec_mode_same[] = "same";
static const char *follow_exec_mode_names[] =
{
follow_exec_mode_new,
follow_exec_mode_same,
NULL,
};
static const char *follow_exec_mode_string = follow_exec_mode_same;
static void
show_follow_exec_mode_string (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
}
/* EXECD_PATHNAME is assumed to be non-NULL. */
static void
@ -468,6 +663,7 @@ follow_exec (ptid_t pid, char *execd_pathname)
{
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
struct inferior *inf = current_inferior ();
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@ -489,6 +685,9 @@ follow_exec (ptid_t pid, char *execd_pathname)
that may write the bp's "shadow contents" (the instruction
value that was overwritten witha TRAP instruction). Since
we now have a new a.out, those shadow contents aren't valid. */
mark_breakpoints_out ();
update_breakpoints_after_exec ();
/* If there was one, it's gone now. We cannot truly step-to-next
@ -506,7 +705,9 @@ follow_exec (ptid_t pid, char *execd_pathname)
th->stop_requested = 0;
/* What is this a.out's name? */
printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
printf_unfiltered (_("%s is executing new program: %s\n"),
target_pid_to_str (inferior_ptid),
execd_pathname);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
@ -525,9 +726,6 @@ follow_exec (ptid_t pid, char *execd_pathname)
execd_pathname = name;
}
/* That a.out is now the one to use. */
exec_file_attach (execd_pathname, 0);
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
dld will have had a chance to initialize the child. */
@ -536,6 +734,30 @@ follow_exec (ptid_t pid, char *execd_pathname)
previous incarnation of this process. */
no_shared_libraries (NULL, 0);
if (follow_exec_mode_string == follow_exec_mode_new)
{
struct program_space *pspace;
struct inferior *new_inf;
/* The user wants to keep the old inferior and program spaces
around. Create a new fresh one, and switch to it. */
inf = add_inferior (current_inferior ()->pid);
pspace = add_program_space (maybe_new_address_space ());
inf->pspace = pspace;
inf->aspace = pspace->aspace;
exit_inferior_num_silent (current_inferior ()->num);
set_current_inferior (inf);
set_current_program_space (pspace);
}
gdb_assert (current_program_space == inf->pspace);
/* That a.out is now the one to use. */
exec_file_attach (execd_pathname, 0);
/* Load the main file's symbols. */
symbol_file_add_main (execd_pathname, 0);
@ -969,6 +1191,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
struct regcache *regcache;
struct gdbarch *gdbarch;
CORE_ADDR actual_pc;
struct address_space *aspace;
head = displaced_step_request_queue;
ptid = head->ptid;
@ -979,8 +1202,9 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
regcache = get_thread_regcache (ptid);
actual_pc = regcache_read_pc (regcache);
aspace = get_regcache_aspace (regcache);
if (breakpoint_here_p (actual_pc))
if (breakpoint_here_p (aspace, actual_pc))
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
@ -1145,6 +1369,7 @@ resume (int step, enum target_signal sig)
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
struct address_space *aspace = get_regcache_aspace (regcache);
QUIT;
@ -1170,7 +1395,7 @@ resume (int step, enum target_signal sig)
removed or inserted, as appropriate. The exception is if we're sitting
at a permanent breakpoint; we need to step over it, but permanent
breakpoints can't be removed. So we have to test for it here. */
if (breakpoint_here_p (pc) == permanent_breakpoint_here)
if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
{
if (gdbarch_skip_permanent_breakpoint_p (gdbarch))
gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
@ -1287,7 +1512,7 @@ a command like `return' or `jump' to continue execution."));
/* Most targets can step a breakpoint instruction, thus
executing it normally. But if this one cannot, just
continue and we will hit it anyway. */
if (step && breakpoint_inserted_here_p (pc))
if (step && breakpoint_inserted_here_p (aspace, pc))
step = 0;
}
@ -1361,23 +1586,26 @@ clear_proceed_status_callback (struct thread_info *tp, void *data)
void
clear_proceed_status (void)
{
if (!non_stop)
{
/* In all-stop mode, delete the per-thread status of all
threads, even if inferior_ptid is null_ptid, there may be
threads on the list. E.g., we may be launching a new
process, while selecting the executable. */
iterate_over_threads (clear_proceed_status_callback, NULL);
}
if (!ptid_equal (inferior_ptid, null_ptid))
{
struct inferior *inferior;
if (non_stop)
{
/* If in non-stop mode, only delete the per-thread status
of the current thread. */
/* If in non-stop mode, only delete the per-thread status of
the current thread. */
clear_proceed_status_thread (inferior_thread ());
}
else
{
/* In all-stop mode, delete the per-thread status of
*all* threads. */
iterate_over_threads (clear_proceed_status_callback, NULL);
}
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
}
@ -1439,7 +1667,8 @@ prepare_to_proceed (int step)
{
struct regcache *regcache = get_thread_regcache (wait_ptid);
if (breakpoint_here_p (regcache_read_pc (regcache)))
if (breakpoint_here_p (get_regcache_aspace (regcache),
regcache_read_pc (regcache)))
{
/* If stepping, remember current thread to switch back to. */
if (step)
@ -1477,6 +1706,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
struct gdbarch *gdbarch;
struct thread_info *tp;
CORE_ADDR pc;
struct address_space *aspace;
int oneproc = 0;
/* If we're stopped at a fork/vfork, follow the branch set by the
@ -1491,6 +1721,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
aspace = get_regcache_aspace (regcache);
pc = regcache_read_pc (regcache);
if (step > 0)
@ -1500,7 +1731,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
if (addr == (CORE_ADDR) -1)
{
if (pc == stop_pc && breakpoint_here_p (pc)
if (pc == stop_pc && breakpoint_here_p (aspace, pc)
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
step one instruction before inserting breakpoints so that
@ -2231,6 +2462,7 @@ adjust_pc_after_break (struct execution_control_state *ecs)
{
struct regcache *regcache;
struct gdbarch *gdbarch;
struct address_space *aspace;
CORE_ADDR breakpoint_pc;
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
@ -2296,6 +2528,8 @@ adjust_pc_after_break (struct execution_control_state *ecs)
if (gdbarch_decr_pc_after_break (gdbarch) == 0)
return;
aspace = get_regcache_aspace (regcache);
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
@ -2309,8 +2543,8 @@ adjust_pc_after_break (struct execution_control_state *ecs)
already queued and arrive later. To suppress those spurious
SIGTRAPs, we keep a list of such breakpoint locations for a bit,
and retire them after a number of stop events are reported. */
if (software_breakpoint_inserted_here_p (breakpoint_pc)
|| (non_stop && moribund_breakpoint_here_p (breakpoint_pc)))
if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
|| (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = NULL;
if (RECORD_IS_USED)
@ -2411,7 +2645,9 @@ handle_syscall_event (struct execution_control_state *ecs)
fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
syscall_number);
ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->event_thread->stop_bpstat
= bpstat_stop_status (get_regcache_aspace (regcache),
stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
if (!ecs->random_signal)
@ -2622,6 +2858,9 @@ handle_inferior_event (struct execution_control_state *ecs)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
inferior_ptid = ecs->ptid;
set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
set_current_program_space (current_inferior ()->pspace);
handle_vfork_child_exec_or_exit (0);
target_terminal_ours (); /* Must do this before mourn anyway */
print_stop_reason (EXITED, ecs->ws.value.integer);
@ -2640,6 +2879,9 @@ handle_inferior_event (struct execution_control_state *ecs)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
inferior_ptid = ecs->ptid;
set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
set_current_program_space (current_inferior ()->pspace);
handle_vfork_child_exec_or_exit (0);
stop_print_frame = 0;
target_terminal_ours (); /* Must do this before mourn anyway */
@ -2696,19 +2938,45 @@ handle_inferior_event (struct execution_control_state *ecs)
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->event_thread->stop_bpstat
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
ptid_t parent;
ptid_t child;
int should_resume;
int follow_child = (follow_fork_mode_string == follow_fork_mode_child);
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
should_resume = follow_fork ();
parent = ecs->ptid;
child = ecs->ws.value.related_pid;
/* In non-stop mode, also resume the other branch. */
if (non_stop && !detach_fork)
{
if (follow_child)
switch_to_thread (parent);
else
switch_to_thread (child);
ecs->event_thread = inferior_thread ();
ecs->ptid = inferior_ptid;
keep_going (ecs);
}
if (follow_child)
switch_to_thread (child);
else
switch_to_thread (parent);
ecs->event_thread = inferior_thread ();
ecs->ptid = inferior_ptid;
@ -2721,6 +2989,22 @@ handle_inferior_event (struct execution_control_state *ecs)
ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
goto process_event_stop_test;
case TARGET_WAITKIND_VFORK_DONE:
/* Done with the shared memory region. Re-insert breakpoints in
the parent, and keep going. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_VFORK_DONE\n");
if (!ptid_equal (ecs->ptid, inferior_ptid))
context_switch (ecs->ptid);
current_inferior ()->waiting_for_vfork_done = 0;
/* This also takes care of reinserting breakpoints in the
previously locked inferior. */
keep_going (ecs);
return;
case TARGET_WAITKIND_EXECD:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
@ -2733,12 +3017,17 @@ handle_inferior_event (struct execution_control_state *ecs)
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
/* Do whatever is necessary to the parent branch of the vfork. */
handle_vfork_child_exec_or_exit (1);
/* This causes the eventpoints and symbol table to be reset.
Must do this now, before trying to determine whether to
stop. */
follow_exec (inferior_ptid, ecs->ws.value.execd_pathname);
ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->event_thread->stop_bpstat
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* Note that this may be referenced from inside
@ -2929,14 +3218,15 @@ targets should add new threads to the thread list themselves in non-stop mode.")
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
int thread_hop_needed = 0;
struct address_space *aspace = get_regcache_aspace (get_current_regcache ());
/* Check if a regular breakpoint has been hit before checking
for a potential single step breakpoint. Otherwise, GDB will
not see this breakpoint hit when stepping onto breakpoints. */
if (regular_breakpoint_inserted_here_p (stop_pc))
if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
{
ecs->random_signal = 0;
if (!breakpoint_thread_match (stop_pc, ecs->ptid))
if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
thread_hop_needed = 1;
}
else if (singlestep_breakpoints_inserted_p)
@ -3223,7 +3513,8 @@ targets should add new threads to the thread list themselves in non-stop mode.")
non-standard signals can't be explained by the breakpoint. */
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
|| (! ecs->event_thread->trap_expected
&& breakpoint_inserted_here_p (stop_pc)
&& breakpoint_inserted_here_p (get_regcache_aspace (get_current_regcache ()),
stop_pc)
&& (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT))
@ -3280,8 +3571,10 @@ targets should add new threads to the thread list themselves in non-stop mode.")
}
/* See if there is a breakpoint at the current PC. */
ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->event_thread->stop_bpstat
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
stop_pc, ecs->ptid);
/* Following in case break condition called a
function. */
stop_print_frame = 1;
@ -3812,6 +4105,7 @@ infrun: not switching back to stepped thread, it has vanished\n");
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = pc_after_resolver;
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
@ -3922,8 +4216,9 @@ infrun: not switching back to stepped thread, it has vanished\n");
/* Normal function call return (static or dynamic). */
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
}
else
insert_step_resume_breakpoint_at_caller (frame);
@ -3948,6 +4243,7 @@ infrun: not switching back to stepped thread, it has vanished\n");
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
@ -3994,6 +4290,7 @@ infrun: not switching back to stepped thread, it has vanished\n");
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
}
@ -4059,6 +4356,7 @@ infrun: not switching back to stepped thread, it has vanished\n");
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = real_stop_pc;
sr_sal.section = find_pc_overlay (sr_sal.pc);
sr_sal.pspace = get_frame_program_space (frame);
/* Do not specify what the fp should be when we stop since
on some machines the prologue is where the new fp value
@ -4338,6 +4636,7 @@ handle_step_into_function (struct gdbarch *gdbarch,
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = ecs->stop_func_start;
sr_sal.section = find_pc_overlay (ecs->stop_func_start);
sr_sal.pspace = get_frame_program_space (get_current_frame ());
/* Do not specify what the fp should be when we stop since on
some machines the prologue is where the new fp value is
@ -4429,6 +4728,7 @@ insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
gdbarch = get_frame_arch (return_frame);
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
sr_sal.pspace = get_frame_program_space (return_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
get_stack_frame_id (return_frame));
@ -4465,6 +4765,7 @@ insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame)
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch,
frame_unwind_caller_pc (next_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
sr_sal.pspace = frame_unwind_program_space (next_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
frame_unwind_caller_id (next_frame));
@ -4968,6 +5269,11 @@ Further execution is probably impossible.\n"));
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
}
/* Try to get rid of automatically added inferiors that are no
longer needed. Keeping those around slows down things linearly.
Note that this never removes the current inferior. */
prune_inferiors ();
}
static int
@ -6039,6 +6345,30 @@ By default, the debugger will follow the parent process."),
show_follow_fork_mode_string,
&setlist, &showlist);
add_setshow_enum_cmd ("follow-exec-mode", class_run,
follow_exec_mode_names,
&follow_exec_mode_string, _("\
Set debugger response to a program call of exec."), _("\
Show debugger response to a program call of exec."), _("\
An exec call replaces the program image of a process.\n\
\n\
follow-exec-mode can be:\n\
\n\
new - the debugger creates a new inferior and rebinds the process \n\
to this new inferior. The program the process was running before\n\
the exec call can be restarted afterwards by restarting the original\n\
inferior.\n\
\n\
same - the debugger keeps the process bound to the same inferior.\n\
The new executable image replaces the previous executable loaded in\n\
the inferior. Restarting the inferior after the exec call restarts\n\
the executable the process was running after the exec call.\n\
\n\
By default, the debugger will use the same inferior."),
NULL,
show_follow_exec_mode_string,
&setlist, &showlist);
add_setshow_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, &scheduler_mode, _("\
Set mode for locking scheduler during execution."), _("\
@ -6097,6 +6427,14 @@ Options are 'forward' or 'reverse'."),
set_exec_direction_func, show_exec_direction_func,
&setlist, &showlist);
/* Set/show detach-on-fork: user-settable mode. */
add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
Set whether gdb will detach the child of a fork."), _("\
Show whether gdb will detach the child of a fork."), _("\
Tells gdb whether to detach the child of a fork."),
NULL, NULL, &setlist, &showlist);
/* ptid initializations */
null_ptid = ptid_build (0, 0, 0);
minus_one_ptid = ptid_build (-1, 0, 0);

View File

@ -1584,6 +1584,8 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
init_sal (&val);
val.pspace = current_program_space;
/* This is where we need to make sure that we have good defaults.
We must guarantee that this section of code is never executed
when we are called with just a function name, since
@ -1635,6 +1637,7 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
if (val.symtab == 0)
val.symtab = file_symtab;
val.pspace = SYMTAB_PSPACE (val.symtab);
val.pc = 0;
values.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
@ -1706,6 +1709,7 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
val.symtab = file_symtab ? file_symtab : default_symtab;
val.line = valx;
val.pc = 0;
val.pspace = current_program_space;
values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
values.sals[0] = val;

View File

@ -41,9 +41,6 @@ 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
{
@ -648,14 +645,6 @@ _initialize_linux_fork (void)
{
init_fork_list ();
/* Set/show detach-on-fork: user-settable mode. */
add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
Set whether gdb will detach the child of a fork."), _("\
Show whether gdb will detach the child of a fork."), _("\
Tells gdb whether to detach the child of a fork."),
NULL, NULL, &setlist, &showlist);
/* Checkpoint command: create a fork of the inferior process
and set it aside for later debugging. */

View File

@ -55,6 +55,7 @@
#include "xml-support.h"
#include "terminal.h"
#include <sys/vfs.h>
#include "solib.h"
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@ -669,24 +670,45 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
if (!detach_fork)
linux_enable_event_reporting (pid_to_ptid (child_pid));
if (has_vforked
&& !non_stop /* Non-stop always resumes both branches. */
&& (!target_is_async_p () || sync_execution)
&& !(follow_child || detach_fork || sched_multi))
{
/* The parent stays blocked inside the vfork syscall until the
child execs or exits. If we don't let the child run, then
the parent stays blocked. If we're telling the parent to run
in the foreground, the user will not be able to ctrl-c to get
back the terminal, effectively hanging the debug session. */
fprintf_filtered (gdb_stderr, _("\
Can not resume the parent process over vfork in the foreground while \n\
holding the child stopped. Try \"set detach-on-fork\" or \
\"set schedule-multiple\".\n"));
return 1;
}
if (! follow_child)
{
/* We're already attached to the parent, by default. */
struct lwp_info *child_lp = NULL;
/* Before detaching from the child, remove all breakpoints from
it. If we forked, then this has already been taken care of
by infrun.c. If we vforked however, any breakpoint inserted
in the parent is visible in the child, even those added while
stopped in a vfork catchpoint. This won't actually modify
the breakpoint list, but will physically remove the
breakpoints from the child. This will remove the breakpoints
from the parent also, but they'll be reinserted below. */
if (has_vforked)
detach_breakpoints (child_pid);
/* We're already attached to the parent, by default. */
/* Detach new forked process? */
if (detach_fork)
{
/* Before detaching from the child, remove all breakpoints
from it. If we forked, then this has already been taken
care of by infrun.c. If we vforked however, any
breakpoint inserted in the parent is visible in the
child, even those added while stopped in a vfork
catchpoint. This will remove the breakpoints from the
parent also, but they'll be reinserted below. */
if (has_vforked)
{
/* keep breakpoints list in sync. */
remove_breakpoints_pid (GET_PID (inferior_ptid));
}
if (info_verbose || debug_linux_nat)
{
target_terminal_ours ();
@ -700,7 +722,6 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
else
{
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
struct cleanup *old_chain;
/* Add process to GDB's tables. */
@ -711,12 +732,47 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
copy_terminal_info (child_inf, parent_inf);
old_chain = save_inferior_ptid ();
save_current_program_space ();
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
lp = add_lwp (inferior_ptid);
lp->stopped = 1;
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
child_lp->resumed = 1;
/* If this is a vfork child, then the address-space is
shared with the parent. */
if (has_vforked)
{
child_inf->pspace = parent_inf->pspace;
child_inf->aspace = parent_inf->aspace;
/* The parent will be frozen until the child is done
with the shared region. Keep track of the
parent. */
child_inf->vfork_parent = parent_inf;
child_inf->pending_detach = 0;
parent_inf->vfork_child = child_inf;
parent_inf->pending_detach = 0;
}
else
{
child_inf->aspace = new_address_space ();
child_inf->pspace = add_program_space (child_inf->aspace);
child_inf->removable = 1;
set_current_program_space (child_inf->pspace);
clone_program_space (child_inf->pspace, parent_inf->pspace);
/* Let the shared library layer (solib-svr4) learn about
this new process, relocate the cloned exec, pull in
shared libraries, and install the solib event
breakpoint. If a "cloned-VM" event was propagated
better throughout the core, this wouldn't be
required. */
solib_create_inferior_hook ();
}
/* Let the thread_db layer learn about this new process. */
check_for_thread_db ();
do_cleanups (old_chain);
@ -724,16 +780,34 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
if (has_vforked)
{
struct lwp_info *lp;
struct inferior *parent_inf;
parent_inf = current_inferior ();
/* If we detached from the child, then we have to be careful
to not insert breakpoints in the parent until the child
is done with the shared memory region. However, if we're
staying attached to the child, then we can and should
insert breakpoints, so that we can debug it. A
subsequent child exec or exit is enough to know when does
the child stops using the parent's address space. */
parent_inf->waiting_for_vfork_done = detach_fork;
lp = find_lwp_pid (pid_to_ptid (parent_pid));
gdb_assert (linux_supports_tracefork_flag >= 0);
if (linux_supports_tracevforkdone (0))
{
int status;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LCFF: waiting for VFORK_DONE on %d\n",
parent_pid);
ptrace (PTRACE_CONT, parent_pid, 0, 0);
my_waitpid (parent_pid, &status, __WALL);
if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
warning (_("Unexpected waitpid result %06x when waiting for "
"vfork-done"), status);
lp->stopped = 1;
lp->resumed = 1;
/* We'll handle the VFORK_DONE event like any other
event, in target_wait. */
}
else
{
@ -768,12 +842,26 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
is only the single-step breakpoint at vfork's return
point. */
usleep (10000);
}
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LCFF: no VFORK_DONE support, sleeping a bit\n");
/* Since we vforked, breakpoints were removed in the parent
too. Put them back. */
reattach_breakpoints (parent_pid);
usleep (10000);
/* Pretend we've seen a PTRACE_EVENT_VFORK_DONE event,
and leave it pending. The next linux_nat_resume call
will notice a pending event, and bypasses actually
resuming the inferior. */
lp->status = 0;
lp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
lp->stopped = 0;
lp->resumed = 1;
/* If we're in async mode, need to tell the event loop
there's something here to process. */
if (target_can_async_p ())
async_file_mark ();
}
}
}
else
@ -781,16 +869,19 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
struct thread_info *tp;
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
/* Before detaching from the parent, remove all breakpoints from it. */
remove_breakpoints ();
struct program_space *parent_pspace;
if (info_verbose || debug_linux_nat)
{
target_terminal_ours ();
fprintf_filtered (gdb_stdlog,
"Attaching after fork to child process %d.\n",
child_pid);
if (has_vforked)
fprintf_filtered (gdb_stdlog, _("\
Attaching after process %d vfork to child process %d.\n"),
parent_pid, child_pid);
else
fprintf_filtered (gdb_stdlog, _("\
Attaching after process %d fork to child process %d.\n"),
parent_pid, child_pid);
}
/* Add the new inferior first, so that the target_detach below
@ -802,53 +893,68 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);
/* If we're vforking, we may want to hold on to the parent until
the child exits or execs. At exec time we can remove the old
breakpoints from the parent and detach it; at exit time we
could do the same (or even, sneakily, resume debugging it - the
child's exec has failed, or something similar).
parent_pspace = parent_inf->pspace;
This doesn't clean up "properly", because we can't call
target_detach, but that's OK; if the current target is "child",
then it doesn't need any further cleanups, and lin_lwp will
generally not encounter vfork (vfork is defined to fork
in libpthread.so).
The holding part is very easy if we have VFORKDONE events;
but keeping track of both processes is beyond GDB at the
moment. So we don't expose the parent to the rest of GDB.
Instead we quietly hold onto it until such time as we can
safely resume it. */
/* If we're vforking, we want to hold on to the parent until the
child exits or execs. At child exec or exit time we can
remove the old breakpoints from the parent and detach or
resume debugging it. Otherwise, detach the parent now; we'll
want to reuse it's program/address spaces, but we can't set
them to the child before removing breakpoints from the
parent, otherwise, the breakpoints module could decide to
remove breakpoints from the wrong process (since they'd be
assigned to the same address space). */
if (has_vforked)
{
struct lwp_info *parent_lwp;
linux_parent_pid = parent_pid;
/* Get rid of the inferior on the core side as well. */
inferior_ptid = null_ptid;
detach_inferior (parent_pid);
/* Also get rid of all its lwps. We will detach from this
inferior soon-ish, but, we will still get an exit event
reported through waitpid when it exits. If we didn't get
rid of the lwps from our list, we would end up reporting
the inferior exit to the core, which would then try to
mourn a non-existing (from the core's perspective)
inferior. */
parent_lwp = find_lwp_pid (pid_to_ptid (parent_pid));
purge_lwp_list (GET_PID (parent_lwp->ptid));
linux_parent_pid = parent_pid;
gdb_assert (child_inf->vfork_parent == NULL);
gdb_assert (parent_inf->vfork_child == NULL);
child_inf->vfork_parent = parent_inf;
child_inf->pending_detach = 0;
parent_inf->vfork_child = child_inf;
parent_inf->pending_detach = detach_fork;
parent_inf->waiting_for_vfork_done = 0;
}
else if (detach_fork)
target_detach (NULL, 0);
/* Note that the detach above makes PARENT_INF dangling. */
/* Add the child thread to the appropriate lists, and switch to
this new thread, before cloning the program space, and
informing the solib layer about this new process. */
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
lp = add_lwp (inferior_ptid);
lp->stopped = 1;
lp->resumed = 1;
/* If this is a vfork child, then the address-space is shared
with the parent. If we detached from the parent, then we can
reuse the parent's program/address spaces. */
if (has_vforked || detach_fork)
{
child_inf->pspace = parent_pspace;
child_inf->aspace = child_inf->pspace->aspace;
}
else
{
child_inf->aspace = new_address_space ();
child_inf->pspace = add_program_space (child_inf->aspace);
child_inf->removable = 1;
set_current_program_space (child_inf->pspace);
clone_program_space (child_inf->pspace, parent_pspace);
/* Let the shared library layer (solib-svr4) learn about
this new process, relocate the cloned exec, pull in
shared libraries, and install the solib event breakpoint.
If a "cloned-VM" event was propagated better throughout
the core, this wouldn't be required. */
solib_create_inferior_hook ();
}
/* Let the thread_db layer learn about this new process. */
check_for_thread_db ();
}
@ -1749,7 +1855,16 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
static int
resume_callback (struct lwp_info *lp, void *data)
{
if (lp->stopped && lp->status == 0)
struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
if (lp->stopped && inf->vfork_child != NULL)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: Not resuming %s (vfork parent)\n",
target_pid_to_str (lp->ptid));
}
else if (lp->stopped && lp->status == 0)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@ -1870,7 +1985,7 @@ linux_nat_resume (struct target_ops *ops,
}
}
if (lp->status)
if (lp->status || lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
{
/* FIXME: What should we do if we are supposed to continue
this thread with a signal? */
@ -2236,25 +2351,28 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
ourstatus->value.execd_pathname
= xstrdup (linux_child_pid_to_exec_file (pid));
if (linux_parent_pid)
{
detach_breakpoints (linux_parent_pid);
ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
return 0;
}
linux_parent_pid = 0;
if (event == PTRACE_EVENT_VFORK_DONE)
{
if (current_inferior ()->waiting_for_vfork_done)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog, "\
LHEW: Got expected PTRACE_EVENT_VFORK_DONE from LWP %ld: stopping\n",
GET_LWP (lp->ptid));
ourstatus->kind = TARGET_WAITKIND_VFORK_DONE;
return 0;
}
/* At this point, all inserted breakpoints are gone. Doing this
as soon as we detect an exec prevents the badness of deleting
a breakpoint writing the current "shadow contents" to lift
the bp. That shadow is NOT valid after an exec.
Note that we have to do this after the detach_breakpoints
call above, otherwise breakpoints wouldn't be lifted from the
parent on a vfork, because detach_breakpoints would think
that breakpoints are not inserted. */
mark_breakpoints_out ();
return 0;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog, "\
LHEW: Got PTRACE_EVENT_VFORK_DONE from LWP %ld: resuming\n",
GET_LWP (lp->ptid));
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
return 1;
}
internal_error (__FILE__, __LINE__,
@ -2456,6 +2574,13 @@ maybe_clear_ignore_sigint (struct lwp_info *lp)
static int
stop_wait_callback (struct lwp_info *lp, void *data)
{
struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
/* If this is a vfork parent, bail out, it is not going to report
any SIGSTOP until the vfork is done with. */
if (inf->vfork_child != NULL)
return 0;
if (!lp->stopped)
{
int status;
@ -2690,7 +2815,7 @@ cancel_breakpoint (struct lwp_info *lp)
CORE_ADDR pc;
pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch);
if (breakpoint_inserted_here_p (pc))
if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,

View File

@ -22,8 +22,10 @@
#include "gdbtypes.h"
#include "linux-tdep.h"
#include "observer.h"
#include "auxv.h"
#include "target.h"
#include "elf-bfd.h"
#include "elf/common.h"
/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
@ -139,6 +141,21 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
return siginfo_type;
}
int
linux_has_shared_address_space (void)
{
/* Determine whether we are running on uClinux or normal Linux
kernel. */
CORE_ADDR dummy;
int target_is_uclinux;
target_is_uclinux
= (target_auxv_search (&current_target, AT_NULL, &dummy) > 0
&& target_auxv_search (&current_target, AT_PAGESZ, &dummy) == 0);
return target_is_uclinux;
}
/* Observer for the executable_changed event, to check whether the new
exec binary is a PIE (Position Independent Executable) specimen, which
is currently unsupported. */
@ -160,6 +177,9 @@ GDB does NOT currently support. Most debugger features will fail if used\n\
in this session.\n"));
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_linux_tdep;
void
_initialize_linux_tdep (void)
{

View File

@ -1226,18 +1226,15 @@ thread_db_wait (struct target_ops *ops,
if (ourstatus->kind == TARGET_WAITKIND_EXECD)
{
/* Breakpoints have already been marked non-inserted by the
layer below. We're safe in knowing that removing them will
not write the shadows of the old image into the new
image. */
remove_thread_event_breakpoints ();
/* New image, it may or may not end up using thread_db. Assume
not unless we find otherwise. */
delete_thread_db_info (GET_PID (ptid));
if (!thread_db_list)
unpush_target (&thread_db_ops);
/* Thread event breakpoints are deleted by
update_breakpoints_after_exec. */
return ptid;
}
@ -1274,13 +1271,12 @@ thread_db_mourn_inferior (struct target_ops *ops)
delete_thread_db_info (GET_PID (inferior_ptid));
/* Delete the old thread event breakpoints. Mark breakpoints out,
so that we don't try to un-insert them. */
mark_breakpoints_out ();
remove_thread_event_breakpoints ();
target_beneath->to_mourn_inferior (target_beneath);
/* Delete the old thread event breakpoints. Do this after mourning
the inferior, so that we don't try to uninsert them. */
remove_thread_event_breakpoints ();
/* Detach thread_db target ops. */
if (!thread_db_list)
unpush_target (ops);

View File

@ -56,7 +56,7 @@ static void mi_on_normal_stop (struct bpstats *bs, int print_frame);
static void mi_new_thread (struct thread_info *t);
static void mi_thread_exit (struct thread_info *t, int silent);
static void mi_new_inferior (int pid);
static void mi_inferior_appeared (int pid);
static void mi_inferior_exit (int pid);
static void mi_on_resume (ptid_t ptid);
static void mi_solib_loaded (struct so_list *solib);
@ -86,7 +86,7 @@ mi_interpreter_init (int top_level)
{
observer_attach_new_thread (mi_new_thread);
observer_attach_thread_exit (mi_thread_exit);
observer_attach_new_inferior (mi_new_inferior);
observer_attach_inferior_appeared (mi_inferior_appeared);
observer_attach_inferior_exit (mi_inferior_exit);
observer_attach_normal_stop (mi_on_normal_stop);
observer_attach_target_resumed (mi_on_resume);
@ -308,12 +308,12 @@ mi_thread_exit (struct thread_info *t, int silent)
gdb_flush (mi->event_channel);
}
static void
mi_new_inferior (int pid)
void
mi_inferior_appeared (int pid)
{
struct mi_interp *mi = top_level_interpreter_data ();
target_terminal_ours ();
fprintf_unfiltered (mi->event_channel, "thread-group-created,id=\"%d\"",
fprintf_unfiltered (mi->event_channel, "thread-group-created,id=\"%d\"",
pid);
gdb_flush (mi->event_channel);
}

View File

@ -362,13 +362,18 @@ mi_cmd_thread_info (char *command, char **argv, int argc)
static int
print_one_inferior (struct inferior *inferior, void *arg)
{
struct cleanup *back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
if (inferior->pid != 0)
{
struct cleanup *back_to
= make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_fmt (uiout, "id", "%d", inferior->pid);
ui_out_field_string (uiout, "type", "process");
ui_out_field_int (uiout, "pid", inferior->pid);
do_cleanups (back_to);
}
ui_out_field_fmt (uiout, "id", "%d", inferior->pid);
ui_out_field_string (uiout, "type", "process");
ui_out_field_int (uiout, "pid", inferior->pid);
do_cleanups (back_to);
return 0;
}

View File

@ -2383,7 +2383,8 @@ mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
the sequence. */
static int
deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
deal_with_atomic_sequence (struct gdbarch *gdbarch,
struct address_space *aspace, CORE_ADDR pc)
{
CORE_ADDR breaks[2] = {-1, -1};
CORE_ADDR loc = pc;
@ -2471,7 +2472,7 @@ deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
/* Effectively inserts the breakpoints. */
for (index = 0; index <= last_breakpoint; index++)
insert_single_step_breakpoint (gdbarch, breaks[index]);
insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
return 1;
}
@ -2485,15 +2486,16 @@ int
mips_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR pc, next_pc;
pc = get_frame_pc (frame);
if (deal_with_atomic_sequence (gdbarch, pc))
if (deal_with_atomic_sequence (gdbarch, aspace, pc))
return 1;
next_pc = mips_next_pc (frame, pc);
insert_single_step_breakpoint (gdbarch, next_pc);
insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
@ -4677,7 +4679,7 @@ mips_single_step_through_delay (struct gdbarch *gdbarch,
if (mips_pc_is_mips16 (pc))
return 0;
if (!breakpoint_here_p (pc + 4))
if (!breakpoint_here_p (get_frame_address_space (frame), pc + 4))
return 0;
if (!safe_frame_unwind_memory (frame, pc, buf, sizeof buf))

View File

@ -705,6 +705,7 @@ monitor_open (char *args, struct monitor_ops *mon_ops, int from_tty)
{
char *name;
char **p;
struct inferior *inf;
if (mon_ops->magic != MONITOR_OPS_MAGIC)
error (_("Magic number of monitor_ops struct wrong."));
@ -822,7 +823,8 @@ monitor_open (char *args, struct monitor_ops *mon_ops, int from_tty)
/* Make run command think we are busy... */
inferior_ptid = monitor_ptid;
add_inferior_silent (ptid_get_pid (inferior_ptid));
inf = current_inferior ();
inferior_appeared (inf, ptid_get_pid (inferior_ptid));
add_thread_silent (inferior_ptid);
/* Give monitor_wait something to read */

View File

@ -640,7 +640,8 @@ procfs_attach (struct target_ops *ops, char *args, int from_tty)
gdb_flush (gdb_stdout);
}
inferior_ptid = do_attach (pid_to_ptid (pid));
inf = add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
inf->attach_flag = 1;
push_target (ops);
@ -1196,7 +1197,8 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
inferior_ptid = do_attach (pid_to_ptid (pid));
procfs_find_new_threads (ops);
inf = add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
inf->attach_flag = 0;
flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */

View File

@ -61,16 +61,53 @@ static void objfile_free_data (struct objfile *objfile);
/* Externally visible variables that are owned by this module.
See declarations in objfile.h for more info. */
struct objfile *object_files; /* Linked list of all objfiles */
struct objfile *current_objfile; /* For symbol file being read in */
struct objfile *symfile_objfile; /* Main symbol table loaded from */
struct objfile *rt_common_objfile; /* For runtime common symbols */
struct objfile_pspace_info
{
int objfiles_changed_p;
struct obj_section **sections;
int num_sections;
};
/* Per-program-space data key. */
static const struct program_space_data *objfiles_pspace_data;
static void
objfiles_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
struct objfile_pspace_info *info;
info = program_space_data (pspace, objfiles_pspace_data);
if (info != NULL)
{
xfree (info->sections);
xfree (info);
}
}
/* Get the current svr4 data. If none is found yet, add it now. This
function always returns a valid object. */
static struct objfile_pspace_info *
get_objfile_pspace_data (struct program_space *pspace)
{
struct objfile_pspace_info *info;
info = program_space_data (pspace, objfiles_pspace_data);
if (info == NULL)
{
info = XZALLOC (struct objfile_pspace_info);
set_program_space_data (pspace, objfiles_pspace_data, info);
}
return info;
}
/* Records whether any objfiles appeared or disappeared since we last updated
address to obj section map. */
static int objfiles_changed_p;
/* Locate all mappable sections of a BFD file.
objfile_p_char is a char * to get it through
bfd_map_over_sections; we cast it back to its proper type. */
@ -208,6 +245,8 @@ allocate_objfile (bfd *abfd, int flags)
objfile->name = xstrdup ("<<anonymous objfile>>");
}
objfile->pspace = current_program_space;
/* Initialize the section indexes for this objfile, so that we can
later detect if they are used w/o being properly assigned to. */
@ -236,9 +275,10 @@ allocate_objfile (bfd *abfd, int flags)
/* Save passed in flag bits. */
objfile->flags |= flags;
objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
/* Rebuild section map next time we need it. */
get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
return (objfile);
return objfile;
}
/* Retrieve the gdbarch associated with OBJFILE. */
@ -512,9 +552,11 @@ free_objfile (struct objfile *objfile)
if (objfile->demangled_names_hash)
htab_delete (objfile->demangled_names_hash);
obstack_free (&objfile->objfile_obstack, 0);
/* Rebuild section map next time we need it. */
get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
xfree (objfile);
objfile = NULL;
objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
}
static void
@ -686,7 +728,7 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
}
/* Rebuild section map next time we need it. */
objfiles_changed_p = 1;
get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
/* Update the table in exec_ops, used to read memory. */
ALL_OBJFILE_OSECTIONS (objfile, s)
@ -1053,28 +1095,31 @@ filter_overlapping_sections (struct obj_section **map, int map_size)
TLS, overlay and overlapping sections. */
static void
update_section_map (struct obj_section ***pmap, int *pmap_size)
update_section_map (struct program_space *pspace,
struct obj_section ***pmap, int *pmap_size)
{
int alloc_size, map_size, i;
struct obj_section *s, **map;
struct objfile *objfile;
gdb_assert (objfiles_changed_p != 0);
gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
map = *pmap;
xfree (map);
alloc_size = 0;
ALL_OBJSECTIONS (objfile, s)
if (insert_section_p (objfile->obfd, s->the_bfd_section))
alloc_size += 1;
ALL_PSPACE_OBJFILES (pspace, objfile)
ALL_OBJFILE_OSECTIONS (objfile, s)
if (insert_section_p (objfile->obfd, s->the_bfd_section))
alloc_size += 1;
map = xmalloc (alloc_size * sizeof (*map));
i = 0;
ALL_OBJSECTIONS (objfile, s)
if (insert_section_p (objfile->obfd, s->the_bfd_section))
map[i++] = s;
ALL_PSPACE_OBJFILES (pspace, objfile)
ALL_OBJFILE_OSECTIONS (objfile, s)
if (insert_section_p (objfile->obfd, s->the_bfd_section))
map[i++] = s;
qsort (map, alloc_size, sizeof (*map), qsort_cmp);
map_size = filter_debuginfo_sections(map, alloc_size);
@ -1110,9 +1155,7 @@ bsearch_cmp (const void *key, const void *elt)
struct obj_section *
find_pc_section (CORE_ADDR pc)
{
static struct obj_section **sections;
static int num_sections;
struct objfile_pspace_info *pspace_info;
struct obj_section *s, **sp;
/* Check for mapped overlay section first. */
@ -1120,17 +1163,23 @@ find_pc_section (CORE_ADDR pc)
if (s)
return s;
if (objfiles_changed_p != 0)
pspace_info = get_objfile_pspace_data (current_program_space);
if (pspace_info->objfiles_changed_p != 0)
{
update_section_map (&sections, &num_sections);
update_section_map (current_program_space,
&pspace_info->sections,
&pspace_info->num_sections);
/* Don't need updates to section map until objfiles are added
or removed. */
objfiles_changed_p = 0;
/* Don't need updates to section map until objfiles are added,
removed or relocated. */
pspace_info->objfiles_changed_p = 0;
}
sp = (struct obj_section **) bsearch (&pc, sections, num_sections,
sizeof (*sections), bsearch_cmp);
sp = (struct obj_section **) bsearch (&pc,
pspace_info->sections,
pspace_info->num_sections,
sizeof (*pspace_info->sections),
bsearch_cmp);
if (sp != NULL)
return *sp;
return NULL;
@ -1271,7 +1320,8 @@ objfile_data (struct objfile *objfile, const struct objfile_data *data)
void
objfiles_changed (void)
{
objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
/* Rebuild section map next time we need it. */
get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1;
}
/* Add reference to ABFD. Returns ABFD. */
@ -1322,3 +1372,13 @@ gdb_bfd_unref (struct bfd *abfd)
name, bfd_errmsg (bfd_get_error ()));
xfree (name);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_objfiles;
void
_initialize_objfiles (void)
{
objfiles_pspace_data
= register_program_space_data_with_cleanup (objfiles_pspace_data_cleanup);
}

View File

@ -23,6 +23,7 @@
#include "gdb_obstack.h" /* For obstack internals. */
#include "symfile.h" /* For struct psymbol_allocation_list */
#include "progspace.h"
struct bcache;
struct htab;
@ -200,6 +201,10 @@ struct objfile
unsigned short flags;
/* The program space associated with this objfile. */
struct program_space *pspace;
/* 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. */
@ -414,11 +419,6 @@ struct objfile
#define OBJF_USERLOADED (1 << 3) /* User loaded */
/* The object file that the main symbol table was loaded from (e.g. the
argument to the "symbol-file" or "file" command). */
extern struct objfile *symfile_objfile;
/* The object file that contains the runtime common minimal symbols
for SunOS4. Note that this objfile has no associated BFD. */
@ -439,11 +439,6 @@ extern struct objfile *rt_common_objfile;
extern struct objfile *current_objfile;
/* All known objfiles are kept in a linked list. This points to the
root of this list. */
extern struct objfile *object_files;
/* Declarations for functions defined in objfiles.c */
extern struct objfile *allocate_objfile (bfd *, int);
@ -524,14 +519,27 @@ extern struct bfd *gdb_bfd_ref (struct bfd *abfd);
extern void gdb_bfd_unref (struct bfd *abfd);
/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete
the objfile during the traversal. */
/* Traverse all object files in the current program space.
ALL_OBJFILES_SAFE works even if you delete the objfile during the
traversal. */
#define ALL_OBJFILES(obj) \
for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next)
/* Traverse all object files in program space SS. */
#define ALL_OBJFILES_SAFE(obj,nxt) \
for ((obj) = object_files; \
#define ALL_PSPACE_OBJFILES(ss, obj) \
for ((obj) = ss->objfiles; (obj) != NULL; (obj) = (obj)->next) \
#define ALL_PSPACE_OBJFILES_SAFE(ss, obj, nxt) \
for ((obj) = ss->objfiles; \
(obj) != NULL? ((nxt)=(obj)->next,1) :0; \
(obj) = (nxt))
#define ALL_OBJFILES(obj) \
for ((obj) = current_program_space->objfiles; \
(obj) != NULL; \
(obj) = (obj)->next)
#define ALL_OBJFILES_SAFE(obj,nxt) \
for ((obj) = current_program_space->objfiles; \
(obj) != NULL? ((nxt)=(obj)->next,1) :0; \
(obj) = (nxt))
@ -550,27 +558,44 @@ extern void gdb_bfd_unref (struct bfd *abfd);
#define ALL_OBJFILE_MSYMBOLS(objfile, m) \
for ((m) = (objfile) -> msymbols; SYMBOL_LINKAGE_NAME(m) != NULL; (m)++)
/* Traverse all symtabs in all objfiles. */
/* Traverse all symtabs in all objfiles in the current symbol
space. */
#define ALL_SYMTABS(objfile, s) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_SYMTABS (objfile, s)
/* Traverse all symtabs in all objfiles, skipping included files
(which share a blockvector with their primary symtab). */
#define ALL_PSPACE_SYMTABS(ss, objfile, s) \
ALL_PSPACE_OBJFILES (ss, objfile) \
ALL_OBJFILE_SYMTABS (objfile, s)
/* Traverse all symtabs in all objfiles in the current program space,
skipping included files (which share a blockvector with their
primary symtab). */
#define ALL_PRIMARY_SYMTABS(objfile, s) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_SYMTABS (objfile, s) \
if ((s)->primary)
/* Traverse all psymtabs in all objfiles. */
#define ALL_PSPACE_PRIMARY_SYMTABS(pspace, objfile, s) \
ALL_PSPACE_OBJFILES (ss, objfile) \
ALL_OBJFILE_SYMTABS (objfile, s) \
if ((s)->primary)
/* Traverse all psymtabs in all objfiles in the current symbol
space. */
#define ALL_PSYMTABS(objfile, p) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)
/* Traverse all minimal symbols in all objfiles. */
#define ALL_PSPACE_PSYMTABS(ss, objfile, p) \
ALL_PSPACE_OBJFILES (ss, objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)
/* Traverse all minimal symbols in all objfiles in the current symbol
space. */
#define ALL_MSYMBOLS(objfile, m) \
ALL_OBJFILES (objfile) \

View File

@ -135,16 +135,25 @@ struct display
{
/* Chain link to next auto-display item. */
struct display *next;
/* The expression as the user typed it. */
char *exp_string;
/* Expression to be evaluated and displayed. */
struct expression *exp;
/* Item number of this auto-display item. */
int number;
/* Display format specified. */
struct format_data format;
/* Program space associated with `block'. */
struct program_space *pspace;
/* Innermost block required by this expression when evaluated */
struct block *block;
/* Status of this display (enabled or disabled) */
int enabled_p;
};
@ -1449,6 +1458,7 @@ display_command (char *exp, int from_tty)
new->exp_string = xstrdup (exp);
new->exp = expr;
new->block = innermost_block;
new->pspace = current_program_space;
new->next = display_chain;
new->number = ++display_number;
new->format = fmt;
@ -1585,7 +1595,12 @@ do_one_display (struct display *d)
}
if (d->block)
within_current_scope = contained_in (get_selected_block (0), d->block);
{
if (d->pspace == current_program_space)
within_current_scope = contained_in (get_selected_block (0), d->block);
else
within_current_scope = 0;
}
else
within_current_scope = 1;
if (!within_current_scope)
@ -1810,6 +1825,7 @@ display_uses_solib_p (const struct display *d,
const union exp_element *const elts = exp->elts;
if (d->block != NULL
&& d->pspace == solib->pspace
&& solib_contains_address_p (solib, d->block->startaddr))
return 1;
@ -1830,7 +1846,8 @@ display_uses_solib_p (const struct display *d,
SYMBOL_OBJ_SECTION (symbol);
if (block != NULL
&& solib_contains_address_p (solib, block->startaddr))
&& solib_contains_address_p (solib,
block->startaddr))
return 1;
if (section && section->objfile == solib->objfile)

View File

@ -3705,7 +3705,8 @@ do_attach (ptid_t ptid)
if ((fail = procfs_debug_inferior (pi)) != 0)
dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL);
inf = add_inferior (pi->pid);
inf = current_inferior ();
inferior_appeared (inf, pi->pid);
/* Let GDB know that the inferior was attached. */
inf->attach_flag = 1;

625
gdb/progspace.c Normal file
View File

@ -0,0 +1,625 @@
/* Program and address space management, for GDB, the GNU debugger.
Copyright (C) 2009 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdbcmd.h"
#include "objfiles.h"
#include "arch-utils.h"
#include "gdbcore.h"
#include "solib.h"
#include "gdbthread.h"
/* The last program space number assigned. */
int last_program_space_num = 0;
/* The head of the program spaces list. */
struct program_space *program_spaces;
/* Pointer to the current program space. */
struct program_space *current_program_space;
/* The last address space number assigned. */
static int highest_address_space_num;
/* Prototypes for local functions */
static void program_space_alloc_data (struct program_space *);
static void program_space_free_data (struct program_space *);
/* An address space. Currently this is not used for much other than
for comparing if pspaces/inferior/threads see the same address
space. */
struct address_space
{
int num;
};
/* Create a new address space object, and add it to the list. */
struct address_space *
new_address_space (void)
{
struct address_space *aspace;
aspace = XZALLOC (struct address_space);
aspace->num = ++highest_address_space_num;
return aspace;
}
/* Maybe create a new address space object, and add it to the list, or
return a pointer to an existing address space, in case inferiors
share an address space on this target system. */
struct address_space *
maybe_new_address_space (void)
{
int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch);
if (shared_aspace)
{
/* Just return the first in the list. */
return program_spaces->aspace;
}
return new_address_space ();
}
static void
free_address_space (struct address_space *aspace)
{
xfree (aspace);
}
/* Start counting over from scratch. */
static void
init_address_spaces (void)
{
highest_address_space_num = 0;
}
/* Adds a new empty program space to the program space list, and binds
it to ASPACE. Returns the pointer to the new object. */
struct program_space *
add_program_space (struct address_space *aspace)
{
struct program_space *pspace;
pspace = XZALLOC (struct program_space);
pspace->num = ++last_program_space_num;
pspace->aspace = aspace;
program_space_alloc_data (pspace);
pspace->next = program_spaces;
program_spaces = pspace;
return pspace;
}
/* Releases program space PSPACE, and all its contents (shared
libraries, objfiles, and any other references to the PSPACE in
other modules). It is an internal error to call this when PSPACE
is the current program space, since there should always be a
program space. */
static void
release_program_space (struct program_space *pspace)
{
struct cleanup *old_chain = save_current_program_space ();
gdb_assert (pspace != current_program_space);
set_current_program_space (pspace);
breakpoint_program_space_exit (pspace);
no_shared_libraries (NULL, 0);
exec_close ();
free_all_objfiles ();
if (!gdbarch_has_shared_address_space (target_gdbarch))
free_address_space (pspace->aspace);
resize_section_table (&pspace->target_sections,
-resize_section_table (&pspace->target_sections, 0));
/* Discard any data modules have associated with the PSPACE. */
program_space_free_data (pspace);
xfree (pspace);
do_cleanups (old_chain);
}
/* Unlinks PSPACE from the pspace list, and releases it. */
void
remove_program_space (struct program_space *pspace)
{
struct program_space *ss, **ss_link;
ss = program_spaces;
ss_link = &program_spaces;
while (ss)
{
if (ss != pspace)
{
ss_link = &ss->next;
ss = *ss_link;
continue;
}
*ss_link = ss->next;
release_program_space (ss);
ss = *ss_link;
}
}
/* Copies program space SRC to DEST. Copies the main executable file,
and the main symbol file. Returns DEST. */
struct program_space *
clone_program_space (struct program_space *dest, struct program_space *src)
{
struct program_space *new_pspace;
struct cleanup *old_chain;
old_chain = save_current_program_space ();
set_current_program_space (dest);
if (src->ebfd != NULL)
exec_file_attach (bfd_get_filename (src->ebfd), 0);
if (src->symfile_object_file != NULL)
symbol_file_add_main (src->symfile_object_file->name, 0);
do_cleanups (old_chain);
return dest;
}
/* Sets PSPACE as the current program space. It is the caller's
responsibility to make sure that the currently selected
inferior/thread matches the selected program space. */
void
set_current_program_space (struct program_space *pspace)
{
if (current_program_space == pspace)
return;
gdb_assert (pspace != NULL);
current_program_space = pspace;
/* Different symbols change our view of the frame chain. */
reinit_frame_cache ();
}
/* A cleanups callback, helper for save_current_program_space
below. */
static void
restore_program_space (void *arg)
{
struct program_space *saved_pspace = arg;
set_current_program_space (saved_pspace);
}
/* Save the current program space so that it may be restored by a later
call to do_cleanups. Returns the struct cleanup pointer needed for
later doing the cleanup. */
struct cleanup *
save_current_program_space (void)
{
struct cleanup *old_chain = make_cleanup (restore_program_space,
current_program_space);
return old_chain;
}
/* Find program space number NUM; returns NULL if not found. */
static struct program_space *
find_program_space_by_num (int num)
{
struct program_space *pspace;
ALL_PSPACES (pspace)
if (pspace->num == num)
return pspace;
return NULL;
}
/* Returns true iff there's no inferior bound to PSPACE. */
static int
pspace_empty_p (struct program_space *pspace)
{
struct inferior *inf;
if (find_inferior_for_program_space (pspace) != NULL)
return 0;
return 1;
}
/* Prune away automatically added program spaces that aren't required
anymore. */
void
prune_program_spaces (void)
{
struct program_space *ss, **ss_link;
struct program_space *current = current_program_space;
ss = program_spaces;
ss_link = &program_spaces;
while (ss)
{
if (ss == current || !pspace_empty_p (ss))
{
ss_link = &ss->next;
ss = *ss_link;
continue;
}
*ss_link = ss->next;
release_program_space (ss);
ss = *ss_link;
}
}
/* Prints the list of program spaces and their details on UIOUT. If
REQUESTED is not -1, it's the ID of the pspace that should be
printed. Otherwise, all spaces are printed. */
static void
print_program_space (struct ui_out *uiout, int requested)
{
struct program_space *pspace;
int count = 0;
struct cleanup *old_chain;
/* Might as well prune away unneeded ones, so the user doesn't even
seem them. */
prune_program_spaces ();
/* Compute number of pspaces we will print. */
ALL_PSPACES (pspace)
{
if (requested != -1 && pspace->num != requested)
continue;
++count;
}
/* There should always be at least one. */
gdb_assert (count > 0);
old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, count, "pspaces");
ui_out_table_header (uiout, 1, ui_left, "current", "");
ui_out_table_header (uiout, 4, ui_left, "id", "Id");
ui_out_table_header (uiout, 17, ui_left, "exec", "Executable");
ui_out_table_body (uiout);
ALL_PSPACES (pspace)
{
struct cleanup *chain2;
struct inferior *inf;
int printed_header;
if (requested != -1 && requested != pspace->num)
continue;
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
if (pspace == current_program_space)
ui_out_field_string (uiout, "current", "*");
else
ui_out_field_skip (uiout, "current");
ui_out_field_int (uiout, "id", pspace->num);
if (pspace->ebfd)
ui_out_field_string (uiout, "exec",
bfd_get_filename (pspace->ebfd));
else
ui_out_field_skip (uiout, "exec");
/* Print extra info that doesn't really fit in tabular form.
Currently, we print the list of inferiors bound to a pspace.
There can be more than one inferior bound to the same pspace,
e.g., both parent/child inferiors in a vfork, or, on targets
that share pspaces between inferiors. */
printed_header = 0;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pspace == pspace)
{
if (!printed_header)
{
printed_header = 1;
printf_filtered ("\n\tBound inferiors: ID %d (%s)",
inf->num,
target_pid_to_str (pid_to_ptid (inf->pid)));
}
else
printf_filtered (", ID %d (%s)",
inf->num,
target_pid_to_str (pid_to_ptid (inf->pid)));
}
ui_out_text (uiout, "\n");
do_cleanups (chain2);
}
do_cleanups (old_chain);
}
/* Boolean test for an already-known program space id. */
static int
valid_program_space_id (int num)
{
struct program_space *pspace;
ALL_PSPACES (pspace)
if (pspace->num == num)
return 1;
return 0;
}
/* If ARGS is NULL or empty, print information about all program
spaces. Otherwise, ARGS is a text representation of a LONG
indicating which the program space to print information about. */
static void
maintenance_info_program_spaces_command (char *args, int from_tty)
{
int requested = -1;
if (args && *args)
{
requested = parse_and_eval_long (args);
if (!valid_program_space_id (requested))
error (_("program space ID %d not known."), requested);
}
print_program_space (uiout, requested);
}
/* Simply returns the count of program spaces. */
int
number_of_program_spaces (void)
{
struct program_space *pspace;
int count = 0;
ALL_PSPACES (pspace)
count++;
return count;
}
/* Update all program spaces matching to address spaces. The user may
have created several program spaces, and loaded executables into
them before connecting to the target interface that will create the
inferiors. All that happens before GDB has a chance to know if the
inferiors will share an address space or not. Call this after
having connected to the target interface and having fetched the
target description, to fixup the program/address spaces mappings.
It is assumed that there are no bound inferiors yet, otherwise,
they'd be left with stale referenced to released aspaces. */
void
update_address_spaces (void)
{
int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch);
struct address_space *aspace = NULL;
struct program_space *pspace;
init_address_spaces ();
ALL_PSPACES (pspace)
{
free_address_space (pspace->aspace);
if (shared_aspace)
{
if (aspace == NULL)
aspace = new_address_space ();
pspace->aspace = aspace;
}
else
pspace->aspace = new_address_space ();
}
}
/* Save the current program space so that it may be restored by a later
call to do_cleanups. Returns the struct cleanup pointer needed for
later doing the cleanup. */
struct cleanup *
save_current_space_and_thread (void)
{
struct cleanup *old_chain;
/* If restoring to null thread, we need to restore the pspace as
well, hence, we need to save the current program space first. */
old_chain = save_current_program_space ();
save_current_inferior ();
make_cleanup_restore_current_thread ();
return old_chain;
}
/* Switches full context to program space PSPACE. Switches to the
first thread found bound to PSPACE. */
void
switch_to_program_space_and_thread (struct program_space *pspace)
{
struct inferior *inf;
inf = find_inferior_for_program_space (pspace);
if (inf != NULL)
{
struct thread_info *tp;
tp = any_live_thread_of_process (inf->pid);
if (tp != NULL)
{
switch_to_thread (tp->ptid);
/* Switching thread switches pspace implicitly. We're
done. */
return;
}
}
switch_to_thread (null_ptid);
set_current_program_space (pspace);
}
/* Keep a registry of per-program_space data-pointers required by other GDB
modules. */
struct program_space_data
{
unsigned index;
void (*cleanup) (struct program_space *, void *);
};
struct program_space_data_registration
{
struct program_space_data *data;
struct program_space_data_registration *next;
};
struct program_space_data_registry
{
struct program_space_data_registration *registrations;
unsigned num_registrations;
};
static struct program_space_data_registry program_space_data_registry
= { NULL, 0 };
const struct program_space_data *
register_program_space_data_with_cleanup
(void (*cleanup) (struct program_space *, void *))
{
struct program_space_data_registration **curr;
/* Append new registration. */
for (curr = &program_space_data_registry.registrations;
*curr != NULL; curr = &(*curr)->next);
*curr = XMALLOC (struct program_space_data_registration);
(*curr)->next = NULL;
(*curr)->data = XMALLOC (struct program_space_data);
(*curr)->data->index = program_space_data_registry.num_registrations++;
(*curr)->data->cleanup = cleanup;
return (*curr)->data;
}
const struct program_space_data *
register_program_space_data (void)
{
return register_program_space_data_with_cleanup (NULL);
}
static void
program_space_alloc_data (struct program_space *pspace)
{
gdb_assert (pspace->data == NULL);
pspace->num_data = program_space_data_registry.num_registrations;
pspace->data = XCALLOC (pspace->num_data, void *);
}
static void
program_space_free_data (struct program_space *pspace)
{
gdb_assert (pspace->data != NULL);
clear_program_space_data (pspace);
xfree (pspace->data);
pspace->data = NULL;
}
void
clear_program_space_data (struct program_space *pspace)
{
struct program_space_data_registration *registration;
int i;
gdb_assert (pspace->data != NULL);
for (registration = program_space_data_registry.registrations, i = 0;
i < pspace->num_data;
registration = registration->next, i++)
if (pspace->data[i] != NULL && registration->data->cleanup)
registration->data->cleanup (pspace, pspace->data[i]);
memset (pspace->data, 0, pspace->num_data * sizeof (void *));
}
void
set_program_space_data (struct program_space *pspace,
const struct program_space_data *data,
void *value)
{
gdb_assert (data->index < pspace->num_data);
pspace->data[data->index] = value;
}
void *
program_space_data (struct program_space *pspace, const struct program_space_data *data)
{
gdb_assert (data->index < pspace->num_data);
return pspace->data[data->index];
}
void
initialize_progspace (void)
{
add_cmd ("program-spaces", class_maintenance,
maintenance_info_program_spaces_command, _("\
Info about currently known program spaces."),
&maintenanceinfolist);
/* There's always one program space. Note that this function isn't
an automatic _initialize_foo function, since other
_initialize_foo routines may need to install their per-pspace
data keys. We can only allocate a progspace when all those
modules have done that. Do this before
initialize_current_architecture, because that accesses exec_bfd,
which in turn dereferences current_program_space. */
current_program_space = add_program_space (new_address_space ());
}

283
gdb/progspace.h Normal file
View File

@ -0,0 +1,283 @@
/* Program and address space management, for GDB, the GNU debugger.
Copyright (C) 2009 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef PROGSPACE_H
#define PROGSPACE_H
#include "target.h"
#include "vec.h"
struct target_ops;
struct bfd;
struct objfile;
struct inferior;
struct exec;
struct address_space;
struct program_space_data;
/* A program space represents a symbolic view of an address space.
Roughly speaking, it holds all the data associated with a
non-running-yet program (main executable, main symbols), and when
an inferior is running and is bound to it, includes the list of its
mapped in shared libraries.
In the traditional debugging scenario, there's a 1-1 correspondence
among program spaces, inferiors and address spaces, like so:
pspace1 (prog1) <--> inf1(pid1) <--> aspace1
In the case of debugging more than one traditional unix process or
program, we still have:
|-----------------+------------+---------|
| pspace1 (prog1) | inf1(pid1) | aspace1 |
|----------------------------------------|
| pspace2 (prog1) | no inf yet | aspace2 |
|-----------------+------------+---------|
| pspace3 (prog2) | inf2(pid2) | aspace3 |
|-----------------+------------+---------|
In the former example, if inf1 forks (and GDB stays attached to
both processes), the new child will have its own program and
address spaces. Like so:
|-----------------+------------+---------|
| pspace1 (prog1) | inf1(pid1) | aspace1 |
|-----------------+------------+---------|
| pspace2 (prog1) | inf2(pid2) | aspace2 |
|-----------------+------------+---------|
However, had inf1 from the latter case vforked instead, it would
share the program and address spaces with its parent, until it
execs or exits, like so:
|-----------------+------------+---------|
| pspace1 (prog1) | inf1(pid1) | aspace1 |
| | inf2(pid2) | |
|-----------------+------------+---------|
When the vfork child execs, it is finally given new program and
address spaces.
|-----------------+------------+---------|
| pspace1 (prog1) | inf1(pid1) | aspace1 |
|-----------------+------------+---------|
| pspace2 (prog1) | inf2(pid2) | aspace2 |
|-----------------+------------+---------|
There are targets where the OS (if any) doesn't provide memory
management or VM protection, where all inferiors share the same
address space --- e.g. uClinux. GDB models this by having all
inferiors share the same address space, but, giving each its own
program space, like so:
|-----------------+------------+---------|
| pspace1 (prog1) | inf1(pid1) | |
|-----------------+------------+ |
| pspace2 (prog1) | inf2(pid2) | aspace1 |
|-----------------+------------+ |
| pspace3 (prog2) | inf3(pid3) | |
|-----------------+------------+---------|
The address space sharing matters for run control and breakpoints
management. E.g., did we just hit a known breakpoint that we need
to step over? Is this breakpoint a duplicate of this other one, or
do I need to insert a trap?
Then, there are targets where all symbols look the same for all
inferiors, although each has its own address space, as e.g.,
Ericsson DICOS. In such case, the model is:
|---------+------------+---------|
| | inf1(pid1) | aspace1 |
| +------------+---------|
| pspace | inf2(pid2) | aspace2 |
| +------------+---------|
| | inf3(pid3) | aspace3 |
|---------+------------+---------|
Note however, that the DICOS debug API takes care of making GDB
believe that breakpoints are "global". That is, although each
process does have its own private copy of data symbols (just like a
bunch of forks), to the breakpoints module, all processes share a
single address space, so all breakpoints set at the same address
are duplicates of each other, even breakpoints set in the data
space (e.g., call dummy breakpoints placed on stack). This allows
a simplification in the spaces implementation: we avoid caring for
a many-many links between address and program spaces. Either
there's a single address space bound to the program space
(traditional unix/uClinux), or, in the DICOS case, the address
space bound to the program space is mostly ignored. */
/* The program space structure. */
struct program_space
{
/* Pointer to next in linked list. */
struct program_space *next;
/* Unique ID number. */
int num;
/* The main executable loaded into this program space. This is
managed by the exec target. */
/* The BFD handle for the main executable. */
bfd *ebfd;
/* The last-modified time, from when the exec was brought in. */
long ebfd_mtime;
/* The address space attached to this program space. More than one
program space may be bound to the same address space. In the
traditional unix-like debugging scenario, this will usually
match the address space bound to the inferior, and is mostly
used by the breakpoints module for address matches. If the
target shares a program space for all inferiors and breakpoints
are global, then this field is ignored (we don't currently
support inferiors sharing a program space if the target doesn't
make breakpoints global). */
struct address_space *aspace;
/* True if this program space's section offsets don't yet represent
the final offsets of the "live" address space (that is, the
section addresses still require the relocation offsets to be
applied, and hence we can't trust the section addresses for
anything that pokes at live memory). E.g., for qOffsets
targets, or for PIE executables, until we connect and ask the
target for the final relocation offsets, the symbols we've used
to set breakpoints point at the wrong addresses. */
int executing_startup;
/* The object file that the main symbol table was loaded from
(e.g. the argument to the "symbol-file" or "file" command). */
struct objfile *symfile_object_file;
/* All known objfiles are kept in a linked list. This points to
the head of this list. */
struct objfile *objfiles;
/* The set of target sections matching the sections mapped into
this program space. Managed by both exec_ops and solib.c. */
struct target_section_table target_sections;
/* List of shared objects mapped into this space. Managed by
solib.c. */
struct so_list *so_list;
/* Per pspace data-pointers required by other GDB modules. */
void **data;
unsigned num_data;
};
/* The object file that the main symbol table was loaded from (e.g. the
argument to the "symbol-file" or "file" command). */
#define symfile_objfile current_program_space->symfile_object_file
/* All known objfiles are kept in a linked list. This points to the
root of this list. */
#define object_files current_program_space->objfiles
/* The set of target sections matching the sections mapped into the
current program space. */
#define current_target_sections (&current_program_space->target_sections)
/* The list of all program spaces. There's always at least one. */
extern struct program_space *program_spaces;
/* The current program space. This is always non-null. */
extern struct program_space *current_program_space;
#define ALL_PSPACES(pspace) \
for ((pspace) = program_spaces; (pspace) != NULL; (pspace) = (pspace)->next)
/* Add a new empty program space, and assign ASPACE to it. Returns the
pointer to the new object. */
extern struct program_space *add_program_space (struct address_space *aspace);
/* Release PSPACE and removes it from the pspace list. */
extern void remove_program_space (struct program_space *pspace);
/* Returns the number of program spaces listed. */
extern int number_of_program_spaces (void);
/* Copies program space SRC to DEST. Copies the main executable file,
and the main symbol file. Returns DEST. */
extern struct program_space *clone_program_space (struct program_space *dest,
struct program_space *src);
/* Save the current program space so that it may be restored by a later
call to do_cleanups. Returns the struct cleanup pointer needed for
later doing the cleanup. */
extern struct cleanup *save_current_program_space (void);
/* Sets PSPACE as the current program space. This is usually used
instead of set_current_space_and_thread when the current
thread/inferior is not important for the operations that follow.
E.g., when accessing the raw symbol tables. If memory access is
required, then you should use switch_to_program_space_and_thread.
Otherwise, it is the caller's responsibility to make sure that the
currently selected inferior/thread matches the selected program
space. */
extern void set_current_program_space (struct program_space *pspace);
/* Saves the current thread (may be null), frame and program space in
the current cleanup chain. */
extern struct cleanup *save_current_space_and_thread (void);
/* Switches full context to program space PSPACE. Switches to the
first thread found bound to PSPACE. */
extern void switch_to_program_space_and_thread (struct program_space *pspace);
/* Create a new address space object, and add it to the list. */
extern struct address_space *new_address_space (void);
/* Maybe create a new address space object, and add it to the list, or
return a pointer to an existing address space, in case inferiors
share an address space. */
extern struct address_space *maybe_new_address_space (void);
/* Update all program spaces matching to address spaces. The user may
have created several program spaces, and loaded executables into
them before connecting to the target interface that will create the
inferiors. All that happens before GDB has a chance to know if the
inferiors will share an address space or not. Call this after
having connected to the target interface and having fetched the
target description, to fixup the program/address spaces
mappings. */
extern void update_address_spaces (void);
/* Prune away automatically added program spaces that aren't required
anymore. */
extern void prune_program_spaces (void);
/* Keep a registry of per-pspace data-pointers required by other GDB
modules. */
extern const struct program_space_data *register_program_space_data (void);
extern const struct program_space_data *register_program_space_data_with_cleanup
(void (*cleanup) (struct program_space *, void *));
extern void clear_program_space_data (struct program_space *pspace);
extern void set_program_space_data (struct program_space *pspace,
const struct program_space_data *data, void *value);
extern void *program_space_data (struct program_space *pspace,
const struct program_space_data *data);
#endif

View File

@ -778,20 +778,22 @@ record_wait (struct target_ops *ops,
if (status->kind == TARGET_WAITKIND_STOPPED
&& status->value.sig == TARGET_SIGNAL_TRAP)
{
struct regcache *regcache;
/* Yes -- check if there is a breakpoint. */
registers_changed ();
tmp_pc = regcache_read_pc (get_current_regcache ());
if (breakpoint_inserted_here_p (tmp_pc))
regcache = get_current_regcache ();
tmp_pc = regcache_read_pc (regcache);
if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
tmp_pc))
{
/* There is a breakpoint. GDB will want to stop. */
CORE_ADDR decr_pc_after_break =
gdbarch_decr_pc_after_break
(get_regcache_arch (get_current_regcache ()));
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR decr_pc_after_break
= gdbarch_decr_pc_after_break (gdbarch);
if (decr_pc_after_break)
{
regcache_write_pc (get_thread_regcache (ret),
tmp_pc + decr_pc_after_break);
}
regcache_write_pc (regcache,
tmp_pc + decr_pc_after_break);
}
else
{
@ -799,11 +801,9 @@ record_wait (struct target_ops *ops,
stepping, therefore gdb will not stop.
Therefore we will not return to gdb.
Record the insn and resume. */
if (!do_record_message (get_current_regcache (),
TARGET_SIGNAL_0))
{
break;
}
if (!do_record_message (regcache, TARGET_SIGNAL_0))
break;
record_beneath_to_resume (record_beneath_to_resume_ops,
ptid, 1,
TARGET_SIGNAL_0);
@ -833,7 +833,8 @@ record_wait (struct target_ops *ops,
if (execution_direction == EXEC_FORWARD)
{
tmp_pc = regcache_read_pc (regcache);
if (breakpoint_inserted_here_p (tmp_pc))
if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
tmp_pc))
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@ -981,7 +982,8 @@ record_wait (struct target_ops *ops,
/* check breakpoint */
tmp_pc = regcache_read_pc (regcache);
if (breakpoint_inserted_here_p (tmp_pc))
if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
tmp_pc))
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,

View File

@ -185,6 +185,11 @@ register_size (struct gdbarch *gdbarch, int regnum)
struct regcache
{
struct regcache_descr *descr;
/* The address space of this register cache (for registers where it
makes sense, like PC or SP). */
struct address_space *aspace;
/* The register buffers. A read-only register cache can hold the
full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) while a read/write
register cache can only hold [0 .. gdbarch_num_regs). */
@ -219,6 +224,7 @@ regcache_xmalloc (struct gdbarch *gdbarch)
= XCALLOC (descr->sizeof_raw_registers, gdb_byte);
regcache->register_valid_p
= XCALLOC (descr->sizeof_raw_register_valid_p, gdb_byte);
regcache->aspace = NULL;
regcache->readonly_p = 1;
regcache->ptid = minus_one_ptid;
return regcache;
@ -254,6 +260,12 @@ get_regcache_arch (const struct regcache *regcache)
return regcache->descr->gdbarch;
}
struct address_space *
get_regcache_aspace (const struct regcache *regcache)
{
return regcache->aspace;
}
/* Return a pointer to register REGNUM's buffer cache. */
static gdb_byte *
@ -340,10 +352,14 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
{
int i;
gdb_byte *buf;
gdb_assert (src != NULL && dst != NULL);
gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
gdb_assert (src != dst);
gdb_assert (src->readonly_p || dst->readonly_p);
dst->aspace = src->aspace;
if (!src->readonly_p)
regcache_save (dst, do_cooked_read, src);
else if (!dst->readonly_p)
@ -362,6 +378,8 @@ regcache_cpy_no_passthrough (struct regcache *dst, struct regcache *src)
move of data into the current regcache. Doing this would be
silly - it would mean that valid_p would be completely invalid. */
gdb_assert (dst->readonly_p);
dst->aspace = src->aspace;
memcpy (dst->registers, src->registers, dst->descr->sizeof_raw_registers);
memcpy (dst->register_valid_p, src->register_valid_p,
dst->descr->sizeof_raw_register_valid_p);
@ -438,6 +456,8 @@ get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
new_regcache = regcache_xmalloc (gdbarch);
new_regcache->readonly_p = 0;
new_regcache->ptid = ptid;
new_regcache->aspace = target_thread_address_space (ptid);
gdb_assert (new_regcache->aspace != NULL);
list = xmalloc (sizeof (struct regcache_list));
list->regcache = new_regcache;

View File

@ -23,6 +23,7 @@
struct regcache;
struct gdbarch;
struct address_space;
extern struct regcache *get_current_regcache (void);
extern struct regcache *get_thread_regcache (ptid_t ptid);
@ -36,6 +37,10 @@ struct regcache *regcache_xmalloc (struct gdbarch *gdbarch);
extern struct gdbarch *get_regcache_arch (const struct regcache *regcache);
/* Return REGCACHE's address space. */
extern struct address_space *get_regcache_aspace (const struct regcache *regcache);
/* Transfer a raw register [0..NUM_REGS) between core-gdb and the
regcache. */

View File

@ -471,7 +471,7 @@ gdbsim_create_inferior (struct target_ops *target, char *exec_file, char *args,
sim_create_inferior (gdbsim_desc, exec_bfd, argv, env);
inferior_ptid = remote_sim_ptid;
add_inferior_silent (ptid_get_pid (inferior_ptid));
inferior_appeared_silent (current_inferior (), ptid_get_pid (inferior_ptid));
add_thread_silent (inferior_ptid);
insert_breakpoints (); /* Needed to get correct instruction in cache */

View File

@ -1183,7 +1183,26 @@ remote_add_inferior (int pid, int attached)
if (attached == -1)
attached = remote_query_attached (pid);
inf = add_inferior (pid);
if (gdbarch_has_global_solist (target_gdbarch))
{
/* If the target shares code across all inferiors, then every
attach adds a new inferior. */
inf = add_inferior (pid);
/* ... and every inferior is bound to the same program space.
However, each inferior may still have its own address
space. */
inf->aspace = maybe_new_address_space ();
inf->pspace = current_program_space;
}
else
{
/* In the traditional debugging scenario, there's a 1-1 match
between program/address spaces. We simply bind the inferior
to the program space's address space. */
inf = current_inferior ();
inferior_appeared (inf, pid);
}
inf->attach_flag = attached;
@ -2639,6 +2658,10 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
this before anything involving memory or registers. */
target_find_description ();
/* Next, now that we know something about the target, update the
address spaces in the program spaces. */
update_address_spaces ();
/* On OSs where the list of libraries is global to all
processes, we fetch them early. */
if (gdbarch_has_global_solist (target_gdbarch))
@ -3486,7 +3509,7 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty)
error (_("Attaching to %s failed"),
target_pid_to_str (pid_to_ptid (pid)));
remote_add_inferior (pid, 1);
set_current_inferior (remote_add_inferior (pid, 1));
inferior_ptid = pid_to_ptid (pid);
@ -6779,11 +6802,14 @@ extended_remote_create_inferior_1 (char *exec_file, char *args,
extended_remote_restart ();
}
/* Clean up from the last time we ran, before we mark the target
running again. This will mark breakpoints uninserted, and
get_offsets may insert breakpoints. */
init_thread_list ();
init_wait_for_inferior ();
if (!have_inferiors ())
{
/* Clean up from the last time we ran, before we mark the target
running again. This will mark breakpoints uninserted, and
get_offsets may insert breakpoints. */
init_thread_list ();
init_wait_for_inferior ();
}
/* Now mark the inferior as running before we do anything else. */
inferior_ptid = magic_null_ptid;

View File

@ -671,6 +671,7 @@ static int
rs6000_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int ii, insn;
CORE_ADDR loc;
@ -697,7 +698,7 @@ rs6000_software_single_step (struct frame_info *frame)
/* ignore invalid breakpoint. */
if (breaks[ii] == -1)
continue;
insert_single_step_breakpoint (gdbarch, breaks[ii]);
insert_single_step_breakpoint (gdbarch, aspace, breaks[ii]);
}
errno = 0; /* FIXME, don't ignore errors! */

View File

@ -1084,6 +1084,7 @@ int
ppc_deal_with_atomic_sequence (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR pc = get_frame_pc (frame);
CORE_ADDR breaks[2] = {-1, -1};
@ -1157,7 +1158,7 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
/* Effectively inserts the breakpoints. */
for (index = 0; index <= last_breakpoint; index++)
insert_single_step_breakpoint (gdbarch, breaks[index]);
insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
return 1;
}

View File

@ -365,10 +365,14 @@ disable_break (void)
static int
enable_break (void)
{
if (symfile_objfile != NULL)
if (symfile_objfile != NULL && has_stack_frames ())
{
struct frame_info *frame = get_current_frame ();
struct address_space *aspace = get_frame_address_space (frame);
base_breakpoint
= deprecated_insert_raw_breakpoint (target_gdbarch,
aspace,
entry_point_address ());
if (base_breakpoint != NULL)

View File

@ -273,12 +273,10 @@ IGNORE_FIRST_LINK_MAP_ENTRY (struct so_list *so)
ptr_type) == 0;
}
/* Per-inferior SVR4 specific data. */
/* Per pspace SVR4 specific data. */
struct svr4_info
{
int pid;
CORE_ADDR debug_base; /* Base of dynamic linker structures */
/* Validity flag for debug_loader_offset. */
@ -292,69 +290,40 @@ struct svr4_info
/* Load map address for the main executable. */
CORE_ADDR main_lm_addr;
CORE_ADDR interp_text_sect_low;
CORE_ADDR interp_text_sect_high;
CORE_ADDR interp_plt_sect_low;
CORE_ADDR interp_plt_sect_high;
};
/* List of known processes using solib-svr4 shared libraries, storing
the required bookkeeping for each. */
typedef struct svr4_info *svr4_info_p;
DEF_VEC_P(svr4_info_p);
VEC(svr4_info_p) *svr4_info = NULL;
/* Get svr4 data for inferior PID (target id). If none is found yet,
add it now. This function always returns a valid object. */
struct svr4_info *
get_svr4_info (int pid)
{
int ix;
struct svr4_info *it;
gdb_assert (pid != 0);
for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix)
{
if (it->pid == pid)
return it;
}
it = XZALLOC (struct svr4_info);
it->pid = pid;
VEC_safe_push (svr4_info_p, svr4_info, it);
return it;
}
/* Get rid of any svr4 related bookkeeping for inferior PID (target
id). */
/* Per-program-space data key. */
static const struct program_space_data *solib_svr4_pspace_data;
static void
remove_svr4_info (int pid)
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
int ix;
struct svr4_info *it;
struct svr4_info *info;
for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix)
{
if (it->pid == pid)
{
VEC_unordered_remove (svr4_info_p, svr4_info, ix);
return;
}
}
info = program_space_data (pspace, solib_svr4_pspace_data);
xfree (info);
}
/* This is an "inferior_exit" observer. Inferior PID (target id) is
being removed from the inferior list, because it exited, was
killed, detached, or we just dropped the connection to the debug
interface --- discard any solib-svr4 related bookkeeping for this
inferior. */
/* Get the current svr4 data. If none is found yet, add it now. This
function always returns a valid object. */
static void
solib_svr4_inferior_exit (int pid)
static struct svr4_info *
get_svr4_info (void)
{
remove_svr4_info (pid);
struct svr4_info *info;
info = program_space_data (current_program_space, solib_svr4_pspace_data);
if (info != NULL)
return info;
info = XZALLOC (struct svr4_info);
set_program_space_data (current_program_space, solib_svr4_pspace_data, info);
return info;
}
/* Local function prototypes */
@ -931,7 +900,7 @@ open_symbol_file_object (void *from_ttyp)
int l_name_size = TYPE_LENGTH (ptr_type);
gdb_byte *l_name_buf = xmalloc (l_name_size);
struct cleanup *cleanups = make_cleanup (xfree, l_name_buf);
struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid));
struct svr4_info *info = get_svr4_info ();
if (symfile_objfile)
if (!query (_("Attempt to reload symbols from process? ")))
@ -982,8 +951,7 @@ open_symbol_file_object (void *from_ttyp)
static struct so_list *
svr4_default_sos (void)
{
struct inferior *inf = current_inferior ();
struct svr4_info *info = get_svr4_info (inf->pid);
struct svr4_info *info = get_svr4_info ();
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
@ -1038,14 +1006,9 @@ svr4_current_sos (void)
struct so_list *head = 0;
struct so_list **link_ptr = &head;
CORE_ADDR ldsomap = 0;
struct inferior *inf;
struct svr4_info *info;
if (ptid_equal (inferior_ptid, null_ptid))
return NULL;
inf = current_inferior ();
info = get_svr4_info (inf->pid);
info = get_svr4_info ();
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
@ -1142,7 +1105,7 @@ CORE_ADDR
svr4_fetch_objfile_link_map (struct objfile *objfile)
{
struct so_list *so;
struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid));
struct svr4_info *info = get_svr4_info ();
/* Cause svr4_current_sos() to be run if it hasn't been already. */
if (info->main_lm_addr == 0)
@ -1182,16 +1145,16 @@ match_main (char *soname)
/* Return 1 if PC lies in the dynamic symbol resolution code of the
SVR4 run time loader. */
static CORE_ADDR interp_text_sect_low;
static CORE_ADDR interp_text_sect_high;
static CORE_ADDR interp_plt_sect_low;
static CORE_ADDR interp_plt_sect_high;
int
svr4_in_dynsym_resolve_code (CORE_ADDR pc)
{
return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
|| (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
struct svr4_info *info = get_svr4_info ();
return ((pc >= info->interp_text_sect_low
&& pc < info->interp_text_sect_high)
|| (pc >= info->interp_plt_sect_low
&& pc < info->interp_plt_sect_high)
|| in_plt_section (pc, NULL));
}
@ -1265,14 +1228,13 @@ enable_break (struct svr4_info *info)
asection *interp_sect;
gdb_byte *interp_name;
CORE_ADDR sym_addr;
struct inferior *inf = current_inferior ();
/* First, remove all the solib event breakpoints. Their addresses
may have changed since the last time we ran the program. */
remove_solib_event_breakpoints ();
interp_text_sect_low = interp_text_sect_high = 0;
interp_plt_sect_low = interp_plt_sect_high = 0;
info->interp_text_sect_low = info->interp_text_sect_high = 0;
info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
/* If we already have a shared library list in the target, and
r_debug contains r_brk, set the breakpoint there - this should
@ -1308,18 +1270,20 @@ enable_break (struct svr4_info *info)
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
interp_text_sect_low =
info->interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_text_sect_high =
interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
info->interp_text_sect_high =
info->interp_text_sect_low
+ bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
interp_plt_sect_low =
info->interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_plt_sect_high =
interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
info->interp_plt_sect_high =
info->interp_plt_sect_low
+ bfd_section_size (tmp_bfd, interp_sect);
}
create_solib_event_breakpoint (target_gdbarch, sym_addr);
@ -1412,18 +1376,20 @@ enable_break (struct svr4_info *info)
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
interp_text_sect_low =
info->interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_text_sect_high =
interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
info->interp_text_sect_high =
info->interp_text_sect_low
+ bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
interp_plt_sect_low =
info->interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_plt_sect_high =
interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
info->interp_plt_sect_high =
info->interp_plt_sect_low
+ bfd_section_size (tmp_bfd, interp_sect);
}
/* Now try to set a breakpoint in the dynamic linker. */
@ -1686,7 +1652,7 @@ svr4_solib_create_inferior_hook (void)
struct thread_info *tp;
struct svr4_info *info;
info = get_svr4_info (PIDGET (inferior_ptid));
info = get_svr4_info ();
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@ -1726,7 +1692,14 @@ svr4_solib_create_inferior_hook (void)
static void
svr4_clear_solib (void)
{
remove_svr4_info (PIDGET (inferior_ptid));
struct svr4_info *info;
info = get_svr4_info ();
info->debug_base = 0;
info->debug_loader_offset_p = 0;
info->debug_loader_offset = 0;
xfree (info->debug_loader_name);
info->debug_loader_name = NULL;
}
static void
@ -1925,6 +1898,8 @@ void
_initialize_svr4_solib (void)
{
solib_svr4_data = gdbarch_data_register_pre_init (solib_svr4_init);
solib_svr4_pspace_data
= register_program_space_data_with_cleanup (svr4_pspace_data_cleanup);
svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
svr4_so_ops.free_so = svr4_free_so;
@ -1937,6 +1912,4 @@ _initialize_svr4_solib (void)
svr4_so_ops.bfd_open = solib_bfd_open;
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
observer_attach_inferior_exit (solib_svr4_inferior_exit);
}

View File

@ -86,9 +86,8 @@ set_solib_ops (struct gdbarch *gdbarch, struct target_so_ops *new_ops)
configuration needs to call set_solib_ops. */
struct target_so_ops *current_target_so_ops;
/* local data declarations */
static struct so_list *so_list_head; /* List of known shared objects */
/* List of known shared objects */
#define so_list_head current_program_space->so_list
/* Local function prototypes */
@ -651,6 +650,7 @@ update_solib_list (int from_tty, struct target_ops *target)
for (i = inferior; i; i = i->next)
{
i->from_tty = from_tty;
i->pspace = current_program_space;
/* Fill in the rest of the `struct so_list' node. */
catch_errors (solib_map_sections, i,
@ -937,11 +937,11 @@ solib_contains_address_p (const struct so_list *const solib,
*/
char *
solib_name_from_address (CORE_ADDR address)
solib_name_from_address (struct program_space *pspace, CORE_ADDR address)
{
struct so_list *so = 0; /* link map state variable */
struct so_list *so = NULL;
for (so = so_list_head; so; so = so->next)
for (so = pspace->so_list; so; so = so->next)
if (solib_contains_address_p (so, address))
return (so->so_name);

View File

@ -25,6 +25,7 @@
struct so_list;
struct target_ops;
struct target_so_ops;
struct program_space;
/* Called when we free all symtabs, to free the shared library information
as well. */
@ -45,7 +46,7 @@ extern void solib_create_inferior_hook (void);
/* If ADDR lies in a shared library, return its name. */
extern char *solib_name_from_address (CORE_ADDR);
extern char *solib_name_from_address (struct program_space *, CORE_ADDR);
/* Return 1 if ADDR lies within SOLIB. */

View File

@ -52,6 +52,9 @@ struct so_list
/* shared object file name, expanded to something GDB can open */
char so_name[SO_NAME_MAX_PATH_SIZE];
/* Program space this shared library belongs to. */
struct program_space *pspace;
/* The following fields of the structure are built from
information gathered from the shared object file itself, and
are set when we actually add it to our symbol tables.

View File

@ -92,6 +92,8 @@ static struct symtab *current_source_symtab;
static int current_source_line;
static struct program_space *current_source_pspace;
/* Default number of lines to print with commands like "list".
This is based on guessing how many long (i.e. more than chars_per_line
characters) lines there will be. To be completely correct, "list"
@ -152,6 +154,7 @@ get_current_source_symtab_and_line (void)
{
struct symtab_and_line cursal = { 0 };
cursal.pspace = current_source_pspace;
cursal.symtab = current_source_symtab;
cursal.line = current_source_line;
cursal.pc = 0;
@ -190,15 +193,17 @@ struct symtab_and_line
set_current_source_symtab_and_line (const struct symtab_and_line *sal)
{
struct symtab_and_line cursal = { 0 };
cursal.pspace = current_source_pspace;
cursal.symtab = current_source_symtab;
cursal.line = current_source_line;
current_source_symtab = sal->symtab;
current_source_line = sal->line;
cursal.pc = 0;
cursal.end = 0;
current_source_pspace = sal->pspace;
current_source_symtab = sal->symtab;
current_source_line = sal->line;
return cursal;
}
@ -232,6 +237,7 @@ select_source_symtab (struct symtab *s)
{
current_source_symtab = s;
current_source_line = 1;
current_source_pspace = SYMTAB_PSPACE (s);
return;
}
@ -245,6 +251,7 @@ select_source_symtab (struct symtab *s)
sals = decode_line_spec (main_name (), 1);
sal = sals.sals[0];
xfree (sals.sals);
current_source_pspace = sal.pspace;
current_source_symtab = sal.symtab;
current_source_line = max (sal.line - (lines_to_list - 1), 1);
if (current_source_symtab)
@ -256,7 +263,7 @@ select_source_symtab (struct symtab *s)
current_source_line = 1;
for (ofp = object_files; ofp != NULL; ofp = ofp->next)
ALL_OBJFILES (ofp)
{
for (s = ofp->symtabs; s; s = s->next)
{
@ -264,15 +271,19 @@ select_source_symtab (struct symtab *s)
int len = strlen (name);
if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
|| strcmp (name, "<<C++-namespaces>>") == 0)))
current_source_symtab = s;
{
current_source_pspace = current_program_space;
current_source_symtab = s;
}
}
}
if (current_source_symtab)
return;
/* How about the partial symbol tables? */
for (ofp = object_files; ofp != NULL; ofp = ofp->next)
ALL_OBJFILES (ofp)
{
for (ps = ofp->psymtabs; ps != NULL; ps = ps->next)
{
@ -293,6 +304,7 @@ select_source_symtab (struct symtab *s)
}
else
{
current_source_pspace = current_program_space;
current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
}
}
@ -317,11 +329,13 @@ show_directories (char *ignore, int from_tty)
void
forget_cached_source_info (void)
{
struct program_space *pspace;
struct symtab *s;
struct objfile *objfile;
struct partial_symtab *pst;
for (objfile = object_files; objfile != NULL; objfile = objfile->next)
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
{
for (s = objfile->symtabs; s != NULL; s = s->next)
{

View File

@ -1312,6 +1312,7 @@ sparc_software_single_step (struct frame_info *frame)
{
struct gdbarch *arch = get_frame_arch (frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR npc, nnpc;
CORE_ADDR pc, orig_npc;
@ -1322,10 +1323,10 @@ sparc_software_single_step (struct frame_info *frame)
/* Analyze the instruction at PC. */
nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
if (npc != 0)
insert_single_step_breakpoint (arch, npc);
insert_single_step_breakpoint (arch, aspace, npc);
if (nnpc != 0)
insert_single_step_breakpoint (arch, nnpc);
insert_single_step_breakpoint (arch, aspace, nnpc);
/* Assert that we have set at least one breakpoint, and that
they're not set at the same spot - unless we're going

View File

@ -1504,6 +1504,7 @@ static int
spu_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR pc, next_pc;
unsigned int insn;
@ -1524,7 +1525,8 @@ spu_software_single_step (struct frame_info *frame)
else
next_pc = (SPUADDR_ADDR (pc) + 4) & (SPU_LS_SIZE - 1);
insert_single_step_breakpoint (gdbarch, SPUADDR (SPUADDR_SPU (pc), next_pc));
insert_single_step_breakpoint (gdbarch,
aspace, SPUADDR (SPUADDR_SPU (pc), next_pc));
if (is_branch (insn, &offset, &reg))
{
@ -1540,7 +1542,7 @@ spu_software_single_step (struct frame_info *frame)
target = target & (SPU_LS_SIZE - 1);
if (target != next_pc)
insert_single_step_breakpoint (gdbarch,
insert_single_step_breakpoint (gdbarch, aspace,
SPUADDR (SPUADDR_SPU (pc), target));
}

View File

@ -648,7 +648,8 @@ print_frame_info (struct frame_info *frame, int print_level,
}
if (print_what != LOCATION)
set_default_breakpoint (1, get_frame_pc (frame), sal.symtab, sal.line);
set_default_breakpoint (1, sal.pspace,
get_frame_pc (frame), sal.symtab, sal.line);
annotate_frame_end ();
@ -825,7 +826,8 @@ print_frame (struct frame_info *frame, int print_level,
#ifdef PC_SOLIB
char *lib = PC_SOLIB (get_frame_pc (frame));
#else
char *lib = solib_name_from_address (get_frame_pc (frame));
char *lib = solib_name_from_address (get_frame_program_space (frame),
get_frame_pc (frame));
#endif
if (lib)
{

View File

@ -2807,7 +2807,7 @@ clear_symtab_users (void)
clear_displays ();
breakpoint_re_set ();
set_default_breakpoint (0, 0, 0, 0);
set_default_breakpoint (0, NULL, 0, 0, 0);
clear_pc_function_cache ();
observer_notify_new_objfile (NULL);

View File

@ -130,10 +130,12 @@ free_symtab (struct symtab *s)
void
print_symbol_bcache_statistics (void)
{
struct program_space *pspace;
struct objfile *objfile;
immediate_quit++;
ALL_OBJFILES (objfile)
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
{
printf_filtered (_("Byte cache statistics for '%s':\n"), objfile->name);
print_bcache_statistics (objfile->psymbol_cache, "partial symbol cache");
@ -145,13 +147,15 @@ print_symbol_bcache_statistics (void)
void
print_objfile_statistics (void)
{
struct program_space *pspace;
struct objfile *objfile;
struct symtab *s;
struct partial_symtab *ps;
int i, linetables, blockvectors;
immediate_quit++;
ALL_OBJFILES (objfile)
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
{
printf_filtered (_("Statistics for '%s':\n"), objfile->name);
if (OBJSTAT (objfile, n_stabs) > 0)
@ -886,6 +890,7 @@ maintenance_print_msymbols (char *args, int from_tty)
struct cleanup *cleanups;
char *filename = DEV_TTY;
char *symname = NULL;
struct program_space *pspace;
struct objfile *objfile;
struct stat sym_st, obj_st;
@ -921,10 +926,11 @@ maintenance_print_msymbols (char *args, int from_tty)
make_cleanup_ui_file_delete (outfile);
immediate_quit++;
ALL_OBJFILES (objfile)
if (symname == NULL
|| (!stat (objfile->name, &obj_st) && sym_st.st_ino == obj_st.st_ino))
dump_msymbols (objfile, outfile);
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
if (symname == NULL
|| (!stat (objfile->name, &obj_st) && sym_st.st_ino == obj_st.st_ino))
dump_msymbols (objfile, outfile);
immediate_quit--;
fprintf_filtered (outfile, "\n\n");
do_cleanups (cleanups);
@ -933,13 +939,15 @@ maintenance_print_msymbols (char *args, int from_tty)
void
maintenance_print_objfiles (char *ignore, int from_tty)
{
struct program_space *pspace;
struct objfile *objfile;
dont_repeat ();
immediate_quit++;
ALL_OBJFILES (objfile)
dump_objfile (objfile);
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
dump_objfile (objfile);
immediate_quit--;
}
@ -948,12 +956,14 @@ maintenance_print_objfiles (char *ignore, int from_tty)
void
maintenance_info_symtabs (char *regexp, int from_tty)
{
struct program_space *pspace;
struct objfile *objfile;
if (regexp)
re_comp (regexp);
ALL_OBJFILES (objfile)
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
{
struct symtab *symtab;
@ -1005,12 +1015,14 @@ maintenance_info_symtabs (char *regexp, int from_tty)
void
maintenance_info_psymtabs (char *regexp, int from_tty)
{
struct program_space *pspace;
struct objfile *objfile;
if (regexp)
re_comp (regexp);
ALL_OBJFILES (objfile)
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct partial_symtab *psymtab;

View File

@ -690,6 +690,7 @@ symbol_search_name (const struct general_symbol_info *gsymbol)
void
init_sal (struct symtab_and_line *sal)
{
sal->pspace = NULL;
sal->symtab = 0;
sal->section = 0;
sal->line = 0;
@ -1994,9 +1995,12 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
struct symtab *best_s = NULL;
struct partial_symtab *ps;
struct objfile *objfile;
struct program_space *pspace;
CORE_ADDR distance = 0;
struct minimal_symbol *msymbol;
pspace = current_program_space;
/* If we know that this is not a text address, return failure. This is
necessary because we loop based on the block's high and low code
addresses, which do not include the data ranges, and because
@ -2152,6 +2156,8 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
init_sal (&val); /* initialize to zeroes */
val.pspace = current_program_space;
/* It's tempting to assume that, if we can't find debugging info for
any function enclosing PC, that we shouldn't search for line
number info, either. However, GAS can emit line number info for
@ -2656,6 +2662,11 @@ find_function_start_sal (struct symbol *sym, int funfirstline)
struct symtab_and_line sal;
struct block *b, *function_block;
struct cleanup *old_chain;
old_chain = save_current_space_and_thread ();
switch_to_program_space_and_thread (objfile->pspace);
pc = BLOCK_START (block);
fixup_symbol_section (sym, objfile);
if (funfirstline)
@ -2707,6 +2718,7 @@ find_function_start_sal (struct symbol *sym, int funfirstline)
}
sal.pc = pc;
sal.pspace = objfile->pspace;
/* Check if we are now inside an inlined function. If we can,
use the call site of the function instead. */
@ -2727,6 +2739,7 @@ find_function_start_sal (struct symbol *sym, int funfirstline)
sal.symtab = SYMBOL_SYMTAB (BLOCK_FUNCTION (function_block));
}
do_cleanups (old_chain);
return sal;
}
@ -4560,6 +4573,7 @@ symtab_observer_executable_changed (void)
initializing it from SYMTAB, LINENO and PC. */
static void
append_expanded_sal (struct symtabs_and_lines *sal,
struct program_space *pspace,
struct symtab *symtab,
int lineno, CORE_ADDR pc)
{
@ -4567,6 +4581,7 @@ append_expanded_sal (struct symtabs_and_lines *sal,
sizeof (sal->sals[0])
* (sal->nelts + 1));
init_sal (sal->sals + sal->nelts);
sal->sals[sal->nelts].pspace = pspace;
sal->sals[sal->nelts].symtab = symtab;
sal->sals[sal->nelts].section = NULL;
sal->sals[sal->nelts].end = 0;
@ -4586,14 +4601,16 @@ append_exact_match_to_sals (char *filename, int lineno,
struct linetable_entry **best_item,
struct symtab **best_symtab)
{
struct program_space *pspace;
struct objfile *objfile;
struct symtab *symtab;
int exact = 0;
int j;
*best_item = 0;
*best_symtab = 0;
ALL_SYMTABS (objfile, symtab)
ALL_PSPACES (pspace)
ALL_PSPACE_SYMTABS (pspace, objfile, symtab)
{
if (strcmp (filename, symtab->filename) == 0)
{
@ -4611,7 +4628,8 @@ append_exact_match_to_sals (char *filename, int lineno,
if (item->line == lineno)
{
exact = 1;
append_expanded_sal (ret, symtab, lineno, item->pc);
append_expanded_sal (ret, objfile->pspace,
symtab, lineno, item->pc);
}
else if (!exact && item->line > lineno
&& (*best_item == NULL
@ -4626,11 +4644,10 @@ append_exact_match_to_sals (char *filename, int lineno,
return exact;
}
/* Compute a set of all sals in
the entire program that correspond to same file
and line as SAL and return those. If there
are several sals that belong to the same block,
only one sal for the block is included in results. */
/* Compute a set of all sals in all program spaces that correspond to
same file and line as SAL and return those. If there are several
sals that belong to the same block, only one sal for the block is
included in results. */
struct symtabs_and_lines
expand_line_sal (struct symtab_and_line sal)
@ -4644,10 +4661,12 @@ expand_line_sal (struct symtab_and_line sal)
int deleted = 0;
struct block **blocks = NULL;
int *filter;
struct cleanup *old_chain;
ret.nelts = 0;
ret.sals = NULL;
/* Only expand sals that represent file.c:line. */
if (sal.symtab == NULL || sal.line == 0 || sal.pc != 0)
{
ret.sals = xmalloc (sizeof (struct symtab_and_line));
@ -4657,11 +4676,14 @@ expand_line_sal (struct symtab_and_line sal)
}
else
{
struct program_space *pspace;
struct linetable_entry *best_item = 0;
struct symtab *best_symtab = 0;
int exact = 0;
char *match_filename;
lineno = sal.line;
match_filename = sal.symtab->filename;
/* We need to find all symtabs for a file which name
is described by sal. We cannot just directly
@ -4674,17 +4696,23 @@ expand_line_sal (struct symtab_and_line sal)
the right name. Then, we iterate over symtabs, knowing
that all symtabs we're interested in are loaded. */
ALL_PSYMTABS (objfile, psymtab)
old_chain = save_current_program_space ();
ALL_PSPACES (pspace)
ALL_PSPACE_PSYMTABS (pspace, objfile, psymtab)
{
if (strcmp (sal.symtab->filename,
psymtab->filename) == 0)
PSYMTAB_TO_SYMTAB (psymtab);
if (strcmp (match_filename, psymtab->filename) == 0)
{
set_current_program_space (pspace);
PSYMTAB_TO_SYMTAB (psymtab);
}
}
do_cleanups (old_chain);
/* Now search the symtab for exact matches and append them. If
none is found, append the best_item and all its exact
matches. */
exact = append_exact_match_to_sals (sal.symtab->filename, lineno,
exact = append_exact_match_to_sals (match_filename, lineno,
&ret, &best_item, &best_symtab);
if (!exact && best_item)
append_exact_match_to_sals (best_symtab->filename, best_item->line,
@ -4700,13 +4728,21 @@ expand_line_sal (struct symtab_and_line sal)
blocks -- for each PC found above we see if there are other PCs
that are in the same block. If yes, the other PCs are filtered out. */
old_chain = save_current_program_space ();
filter = alloca (ret.nelts * sizeof (int));
blocks = alloca (ret.nelts * sizeof (struct block *));
for (i = 0; i < ret.nelts; ++i)
{
struct blockvector *bl;
struct block *b;
set_current_program_space (ret.sals[i].pspace);
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);
}
do_cleanups (old_chain);
for (i = 0; i < ret.nelts; ++i)
if (blocks[i] != NULL)

View File

@ -32,6 +32,7 @@ struct block;
struct blockvector;
struct axs_value;
struct agent_expr;
struct program_space;
/* Some of the structures in this file are space critical.
The space-critical structures are:
@ -823,6 +824,7 @@ struct symtab
#define BLOCKVECTOR(symtab) (symtab)->blockvector
#define LINETABLE(symtab) (symtab)->linetable
#define SYMTAB_PSPACE(symtab) (symtab)->objfile->pspace
/* Each source file that has not been fully read in is represented by
@ -1170,6 +1172,9 @@ extern void msymbols_sort (struct objfile *objfile);
struct symtab_and_line
{
/* The program space of this sal. */
struct program_space *pspace;
struct symtab *symtab;
struct obj_section *section;
/* Line number. Line numbers start at 1 and proceed through symtab->nlines.

View File

@ -1267,7 +1267,10 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
return -1;
}
inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
if (!ptid_equal (inferior_ptid, null_ptid))
inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
else
inf = NULL;
if (inf != NULL
&& (region->attrib.cache
@ -2046,7 +2049,7 @@ target_detach (char *args, int from_tty)
else
/* If we're in breakpoints-always-inserted mode, have to remove
them before detaching. */
remove_breakpoints ();
remove_breakpoints_pid (PIDGET (inferior_ptid));
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
@ -2547,6 +2550,27 @@ target_get_osdata (const char *type)
return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
}
/* Determine the current address space of thread PTID. */
struct address_space *
target_thread_address_space (ptid_t ptid)
{
struct inferior *inf;
/* For now, assume frame chains and inferiors only see one address
space. */
/* Fall-back to the "main" address space of the inferior. */
inf = find_inferior_pid (ptid_get_pid (ptid));
if (inf == NULL || inf->aspace == NULL)
internal_error (__FILE__, __LINE__, "\
Can't determine the current address space of thread %s\n",
target_pid_to_str (ptid));
return inf->aspace;
}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
@ -2658,7 +2682,7 @@ generic_mourn_inferior (void)
if (!ptid_equal (ptid, null_ptid))
{
int pid = ptid_get_pid (ptid);
delete_inferior (pid);
exit_inferior (pid);
}
breakpoint_init_inferior (inf_exited);

View File

@ -110,6 +110,15 @@ enum target_waitkind
TARGET_WAITKIND_EXECD,
/* The program had previously vforked, and now the child is done
with the shared memory region, because it exec'ed or exited.
Note that the event is reported to the vfork parent. This is
only used if GDB did not stay attached to the vfork child,
otherwise, a TARGET_WAITKIND_EXECD or
TARGET_WAITKIND_EXIT|SIGNALLED event associated with the child
has the same effect. */
TARGET_WAITKIND_VFORK_DONE,
/* The program has entered or returned from a system call. On
HP-UX, this is used in the hardware watchpoint implementation.
The syscall's unique integer ID number is in value.syscall_id */
@ -685,6 +694,10 @@ extern void target_store_registers (struct regcache *regcache, int regs);
#define target_prepare_to_store(regcache) \
(*current_target.to_prepare_to_store) (regcache)
/* Determine current address space of thread PTID. */
struct address_space *target_thread_address_space (ptid_t);
/* Returns true if this target can debug multiple processes
simultaneously. */

View File

@ -1,3 +1,25 @@
2009-10-19 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
* gdb.base/foll-vfork.exp: Adjust to spell out "follow-fork".
* gdb.base/foll-exec.exp: Adjust to expect a process id before
"Executing new program".
* gdb.base/foll-fork.exp: Adjust to spell out "follow-fork".
* gdb.base/multi-forks.exp: Ditto. Adjust to the inferior being
left listed after having been killed.
* gdb.base/attach.exp: Adjust to spell out "symbol-file".
* gdb.base/maint.exp: Adjust test.
* Makefile.in (ALL_SUBDIRS): Add gdb.multi.
* gdb.multi/Makefile.in: New.
* gdb.multi/base.exp: New.
* gdb.multi/goodbye.c: New.
* gdb.multi/hangout.c: New.
* gdb.multi/hello.c: New.
* gdb.multi/bkpt-multi-exec.c: New.
* gdb.multi/bkpt-multi-exec.exp: New.
* gdb.multi/crashme.c: New.
2009-10-13 Tristan Gingold <gingold@adacore.com>
* gdb.base/sepdebug.exp: Check debug info are found.

View File

@ -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)

View File

@ -291,7 +291,7 @@ proc do_attach_tests {} {
# Explicitly flush out any knowledge of the previous attachment.
set test "before attach3, flush symbols"
gdb_test_multiple "symbol" "$test" {
gdb_test_multiple "symbol-file" "$test" {
-re "Discard symbol table from.*y or n. $" {
gdb_test "y" "No symbol file now." \
"$test"

View File

@ -152,7 +152,7 @@ proc do_exec_tests {} {
#
send_gdb "next\n"
gdb_expect {
-re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
-re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execlp call"}
-re "$gdb_prompt $" {fail "step through execlp call"}
timeout {fail "(timeout) step through execlp call"}
@ -230,7 +230,7 @@ proc do_exec_tests {} {
setup_xfail hppa2.0w-hp-hpux* CLLbs16760
send_gdb "continue\n"
gdb_expect {
-re ".*Executing new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
-re ".*xecuting new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
{pass "hit catch exec"}
-re "$gdb_prompt $" {fail "hit catch exec"}
timeout {fail "(timeout) hit catch exec"}
@ -299,7 +299,7 @@ proc do_exec_tests {} {
#
send_gdb "next 2\n"
gdb_expect {
-re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
-re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execl call"}
-re "$gdb_prompt $" {fail "step through execl call"}
timeout {fail "(timeout) step through execl call"}
@ -353,7 +353,7 @@ proc do_exec_tests {} {
}
send_gdb "next\n"
gdb_expect {
-re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
-re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execv call"}
-re "$gdb_prompt $" {fail "step through execv call"}
timeout {fail "(timeout) step through execv call"}
@ -394,7 +394,7 @@ proc do_exec_tests {} {
#
send_gdb "continue\n"
gdb_expect {
-re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
-re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "continue through exec"}
-re "$gdb_prompt $" {fail "continue through exec"}
timeout {fail "(timeout) continue through exec"}

View File

@ -64,7 +64,7 @@ proc check_fork_catchpoints {} {
proc default_fork_parent_follow {} {
global gdb_prompt
send_gdb "show follow\n"
send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
{pass "default show parent follow, no catchpoints"}
@ -88,12 +88,12 @@ proc default_fork_parent_follow {} {
proc explicit_fork_parent_follow {} {
global gdb_prompt
send_gdb "set follow parent\n"
send_gdb "set follow-fork parent\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow parent"}
timeout {fail "(timeout) set follow parent"}
-re "$gdb_prompt $" {pass "set follow-fork parent"}
timeout {fail "(timeout) set follow-fork parent"}
}
send_gdb "show follow\n"
send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
{pass "explicit show parent follow, no catchpoints"}
@ -117,12 +117,12 @@ proc explicit_fork_parent_follow {} {
proc explicit_fork_child_follow {} {
global gdb_prompt
send_gdb "set follow child\n"
send_gdb "set follow-fork child\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow child"}
timeout {fail "(timeout) set follow child"}
-re "$gdb_prompt $" {pass "set follow-fork child"}
timeout {fail "(timeout) set follow-fork child"}
}
send_gdb "show follow\n"
send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"child\"..*$gdb_prompt $"\
{pass "explicit show child follow, no catchpoints"}
@ -131,7 +131,7 @@ proc explicit_fork_child_follow {} {
}
send_gdb "next 2\n"
gdb_expect {
-re "Attaching after fork to.*$gdb_prompt $"\
-re "Attaching after.* fork to.*$gdb_prompt $"\
{pass "explicit child follow, no catchpoints"}
-re "$gdb_prompt $" {fail "explicit child follow, no catchpoints"}
timeout {fail "(timeout) explicit child follow, no catchpoints"}
@ -185,24 +185,24 @@ proc catch_fork_child_follow {} {
}
}
send_gdb "set follow child\n"
send_gdb "set follow-fork child\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow child"}
timeout {fail "(timeout) set follow child"}
-re "$gdb_prompt $" {pass "set follow-fork child"}
timeout {fail "(timeout) set follow-fork child"}
}
send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
-re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
{pass "set follow child, tbreak"}
-re "$gdb_prompt $" {fail "set follow child, tbreak"}
timeout {fail "(timeout) set follow child, tbreak"}
{pass "set follow-fork child, tbreak"}
-re "$gdb_prompt $" {fail "set follow-fork child, tbreak"}
timeout {fail "(timeout) set follow-fork child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
-re "Attaching after fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
{pass "set follow child, hit tbreak"}
-re "$gdb_prompt $" {fail "set follow child, hit tbreak"}
timeout {fail "(timeout) set follow child, hit tbreak"}
-re "Attaching after.* fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
{pass "set follow-fork child, hit tbreak"}
-re "$gdb_prompt $" {fail "set follow-fork child, hit tbreak"}
timeout {fail "(timeout) set follow-fork child, hit tbreak"}
}
# The parent has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
@ -215,12 +215,12 @@ proc catch_fork_child_follow {} {
send_gdb "y\n"
gdb_expect {
-re "$gdb_prompt $"\
{pass "set follow child, cleanup"}
timeout {fail "(timeout) set follow child, cleanup"}
{pass "set follow-fork child, cleanup"}
timeout {fail "(timeout) set follow-fork child, cleanup"}
}
}
-re "$gdb_prompt $" {fail "set follow child, cleanup"}
timeout {fail "(timeout) set follow child, cleanup"}
-re "$gdb_prompt $" {fail "set follow-fork child, cleanup"}
timeout {fail "(timeout) set follow-fork child, cleanup"}
}
}
@ -244,7 +244,7 @@ proc catch_fork_unpatch_child {} {
"Breakpoint .*file .*$srcfile, line .*" \
"unpatch child, breakpoint at exit call"
gdb_test "set follow child" "" "unpatch child, set follow child"
gdb_test "set follow-fork child" "" "unpatch child, set follow-fork child"
set test "unpatch child, unpatched parent breakpoints from child"
gdb_test_multiple "continue" $test {
@ -297,24 +297,24 @@ proc tcatch_fork_parent_follow {} {
-re "$gdb_prompt $" {fail "explicit parent follow, tcatch fork"}
timeout {fail "(timeout) explicit parent follow, tcatch fork"}
}
send_gdb "set follow parent\n"
send_gdb "set follow-fork parent\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow parent"}
timeout {fail "(timeout) set follow parent"}
-re "$gdb_prompt $" {pass "set follow-fork parent"}
timeout {fail "(timeout) set follow-fork parent"}
}
send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
-re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
{pass "set follow parent, tbreak"}
-re "$gdb_prompt $" {fail "set follow parent, tbreak"}
timeout {fail "(timeout) set follow child, tbreak"}
{pass "set follow-fork parent, tbreak"}
-re "$gdb_prompt $" {fail "set follow-fork parent, tbreak"}
timeout {fail "(timeout) set follow-fork child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
-re ".*Detaching after fork from.* at .*$bp_after_fork.*$gdb_prompt $"\
{pass "set follow parent, hit tbreak"}
-re "$gdb_prompt $" {fail "set follow parent, hit tbreak"}
timeout {fail "(timeout) set follow parent, hit tbreak"}
{pass "set follow-fork parent, hit tbreak"}
-re "$gdb_prompt $" {fail "set follow-fork parent, hit tbreak"}
timeout {fail "(timeout) set follow-fork parent, hit tbreak"}
}
# The child has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
@ -327,12 +327,12 @@ proc tcatch_fork_parent_follow {} {
send_gdb "y\n"
gdb_expect {
-re "$gdb_prompt $"\
{pass "set follow parent, cleanup"}
timeout {fail "(timeout) set follow parent, cleanup"}
{pass "set follow-fork parent, cleanup"}
timeout {fail "(timeout) set follow-fork parent, cleanup"}
}
}
-re "$gdb_prompt $" {fail "set follow parent, cleanup"}
timeout {fail "(timeout) set follow parent, cleanup"}
-re "$gdb_prompt $" {fail "set follow-fork parent, cleanup"}
timeout {fail "(timeout) set follow-fork parent, cleanup"}
}
}
@ -349,35 +349,35 @@ A fork or vfork creates a new process. follow-fork-mode can be:.*
.*child - the new process is debugged after a fork.*
The unfollowed process will continue to run..*
By default, the debugger will follow the parent process..*$gdb_prompt $"\
{ pass "help set follow" }
{ pass "help set follow-fork" }
-re "$gdb_prompt $" { fail "help set follow" }
timeout { fail "(timeout) help set follow" }
timeout { fail "(timeout) help set follow-fork" }
}
# Verify that we can set follow-fork-mode, using an abbreviation
# for both the flag and its value.
#
send_gdb "set follow ch\n"
send_gdb "show fol\n"
send_gdb "set follow-fork ch\n"
send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"child\".*$gdb_prompt $"\
{pass "set follow, using abbreviations"}
timeout {fail "(timeout) set follow, using abbreviations"}
{pass "set follow-fork, using abbreviations"}
timeout {fail "(timeout) set follow-fork, using abbreviations"}
}
# Verify that we cannot set follow-fork-mode to nonsense.
#
send_gdb "set follow chork\n"
send_gdb "set follow-fork chork\n"
gdb_expect {
-re "Undefined item: \"chork\".*$gdb_prompt $"\
{pass "set follow to nonsense is prohibited"}
-re "$gdb_prompt $" {fail "set follow to nonsense is prohibited"}
timeout {fail "(timeout) set follow to nonsense is prohibited"}
{pass "set follow-fork to nonsense is prohibited"}
-re "$gdb_prompt $" {fail "set follow-fork to nonsense is prohibited"}
timeout {fail "(timeout) set follow-fork to nonsense is prohibited"}
}
send_gdb "set follow parent\n"
send_gdb "set follow-fork parent\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow to nonsense is prohibited (reset parent)"}
timeout {fail "set follow to nonsense is prohibited (reset parent)"}
-re "$gdb_prompt $" {pass "set follow-fork to nonsense is prohibited (reset parent)"}
timeout {fail "set follow-fork to nonsense is prohibited (reset parent)"}
}
# Check that fork catchpoints are supported, as an indicator for whether

View File

@ -93,10 +93,10 @@ proc check_vfork_catchpoints {} {
proc vfork_parent_follow_through_step {} {
global gdb_prompt
send_gdb "set follow parent\n"
send_gdb "set follow-fork parent\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow parent, vfork through step"}
timeout {fail "set follow parent, vfork through step"}
-re "$gdb_prompt $" {pass "set follow-fork parent, vfork through step"}
timeout {fail "set follow-fork parent, vfork through step"}
}
send_gdb "next\n"
gdb_expect {
@ -116,10 +116,10 @@ proc vfork_parent_follow_to_bp {} {
global gdb_prompt
global srcfile
send_gdb "set follow parent\n"
send_gdb "set follow-fork parent\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow parent, vfork to bp"}
timeout {fail "set follow parent, vfork to bp"}
-re "$gdb_prompt $" {pass "set follow-fork parent, vfork to bp"}
timeout {fail "set follow-fork parent, vfork to bp"}
}
send_gdb "break ${srcfile}:18\n"
gdb_expect {
@ -144,14 +144,14 @@ proc vfork_and_exec_child_follow_to_main_bp {} {
global gdb_prompt
global binfile
send_gdb "set follow child\n"
send_gdb "set follow-fork child\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow child, vfork and exec to main bp"}
timeout {fail "set follow child, vfork and exec to main bp"}
-re "$gdb_prompt $" {pass "set follow-fork child, vfork and exec to main bp"}
timeout {fail "set follow-fork child, vfork and exec to main bp"}
}
send_gdb "continue\n"
gdb_expect {
-re "Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
-re "Attaching after.* vfork to.*xecuting new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
{pass "vfork and exec child follow, to main bp"}
-re "$gdb_prompt $" {fail "vfork and exec child follow, to main bp"}
timeout {fail "(timeout) vfork and exec child follow, to main bp" }
@ -193,7 +193,7 @@ proc vfork_and_exec_child_follow_through_step {} {
# This test cannot be performed prior to HP-UX 10.30, because ptrace-based
# debugging of a vforking program basically doesn't allow the child to do
# things like hit a breakpoint between a vfork and exec. This means that
# saying "set follow child; next" at a vfork() call won't work, because
# saying "set follow-fork child; next" at a vfork() call won't work, because
# the implementation of "next" sets a "step resume" breakpoint at the
# return from the vfork(), which the child will hit on its way to exec'ing.
#
@ -202,10 +202,10 @@ proc vfork_and_exec_child_follow_through_step {} {
return 0
}
send_gdb "set follow child\n"
send_gdb "set follow-fork child\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow child, vfork and exec through step"}
timeout {fail "set follow child, vfork and exec through step"}
-re "$gdb_prompt $" {pass "set follow-fork child, vfork and exec through step"}
timeout {fail "set follow-fork child, vfork and exec through step"}
}
send_gdb "next\n"
gdb_expect {
@ -248,10 +248,10 @@ proc tcatch_vfork_then_parent_follow {} {
global gdb_prompt
global srcfile
send_gdb "set follow parent\n"
send_gdb "set follow-fork parent\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow parent, tcatch vfork"}
timeout {fail "set follow parent, tcatch vfork"}
-re "$gdb_prompt $" {pass "set follow-fork parent, tcatch vfork"}
timeout {fail "set follow-fork parent, tcatch vfork"}
}
send_gdb "tcatch vfork\n"
gdb_expect {
@ -294,10 +294,10 @@ proc tcatch_vfork_then_child_follow {} {
global srcfile
global srcfile2
send_gdb "set follow child\n"
send_gdb "set follow-fork child\n"
gdb_expect {
-re "$gdb_prompt $" {pass "set follow child, tcatch vfork"}
timeout {fail "set follow child, tcatch vfork"}
-re "$gdb_prompt $" {pass "set follow-fork child, tcatch vfork"}
timeout {fail "set follow-fork child, tcatch vfork"}
}
send_gdb "tcatch vfork\n"
gdb_expect {

View File

@ -478,9 +478,9 @@ set bp_location6 [gdb_get_line_number "set breakpoint 6 here"]
send_gdb "maint info breakpoints\n"
gdb_expect {
-re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex\[ \t\]+in main at.*break.c:$bp_location6\r\n\[ \t\]+breakpoint already hit 1 time\r\n.*$gdb_prompt $"\
-re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex\[ \t\]+in main at.*break.c:$bp_location6 inf 1\r\n\[ \t\]+breakpoint already hit 1 time\r\n.*$gdb_prompt $"\
{ pass "maint info breakpoints" }
-re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex in main at.*break.c:$bp_location6\r\n\[ \t\]+breakpoint already hit 1 time\r\n-1\[ \t\]+shlib events\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex.*breakpoint already hit.*$gdb_prompt $"\
-re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex in main at.*break.c:$bp_location6 sspace 1\r\n\[ \t\]+breakpoint already hit 1 time\r\n-1\[ \t\]+shlib events\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex.*breakpoint already hit.*$gdb_prompt $"\
{ pass "maint info breakpoints (with shlib events)" }
-re ".*$gdb_prompt $" { fail "maint info breakpoints" }
timeout { fail "(timeout) maint info breakpoints" }

View File

@ -121,7 +121,7 @@ proc continue_to_exit_bp_loc {} {
# The result should be that each of the 4 forks returns zero.
runto_main
gdb_test "set follow child"
gdb_test "set follow-fork child"
continue_to_exit_bp_loc
gdb_test "print pids" "\\$.* = \\{0, 0, 0, 0\\}.*" "follow child, print pids"
@ -130,7 +130,7 @@ gdb_test "print pids" "\\$.* = \\{0, 0, 0, 0\\}.*" "follow child, print pids"
# Result should be that none of the 4 forks returns zero.
runto_main
gdb_test "set follow parent" "" ""
gdb_test "set follow-fork parent" "" ""
continue_to_exit_bp_loc
gdb_test "print pids\[0\]==0 || pids\[1\]==0 || pids\[2\]==0 || pids\[3\]==0" \
@ -198,26 +198,26 @@ gdb_test "detach inferior 5" "Detaching .*" "Detach 5"
#
gdb_test "kill inferior 6" "" "Kill 6"
gdb_test "info inferior 6" "Inferior ID 6 not known." "Did kill 6"
gdb_test "info inferior 6" "<null>.*" "Did kill 6"
gdb_test "kill inferior 7" "" "Kill 7"
gdb_test "info inferior 7" "Inferior ID 7 not known." "Did kill 7"
gdb_test "info inferior 7" "<null>.*" "Did kill 7"
gdb_test "kill inferior 8" "" "Kill 8"
gdb_test "info inferior 8" "Inferior ID 8 not known." "Did kill 8"
gdb_test "info inferior 8" "<null>.*" "Did kill 8"
gdb_test "kill inferior 9" "" "Kill 9"
gdb_test "info inferior 9" "Inferior ID 9 not known." "Did kill 9"
gdb_test "info inferior 9" "<null>.*" "Did kill 9"
gdb_test "kill inferior 10" "" "Kill 10"
gdb_test "info inferior 10" "Inferior ID 10 not known." "Did kill 10"
gdb_test "info inferior 10" "<null>.*" "Did kill 10"
gdb_test "kill inferior 11" "" "Kill 11"
gdb_test "info inferior 11" "Inferior ID 11 not known." "Did kill 11"
gdb_test "info inferior 11" "<null>.*" "Did kill 11"
gdb_test "kill inferior 12" "" "Kill 12"
gdb_test "info inferior 12" "Inferior ID 12 not known." "Did kill 12"
gdb_test "info inferior 12" "<null>.*" "Did kill 12"
gdb_test "kill inferior 13" "" "Kill 13"
gdb_test "info inferior 13" "Inferior ID 13 not known." "Did kill 13"
gdb_test "info inferior 13" "<null>.*" "Did kill 13"
gdb_test "kill inferior 14" "" "Kill 14"
gdb_test "info inferior 14" "Inferior ID 14 not known." "Did kill 14"
gdb_test "info inferior 14" "<null>.*" "Did kill 14"
gdb_test "kill inferior 15" "" "Kill 15"
gdb_test "info inferior 15" "Inferior ID 15 not known." "Did kill 15"
gdb_test "info inferior 15" "<null>.*" "Did kill 15"
gdb_test "kill inferior 16" "" "Kill 16"
gdb_test "info inferior 16" "Inferior ID 16 not known." "Did kill 16"
gdb_test "info inferior 16" "<null>.*" "Did kill 16"
return 0

View File

@ -440,6 +440,24 @@ any_thread_of_process (int pid)
return NULL;
}
struct thread_info *
any_live_thread_of_process (int pid)
{
struct thread_info *tp;
struct thread_info *tp_running = NULL;
for (tp = thread_list; tp; tp = tp->next)
if (ptid_get_pid (tp->ptid) == pid)
{
if (tp->state_ == THREAD_STOPPED)
return tp;
else if (tp->state_ == THREAD_RUNNING)
tp_running = tp;
}
return tp_running;
}
/* Print a list of thread ids currently known, and the total number of
threads. To be used from within catch_errors. */
static int
@ -845,6 +863,19 @@ info_threads_command (char *arg, int from_tty)
void
switch_to_thread (ptid_t ptid)
{
/* Switch the program space as well, if we can infer it from the now
current thread. Otherwise, it's up to the caller to select the
space it wants. */
if (!ptid_equal (ptid, null_ptid))
{
struct inferior *inf;
inf = find_inferior_pid (ptid_get_pid (ptid));
gdb_assert (inf != NULL);
set_current_program_space (inf->pspace);
set_current_inferior (inf);
}
if (ptid_equal (ptid, inferior_ptid))
return;
@ -909,7 +940,7 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
select_frame (get_current_frame ());
/* Warn the user. */
if (!ui_out_is_mi_like_p (uiout))
if (frame_level > 0 && !ui_out_is_mi_like_p (uiout))
{
warning (_("\
Couldn't restore frame #%d in current thread, at reparsed frame #0\n"),
@ -927,6 +958,7 @@ struct current_thread_cleanup
struct frame_id selected_frame_id;
int selected_frame_level;
int was_stopped;
int inf_id;
};
static void
@ -945,7 +977,10 @@ do_restore_current_thread_cleanup (void *arg)
&& find_inferior_pid (ptid_get_pid (tp->ptid)) != NULL)
restore_current_thread (old->inferior_ptid);
else
restore_current_thread (null_ptid);
{
restore_current_thread (null_ptid);
set_current_inferior (find_inferior_id (old->inf_id));
}
/* The running state of the originally selected thread may have
changed, so we have to recheck it here. */
@ -979,6 +1014,7 @@ make_cleanup_restore_current_thread (void)
old = xmalloc (sizeof (struct current_thread_cleanup));
old->inferior_ptid = inferior_ptid;
old->inf_id = current_inferior ()->num;
if (!ptid_equal (inferior_ptid, null_ptid))
{

View File

@ -1187,6 +1187,9 @@ kill_or_detach (struct inferior *inf, void *args)
struct qt_args *qt = args;
struct thread_info *thread;
if (inf->pid == 0)
return 0;
thread = any_thread_of_process (inf->pid);
if (thread != NULL)
{
@ -1214,6 +1217,9 @@ print_inferior_quit_action (struct inferior *inf, void *arg)
{
struct ui_file *stb = arg;
if (inf->pid == 0)
return 0;
if (inf->attach_flag)
fprintf_filtered (stb,
_("\tInferior %d [%s] will be detached.\n"), inf->num,
@ -1721,6 +1727,13 @@ gdb_init (char *argv0)
initialize_targets (); /* Setup target_terminal macros for utils.c */
initialize_utils (); /* Make errors and warnings possible */
initialize_all_files ();
/* This creates the current_program_space. Do this after all the
_initialize_foo routines have had a chance to install their
per-sspace data keys. Also do this before
initialize_current_architecture is called, because it accesses
exec_bfd of the current program space. */
initialize_progspace ();
initialize_inferiors ();
initialize_current_architecture ();
init_cli_cmds();
init_main (); /* But that omits this file! Do it now */

View File

@ -36,6 +36,7 @@
#include "tui/tui-stack.h"
#include "tui/tui-file.h"
#include "tui/tui-disasm.h"
#include "progspace.h"
#include "gdb_curses.h"
@ -259,7 +260,8 @@ tui_set_disassem_content (struct gdbarch *gdbarch, CORE_ADDR pc)
/* See whether there is a breakpoint installed. */
src->has_break = (!src->is_exec_point
&& breakpoint_here_p (pc) != no_breakpoint_here);
&& breakpoint_here_p (current_program_space->aspace, pc)
!= no_breakpoint_here);
xfree (asm_lines[i].addr_string);
xfree (asm_lines[i].insn);

View File

@ -1585,7 +1585,8 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
clear_proceed_status ();
init_wait_for_inferior ();
inf = add_inferior (pid);
inf = current_inferior ();
inferior_appeared (inf, pid);
inf->attach_flag = attaching;
/* Make the new process the current inferior, so terminal handling