binutils-gdb/gdb/linux-tdep.c
Pedro Alves f6ac5f3d63 Convert struct target_ops to C++
I.e., use C++ virtual methods and inheritance instead of tables of
function pointers.

Unfortunately, there's no way to do a smooth transition.  ALL native
targets in the tree must be converted at the same time.  I've tested
all I could with cross compilers and with help from GCC compile farm,
but naturally I haven't been able to test many of the ports.  Still, I
made a best effort to port everything over, and while I expect some
build problems due to typos and such, which should be trivial to fix,
I don't expect any design problems.

* Implementation notes:

- The flattened current_target is gone.  References to current_target
  or current_target.beneath are replaced with references to
  target_stack (the top of the stack) directly.

- To keep "set debug target" working, this adds a new debug_stratum
  layer that sits on top of the stack, prints the debug, and delegates
  to the target beneath.

  In addition, this makes the shortname and longname properties of
  target_ops be virtual methods instead of data fields, and makes the
  debug target defer those to the target beneath.  This is so that
  debug code sprinkled around that does "if (debugtarget) ..."  can
  transparently print the name of the target beneath.

  A patch later in the series actually splits out the
  shortname/longname methods to a separate structure, but I preferred
  to keep that chance separate as it is associated with changing a bit
  the design of how targets are registered and open.

- Since you can't check whether a C++ virtual method is overridden,
  the old method of checking whether a target_ops implements a method
  by comparing the function pointer must be replaced with something
  else.

  Some cases are fixed by adding a parallel "can_do_foo" target_ops
  methods.  E.g.,:

    +  for (t = target_stack; t != NULL; t = t->beneath)
	 {
    -      if (t->to_create_inferior != NULL)
    +      if (t->can_create_inferior ())
	    break;
	 }

  Others are fixed by changing void return type to bool or int return
  type, and have the default implementation return false or -1, to
  indicate lack of support.

