diff options
Diffstat (limited to 'gdb/gdbserver')
31 files changed, 1704 insertions, 769 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 4ae5b33..a82dd86 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,395 @@ +2017-09-22 Simon Marchi <simon.marchi@ericsson.com> + + * win32-i386-low.c (i386_arch_setup): Call init_target_desc. + +2017-09-21 Kevin Buettner <kevinb@redhat.com> + + * linux-low.h (struct lwp_info): Add new field, thread_handle. + (thread_db_thread_handle): Declare. + * linux-low.c (linux_target_ops): Initialize thread_handle. + * server.c (handle_qxfer_threads_worker): Add support for + "handle" attribute. + * target.h (struct target_ops): Add new function pointer, + thread_handle. + (target_thread_handle): Define. + * thread-db.c (find_one_thread, attach_thread): Set thread_handle + field in lwp. + (thread_db_thread_handle): New function. + +2017-09-21 Kevin Buettner <kevinb@redhat.com> + + * linux-low.c (handle_extended_wait): Call thread_db_notice_clone(). + * linux-low.h (thread_db_notice_clone): Declare. + * thread-db.c (thread_db_notice_clone): New function. + +2017-09-21 Pedro Alves <palves@redhat.com> + + * server.c (gdb_read_memory, handle_status, process_serial_event) + (handle_serial_event, handle_target_event): Adjust to + set_desired_thread prototype change. + * target.c (set_desired_thread): Remove 'use_general' parameter + and adjust. + * target.h (set_desired_thread): Remove 'use_general' parameter. + +2017-09-20 Tom Tromey <tom@tromey.com> + + * target.c (target_terminal::terminal_state): Define. + (target_terminal::init): Rename from target_terminal_init. + (target_terminal::inferior): Rename from + target_terminal_inferior. + (target_terminal::ours): Rename from target_terminal_ours. + (target_terminal::ours_for_output, target_terminal::info): New. + +2017-09-16 Simon Marchi <simon.marchi@ericsson.com> + + * server.c (accumulate_file_name_length): Remove. + (emit_dll_description): Adjust to std::string change. + (handle_qxfer_libraries): Use std::string to hold document. + +2017-09-16 Simon Marchi <simon.marchi@ericsson.com> + + * linux-low.c (linux_qxfer_libraries_svr4): Adjust to change of + return type of xml_escape_text. + * server.c (emit_dll_description): Likewise. + +2017-09-16 Simon Marchi <simon.marchi@ericsson.com> + + * server.c (captured_main): Accept argument for --selftest. + Update run_tests call. + * linux-x86-tdesc-selftest.c (initialize_low_tdesc): Add names + when registering selftests. + +2017-09-16 Sergio Durigan Junior <sergiodj@redhat.com> + + * regcache.c (get_thread_regcache): Update code to use "std::vector" + instead of "VEC" for "target_desc.reg_defs". + (regcache_cpy): Likewise. + (registers_to_string): Likewise. + (registers_from_string): Likewise. + (find_regno): Likewise. + (supply_regblock): Likewise. + (regcache_raw_read_unsigned): Likewise. + * tdesc.c (init_target_desc): Likewise. + (tdesc_create_reg): Likewise. + * tdesc.h: Remove declaration of "tdesc_reg_p". Include <vector>. + (struct target_desc) <reg_defs>: Convert to "std::vector". + (target_desc): Do not initialize "reg_defs". + (~target_desc): Update code to use "std::vector" instead of "VEC" + for "target_desc.reg_defs". + (operator==): Likewise. + +2017-09-15 Simon Marchi <simon.marchi@ericsson.com> + + * inferiors.h (thread_to_gdb_id): Remove. + * inferiors.c (thread_to_gdb_id): Remove. + * server.c (handle_qxfer_threads_worker, handle_query): Adjust. + * lynx-low.c (lynx_resume, lynx_wait_1, lynx_fetch_registers, + lynx_store_registers, lynx_read_memory, lynx_write_memory): + Likewise. + * nto-low.c (nto_fetch_registers, nto_store_registers, + nto_stopped_by_watchpoint, nto_stopped_data_address): Likewise. + +2017-09-15 Simon Marchi <simon.marchi@ericsson.com> + + * inferiors.h (gdb_id_to_thread_id): Remove. + * inferiors.c (gdb_id_to_thread_id): Remove. + * server.c (process_serial_event): Adjust to gdb_id_to_thread_id + removal. Move pid declaration closer to where it's used. + +2017-09-15 Simon Marchi <simon.marchi@ericsson.com> + + * server.c (handle_detach): New function. + (process_serial_event): Move code out, call handle_detach. + +2017-09-15 Simon Marchi <simon.marchi@ericsson.com> + + * server.c (require_running): Rename to ... + (require_running_or_return): ... this ... + (require_running_or_break): ... and this. + (handle_query, process_serial_event): Adjust. + +2017-09-15 Simon Marchi <simon.marchi@ericsson.com> + + * linux-low.c (linux_set_resume_request): Remove unused + variables. + +2017-09-15 Simon Marchi <simon.marchi@ericsson.com> + + * server.c (first_thread_of): Remove. + (process_serial_event): Replace usage of first_thread_of with + find_any_thread_of_pid. + * tracepoint.c (same_process_p): Remove. + (gdb_agent_about_to_close): Replace usage of same_process_p with + find_any_thread_of_pid. + * linux-x86-low.c (same_process_callback): Remove. + (x86_arch_setup_process_callback): Replace usage of + same_process_callback with find_any_thread_of_pid. + * thread-db.c (any_thread_of): Remove. + (switch_to_process): Replace usage of any_thread_of with + find_any_thread_of_pid. + * inferiors.c (thread_pid_matches_callback): Remove. + (find_thread_process): Adjust to use find_any_thread_of_pid. + +2017-09-10 Sergio Durigan Junior <sergiodj@redhat.com> + + * regcache.c (get_thread_regcache): Guard calls to "memset" + with "!VEC_empty". + +2017-09-10 Sergio Durigan Junior <sergiodj@redhat.com> + + * linux-low.c (handle_extended_wait): Use + "allocate_target_description" instead of "XNEW". + * linux-x86-low.c (initialize_low_arch): Likewise. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * configure.srv (srv_i386_regobj): Remove. + (srv_amd64_regobj): Remove. + (srv_regobj): Set it to "" for x86 non-linux targets. + * linux-x86-tdesc.c (i386_linux_read_description): + * lynx-i386-low.c: Include x86-xstate.h and arch/i386.h. + (init_registers_i386): Remove the declaration. + (tdesc_i386): Remove the declaration. + (lynx_i386_arch_setup): Call i386_create_target_description. + * nto-x86-low.c: Likewise. + * win32-i386-low.c [__x86_64__]: include arch/amd64.h. + [!__x86_64__]: include arch/i386.h. + (i386_arch_setup) [__x86_64__]: Call amd64_create_target_description. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * configure.srv (srv_amd64_linux_xmlfiles): Remove + i386/amd64-XXX-linux from it. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * configure.srv: Empty srv_amd64_linux_regobj if $development is + false. + (ipa_amd64_linux_regobj): Remove. + (ipa_x32_linux_regobj): Remove. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * Makefile.in (arch-amd64.o): New rule. + * configure.srv: Append arch-amd64.o. + * linux-amd64-ipa.c: Include common/x86-xstate.h. + (get_ipa_tdesc): Call amd64_linux_read_description. + (initialize_low_tracepoint): Don't call init_registers_x32_XXX + and init_registers_amd64_XXX. + * linux-x86-low.c (x86_linux_read_description): Call + amd64_linux_read_description. + (x86_get_ipa_tdesc_idx): Call amd64_get_ipa_tdesc_idx. + (initialize_low_arch): Don't call init_registers_x32_XXX and + init_registers_amd64_XXX. + * linux-x86-tdesc-selftest.c: Declare init_registers_amd64_XXX + and tdesc_amd64_XXX. + [__x86_64__] (amd64_tdesc_test): New function. + (initialize_low_tdesc) [__x86_64__]: Call init_registers_x32_XXX + and init_registers_amd64_XXX. + * linux-x86-tdesc.c: Include arch/amd64.h. + (xcr0_to_tdesc_idx): New function. + (i386_linux_read_description): New function. + (amd64_get_ipa_tdesc_idx): New function. + * linux-x86-tdesc.h (amd64_get_ipa_tdesc_idx): Declare. + (amd64_get_ipa_tdesc): Declare. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * configure.srv (srv_i386_linux_xmlfiles): Remove + i386/i386-XXX-linux.xml from it. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * configure.srv: Set srv_i386_linux_regobj empty if $development + is false. + * linux-i386-ipa.c (initialize_low_tracepoint): Don't call + initialize_low_tdesc. + * linux-x86-low.c (initialize_low_arch): Wrap initialize_low_tdesc + with #if initialize_low_tdesc. + * linux-x86-tdesc-selftest.c: New file. + * linux-x86-tdesc.c: Move code to linux-x86-tdesc-selftest.c. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * Makefile.in (arch-i386.o): New rule. + * configure.srv (i[34567]86-*-linux*): Add arch-i386.o. + (x86_64-*-linux*): Likewise. + * linux-x86-tdesc.c: Don't include ../features/i386/32bit-XXX.c, + include arch/i386.h. + (i386_linux_read_description): Remove code and call + i386_create_target_description. + * tdesc.c (allocate_target_description): New function. + * tdesc.h (set_tdesc_architecture): Remove declaration. + (set_tdesc_osabi): Likewise. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * linux-x86-tdesc.c: Don't include <inttypes.h>. + (i386_linux_read_description) [!IN_PROCESS_AGENT]: Call + set_tdesc_architecture and set_tdesc_osabi. Remove code setting + .xmltarget. + * server.c (get_features_xml): Call tdesc_get_features_xml. + * tdesc.c (set_tdesc_architecture): New function. + (set_tdesc_osabi): New function. + (tdesc_get_features_xml): New function. + (tdesc_create_feature): Add an argument. + * tdesc.h (struct target_desc) <features>: New field. + <arch, osabi>: New field. + (~target_desc): xfree features, arch, and osabi. + (target_desc::oerator==): Don't compare .xmltarget. + [!IN_PROCESS_AGENT] (set_tdesc_architecture): Declare. + (set_tdesc_osabi): Likewise. + (tdesc_get_features_xml): Likewise. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * linux-x86-tdesc.c: Include selftest.h. + (i386_tdesc_test): New function. + (initialize_low_tdesc): Call selftests::register_test. + * tdesc.h: Include regdef.h. + (target_desc): Override operator == and !=. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * configure.srv (srv_tgtobj): Append linux-x86-tdesc.o. + (ipa_obj): Likewise. + * linux-i386-ipa.c: Include common/x86-xstate.h + (get_ipa_tdesc): Call i386_linux_read_description. + (initialize_low_tracepoint): Don't call init_registers_XXX + functions, call initialize_low_tdesc instead. + * linux-x86-low.c (x86_linux_read_description): Call + i386_linux_read_description. + (initialize_low_arch): Don't call init_registers_i386_XXX + functions, call initialize_low_tdesc. + * linux-x86-tdesc.c: New file. + * linux-x86-tdesc.h (x86_linux_tdesc): New X86_TDESC_LAST. + (i386_get_ipa_tdesc_idx): Declare. + (i386_get_ipa_tdesc): Declare. + (initialize_low_tdesc): Declare. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * linux-x86-low.c (x86_get_ipa_tdesc_idx): Use X86_TDESC_MMX + instead of 0. + +2017-09-05 Yao Qi <yao.qi@linaro.org> + + * Makefile.in (IPA_OBJS): Add vec-ipa.o + * regcache.c (get_thread_regcache): Use VEC_length. + (init_register_cache): Likewise. + (regcache_cpy): Likewise. + (registers_to_string): Iterate reg_defs via VEC_iterate. + (find_regno): Likewise. + (find_register_by_number): Use VEC_index. + (register_size): Call find_register_by_number. + (register_data): Call find_register_by_number. + (supply_regblock): Use VEC_length. + (regcache_raw_read_unsigned): Likewise. + * tdesc.c (init_target_desc): Iterate reg_defs via + VEC_iterate. + (default_description): Update initializer. + (copy_target_description): Don't update field num_registers. + * tdesc.h (struct target_desc) <reg_defs>: Change it to VEC. + <num_registers>: Remove. + +2017-09-04 Simon Marchi <simon.marchi@ericsson.com> + + * Makefile.in (.SECONDARY): Define target. + +2017-09-03 Simon Marchi <simon.marchi@ericsson.com> + + * linux-low.c (linux_wait_1): Adjust. + * server.c (queue_stop_reply_callback): Adjust. + +2017-08-31 Sergio Durigan Junior <sergiodj@redhat.com> + + * server.c (handle_general_set): Handle QEnvironmentHexEncoded, + QEnvironmentUnset and QEnvironmentReset packets. + (handle_query): Inform remote that QEnvironmentHexEncoded, + QEnvironmentUnset and QEnvironmentReset are supported. + +2017-08-25 Simon Marchi <simon.marchi@ericsson.com> + + * inferiors.h (inferior_target_data): Rename to ... + (thread_target_data): ... this. + (inferior_regcache_data): Rename to ... + (thread_regcache_data): ... this. + (set_inferior_regcache_data): Rename to ... + (set_thread_regcache_data): ... this. + * inferiors.c (inferior_target_data): Rename to ... + (thread_target_data): ... this. + (inferior_regcache_data): Rename to ... + (thread_regcache_data): ... this. + (set_inferior_regcache_data): Rename to ... + (set_thread_regcache_data): ... this. + (free_one_thread): Update. + * linux-low.h (get_thread_lwp): Update. + * regcache.c (get_thread_regcache): Update. + (regcache_invalidate_thread): Update. + (free_register_cache_thread): Update. + * win32-i386-low.c (update_debug_registers_callback): Update. + (win32_get_current_dr): Update. + * win32-low.c (thread_rec): Update. + (delete_thread_info): Update. + (continue_one_thread): Update. + (suspend_one_thread): Update. + +2017-08-24 Simon Marchi <simon.marchi@ericsson.com> + + * inferiors.c (set_inferior_target_data): Remove. + * inferiors.h (set_inferior_target_data): Remove. + +2017-08-18 Yao Qi <yao.qi@linaro.org> + + * Makefile.in (OBS): Add selftest.o. + * configure.ac: AC_DEFINE GDB_SELF_TEST if $development. + * configure, config.in: Re-generated. + * server.c: Include common/sefltest.h. + (captured_main): Handle option --selftest. + +2017-08-09 Yao Qi <yao.qi@linaro.org> + + * configure.srv (srv_i386_regobj): Remove i386-avx.o, + i386-avx-avx512.o, i386-avx-mpx-avx512-pku.o, i386-mpx.o, + i386-avx-mpx.o and i386-mmx.o. + (srv_amd64_regobj): Remove amd64-avx.o, amd64-avx-avx512.o, + amd64-avx-mpx-avx512-pku.o, amd64-mpx.o and amd64-avx-mpx.o. + (srv_i386_xmlfiles): Remove i386/i386-avx.xml, + i386/i386-avx-avx512.xml, i386/i386-avx-mpx-avx512-pku.xml, + i386/i386-mpx.xml, i386/i386-avx-mpx.xml and i386/i386-mmx.xml. + (srv_amd64_xmlfile):i386/amd64-avx.xml, i386/amd64-avx-avx512.xml, + i386/amd64-avx-mpx-avx512-pku.xml, i386/amd64-mpx.xml, + i386/amd64-avx-mpx.xml. + +2017-08-09 Yao Qi <yao.qi@linaro.org> + + * configure.srv (srv_amd64_regobj): Remove x32.o, x32-avx.o + and x32-avx-avx512.o. + (srv_amd64_xmlfiles): Remove i386/x32.xml, i386/x32-avx.xml + i386/x32-avx-avx512.xml. + +2017-07-26 Simon Marchi <simon.marchi@ericsson.com> + + * tracepoint.h (enum class fast_tpoint_collect_result): New + enumeration. + (fast_tracepoint_collecting): Change return type to + fast_tpoint_collect_result. + * tracepoint.c (fast_tracepoint_collecting): Likewise. + * linux-low.h: Include tracepoint.h. + (struct lwp_info) <collecting_fast_tracepoint>: Change type to + fast_tpoint_collect_result. + * linux-low.c (handle_tracepoints): Adjust. + (linux_fast_tracepoint_collecting): Change return type to + fast_tpoint_collect_result. + (maybe_move_out_of_jump_pad, linux_wait_for_event_filtered, + linux_wait_1, stuck_in_jump_pad_callback, + lwp_signal_can_be_delivered, linux_resume_one_lwp_throw, + proceed_one_lwp): Adjust to type change. + +2017-07-10 Yao Qi <yao.qi@linaro.org> + + * linux-x86-low.c (x86_linux_read_description): Re-indent the code. + 2017-06-29 Yao Qi <yao.qi@linaro.org> * tdesc.h (struct target_desc) [IN_PROCESS_AGENT] <expedite_regs>: diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 4e0080e..1bbe515 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -258,6 +258,7 @@ OBS = \ regcache.o \ remote-utils.o \ rsp-low.o \ + selftest.o \ server.o \ signals.o \ signals-state-save-restore.o \ @@ -399,6 +400,7 @@ IPA_OBJS = \ tdesc-ipa.o \ tracepoint-ipa.o \ utils-ipa.o \ + vec-ipa.o \ ${IPA_DEPFILES} IPA_LIB = libinproctrace.so @@ -526,6 +528,14 @@ ax.o: ax.c $(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $< $(POSTCOMPILE) +arch-i386.o: ../arch/i386.c + $(COMPILE) $< + $(POSTCOMPILE) + +arch-amd64.o: ../arch/amd64.c + $(COMPILE) $< + $(POSTCOMPILE) + # Rules for objects that go in the in-process agent. %-ipa.o: %-generated.c @@ -551,6 +561,10 @@ ax.o: ax.c $(IPAGENT_COMPILE) $< $(POSTCOMPILE) +%-ipa.o: ../arch/%.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + # Rules for objects that go in the gdbserver binary. %.o: %-generated.c @@ -631,4 +645,7 @@ endif # Disable implicit make rules. include $(srcdir)/../disable-implicit-rules.mk +# Do not delete intermediate files (e.g. *-generated.c). +.SECONDARY: + # This is the end of "Makefile.in". diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in index 34a7443..5dacbac 100644 --- a/gdb/gdbserver/config.in +++ b/gdb/gdbserver/config.in @@ -8,6 +8,9 @@ /* Define to 1 if using `alloca.c'. */ #undef C_ALLOCA +/* Define if self-testing features should be enabled */ +#undef GDB_SELF_TEST + /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure index 35aeabc..30aa95b 100755 --- a/gdb/gdbserver/configure +++ b/gdb/gdbserver/configure @@ -5813,6 +5813,12 @@ fi fi +if $development; then + +$as_echo "#define GDB_SELF_TEST 1" >>confdefs.h + +fi + case ${build_alias} in "") build_noncanonical=${build} ;; *) build_noncanonical=${build_alias} ;; diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index 4ea7913..36e21c5 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -56,6 +56,11 @@ else fi GDB_AC_LIBMCHECK(${libmcheck_default}) +if $development; then + AC_DEFINE(GDB_SELF_TEST, 1, + [Define if self-testing features should be enabled]) +fi + ACX_NONCANONICAL_TARGET ACX_NONCANONICAL_HOST diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 43f90c9..2a0c2b2 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -24,21 +24,22 @@ # Default hostio_last_error implementation srv_hostio_err_objs="hostio-errno.o" -srv_i386_regobj="i386.o i386-avx.o i386-avx-avx512.o i386-avx-mpx-avx512-pku.o i386-mpx.o i386-avx-mpx.o i386-mmx.o" -srv_i386_linux_regobj="i386-linux.o i386-avx-linux.o i386-avx-avx512-linux.o i386-avx-mpx-avx512-pku-linux.o i386-mpx-linux.o i386-avx-mpx-linux.o i386-mmx-linux.o" -srv_amd64_regobj="amd64.o amd64-avx.o amd64-avx-avx512.o amd64-avx-mpx-avx512-pku.o amd64-mpx.o amd64-avx-mpx.o x32.o x32-avx.o x32-avx-avx512.o" -srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o amd64-avx-avx512-linux.o amd64-avx-mpx-avx512-pku-linux.o amd64-mpx-linux.o amd64-avx-mpx-linux.o x32-linux.o x32-avx-linux.o x32-avx-avx512-linux.o" +if $development; then + srv_i386_linux_regobj="i386-linux.o i386-avx-linux.o i386-avx-avx512-linux.o i386-avx-mpx-avx512-pku-linux.o i386-mpx-linux.o i386-avx-mpx-linux.o i386-mmx-linux.o linux-x86-tdesc-selftest.o" + srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o amd64-avx-avx512-linux.o amd64-avx-mpx-avx512-pku-linux.o amd64-mpx-linux.o amd64-avx-mpx-linux.o x32-linux.o x32-avx-linux.o x32-avx-avx512-linux.o" +else + srv_i386_linux_regobj="" + srv_amd64_linux_regobj="" +fi -ipa_i386_linux_regobj="i386-linux-ipa.o i386-avx-linux-ipa.o i386-avx-mpx-linux-ipa.o i386-avx-avx512-linux-ipa.o i386-avx-mpx-avx512-pku-linux-ipa.o i386-mpx-linux-ipa.o i386-mmx-linux-ipa.o" -ipa_amd64_linux_regobj="amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx-mpx-linux-ipa.o amd64-avx-avx512-linux-ipa.o amd64-avx-mpx-avx512-pku-linux-ipa.o amd64-mpx-linux-ipa.o" ipa_ppc_linux_regobj="powerpc-32l-ipa.o powerpc-altivec32l-ipa.o powerpc-cell32l-ipa.o powerpc-vsx32l-ipa.o powerpc-isa205-32l-ipa.o powerpc-isa205-altivec32l-ipa.o powerpc-isa205-vsx32l-ipa.o powerpc-e500l-ipa.o powerpc-64l-ipa.o powerpc-altivec64l-ipa.o powerpc-cell64l-ipa.o powerpc-vsx64l-ipa.o powerpc-isa205-64l-ipa.o powerpc-isa205-altivec64l-ipa.o powerpc-isa205-vsx64l-ipa.o" srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml i386/32bit-avx512.xml i386/32bit-mpx.xml i386/32bit-pkeys.xml" srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-segments.xml i386/64bit-sse.xml i386/64bit-avx.xml i386/64bit-avx512.xml i386/x32-core.xml i386/64bit-mpx.xml i386/64bit-pkeys.xml" -srv_i386_xmlfiles="i386/i386.xml i386/i386-avx.xml i386/i386-avx-avx512.xml i386/i386-avx-mpx-avx512-pku.xml i386/i386-mpx.xml i386/i386-avx-mpx.xml i386/i386-mmx.xml $srv_i386_32bit_xmlfiles" -srv_amd64_xmlfiles="i386/amd64.xml i386/amd64-avx.xml i386/amd64-avx-avx512.xml i386/amd64-avx-mpx-avx512-pku.xml i386/x32.xml i386/x32-avx.xml i386/x32-avx-avx512.xml i386/amd64-mpx.xml i386/amd64-avx-mpx.xml $srv_i386_64bit_xmlfiles" -srv_i386_linux_xmlfiles="i386/i386-linux.xml i386/i386-avx-linux.xml i386/i386-avx-avx512-linux.xml i386/i386-avx-mpx-avx512-pku-linux.xml i386/i386-mmx-linux.xml i386/32bit-linux.xml i386/i386-mpx-linux.xml i386/i386-avx-mpx-linux.xml $srv_i386_32bit_xmlfiles" -srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd64-avx-avx512.xml i386/amd64-avx-mpx-avx512-pku-linux.xml i386/64bit-linux.xml i386/amd64-mpx-linux.xml i386/amd64-avx-mpx-linux.xml i386/x32-linux.xml i386/x32-avx-linux.xml i386/x32-avx-avx512-linux.xml $srv_i386_64bit_xmlfiles" +srv_i386_xmlfiles="i386/i386.xml $srv_i386_32bit_xmlfiles" +srv_amd64_xmlfiles="i386/amd64.xml $srv_i386_64bit_xmlfiles" +srv_i386_linux_xmlfiles="i386/32bit-linux.xml $srv_i386_32bit_xmlfiles" +srv_amd64_linux_xmlfiles="i386/64bit-linux.xml $srv_i386_64bit_xmlfiles" # Linux object files. This is so we don't have to repeat @@ -110,8 +111,9 @@ case "${target}" in srv_linux_usrregs=yes srv_linux_thread_db=yes ;; - i[34567]86-*-cygwin*) srv_regobj="$srv_i386_regobj" + i[34567]86-*-cygwin*) srv_regobj="" srv_tgtobj="x86-low.o x86-dregs.o win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch-i386.o" srv_xmlfiles="$srv_i386_xmlfiles" ;; i[34567]86-*-linux*) srv_regobj="$srv_i386_linux_regobj" @@ -121,25 +123,30 @@ case "${target}" in srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles" srv_tgtobj="amd64-linux-siginfo.o" fi + srv_tgtobj="${srv_tgtobj} arch-i386.o" srv_tgtobj="${srv_tgtobj} $srv_linux_obj linux-x86-low.o x86-low.o x86-dregs.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o" srv_tgtobj="${srv_tgtobj} linux-btrace.o x86-linux.o" srv_tgtobj="${srv_tgtobj} x86-linux-dregs.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes srv_linux_btrace=yes - ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o" + ipa_obj="linux-i386-ipa.o linux-x86-tdesc-ipa.o" + ipa_obj="${ipa_obj} i386-ipa.o" ;; - i[34567]86-*-lynxos*) srv_regobj="i386.o" + i[34567]86-*-lynxos*) srv_regobj="" srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o fork-inferior.o" + srv_tgtobj="${srv_tgtobj} arch-i386.o" srv_xmlfiles="i386/i386.xml" srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml" srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml" srv_lynxos=yes ;; i[34567]86-*-mingw32ce*) - srv_regobj="$srv_i386_regobj" + srv_regobj="" srv_tgtobj="x86-low.o x86-dregs.o win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch-i386.o" srv_tgtobj="${srv_tgtobj} wincecompat.o" srv_xmlfiles="$srv_i386_xmlfiles" # hostio_last_error implementation is in win32-low.c @@ -147,13 +154,14 @@ case "${target}" in srv_mingw=yes srv_mingwce=yes ;; - i[34567]86-*-mingw*) srv_regobj="$srv_i386_regobj" + i[34567]86-*-mingw*) srv_regobj="" srv_tgtobj="x86-low.o x86-dregs.o win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch-i386.o" srv_xmlfiles="$srv_i386_xmlfiles" srv_mingw=yes ;; - i[34567]86-*-nto*) srv_regobj="$srv_i386_regobj" - srv_tgtobj="nto-low.o nto-x86-low.o" + i[34567]86-*-nto*) srv_regobj="" + srv_tgtobj="nto-low.o nto-x86-low.o arch-i386.o" srv_xmlfiles="$srv_i386_xmlfiles" srv_qnx="yes" ;; @@ -356,6 +364,8 @@ case "${target}" in ;; x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj" srv_tgtobj="$srv_linux_obj linux-x86-low.o x86-low.o x86-dregs.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} arch-i386.o arch-amd64.o" + srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o" srv_tgtobj="${srv_tgtobj} linux-btrace.o x86-linux.o" srv_tgtobj="${srv_tgtobj} x86-linux-dregs.o" srv_tgtobj="${srv_tgtobj} amd64-linux-siginfo.o" @@ -364,20 +374,18 @@ case "${target}" in srv_linux_regsets=yes srv_linux_thread_db=yes srv_linux_btrace=yes - if test "$gdb_cv_x86_is_x32" = yes ; then - ipa_obj="${ipa_x32_linux_regobj}" - else - ipa_obj="${ipa_amd64_linux_regobj}" - fi - ipa_obj="${ipa_obj} linux-amd64-ipa.o" + ipa_obj="linux-amd64-ipa.o linux-x86-tdesc-ipa.o" + ipa_obj="${ipa_obj} amd64-ipa.o" ;; - x86_64-*-mingw*) srv_regobj="$srv_amd64_regobj" + x86_64-*-mingw*) srv_regobj="" srv_tgtobj="x86-low.o x86-dregs.o i387-fp.o win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch-amd64.o" srv_xmlfiles="$srv_i386_xmlfiles $srv_amd64_xmlfiles" srv_mingw=yes ;; - x86_64-*-cygwin*) srv_regobj="$srv_amd64_regobj" + x86_64-*-cygwin*) srv_regobj="" srv_tgtobj="x86-low.o x86-dregs.o i387-fp.o win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch-amd64.o" srv_xmlfiles="$srv_i386_xmlfiles" ;; diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 5a4a0d1..72f0412 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -121,12 +121,6 @@ add_thread (ptid_t thread_id, void *target_data) return new_thread; } -ptid_t -thread_to_gdb_id (struct thread_info *thread) -{ - return thread->entry.id; -} - /* Wrapper around get_first_inferior to return a struct thread_info *. */ struct thread_info * @@ -141,25 +135,13 @@ find_thread_ptid (ptid_t ptid) return (struct thread_info *) find_inferior_id (&all_threads, ptid); } -/* Predicate function for matching thread entry's pid to the given - pid value passed by address in ARGS. */ - -static int -thread_pid_matches_callback (struct inferior_list_entry *entry, void *args) -{ - return (ptid_get_pid (entry->id) == *(pid_t *)args); -} - /* Find a thread associated with the given PROCESS, or NULL if no such thread exists. */ static struct thread_info * find_thread_process (const struct process_info *const process) { - pid_t pid = ptid_get_pid (ptid_of (process)); - - return (struct thread_info *) - find_inferior (&all_threads, thread_pid_matches_callback, &pid); + return find_any_thread_of_pid (process->entry.id.pid ()); } /* Helper for find_any_thread_of_pid. Returns true if a thread @@ -185,19 +167,11 @@ find_any_thread_of_pid (int pid) return (struct thread_info *) entry; } -ptid_t -gdb_id_to_thread_id (ptid_t gdb_id) -{ - struct thread_info *thread = find_thread_ptid (gdb_id); - - return thread ? thread->entry.id : null_ptid; -} - static void free_one_thread (struct inferior_list_entry *inf) { struct thread_info *thread = get_thread (inf); - free_register_cache (inferior_regcache_data (thread)); + free_register_cache (thread_regcache_data (thread)); free (thread); } @@ -309,27 +283,21 @@ find_inferior_id (struct inferior_list *list, ptid_t id) } void * -inferior_target_data (struct thread_info *inferior) -{ - return inferior->target_data; -} - -void -set_inferior_target_data (struct thread_info *inferior, void *data) +thread_target_data (struct thread_info *thread) { - inferior->target_data = data; + return thread->target_data; } struct regcache * -inferior_regcache_data (struct thread_info *inferior) +thread_regcache_data (struct thread_info *thread) { - return inferior->regcache_data; + return thread->regcache_data; } void -set_inferior_regcache_data (struct thread_info *inferior, struct regcache *data) +set_thread_regcache_data (struct thread_info *thread, struct regcache *data) { - inferior->regcache_data = data; + thread->regcache_data = data; } /* Return true if LIST has exactly one entry. */ diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h index 2290a63..aef8433 100644 --- a/gdb/gdbserver/inferiors.h +++ b/gdb/gdbserver/inferiors.h @@ -143,9 +143,6 @@ struct process_info *find_process_pid (int pid); int have_started_inferiors_p (void); int have_attached_inferiors_p (void); -ptid_t thread_to_gdb_id (struct thread_info *); -ptid_t gdb_id_to_thread_id (ptid_t); - void clear_inferiors (void); struct inferior_list_entry *find_inferior (struct inferior_list *, @@ -160,9 +157,8 @@ struct inferior_list_entry * void *), void *arg); -void *inferior_target_data (struct thread_info *); -void set_inferior_target_data (struct thread_info *, void *); -struct regcache *inferior_regcache_data (struct thread_info *); -void set_inferior_regcache_data (struct thread_info *, struct regcache *); +void *thread_target_data (struct thread_info *); +struct regcache *thread_regcache_data (struct thread_info *); +void set_thread_regcache_data (struct thread_info *, struct regcache *); #endif /* INFERIORS_H */ diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c index 67f36c2..85d0d45 100644 --- a/gdb/gdbserver/linux-amd64-ipa.c +++ b/gdb/gdbserver/linux-amd64-ipa.c @@ -22,6 +22,7 @@ #include <sys/mman.h> #include "tracepoint.h" #include "linux-x86-tdesc.h" +#include "common/x86-xstate.h" /* Defined in auto-generated file amd64-linux.c. */ void init_registers_amd64_linux (void); @@ -174,38 +175,37 @@ supply_static_tracepoint_registers (struct regcache *regcache, const struct target_desc * get_ipa_tdesc (int idx) { -#if defined __ILP32__ - switch (idx) + if (idx >= X86_TDESC_LAST) { - case X86_TDESC_SSE: - return tdesc_x32_linux; - case X86_TDESC_AVX: - return tdesc_x32_avx_linux; - case X86_TDESC_AVX512: - return tdesc_x32_avx512_linux; - default: - break; + internal_error (__FILE__, __LINE__, + "unknown ipa tdesc index: %d", idx); } -#else + +#if defined __ILP32__ switch (idx) { case X86_TDESC_SSE: - return tdesc_amd64_linux; + return amd64_linux_read_description (X86_XSTATE_SSE_MASK, true); case X86_TDESC_AVX: - return tdesc_amd64_avx_linux; - case X86_TDESC_MPX: - return tdesc_amd64_mpx_linux; - case X86_TDESC_AVX_MPX: - return tdesc_amd64_avx_mpx_linux; - case X86_TDESC_AVX_MPX_AVX512_PKU: - return tdesc_amd64_avx_mpx_avx512_pku_linux; + return amd64_linux_read_description (X86_XSTATE_AVX_MASK, true); case X86_TDESC_AVX_AVX512: - return tdesc_amd64_avx_avx512_linux; + return amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true); default: - internal_error (__FILE__, __LINE__, - "unknown ipa tdesc index: %d", idx); - return tdesc_amd64_linux; + break; } +#else + /* Map the tdesc index to xcr0 mask. */ + uint64_t idx2mask[X86_TDESC_LAST] = { + X86_XSTATE_X87_MASK, + X86_XSTATE_SSE_MASK, + X86_XSTATE_AVX_MASK, + X86_XSTATE_MPX_MASK, + X86_XSTATE_AVX_MPX_MASK, + X86_XSTATE_AVX_AVX512_MASK, + X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, + }; + + return amd64_linux_read_description (idx2mask[idx], false); #endif internal_error (__FILE__, __LINE__, @@ -276,16 +276,4 @@ alloc_jump_pad_buffer (size_t size) void initialize_low_tracepoint (void) { -#if defined __ILP32__ - init_registers_x32_linux (); - init_registers_x32_avx_linux (); - init_registers_x32_avx512_linux (); -#else - init_registers_amd64_linux (); - init_registers_amd64_avx_linux (); - init_registers_amd64_mpx_linux (); - init_registers_amd64_avx_mpx_linux (); - init_registers_amd64_avx_avx512_linux (); - init_registers_amd64_avx_mpx_avx512_pku_linux (); -#endif } diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c index e9ac78b..785a63e 100644 --- a/gdb/gdbserver/linux-i386-ipa.c +++ b/gdb/gdbserver/linux-i386-ipa.c @@ -22,6 +22,7 @@ #include <sys/mman.h> #include "tracepoint.h" #include "linux-x86-tdesc.h" +#include "common/x86-xstate.h" /* GDB register numbers. */ @@ -250,27 +251,24 @@ initialize_fast_tracepoint_trampoline_buffer (void) const struct target_desc * get_ipa_tdesc (int idx) { - switch (idx) + if (idx >= X86_TDESC_LAST) { - case X86_TDESC_MMX: - return tdesc_i386_mmx_linux; - case X86_TDESC_SSE: - return tdesc_i386_linux; - case X86_TDESC_AVX: - return tdesc_i386_avx_linux; - case X86_TDESC_MPX: - return tdesc_i386_mpx_linux; - case X86_TDESC_AVX_MPX: - return tdesc_i386_avx_mpx_linux; - case X86_TDESC_AVX_AVX512: - return tdesc_i386_avx_avx512_linux; - case X86_TDESC_AVX_MPX_AVX512_PKU: - return tdesc_i386_avx_mpx_avx512_pku_linux; - default: internal_error (__FILE__, __LINE__, "unknown ipa tdesc index: %d", idx); - return tdesc_i386_linux; } + + /* Map the tdesc index to xcr0 mask. */ + uint64_t idx2mask[X86_TDESC_LAST] = { + X86_XSTATE_X87_MASK, + X86_XSTATE_SSE_MASK, + X86_XSTATE_AVX_MASK, + X86_XSTATE_MPX_MASK, + X86_XSTATE_AVX_MPX_MASK, + X86_XSTATE_AVX_AVX512_MASK, + X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, + }; + + return i386_linux_read_description (idx2mask[idx]); } /* Allocate buffer for the jump pads. On i386, we can reach an arbitrary @@ -291,12 +289,5 @@ alloc_jump_pad_buffer (size_t size) void initialize_low_tracepoint (void) { - init_registers_i386_mmx_linux (); - init_registers_i386_linux (); - init_registers_i386_avx_linux (); - init_registers_i386_mpx_linux (); - init_registers_i386_avx_avx512_linux (); - init_registers_i386_avx_mpx_avx512_pku_linux (); - initialize_fast_tracepoint_trampoline_buffer (); } diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 3d7cfe3..c62dc19 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -570,7 +570,7 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) clone_all_breakpoints (child_thr, event_thr); - tdesc = XNEW (struct target_desc); + tdesc = allocate_target_description (); copy_target_description (tdesc, parent_proc->tdesc); child_proc->tdesc = tdesc; @@ -656,6 +656,8 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) new_lwp->status_pending = status; } + thread_db_notice_clone (get_thread_process (event_thr), ptid); + /* Don't report the event. */ return 1; } @@ -2082,7 +2084,9 @@ handle_tracepoints (struct lwp_info *lwp) lwp_suspended_decr (lwp); gdb_assert (lwp->suspended == 0); - gdb_assert (!stabilizing_threads || lwp->collecting_fast_tracepoint); + gdb_assert (!stabilizing_threads + || (lwp->collecting_fast_tracepoint + != fast_tpoint_collect_result::not_collecting)); if (tpoint_related_event) { @@ -2094,10 +2098,10 @@ handle_tracepoints (struct lwp_info *lwp) return 0; } -/* Convenience wrapper. Returns true if LWP is presently collecting a - fast tracepoint. */ +/* Convenience wrapper. Returns information about LWP's fast tracepoint + collection status. */ -static int +static fast_tpoint_collect_result linux_fast_tracepoint_collecting (struct lwp_info *lwp, struct fast_tpoint_collect_status *status) { @@ -2105,14 +2109,14 @@ linux_fast_tracepoint_collecting (struct lwp_info *lwp, struct thread_info *thread = get_lwp_thread (lwp); if (the_low_target.get_thread_area == NULL) - return 0; + return fast_tpoint_collect_result::not_collecting; /* Get the thread area address. This is used to recognize which thread is which when tracing with the in-process agent library. We don't read anything from the address, and treat it as opaque; it's the address itself that we assume is unique per-thread. */ if ((*the_low_target.get_thread_area) (lwpid_of (thread), &thread_area) == -1) - return 0; + return fast_tpoint_collect_result::not_collecting; return fast_tracepoint_collecting (thread_area, lwp->stop_pc, status); } @@ -2136,14 +2140,14 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) && agent_loaded_p ()) { struct fast_tpoint_collect_status status; - int r; if (debug_threads) debug_printf ("Checking whether LWP %ld needs to move out of the " "jump pad.\n", lwpid_of (current_thread)); - r = linux_fast_tracepoint_collecting (lwp, &status); + fast_tpoint_collect_result r + = linux_fast_tracepoint_collecting (lwp, &status); if (wstat == NULL || (WSTOPSIG (*wstat) != SIGILL @@ -2153,9 +2157,10 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) { lwp->collecting_fast_tracepoint = r; - if (r != 0) + if (r != fast_tpoint_collect_result::not_collecting) { - if (r == 1 && lwp->exit_jump_pad_bkpt == NULL) + if (r == fast_tpoint_collect_result::before_insn + && lwp->exit_jump_pad_bkpt == NULL) { /* Haven't executed the original instruction yet. Set breakpoint there, and wait till it's hit, @@ -2181,9 +2186,10 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) reporting to GDB. Otherwise, it's an IPA lib bug: just report the signal to GDB, and pray for the best. */ - lwp->collecting_fast_tracepoint = 0; + lwp->collecting_fast_tracepoint + = fast_tpoint_collect_result::not_collecting; - if (r != 0 + if (r != fast_tpoint_collect_result::not_collecting && (status.adjusted_insn_addr <= lwp->stop_pc && lwp->stop_pc < status.adjusted_insn_addr_end)) { @@ -2715,7 +2721,8 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, if (stopping_threads == NOT_STOPPING_THREADS && requested_child->status_pending_p - && requested_child->collecting_fast_tracepoint) + && (requested_child->collecting_fast_tracepoint + != fast_tpoint_collect_result::not_collecting)) { enqueue_one_deferred_signal (requested_child, &requested_child->status_pending); @@ -3467,20 +3474,22 @@ linux_wait_1 (ptid_t ptid, } } - if (event_child->collecting_fast_tracepoint) + if (event_child->collecting_fast_tracepoint + != fast_tpoint_collect_result::not_collecting) { if (debug_threads) debug_printf ("LWP %ld was trying to move out of the jump pad (%d). " "Check if we're already there.\n", lwpid_of (current_thread), - event_child->collecting_fast_tracepoint); + (int) event_child->collecting_fast_tracepoint); trace_event = 1; event_child->collecting_fast_tracepoint = linux_fast_tracepoint_collecting (event_child, NULL); - if (event_child->collecting_fast_tracepoint != 1) + if (event_child->collecting_fast_tracepoint + != fast_tpoint_collect_result::before_insn) { /* No longer need this breakpoint. */ if (event_child->exit_jump_pad_bkpt != NULL) @@ -3507,7 +3516,8 @@ linux_wait_1 (ptid_t ptid, } } - if (event_child->collecting_fast_tracepoint == 0) + if (event_child->collecting_fast_tracepoint + == fast_tpoint_collect_result::not_collecting) { if (debug_threads) debug_printf ("fast tracepoint finished " @@ -3725,12 +3735,11 @@ linux_wait_1 (ptid_t ptid, { if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) { - char *str; + std::string str + = target_waitstatus_to_string (&event_child->waitstatus); - str = target_waitstatus_to_string (&event_child->waitstatus); debug_printf ("LWP %ld: extended event with waitstatus %s\n", - lwpid_of (get_lwp_thread (event_child)), str); - xfree (str); + lwpid_of (get_lwp_thread (event_child)), str.c_str ()); } if (current_thread->last_resume_kind == resume_step) { @@ -4192,7 +4201,8 @@ stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data) && (gdb_breakpoint_here (lwp->stop_pc) || lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT || thread->last_resume_kind == resume_step) - && linux_fast_tracepoint_collecting (lwp, NULL)); + && (linux_fast_tracepoint_collecting (lwp, NULL) + != fast_tpoint_collect_result::not_collecting)); } static void @@ -4369,7 +4379,8 @@ single_step (struct lwp_info* lwp) static int lwp_signal_can_be_delivered (struct lwp_info *lwp) { - return !lwp->collecting_fast_tracepoint; + return (lwp->collecting_fast_tracepoint + == fast_tpoint_collect_result::not_collecting); } /* Resume execution of LWP. If STEP is nonzero, single-step it. If @@ -4381,7 +4392,6 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, { struct thread_info *thread = get_lwp_thread (lwp); struct thread_info *saved_thread; - int fast_tp_collecting; int ptrace_request; struct process_info *proc = get_thread_process (thread); @@ -4397,9 +4407,12 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, gdb_assert (lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); - fast_tp_collecting = lwp->collecting_fast_tracepoint; + fast_tpoint_collect_result fast_tp_collecting + = lwp->collecting_fast_tracepoint; - gdb_assert (!stabilizing_threads || fast_tp_collecting); + gdb_assert (!stabilizing_threads + || (fast_tp_collecting + != fast_tpoint_collect_result::not_collecting)); /* Cancel actions that rely on GDB not changing the PC (e.g., the user used the "jump" command, or "set $pc = foo"). */ @@ -4455,7 +4468,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, if (can_hardware_single_step ()) { - if (fast_tp_collecting == 0) + if (fast_tp_collecting == fast_tpoint_collect_result::not_collecting) { if (step == 0) warning ("BAD - reinserting but not stepping."); @@ -4468,14 +4481,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, step = maybe_hw_step (thread); } - if (fast_tp_collecting == 1) + if (fast_tp_collecting == fast_tpoint_collect_result::before_insn) { if (debug_threads) debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad" " (exit-jump-pad-bkpt)\n", lwpid_of (thread)); } - else if (fast_tp_collecting == 2) + else if (fast_tp_collecting == fast_tpoint_collect_result::at_insn) { if (debug_threads) debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad" @@ -4700,7 +4713,6 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg) does not yet know are new fork children. */ if (lwp->fork_relative != NULL) { - struct inferior_list_entry *inf, *tmp; struct lwp_info *rel = lwp->fork_relative; if (rel->status_pending_p @@ -5294,7 +5306,8 @@ proceed_one_lwp (struct inferior_list_entry *entry, void *except) if (thread->last_resume_kind == resume_stop && lwp->pending_signals_to_report == NULL - && lwp->collecting_fast_tracepoint == 0) + && (lwp->collecting_fast_tracepoint + == fast_tpoint_collect_result::not_collecting)) { /* We haven't reported this LWP as stopped yet (otherwise, the last_status.kind check above would catch it, and we wouldn't @@ -7277,7 +7290,6 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, { /* 6x the size for xml_escape_text below. */ size_t len = 6 * strlen ((char *) libname); - char *name; if (!header_done) { @@ -7296,12 +7308,11 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, p = document + document_len; } - name = xml_escape_text ((char *) libname); + std::string name = xml_escape_text ((char *) libname); p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" " "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>", - name, (unsigned long) lm_addr, + name.c_str (), (unsigned long) lm_addr, (unsigned long) l_addr, (unsigned long) l_ld); - free (name); } } @@ -7694,6 +7705,11 @@ static struct target_ops linux_target_ops = { linux_supports_software_single_step, linux_supports_catch_syscall, linux_get_ipa_tdesc_idx, +#if USE_THREAD_DB + thread_db_thread_handle, +#else + NULL, +#endif }; #ifdef HAVE_LINUX_REGSETS diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 6328da0..85bb8ca 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -26,6 +26,7 @@ /* Included for ptrace type definitions. */ #include "nat/linux-ptrace.h" #include "target/waitstatus.h" /* For enum target_stop_reason. */ +#include "tracepoint.h" #define PTRACE_XFER_TYPE long @@ -251,7 +252,7 @@ struct linux_target_ops extern struct linux_target_ops the_low_target; -#define get_thread_lwp(thr) ((struct lwp_info *) (inferior_target_data (thr))) +#define get_thread_lwp(thr) ((struct lwp_info *) (thread_target_data (thr))) #define get_lwp_thread(lwp) ((lwp)->thread) /* This struct is recorded in the target_data field of struct thread_info. @@ -353,12 +354,11 @@ struct lwp_info and then processed and cleared in linux_resume_one_lwp. */ struct thread_resume *resume; - /* True if it is known that this lwp is presently collecting a fast - tracepoint (it is in the jump pad or in some code that will - return to the jump pad. Normally, we won't care about this, but - we will if a signal arrives to this lwp while it is - collecting. */ - int collecting_fast_tracepoint; + /* Information bout this lwp's fast tracepoint collection status (is it + currently stopped in the jump pad, and if so, before or at/after the + relocated instruction). Normally, we won't care about this, but we will + if a signal arrives to this lwp while it is collecting. */ + fast_tpoint_collect_result collecting_fast_tracepoint; /* If this is non-zero, it points to a chain of signals which need to be reported to GDB. These were deferred because the thread @@ -374,6 +374,9 @@ struct lwp_info /* The thread handle, used for e.g. TLS access. Only valid if THREAD_KNOWN is set. */ td_thrhandle_t th; + + /* The pthread_t handle. */ + thread_t thread_handle; #endif /* Arch-specific additions. */ @@ -410,4 +413,12 @@ int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, CORE_ADDR load_module, CORE_ADDR *address); int thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp); +/* Called from linux-low.c when a clone event is detected. Upon entry, + both the clone and the parent should be stopped. This function does + whatever is required have the clone under thread_db's control. */ + +void thread_db_notice_clone (struct process_info *proc, ptid_t lwp); + +bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len); + extern int have_ptrace_getregset; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index b39026c..49f6b2d 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -757,7 +757,7 @@ x86_linux_read_description (void) { have_ptrace_getfpxregs = 0; have_ptrace_getregset = 0; - return tdesc_i386_mmx_linux; + return i386_linux_read_description (X86_XSTATE_X87); } else have_ptrace_getfpxregs = 1; @@ -809,7 +809,7 @@ x86_linux_read_description (void) /* Check the native XCR0 only if PTRACE_GETREGSET is available. */ xcr0_features = (have_ptrace_getregset - && (xcr0 & X86_XSTATE_ALL_MASK)); + && (xcr0 & X86_XSTATE_ALL_MASK)); if (xcr0_features) x86_xcr0 = xcr0; @@ -817,103 +817,35 @@ x86_linux_read_description (void) if (machine == EM_X86_64) { #ifdef __x86_64__ - if (is_elf64) - { - if (xcr0_features) - { - switch (xcr0 & X86_XSTATE_ALL_MASK) - { - case X86_XSTATE_AVX_MPX_AVX512_PKU_MASK: - return tdesc_amd64_avx_mpx_avx512_pku_linux; - - case X86_XSTATE_AVX_AVX512_MASK: - return tdesc_amd64_avx_avx512_linux; - - case X86_XSTATE_AVX_MPX_MASK: - return tdesc_amd64_avx_mpx_linux; - - case X86_XSTATE_MPX_MASK: - return tdesc_amd64_mpx_linux; + const target_desc *tdesc = NULL; - case X86_XSTATE_AVX_MASK: - return tdesc_amd64_avx_linux; - - default: - return tdesc_amd64_linux; - } - } - else - return tdesc_amd64_linux; - } - else + if (xcr0_features) { - if (xcr0_features) - { - switch (xcr0 & X86_XSTATE_ALL_MASK) - { - case X86_XSTATE_AVX_MPX_AVX512_PKU_MASK: - /* No x32 MPX and PKU, fall back to avx_avx512. */ - return tdesc_x32_avx_avx512_linux; - - case X86_XSTATE_AVX_AVX512_MASK: - return tdesc_x32_avx_avx512_linux; - - case X86_XSTATE_MPX_MASK: /* No MPX on x32. */ - case X86_XSTATE_AVX_MASK: - return tdesc_x32_avx_linux; - - default: - return tdesc_x32_linux; - } - } - else - return tdesc_x32_linux; + tdesc = amd64_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK, + !is_elf64); } + + if (tdesc == NULL) + tdesc = amd64_linux_read_description (X86_XSTATE_SSE_MASK, !is_elf64); + return tdesc; #endif } else { - if (xcr0_features) - { - switch (xcr0 & X86_XSTATE_ALL_MASK) - { - case X86_XSTATE_AVX_MPX_AVX512_PKU_MASK: - return tdesc_i386_avx_mpx_avx512_pku_linux; - - case (X86_XSTATE_AVX_AVX512_MASK): - return tdesc_i386_avx_avx512_linux; + const target_desc *tdesc = NULL; - case (X86_XSTATE_MPX_MASK): - return tdesc_i386_mpx_linux; - - case (X86_XSTATE_AVX_MPX_MASK): - return tdesc_i386_avx_mpx_linux; + if (xcr0_features) + tdesc = i386_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK); - case (X86_XSTATE_AVX_MASK): - return tdesc_i386_avx_linux; + if (tdesc == NULL) + tdesc = i386_linux_read_description (X86_XSTATE_SSE); - default: - return tdesc_i386_linux; - } - } - else - return tdesc_i386_linux; + return tdesc; } gdb_assert_not_reached ("failed to return tdesc"); } -/* Callback for find_inferior. Stops iteration when a thread with a - given PID is found. */ - -static int -same_process_callback (struct inferior_list_entry *entry, void *data) -{ - int pid = *(int *) data; - - return (ptid_get_pid (entry->id) == pid); -} - /* Callback for for_each_inferior. Calls the arch_setup routine for each process. */ @@ -923,9 +855,7 @@ x86_arch_setup_process_callback (struct inferior_list_entry *entry) int pid = ptid_get_pid (entry->id); /* Look up any thread of this processes. */ - current_thread - = (struct thread_info *) find_inferior (&all_threads, - same_process_callback, &pid); + current_thread = find_any_thread_of_pid (pid); the_low_target.arch_setup (); } @@ -2897,37 +2827,13 @@ x86_get_ipa_tdesc_idx (void) const struct target_desc *tdesc = regcache->tdesc; #ifdef __x86_64__ - if (tdesc == tdesc_amd64_linux || tdesc == tdesc_amd64_linux_no_xml - || tdesc == tdesc_x32_linux) - return X86_TDESC_SSE; - if (tdesc == tdesc_amd64_avx_linux || tdesc == tdesc_x32_avx_linux) - return X86_TDESC_AVX; - if (tdesc == tdesc_amd64_mpx_linux) - return X86_TDESC_MPX; - if (tdesc == tdesc_amd64_avx_mpx_linux) - return X86_TDESC_AVX_MPX; - if (tdesc == tdesc_amd64_avx_mpx_avx512_pku_linux || tdesc == tdesc_x32_avx_avx512_linux) - return X86_TDESC_AVX_MPX_AVX512_PKU; - if (tdesc == tdesc_amd64_avx_avx512_linux) - return X86_TDESC_AVX_AVX512; + return amd64_get_ipa_tdesc_idx (tdesc); #endif - if (tdesc == tdesc_i386_mmx_linux) - return X86_TDESC_MMX; - if (tdesc == tdesc_i386_linux || tdesc == tdesc_i386_linux_no_xml) + if (tdesc == tdesc_i386_linux_no_xml) return X86_TDESC_SSE; - if (tdesc == tdesc_i386_avx_linux) - return X86_TDESC_AVX; - if (tdesc == tdesc_i386_mpx_linux) - return X86_TDESC_MPX; - if (tdesc == tdesc_i386_avx_mpx_linux) - return X86_TDESC_AVX_MPX; - if (tdesc == tdesc_i386_avx_mpx_avx512_pku_linux) - return X86_TDESC_AVX_MPX_AVX512_PKU; - if (tdesc == tdesc_i386_avx_avx512_linux) - return X86_TDESC_AVX_AVX512; - return 0; + return i386_get_ipa_tdesc_idx (tdesc); } /* This is initialized assuming an amd64 target. @@ -2981,31 +2887,20 @@ initialize_low_arch (void) { /* Initialize the Linux target descriptions. */ #ifdef __x86_64__ - init_registers_amd64_linux (); - init_registers_amd64_avx_linux (); - init_registers_amd64_mpx_linux (); - init_registers_amd64_avx_mpx_linux (); - init_registers_amd64_avx_avx512_linux (); - init_registers_amd64_avx_mpx_avx512_pku_linux (); - - init_registers_x32_linux (); - init_registers_x32_avx_linux (); - init_registers_x32_avx_avx512_linux (); - - tdesc_amd64_linux_no_xml = XNEW (struct target_desc); - copy_target_description (tdesc_amd64_linux_no_xml, tdesc_amd64_linux); + tdesc_amd64_linux_no_xml = allocate_target_description (); + copy_target_description (tdesc_amd64_linux_no_xml, + amd64_linux_read_description (X86_XSTATE_SSE_MASK, + false)); tdesc_amd64_linux_no_xml->xmltarget = xmltarget_amd64_linux_no_xml; #endif - init_registers_i386_linux (); - init_registers_i386_mmx_linux (); - init_registers_i386_avx_linux (); - init_registers_i386_mpx_linux (); - init_registers_i386_avx_mpx_linux (); - init_registers_i386_avx_avx512_linux (); - init_registers_i386_avx_mpx_avx512_pku_linux (); - - tdesc_i386_linux_no_xml = XNEW (struct target_desc); - copy_target_description (tdesc_i386_linux_no_xml, tdesc_i386_linux); + +#if GDB_SELF_TEST + initialize_low_tdesc (); +#endif + + tdesc_i386_linux_no_xml = allocate_target_description (); + copy_target_description (tdesc_i386_linux_no_xml, + i386_linux_read_description (X86_XSTATE_SSE_MASK)); tdesc_i386_linux_no_xml->xmltarget = xmltarget_i386_linux_no_xml; initialize_regsets_info (&x86_regsets_info); diff --git a/gdb/gdbserver/linux-x86-tdesc-selftest.c b/gdb/gdbserver/linux-x86-tdesc-selftest.c new file mode 100644 index 0000000..c5ab2ab --- /dev/null +++ b/gdb/gdbserver/linux-x86-tdesc-selftest.c @@ -0,0 +1,183 @@ +/* Copyright (C) 2017 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 "server.h" +#include "linux-x86-tdesc.h" +#include "tdesc.h" +#include "common/selftest.h" +#include "x86-xstate.h" + +/* Defined in auto-generated file i386-linux.c. */ +void init_registers_i386_linux (void); +extern const struct target_desc *tdesc_i386_linux; + +/* Defined in auto-generated file i386-mmx-linux.c. */ +void init_registers_i386_mmx_linux (void); +extern const struct target_desc *tdesc_i386_mmx_linux; + +/* Defined in auto-generated file i386-avx-linux.c. */ +void init_registers_i386_avx_linux (void); +extern const struct target_desc *tdesc_i386_avx_linux; + +/* Defined in auto-generated file i386-avx-mpx-linux.c. */ +void init_registers_i386_avx_mpx_linux (void); +extern const struct target_desc *tdesc_i386_avx_mpx_linux; + +/* Defined in auto-generated file i386-avx-avx512-linux.c. */ +void init_registers_i386_avx_avx512_linux (void); +extern const struct target_desc *tdesc_i386_avx_avx512_linux; + +/* Defined in auto-generated file i386-avx-mpx-avx512-linux.c. */ +void init_registers_i386_avx_mpx_avx512_pku_linux (void); +extern const struct target_desc *tdesc_i386_avx_mpx_avx512_pku_linux; + +/* Defined in auto-generated file i386-mpx-linux.c. */ +void init_registers_i386_mpx_linux (void); +extern const struct target_desc *tdesc_i386_mpx_linux; + +#ifdef __x86_64__ + +/* Defined in auto-generated file amd64-linux.c. */ +void init_registers_amd64_linux (void); +extern const struct target_desc *tdesc_amd64_linux; + +/* Defined in auto-generated file amd64-avx-linux.c. */ +void init_registers_amd64_avx_linux (void); +extern const struct target_desc *tdesc_amd64_avx_linux; + +/* Defined in auto-generated file amd64-avx-avx512-linux.c. */ +void init_registers_amd64_avx_avx512_linux (void); +extern const struct target_desc *tdesc_amd64_avx_avx512_linux; + +/* Defined in auto-generated file amd64-avx-mpx-avx512-pku-linux.c. */ +void init_registers_amd64_avx_mpx_avx512_pku_linux (void); +extern const struct target_desc *tdesc_amd64_avx_mpx_avx512_pku_linux; + +/* Defined in auto-generated file amd64-avx-mpx-linux.c. */ +void init_registers_amd64_avx_mpx_linux (void); +extern const struct target_desc *tdesc_amd64_avx_mpx_linux; + +/* Defined in auto-generated file amd64-mpx-linux.c. */ +void init_registers_amd64_mpx_linux (void); +extern const struct target_desc *tdesc_amd64_mpx_linux; + +/* Defined in auto-generated file x32-linux.c. */ +void init_registers_x32_linux (void); +extern const struct target_desc *tdesc_x32_linux; + +/* Defined in auto-generated file x32-avx-linux.c. */ +void init_registers_x32_avx_linux (void); +extern const struct target_desc *tdesc_x32_avx_linux; + +/* Defined in auto-generated file x32-avx-avx512-linux.c. */ +void init_registers_x32_avx_avx512_linux (void); +extern const struct target_desc *tdesc_x32_avx_avx512_linux; + +#endif + +namespace selftests { +namespace tdesc { +static void +i386_tdesc_test () +{ + struct + { + unsigned int mask; + const target_desc *tdesc; + } tdesc_tests[] = { + { X86_XSTATE_X87, tdesc_i386_mmx_linux }, + { X86_XSTATE_SSE_MASK, tdesc_i386_linux }, + { X86_XSTATE_AVX_MASK, tdesc_i386_avx_linux }, + { X86_XSTATE_MPX_MASK, tdesc_i386_mpx_linux }, + { X86_XSTATE_AVX_MPX_MASK, tdesc_i386_avx_mpx_linux }, + { X86_XSTATE_AVX_AVX512_MASK, tdesc_i386_avx_avx512_linux }, + { X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, tdesc_i386_avx_mpx_avx512_pku_linux } + }; + + for (auto &elem : tdesc_tests) + { + const target_desc *tdesc = i386_linux_read_description (elem.mask); + + SELF_CHECK (*tdesc == *elem.tdesc); + } +} + +#ifdef __x86_64__ + +static void +amd64_tdesc_test () +{ + struct + { + unsigned int mask; + const target_desc *tdesc[2]; + } tdesc_tests[] = { + { X86_XSTATE_SSE_MASK, { tdesc_amd64_linux, tdesc_x32_linux } }, + { X86_XSTATE_AVX_MASK, { tdesc_amd64_avx_linux, tdesc_x32_avx_linux } }, + { X86_XSTATE_MPX_MASK, { tdesc_amd64_mpx_linux, tdesc_x32_avx_linux } }, + { X86_XSTATE_AVX_MPX_MASK, { tdesc_amd64_avx_mpx_linux, + tdesc_x32_avx_linux } }, + { X86_XSTATE_AVX_AVX512_MASK, { tdesc_amd64_avx_avx512_linux, + tdesc_x32_avx_avx512_linux } }, + { X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, + { tdesc_amd64_avx_mpx_avx512_pku_linux, tdesc_x32_avx_avx512_linux } }, + }; + + for (auto &elem : tdesc_tests) + { + for (int i = 0; i < 2; i++) + { + const target_desc *tdesc = amd64_linux_read_description (elem.mask, + i); + + SELF_CHECK (*tdesc == *elem.tdesc[i]); + } + } +} + +#endif +} +} // namespace selftests + +void +initialize_low_tdesc () +{ + init_registers_i386_linux (); + init_registers_i386_mmx_linux (); + init_registers_i386_avx_linux (); + init_registers_i386_mpx_linux (); + init_registers_i386_avx_mpx_linux (); + init_registers_i386_avx_avx512_linux (); + init_registers_i386_avx_mpx_avx512_pku_linux (); + + selftests::register_test ("i386-tdesc", selftests::tdesc::i386_tdesc_test); + +#ifdef __x86_64__ + init_registers_x32_linux (); + init_registers_x32_avx_linux (); + init_registers_x32_avx_avx512_linux (); + + init_registers_amd64_linux (); + init_registers_amd64_avx_linux (); + init_registers_amd64_mpx_linux (); + init_registers_amd64_avx_mpx_linux (); + init_registers_amd64_avx_avx512_linux (); + init_registers_amd64_avx_mpx_avx512_pku_linux (); + + selftests::register_test ("amd64-tdesc", selftests::tdesc::amd64_tdesc_test); +#endif +} diff --git a/gdb/gdbserver/linux-x86-tdesc.c b/gdb/gdbserver/linux-x86-tdesc.c new file mode 100644 index 0000000..d27068c --- /dev/null +++ b/gdb/gdbserver/linux-x86-tdesc.c @@ -0,0 +1,173 @@ +/* GNU/Linux/x86-64 specific target description, for the remote server + for GDB. + Copyright (C) 2017 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 "server.h" +#include "tdesc.h" +#include "linux-x86-tdesc.h" +#include "arch/i386.h" +#include "common/x86-xstate.h" +#ifdef __x86_64__ +#include "arch/amd64.h" +#endif + +/* Return the right x86_linux_tdesc index for a given XCR0. Return + X86_TDESC_LAST if can't find a match. */ + +static enum x86_linux_tdesc +xcr0_to_tdesc_idx (uint64_t xcr0, bool is_x32) +{ + if (xcr0 & X86_XSTATE_PKRU) + { + if (is_x32) + { + /* No x32 MPX and PKU, fall back to avx_avx512. */ + return X86_TDESC_AVX_AVX512; + } + else + return X86_TDESC_AVX_MPX_AVX512_PKU; + } + else if (xcr0 & X86_XSTATE_AVX512) + return X86_TDESC_AVX_AVX512; + else if ((xcr0 & X86_XSTATE_AVX_MPX_MASK) == X86_XSTATE_AVX_MPX_MASK) + { + if (is_x32) /* No MPX on x32. */ + return X86_TDESC_AVX; + else + return X86_TDESC_AVX_MPX; + } + else if (xcr0 & X86_XSTATE_MPX) + { + if (is_x32) /* No MPX on x32. */ + return X86_TDESC_AVX; + else + return X86_TDESC_MPX; + } + else if (xcr0 & X86_XSTATE_AVX) + return X86_TDESC_AVX; + else if (xcr0 & X86_XSTATE_SSE) + return X86_TDESC_SSE; + else if (xcr0 & X86_XSTATE_X87) + return X86_TDESC_MMX; + else + return X86_TDESC_LAST; +} + +static struct target_desc *i386_tdescs[X86_TDESC_LAST] = { }; + +#if defined __i386__ || !defined IN_PROCESS_AGENT + +/* Return the target description according to XCR0. */ + +const struct target_desc * +i386_linux_read_description (uint64_t xcr0) +{ + enum x86_linux_tdesc idx = xcr0_to_tdesc_idx (xcr0, false); + + if (idx == X86_TDESC_LAST) + return NULL; + + struct target_desc **tdesc = &i386_tdescs[idx]; + + if (*tdesc == NULL) + { + *tdesc = i386_create_target_description (xcr0, true); + + init_target_desc (*tdesc); + +#ifndef IN_PROCESS_AGENT + static const char *expedite_regs_i386[] = { "ebp", "esp", "eip", NULL }; + (*tdesc)->expedite_regs = expedite_regs_i386; +#endif + } + + return *tdesc;; +} +#endif + +#ifdef __x86_64__ + +static target_desc *amd64_tdescs[X86_TDESC_LAST] = { }; +static target_desc *x32_tdescs[X86_TDESC_LAST] = { }; + +const struct target_desc * +amd64_linux_read_description (uint64_t xcr0, bool is_x32) +{ + enum x86_linux_tdesc idx = xcr0_to_tdesc_idx (xcr0, is_x32); + + if (idx == X86_TDESC_LAST) + return NULL; + + struct target_desc **tdesc = NULL; + + if (is_x32) + tdesc = &x32_tdescs[idx]; + else + tdesc = &amd64_tdescs[idx]; + + if (*tdesc == NULL) + { + *tdesc = amd64_create_target_description (xcr0, is_x32, true); + + init_target_desc (*tdesc); + +#ifndef IN_PROCESS_AGENT + static const char *expedite_regs_amd64[] = { "rbp", "rsp", "rip", NULL }; + (*tdesc)->expedite_regs = expedite_regs_amd64; +#endif + } + return *tdesc; +} + +#endif + +#ifndef IN_PROCESS_AGENT + +int +i386_get_ipa_tdesc_idx (const struct target_desc *tdesc) +{ + for (int i = 0; i < X86_TDESC_LAST; i++) + { + if (tdesc == i386_tdescs[i]) + return i; + } + + /* If none tdesc is found, return the one with minimum features. */ + return X86_TDESC_MMX; +} + +#if defined __x86_64__ +int +amd64_get_ipa_tdesc_idx (const struct target_desc *tdesc) +{ + for (int i = 0; i < X86_TDESC_LAST; i++) + { + if (tdesc == amd64_tdescs[i]) + return i; + } + for (int i = 0; i < X86_TDESC_LAST; i++) + { + if (tdesc == x32_tdescs[i]) + return i; + } + + return X86_TDESC_SSE; +} + +#endif +#endif diff --git a/gdb/gdbserver/linux-x86-tdesc.h b/gdb/gdbserver/linux-x86-tdesc.h index bbe4078..a6dc330 100644 --- a/gdb/gdbserver/linux-x86-tdesc.h +++ b/gdb/gdbserver/linux-x86-tdesc.h @@ -30,78 +30,24 @@ enum x86_linux_tdesc { X86_TDESC_AVX_MPX = 4, X86_TDESC_AVX_AVX512 = 5, X86_TDESC_AVX_MPX_AVX512_PKU = 6, + X86_TDESC_LAST = 7, }; -#ifdef __x86_64__ - -#if defined __LP64__ || !defined IN_PROCESS_AGENT -/* Defined in auto-generated file amd64-linux.c. */ -void init_registers_amd64_linux (void); -extern const struct target_desc *tdesc_amd64_linux; - -/* Defined in auto-generated file amd64-avx-linux.c. */ -void init_registers_amd64_avx_linux (void); -extern const struct target_desc *tdesc_amd64_avx_linux; - -/* Defined in auto-generated file amd64-avx-avx512-linux.c. */ -void init_registers_amd64_avx_avx512_linux (void); -extern const struct target_desc *tdesc_amd64_avx_avx512_linux; - -/* Defined in auto-generated file amd64-avx-mpx-avx512-pku-linux.c. */ -void init_registers_amd64_avx_mpx_avx512_pku_linux (void); -extern const struct target_desc *tdesc_amd64_avx_mpx_avx512_pku_linux; - -/* Defined in auto-generated file amd64-avx-mpx-linux.c. */ -void init_registers_amd64_avx_mpx_linux (void); -extern const struct target_desc *tdesc_amd64_avx_mpx_linux; - -/* Defined in auto-generated file amd64-mpx-linux.c. */ -void init_registers_amd64_mpx_linux (void); -extern const struct target_desc *tdesc_amd64_mpx_linux; -#endif - -#if defined __ILP32__ || !defined IN_PROCESS_AGENT -/* Defined in auto-generated file x32-linux.c. */ -void init_registers_x32_linux (void); -extern const struct target_desc *tdesc_x32_linux; - -/* Defined in auto-generated file x32-avx-linux.c. */ -void init_registers_x32_avx_linux (void); -extern const struct target_desc *tdesc_x32_avx_linux; - -/* Defined in auto-generated file x32-avx-avx512-linux.c. */ -void init_registers_x32_avx_avx512_linux (void); -extern const struct target_desc *tdesc_x32_avx_avx512_linux; +#if defined __i386__ || !defined IN_PROCESS_AGENT +int i386_get_ipa_tdesc_idx (const struct target_desc *tdesc); #endif +#if defined __x86_64__ && !defined IN_PROCESS_AGENT +int amd64_get_ipa_tdesc_idx (const struct target_desc *tdesc); #endif -#if defined __i386__ || !defined IN_PROCESS_AGENT -/* Defined in auto-generated file i386-linux.c. */ -void init_registers_i386_linux (void); -extern const struct target_desc *tdesc_i386_linux; - -/* Defined in auto-generated file i386-mmx-linux.c. */ -void init_registers_i386_mmx_linux (void); -extern const struct target_desc *tdesc_i386_mmx_linux; - -/* Defined in auto-generated file i386-avx-linux.c. */ -void init_registers_i386_avx_linux (void); -extern const struct target_desc *tdesc_i386_avx_linux; +const struct target_desc *i386_get_ipa_tdesc (int idx); -/* Defined in auto-generated file i386-avx-mpx-linux.c. */ -void init_registers_i386_avx_mpx_linux (void); -extern const struct target_desc *tdesc_i386_avx_mpx_linux; - -/* Defined in auto-generated file i386-avx-avx512-linux.c. */ -void init_registers_i386_avx_avx512_linux (void); -extern const struct target_desc *tdesc_i386_avx_avx512_linux; +#ifdef __x86_64__ +const struct target_desc *amd64_linux_read_description (uint64_t xcr0, + bool is_x32); +#endif -/* Defined in auto-generated file i386-avx-mpx-avx512-linux.c. */ -void init_registers_i386_avx_mpx_avx512_pku_linux (void); -extern const struct target_desc *tdesc_i386_avx_mpx_avx512_pku_linux; +const struct target_desc *i386_linux_read_description (uint64_t xcr0); -/* Defined in auto-generated file i386-mpx-linux.c. */ -void init_registers_i386_mpx_linux (void); -extern const struct target_desc *tdesc_i386_mpx_linux; -#endif +void initialize_low_tdesc (); diff --git a/gdb/gdbserver/lynx-i386-low.c b/gdb/gdbserver/lynx-i386-low.c index 64e6c0f..57181d6 100644 --- a/gdb/gdbserver/lynx-i386-low.c +++ b/gdb/gdbserver/lynx-i386-low.c @@ -19,6 +19,8 @@ #include "lynx-low.h" #include <limits.h> #include <sys/ptrace.h> +#include "x86-xstate.h" +#include "arch/i386.h" /* The following two typedefs are defined in a .h file which is not in the standard include path (/sys/include/family/x86/ucontext.h), @@ -118,10 +120,6 @@ enum lynx_i386_gdb_regnum I386_SENTINEL_REGUM }; -/* Defined in auto-generated file i386.c. */ -extern void init_registers_i386 (void); -extern const struct target_desc *tdesc_i386; - /* The fill_function for the general-purpose register set. */ static void @@ -295,8 +293,7 @@ lynx_i386_store_fpregset (struct regcache *regcache, const char *buf) static void lynx_i386_arch_setup (void) { - init_registers_i386 (); - lynx_tdesc = tdesc_i386; + lynx_tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false); } /* Description of all the x86-lynx register sets. */ diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c index 77f570e..f074dd5 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -350,7 +350,7 @@ lynx_resume (struct thread_resume *resume_info, size_t n) the moment we resume its execution for the first time. It is fine to use the current_thread's ptid in those cases. */ if (ptid_equal (ptid, minus_one_ptid)) - ptid = thread_to_gdb_id (current_thread); + ptid = ptid_of (current_thread); regcache_invalidate_pid (ptid_get_pid (ptid)); @@ -423,7 +423,7 @@ lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options) ptid_t new_ptid; if (ptid_equal (ptid, minus_one_ptid)) - pid = lynx_ptid_get_pid (thread_to_gdb_id (current_thread)); + pid = lynx_ptid_get_pid (ptid_of (current_thread)); else pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); @@ -612,7 +612,7 @@ static void lynx_fetch_registers (struct regcache *regcache, int regno) { struct lynx_regset_info *regset = lynx_target_regsets; - ptid_t inferior_ptid = thread_to_gdb_id (current_thread); + ptid_t inferior_ptid = ptid_of (current_thread); lynx_debug ("lynx_fetch_registers (regno = %d)", regno); @@ -637,7 +637,7 @@ static void lynx_store_registers (struct regcache *regcache, int regno) { struct lynx_regset_info *regset = lynx_target_regsets; - ptid_t inferior_ptid = thread_to_gdb_id (current_thread); + ptid_t inferior_ptid = ptid_of (current_thread); lynx_debug ("lynx_store_registers (regno = %d)", regno); @@ -673,7 +673,7 @@ lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) int buf; const int xfer_size = sizeof (buf); CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; - ptid_t inferior_ptid = thread_to_gdb_id (current_thread); + ptid_t inferior_ptid = ptid_of (current_thread); while (addr < memaddr + len) { @@ -706,7 +706,7 @@ lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) int buf; const int xfer_size = sizeof (buf); CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; - ptid_t inferior_ptid = thread_to_gdb_id (current_thread); + ptid_t inferior_ptid = ptid_of (current_thread); while (addr < memaddr + len) { @@ -742,7 +742,7 @@ lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) static void lynx_request_interrupt (void) { - ptid_t inferior_ptid = thread_to_gdb_id (get_first_thread ()); + ptid_t inferior_ptid = ptid_of (get_first_thread ()); kill (lynx_ptid_get_pid (inferior_ptid), SIGINT); } diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index a5f1543..a8c981a 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -620,7 +620,6 @@ nto_fetch_registers (struct regcache *regcache, int regno) { int regsize; procfs_greg greg; - ptid_t ptid; TRACE ("%s (regno=%d)\n", __func__, regno); if (regno >= the_low_target.num_regs) @@ -631,7 +630,7 @@ nto_fetch_registers (struct regcache *regcache, int regno) TRACE ("current_thread is NULL\n"); return; } - ptid = thread_to_gdb_id (current_thread); + ptid_t ptid = ptid_of (current_thread); if (!nto_set_thread (ptid)) return; @@ -669,7 +668,6 @@ nto_store_registers (struct regcache *regcache, int regno) { procfs_greg greg; int err; - ptid_t ptid; TRACE ("%s (regno:%d)\n", __func__, regno); @@ -678,7 +676,7 @@ nto_store_registers (struct regcache *regcache, int regno) TRACE ("current_thread is NULL\n"); return; } - ptid = thread_to_gdb_id (current_thread); + ptid_t ptid = ptid_of (current_thread); if (!nto_set_thread (ptid)) return; @@ -867,9 +865,7 @@ nto_stopped_by_watchpoint (void) TRACE ("%s\n", __func__); if (nto_inferior.ctl_fd != -1 && current_thread != NULL) { - ptid_t ptid; - - ptid = thread_to_gdb_id (current_thread); + ptid_t ptid = ptid_of (current_thread); if (nto_set_thread (ptid)) { const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR @@ -899,9 +895,7 @@ nto_stopped_data_address (void) TRACE ("%s\n", __func__); if (nto_inferior.ctl_fd != -1 && current_thread != NULL) { - ptid_t ptid; - - ptid = thread_to_gdb_id (current_thread); + ptid_t ptid = ptid_of (current_thread); if (nto_set_thread (ptid)) { diff --git a/gdb/gdbserver/nto-x86-low.c b/gdb/gdbserver/nto-x86-low.c index 901ac7b..cfa5993 100644 --- a/gdb/gdbserver/nto-x86-low.c +++ b/gdb/gdbserver/nto-x86-low.c @@ -23,12 +23,8 @@ #include "regcache.h" #include <x86/context.h> - - -/* Defined in auto-generated build-time file gdb/gdbserver/i386.c. */ -extern void init_registers_i386 (); -extern struct reg *regs_i386; -extern const struct target_desc *tdesc_i386; +#include "x86-xstate.h" +#include "arch/i386.h" const unsigned char x86_breakpoint[] = { 0xCC }; #define x86_breakpoint_len 1 @@ -90,9 +86,8 @@ nto_x86_register_offset (int gdbregno) static void nto_x86_arch_setup (void) { - init_registers_i386 (); the_low_target.num_regs = 16; - nto_tdesc = tdesc_i386; + nto_tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false); } struct nto_target_ops the_low_target = diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c index 0f16f60..7548091 100644 --- a/gdb/gdbserver/regcache.c +++ b/gdb/gdbserver/regcache.c @@ -28,7 +28,7 @@ get_thread_regcache (struct thread_info *thread, int fetch) { struct regcache *regcache; - regcache = inferior_regcache_data (thread); + regcache = thread_regcache_data (thread); /* Threads' regcaches are created lazily, because biarch targets add the main thread/lwp before seeing it stop for the first time, and @@ -44,7 +44,7 @@ get_thread_regcache (struct thread_info *thread, int fetch) gdb_assert (proc->tdesc != NULL); regcache = new_register_cache (proc->tdesc); - set_inferior_regcache_data (thread, regcache); + set_thread_regcache_data (thread, regcache); } if (fetch && regcache->registers_valid == 0) @@ -54,7 +54,7 @@ get_thread_regcache (struct thread_info *thread, int fetch) current_thread = thread; /* Invalidate all registers, to prevent stale left-overs. */ memset (regcache->register_status, REG_UNAVAILABLE, - regcache->tdesc->num_registers); + regcache->tdesc->reg_defs.size ()); fetch_inferior_registers (regcache, -1); current_thread = saved_thread; regcache->registers_valid = 1; @@ -76,7 +76,7 @@ regcache_invalidate_thread (struct thread_info *thread) { struct regcache *regcache; - regcache = inferior_regcache_data (thread); + regcache = thread_regcache_data (thread); if (regcache == NULL) return; @@ -145,9 +145,9 @@ init_register_cache (struct regcache *regcache, = (unsigned char *) xcalloc (1, tdesc->registers_size); regcache->registers_owned = 1; regcache->register_status - = (unsigned char *) xmalloc (tdesc->num_registers); + = (unsigned char *) xmalloc (tdesc->reg_defs.size ()); memset ((void *) regcache->register_status, REG_UNAVAILABLE, - tdesc->num_registers); + tdesc->reg_defs.size ()); #else gdb_assert_not_reached ("can't allocate memory from the heap"); #endif @@ -204,7 +204,7 @@ regcache_cpy (struct regcache *dst, struct regcache *src) #ifndef IN_PROCESS_AGENT if (dst->register_status != NULL && src->register_status != NULL) memcpy (dst->register_status, src->register_status, - src->tdesc->num_registers); + src->tdesc->reg_defs.size ()); #endif dst->registers_valid = src->registers_valid; } @@ -217,10 +217,11 @@ registers_to_string (struct regcache *regcache, char *buf) { unsigned char *registers = regcache->registers; const struct target_desc *tdesc = regcache->tdesc; - int i; - for (i = 0; i < tdesc->num_registers; i++) + for (int i = 0; i < tdesc->reg_defs.size (); ++i) { + struct reg *reg = tdesc->reg_defs[i]; + if (regcache->register_status[i] == REG_VALID) { bin2hex (registers, buf, register_size (tdesc, i)); @@ -256,34 +257,36 @@ registers_from_string (struct regcache *regcache, char *buf) int find_regno (const struct target_desc *tdesc, const char *name) { - int i; + for (int i = 0; i < tdesc->reg_defs.size (); ++i) + { + struct reg *reg = tdesc->reg_defs[i]; - for (i = 0; i < tdesc->num_registers; i++) - if (strcmp (name, tdesc->reg_defs[i].name) == 0) - return i; + if (strcmp (name, reg->name) == 0) + return i; + } internal_error (__FILE__, __LINE__, "Unknown register %s requested", name); } +#endif + struct reg * find_register_by_number (const struct target_desc *tdesc, int n) { - return &tdesc->reg_defs[n]; + return tdesc->reg_defs[n]; } -#endif - #ifndef IN_PROCESS_AGENT static void free_register_cache_thread (struct thread_info *thread) { - struct regcache *regcache = inferior_regcache_data (thread); + struct regcache *regcache = thread_regcache_data (thread); if (regcache != NULL) { regcache_invalidate_thread (thread); free_register_cache (regcache); - set_inferior_regcache_data (thread, NULL); + set_thread_regcache_data (thread, NULL); } } @@ -312,7 +315,7 @@ register_cache_size (const struct target_desc *tdesc) int register_size (const struct target_desc *tdesc, int n) { - return tdesc->reg_defs[n].size / 8; + return find_register_by_number (tdesc, n)->size / 8; } /* See common/common-regcache.h. */ @@ -326,7 +329,8 @@ regcache_register_size (const struct regcache *regcache, int n) static unsigned char * register_data (struct regcache *regcache, int n, int fetch) { - return regcache->registers + regcache->tdesc->reg_defs[n].offset / 8; + return (regcache->registers + + find_register_by_number (regcache->tdesc, n)->offset / 8); } /* Supply register N, whose contents are stored in BUF, to REGCACHE. @@ -385,7 +389,7 @@ supply_regblock (struct regcache *regcache, const void *buf) { int i; - for (i = 0; i < tdesc->num_registers; i++) + for (i = 0; i < tdesc->reg_defs.size (); i++) regcache->register_status[i] = REG_VALID; } #endif @@ -399,7 +403,7 @@ supply_regblock (struct regcache *regcache, const void *buf) { int i; - for (i = 0; i < tdesc->num_registers; i++) + for (i = 0; i < tdesc->reg_defs.size (); i++) regcache->register_status[i] = REG_UNAVAILABLE; } #endif @@ -431,7 +435,8 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum, int size; gdb_assert (regcache != NULL); - gdb_assert (regnum >= 0 && regnum < regcache->tdesc->num_registers); + gdb_assert (regnum >= 0 + && regnum < regcache->tdesc->reg_defs.size ()); size = register_size (regcache->tdesc, regnum); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 3838351..f3eee31 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -40,6 +40,22 @@ #include "job-control.h" #include "environ.h" +#include "common/selftest.h" + +#define require_running_or_return(BUF) \ + if (!target_running ()) \ + { \ + write_enn (BUF); \ + return; \ + } + +#define require_running_or_break(BUF) \ + if (!target_running ()) \ + { \ + write_enn (BUF); \ + break; \ + } + /* The environment to pass to the inferior when creating it. */ static gdb_environ our_environ; @@ -631,6 +647,67 @@ handle_general_set (char *own_buf) return; } + if (strcmp (own_buf, "QEnvironmentReset") == 0) + { + our_environ = gdb_environ::from_host_environ (); + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QEnvironmentHexEncoded:")) + { + const char *p = own_buf + sizeof ("QEnvironmentHexEncoded:") - 1; + /* The final form of the environment variable. FINAL_VAR will + hold the 'VAR=VALUE' format. */ + std::string final_var = hex2str (p); + std::string var_name, var_value; + + if (remote_debug) + { + debug_printf (_("[QEnvironmentHexEncoded received '%s']\n"), p); + debug_printf (_("[Environment variable to be set: '%s']\n"), + final_var.c_str ()); + debug_flush (); + } + + size_t pos = final_var.find ('='); + if (pos == std::string::npos) + { + warning (_("Unexpected format for environment variable: '%s'"), + final_var.c_str ()); + write_enn (own_buf); + return; + } + + var_name = final_var.substr (0, pos); + var_value = final_var.substr (pos + 1, std::string::npos); + + our_environ.set (var_name.c_str (), var_value.c_str ()); + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QEnvironmentUnset:")) + { + const char *p = own_buf + sizeof ("QEnvironmentUnset:") - 1; + std::string varname = hex2str (p); + + if (remote_debug) + { + debug_printf (_("[QEnvironmentUnset received '%s']\n"), p); + debug_printf (_("[Environment variable to be unset: '%s']\n"), + varname.c_str ()); + debug_flush (); + } + + our_environ.unset (varname.c_str ()); + + write_ok (own_buf); + return; + } + if (strcmp (own_buf, "QStartNoAckMode") == 0) { if (remote_debug) @@ -810,12 +887,14 @@ get_features_xml (const char *annex) This variable is set up from the auto-generated init_registers_... routine for the current target. */ - if (desc->xmltarget != NULL && strcmp (annex, "target.xml") == 0) + if (strcmp (annex, "target.xml") == 0) { - if (*desc->xmltarget == '@') - return desc->xmltarget + 1; + const char *ret = tdesc_get_features_xml ((target_desc*) desc); + + if (*ret == '@') + return ret + 1; else - annex = desc->xmltarget; + annex = ret; } #ifdef USE_XML @@ -890,7 +969,7 @@ gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) res = prepare_to_access_memory (); if (res == 0) { - if (set_desired_thread (1)) + if (set_desired_thread ()) res = read_inferior_memory (memaddr, myaddr, len); else res = 1; @@ -917,7 +996,7 @@ gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) ret = prepare_to_access_memory (); if (ret == 0) { - if (set_desired_thread (1)) + if (set_desired_thread ()) ret = write_inferior_memory (memaddr, myaddr, len); else ret = EIO; @@ -1078,12 +1157,99 @@ handle_search_memory (char *own_buf, int packet_len) free (pattern); } -#define require_running(BUF) \ - if (!target_running ()) \ - { \ - write_enn (BUF); \ - return; \ +/* Handle the "D" packet. */ + +static void +handle_detach (char *own_buf) +{ + require_running_or_return (own_buf); + + int pid; + + if (multi_process) + { + /* skip 'D;' */ + pid = strtol (&own_buf[2], NULL, 16); } + else + pid = ptid_get_pid (current_ptid); + + if ((tracing && disconnected_tracing) || any_persistent_commands ()) + { + struct process_info *process = find_process_pid (pid); + + if (process == NULL) + { + write_enn (own_buf); + return; + } + + if (tracing && disconnected_tracing) + fprintf (stderr, + "Disconnected tracing in effect, " + "leaving gdbserver attached to the process\n"); + + if (any_persistent_commands ()) + fprintf (stderr, + "Persistent commands are present, " + "leaving gdbserver attached to the process\n"); + + /* Make sure we're in non-stop/async mode, so we we can both + wait for an async socket accept, and handle async target + events simultaneously. There's also no point either in + having the target stop all threads, when we're going to + pass signals down without informing GDB. */ + if (!non_stop) + { + if (debug_threads) + debug_printf ("Forcing non-stop mode\n"); + + non_stop = 1; + start_non_stop (1); + } + + process->gdb_detached = 1; + + /* Detaching implicitly resumes all threads. */ + target_continue_no_signal (minus_one_ptid); + + write_ok (own_buf); + return; + } + + fprintf (stderr, "Detaching from process %d\n", pid); + stop_tracing (); + if (detach_inferior (pid) != 0) + write_enn (own_buf); + else + { + discard_queued_stop_replies (pid_to_ptid (pid)); + write_ok (own_buf); + + if (extended_protocol || target_running ()) + { + /* There is still at least one inferior remaining or + we are in extended mode, so don't terminate gdbserver, + and instead treat this like a normal program exit. */ + last_status.kind = TARGET_WAITKIND_EXITED; + last_status.value.integer = 0; + last_ptid = pid_to_ptid (pid); + + current_thread = NULL; + } + else + { + putpkt (own_buf); + remote_close (); + + /* If we are attached, then we can exit. Otherwise, we + need to hang around doing nothing, until the child is + gone. */ + join_inferior (pid); + exit (0); + } + } +} /* Parse options to --debug-format= and "monitor set debug-format". ARG is the text after "--debug-format=" or "monitor set debug-format". @@ -1343,45 +1509,18 @@ handle_qxfer_features (const char *annex, } /* Worker routine for handle_qxfer_libraries. - Add to the length pointed to by ARG a conservative estimate of the - length needed to transmit the file name of INF. */ - -static void -accumulate_file_name_length (struct inferior_list_entry *inf, void *arg) -{ - struct dll_info *dll = (struct dll_info *) inf; - unsigned int *total_len = (unsigned int *) arg; - - /* Over-estimate the necessary memory. Assume that every character - in the library name must be escaped. */ - *total_len += 128 + 6 * strlen (dll->name); -} - -/* Worker routine for handle_qxfer_libraries. Emit the XML to describe the library in INF. */ static void emit_dll_description (struct inferior_list_entry *inf, void *arg) { struct dll_info *dll = (struct dll_info *) inf; - char **p_ptr = (char **) arg; - char *p = *p_ptr; - char *name; - - strcpy (p, " <library name=\""); - p = p + strlen (p); - name = xml_escape_text (dll->name); - strcpy (p, name); - free (name); - p = p + strlen (p); - strcpy (p, "\"><segment address=\""); - p = p + strlen (p); - sprintf (p, "0x%lx", (long) dll->base_addr); - p = p + strlen (p); - strcpy (p, "\"/></library>\n"); - p = p + strlen (p); - - *p_ptr = p; + std::string *document = (std::string *) arg; + std::string name = xml_escape_text (dll->name); + + *document += string_printf + (" <library name=\"%s\"><segment address=\"0x%lx\"/></library>\n", + name.c_str (), (long) dll->base_addr); } /* Handle qXfer:libraries:read. */ @@ -1391,43 +1530,26 @@ handle_qxfer_libraries (const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { - unsigned int total_len; - char *document, *p; - if (writebuf != NULL) return -2; if (annex[0] != '\0' || current_thread == NULL) return -1; - total_len = 64; - for_each_inferior_with_data (&all_dlls, accumulate_file_name_length, - &total_len); + std::string document = "<library-list version=\"1.0\">\n"; - document = (char *) malloc (total_len); - if (document == NULL) - return -1; + for_each_inferior_with_data (&all_dlls, emit_dll_description, &document); - strcpy (document, "<library-list version=\"1.0\">\n"); - p = document + strlen (document); + document += "</library-list>\n"; - for_each_inferior_with_data (&all_dlls, emit_dll_description, &p); - - strcpy (p, "</library-list>\n"); - - total_len = strlen (document); + if (offset > document.length ()) + return -1; - if (offset > total_len) - { - free (document); - return -1; - } + if (offset + len > document.length ()) + len = document.length () - offset; - if (offset + len > total_len) - len = total_len - offset; + memcpy (readbuf, &document[offset], len); - memcpy (readbuf, document + offset, len); - free (document); return len; } @@ -1521,11 +1643,14 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg) { struct thread_info *thread = (struct thread_info *) inf; struct buffer *buffer = (struct buffer *) arg; - ptid_t ptid = thread_to_gdb_id (thread); + ptid_t ptid = ptid_of (thread); char ptid_s[100]; int core = target_core_of_thread (ptid); char core_s[21]; const char *name = target_thread_name (ptid); + int handle_len; + gdb_byte *handle; + bool handle_status = target_thread_handle (ptid, &handle, &handle_len); write_ptid (ptid_s, ptid); @@ -1540,6 +1665,13 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg) if (name != NULL) buffer_xml_printf (buffer, " name=\"%s\"", name); + if (handle_status) + { + char *handle_s = (char *) alloca (handle_len * 2 + 1); + bin2hex (handle, handle_s, handle_len); + buffer_xml_printf (buffer, " handle=\"%s\"", handle_s); + } + buffer_xml_printf (buffer, "/>\n"); } @@ -2005,21 +2137,20 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) /* Reply the current thread id. */ if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC) { - ptid_t gdb_id; - require_running (own_buf); + ptid_t ptid; + require_running_or_return (own_buf); - if (!ptid_equal (general_thread, null_ptid) - && !ptid_equal (general_thread, minus_one_ptid)) - gdb_id = general_thread; + if (general_thread != null_ptid && general_thread != minus_one_ptid) + ptid = general_thread; else { thread_ptr = get_first_inferior (&all_threads); - gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); + ptid = thread_ptr->id; } sprintf (own_buf, "QC"); own_buf += 2; - write_ptid (own_buf, gdb_id); + write_ptid (own_buf, ptid); return; } @@ -2075,28 +2206,22 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) { if (strcmp ("qfThreadInfo", own_buf) == 0) { - ptid_t gdb_id; - - require_running (own_buf); + require_running_or_return (own_buf); thread_ptr = get_first_inferior (&all_threads); *own_buf++ = 'm'; - gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); - write_ptid (own_buf, gdb_id); + write_ptid (own_buf, thread_ptr->id); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", own_buf) == 0) { - ptid_t gdb_id; - - require_running (own_buf); + require_running_or_return (own_buf); if (thread_ptr != NULL) { *own_buf++ = 'm'; - gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); - write_ptid (own_buf, gdb_id); + write_ptid (own_buf, thread_ptr->id); thread_ptr = thread_ptr->next; return; } @@ -2113,7 +2238,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) { CORE_ADDR text, data; - require_running (own_buf); + require_running_or_return (own_buf); if (the_target->read_offsets (&text, &data)) sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX", (long)text, (long)data, (long)data); @@ -2228,7 +2353,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) } sprintf (own_buf, - "PacketSize=%x;QPassSignals+;QProgramSignals+;QStartupWithShell+", + "PacketSize=%x;QPassSignals+;QProgramSignals+;" + "QStartupWithShell+;QEnvironmentHexEncoded+;" + "QEnvironmentReset+;QEnvironmentUnset+", PBUFSIZ - 1); if (target_supports_catch_syscall ()) @@ -2348,7 +2475,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) int i, err; ptid_t ptid = null_ptid; - require_running (own_buf); + require_running_or_return (own_buf); for (i = 0; i < 3; i++) { @@ -2461,7 +2588,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (startswith (own_buf, "qSearch:memory:")) { - require_running (own_buf); + require_running_or_return (own_buf); handle_search_memory (own_buf, packet_len); return; } @@ -2479,7 +2606,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) } else { - require_running (own_buf); + require_running_or_return (own_buf); process = current_process (); } @@ -2501,7 +2628,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) int len; unsigned long long crc; - require_running (own_buf); + require_running_or_return (own_buf); comma = unpack_varlen_hex (own_buf + 5, &base); if (*comma++ != ',') { @@ -3116,14 +3243,12 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) { if (debug_threads) { - char *status_string + std::string status_string = target_waitstatus_to_string (&thread->last_status); debug_printf ("Reporting thread %s as already stopped with %s\n", target_pid_to_str (entry->id), - status_string); - - xfree (status_string); + status_string.c_str ()); } gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE); @@ -3283,7 +3408,7 @@ handle_status (char *own_buf) /* GDB assumes the current thread is the thread we're reporting the status for. */ general_thread = thread->id; - set_desired_thread (1); + set_desired_thread (); gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE); prepare_resume_reply (own_buf, tp->entry.id, &tp->last_status); @@ -3376,26 +3501,6 @@ gdbserver_show_disableable (FILE *stream) " threads \tAll of the above\n"); } - -#undef require_running -#define require_running(BUF) \ - if (!target_running ()) \ - { \ - write_enn (BUF); \ - break; \ - } - -static int -first_thread_of (struct inferior_list_entry *entry, void *args) -{ - int pid = * (int *) args; - - if (ptid_get_pid (entry->id) == pid) - return 1; - - return 0; -} - static void kill_inferior_callback (struct inferior_list_entry *entry) { @@ -3521,6 +3626,8 @@ captured_main (int argc, char *argv[]) volatile int multi_mode = 0; volatile int attach = 0; int was_running; + bool selftest = false; + const char *selftest_filter = NULL; while (*next_arg != NULL && **next_arg == '-') { @@ -3639,6 +3746,13 @@ captured_main (int argc, char *argv[]) startup_with_shell = false; else if (strcmp (*next_arg, "--once") == 0) run_once = 1; + else if (strcmp (*next_arg, "--selftest") == 0) + selftest = true; + else if (startswith (*next_arg, "--selftest=")) + { + selftest = true; + selftest_filter = *next_arg + strlen ("--selftest="); + } else { fprintf (stderr, "Unknown argument: %s\n", *next_arg); @@ -3654,7 +3768,8 @@ captured_main (int argc, char *argv[]) port = *next_arg; next_arg++; } - if (port == NULL || (!attach && !multi_mode && *next_arg == NULL)) + if ((port == NULL || (!attach && !multi_mode && *next_arg == NULL)) + && !selftest) { gdbserver_usage (stderr); exit (1); @@ -3670,7 +3785,8 @@ captured_main (int argc, char *argv[]) starting the inferior. Inferiors created in this scenario have stdin,stdout redirected. So do this here before we call start_inferior. */ - remote_prepare (port); + if (port != NULL) + remote_prepare (port); bad_attach = 0; pid = 0; @@ -3711,6 +3827,12 @@ captured_main (int argc, char *argv[]) own_buf = (char *) xmalloc (PBUFSIZ + 1); mem_buf = (unsigned char *) xmalloc (PBUFSIZ); + if (selftest) + { + selftests::run_tests (selftest_filter); + throw_quit ("Quit"); + } + if (pid == 0 && *next_arg != NULL) { int i, n; @@ -3940,13 +4062,10 @@ process_point_options (struct gdb_breakpoint *bp, char **packet) static int process_serial_event (void) { - char ch; - int i = 0; int signal; unsigned int len; int res; CORE_ADDR mem_addr; - int pid; unsigned char sig; int packet_len; int new_packet_len = -1; @@ -3963,8 +4082,7 @@ process_serial_event (void) } response_needed = 1; - i = 0; - ch = own_buf[i++]; + char ch = own_buf[0]; switch (ch) { case 'q': @@ -3974,91 +4092,7 @@ process_serial_event (void) handle_general_set (own_buf); break; case 'D': - require_running (own_buf); - - if (multi_process) - { - i++; /* skip ';' */ - pid = strtol (&own_buf[i], NULL, 16); - } - else - pid = ptid_get_pid (current_ptid); - - if ((tracing && disconnected_tracing) || any_persistent_commands ()) - { - struct process_info *process = find_process_pid (pid); - - if (process == NULL) - { - write_enn (own_buf); - break; - } - - if (tracing && disconnected_tracing) - fprintf (stderr, - "Disconnected tracing in effect, " - "leaving gdbserver attached to the process\n"); - - if (any_persistent_commands ()) - fprintf (stderr, - "Persistent commands are present, " - "leaving gdbserver attached to the process\n"); - - /* Make sure we're in non-stop/async mode, so we we can both - wait for an async socket accept, and handle async target - events simultaneously. There's also no point either in - having the target stop all threads, when we're going to - pass signals down without informing GDB. */ - if (!non_stop) - { - if (debug_threads) - debug_printf ("Forcing non-stop mode\n"); - - non_stop = 1; - start_non_stop (1); - } - - process->gdb_detached = 1; - - /* Detaching implicitly resumes all threads. */ - target_continue_no_signal (minus_one_ptid); - - write_ok (own_buf); - break; /* from switch/case */ - } - - fprintf (stderr, "Detaching from process %d\n", pid); - stop_tracing (); - if (detach_inferior (pid) != 0) - write_enn (own_buf); - else - { - discard_queued_stop_replies (pid_to_ptid (pid)); - write_ok (own_buf); - - if (extended_protocol || target_running ()) - { - /* There is still at least one inferior remaining or - we are in extended mode, so don't terminate gdbserver, - and instead treat this like a normal program exit. */ - last_status.kind = TARGET_WAITKIND_EXITED; - last_status.value.integer = 0; - last_ptid = pid_to_ptid (pid); - - current_thread = NULL; - } - else - { - putpkt (own_buf); - remote_close (); - - /* If we are attached, then we can exit. Otherwise, we - need to hang around doing nothing, until the child is - gone. */ - join_inferior (pid); - exit (0); - } - } + handle_detach (own_buf); break; case '!': extended_protocol = 1; @@ -4070,27 +4104,18 @@ process_serial_event (void) case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { - ptid_t gdb_id, thread_id; - int pid; - - require_running (own_buf); + require_running_or_break (own_buf); - gdb_id = read_ptid (&own_buf[2], NULL); + ptid_t thread_id = read_ptid (&own_buf[2], NULL); - pid = ptid_get_pid (gdb_id); - - if (ptid_equal (gdb_id, null_ptid) - || ptid_equal (gdb_id, minus_one_ptid)) + if (thread_id == null_ptid || thread_id == minus_one_ptid) thread_id = null_ptid; - else if (pid != 0 - && ptid_equal (pid_to_ptid (pid), - gdb_id)) + else if (thread_id.is_pid ()) { - struct thread_info *thread = - (struct thread_info *) find_inferior (&all_threads, - first_thread_of, - &pid); - if (!thread) + /* The ptid represents a pid. */ + thread_info *thread = find_any_thread_of_pid (thread_id.pid ()); + + if (thread == NULL) { write_enn (own_buf); break; @@ -4100,8 +4125,8 @@ process_serial_event (void) } else { - thread_id = gdb_id_to_thread_id (gdb_id); - if (ptid_equal (thread_id, null_ptid)) + /* The ptid represents a lwp/tid. */ + if (find_thread_ptid (thread_id) == NULL) { write_enn (own_buf); break; @@ -4124,7 +4149,7 @@ process_serial_event (void) } general_thread = thread_id; - set_desired_thread (1); + set_desired_thread (); gdb_assert (current_thread != NULL); } else if (own_buf[1] == 'c') @@ -4140,7 +4165,7 @@ process_serial_event (void) } break; case 'g': - require_running (own_buf); + require_running_or_break (own_buf); if (current_traceframe >= 0) { struct regcache *regcache @@ -4157,7 +4182,7 @@ process_serial_event (void) { struct regcache *regcache; - if (!set_desired_thread (1)) + if (!set_desired_thread ()) write_enn (own_buf); else { @@ -4167,14 +4192,14 @@ process_serial_event (void) } break; case 'G': - require_running (own_buf); + require_running_or_break (own_buf); if (current_traceframe >= 0) write_enn (own_buf); else { struct regcache *regcache; - if (!set_desired_thread (1)) + if (!set_desired_thread ()) write_enn (own_buf); else { @@ -4185,7 +4210,7 @@ process_serial_event (void) } break; case 'm': - require_running (own_buf); + require_running_or_break (own_buf); decode_m_packet (&own_buf[1], &mem_addr, &len); res = gdb_read_memory (mem_addr, mem_buf, len); if (res < 0) @@ -4194,7 +4219,7 @@ process_serial_event (void) bin2hex (mem_buf, own_buf, res); break; case 'M': - require_running (own_buf); + require_running_or_break (own_buf); decode_M_packet (&own_buf[1], &mem_addr, &len, &mem_buf); if (gdb_write_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); @@ -4202,7 +4227,7 @@ process_serial_event (void) write_enn (own_buf); break; case 'X': - require_running (own_buf); + require_running_or_break (own_buf); if (decode_X_packet (&own_buf[1], packet_len - 1, &mem_addr, &len, &mem_buf) < 0 || gdb_write_memory (mem_addr, mem_buf, len) != 0) @@ -4211,7 +4236,7 @@ process_serial_event (void) write_ok (own_buf); break; case 'C': - require_running (own_buf); + require_running_or_break (own_buf); hex2bin (own_buf + 1, &sig, 1); if (gdb_signal_to_host_p ((enum gdb_signal) sig)) signal = gdb_signal_to_host ((enum gdb_signal) sig); @@ -4220,7 +4245,7 @@ process_serial_event (void) myresume (own_buf, 0, signal); break; case 'S': - require_running (own_buf); + require_running_or_break (own_buf); hex2bin (own_buf + 1, &sig, 1); if (gdb_signal_to_host_p ((enum gdb_signal) sig)) signal = gdb_signal_to_host ((enum gdb_signal) sig); @@ -4229,12 +4254,12 @@ process_serial_event (void) myresume (own_buf, 1, signal); break; case 'c': - require_running (own_buf); + require_running_or_break (own_buf); signal = 0; myresume (own_buf, 0, signal); break; case 's': - require_running (own_buf); + require_running_or_break (own_buf); signal = 0; myresume (own_buf, 1, signal); break; @@ -4306,13 +4331,10 @@ process_serial_event (void) case 'T': { - ptid_t gdb_id, thread_id; + require_running_or_break (own_buf); - require_running (own_buf); - - gdb_id = read_ptid (&own_buf[1], NULL); - thread_id = gdb_id_to_thread_id (gdb_id); - if (ptid_equal (thread_id, null_ptid)) + ptid_t thread_id = read_ptid (&own_buf[1], NULL); + if (find_thread_ptid (thread_id) == NULL) { write_enn (own_buf); break; @@ -4408,7 +4430,7 @@ handle_serial_event (int err, gdb_client_data client_data) /* Be sure to not change the selected thread behind GDB's back. Important in the non-stop mode asynchronous protocol. */ - set_desired_thread (1); + set_desired_thread (); return 0; } @@ -4503,7 +4525,18 @@ handle_target_event (int err, gdb_client_data client_data) /* Be sure to not change the selected thread behind GDB's back. Important in the non-stop mode asynchronous protocol. */ - set_desired_thread (1); + set_desired_thread (); return 0; } + +#if GDB_SELF_TEST +namespace selftests +{ + +void +reset () +{} + +} // namespace selftests +#endif /* GDB_SELF_TEST */ diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c index 7526463..7f5bed7 100644 --- a/gdb/gdbserver/target.c +++ b/gdb/gdbserver/target.c @@ -24,14 +24,9 @@ struct target_ops *the_target; int -set_desired_thread (int use_general) +set_desired_thread () { - struct thread_info *found; - - if (use_general == 1) - found = find_thread_ptid (general_thread); - else - found = find_thread_ptid (cont_thread); + thread_info *found = find_thread_ptid (general_thread); current_thread = found; return (current_thread != NULL); @@ -388,10 +383,15 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr) return size; } +/* Define it. */ + +enum target_terminal::terminal_state target_terminal::terminal_state + = target_terminal::terminal_is_ours; + /* See target/target.h. */ void -target_terminal_init () +target_terminal::init () { /* Placeholder needed because of fork_inferior. Not necessary on GDBserver. */ @@ -400,7 +400,7 @@ target_terminal_init () /* See target/target.h. */ void -target_terminal_inferior () +target_terminal::inferior () { /* Placeholder needed because of fork_inferior. Not necessary on GDBserver. */ @@ -409,8 +409,24 @@ target_terminal_inferior () /* See target/target.h. */ void -target_terminal_ours () +target_terminal::ours () { /* Placeholder needed because of fork_inferior. Not necessary on GDBserver. */ } + +/* See target/target.h. */ + +void +target_terminal::ours_for_output (void) +{ + /* Placeholder. */ +} + +/* See target/target.h. */ + +void +target_terminal::info (const char *arg, int from_tty) +{ + /* Placeholder. */ +} diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index be89258..0a3d1db 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -475,6 +475,11 @@ struct target_ops /* Return tdesc index for IPA. */ int (*get_ipa_tdesc_idx) (void); + + /* Thread ID to (numeric) thread handle: Return true on success and + false for failure. Return pointer to thread handle via HANDLE + and the handle's length via HANDLE_LEN. */ + bool (*thread_handle) (ptid_t ptid, gdb_byte **handle, int *handle_len); }; extern struct target_ops *the_target; @@ -693,12 +698,17 @@ void done_accessing_memory (void); (the_target->thread_name ? (*the_target->thread_name) (ptid) \ : NULL) +#define target_thread_handle(ptid, handle, handle_len) \ + (the_target->thread_handle ? (*the_target->thread_handle) \ + (ptid, handle, handle_len) \ + : false) + int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len); -int set_desired_thread (int id); +int set_desired_thread (); const char *target_pid_to_str (ptid_t); diff --git a/gdb/gdbserver/tdesc.c b/gdb/gdbserver/tdesc.c index fdd35197..63d6467 100644 --- a/gdb/gdbserver/tdesc.c +++ b/gdb/gdbserver/tdesc.c @@ -22,13 +22,12 @@ void init_target_desc (struct target_desc *tdesc) { - int offset, i; + int offset = 0; - offset = 0; - for (i = 0; i < tdesc->num_registers; i++) + for (reg *reg : tdesc->reg_defs) { - tdesc->reg_defs[i].offset = offset; - offset += tdesc->reg_defs[i].size; + reg->offset = offset; + offset += reg->size; } tdesc->registers_size = offset / 8; @@ -38,16 +37,21 @@ init_target_desc (struct target_desc *tdesc) gdb_assert (2 * tdesc->registers_size + 32 <= PBUFSIZ); } +struct target_desc * +allocate_target_description (void) +{ + return new target_desc (); +} + #ifndef IN_PROCESS_AGENT -static const struct target_desc default_description = { 0 }; +static const struct target_desc default_description {}; void copy_target_description (struct target_desc *dest, const struct target_desc *src) { dest->reg_defs = src->reg_defs; - dest->num_registers = src->num_registers; dest->expedite_regs = src->expedite_regs; dest->registers_size = src->registers_size; dest->xmltarget = src->xmltarget; @@ -62,4 +66,174 @@ current_target_desc (void) return current_process ()->tdesc; } +/* See arch/tdesc.h. */ + +void +set_tdesc_architecture (struct target_desc *target_desc, + const char *name) +{ + target_desc->arch = xstrdup (name); +} + +/* See arch/tdesc.h. */ + +void +set_tdesc_osabi (struct target_desc *target_desc, const char *name) +{ + target_desc->osabi = xstrdup (name); +} + +/* Return a string which is of XML format, including XML target + description to be sent to GDB. */ + +const char * +tdesc_get_features_xml (target_desc *tdesc) +{ + /* Either .xmltarget or .features is not NULL. */ + gdb_assert (tdesc->xmltarget != NULL + || (tdesc->features != NULL + && tdesc->arch != NULL + && tdesc->osabi != NULL)); + + if (tdesc->xmltarget == NULL) + { + std::string buffer ("@<?xml version=\"1.0\"?>"); + + buffer += "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"; + buffer += "<target>"; + buffer += "<architecture>"; + buffer += tdesc->arch; + buffer += "</architecture>"; + + buffer += "<osabi>"; + buffer += tdesc->osabi; + buffer += "</osabi>"; + + char *xml; + + for (int i = 0; VEC_iterate (char_ptr, tdesc->features, i, xml); i++) + { + buffer += "<xi:include href=\""; + buffer += xml; + buffer += "\"/>"; + } + + buffer += "</target>"; + + tdesc->xmltarget = xstrdup (buffer.c_str ()); + } + + return tdesc->xmltarget; +} #endif + +struct tdesc_type +{}; + +/* See arch/tdesc.h. */ + +struct tdesc_feature * +tdesc_create_feature (struct target_desc *tdesc, const char *name, + const char *xml) +{ +#ifndef IN_PROCESS_AGENT + VEC_safe_push (char_ptr, tdesc->features, xstrdup (xml)); +#endif + return tdesc; +} + +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_flags (struct tdesc_feature *feature, const char *name, + int size) +{ + return NULL; +} + +/* See arch/tdesc.h. */ + +void +tdesc_add_flag (struct tdesc_type *type, int start, + const char *flag_name) +{} + +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_named_type (const struct tdesc_feature *feature, const char *id) +{ + return NULL; +} + +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_union (struct tdesc_feature *feature, const char *id) +{ + return NULL; +} + +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_struct (struct tdesc_feature *feature, const char *id) +{ + return NULL; +} + +/* See arch/tdesc.h. */ + +void +tdesc_create_reg (struct tdesc_feature *feature, const char *name, + int regnum, int save_restore, const char *group, + int bitsize, const char *type) +{ + struct target_desc *tdesc = (struct target_desc *) feature; + + while (tdesc->reg_defs.size () < regnum) + { + struct reg *reg = XCNEW (struct reg); + + reg->name = ""; + reg->size = 0; + tdesc->reg_defs.push_back (reg); + } + + gdb_assert (regnum == 0 + || regnum == tdesc->reg_defs.size ()); + + struct reg *reg = XCNEW (struct reg); + + reg->name = name; + reg->size = bitsize; + tdesc->reg_defs.push_back (reg); +} + +/* See arch/tdesc.h. */ + +struct tdesc_type * +tdesc_create_vector (struct tdesc_feature *feature, const char *name, + struct tdesc_type *field_type, int count) +{ + return NULL; +} + +void +tdesc_add_bitfield (struct tdesc_type *type, const char *field_name, + int start, int end) +{} + +/* See arch/tdesc.h. */ + +void +tdesc_add_field (struct tdesc_type *type, const char *field_name, + struct tdesc_type *field_type) +{} + +/* See arch/tdesc.h. */ + +void +tdesc_set_struct_size (struct tdesc_type *type, int size) +{ +} diff --git a/gdb/gdbserver/tdesc.h b/gdb/gdbserver/tdesc.h index 0341278..24efcd1 100644 --- a/gdb/gdbserver/tdesc.h +++ b/gdb/gdbserver/tdesc.h @@ -19,19 +19,22 @@ #ifndef TDESC_H #define TDESC_H -struct reg; +#include "arch/tdesc.h" -/* A target description. */ +#include "regdef.h" +#include <vector> -struct target_desc +struct tdesc_feature +{}; + +/* A target description. Inherit from tdesc_feature so that target_desc + can be used as tdesc_feature. */ + +struct target_desc : tdesc_feature { - /* An array of NUM_REGISTERS elements of register definitions that + /* A vector of elements of register definitions that describe the inferior's register set. */ - struct reg *reg_defs; - - /* The number of registers in inferior's register set (and thus in - the regcache). */ - int num_registers; + std::vector<struct reg *> reg_defs; /* The register cache size, in bytes. */ int registers_size; @@ -39,13 +42,79 @@ struct target_desc #ifndef IN_PROCESS_AGENT /* An array of register names. These are the "expedite" registers: registers whose values are sent along with stop replies. */ - const char **expedite_regs; + const char **expedite_regs = NULL; /* Defines what to return when looking for the "target.xml" file in response to qXfer:features:read. Its contents can either be verbatim XML code (prefixed with a '@') or else the name of the - actual XML file to be used in place of "target.xml". */ - const char *xmltarget; + actual XML file to be used in place of "target.xml". + + It can be NULL, then, its content is got from the following three + fields features, arch, and osabi in tdesc_get_features_xml. */ + const char *xmltarget = NULL; + + /* XML features in this target description. */ + VEC (char_ptr) *features = NULL; + + /* The value of <architecture> element in the XML, replying GDB. */ + const char *arch = NULL; + + /* The value of <osabi> element in the XML, replying GDB. */ + const char *osabi = NULL; + +public: + target_desc () + : registers_size (0) + {} + + ~target_desc () + { + int i; + + for (reg *reg : reg_defs) + xfree (reg); + + xfree ((char *) arch); + xfree ((char *) osabi); + + char *f; + + for (i = 0; VEC_iterate (char_ptr, features, i, f); i++) + xfree (f); + VEC_free (char_ptr, features); + } + + bool operator== (const target_desc &other) const + { + if (reg_defs.size () != other.reg_defs.size ()) + return false; + + for (int i = 0; i < reg_defs.size (); ++i) + { + struct reg *reg = reg_defs[i]; + struct reg *reg2 = other.reg_defs[i]; + + if (reg != reg2 && *reg != *reg2) + return false; + } + + /* Compare expedite_regs. */ + int i = 0; + for (; expedite_regs[i] != NULL; i++) + { + if (strcmp (expedite_regs[i], other.expedite_regs[i]) != 0) + return false; + } + if (other.expedite_regs[i] != NULL) + return false; + + return true; + } + + bool operator!= (const target_desc &other) const + { + return !(*this == other); + } #endif }; @@ -63,4 +132,8 @@ void init_target_desc (struct target_desc *tdesc); const struct target_desc *current_target_desc (void); +#ifndef IN_PROCESS_AGENT +const char *tdesc_get_features_xml (struct target_desc *tdesc); +#endif + #endif /* TDESC_H */ diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index 1ffb79d..9156d89 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -200,6 +200,7 @@ find_one_thread (ptid_t ptid) lwp->thread_known = 1; lwp->th = th; + lwp->thread_handle = ti.ti_tid; return 1; } @@ -231,6 +232,7 @@ attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) gdb_assert (lwp != NULL); lwp->thread_known = 1; lwp->th = *th_p; + lwp->thread_handle = ti_p->ti_tid; return 1; } @@ -439,6 +441,36 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, return err; } +/* See linux-low.h. */ + +bool +thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len) +{ + struct thread_db *thread_db; + struct lwp_info *lwp; + struct thread_info *thread + = (struct thread_info *) find_inferior_id (&all_threads, ptid); + + if (thread == NULL) + return false; + + thread_db = get_thread_process (thread)->priv->thread_db; + + if (thread_db == NULL) + return false; + + lwp = get_thread_lwp (thread); + + if (!lwp->thread_known && !find_one_thread (thread->entry.id)) + return false; + + gdb_assert (lwp->thread_known); + + *handle = (gdb_byte *) &lwp->thread_handle; + *handle_len = sizeof (lwp->thread_handle); + return true; +} + #ifdef USE_LIBTHREAD_DB_DIRECTLY static int @@ -733,25 +765,12 @@ thread_db_init (void) return 0; } -static int -any_thread_of (struct inferior_list_entry *entry, void *args) -{ - int *pid_p = (int *) args; - - if (ptid_get_pid (entry->id) == *pid_p) - return 1; - - return 0; -} - static void switch_to_process (struct process_info *proc) { int pid = pid_of (proc); - current_thread = - (struct thread_info *) find_inferior (&all_threads, - any_thread_of, &pid); + current_thread = find_any_thread_of_pid (pid); } /* Disconnect from libthread_db and free resources. */ @@ -864,3 +883,19 @@ thread_db_handle_monitor_command (char *mon) /* Tell server.c to perform default processing. */ return 0; } + +/* See linux-low.h. */ + +void +thread_db_notice_clone (struct process_info *proc, ptid_t ptid) +{ + struct thread_db *thread_db = proc->priv->thread_db; + + /* If the thread layer isn't initialized, return. It may just + be that the program uses clone, but does not use libthread_db. */ + if (thread_db == NULL || !thread_db->all_symbols_looked_up) + return; + + if (!find_one_thread (ptid)) + warning ("Cannot find thread after clone.\n"); +} diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index d4fe76a..0f41ff4 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -3956,17 +3956,6 @@ cmd_qtstmat (char *packet) run_inferior_command (packet, strlen (packet) + 1); } -/* Helper for gdb_agent_about_to_close. - Return non-zero if thread ENTRY is in the same process in DATA. */ - -static int -same_process_p (struct inferior_list_entry *entry, void *data) -{ - int *pid = (int *) data; - - return ptid_get_pid (entry->id) == *pid; -} - /* Sent the agent a command to close it. */ void @@ -3981,8 +3970,7 @@ gdb_agent_about_to_close (int pid) saved_thread = current_thread; /* Find any thread which belongs to process PID. */ - current_thread = (struct thread_info *) - find_inferior (&all_threads, same_process_p, &pid); + current_thread = find_any_thread_of_pid (pid); strcpy (buf, "close"); @@ -5581,7 +5569,7 @@ force_unlock_trace_buffer (void) case, if we want to move the thread out of the jump pad, we need to single-step it until this function returns 0. */ -int +fast_tpoint_collect_result fast_tracepoint_collecting (CORE_ADDR thread_area, CORE_ADDR stop_pc, struct fast_tpoint_collect_status *status) @@ -5656,7 +5644,7 @@ fast_tracepoint_collecting (CORE_ADDR thread_area, if (tpoint == NULL) { warning ("in jump pad, but no matching tpoint?"); - return 0; + return fast_tpoint_collect_result::not_collecting; } else { @@ -5684,7 +5672,7 @@ fast_tracepoint_collecting (CORE_ADDR thread_area, if (tpoint == NULL) { warning ("in trampoline, but no matching tpoint?"); - return 0; + return fast_tpoint_collect_result::not_collecting; } else { @@ -5712,14 +5700,14 @@ fast_tracepoint_collecting (CORE_ADDR thread_area, { trace_debug ("fast_tracepoint_collecting:" " failed reading 'collecting' in the inferior"); - return 0; + return fast_tpoint_collect_result::not_collecting; } if (!ipa_collecting) { trace_debug ("fast_tracepoint_collecting: not collecting" " (and nobody is)."); - return 0; + return fast_tpoint_collect_result::not_collecting; } /* Some thread is collecting. Check which. */ @@ -5732,7 +5720,7 @@ fast_tracepoint_collecting (CORE_ADDR thread_area, { trace_debug ("fast_tracepoint_collecting: not collecting " "(another thread is)"); - return 0; + return fast_tpoint_collect_result::not_collecting; } tpoint @@ -5742,7 +5730,7 @@ fast_tracepoint_collecting (CORE_ADDR thread_area, warning ("fast_tracepoint_collecting: collecting, " "but tpoint %s not found?", paddress ((CORE_ADDR) ipa_collecting_obj.tpoint)); - return 0; + return fast_tpoint_collect_result::not_collecting; } /* The thread is within `gdb_collect', skip over the rest of @@ -5769,7 +5757,7 @@ fast_tracepoint_collecting (CORE_ADDR thread_area, fast_tracepoint_collecting, returning continue-until-break at %s", paddress (tpoint->adjusted_insn_addr)); - return 1; /* continue */ + return fast_tpoint_collect_result::before_insn; /* continue */ } else { @@ -5780,7 +5768,7 @@ fast_tracepoint_collecting, returning continue-until-break at %s", paddress (tpoint->adjusted_insn_addr), paddress (tpoint->adjusted_insn_addr_end)); - return 2; /* single-step */ + return fast_tpoint_collect_result::at_insn; /* single-step */ } } diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h index 799a16c..31103a3 100644 --- a/gdb/gdbserver/tracepoint.h +++ b/gdb/gdbserver/tracepoint.h @@ -115,9 +115,25 @@ struct fast_tpoint_collect_status CORE_ADDR adjusted_insn_addr_end; }; -int fast_tracepoint_collecting (CORE_ADDR thread_area, - CORE_ADDR stop_pc, - struct fast_tpoint_collect_status *status); +/* The possible states a thread can be in, related to the collection of fast + tracepoint. */ + +enum class fast_tpoint_collect_result +{ + /* Not collecting a fast tracepoint. */ + not_collecting, + + /* In the jump pad, but before the relocated instruction. */ + before_insn, + + /* In the jump pad, but at (or after) the relocated instruction. */ + at_insn, +}; + +fast_tpoint_collect_result fast_tracepoint_collecting + (CORE_ADDR thread_area, CORE_ADDR stop_pc, + struct fast_tpoint_collect_status *status); + void force_unlock_trace_buffer (void); int handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc); diff --git a/gdb/gdbserver/win32-i386-low.c b/gdb/gdbserver/win32-i386-low.c index c505190..03d6e17 100644 --- a/gdb/gdbserver/win32-i386-low.c +++ b/gdb/gdbserver/win32-i386-low.c @@ -18,6 +18,12 @@ #include "server.h" #include "win32-low.h" #include "x86-low.h" +#include "x86-xstate.h" +#ifdef __x86_64__ +#include "arch/amd64.h" +#endif +#include "arch/i386.h" +#include "tdesc.h" #ifndef CONTEXT_EXTENDED_REGISTERS #define CONTEXT_EXTENDED_REGISTERS 0 @@ -28,16 +34,6 @@ #define FLAG_TRACE_BIT 0x100 -#ifdef __x86_64__ -/* Defined in auto-generated build-time file gdb/gdbserver/amd64.c. */ -void init_registers_amd64 (void); -extern const struct target_desc *tdesc_amd64; -#else -/* Defined in auto-generated build-time file gdb/gdbserver/i386.c. */ -void init_registers_i386 (void); -extern const struct target_desc *tdesc_i386; -#endif - static struct x86_debug_reg_state debug_reg_state; static int @@ -45,7 +41,7 @@ update_debug_registers_callback (struct inferior_list_entry *entry, void *pid_p) { struct thread_info *thr = (struct thread_info *) entry; - win32_thread_info *th = (win32_thread_info *) inferior_target_data (thr); + win32_thread_info *th = (win32_thread_info *) thread_target_data (thr); int pid = *(int *) pid_p; /* Only update the threads of this process. */ @@ -90,7 +86,7 @@ static DWORD64 win32_get_current_dr (int dr) { win32_thread_info *th - = (win32_thread_info *) inferior_target_data (current_thread); + = (win32_thread_info *) thread_target_data (current_thread); win32_require_context (th); @@ -448,13 +444,18 @@ static const unsigned char i386_win32_breakpoint = 0xcc; static void i386_arch_setup (void) { + struct target_desc *tdesc; + #ifdef __x86_64__ - init_registers_amd64 (); - win32_tdesc = tdesc_amd64; + tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false, + false); #else - init_registers_i386 (); - win32_tdesc = tdesc_i386; + tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false); #endif + + init_target_desc (tdesc); + + win32_tdesc = tdesc; } struct win32_target_ops the_low_target = { diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 88f6911..cc84d15 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -198,7 +198,7 @@ thread_rec (ptid_t ptid, int get_context) if (thread == NULL) return NULL; - th = (win32_thread_info *) inferior_target_data (thread); + th = (win32_thread_info *) thread_target_data (thread); if (get_context) win32_require_context (th); return th; @@ -232,7 +232,7 @@ static void delete_thread_info (struct inferior_list_entry *entry) { struct thread_info *thread = (struct thread_info *) entry; - win32_thread_info *th = (win32_thread_info *) inferior_target_data (thread); + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); remove_thread (thread); CloseHandle (th->h); @@ -433,7 +433,7 @@ continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr) { struct thread_info *thread = (struct thread_info *) this_thread; int thread_id = * (int *) id_ptr; - win32_thread_info *th = (win32_thread_info *) inferior_target_data (thread); + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); if (thread_id == -1 || thread_id == th->tid) { @@ -1333,7 +1333,7 @@ static void suspend_one_thread (struct inferior_list_entry *entry) { struct thread_info *thread = (struct thread_info *) entry; - win32_thread_info *th = (win32_thread_info *) inferior_target_data (thread); + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); if (!th->suspended) { |