- make-target-delegates was adjusted to generate C++ classes and
  methods.

  It needed tweaks to grok "virtual" in front of the target method
  name, and for the fact that methods are no longer function pointers.
  (In particular, the current code parsing the return type was simple
  because it could simply parse up until the '(' in '(*to_foo)'.

  It now generates a couple C++ classes that inherit target_ops:
  dummy_target and debug_target.

  Since we need to generate the class declarations as well, i.e., we
  need to emit methods twice, we now generate the code in two passes.

- The core_target global is renamed to avoid conflict with the
  "core_target" class.

- ctf/tfile targets

  init_tracefile_ops is replaced by a base class that is inherited by
  both ctf and tfile.

- bsd-uthread

  The bsd_uthread_ops_hack hack is gone.  It's not needed because
  nothing was extending a target created by bsd_uthread_target.

- remote/extended-remote targets

  This is a first pass, just enough to C++ify target_ops.

  A later pass will convert more free functions to methods, and make
  remote_state be truly per remote instance, allowing multiple
  simultaneous instances of remote targets.

- inf-child/"native" is converted to an actual base class
  (inf_child_target), that is inherited by all native targets.

- GNU/Linux

  The old weird double-target linux_ops mechanism in linux-nat.c, is
  gone, replaced by adding a few virtual methods to linux-nat.h's
  target_ops, called low_XXX, that the concrete linux-nat
  implementations override.  Sort of like gdbserver's
  linux_target_ops, but simpler, for requiring only one
  target_ops-like hierarchy, which spares implementing the same method
  twice when we need to forward the method to a low implementation.
  The low target simply reimplements the target_ops method directly in
  that case.

  There are a few remaining linux-nat.c hooks that would be better
  converted to low_ methods like above too.  E.g.:

   linux_nat_set_new_thread (t, x86_linux_new_thread);
   linux_nat_set_new_fork (t, x86_linux_new_fork);
   linux_nat_set_forget_process

  That'll be done in a follow up patch.

- We can no longer use functions like x86_use_watchpoints to install
  custom methods on an arbitrary base target.

  The patch replaces instances of such a pattern with template mixins.
  For example memory_breakpoint_target defined in target.h, or
  x86_nat_target in x86-nat.h.

- linux_trad_target, MIPS and Alpha GNU/Linux

  The code in the new linux-nat-trad.h/c files which was split off of
  inf-ptrace.h/c recently, is converted to a C++ base class, and used
  by the MIPS and Alpha GNU/Linux ports.

- BSD targets

  The

    $architecture x NetBSD/OpenBSD/FreeBSD

  support matrix complicates things a bit.  There's common BSD target
  code, and there's common architecture-specific code shared between
  the different BSDs.  Currently, all that is stiched together to form
  a final target, via the i386bsd_target, x86bsd_target,
  fbsd_nat_add_target functions etc.

  This introduces new fbsd_nat_target, obsd_nat_target and
  nbsd_nat_target classes that serve as base/prototype target for the
  corresponding BSD variant.

  And introduces generic i386/AMD64 BSD targets, to be used as
  template mixin to build a final target.  Similarly, a generic SPARC
  target is added, used by both BSD and Linux ports.

- bsd_kvm_add_target, BSD libkvm target

  I considered making bsd_kvm_supply_pcb a virtual method, and then
  have each port inherit bsd_kvm_target and override that method, but
  that was resulting in lots of unjustified churn, so I left the
  function pointer mechanism alone.

gdb/ChangeLog:
2018-05-02  Pedro Alves  <palves@redhat.com>
	    John Baldwin  <jhb@freebsd.org>

	* target.h (enum strata) <debug_stratum>: New.
	(struct target_ops) <all delegation methods>: Replace by C++
	virtual methods, and drop "to_" prefix.  All references updated
	throughout.
	<to_shortname, to_longname, to_doc, to_data,
	to_have_steppable_watchpoint, to_have_continuable_watchpoint,
	to_has_thread_control, to_attach_no_wait>: Delete, replaced by
	virtual methods.  All references updated throughout.
	<can_attach, supports_terminal_ours, can_create_inferior,
	get_thread_control_capabilities, attach_no_wait>: New
	virtual methods.
	<insert_breakpoint, remove_breakpoint>: Now
	TARGET_DEFAULT_NORETURN methods.
	<info_proc>: Now returns bool.
	<to_magic>: Delete.
	(OPS_MAGIC): Delete.
	(current_target): Delete.  All references replaced by references
	to ...
	(target_stack): ... this.  New.
	(target_shortname, target_longname): Adjust.
	(target_can_run): Now a function declaration.
	(default_child_has_all_memory, default_child_has_memory)
	(default_child_has_stack, default_child_has_registers)
	(default_child_has_execution): Remove target_ops parameter.
	(complete_target_initialization): Delete.
	(memory_breakpoint_target): New template class.
	(test_target_ops): Refactor as a C++ class with virtual methods.
	* make-target-delegates (NAME_PART): Tighten.
	(POINTER_PART, CP_SYMBOL): New.
	(SIMPLE_RETURN_PART): Reimplement.
	(VEC_RETURN_PART): Expect less.
	(RETURN_PART, VIRTUAL_PART): New.
	(METHOD): Adjust to C++ virtual methods.
	(scan_target_h): Remove reference to C99.
	(dname): Output "target_ops::" prefix.
	(write_function_header): Adjust to output a C++ class method.
	(write_declaration): New.
	(write_delegator): Adjust to output a C++ class method.
	(tdname): Output "dummy_target::" prefix.
	(write_tdefault, write_debugmethod): Adjust to output a C++ class
	method.
	(tdefault_names, debug_names): Delete.
	(return_types, tdefaults, styles, argtypes_array): New.
	(top level): All methods are delegators.
	(print_class): New.
	(top level): Print dummy_target and debug_target classes.
	* target-delegates.c: Regenerate.
	* target-debug.h (target_debug_print_enum_info_proc_what)
	(target_debug_print_thread_control_capabilities)
	(target_debug_print_thread_info_p): New.
	* target.c (dummy_target): Delete.
	(the_dummy_target, the_debug_target): New.
	(target_stack): Now extern.
	(set_targetdebug): Push/unpush debug target.
	(default_child_has_all_memory, default_child_has_memory)
	(default_child_has_stack, default_child_has_registers)
	(default_child_has_execution): Remove target_ops parameter.
	(complete_target_initialization): Delete.
	(add_target_with_completer): No longer call
	complete_target_initialization.
	(target_supports_terminal_ours): Use regular delegation.
	(update_current_target): Delete.
	(push_target): No longer check magic number.  Don't call
	update_current_target.
	(unpush_target): Don't call update_current_target.
	(target_is_pushed): No longer check magic number.
	(target_require_runnable): Skip for all stratums over
	process_stratum.
	(target_ops::info_proc): New.
	(target_info_proc): Use find_target_at and
	find_default_run_target.
	(target_supports_disable_randomization): Use regular delegation.
	(target_get_osdata): Use find_target_at.
	(target_ops::open, target_ops::close, target_ops::can_attach)
	(target_ops::attach, target_ops::can_create_inferior)
	(target_ops::create_inferior, target_ops::can_run)
	(target_can_run): New.
	(default_fileio_target): Use regular delegation.
	(target_ops::fileio_open, target_ops::fileio_pwrite)
	(target_ops::fileio_pread, target_ops::fileio_fstat)
	(target_ops::fileio_close, target_ops::fileio_unlink)
	(target_ops::fileio_readlink): New.
	(target_fileio_open_1, target_fileio_unlink)
	(target_fileio_readlink): Always call the target method.  Handle
	FILEIO_ENOSYS.
	(return_zero, return_zero_has_execution): Delete.
	(init_dummy_target): Delete.
	(dummy_target::dummy_target, dummy_target::shortname)
	(dummy_target::longname, dummy_target::doc)
	(debug_target::debug_target, debug_target::shortname)
	(debug_target::longname, debug_target::doc): New.
	(target_supports_delete_record): Use regular delegation.
	(setup_target_debug): Delete.
	(maintenance_print_target_stack): Skip debug_stratum.
	(initialize_targets): Instantiate the_dummy_target and
	the_debug_target.
	* auxv.c (target_auxv_parse): Remove 'ops' parameter.  Adjust to
	use target_stack.
	(target_auxv_search, fprint_target_auxv): Adjust.
	(info_auxv_command): Adjust to use target_stack.
	* auxv.h (target_auxv_parse): Remove 'ops' parameter.
	* exceptions.c (print_flush): Handle a NULL target_stack.
	* regcache.c (target_ops_no_register): Refactor as class with
	virtual methods.

	* exec.c (exec_target): New class.
	(exec_ops): Now an exec_target.
	(exec_open, exec_close_1, exec_get_section_table)
	(exec_xfer_partial, exec_files_info, exec_has_memory)
	(exec_make_note_section): Refactor as exec_target methods.
	(exec_file_clear, ignore, exec_remove_breakpoint, init_exec_ops):
	Delete.
	(exec_target::find_memory_regions): New.
	(_initialize_exec): Don't call init_exec_ops.
	* gdbcore.h (exec_file_clear): Delete.

	* corefile.c (core_target): Delete.
	(core_file_command): Adjust.
	* corelow.c (core_target): New class.
	(the_core_target): New.
	(core_close): Remove target_ops parameter.
	(core_close_cleanup): Adjust.
	(core_target::close): New.
	(core_open, core_detach, get_core_registers, core_files_info)
	(core_xfer_partial, core_thread_alive, core_read_description)
	(core_pid_to_str, core_thread_name, core_has_memory)
	(core_has_stack, core_has_registers, core_info_proc): Rework as
	core_target methods.
	(ignore, core_remove_breakpoint, init_core_ops): Delete.
	(_initialize_corelow): Initialize the_core_target.
	* gdbcore.h (core_target): Delete.
	(the_core_target): New.

	* ctf.c: (ctf_target): New class.
	(ctf_ops): Now a ctf_target.
	(ctf_open, ctf_close, ctf_files_info, ctf_fetch_registers)
	(ctf_xfer_partial, ctf_get_trace_state_variable_value)
	(ctf_trace_find, ctf_traceframe_info): Refactor as ctf_target
	methods.
	(init_ctf_ops): Delete.
	(_initialize_ctf): Don't call it.
	* tracefile-tfile.c (tfile_target): New class.
	(tfile_ops): Now a tfile_target.
	(tfile_open, tfile_close, tfile_files_info)
	(tfile_get_tracepoint_status, tfile_trace_find)
	(tfile_fetch_registers, tfile_xfer_partial)
	(tfile_get_trace_state_variable_value, tfile_traceframe_info):
	Refactor as tfile_target methods.
	(tfile_xfer_partial_features): Remove target_ops parameter.
	(init_tfile_ops): Delete.
	(_initialize_tracefile_tfile): Don't call it.
	* tracefile.c (tracefile_has_all_memory, tracefile_has_memory)
	(tracefile_has_stack, tracefile_has_registers)
	(tracefile_thread_alive, tracefile_get_trace_status): Refactor as
	tracefile_target methods.
	(init_tracefile_ops): Delete.
	(tracefile_target::tracefile_target): New.
	* tracefile.h: Include "target.h".
	(tracefile_target): New class.
	(init_tracefile_ops): Delete.

	* spu-multiarch.c (spu_multiarch_target): New class.
	(spu_ops): Now a spu_multiarch_target.
	(spu_thread_architecture, spu_region_ok_for_hw_watchpoint)
	(spu_fetch_registers, spu_store_registers, spu_xfer_partial)
	(spu_search_memory, spu_mourn_inferior): Refactor as
	spu_multiarch_target methods.
	(init_spu_ops): Delete.
	(_initialize_spu_multiarch): Remove references to init_spu_ops,
	complete_target_initialization.

	* ravenscar-thread.c (ravenscar_thread_target): New class.
	(ravenscar_ops): Now a ravenscar_thread_target.
	(ravenscar_resume, ravenscar_wait, ravenscar_update_thread_list)
	(ravenscar_thread_alive, ravenscar_pid_to_str)
	(ravenscar_fetch_registers, ravenscar_store_registers)
	(ravenscar_prepare_to_store, ravenscar_stopped_by_sw_breakpoint)
	(ravenscar_stopped_by_hw_breakpoint)
	(ravenscar_stopped_by_watchpoint, ravenscar_stopped_data_address)
	(ravenscar_mourn_inferior, ravenscar_core_of_thread)
	(ravenscar_get_ada_task_ptid): Refactor as ravenscar_thread_target
	methods.
	(init_ravenscar_thread_ops): Delete.
	(_initialize_ravenscar): Remove references to
	init_ravenscar_thread_ops and complete_target_initialization.

	* bsd-uthread.c (bsd_uthread_ops_hack): Delete.
	(bsd_uthread_target): New class.
	(bsd_uthread_ops): Now a bsd_uthread_target.
	(bsd_uthread_activate): Adjust to refer to bsd_uthread_ops.
	(bsd_uthread_close, bsd_uthread_mourn_inferior)
	(bsd_uthread_fetch_registers, bsd_uthread_store_registers)
	(bsd_uthread_wait, bsd_uthread_resume, bsd_uthread_thread_alive)
	(bsd_uthread_update_thread_list, bsd_uthread_extra_thread_info)
	(bsd_uthread_pid_to_str): Refactor as bsd_uthread_target methods.
	(bsd_uthread_target): Delete function.
	(_initialize_bsd_uthread): Remove reference to
	complete_target_initialization.

	* bfd-target.c (target_bfd_data): Delete.  Fields folded into ...
	(target_bfd): ... this new class.
	(target_bfd_xfer_partial, target_bfd_get_section_table)
	(target_bfd_close): Refactor as target_bfd methods.
	(target_bfd::~target_bfd): New.
	(target_bfd_reopen): Adjust.
	(target_bfd::close): New.

	* record-btrace.c (record_btrace_target): New class.
	(record_btrace_ops): Now a record_btrace_target.
	(record_btrace_open, record_btrace_stop_recording)
	(record_btrace_disconnect, record_btrace_close)
	(record_btrace_async, record_btrace_info)
	(record_btrace_insn_history, record_btrace_insn_history_range)
	(record_btrace_insn_history_from, record_btrace_call_history)
	(record_btrace_call_history_range)
	(record_btrace_call_history_from, record_btrace_record_method)
	(record_btrace_is_replaying, record_btrace_will_replay)
	(record_btrace_xfer_partial, record_btrace_insert_breakpoint)
	(record_btrace_remove_breakpoint, record_btrace_fetch_registers)
	(record_btrace_store_registers, record_btrace_prepare_to_store)
	(record_btrace_to_get_unwinder)
	(record_btrace_to_get_tailcall_unwinder, record_btrace_resume)
	(record_btrace_commit_resume, record_btrace_wait)
	(record_btrace_stop, record_btrace_can_execute_reverse)
	(record_btrace_stopped_by_sw_breakpoint)
	(record_btrace_supports_stopped_by_sw_breakpoint)
	(record_btrace_stopped_by_hw_breakpoint)
	(record_btrace_supports_stopped_by_hw_breakpoint)
	(record_btrace_update_thread_list, record_btrace_thread_alive)
	(record_btrace_goto_begin, record_btrace_goto_end)
	(record_btrace_goto, record_btrace_stop_replaying_all)
	(record_btrace_execution_direction)
	(record_btrace_prepare_to_generate_core)
	(record_btrace_done_generating_core): Refactor as
	record_btrace_target methods.
	(init_record_btrace_ops): Delete.
	(_initialize_record_btrace): Remove reference to
	init_record_btrace_ops.
	* record-full.c (RECORD_FULL_IS_REPLAY): Adjust to always refer to
	the execution_direction global.
	(record_full_base_target, record_full_target)
	(record_full_core_target): New classes.
	(record_full_ops): Now a record_full_target.
	(record_full_core_ops): Now a record_full_core_target.
	(record_full_target::detach, record_full_target::disconnect)
	(record_full_core_target::disconnect)
	(record_full_target::mourn_inferior, record_full_target::kill):
	New.
	(record_full_open, record_full_close, record_full_async): Refactor
	as methods of the record_full_base_target class.
	(record_full_resume, record_full_commit_resume): Refactor
	as methods of the record_full_target class.
	(record_full_wait, record_full_stopped_by_watchpoint)
	(record_full_stopped_data_address)
	(record_full_stopped_by_sw_breakpoint)
	(record_full_supports_stopped_by_sw_breakpoint)
	(record_full_stopped_by_hw_breakpoint)
	(record_full_supports_stopped_by_hw_breakpoint): Refactor as
	methods of the record_full_base_target class.
	(record_full_store_registers, record_full_xfer_partial)
	(record_full_insert_breakpoint, record_full_remove_breakpoint):
	Refactor as methods of the record_full_target class.
	(record_full_can_execute_reverse, record_full_get_bookmark)
	(record_full_goto_bookmark, record_full_execution_direction)
	(record_full_record_method, record_full_info, record_full_delete)
	(record_full_is_replaying, record_full_will_replay)
	(record_full_goto_begin, record_full_goto_end, record_full_goto)
	(record_full_stop_replaying): Refactor as methods of the
	record_full_base_target class.
	(record_full_core_resume, record_full_core_kill)
	(record_full_core_fetch_registers)
	(record_full_core_prepare_to_store)
	(record_full_core_store_registers, record_full_core_xfer_partial)
	(record_full_core_insert_breakpoint)
	(record_full_core_remove_breakpoint)
	(record_full_core_has_execution): Refactor
	as methods of the record_full_core_target class.
	(record_full_base_target::supports_delete_record): New.
	(init_record_full_ops): Delete.
	(init_record_full_core_ops): Delete.
	(record_full_save): Refactor as method of the
	record_full_base_target class.
	(_initialize_record_full): Remove references to
	init_record_full_ops and init_record_full_core_ops.

	* remote.c (remote_target, extended_remote_target): New classes.
	(remote_ops): Now a remote_target.
	(extended_remote_ops): Now an extended_remote_target.
	(remote_insert_fork_catchpoint, remote_remove_fork_catchpoint)
	(remote_insert_vfork_catchpoint, remote_remove_vfork_catchpoint)
	(remote_insert_exec_catchpoint, remote_remove_exec_catchpoint)
	(remote_pass_signals, remote_set_syscall_catchpoint)
	(remote_program_signals, )
	(remote_thread_always_alive): Remove target_ops parameter.
	(remote_thread_alive, remote_thread_name)
	(remote_update_thread_list, remote_threads_extra_info)
	(remote_static_tracepoint_marker_at)
	(remote_static_tracepoint_markers_by_strid)
	(remote_get_ada_task_ptid, remote_close, remote_start_remote)
	(remote_open): Refactor as methods of remote_target.
	(extended_remote_open, extended_remote_detach)
	(extended_remote_attach, extended_remote_post_attach):
	(extended_remote_supports_disable_randomization)
	(extended_remote_create_inferior): : Refactor as method of
	extended_remote_target.
	(remote_set_permissions, remote_open_1, remote_detach)
	(remote_follow_fork, remote_follow_exec, remote_disconnect)
	(remote_resume, remote_commit_resume, remote_stop)
	(remote_interrupt, remote_pass_ctrlc, remote_terminal_inferior)
	(remote_terminal_ours, remote_wait, remote_fetch_registers)
	(remote_prepare_to_store, remote_store_registers)
	(remote_flash_erase, remote_flash_done, remote_files_info)
	(remote_kill, remote_mourn, remote_insert_breakpoint)
	(remote_remove_breakpoint, remote_insert_watchpoint)
	(remote_watchpoint_addr_within_range)
	(remote_remove_watchpoint, remote_region_ok_for_hw_watchpoint)
	(remote_check_watch_resources, remote_stopped_by_sw_breakpoint)
	(remote_supports_stopped_by_sw_breakpoint)
	(remote_stopped_by_hw_breakpoint)
	(remote_supports_stopped_by_hw_breakpoint)
	(remote_stopped_by_watchpoint, remote_stopped_data_address)
	(remote_insert_hw_breakpoint, remote_remove_hw_breakpoint)
	(remote_verify_memory): Refactor as methods of remote_target.
	(remote_write_qxfer, remote_read_qxfer): Remove target_ops
	parameter.
	(remote_xfer_partial, remote_get_memory_xfer_limit)
	(remote_search_memory, remote_rcmd, remote_memory_map)
	(remote_pid_to_str, remote_get_thread_local_address)
	(remote_get_tib_address, remote_read_description): Refactor as
	methods of remote_target.
	(remote_target::fileio_open, remote_target::fileio_pwrite)
	(remote_target::fileio_pread, remote_target::fileio_close): New.
	(remote_hostio_readlink, remote_hostio_fstat)
	(remote_filesystem_is_local, remote_can_execute_reverse)
	(remote_supports_non_stop, remote_supports_disable_randomization)
	(remote_supports_multi_process, remote_supports_cond_breakpoints)
	(remote_supports_enable_disable_tracepoint)
	(remote_supports_string_tracing)
	(remote_can_run_breakpoint_commands, remote_trace_init)
	(remote_download_tracepoint, remote_can_download_tracepoint)
	(remote_download_trace_state_variable, remote_enable_tracepoint)
	(remote_disable_tracepoint, remote_trace_set_readonly_regions)
	(remote_trace_start, remote_get_trace_status)
	(remote_get_tracepoint_status, remote_trace_stop)
	(remote_trace_find, remote_get_trace_state_variable_value)
	(remote_save_trace_data, remote_get_raw_trace_data)
	(remote_set_disconnected_tracing, remote_core_of_thread)
	(remote_set_circular_trace_buffer, remote_traceframe_info)
	(remote_get_min_fast_tracepoint_insn_len)
	(remote_set_trace_buffer_size, remote_set_trace_notes)
	(remote_use_agent, remote_can_use_agent, remote_enable_btrace)
	(remote_disable_btrace, remote_teardown_btrace)
	(remote_read_btrace, remote_btrace_conf)
	(remote_augmented_libraries_svr4_read, remote_load)
	(remote_pid_to_exec_file, remote_can_do_single_step)
	(remote_execution_direction, remote_thread_handle_to_thread_info):
	Refactor as methods of remote_target.
	(init_remote_ops, init_extended_remote_ops): Delete.
	(remote_can_async_p, remote_is_async_p, remote_async)
	(remote_thread_events, remote_upload_tracepoints)
	(remote_upload_trace_state_variables): Refactor as methods of
	remote_target.
	(_initialize_remote): Remove references to init_remote_ops and
	init_extended_remote_ops.

	* remote-sim.c (gdbsim_target): New class.
	(gdbsim_fetch_register, gdbsim_store_register, gdbsim_kill)
	(gdbsim_load, gdbsim_create_inferior, gdbsim_open, gdbsim_close)
	(gdbsim_detach, gdbsim_resume, gdbsim_interrupt)
	(gdbsim_wait, gdbsim_prepare_to_store, gdbsim_xfer_partial)
	(gdbsim_files_info, gdbsim_mourn_inferior, gdbsim_thread_alive)
	(gdbsim_pid_to_str, gdbsim_has_all_memory, gdbsim_has_memory):
	Refactor as methods of gdbsim_target.
	(gdbsim_ops): Now a gdbsim_target.
	(init_gdbsim_ops): Delete.
	(gdbsim_cntrl_c): Adjust.
	(_initialize_remote_sim): Remove reference to init_gdbsim_ops.

	* amd64-linux-nat.c (amd64_linux_nat_target): New class.
	(the_amd64_linux_nat_target): New.
	(amd64_linux_fetch_inferior_registers)
	(amd64_linux_store_inferior_registers): Refactor as methods of
	amd64_linux_nat_target.
	(_initialize_amd64_linux_nat): Adjust.  Set linux_target.
	* i386-linux-nat.c: Don't include "linux-nat.h".
	(i386_linux_nat_target): New class.
	(the_i386_linux_nat_target): New.
	(i386_linux_fetch_inferior_registers)
	(i386_linux_store_inferior_registers, i386_linux_resume): Refactor
	as methods of i386_linux_nat_target.
	(_initialize_i386_linux_nat): Adjust.  Set linux_target.
	* inf-child.c (inf_child_ops): Delete.
	(inf_child_fetch_inferior_registers)
	(inf_child_store_inferior_registers): Delete.
	(inf_child_post_attach, inf_child_prepare_to_store): Refactor as
	methods of inf_child_target.
	(inf_child_target::supports_terminal_ours)
	(inf_child_target::terminal_init)
	(inf_child_target::terminal_inferior)
	(inf_child_target::terminal_ours_for_output)
	(inf_child_target::terminal_ours, inf_child_target::interrupt)
	(inf_child_target::pass_ctrlc, inf_child_target::terminal_info):
	New.
	(inf_child_open, inf_child_disconnect, inf_child_close)
	(inf_child_mourn_inferior, inf_child_maybe_unpush_target)
	(inf_child_post_startup_inferior, inf_child_can_run)
	(inf_child_pid_to_exec_file): Refactor as methods of
	inf_child_target.
	(inf_child_follow_fork): Delete.
	(inf_child_target::can_create_inferior)
	(inf_child_target::can_attach): New.
	(inf_child_target::has_all_memory, inf_child_target::has_memory)
	(inf_child_target::has_stack, inf_child_target::has_registers)
	(inf_child_target::has_execution): New.
	(inf_child_fileio_open, inf_child_fileio_pwrite)
	(inf_child_fileio_pread, inf_child_fileio_fstat)
	(inf_child_fileio_close, inf_child_fileio_unlink)
	(inf_child_fileio_readlink, inf_child_use_agent)
	(inf_child_can_use_agent): Refactor as methods of
	inf_child_target.
	(return_zero, inf_child_target): Delete.
	(inf_child_target::inf_child_target): New.
	* inf-child.h: Include "target.h".
	(inf_child_target): Delete function prototype.
	(inf_child_target): New class.
	(inf_child_open_target, inf_child_mourn_inferior)
	(inf_child_maybe_unpush_target): Delete.
	* inf-ptrace.c (inf_ptrace_target::~inf_ptrace_target): New.
	(inf_ptrace_follow_fork, inf_ptrace_insert_fork_catchpoint)
	(inf_ptrace_remove_fork_catchpoint, inf_ptrace_create_inferior)
	(inf_ptrace_post_startup_inferior, inf_ptrace_mourn_inferior)
	(inf_ptrace_attach, inf_ptrace_post_attach, inf_ptrace_detach)
	(inf_ptrace_detach_success, inf_ptrace_kill, inf_ptrace_resume)
	(inf_ptrace_wait, inf_ptrace_xfer_partial)
	(inf_ptrace_thread_alive, inf_ptrace_files_info)
	(inf_ptrace_pid_to_str, inf_ptrace_auxv_parse): Refactor as
	methods of inf_ptrace_target.
	(inf_ptrace_target): Delete function.
	* inf-ptrace.h: Include "inf-child.h".
	(inf_ptrace_target): Delete function declaration.
	(inf_ptrace_target): New class.
	(inf_ptrace_trad_target, inf_ptrace_detach_success): Delete.
	* linux-nat.c (linux_target): New.
	(linux_ops, linux_ops_saved, super_xfer_partial): Delete.
	(linux_nat_target::~linux_nat_target): New.
	(linux_child_post_attach, linux_child_post_startup_inferior)
	(linux_child_follow_fork, linux_child_insert_fork_catchpoint)
	(linux_child_remove_fork_catchpoint)
	(linux_child_insert_vfork_catchpoint)
	(linux_child_remove_vfork_catchpoint)
	(linux_child_insert_exec_catchpoint)
	(linux_child_remove_exec_catchpoint)
	(linux_child_set_syscall_catchpoint, linux_nat_pass_signals)
	(linux_nat_create_inferior, linux_nat_attach, linux_nat_detach)
	(linux_nat_resume, linux_nat_stopped_by_watchpoint)
	(linux_nat_stopped_data_address)
	(linux_nat_stopped_by_sw_breakpoint)
	(linux_nat_supports_stopped_by_sw_breakpoint)
	(linux_nat_stopped_by_hw_breakpoint)
	(linux_nat_supports_stopped_by_hw_breakpoint, linux_nat_wait)
	(linux_nat_kill, linux_nat_mourn_inferior)
	(linux_nat_xfer_partial, linux_nat_thread_alive)
	(linux_nat_update_thread_list, linux_nat_pid_to_str)
	(linux_nat_thread_name, linux_child_pid_to_exec_file)
	(linux_child_static_tracepoint_markers_by_strid)
	(linux_nat_is_async_p, linux_nat_can_async_p)
	(linux_nat_supports_non_stop, linux_nat_always_non_stop_p)
	(linux_nat_supports_multi_process)
	(linux_nat_supports_disable_randomization, linux_nat_async)
	(linux_nat_stop, linux_nat_close, linux_nat_thread_address_space)
	(linux_nat_core_of_thread, linux_nat_filesystem_is_local)
	(linux_nat_fileio_open, linux_nat_fileio_readlink)
	(linux_nat_fileio_unlink, linux_nat_thread_events): Refactor as
	methods of linux_nat_target.
	(linux_nat_wait_1, linux_xfer_siginfo, linux_proc_xfer_partial)
	(linux_proc_xfer_spu, linux_nat_xfer_osdata): Remove target_ops
	parameter.
	(check_stopped_by_watchpoint): Adjust.
	(linux_xfer_partial): Delete.
	(linux_target_install_ops, linux_target, linux_nat_add_target):
	Delete.
	(linux_nat_target::linux_nat_target): New.
	* linux-nat.h: Include "inf-ptrace.h".
	(linux_nat_target): New.
	(linux_target, linux_target_install_ops, linux_nat_add_target):
	Delete function declarations.
	(linux_target): Declare global.
	* linux-thread-db.c (thread_db_target): New.
	(thread_db_target::thread_db_target): New.
	(thread_db_ops): Delete.
	(the_thread_db_target): New.
	(thread_db_detach, thread_db_wait, thread_db_mourn_inferior)
	(thread_db_update_thread_list, thread_db_pid_to_str)
	(thread_db_extra_thread_info)
	(thread_db_thread_handle_to_thread_info)
	(thread_db_get_thread_local_address, thread_db_get_ada_task_ptid)
	(thread_db_resume): Refactor as methods of thread_db_target.
	(init_thread_db_ops): Delete.
	(_initialize_thread_db): Remove reference to init_thread_db_ops.
	* x86-linux-nat.c: Don't include "linux-nat.h".
	(super_post_startup_inferior): Delete.
	(x86_linux_nat_target::~x86_linux_nat_target): New.
	(x86_linux_child_post_startup_inferior)
	(x86_linux_read_description, x86_linux_enable_btrace)
	(x86_linux_disable_btrace, x86_linux_teardown_btrace)
	(x86_linux_read_btrace, x86_linux_btrace_conf): Refactor as
	methods of x86_linux_nat_target.
	(x86_linux_create_target): Delete.  Bits folded ...
	(x86_linux_add_target): ... here.  Now takes a linux_nat_target
	pointer.
	* x86-linux-nat.h: Include "linux-nat.h" and "x86-nat.h".
	(x86_linux_nat_target): New class.
	(x86_linux_create_target): Delete.
	(x86_linux_add_target): Now takes a linux_nat_target pointer.
	* x86-nat.c (x86_insert_watchpoint, x86_remove_watchpoint)
	(x86_region_ok_for_watchpoint, x86_stopped_data_address)
	(x86_stopped_by_watchpoint, x86_insert_hw_breakpoint)
	(x86_remove_hw_breakpoint, x86_can_use_hw_breakpoint)
	(x86_stopped_by_hw_breakpoint): Remove target_ops parameter and
	make extern.
	(x86_use_watchpoints): Delete.
	* x86-nat.h: Include "breakpoint.h" and "target.h".
	(x86_use_watchpoints): Delete.
	(x86_can_use_hw_breakpoint, x86_region_ok_for_hw_watchpoint)
	(x86_stopped_by_watchpoint, x86_stopped_data_address)
	(x86_insert_watchpoint, x86_remove_watchpoint)
	(x86_insert_hw_breakpoint, x86_remove_hw_breakpoint)
	(x86_stopped_by_hw_breakpoint): New declarations.
	(x86_nat_target): New template class.

	* ppc-linux-nat.c (ppc_linux_nat_target): New class.
	(the_ppc_linux_nat_target): New.
	(ppc_linux_fetch_inferior_registers)
	(ppc_linux_can_use_hw_breakpoint)
	(ppc_linux_region_ok_for_hw_watchpoint)
	(ppc_linux_ranged_break_num_registers)
	(ppc_linux_insert_hw_breakpoint, ppc_linux_remove_hw_breakpoint)
	(ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_can_accel_watchpoint_condition)
	(ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint)
	(ppc_linux_stopped_data_address, ppc_linux_stopped_by_watchpoint)
	(ppc_linux_watchpoint_addr_within_range)
	(ppc_linux_masked_watch_num_registers)
	(ppc_linux_store_inferior_registers, ppc_linux_auxv_parse)
	(ppc_linux_read_description): Refactor as methods of
	ppc_linux_nat_target.
	(_initialize_ppc_linux_nat): Adjust.  Set linux_target.

	* procfs.c (procfs_xfer_partial): Delete forward declaration.
	(procfs_target): New class.
	(the_procfs_target): New.
	(procfs_target): Delete function.
	(procfs_auxv_parse, procfs_attach, procfs_detach)
	(procfs_fetch_registers, procfs_store_registers, procfs_wait)
	(procfs_xfer_partial, procfs_resume, procfs_pass_signals)
	(procfs_files_info, procfs_kill_inferior, procfs_mourn_inferior)
	(procfs_create_inferior, procfs_update_thread_list)
	(procfs_thread_alive, procfs_pid_to_str)
	(procfs_can_use_hw_breakpoint, procfs_stopped_by_watchpoint)
	(procfs_stopped_data_address, procfs_insert_watchpoint)
	(procfs_remove_watchpoint, procfs_region_ok_for_hw_watchpoint)
	(proc_find_memory_regions, procfs_info_proc)
	(procfs_make_note_section): Refactor as methods of procfs_target.
	(_initialize_procfs): Adjust.
	* sol-thread.c (sol_thread_target): New class.
	(sol_thread_ops): Now a sol_thread_target.
	(sol_thread_detach, sol_thread_resume, sol_thread_wait)
	(sol_thread_fetch_registers, sol_thread_store_registers)
	(sol_thread_xfer_partial, sol_thread_mourn_inferior)
	(sol_thread_alive, solaris_pid_to_str, sol_update_thread_list)
	(sol_get_ada_task_ptid): Refactor as methods of sol_thread_target.
	(init_sol_thread_ops): Delete.
	(_initialize_sol_thread): Adjust.  Remove references to
	init_sol_thread_ops and complete_target_initialization.

	* windows-nat.c (windows_nat_target): New class.
	(windows_fetch_inferior_registers)
	(windows_store_inferior_registers, windows_resume, windows_wait)
	(windows_attach, windows_detach, windows_pid_to_exec_file)
	(windows_files_info, windows_create_inferior)
	(windows_mourn_inferior, windows_interrupt, windows_kill_inferior)
	(windows_close, windows_pid_to_str, windows_xfer_partial)
	(windows_get_tib_address, windows_get_ada_task_ptid)
	(windows_thread_name, windows_thread_alive): Refactor as
	windows_nat_target methods.
	(do_initial_windows_stuff): Adjust.
	(windows_target): Delete function.
	(_initialize_windows_nat): Adjust.

	* darwin-nat.c (darwin_resume, darwin_wait_to, darwin_interrupt)
	(darwin_mourn_inferior, darwin_kill_inferior)
	(darwin_create_inferior, darwin_attach, darwin_detach)
	(darwin_pid_to_str, darwin_thread_alive, darwin_xfer_partial)
	(darwin_pid_to_exec_file, darwin_get_ada_task_ptid)
	(darwin_supports_multi_process): Refactor as darwin_nat_target
	methods.
	(darwin_resume_to, darwin_files_info): Delete.
	(_initialize_darwin_inferior): Rename to ...
	(_initialize_darwin_nat): ... this.  Adjust to C++ification.
	* darwin-nat.h: Include "inf-child.h".
	(darwin_nat_target): New class.
	(darwin_complete_target): Delete.
	* i386-darwin-nat.c (i386_darwin_nat_target): New class.
	(darwin_target): New.
	(i386_darwin_fetch_inferior_registers)
	(i386_darwin_store_inferior_registers): Refactor as methods of
	darwin_nat_target.
	(darwin_complete_target): Delete, with ...
	(_initialize_i386_darwin_nat): ... bits factored out here.

	* alpha-linux-nat.c (alpha_linux_nat_target): New class.
	(the_alpha_linux_nat_target): New.
	(alpha_linux_register_u_offset): Refactor as
	alpha_linux_nat_target method.
	(_initialize_alpha_linux_nat): Adjust.
	* linux-nat-trad.c (inf_ptrace_register_u_offset): Delete.
	(inf_ptrace_fetch_register, inf_ptrace_fetch_registers)
	(inf_ptrace_store_register, inf_ptrace_store_registers): Refact as
	methods of linux_nat_trad_target.
	(linux_trad_target): Delete.
	* linux-nat-trad.h (linux_trad_target): Delete function.
	(linux_nat_trad_target): New class.
	* mips-linux-nat.c (mips_linux_nat_target): New class.
	(super_fetch_registers, super_store_registers, super_close):
	Delete.
	(the_mips_linux_nat_target): New.
	(mips64_linux_regsets_fetch_registers)
	(mips64_linux_regsets_store_registers)
	(mips64_linux_fetch_registers, mips64_linux_store_registers)
	(mips_linux_register_u_offset, mips_linux_read_description)
	(mips_linux_can_use_hw_breakpoint)
	(mips_linux_stopped_by_watchpoint)
	(mips_linux_stopped_data_address)
	(mips_linux_region_ok_for_hw_watchpoint)
	(mips_linux_insert_watchpoint, mips_linux_remove_watchpoint)
	(mips_linux_close): Refactor as methods of mips_linux_nat.
	(_initialize_mips_linux_nat): Adjust to C++ification.

	* aix-thread.c (aix_thread_target): New class.
	(aix_thread_ops): Now an aix_thread_target.
	(aix_thread_detach, aix_thread_resume, aix_thread_wait)
	(aix_thread_fetch_registers, aix_thread_store_registers)
	(aix_thread_xfer_partial, aix_thread_mourn_inferior)
	(aix_thread_thread_alive, aix_thread_pid_to_str)
	(aix_thread_extra_thread_info, aix_thread_get_ada_task_ptid):
	Refactor as methods of aix_thread_target.
	(init_aix_thread_ops): Delete.
	(_initialize_aix_thread): Remove references to init_aix_thread_ops
	and complete_target_initialization.
	* rs6000-nat.c (rs6000_xfer_shared_libraries): Delete.
	(rs6000_nat_target): New class.
	(the_rs6000_nat_target): New.
	(rs6000_fetch_inferior_registers, rs6000_store_inferior_registers)
	(rs6000_xfer_partial, rs6000_wait, rs6000_create_inferior)
	(rs6000_xfer_shared_libraries): Refactor as rs6000_nat_target methods.
	(super_create_inferior): Delete.
	(_initialize_rs6000_nat): Adjust to C++ification.

	* arm-linux-nat.c (arm_linux_nat_target): New class.
	(the_arm_linux_nat_target): New.
	(arm_linux_fetch_inferior_registers)
	(arm_linux_store_inferior_registers, arm_linux_read_description)
	(arm_linux_can_use_hw_breakpoint, arm_linux_insert_hw_breakpoint)
	(arm_linux_remove_hw_breakpoint)
	(arm_linux_region_ok_for_hw_watchpoint)
	(arm_linux_insert_watchpoint, arm_linux_remove_watchpoint)
	(arm_linux_stopped_data_address, arm_linux_stopped_by_watchpoint)
	(arm_linux_watchpoint_addr_within_range): Refactor as methods of
	arm_linux_nat_target.
	(_initialize_arm_linux_nat): Adjust to C++ification.

	* aarch64-linux-nat.c (aarch64_linux_nat_target): New class.
	(the_aarch64_linux_nat_target): New.
	(aarch64_linux_fetch_inferior_registers)
	(aarch64_linux_store_inferior_registers)
	(aarch64_linux_child_post_startup_inferior)
	(aarch64_linux_read_description)
	(aarch64_linux_can_use_hw_breakpoint)
	(aarch64_linux_insert_hw_breakpoint)
	(aarch64_linux_remove_hw_breakpoint)
	(aarch64_linux_insert_watchpoint, aarch64_linux_remove_watchpoint)
	(aarch64_linux_region_ok_for_hw_watchpoint)
	(aarch64_linux_stopped_data_address)
	(aarch64_linux_stopped_by_watchpoint)
	(aarch64_linux_watchpoint_addr_within_range)
	(aarch64_linux_can_do_single_step): Refactor as methods of
	aarch64_linux_nat_target.
	(super_post_startup_inferior): Delete.
	(_initialize_aarch64_linux_nat): Adjust to C++ification.

	* hppa-linux-nat.c (hppa_linux_nat_target): New class.
	(the_hppa_linux_nat_target): New.
	(hppa_linux_fetch_inferior_registers)
	(hppa_linux_store_inferior_registers): Refactor as methods of
	hppa_linux_nat_target.
	(_initialize_hppa_linux_nat): Adjust to C++ification.

	* ia64-linux-nat.c (ia64_linux_nat_target): New class.
	(the_ia64_linux_nat_target): New.
	(ia64_linux_insert_watchpoint, ia64_linux_remove_watchpoint)
	(ia64_linux_stopped_data_address)
	(ia64_linux_stopped_by_watchpoint, ia64_linux_fetch_registers)
	(ia64_linux_store_registers, ia64_linux_xfer_partial): Refactor as
	ia64_linux_nat_target methods.
	(super_xfer_partial): Delete.
	(_initialize_ia64_linux_nat): Adjust to C++ification.

	* m32r-linux-nat.c (m32r_linux_nat_target): New class.
	(the_m32r_linux_nat_target): New.
	(m32r_linux_fetch_inferior_registers)
	(m32r_linux_store_inferior_registers): Refactor as
	m32r_linux_nat_target methods.
	(_initialize_m32r_linux_nat): Adjust to C++ification.

	* m68k-linux-nat.c (m68k_linux_nat_target): New class.
	(the_m68k_linux_nat_target): New.
	(m68k_linux_fetch_inferior_registers)
	(m68k_linux_store_inferior_registers): Refactor as
	m68k_linux_nat_target methods.
	(_initialize_m68k_linux_nat): Adjust to C++ification.

	* s390-linux-nat.c (s390_linux_nat_target): New class.
	(the_s390_linux_nat_target): New.
	(s390_linux_fetch_inferior_registers)
	(s390_linux_store_inferior_registers, s390_stopped_by_watchpoint)
	(s390_insert_watchpoint, s390_remove_watchpoint)
	(s390_can_use_hw_breakpoint, s390_insert_hw_breakpoint)
	(s390_remove_hw_breakpoint, s390_region_ok_for_hw_watchpoint)
	(s390_auxv_parse, s390_read_description): Refactor as methods of
	s390_linux_nat_target.
	(_initialize_s390_nat): Adjust to C++ification.

	* sparc-linux-nat.c (sparc_linux_nat_target): New class.
	(the_sparc_linux_nat_target): New.
	(_initialize_sparc_linux_nat): Adjust to C++ification.
	* sparc-nat.c (sparc_fetch_inferior_registers)
	(sparc_store_inferior_registers): Remove target_ops parameter.
	* sparc-nat.h (sparc_fetch_inferior_registers)
	(sparc_store_inferior_registers): Remove target_ops parameter.
	* sparc64-linux-nat.c (sparc64_linux_nat_target): New class.
	(the_sparc64_linux_nat_target): New.
	(_initialize_sparc64_linux_nat): Adjust to C++ification.

	* spu-linux-nat.c (spu_linux_nat_target): New class.
	(the_spu_linux_nat_target): New.
	(spu_child_post_startup_inferior, spu_child_post_attach)
	(spu_child_wait, spu_fetch_inferior_registers)
	(spu_store_inferior_registers, spu_xfer_partial)
	(spu_can_use_hw_breakpoint): Refactor as spu_linux_nat_target
	methods.
	(_initialize_spu_nat): Adjust to C++ification.

	* tilegx-linux-nat.c (tilegx_linux_nat_target): New class.
	(the_tilegx_linux_nat_target): New.
	(fetch_inferior_registers, store_inferior_registers):
	Refactor as methods.
	(_initialize_tile_linux_nat): Adjust to C++ification.

	* xtensa-linux-nat.c (xtensa_linux_nat_target): New class.
	(the_xtensa_linux_nat_target): New.
	(xtensa_linux_fetch_inferior_registers)
	(xtensa_linux_store_inferior_registers): Refactor as
	xtensa_linux_nat_target methods.
	(_initialize_xtensa_linux_nat): Adjust to C++ification.

	* fbsd-nat.c (USE_SIGTRAP_SIGINFO): Delete.
	(fbsd_pid_to_exec_file, fbsd_find_memory_regions)
	(fbsd_find_memory_regions, fbsd_info_proc, fbsd_xfer_partial)
	(fbsd_thread_alive, fbsd_pid_to_str, fbsd_thread_name)
	(fbsd_update_thread_list, fbsd_resume, fbsd_wait)
	(fbsd_stopped_by_sw_breakpoint)
	(fbsd_supports_stopped_by_sw_breakpoint, fbsd_follow_fork)
	(fbsd_insert_fork_catchpoint, fbsd_remove_fork_catchpoint)
	(fbsd_insert_vfork_catchpoint, fbsd_remove_vfork_catchpoint)
	(fbsd_post_startup_inferior, fbsd_post_attach)
	(fbsd_insert_exec_catchpoint, fbsd_remove_exec_catchpoint)
	(fbsd_set_syscall_catchpoint)
	(super_xfer_partial, super_resume, super_wait)
	(fbsd_supports_stopped_by_hw_breakpoint): Delete.
	(fbsd_handle_debug_trap): Remove target_ops parameter.
	(fbsd_nat_add_target): Delete.
	* fbsd-nat.h: Include "inf-ptrace.h".
	(fbsd_nat_add_target): Delete.
	(USE_SIGTRAP_SIGINFO): Define.
	(fbsd_nat_target): New class.

	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers)
	(amd64bsd_store_inferior_registers): Remove target_ops parameter.
	(amd64bsd_target): Delete.
	* amd64-bsd-nat.h: New file.
	* amd64-fbsd-nat.c: Include "amd64-bsd-nat.h" instead of
	"x86-bsd-nat.h".
	(amd64_fbsd_nat_target): New class.
	(the_amd64_fbsd_nat_target): New.
	(amd64fbsd_read_description): Refactor as method of
	amd64_fbsd_nat_target.
	(amd64_fbsd_nat_target::supports_stopped_by_hw_breakpoint): New.
	(_initialize_amd64fbsd_nat): Adjust to C++ification.
	* amd64-nat.h (amd64bsd_target): Delete function declaration.
	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers)
	(i386bsd_store_inferior_registers): Remove target_ops parameter.
	(i386bsd_target): Delete.
	* i386-bsd-nat.h (i386bsd_target): Delete function declaration.
	(i386bsd_fetch_inferior_registers)
	(i386bsd_store_inferior_registers): Declare.
	(i386_bsd_nat_target): New class.
	* i386-fbsd-nat.c (i386_fbsd_nat_target): New class.
	(the_i386_fbsd_nat_target): New.
	(i386fbsd_resume, i386fbsd_read_description): Refactor as
	i386_fbsd_nat_target methods.
	(i386_fbsd_nat_target::supports_stopped_by_hw_breakpoint): New.
	(_initialize_i386fbsd_nat): Adjust to C++ification.
	* x86-bsd-nat.c (super_mourn_inferior): Delete.
	(x86bsd_mourn_inferior, x86bsd_target): Delete.
	(_initialize_x86_bsd_nat): Adjust to C++ification.
	* x86-bsd-nat.h: Include "x86-nat.h".
	(x86bsd_target): Delete declaration.
	(x86bsd_nat_target): New class.

	* aarch64-fbsd-nat.c (aarch64_fbsd_nat_target): New class.
	(the_aarch64_fbsd_nat_target): New.
	(aarch64_fbsd_fetch_inferior_registers)
	(aarch64_fbsd_store_inferior_registers): Refactor as methods of
	aarch64_fbsd_nat_target.
	(_initialize_aarch64_fbsd_nat): Adjust to C++ification.
	* alpha-bsd-nat.c (alpha_bsd_nat_target): New class.
	(the_alpha_bsd_nat_target): New.
	(alphabsd_fetch_inferior_registers)
	(alphabsd_store_inferior_registers): Refactor as
	alpha_bsd_nat_target methods.
	(_initialize_alphabsd_nat): Refactor as methods of
	alpha_bsd_nat_target.
	* amd64-nbsd-nat.c: Include "amd64-bsd-nat.h".
	(the_amd64_nbsd_nat_target): New.
	(_initialize_amd64nbsd_nat): Adjust to C++ification.
	* amd64-obsd-nat.c: Include "amd64-bsd-nat.h".
	(the_amd64_obsd_nat_target): New.
	(_initialize_amd64obsd_nat): Adjust to C++ification.
	* arm-fbsd-nat.c (arm_fbsd_nat_target): New.
	(the_arm_fbsd_nat_target): New.
	(arm_fbsd_fetch_inferior_registers)
	(arm_fbsd_store_inferior_registers, arm_fbsd_read_description):
	(_initialize_arm_fbsd_nat): Refactor as methods of
	arm_fbsd_nat_target.
	(_initialize_arm_fbsd_nat): Adjust to C++ification.
	* arm-nbsd-nat.c (arm_netbsd_nat_target): New class.
	(the_arm_netbsd_nat_target): New.
	(armnbsd_fetch_registers, armnbsd_store_registers): Refactor as
	arm_netbsd_nat_target.
	(_initialize_arm_netbsd_nat): Adjust to C++ification.
	* hppa-nbsd-nat.c (hppa_nbsd_nat_target): New class.
	(the_hppa_nbsd_nat_target): New.
	(hppanbsd_fetch_registers, hppanbsd_store_registers): Refactor as
	hppa_nbsd_nat_target methods.
	(_initialize_hppanbsd_nat): Adjust to C++ification.
	* hppa-obsd-nat.c (hppa_obsd_nat_target): New class.
	(the_hppa_obsd_nat_target): New.
	(hppaobsd_fetch_registers, hppaobsd_store_registers): Refactor as
	methods of hppa_obsd_nat_target.
	(_initialize_hppaobsd_nat): Adjust to C++ification.  Use
	add_target.
	* i386-nbsd-nat.c (the_i386_nbsd_nat_target): New.
	(_initialize_i386nbsd_nat): Adjust to C++ification.  Use
	add_target.
	* i386-obsd-nat.c (the_i386_obsd_nat_target): New.
	(_initialize_i386obsd_nat): Use add_target.
	* m68k-bsd-nat.c (m68k_bsd_nat_target): New class.
	(the_m68k_bsd_nat_target): New.
	(m68kbsd_fetch_inferior_registers)
	(m68kbsd_store_inferior_registers): Refactor as methods of
	m68k_bsd_nat_target.
	(_initialize_m68kbsd_nat): Adjust to C++ification.
	* mips-fbsd-nat.c (mips_fbsd_nat_target): New class.
	(the_mips_fbsd_nat_target): New.
	(mips_fbsd_fetch_inferior_registers)
	(mips_fbsd_store_inferior_registers): Refactor as methods of
	mips_fbsd_nat_target.
	(_initialize_mips_fbsd_nat): Adjust to C++ification.  Use
	add_target.
	* mips-nbsd-nat.c (mips_nbsd_nat_target): New class.
	(the_mips_nbsd_nat_target): New.
	(mipsnbsd_fetch_inferior_registers)
	(mipsnbsd_store_inferior_registers): Refactor as methods of
	mips_nbsd_nat_target.
	(_initialize_mipsnbsd_nat): Adjust to C++ification.
	* mips64-obsd-nat.c (mips64_obsd_nat_target): New class.
	(the_mips64_obsd_nat_target): New.
	(mips64obsd_fetch_inferior_registers)
	(mips64obsd_store_inferior_registers): Refactor as methods of
	mips64_obsd_nat_target.
	(_initialize_mips64obsd_nat): Adjust to C++ification.  Use
	add_target.
	* nbsd-nat.c (nbsd_pid_to_exec_file): Refactor as method of
	nbsd_nat_target.
	* nbsd-nat.h: Include "inf-ptrace.h".
	(nbsd_nat_target): New class.
	* obsd-nat.c (obsd_pid_to_str, obsd_update_thread_list)
	(obsd_wait): Refactor as methods of obsd_nat_target.
	(obsd_add_target): Delete.
	* obsd-nat.h: Include "inf-ptrace.h".
	(obsd_nat_target): New class.
	* ppc-fbsd-nat.c (ppc_fbsd_nat_target): New class.
	(the_ppc_fbsd_nat_target): New.
	(ppcfbsd_fetch_inferior_registers)
	(ppcfbsd_store_inferior_registers): Refactor as methods of
	ppc_fbsd_nat_target.
	(_initialize_ppcfbsd_nat): Adjust to C++ification.  Use
	add_target.
	* ppc-nbsd-nat.c (ppc_nbsd_nat_target): New class.
	(the_ppc_nbsd_nat_target): New.
	(ppcnbsd_fetch_inferior_registers)
	(ppcnbsd_store_inferior_registers): Refactor as methods of
	ppc_nbsd_nat_target.
	(_initialize_ppcnbsd_nat): Adjust to C++ification.
	* ppc-obsd-nat.c (ppc_obsd_nat_target): New class.
	(the_ppc_obsd_nat_target): New.
	(ppcobsd_fetch_registers, ppcobsd_store_registers): Refactor as
	methods of ppc_obsd_nat_target.
	(_initialize_ppcobsd_nat): Adjust to C++ification.  Use
	add_target.
	* sh-nbsd-nat.c (sh_nbsd_nat_target): New class.
	(the_sh_nbsd_nat_target): New.
	(shnbsd_fetch_inferior_registers)
	(shnbsd_store_inferior_registers): Refactor as methods of
	sh_nbsd_nat_target.
	(_initialize_shnbsd_nat): Adjust to C++ification.
	* sparc-nat.c (sparc_xfer_wcookie): Make extern.
	(inf_ptrace_xfer_partial): Delete.
	(sparc_xfer_partial, sparc_target): Delete.
	* sparc-nat.h (sparc_fetch_inferior_registers)
	(sparc_store_inferior_registers, sparc_xfer_wcookie): Declare.
	(sparc_target): Delete function declaration.
	(sparc_target): New template class.
	* sparc-nbsd-nat.c (the_sparc_nbsd_nat_target): New.
	(_initialize_sparcnbsd_nat): Adjust to C++ification.
	* sparc64-fbsd-nat.c (the_sparc64_fbsd_nat_target): New.
	(_initialize_sparc64fbsd_nat): Adjust to C++ification.  Use
	add_target.
	* sparc64-nbsd-nat.c (the_sparc64_nbsd_nat_target): New.
	(_initialize_sparc64nbsd_nat): Adjust to C++ification.
	* sparc64-obsd-nat.c (the_sparc64_obsd_nat_target): New.
	(_initialize_sparc64obsd_nat): Adjust to C++ification.  Use
	add_target.
	* vax-bsd-nat.c (vax_bsd_nat_target): New class.
	(the_vax_bsd_nat_target): New.
	(vaxbsd_fetch_inferior_registers)
	(vaxbsd_store_inferior_registers): Refactor as vax_bsd_nat_target
	methods.
	(_initialize_vaxbsd_nat): Adjust to C++ification.

	* bsd-kvm.c (bsd_kvm_target): New class.
	(bsd_kvm_ops): Now a bsd_kvm_target.
	(bsd_kvm_open, bsd_kvm_close, bsd_kvm_xfer_partial)
	(bsd_kvm_files_info, bsd_kvm_fetch_registers)
	(bsd_kvm_thread_alive, bsd_kvm_pid_to_str): Refactor as methods of
	bsd_kvm_target.
	(bsd_kvm_return_one): Delete.
	(bsd_kvm_add_target): Adjust to C++ification.

	* nto-procfs.c (nto_procfs_target, nto_procfs_target_native)
	(nto_procfs_target_procfs): New classes.
	(procfs_open_1, procfs_thread_alive, procfs_update_thread_list)
	(procfs_files_info, procfs_pid_to_exec_file, procfs_attach)
	(procfs_post_attach, procfs_wait, procfs_fetch_registers)
	(procfs_xfer_partial, procfs_detach, procfs_insert_breakpoint)
	(procfs_remove_breakpoint, procfs_insert_hw_breakpoint)
	(procfs_remove_hw_breakpoint, procfs_resume)
	(procfs_mourn_inferior, procfs_create_inferior, procfs_interrupt)
	(procfs_kill_inferior, procfs_store_registers)
	(procfs_pass_signals, procfs_pid_to_str, procfs_can_run): Refactor
	as methods of nto_procfs_target.
	(nto_procfs_ops): Now an nto_procfs_target_procfs.
	(nto_native_ops): Delete.
	(procfs_open, procfs_native_open): Delete.
	(nto_native_ops): Now an nto_procfs_target_native.
	(init_procfs_targets): Adjust to C++ification.
	(procfs_can_use_hw_breakpoint, procfs_remove_hw_watchpoint)
	(procfs_insert_hw_watchpoint, procfs_stopped_by_watchpoint):
	Refactor as methods of nto_procfs_target.

	* go32-nat.c (go32_nat_target): New class.
	(the_go32_nat_target): New.
	(go32_attach, go32_resume, go32_wait, go32_fetch_registers)
	(go32_store_registers, go32_xfer_partial, go32_files_info)
	(go32_kill_inferior, go32_create_inferior, go32_mourn_inferior)
	(go32_terminal_init, go32_terminal_info, go32_terminal_inferior)
	(go32_terminal_ours, go32_pass_ctrlc, go32_thread_alive)
	(go32_pid_to_str): Refactor as methods of go32_nat_target.
	(go32_target): Delete.
	(_initialize_go32_nat): Adjust to C++ification.

	* gnu-nat.c (gnu_wait, gnu_resume, gnu_kill_inferior)
	(gnu_mourn_inferior, gnu_create_inferior, gnu_attach, gnu_detach)
	(gnu_stop, gnu_thread_alive, gnu_xfer_partial)
	(gnu_find_memory_regions, gnu_pid_to_str): Refactor as methods of
	gnu_nat_target.
	(gnu_target): Delete.
	* gnu-nat.h (gnu_target): Delete.
	(gnu_nat_target): New class.
	* i386-gnu-nat.c (gnu_base_target): New.
	(i386_gnu_nat_target): New class.
	(the_i386_gnu_nat_target): New.
	(_initialize_i386gnu_nat): Adjust to C++ification.

gdb/testsuite/ChangeLog:
2018-05-02  Pedro Alves  <palves@redhat.com>

	* gdb.base/breakpoint-in-ro-region.exp: Adjust to to_resume and
	to_log_command renames.
	* gdb.base/sss-bp-on-user-bp-2.exp: Likewise.
2018-05-03 00:48:36 +01:00

2547 lines
75 KiB
C

/* Target-dependent code for GNU/Linux, architecture independent.
Copyright (C) 2009-2018 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 "gdbtypes.h"
#include "linux-tdep.h"
#include "auxv.h"
#include "target.h"
#include "gdbthread.h"
#include "gdbcore.h"
#include "regcache.h"
#include "regset.h"
#include "elf/common.h"
#include "elf-bfd.h" /* for elfcore_write_* */
#include "inferior.h"
#include "cli/cli-utils.h"
#include "arch-utils.h"
#include "gdb_obstack.h"
#include "observable.h"
#include "objfiles.h"
#include "infcall.h"
#include "gdbcmd.h"
#include "gdb_regex.h"
#include "common/enum-flags.h"
#include "common/gdb_optional.h"
#include <ctype.h>
/* This enum represents the values that the user can choose when
informing the Linux kernel about which memory mappings will be
dumped in a corefile. They are described in the file
Documentation/filesystems/proc.txt, inside the Linux kernel
tree. */
enum filter_flag
{
COREFILTER_ANON_PRIVATE = 1 << 0,
COREFILTER_ANON_SHARED = 1 << 1,
COREFILTER_MAPPED_PRIVATE = 1 << 2,
COREFILTER_MAPPED_SHARED = 1 << 3,
COREFILTER_ELF_HEADERS = 1 << 4,
COREFILTER_HUGETLB_PRIVATE = 1 << 5,
COREFILTER_HUGETLB_SHARED = 1 << 6,
};
DEF_ENUM_FLAGS_TYPE (enum filter_flag, filter_flags);
/* This struct is used to map flags found in the "VmFlags:" field (in
the /proc/<PID>/smaps file). */
struct smaps_vmflags
{
/* Zero if this structure has not been initialized yet. It
probably means that the Linux kernel being used does not emit
the "VmFlags:" field on "/proc/PID/smaps". */
unsigned int initialized_p : 1;
/* Memory mapped I/O area (VM_IO, "io"). */
unsigned int io_page : 1;
/* Area uses huge TLB pages (VM_HUGETLB, "ht"). */
unsigned int uses_huge_tlb : 1;
/* Do not include this memory region on the coredump (VM_DONTDUMP, "dd"). */
unsigned int exclude_coredump : 1;
/* Is this a MAP_SHARED mapping (VM_SHARED, "sh"). */
unsigned int shared_mapping : 1;
};
/* Whether to take the /proc/PID/coredump_filter into account when
generating a corefile. */
static int use_coredump_filter = 1;
/* Whether the value of smaps_vmflags->exclude_coredump should be
ignored, including mappings marked with the VM_DONTDUMP flag in
the dump. */
static int dump_excluded_mappings = 0;
/* This enum represents the signals' numbers on a generic architecture
running the Linux kernel. The definition of "generic" comes from
the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
tree, which is the "de facto" implementation of signal numbers to
be used by new architecture ports.
For those architectures which have differences between the generic
standard (e.g., Alpha), we define the different signals (and *only*
those) in the specific target-dependent file (e.g.,
alpha-linux-tdep.c, for Alpha). Please refer to the architecture's
tdep file for more information.
ARM deserves a special mention here. On the file
<arch/arm/include/uapi/asm/signal.h>, it defines only one different
(and ARM-only) signal, which is SIGSWI, with the same number as
SIGRTMIN. This signal is used only for a very specific target,
called ArthurOS (from RISCOS). Therefore, we do not handle it on
the ARM-tdep file, and we can safely use the generic signal handler
here for ARM targets.
As stated above, this enum is derived from
<include/uapi/asm-generic/signal.h>, from the Linux kernel
tree. */
enum
{
LINUX_SIGHUP = 1,
LINUX_SIGINT = 2,
LINUX_SIGQUIT = 3,
LINUX_SIGILL = 4,
LINUX_SIGTRAP = 5,
LINUX_SIGABRT = 6,
LINUX_SIGIOT = 6,
LINUX_SIGBUS = 7,
LINUX_SIGFPE = 8,
LINUX_SIGKILL = 9,
LINUX_SIGUSR1 = 10,
LINUX_SIGSEGV = 11,
LINUX_SIGUSR2 = 12,
LINUX_SIGPIPE = 13,
LINUX_SIGALRM = 14,
LINUX_SIGTERM = 15,
LINUX_SIGSTKFLT = 16,
LINUX_SIGCHLD = 17,
LINUX_SIGCONT = 18,
LINUX_SIGSTOP = 19,
LINUX_SIGTSTP = 20,
LINUX_SIGTTIN = 21,
LINUX_SIGTTOU = 22,
LINUX_SIGURG = 23,
LINUX_SIGXCPU = 24,
LINUX_SIGXFSZ = 25,
LINUX_SIGVTALRM = 26,
LINUX_SIGPROF = 27,
LINUX_SIGWINCH = 28,
LINUX_SIGIO = 29,
LINUX_SIGPOLL = LINUX_SIGIO,
LINUX_SIGPWR = 30,
LINUX_SIGSYS = 31,
LINUX_SIGUNUSED = 31,
LINUX_SIGRTMIN = 32,
LINUX_SIGRTMAX = 64,
};
static struct gdbarch_data *linux_gdbarch_data_handle;
struct linux_gdbarch_data
{
struct type *siginfo_type;
};
static void *
init_linux_gdbarch_data (struct gdbarch *gdbarch)
{
return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct linux_gdbarch_data);
}
static struct linux_gdbarch_data *
get_linux_gdbarch_data (struct gdbarch *gdbarch)
{
return ((struct linux_gdbarch_data *)
gdbarch_data (gdbarch, linux_gdbarch_data_handle));
}
/* Per-inferior data key. */
static const struct inferior_data *linux_inferior_data;
/* Linux-specific cached data. This is used by GDB for caching
purposes for each inferior. This helps reduce the overhead of
transfering data from a remote target to the local host. */
struct linux_info
{
/* Cache of the inferior's vsyscall/vDSO mapping range. Only valid
if VSYSCALL_RANGE_P is positive. This is cached because getting
at this info requires an auxv lookup (which is itself cached),
and looking through the inferior's mappings (which change
throughout execution and therefore cannot be cached). */
struct mem_range vsyscall_range;
/* Zero if we haven't tried looking up the vsyscall's range before
yet. Positive if we tried looking it up, and found it. Negative
if we tried looking it up but failed. */
int vsyscall_range_p;
};
/* Frees whatever allocated space there is to be freed and sets INF's
linux cache data pointer to NULL. */
static void
invalidate_linux_cache_inf (struct inferior *inf)
{
struct linux_info *info;
info = (struct linux_info *) inferior_data (inf, linux_inferior_data);
if (info != NULL)
{
xfree (info);
set_inferior_data (inf, linux_inferior_data, NULL);
}
}
/* Handles the cleanup of the linux cache for inferior INF. ARG is
ignored. Callback for the inferior_appeared and inferior_exit
events. */
static void
linux_inferior_data_cleanup (struct inferior *inf, void *arg)
{
invalidate_linux_cache_inf (inf);
}
/* Fetch the linux cache info for INF. This function always returns a
valid INFO pointer. */
static struct linux_info *
get_linux_inferior_data (void)
{
struct linux_info *info;
struct inferior *inf = current_inferior ();
info = (struct linux_info *) inferior_data (inf, linux_inferior_data);
if (info == NULL)
{
info = XCNEW (struct linux_info);
set_inferior_data (inf, linux_inferior_data, info);
}
return info;
}
/* See linux-tdep.h. */
struct type *
linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch,
linux_siginfo_extra_fields extra_fields)
{
struct linux_gdbarch_data *linux_gdbarch_data;
struct type *int_type, *uint_type, *long_type, *void_ptr_type, *short_type;
struct type *uid_type, *pid_type;
struct type *sigval_type, *clock_type;
struct type *siginfo_type, *sifields_type;
struct type *type;
linux_gdbarch_data = get_linux_gdbarch_data (gdbarch);
if (linux_gdbarch_data->siginfo_type != NULL)
return linux_gdbarch_data->siginfo_type;
int_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
0, "int");
uint_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
1, "unsigned int");
long_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch),
0, "long");
short_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch),
0, "short");
void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void);
/* sival_t */
sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
TYPE_NAME (sigval_type) = xstrdup ("sigval_t");
append_composite_type_field (sigval_type, "sival_int", int_type);
append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type);
/* __pid_t */
pid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
TYPE_LENGTH (int_type) * TARGET_CHAR_BIT, "__pid_t");
TYPE_TARGET_TYPE (pid_type) = int_type;
TYPE_TARGET_STUB (pid_type) = 1;
/* __uid_t */
uid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
TYPE_LENGTH (uint_type) * TARGET_CHAR_BIT, "__uid_t");
TYPE_TARGET_TYPE (uid_type) = uint_type;
TYPE_TARGET_STUB (uid_type) = 1;
/* __clock_t */
clock_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
TYPE_LENGTH (long_type) * TARGET_CHAR_BIT,
"__clock_t");
TYPE_TARGET_TYPE (clock_type) = long_type;
TYPE_TARGET_STUB (clock_type) = 1;
/* _sifields */
sifields_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
{
const int si_max_size = 128;
int si_pad_size;
int size_of_int = gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT;
/* _pad */
if (gdbarch_ptr_bit (gdbarch) == 64)
si_pad_size = (si_max_size / size_of_int) - 4;
else
si_pad_size = (si_max_size / size_of_int) - 3;
append_composite_type_field (sifields_type, "_pad",
init_vector_type (int_type, si_pad_size));
}
/* _kill */
type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (type, "si_pid", pid_type);
append_composite_type_field (type, "si_uid", uid_type);
append_composite_type_field (sifields_type, "_kill", type);
/* _timer */
type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (type, "si_tid", int_type);
append_composite_type_field (type, "si_overrun", int_type);
append_composite_type_field (type, "si_sigval", sigval_type);
append_composite_type_field (sifields_type, "_timer", type);
/* _rt */
type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (type, "si_pid", pid_type);
append_composite_type_field (type, "si_uid", uid_type);
append_composite_type_field (type, "si_sigval", sigval_type);
append_composite_type_field (sifields_type, "_rt", type);
/* _sigchld */
type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (type, "si_pid", pid_type);
append_composite_type_field (type, "si_uid", uid_type);
append_composite_type_field (type, "si_status", int_type);
append_composite_type_field (type, "si_utime", clock_type);
append_composite_type_field (type, "si_stime", clock_type);
append_composite_type_field (sifields_type, "_sigchld", type);
/* _sigfault */
type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (type, "si_addr", void_ptr_type);
/* Additional bound fields for _sigfault in case they were requested. */
if ((extra_fields & LINUX_SIGINFO_FIELD_ADDR_BND) != 0)
{
struct type *sigfault_bnd_fields;
append_composite_type_field (type, "_addr_lsb", short_type);
sigfault_bnd_fields = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (sigfault_bnd_fields, "_lower", void_ptr_type);
append_composite_type_field (sigfault_bnd_fields, "_upper", void_ptr_type);
append_composite_type_field (type, "_addr_bnd", sigfault_bnd_fields);
}
append_composite_type_field (sifields_type, "_sigfault", type);
/* _sigpoll */
type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
append_composite_type_field (type, "si_band", long_type);
append_composite_type_field (type, "si_fd", int_type);
append_composite_type_field (sifields_type, "_sigpoll", type);
/* struct siginfo */
siginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
TYPE_NAME (siginfo_type) = xstrdup ("siginfo");
append_composite_type_field (siginfo_type, "si_signo", int_type);
append_composite_type_field (siginfo_type, "si_errno", int_type);
append_composite_type_field (siginfo_type, "si_code", int_type);
append_composite_type_field_aligned (siginfo_type,
"_sifields", sifields_type,
TYPE_LENGTH (long_type));
linux_gdbarch_data->siginfo_type = siginfo_type;
return siginfo_type;
}
/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
static struct type *
linux_get_siginfo_type (struct gdbarch *gdbarch)
{
return linux_get_siginfo_type_with_fields (gdbarch, 0);
}
/* Return true if the target is running on uClinux instead of normal
Linux kernel. */
int
linux_is_uclinux (void)
{
CORE_ADDR dummy;
return (target_auxv_search (target_stack, AT_NULL, &dummy) > 0
&& target_auxv_search (target_stack, AT_PAGESZ, &dummy) == 0);
}
static int
linux_has_shared_address_space (struct gdbarch *gdbarch)
{
return linux_is_uclinux ();
}
/* This is how we want PTIDs from core files to be printed. */
static const char *
linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
{
static char buf[80];
if (ptid_get_lwp (ptid) != 0)
{
snprintf (buf, sizeof (buf), "LWP %ld", ptid_get_lwp (ptid));
return buf;
}
return normal_pid_to_str (ptid);
}
/* Service function for corefiles and info proc. */
static void
read_mapping (const char *line,
ULONGEST *addr, ULONGEST *endaddr,
const char **permissions, size_t *permissions_len,
ULONGEST *offset,
const char **device, size_t *device_len,
ULONGEST *inode,
const char **filename)
{
const char *p = line;
*addr = strtoulst (p, &p, 16);
if (*p == '-')
p++;
*endaddr = strtoulst (p, &p, 16);
p = skip_spaces (p);
*permissions = p;
while (*p && !isspace (*p))
p++;
*permissions_len = p - *permissions;
*offset = strtoulst (p, &p, 16);
p = skip_spaces (p);
*device = p;
while (*p && !isspace (*p))
p++;
*device_len = p - *device;
*inode = strtoulst (p, &p, 10);
p = skip_spaces (p);
*filename = p;
}
/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
This function was based on the documentation found on
<Documentation/filesystems/proc.txt>, on the Linux kernel.
Linux kernels before commit
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
field on smaps. */
static void
decode_vmflags (char *p, struct smaps_vmflags *v)
{
char *saveptr = NULL;
const char *s;
v->initialized_p = 1;
p = skip_to_space (p);
p = skip_spaces (p);
for (s = strtok_r (p, " ", &saveptr);
s != NULL;
s = strtok_r (NULL, " ", &saveptr))
{
if (strcmp (s, "io") == 0)
v->io_page = 1;
else if (strcmp (s, "ht") == 0)
v->uses_huge_tlb = 1;
else if (strcmp (s, "dd") == 0)
v->exclude_coredump = 1;
else if (strcmp (s, "sh") == 0)
v->shared_mapping = 1;
}
}
/* Regexes used by mapping_is_anonymous_p. Put in a structure because
they're initialized lazily. */
struct mapping_regexes
{
/* Matches "/dev/zero" filenames (with or without the "(deleted)"
string in the end). We know for sure, based on the Linux kernel
code, that memory mappings whose associated filename is
"/dev/zero" are guaranteed to be MAP_ANONYMOUS. */
compiled_regex dev_zero
{"^/dev/zero\\( (deleted)\\)\\?$", REG_NOSUB,
_("Could not compile regex to match /dev/zero filename")};
/* Matches "/SYSV%08x" filenames (with or without the "(deleted)"
string in the end). These filenames refer to shared memory
(shmem), and memory mappings associated with them are
MAP_ANONYMOUS as well. */
compiled_regex shmem_file
{"^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$", REG_NOSUB,
_("Could not compile regex to match shmem filenames")};
/* A heuristic we use to try to mimic the Linux kernel's 'n_link ==
0' code, which is responsible to decide if it is dealing with a
'MAP_SHARED | MAP_ANONYMOUS' mapping. In other words, if
FILE_DELETED matches, it does not necessarily mean that we are
dealing with an anonymous shared mapping. However, there is no
easy way to detect this currently, so this is the best
approximation we have.
As a result, GDB will dump readonly pages of deleted executables
when using the default value of coredump_filter (0x33), while the
Linux kernel will not dump those pages. But we can live with
that. */
compiled_regex file_deleted
{" (deleted)$", REG_NOSUB,
_("Could not compile regex to match '<file> (deleted)'")};
};
/* Return 1 if the memory mapping is anonymous, 0 otherwise.
FILENAME is the name of the file present in the first line of the
memory mapping, in the "/proc/PID/smaps" output. For example, if
the first line is:
7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770 /path/to/file
Then FILENAME will be "/path/to/file". */
static int
mapping_is_anonymous_p (const char *filename)
{
static gdb::optional<mapping_regexes> regexes;
static int init_regex_p = 0;
if (!init_regex_p)
{
/* Let's be pessimistic and assume there will be an error while
compiling the regex'es. */
init_regex_p = -1;
regexes.emplace ();
/* If we reached this point, then everything succeeded. */
init_regex_p = 1;
}
if (init_regex_p == -1)
{
const char deleted[] = " (deleted)";
size_t del_len = sizeof (deleted) - 1;
size_t filename_len = strlen (filename);
/* There was an error while compiling the regex'es above. In
order to try to give some reliable information to the caller,
we just try to find the string " (deleted)" in the filename.
If we managed to find it, then we assume the mapping is
anonymous. */
return (filename_len >= del_len
&& strcmp (filename + filename_len - del_len, deleted) == 0);
}
if (*filename == '\0'
|| regexes->dev_zero.exec (filename, 0, NULL, 0) == 0
|| regexes->shmem_file.exec (filename, 0, NULL, 0) == 0
|| regexes->file_deleted.exec (filename, 0, NULL, 0) == 0)
return 1;
return 0;
}
/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
greater than 0 if it should.
In a nutshell, this is the logic that we follow in order to decide
if a mapping should be dumped or not.
- If the mapping is associated to a file whose name ends with
" (deleted)", or if the file is "/dev/zero", or if it is
"/SYSV%08x" (shared memory), or if there is no file associated
with it, or if the AnonHugePages: or the Anonymous: fields in the
/proc/PID/smaps have contents, then GDB considers this mapping to
be anonymous. Otherwise, GDB considers this mapping to be a
file-backed mapping (because there will be a file associated with
it).
It is worth mentioning that, from all those checks described
above, the most fragile is the one to see if the file name ends
with " (deleted)". This does not necessarily mean that the
mapping is anonymous, because the deleted file associated with
the mapping may have been a hard link to another file, for
example. The Linux kernel checks to see if "i_nlink == 0", but
GDB cannot easily (and normally) do this check (iff running as
root, it could find the mapping in /proc/PID/map_files/ and
determine whether there still are other hard links to the
inode/file). Therefore, we made a compromise here, and we assume
that if the file name ends with " (deleted)", then the mapping is
indeed anonymous. FWIW, this is something the Linux kernel could
do better: expose this information in a more direct way.
- If we see the flag "sh" in the "VmFlags:" field (in
/proc/PID/smaps), then certainly the memory mapping is shared
(VM_SHARED). If we have access to the VmFlags, and we don't see
the "sh" there, then certainly the mapping is private. However,
Linux kernels before commit
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
"VmFlags:" field; in that case, we use another heuristic: if we
see 'p' in the permission flags, then we assume that the mapping
is private, even though the presence of the 's' flag there would
mean VM_MAYSHARE, which means the mapping could still be private.
This should work OK enough, however. */
static int
dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
int maybe_private_p, int mapping_anon_p, int mapping_file_p,
const char *filename)
{
/* Initially, we trust in what we received from our caller. This
value may not be very precise (i.e., it was probably gathered
from the permission line in the /proc/PID/smaps list, which
actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
what we have until we take a look at the "VmFlags:" field
(assuming that the version of the Linux kernel being used
supports it, of course). */
int private_p = maybe_private_p;
/* We always dump vDSO and vsyscall mappings, because it's likely that
there'll be no file to read the contents from at core load time.
The kernel does the same. */
if (strcmp ("[vdso]", filename) == 0
|| strcmp ("[vsyscall]", filename) == 0)
return 1;
if (v->initialized_p)
{
/* We never dump I/O mappings. */
if (v->io_page)
return 0;
/* Check if we should exclude this mapping. */
if (!dump_excluded_mappings && v->exclude_coredump)
return 0;
/* Update our notion of whether this mapping is shared or
private based on a trustworthy value. */
private_p = !v->shared_mapping;
/* HugeTLB checking. */
if (v->uses_huge_tlb)
{
if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
|| (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
return 1;
return 0;
}
}
if (private_p)
{
if (mapping_anon_p && mapping_file_p)
{
/* This is a special situation. It can happen when we see a
mapping that is file-backed, but that contains anonymous
pages. */
return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
|| (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
}
else if (mapping_anon_p)
return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
else
return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
}
else
{
if (mapping_anon_p && mapping_file_p)
{
/* This is a special situation. It can happen when we see a
mapping that is file-backed, but that contains anonymous
pages. */
return ((filterflags & COREFILTER_ANON_SHARED) != 0
|| (filterflags & COREFILTER_MAPPED_SHARED) != 0);
}
else if (mapping_anon_p)
return (filterflags & COREFILTER_ANON_SHARED) != 0;
else
return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
}
}
/* Implement the "info proc" command. */
static void
linux_info_proc (struct gdbarch *gdbarch, const char *args,
enum info_proc_what what)
{
/* A long is used for pid instead of an int to avoid a loss of precision
compiler warning from the output of strtoul. */
long pid;
int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
int cwd_f = (what == IP_MINIMAL || what == IP_CWD || what == IP_ALL);
int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
int status_f = (what == IP_STATUS || what == IP_ALL);
int stat_f = (what == IP_STAT || what == IP_ALL);
char filename[100];
char *data;
int target_errno;
if (args && isdigit (args[0]))
{
char *tem;
pid = strtoul (args, &tem, 10);
args = tem;
}
else
{
if (!target_has_execution)
error (_("No current process: you must name one."));
if (current_inferior ()->fake_pid_p)
error (_("Can't determine the current process's PID: you must name one."));
pid = current_inferior ()->pid;
}
args = skip_spaces (args);
if (args && args[0])
error (_("Too many parameters: %s"), args);
printf_filtered (_("process %ld\n"), pid);
if (cmdline_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cmdline", pid);
gdb_byte *buffer;
ssize_t len = target_fileio_read_alloc (NULL, filename, &buffer);
if (len > 0)
{
gdb::unique_xmalloc_ptr<char> cmdline ((char *) buffer);
ssize_t pos;
for (pos = 0; pos < len - 1; pos++)
{
if (buffer[pos] == '\0')
buffer[pos] = ' ';
}
buffer[len - 1] = '\0';
printf_filtered ("cmdline = '%s'\n", buffer);
}
else
warning (_("unable to open /proc file '%s'"), filename);
}
if (cwd_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cwd", pid);
gdb::optional<std::string> contents
= target_fileio_readlink (NULL, filename, &target_errno);
if (contents.has_value ())
printf_filtered ("cwd = '%s'\n", contents->c_str ());
else
warning (_("unable to read link '%s'"), filename);
}
if (exe_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/exe", pid);
gdb::optional<std::string> contents
= target_fileio_readlink (NULL, filename, &target_errno);
if (contents.has_value ())
printf_filtered ("exe = '%s'\n", contents->c_str ());
else
warning (_("unable to read link '%s'"), filename);
}
if (mappings_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/maps", pid);
gdb::unique_xmalloc_ptr<char> map
= target_fileio_read_stralloc (NULL, filename);
if (map != NULL)
{
char *line;
printf_filtered (_("Mapped address spaces:\n\n"));
if (gdbarch_addr_bit (gdbarch) == 32)
{
printf_filtered ("\t%10s %10s %10s %10s %s\n",
"Start Addr",
" End Addr",
" Size", " Offset", "objfile");
}
else
{
printf_filtered (" %18s %18s %10s %10s %s\n",
"Start Addr",
" End Addr",
" Size", " Offset", "objfile");
}
for (line = strtok (map.get (), "\n");
line;
line = strtok (NULL, "\n"))
{
ULONGEST addr, endaddr, offset, inode;
const char *permissions, *device, *filename;
size_t permissions_len, device_len;
read_mapping (line, &addr, &endaddr,
&permissions, &permissions_len,
&offset, &device, &device_len,
&inode, &filename);
if (gdbarch_addr_bit (gdbarch) == 32)
{
printf_filtered ("\t%10s %10s %10s %10s %s\n",
paddress (gdbarch, addr),
paddress (gdbarch, endaddr),
hex_string (endaddr - addr),
hex_string (offset),
*filename? filename : "");
}
else
{
printf_filtered (" %18s %18s %10s %10s %s\n",
paddress (gdbarch, addr),
paddress (gdbarch, endaddr),
hex_string (endaddr - addr),
hex_string (offset),
*filename? filename : "");
}
}
}
else
warning (_("unable to open /proc file '%s'"), filename);
}
if (status_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/status", pid);
gdb::unique_xmalloc_ptr<char> status
= target_fileio_read_stralloc (NULL, filename);
if (status)
puts_filtered (status.get ());
else
warning (_("unable to open /proc file '%s'"), filename);
}
if (stat_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/stat", pid);
gdb::unique_xmalloc_ptr<char> statstr
= target_fileio_read_stralloc (NULL, filename);
if (statstr)
{
const char *p = statstr.get ();
printf_filtered (_("Process: %s\n"),
pulongest (strtoulst (p, &p, 10)));
p = skip_spaces (p);
if (*p == '(')
{
/* ps command also relies on no trailing fields
ever contain ')'. */
const char *ep = strrchr (p, ')');
if (ep != NULL)
{
printf_filtered ("Exec file: %.*s\n",
(int) (ep - p - 1), p + 1);
p = ep + 1;
}
}
p = skip_spaces (p);
if (*p)
printf_filtered (_("State: %c\n"), *p++);
if (*p)
printf_filtered (_("Parent process: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Process group: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Session id: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("TTY: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("TTY owner process group: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Flags: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Minor faults (no memory page): %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Minor faults, children: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Major faults (memory page faults): %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Major faults, children: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("utime: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("stime: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("utime, children: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("stime, children: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("jiffies remaining in current "
"time slice: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("'nice' value: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("jiffies until next timeout: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("jiffies until next SIGALRM: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("start time (jiffies since "
"system boot): %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Virtual memory size: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Resident set size: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("rlim: %s\n"),
pulongest (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Start of text: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("End of text: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Start of stack: %s\n"),
hex_string (strtoulst (p, &p, 10)));
#if 0 /* Don't know how architecture-dependent the rest is...
Anyway the signal bitmap info is available from "status". */
if (*p)
printf_filtered (_("Kernel stack pointer: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Kernel instr pointer: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Pending signals bitmap: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Blocked signals bitmap: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Ignored signals bitmap: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("Catched signals bitmap: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
printf_filtered (_("wchan (system call): %s\n"),
hex_string (strtoulst (p, &p, 10)));
#endif
}
else
warning (_("unable to open /proc file '%s'"), filename);
}
}
/* Implement "info proc mappings" for a corefile. */
static void
linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
{
asection *section;
ULONGEST count, page_size;
unsigned char *descdata, *filenames, *descend;
size_t note_size;
unsigned int addr_size_bits, addr_size;
struct gdbarch *core_gdbarch = gdbarch_from_bfd (core_bfd);
/* We assume this for reading 64-bit core files. */
gdb_static_assert (sizeof (ULONGEST) >= 8);
section = bfd_get_section_by_name (core_bfd, ".note.linuxcore.file");
if (section == NULL)
{
warning (_("unable to find mappings in core file"));
return;
}
addr_size_bits = gdbarch_addr_bit (core_gdbarch);
addr_size = addr_size_bits / 8;
note_size = bfd_get_section_size (section);
if (note_size < 2 * addr_size)
error (_("malformed core note - too short for header"));
gdb::def_vector<unsigned char> contents (note_size);
if (!bfd_get_section_contents (core_bfd, section, contents.data (),
0, note_size))
error (_("could not get core note contents"));
descdata = contents.data ();
descend = descdata + note_size;
if (descdata[note_size - 1] != '\0')
error (_("malformed note - does not end with \\0"));
count = bfd_get (addr_size_bits, core_bfd, descdata);
descdata += addr_size;
page_size = bfd_get (addr_size_bits, core_bfd, descdata);
descdata += addr_size;
if (note_size < 2 * addr_size + count * 3 * addr_size)
error (_("malformed note - too short for supplied file count"));
printf_filtered (_("Mapped address spaces:\n\n"));
if (gdbarch_addr_bit (gdbarch) == 32)
{
printf_filtered ("\t%10s %10s %10s %10s %s\n",
"Start Addr",
" End Addr",
" Size", " Offset", "objfile");
}
else
{
printf_filtered (" %18s %18s %10s %10s %s\n",
"Start Addr",
" End Addr",
" Size", " Offset", "objfile");
}
filenames = descdata + count * 3 * addr_size;
while (--count > 0)
{
ULONGEST start, end, file_ofs;
if (filenames == descend)
error (_("malformed note - filenames end too early"));
start = bfd_get (addr_size_bits, core_bfd, descdata);
descdata += addr_size;
end = bfd_get (addr_size_bits, core_bfd, descdata);
descdata += addr_size;
file_ofs = bfd_get (addr_size_bits, core_bfd, descdata);
descdata += addr_size;
file_ofs *= page_size;
if (gdbarch_addr_bit (gdbarch) == 32)
printf_filtered ("\t%10s %10s %10s %10s %s\n",
paddress (gdbarch, start),
paddress (gdbarch, end),
hex_string (end - start),
hex_string (file_ofs),
filenames);
else
printf_filtered (" %18s %18s %10s %10s %s\n",
paddress (gdbarch, start),
paddress (gdbarch, end),
hex_string (end - start),
hex_string (file_ofs),
filenames);
filenames += 1 + strlen ((char *) filenames);
}
}
/* Implement "info proc" for a corefile. */
static void
linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
enum info_proc_what what)
{
int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
if (exe_f)
{
const char *exe;
exe = bfd_core_file_failing_command (core_bfd);
if (exe != NULL)
printf_filtered ("exe = '%s'\n", exe);
else
warning (_("unable to find command name in core file"));
}
if (mappings_f)
linux_core_info_proc_mappings (gdbarch, args);
if (!exe_f && !mappings_f)
error (_("unable to handle request"));
}
/* Read siginfo data from the core, if possible. Returns -1 on
failure. Otherwise, returns the number of bytes read. READBUF,
OFFSET, and LEN are all as specified by the to_xfer_partial
interface. */
static LONGEST
linux_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf,
ULONGEST offset, ULONGEST len)
{
thread_section_name section_name (".note.linuxcore.siginfo", inferior_ptid);
asection *section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
if (section == NULL)
return -1;
if (!bfd_get_section_contents (core_bfd, section, readbuf, offset, len))
return -1;
return len;
}
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
int exec, int modified,
const char *filename,
void *data);
/* List memory regions in the inferior for a corefile. */
static int
linux_find_memory_regions_full (struct gdbarch *gdbarch,
linux_find_memory_region_ftype *func,
void *obfd)
{
char mapsfilename[100];
char coredumpfilter_name[100];
pid_t pid;
/* Default dump behavior of coredump_filter (0x33), according to
Documentation/filesystems/proc.txt from the Linux kernel
tree. */
filter_flags filterflags = (COREFILTER_ANON_PRIVATE
| COREFILTER_ANON_SHARED
| COREFILTER_ELF_HEADERS
| COREFILTER_HUGETLB_PRIVATE);
/* We need to know the real target PID to access /proc. */
if (current_inferior ()->fake_pid_p)
return 1;
pid = current_inferior ()->pid;
if (use_coredump_filter)
{
xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
"/proc/%d/coredump_filter", pid);
gdb::unique_xmalloc_ptr<char> coredumpfilterdata
= target_fileio_read_stralloc (NULL, coredumpfilter_name);
if (coredumpfilterdata != NULL)
{
unsigned int flags;
sscanf (coredumpfilterdata.get (), "%x", &flags);
filterflags = (enum filter_flag) flags;
}
}
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
gdb::unique_xmalloc_ptr<char> data
= target_fileio_read_stralloc (NULL, mapsfilename);
if (data == NULL)
{
/* Older Linux kernels did not support /proc/PID/smaps. */
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
data = target_fileio_read_stralloc (NULL, mapsfilename);
}
if (data != NULL)
{
char *line, *t;
line = strtok_r (data.get (), "\n", &t);
while (line != NULL)
{
ULONGEST addr, endaddr, offset, inode;
const char *permissions, *device, *filename;
struct smaps_vmflags v;
size_t permissions_len, device_len;
int read, write, exec, priv;
int has_anonymous = 0;
int should_dump_p = 0;
int mapping_anon_p;
int mapping_file_p;
memset (&v, 0, sizeof (v));
read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
&offset, &device, &device_len, &inode, &filename);
mapping_anon_p = mapping_is_anonymous_p (filename);
/* If the mapping is not anonymous, then we can consider it
to be file-backed. These two states (anonymous or
file-backed) seem to be exclusive, but they can actually
coexist. For example, if a file-backed mapping has
"Anonymous:" pages (see more below), then the Linux
kernel will dump this mapping when the user specified
that she only wants anonymous mappings in the corefile
(*even* when she explicitly disabled the dumping of
file-backed mappings). */
mapping_file_p = !mapping_anon_p;
/* Decode permissions. */
read = (memchr (permissions, 'r', permissions_len) != 0);
write = (memchr (permissions, 'w', permissions_len) != 0);
exec = (memchr (permissions, 'x', permissions_len) != 0);
/* 'private' here actually means VM_MAYSHARE, and not
VM_SHARED. In order to know if a mapping is really
private or not, we must check the flag "sh" in the
VmFlags field. This is done by decode_vmflags. However,
if we are using a Linux kernel released before the commit
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
not have the VmFlags there. In this case, there is
really no way to know if we are dealing with VM_SHARED,
so we just assume that VM_MAYSHARE is enough. */
priv = memchr (permissions, 'p', permissions_len) != 0;
/* Try to detect if region should be dumped by parsing smaps
counters. */
for (line = strtok_r (NULL, "\n", &t);
line != NULL && line[0] >= 'A' && line[0] <= 'Z';
line = strtok_r (NULL, "\n", &t))
{
char keyword[64 + 1];
if (sscanf (line, "%64s", keyword) != 1)
{
warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
break;
}
if (strcmp (keyword, "Anonymous:") == 0)
{
/* Older Linux kernels did not support the
"Anonymous:" counter. Check it here. */
has_anonymous = 1;
}
else if (strcmp (keyword, "VmFlags:") == 0)
decode_vmflags (line, &v);
if (strcmp (keyword, "AnonHugePages:") == 0
|| strcmp (keyword, "Anonymous:") == 0)
{
unsigned long number;
if (sscanf (line, "%*s%lu", &number) != 1)
{
warning (_("Error parsing {s,}maps file '%s' number"),
mapsfilename);
break;
}
if (number > 0)
{
/* Even if we are dealing with a file-backed
mapping, if it contains anonymous pages we
consider it to be *also* an anonymous
mapping, because this is what the Linux
kernel does:
// Dump segments that have been written to.
if (vma->anon_vma && FILTER(ANON_PRIVATE))
goto whole;
Note that if the mapping is already marked as
file-backed (i.e., mapping_file_p is
non-zero), then this is a special case, and
this mapping will be dumped either when the
user wants to dump file-backed *or* anonymous
mappings. */
mapping_anon_p = 1;
}
}
}
if (has_anonymous)
should_dump_p = dump_mapping_p (filterflags, &v, priv,
mapping_anon_p, mapping_file_p,
filename);
else
{
/* Older Linux kernels did not support the "Anonymous:" counter.
If it is missing, we can't be sure - dump all the pages. */
should_dump_p = 1;
}
/* Invoke the callback function to create the corefile segment. */
if (should_dump_p)
func (addr, endaddr - addr, offset, inode,
read, write, exec, 1, /* MODIFIED is true because we
want to dump the mapping. */
filename, obfd);
}
return 0;
}
return 1;
}
/* A structure for passing information through
linux_find_memory_regions_full. */
struct linux_find_memory_regions_data
{
/* The original callback. */
find_memory_region_ftype func;
/* The original datum. */
void *obfd;
};
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
static int
linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write, int exec, int modified,
const char *filename, void *arg)
{
struct linux_find_memory_regions_data *data
= (struct linux_find_memory_regions_data *) arg;
return data->func (vaddr, size, read, write, exec, modified, data->obfd);
}
/* A variant of linux_find_memory_regions_full that is suitable as the
gdbarch find_memory_regions method. */
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
find_memory_region_ftype func, void *obfd)
{
struct linux_find_memory_regions_data data;
data.func = func;
data.obfd = obfd;
return linux_find_memory_regions_full (gdbarch,
linux_find_memory_regions_thunk,
&data);
}
/* Determine which signal stopped execution. */
static int
find_signalled_thread (struct thread_info *info, void *data)
{
if (info->suspend.stop_signal != GDB_SIGNAL_0
&& ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
return 1;
return 0;
}
/* Generate corefile notes for SPU contexts. */
static char *
linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
{
static const char *spu_files[] =
{
"object-id",
"mem",
"regs",
"fpcr",
"lslr",
"decr",
"decr_status",
"signal1",
"signal1_type",
"signal2",
"signal2_type",
"event_mask",
"event_status",
"mbox_info",
"ibox_info",
"wbox_info",
"dma_info",
"proxydma_info",
};
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
/* Determine list of SPU ids. */
gdb::optional<gdb::byte_vector>
spu_ids = target_read_alloc (target_stack, TARGET_OBJECT_SPU, NULL);
if (!spu_ids)
return note_data;
/* Generate corefile notes for each SPU file. */
for (size_t i = 0; i < spu_ids->size (); i += 4)
{
int fd = extract_unsigned_integer (spu_ids->data () + i, 4, byte_order);
for (size_t j = 0; j < sizeof (spu_files) / sizeof (spu_files[0]); j++)
{
char annex[32], note_name[32];
xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[j]);
gdb::optional<gdb::byte_vector> spu_data
= target_read_alloc (target_stack, TARGET_OBJECT_SPU, annex);
if (spu_data && !spu_data->empty ())
{
xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
note_data = elfcore_write_note (obfd, note_data, note_size,
note_name, NT_SPU,
spu_data->data (),
spu_data->size ());
if (!note_data)
return nullptr;
}
}
}
return note_data;
}
/* This is used to pass information from
linux_make_mappings_corefile_notes through
linux_find_memory_regions_full. */
struct linux_make_mappings_data
{
/* Number of files mapped. */
ULONGEST file_count;
/* The obstack for the main part of the data. */
struct obstack *data_obstack;
/* The filename obstack. */
struct obstack *filename_obstack;
/* The architecture's "long" type. */
struct type *long_type;
};
static linux_find_memory_region_ftype linux_make_mappings_callback;
/* A callback for linux_find_memory_regions_full that updates the
mappings data for linux_make_mappings_corefile_notes. */
static int
linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write, int exec, int modified,
const char *filename, void *data)
{
struct linux_make_mappings_data *map_data
= (struct linux_make_mappings_data *) data;
gdb_byte buf[sizeof (ULONGEST)];
if (*filename == '\0' || inode == 0)
return 0;
++map_data->file_count;
pack_long (buf, map_data->long_type, vaddr);
obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
pack_long (buf, map_data->long_type, vaddr + size);
obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
pack_long (buf, map_data->long_type, offset);
obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
obstack_grow_str0 (map_data->filename_obstack, filename);
return 0;
}
/* Write the file mapping data to the core file, if possible. OBFD is
the output BFD. NOTE_DATA is the current note data, and NOTE_SIZE
is a pointer to the note size. Returns the new NOTE_DATA and
updates NOTE_SIZE. */
static char *
linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
char *note_data, int *note_size)
{
struct linux_make_mappings_data mapping_data;
struct type *long_type
= arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), 0, "long");
gdb_byte buf[sizeof (ULONGEST)];
auto_obstack data_obstack, filename_obstack;
mapping_data.file_count = 0;
mapping_data.data_obstack = &data_obstack;
mapping_data.filename_obstack = &filename_obstack;
mapping_data.long_type = long_type;
/* Reserve space for the count. */
obstack_blank (&data_obstack, TYPE_LENGTH (long_type));
/* We always write the page size as 1 since we have no good way to
determine the correct value. */
pack_long (buf, long_type, 1);
obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
&mapping_data);
if (mapping_data.file_count != 0)
{
/* Write the count to the obstack. */
pack_long ((gdb_byte *) obstack_base (&data_obstack),
long_type, mapping_data.file_count);
/* Copy the filenames to the data obstack. */
obstack_grow (&data_obstack, obstack_base (&filename_obstack),
obstack_object_size (&filename_obstack));
note_data = elfcore_write_note (obfd, note_data, note_size,
"CORE", NT_FILE,
obstack_base (&data_obstack),
obstack_object_size (&data_obstack));
}
return note_data;
}
/* Structure for passing information from
linux_collect_thread_registers via an iterator to
linux_collect_regset_section_cb. */
struct linux_collect_regset_section_cb_data
{
struct gdbarch *gdbarch;
const struct regcache *regcache;
bfd *obfd;
char *note_data;
int *note_size;
unsigned long lwp;
enum gdb_signal stop_signal;
int abort_iteration;
};
/* Callback for iterate_over_regset_sections that records a single
regset in the corefile note section. */
static void
linux_collect_regset_section_cb (const char *sect_name, int size,
const struct regset *regset,
const char *human_name, void *cb_data)
{
char *buf;
struct linux_collect_regset_section_cb_data *data
= (struct linux_collect_regset_section_cb_data *) cb_data;
if (data->abort_iteration)
return;
gdb_assert (regset && regset->collect_regset);
buf = (char *) xmalloc (size);
regset->collect_regset (regset, data->regcache, -1, buf, size);
/* PRSTATUS still needs to be treated specially. */
if (strcmp (sect_name, ".reg") == 0)
data->note_data = (char *) elfcore_write_prstatus
(data->obfd, data->note_data, data->note_size, data->lwp,
gdb_signal_to_host (data->stop_signal), buf);
else
data->note_data = (char *) elfcore_write_register_note
(data->obfd, data->note_data, data->note_size,
sect_name, buf, size);
xfree (buf);
if (data->note_data == NULL)
data->abort_iteration = 1;
}
/* Records the thread's register state for the corefile note
section. */
static char *
linux_collect_thread_registers (const struct regcache *regcache,
ptid_t ptid, bfd *obfd,
char *note_data, int *note_size,
enum gdb_signal stop_signal)
{
struct gdbarch *gdbarch = regcache->arch ();
struct linux_collect_regset_section_cb_data data;
data.gdbarch = gdbarch;
data.regcache = regcache;
data.obfd = obfd;
data.note_data = note_data;
data.note_size = note_size;
data.stop_signal = stop_signal;
data.abort_iteration = 0;
/* For remote targets the LWP may not be available, so use the TID. */
data.lwp = ptid_get_lwp (ptid);
if (!data.lwp)
data.lwp = ptid_get_tid (ptid);
gdbarch_iterate_over_regset_sections (gdbarch,
linux_collect_regset_section_cb,
&data, regcache);
return data.note_data;
}
/* Fetch the siginfo data for the specified thread, if it exists. If
there is no data, or we could not read it, return an empty
buffer. */
static gdb::byte_vector
linux_get_siginfo_data (thread_info *thread, struct gdbarch *gdbarch)
{
struct type *siginfo_type;
LONGEST bytes_read;
if (!gdbarch_get_siginfo_type_p (gdbarch))
return gdb::byte_vector ();
scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
inferior_ptid = thread->ptid;
siginfo_type = gdbarch_get_siginfo_type (gdbarch);
gdb::byte_vector buf (TYPE_LENGTH (siginfo_type));
bytes_read = target_read (target_stack, TARGET_OBJECT_SIGNAL_INFO, NULL,
buf.data (), 0, TYPE_LENGTH (siginfo_type));
if (bytes_read != TYPE_LENGTH (siginfo_type))
buf.clear ();
return buf;
}
struct linux_corefile_thread_data
{
struct gdbarch *gdbarch;
bfd *obfd;
char *note_data;
int *note_size;
enum gdb_signal stop_signal;
};
/* Records the thread's register state for the corefile note
section. */
static void
linux_corefile_thread (struct thread_info *info,
struct linux_corefile_thread_data *args)
{
struct regcache *regcache;
regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
target_fetch_registers (regcache, -1);
gdb::byte_vector siginfo_data = linux_get_siginfo_data (info, args->gdbarch);
args->note_data = linux_collect_thread_registers
(regcache, info->ptid, args->obfd, args->note_data,
args->note_size, args->stop_signal);
/* Don't return anything if we got no register information above,
such a core file is useless. */
if (args->note_data != NULL)
if (!siginfo_data.empty ())
args->note_data = elfcore_write_note (args->obfd,
args->note_data,
args->note_size,
"CORE", NT_SIGINFO,
siginfo_data.data (),
siginfo_data.size ());
}
/* Fill the PRPSINFO structure with information about the process being
debugged. Returns 1 in case of success, 0 for failures. Please note that
even if the structure cannot be entirely filled (e.g., GDB was unable to
gather information about the process UID/GID), this function will still
return 1 since some information was already recorded. It will only return
0 iff nothing can be gathered. */
static int
linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
{
/* The filename which we will use to obtain some info about the process.
We will basically use this to store the `/proc/PID/FILENAME' file. */
char filename[100];
/* The basename of the executable. */
const char *basename;
char *infargs;
/* Temporary buffer. */
char *tmpstr;
/* The valid states of a process, according to the Linux kernel. */
const char valid_states[] = "RSDTZW";
/* The program state. */
const char *prog_state;
/* The state of the process. */
char pr_sname;
/* The PID of the program which generated the corefile. */
pid_t pid;
/* Process flags. */
unsigned int pr_flag;
/* Process nice value. */
long pr_nice;
/* The number of fields read by `sscanf'. */
int n_fields = 0;
gdb_assert (p != NULL);
/* Obtaining PID and filename. */
pid = ptid_get_pid (inferior_ptid);
xsnprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid);
/* The full name of the program which generated the corefile. */
gdb::unique_xmalloc_ptr<char> fname
= target_fileio_read_stralloc (NULL, filename);
if (fname == NULL || fname.get ()[0] == '\0')
{
/* No program name was read, so we won't be able to retrieve more
information about the process. */
return 0;
}
memset (p, 0, sizeof (*p));
/* Defining the PID. */
p->pr_pid = pid;
/* Copying the program name. Only the basename matters. */
basename = lbasename (fname.get ());
strncpy (p->pr_fname, basename, sizeof (p->pr_fname));
p->pr_fname[sizeof (p->pr_fname) - 1] = '\0';
infargs = get_inferior_args ();
/* The arguments of the program. */
std::string psargs = fname.get ();
if (infargs != NULL)
psargs = psargs + " " + infargs;
strncpy (p->pr_psargs, psargs.c_str (), sizeof (p->pr_psargs));
p->pr_psargs[sizeof (p->pr_psargs) - 1] = '\0';
xsnprintf (filename, sizeof (filename), "/proc/%d/stat", (int) pid);
/* The contents of `/proc/PID/stat'. */
gdb::unique_xmalloc_ptr<char> proc_stat_contents
= target_fileio_read_stralloc (NULL, filename);
char *proc_stat = proc_stat_contents.get ();
if (proc_stat == NULL || *proc_stat == '\0')
{
/* Despite being unable to read more information about the
process, we return 1 here because at least we have its
command line, PID and arguments. */
return 1;
}
/* Ok, we have the stats. It's time to do a little parsing of the
contents of the buffer, so that we end up reading what we want.
The following parsing mechanism is strongly based on the
information generated by the `fs/proc/array.c' file, present in
the Linux kernel tree. More details about how the information is
displayed can be obtained by seeing the manpage of proc(5),
specifically under the entry of `/proc/[pid]/stat'. */
/* Getting rid of the PID, since we already have it. */
while (isdigit (*proc_stat))
++proc_stat;
proc_stat = skip_spaces (proc_stat);
/* ps command also relies on no trailing fields ever contain ')'. */
proc_stat = strrchr (proc_stat, ')');
if (proc_stat == NULL)
return 1;
proc_stat++;
proc_stat = skip_spaces (proc_stat);
n_fields = sscanf (proc_stat,
"%c" /* Process state. */
"%d%d%d" /* Parent PID, group ID, session ID. */
"%*d%*d" /* tty_nr, tpgid (not used). */
"%u" /* Flags. */
"%*s%*s%*s%*s" /* minflt, cminflt, majflt,
cmajflt (not used). */
"%*s%*s%*s%*s" /* utime, stime, cutime,
cstime (not used). */
"%*s" /* Priority (not used). */
"%ld", /* Nice. */
&pr_sname,
&p->pr_ppid, &p->pr_pgrp, &p->pr_sid,
&pr_flag,
&pr_nice);
if (n_fields != 6)
{
/* Again, we couldn't read the complementary information about
the process state. However, we already have minimal
information, so we just return 1 here. */
return 1;
}
/* Filling the structure fields. */
prog_state = strchr (valid_states, pr_sname);
if (prog_state != NULL)
p->pr_state = prog_state - valid_states;
else
{
/* Zero means "Running". */
p->pr_state = 0;
}
p->pr_sname = p->pr_state > 5 ? '.' : pr_sname;
p->pr_zomb = p->pr_sname == 'Z';
p->pr_nice = pr_nice;
p->pr_flag = pr_flag;
/* Finally, obtaining the UID and GID. For that, we read and parse the
contents of the `/proc/PID/status' file. */
xsnprintf (filename, sizeof (filename), "/proc/%d/status", (int) pid);
/* The contents of `/proc/PID/status'. */
gdb::unique_xmalloc_ptr<char> proc_status_contents
= target_fileio_read_stralloc (NULL, filename);
char *proc_status = proc_status_contents.get ();
if (proc_status == NULL || *proc_status == '\0')
{
/* Returning 1 since we already have a bunch of information. */
return 1;
}
/* Extracting the UID. */
tmpstr = strstr (proc_status, "Uid:");
if (tmpstr != NULL)
{
/* Advancing the pointer to the beginning of the UID. */
tmpstr += sizeof ("Uid:");
while (*tmpstr != '\0' && !isdigit (*tmpstr))
++tmpstr;
if (isdigit (*tmpstr))
p->pr_uid = strtol (tmpstr, &tmpstr, 10);
}
/* Extracting the GID. */
tmpstr = strstr (proc_status, "Gid:");
if (tmpstr != NULL)
{
/* Advancing the pointer to the beginning of the GID. */
tmpstr += sizeof ("Gid:");
while (*tmpstr != '\0' && !isdigit (*tmpstr))
++tmpstr;
if (isdigit (*tmpstr))
p->pr_gid = strtol (tmpstr, &tmpstr, 10);
}
return 1;
}
/* Build the note section for a corefile, and return it in a malloc
buffer. */
static char *
linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
{
struct linux_corefile_thread_data thread_args;
struct elf_internal_linux_prpsinfo prpsinfo;
char *note_data = NULL;
struct thread_info *curr_thr, *signalled_thr, *thr;
if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
return NULL;
if (linux_fill_prpsinfo (&prpsinfo))
{
if (gdbarch_ptr_bit (gdbarch) == 64)
note_data = elfcore_write_linux_prpsinfo64 (obfd,
note_data, note_size,
&prpsinfo);
else
note_data = elfcore_write_linux_prpsinfo32 (obfd,
note_data, note_size,
&prpsinfo);
}
/* Thread register information. */
TRY
{
update_thread_list ();
}
CATCH (e, RETURN_MASK_ERROR)
{
exception_print (gdb_stderr, e);
}
END_CATCH
/* Like the kernel, prefer dumping the signalled thread first.
"First thread" is what tools use to infer the signalled thread.
In case there's more than one signalled thread, prefer the
current thread, if it is signalled. */
curr_thr = inferior_thread ();
if (curr_thr->suspend.stop_signal != GDB_SIGNAL_0)
signalled_thr = curr_thr;
else
{
signalled_thr = iterate_over_threads (find_signalled_thread, NULL);
if (signalled_thr == NULL)
signalled_thr = curr_thr;
}
thread_args.gdbarch = gdbarch;
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
thread_args.stop_signal = signalled_thr->suspend.stop_signal;
linux_corefile_thread (signalled_thr, &thread_args);
ALL_NON_EXITED_THREADS (thr)
{
if (thr == signalled_thr)
continue;
if (ptid_get_pid (thr->ptid) != ptid_get_pid (inferior_ptid))
continue;
linux_corefile_thread (thr, &thread_args);
}
note_data = thread_args.note_data;
if (!note_data)
return NULL;
/* Auxillary vector. */
gdb::optional<gdb::byte_vector> auxv =
target_read_alloc (target_stack, TARGET_OBJECT_AUXV, NULL);
if (auxv && !auxv->empty ())
{
note_data = elfcore_write_note (obfd, note_data, note_size,
"CORE", NT_AUXV, auxv->data (),
auxv->size ());
if (!note_data)
return NULL;
}
/* SPU information. */
note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
if (!note_data)
return NULL;
/* File mappings. */
note_data = linux_make_mappings_corefile_notes (gdbarch, obfd,
note_data, note_size);
return note_data;
}
/* Implementation of `gdbarch_gdb_signal_from_target', as defined in
gdbarch.h. This function is not static because it is exported to
other -tdep files. */
enum gdb_signal
linux_gdb_signal_from_target (struct gdbarch *gdbarch, int signal)
{
switch (signal)
{
case 0:
return GDB_SIGNAL_0;
case LINUX_SIGHUP:
return GDB_SIGNAL_HUP;
case LINUX_SIGINT:
return GDB_SIGNAL_INT;
case LINUX_SIGQUIT:
return GDB_SIGNAL_QUIT;
case LINUX_SIGILL:
return GDB_SIGNAL_ILL;
case LINUX_SIGTRAP:
return GDB_SIGNAL_TRAP;
case LINUX_SIGABRT:
return GDB_SIGNAL_ABRT;
case LINUX_SIGBUS:
return GDB_SIGNAL_BUS;
case LINUX_SIGFPE:
return GDB_SIGNAL_FPE;
case LINUX_SIGKILL:
return GDB_SIGNAL_KILL;
case LINUX_SIGUSR1:
return GDB_SIGNAL_USR1;
case LINUX_SIGSEGV:
return GDB_SIGNAL_SEGV;
case LINUX_SIGUSR2:
return GDB_SIGNAL_USR2;
case LINUX_SIGPIPE:
return GDB_SIGNAL_PIPE;
case LINUX_SIGALRM:
return GDB_SIGNAL_ALRM;
case LINUX_SIGTERM:
return GDB_SIGNAL_TERM;
case LINUX_SIGCHLD:
return GDB_SIGNAL_CHLD;
case LINUX_SIGCONT:
return GDB_SIGNAL_CONT;
case LINUX_SIGSTOP:
return GDB_SIGNAL_STOP;
case LINUX_SIGTSTP:
return GDB_SIGNAL_TSTP;
case LINUX_SIGTTIN:
return GDB_SIGNAL_TTIN;
case LINUX_SIGTTOU:
return GDB_SIGNAL_TTOU;
case LINUX_SIGURG:
return GDB_SIGNAL_URG;
case LINUX_SIGXCPU:
return GDB_SIGNAL_XCPU;
case LINUX_SIGXFSZ:
return GDB_SIGNAL_XFSZ;
case LINUX_SIGVTALRM:
return GDB_SIGNAL_VTALRM;
case LINUX_SIGPROF:
return GDB_SIGNAL_PROF;
case LINUX_SIGWINCH:
return GDB_SIGNAL_WINCH;
/* No way to differentiate between SIGIO and SIGPOLL.
Therefore, we just handle the first one. */
case LINUX_SIGIO:
return GDB_SIGNAL_IO;
case LINUX_SIGPWR:
return GDB_SIGNAL_PWR;
case LINUX_SIGSYS:
return GDB_SIGNAL_SYS;
/* SIGRTMIN and SIGRTMAX are not continuous in <gdb/signals.def>,
therefore we have to handle them here. */
case LINUX_SIGRTMIN:
return GDB_SIGNAL_REALTIME_32;
case LINUX_SIGRTMAX:
return GDB_SIGNAL_REALTIME_64;
}
if (signal >= LINUX_SIGRTMIN + 1 && signal <= LINUX_SIGRTMAX - 1)
{
int offset = signal - LINUX_SIGRTMIN + 1;
return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_33 + offset);
}
return GDB_SIGNAL_UNKNOWN;
}
/* Implementation of `gdbarch_gdb_signal_to_target', as defined in
gdbarch.h. This function is not static because it is exported to
other -tdep files. */
int
linux_gdb_signal_to_target (struct gdbarch *gdbarch,
enum gdb_signal signal)
{
switch (signal)
{
case GDB_SIGNAL_0:
return 0;
case GDB_SIGNAL_HUP:
return LINUX_SIGHUP;
case GDB_SIGNAL_INT:
return LINUX_SIGINT;
case GDB_SIGNAL_QUIT:
return LINUX_SIGQUIT;
case GDB_SIGNAL_ILL:
return LINUX_SIGILL;
case GDB_SIGNAL_TRAP:
return LINUX_SIGTRAP;
case GDB_SIGNAL_ABRT:
return LINUX_SIGABRT;
case GDB_SIGNAL_FPE:
return LINUX_SIGFPE;
case GDB_SIGNAL_KILL:
return LINUX_SIGKILL;
case GDB_SIGNAL_BUS:
return LINUX_SIGBUS;
case GDB_SIGNAL_SEGV:
return LINUX_SIGSEGV;
case GDB_SIGNAL_SYS:
return LINUX_SIGSYS;
case GDB_SIGNAL_PIPE:
return LINUX_SIGPIPE;
case GDB_SIGNAL_ALRM:
return LINUX_SIGALRM;
case GDB_SIGNAL_TERM:
return LINUX_SIGTERM;
case GDB_SIGNAL_URG:
return LINUX_SIGURG;
case GDB_SIGNAL_STOP:
return LINUX_SIGSTOP;
case GDB_SIGNAL_TSTP:
return LINUX_SIGTSTP;
case GDB_SIGNAL_CONT:
return LINUX_SIGCONT;
case GDB_SIGNAL_CHLD:
return LINUX_SIGCHLD;
case GDB_SIGNAL_TTIN:
return LINUX_SIGTTIN;
case GDB_SIGNAL_TTOU:
return LINUX_SIGTTOU;
case GDB_SIGNAL_IO:
return LINUX_SIGIO;
case GDB_SIGNAL_XCPU:
return LINUX_SIGXCPU;
case GDB_SIGNAL_XFSZ:
return LINUX_SIGXFSZ;
case GDB_SIGNAL_VTALRM:
return LINUX_SIGVTALRM;
case GDB_SIGNAL_PROF:
return LINUX_SIGPROF;
case GDB_SIGNAL_WINCH:
return LINUX_SIGWINCH;
case GDB_SIGNAL_USR1:
return LINUX_SIGUSR1;
case GDB_SIGNAL_USR2:
return LINUX_SIGUSR2;
case GDB_SIGNAL_PWR:
return LINUX_SIGPWR;
case GDB_SIGNAL_POLL:
return LINUX_SIGPOLL;
/* GDB_SIGNAL_REALTIME_32 is not continuous in <gdb/signals.def>,
therefore we have to handle it here. */
case GDB_SIGNAL_REALTIME_32:
return LINUX_SIGRTMIN;
/* Same comment applies to _64. */
case GDB_SIGNAL_REALTIME_64:
return LINUX_SIGRTMAX;
}
/* GDB_SIGNAL_REALTIME_33 to _64 are continuous. */
if (signal >= GDB_SIGNAL_REALTIME_33
&& signal <= GDB_SIGNAL_REALTIME_63)
{
int offset = signal - GDB_SIGNAL_REALTIME_33;
return LINUX_SIGRTMIN + 1 + offset;
}
return -1;
}
/* Helper for linux_vsyscall_range that does the real work of finding
the vsyscall's address range. */
static int
linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
{
char filename[100];
long pid;
if (target_auxv_search (target_stack, AT_SYSINFO_EHDR, &range->start) <= 0)
return 0;
/* It doesn't make sense to access the host's /proc when debugging a
core file. Instead, look for the PT_LOAD segment that matches
the vDSO. */
if (!target_has_execution)
{
Elf_Internal_Phdr *phdrs;
long phdrs_size;
int num_phdrs, i;
phdrs_size = bfd_get_elf_phdr_upper_bound (core_bfd);
if (phdrs_size == -1)
return 0;
phdrs = (Elf_Internal_Phdr *) alloca (phdrs_size);
num_phdrs = bfd_get_elf_phdrs (core_bfd, phdrs);
if (num_phdrs == -1)
return 0;
for (i = 0; i < num_phdrs; i++)
if (phdrs[i].p_type == PT_LOAD
&& phdrs[i].p_vaddr == range->start)
{
range->length = phdrs[i].p_memsz;
return 1;
}
return 0;
}
/* We need to know the real target PID to access /proc. */
if (current_inferior ()->fake_pid_p)
return 0;
pid = current_inferior ()->pid;
/* Note that reading /proc/PID/task/PID/maps (1) is much faster than
reading /proc/PID/maps (2). The later identifies thread stacks
in the output, which requires scanning every thread in the thread
group to check whether a VMA is actually a thread's stack. With
Linux 4.4 on an Intel i7-4810MQ @ 2.80GHz, with an inferior with
a few thousand threads, (1) takes a few miliseconds, while (2)
takes several seconds. Also note that "smaps", what we read for
determining core dump mappings, is even slower than "maps". */
xsnprintf (filename, sizeof filename, "/proc/%ld/task/%ld/maps", pid, pid);
gdb::unique_xmalloc_ptr<char> data
= target_fileio_read_stralloc (NULL, filename);
if (data != NULL)
{
char *line;
char *saveptr = NULL;
for (line = strtok_r (data.get (), "\n", &saveptr);
line != NULL;
line = strtok_r (NULL, "\n", &saveptr))
{
ULONGEST addr, endaddr;
const char *p = line;
addr = strtoulst (p, &p, 16);
if (addr == range->start)
{
if (*p == '-')
p++;
endaddr = strtoulst (p, &p, 16);
range->length = endaddr - addr;
return 1;
}
}
}
else
warning (_("unable to open /proc file '%s'"), filename);
return 0;
}
/* Implementation of the "vsyscall_range" gdbarch hook. Handles
caching, and defers the real work to linux_vsyscall_range_raw. */
static int
linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
{
struct linux_info *info = get_linux_inferior_data ();
if (info->vsyscall_range_p == 0)
{
if (linux_vsyscall_range_raw (gdbarch, &info->vsyscall_range))
info->vsyscall_range_p = 1;
else
info->vsyscall_range_p = -1;
}
if (info->vsyscall_range_p < 0)
return 0;
*range = info->vsyscall_range;
return 1;
}
/* Symbols for linux_infcall_mmap's ARG_FLAGS; their Linux MAP_* system
definitions would be dependent on compilation host. */
#define GDB_MMAP_MAP_PRIVATE 0x02 /* Changes are private. */
#define GDB_MMAP_MAP_ANONYMOUS 0x20 /* Don't use a file. */
/* See gdbarch.sh 'infcall_mmap'. */
static CORE_ADDR
linux_infcall_mmap (CORE_ADDR size, unsigned prot)
{
struct objfile *objf;
/* Do there still exist any Linux systems without "mmap64"?
"mmap" uses 64-bit off_t on x86_64 and 32-bit off_t on i386 and x32. */
struct value *mmap_val = find_function_in_inferior ("mmap64", &objf);
struct value *addr_val;
struct gdbarch *gdbarch = get_objfile_arch (objf);
CORE_ADDR retval;
enum
{
ARG_ADDR, ARG_LENGTH, ARG_PROT, ARG_FLAGS, ARG_FD, ARG_OFFSET, ARG_LAST
};
struct value *arg[ARG_LAST];
arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
0);
/* Assuming sizeof (unsigned long) == sizeof (size_t). */
arg[ARG_LENGTH] = value_from_ulongest
(builtin_type (gdbarch)->builtin_unsigned_long, size);
gdb_assert ((prot & ~(GDB_MMAP_PROT_READ | GDB_MMAP_PROT_WRITE
| GDB_MMAP_PROT_EXEC))
== 0);
arg[ARG_PROT] = value_from_longest (builtin_type (gdbarch)->builtin_int, prot);
arg[ARG_FLAGS] = value_from_longest (builtin_type (gdbarch)->builtin_int,
GDB_MMAP_MAP_PRIVATE
| GDB_MMAP_MAP_ANONYMOUS);
arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
0);
addr_val = call_function_by_hand (mmap_val, NULL, ARG_LAST, arg);
retval = value_as_address (addr_val);
if (retval == (CORE_ADDR) -1)
error (_("Failed inferior mmap call for %s bytes, errno is changed."),
pulongest (size));
return retval;
}
/* See gdbarch.sh 'infcall_munmap'. */
static void
linux_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
{
struct objfile *objf;
struct value *munmap_val = find_function_in_inferior ("munmap", &objf);
struct value *retval_val;
struct gdbarch *gdbarch = get_objfile_arch (objf);
LONGEST retval;
enum
{
ARG_ADDR, ARG_LENGTH, ARG_LAST
};
struct value *arg[ARG_LAST];
arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
addr);
/* Assuming sizeof (unsigned long) == sizeof (size_t). */
arg[ARG_LENGTH] = value_from_ulongest
(builtin_type (gdbarch)->builtin_unsigned_long, size);
retval_val = call_function_by_hand (munmap_val, NULL, ARG_LAST, arg);
retval = value_as_long (retval_val);
if (retval != 0)
warning (_("Failed inferior munmap call at %s for %s bytes, "
"errno is changed."),
hex_string (addr), pulongest (size));
}
/* See linux-tdep.h. */
CORE_ADDR
linux_displaced_step_location (struct gdbarch *gdbarch)
{
CORE_ADDR addr;
int bp_len;
/* Determine entry point from target auxiliary vector. This avoids
the need for symbols. Also, when debugging a stand-alone SPU
executable, entry_point_address () will point to an SPU
local-store address and is thus not usable as displaced stepping
location. The auxiliary vector gets us the PowerPC-side entry
point address instead. */
if (target_auxv_search (target_stack, AT_ENTRY, &addr) <= 0)
throw_error (NOT_SUPPORTED_ERROR,
_("Cannot find AT_ENTRY auxiliary vector entry."));
/* Make certain that the address points at real code, and not a
function descriptor. */
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
target_stack);
/* Inferior calls also use the entry point as a breakpoint location.
We don't want displaced stepping to interfere with those
breakpoints, so leave space. */
gdbarch_breakpoint_from_pc (gdbarch, &addr, &bp_len);
addr += bp_len * 2;
return addr;
}
/* Display whether the gcore command is using the
/proc/PID/coredump_filter file. */
static void
show_use_coredump_filter (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
" corefiles is %s.\n"), value);
}
/* Display whether the gcore command is dumping mappings marked with
the VM_DONTDUMP flag. */
static void
show_dump_excluded_mappings (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Dumping of mappings marked with the VM_DONTDUMP"
" flag is %s.\n"), value);
}
/* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types. */
void
linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
set_gdbarch_info_proc (gdbarch, linux_info_proc);
set_gdbarch_core_info_proc (gdbarch, linux_core_info_proc);
set_gdbarch_core_xfer_siginfo (gdbarch, linux_core_xfer_siginfo);
set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes);
set_gdbarch_has_shared_address_space (gdbarch,
linux_has_shared_address_space);
set_gdbarch_gdb_signal_from_target (gdbarch,
linux_gdb_signal_from_target);
set_gdbarch_gdb_signal_to_target (gdbarch,
linux_gdb_signal_to_target);
set_gdbarch_vsyscall_range (gdbarch, linux_vsyscall_range);
set_gdbarch_infcall_mmap (gdbarch, linux_infcall_mmap);
set_gdbarch_infcall_munmap (gdbarch, linux_infcall_munmap);
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
}
void
_initialize_linux_tdep (void)
{
linux_gdbarch_data_handle =
gdbarch_data_register_post_init (init_linux_gdbarch_data);
/* Set a cache per-inferior. */
linux_inferior_data
= register_inferior_data_with_cleanup (NULL, linux_inferior_data_cleanup);
/* Observers used to invalidate the cache when needed. */
gdb::observers::inferior_exit.attach (invalidate_linux_cache_inf);
gdb::observers::inferior_appeared.attach (invalidate_linux_cache_inf);
add_setshow_boolean_cmd ("use-coredump-filter", class_files,
&use_coredump_filter, _("\
Set whether gcore should consider /proc/PID/coredump_filter."),
_("\
Show whether gcore should consider /proc/PID/coredump_filter."),
_("\
Use this command to set whether gcore should consider the contents\n\
of /proc/PID/coredump_filter when generating the corefile. For more information\n\
about this file, refer to the manpage of core(5)."),
NULL, show_use_coredump_filter,
&setlist, &showlist);
add_setshow_boolean_cmd ("dump-excluded-mappings", class_files,
&dump_excluded_mappings, _("\
Set whether gcore should dump mappings marked with the VM_DONTDUMP flag."),
_("\
Show whether gcore should dump mappings marked with the VM_DONTDUMP flag."),
_("\
Use this command to set whether gcore should dump mappings marked with the\n\
VM_DONTDUMP flag (\"dd\" in /proc/PID/smaps) when generating the corefile. For\n\
more information about this file, refer to the manpage of proc(5) and core(5)."),
NULL, show_dump_excluded_mappings,
&setlist, &showlist);
}