From 95954743cb49efcc384c378173606fd309b6e6ac Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 1 Apr 2009 22:50:24 +0000 Subject: [PATCH] 2009-04-01 Pedro Alves Implement the multiprocess extensions, and add linux multiprocess support. * server.h (ULONGEST): Declare. (struct ptid, ptid_t): New. (minus_one_ptid, null_ptid): Declare. (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) (ptid_get_tid, ptid_equal, ptid_is_pid): Declare. (struct inferior_list_entry): Change `id' type from unsigned from to ptid_t. (struct sym_cache, struct breakpoint, struct process_info_private): Forward declare. (struct process_info): Declare. (current_process): Declare. (all_processes): Declare. (initialize_inferiors): Declare. (add_thread): Adjust to use ptid_t. (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto. (add_process, remove_process, find_thread_pid): Declare. (find_inferior_id): Adjust to use ptid_t. (cont_thread, general_thread, step_thread): Change type to ptid_t. (multi_process): Declare. (push_event): Adjust to use ptid_t. (read_ptid, write_ptid): Declare. (prepare_resume_reply): Adjust to use ptid_t. (clear_symbol_cache): Declare. * inferiors.c (all_processes): New. (null_ptid, minus_one_ptid): New. (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) (ptid_get_tid, ptid_equal, ptid_is_pid): New. (add_thread): Change unsigned long to ptid. Remove gdb_id parameter. Adjust. (thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid. (gdb_id_to_thread): Rename to ... (find_thread_pid): ... this. Change unsigned long to ptid. (gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid. (loaded_dll, pull_pid_from_list): Adjust. (add_process, remove_process, find_process_pid) (get_thread_process, current_process, initialize_inferiors): New. * target.h (struct thread_resume) : Change type to ptid_t. (struct target_waitstatus) : Ditto. (struct target_ops) : Add `pid' argument. Change return type to int. (struct target_ops) : Add `pid' argument. (struct target_ops) : Change pid's type to ptid_t. (struct target_ops) : Add `ptid' field. Change return type to ptid. (kill_inferior, detach_inferior, join_inferior): Add `pid' argument. (mywait): Add `ptid' argument. Change return type to ptid_t. (target_pid_to_str): Declare. * target.c (set_desired_inferior): Adjust to use ptids. (mywait): Add new `ptid' argument. Adjust. (target_pid_to_str): New. * mem-break.h (free_all_breakpoints): Declare. * mem-break.c (breakpoints): Delelete. (set_breakpoint_at, delete_breakpoint, find_breakpoint_at) (check_mem_read, check_mem_write, delete_all_breakpoints): Adjust to use per-process breakpoint list. (free_all_breakpoints): New. * remote-utils.c (struct sym_cache) : Drop `const'. (symbol_cache, all_symbols_looked_up): Delete. (hexchars): New. (ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one, read_ptid): New. (prepare_resume_reply): Change ptid argument's type from unsigned long to ptid_t. Adjust. Implement W;process and X;process. (free_sym_cache, clear_symbol_cache): New. (look_up_one_symbol): Adjust to per-process symbol cache. * * server.c (cont_thread, general_thread, step_thread): Change type to ptid_t. (attached): Delete. (multi_process): New. (last_ptid): Change type to ptid_t. (struct vstop_notif) : Change type to ptid_t. (queue_stop_reply, push_event): Change `ptid' argument's type to ptid_t. (discard_queued_stop_replies): Add `pid' argument. (start_inferior): Adjust to use ptids. Adjust to mywait interface changes. Don't reference the `attached' global. (attach_inferior): Adjust to mywait interface changes. (handle_query): Adjust to use ptids. Parse GDB's qSupported features. Handle and report "multiprocess+". Handle "qAttached:PID". (handle_v_cont): Adjust to use ptids. Adjust to mywait interface changes. (handle_v_kill): New. (handle_v_stopped): Adjust to use target_pid_to_str. (handle_v_requests): Allow multiple attaches and runs when multiprocess extensions are in effect. Handle "vKill". (myresume): Adjust to use ptids. (queue_stop_reply_callback): Add `arg' parameter. Handle it. (handle_status): Adjust to discard_queued_stop_replies interface change. (first_thread_of, kill_inferior_callback) (detach_or_kill_inferior_callback, join_inferiors_callback): New. (main): Call initialize_inferiors. Adjust to use ptids, killing and detaching from all inferiors. Handle multiprocess packet variants. * linux-low.h: Include gdb_proc_service.h. (struct process_info_private): New. (struct linux_target_ops) : Use ptid_get_pid. : Use ptid_get_lwp. (get_lwp_thread): Adjust. (struct lwp_info): Add `dead' member. (find_lwp_pid): Declare. * linux-low.c (thread_db_active): Delete. (new_inferior): Adjust comment. (inferior_pid): Delete. (linux_add_process): New. (handle_extended_wait): Adjust. (add_lwp): Change unsigned long to ptid. (linux_create_inferior): Add process to processes table. Adjust to use ptids. Don't set new_inferior here. (linux_attach_lwp): Rename to ... (linux_attach_lwp_1): ... this. Add `initial' argument. Handle it. Adjust to use ptids. (linux_attach_lwp): New. (linux_attach): Add process to processes table. Don't set new_inferior here. (struct counter): New. (second_thread_of_pid_p, last_thread_of_process_p): New. (linux_kill_one_lwp): Add `args' parameter. Handle it. Adjust to multiple processes. (linux_kill): Add `pid' argument. Handle it. Adjust to multiple processes. Remove process from process table. (linux_detach_one_lwp): Add `args' parameter. Handle it. Adjust to multiple processes. (any_thread_of): New. (linux_detach): Add `pid' argument, and handle it. Remove process from processes table. (linux_join): Add `pid' argument. Handle it. (linux_thread_alive): Change unsighed long argument to ptid_t. Consider dead lwps as not being alive. (status_pending_p): Rename `dummy' argument to `arg'. Filter out threads we're not interested in. (same_lwp, find_lwp_pid): New. (linux_wait_for_lwp): Change `pid' argument's type from int to ptid_t. Adjust. (linux_wait_for_event): Rename to ... (linux_wait_for_event_1): ... this. Change `pid' argument's type from int to ptid_t. Adjust. (linux_wait_for_event): New. (linux_wait_1): Add `ptid' argument. Change return type to ptid_t. Adjust. Use last_thread_of_process_p. Remove processes that exit from the process table. (linux_wait): Add `ptid' argument. Change return type to ptid_t. Adjust. (mark_lwp_dead): New. (wait_for_sigstop): Adjust to use ptids. If a process exits while stopping all threads, mark its main lwp as dead. (linux_set_resume_request, linux_resume_one_thread): Adjust to use ptids. (fetch_register, usr_store_inferior_registers) (regsets_fetch_inferior_registers) (regsets_store_inferior_registers, linux_read_memory) (linux_write_memory): Inline `inferior_pid'. (linux_look_up_symbols): Adjust to use per-process `thread_db_active'. (linux_request_interrupt): Adjust to use ptids. (linux_read_auxv): Inline `inferior_pid'. (initialize_low): Don't reference thread_db_active. * gdb_proc_service.h (struct ps_prochandle) : Remove. * proc-service.c (ps_lgetregs): Use find_lwp_pid. (ps_getpid): Return the pid of the current inferior. * thread-db.c (proc_handle, thread_agent): Delete. (thread_db_create_event, thread_db_enable_reporting): Adjust to per-process data. (find_one_thread): Change argument type to ptid_t. Adjust to per-process data. (maybe_attach_thread): Adjust to per-process data and ptids. (thread_db_find_new_threads): Ditto. (thread_db_init): Ditto. * spu-low.c (spu_create_inferior, spu_attach): Add process to processes table. Adjust to use ptids. (spu_kill, spu_detach): Adjust interface. Remove process from processes table. (spu_join, spu_thread_alive): Adjust interface. (spu_wait): Adjust interface. Remove process from processes table. Adjust to use ptids. * win32-low.c (current_inferior_tid): Delete. (current_inferior_ptid): New. (debug_event_ptid): New. (thread_rec): Take a ptid. Adjust. (child_add_thread): Add `pid' argument. Adjust to use ptids. (child_delete_thread): Ditto. (do_initial_child_stuff): Add `attached' argument. Add process to processes table. (child_fetch_inferior_registers, child_store_inferior_registers): Adjust. (win32_create_inferior): Pass 0 to do_initial_child_stuff. (win32_attach): Pass 1 to do_initial_child_stuff. (win32_kill): Adjust interface. Remove process from processes table. (win32_detach): Ditto. (win32_join): Adjust interface. (win32_thread_alive): Take a ptid. (win32_resume): Adjust to use ptids. (get_child_debug_event): Ditto. (win32_wait): Adjust interface. Remove exiting process from processes table. --- gdb/gdbserver/ChangeLog | 203 ++++++++++++ gdb/gdbserver/gdb_proc_service.h | 4 +- gdb/gdbserver/inferiors.c | 169 ++++++++-- gdb/gdbserver/linux-low.c | 539 ++++++++++++++++++++++--------- gdb/gdbserver/linux-low.h | 28 +- gdb/gdbserver/mem-break.c | 47 ++- gdb/gdbserver/mem-break.h | 5 + gdb/gdbserver/proc-service.c | 5 +- gdb/gdbserver/remote-utils.c | 192 +++++++++-- gdb/gdbserver/server.c | 369 +++++++++++++++------ gdb/gdbserver/server.h | 132 +++++++- gdb/gdbserver/spu-low.c | 45 ++- gdb/gdbserver/target.c | 67 ++-- gdb/gdbserver/target.h | 51 +-- gdb/gdbserver/thread-db.c | 69 ++-- gdb/gdbserver/win32-low.c | 117 ++++--- 16 files changed, 1585 insertions(+), 457 deletions(-) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index a9bbf3ad356..6159aca735d 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,206 @@ +2009-04-01 Pedro Alves + + Implement the multiprocess extensions, and add linux multiprocess + support. + + * server.h (ULONGEST): Declare. + (struct ptid, ptid_t): New. + (minus_one_ptid, null_ptid): Declare. + (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) + (ptid_get_tid, ptid_equal, ptid_is_pid): Declare. + (struct inferior_list_entry): Change `id' type from unsigned from + to ptid_t. + (struct sym_cache, struct breakpoint, struct + process_info_private): Forward declare. + (struct process_info): Declare. + (current_process): Declare. + (all_processes): Declare. + (initialize_inferiors): Declare. + (add_thread): Adjust to use ptid_t. + (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto. + (add_process, remove_process, find_thread_pid): Declare. + (find_inferior_id): Adjust to use ptid_t. + (cont_thread, general_thread, step_thread): Change type to ptid_t. + (multi_process): Declare. + (push_event): Adjust to use ptid_t. + (read_ptid, write_ptid): Declare. + (prepare_resume_reply): Adjust to use ptid_t. + (clear_symbol_cache): Declare. + * inferiors.c (all_processes): New. + (null_ptid, minus_one_ptid): New. + (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) + (ptid_get_tid, ptid_equal, ptid_is_pid): New. + (add_thread): Change unsigned long to ptid. Remove gdb_id + parameter. Adjust. + (thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid. + (gdb_id_to_thread): Rename to ... + (find_thread_pid): ... this. Change unsigned long to ptid. + (gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid. + (loaded_dll, pull_pid_from_list): Adjust. + (add_process, remove_process, find_process_pid) + (get_thread_process, current_process, initialize_inferiors): New. + * target.h (struct thread_resume) : Change type to ptid_t. + (struct target_waitstatus) : Ditto. + (struct target_ops) : Add `pid' argument. Change + return type to int. + (struct target_ops) : Add `pid' argument. + (struct target_ops) : Change pid's type to ptid_t. + (struct target_ops) : Add `ptid' field. Change return type + to ptid. + (kill_inferior, detach_inferior, join_inferior): Add `pid' argument. + (mywait): Add `ptid' argument. Change return type to ptid_t. + (target_pid_to_str): Declare. + * target.c (set_desired_inferior): Adjust to use ptids. + (mywait): Add new `ptid' argument. Adjust. + (target_pid_to_str): New. + * mem-break.h (free_all_breakpoints): Declare. + * mem-break.c (breakpoints): Delelete. + (set_breakpoint_at, delete_breakpoint, find_breakpoint_at) + (check_mem_read, check_mem_write, delete_all_breakpoints): Adjust + to use per-process breakpoint list. + (free_all_breakpoints): New. + * remote-utils.c (struct sym_cache) : Drop `const'. + (symbol_cache, all_symbols_looked_up): Delete. + (hexchars): New. + (ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one, + read_ptid): New. + (prepare_resume_reply): Change ptid argument's type from unsigned + long to ptid_t. Adjust. Implement W;process and X;process. + (free_sym_cache, clear_symbol_cache): New. + (look_up_one_symbol): Adjust to per-process symbol cache. * + * server.c (cont_thread, general_thread, step_thread): Change type + to ptid_t. + (attached): Delete. + (multi_process): New. + (last_ptid): Change type to ptid_t. + (struct vstop_notif) : Change type to ptid_t. + (queue_stop_reply, push_event): Change `ptid' argument's type to + ptid_t. + (discard_queued_stop_replies): Add `pid' argument. + (start_inferior): Adjust to use ptids. Adjust to mywait interface + changes. Don't reference the `attached' global. + (attach_inferior): Adjust to mywait interface changes. + (handle_query): Adjust to use ptids. Parse GDB's qSupported + features. Handle and report "multiprocess+". Handle + "qAttached:PID". + (handle_v_cont): Adjust to use ptids. Adjust to mywait interface + changes. + (handle_v_kill): New. + (handle_v_stopped): Adjust to use target_pid_to_str. + (handle_v_requests): Allow multiple attaches and runs when + multiprocess extensions are in effect. Handle "vKill". + (myresume): Adjust to use ptids. + (queue_stop_reply_callback): Add `arg' parameter. Handle it. + (handle_status): Adjust to discard_queued_stop_replies interface + change. + (first_thread_of, kill_inferior_callback) + (detach_or_kill_inferior_callback, join_inferiors_callback): New. + (main): Call initialize_inferiors. Adjust to use ptids, killing + and detaching from all inferiors. Handle multiprocess packet + variants. + * linux-low.h: Include gdb_proc_service.h. + (struct process_info_private): New. + (struct linux_target_ops) : Use ptid_get_pid. + : Use ptid_get_lwp. + (get_lwp_thread): Adjust. + (struct lwp_info): Add `dead' member. + (find_lwp_pid): Declare. + * linux-low.c (thread_db_active): Delete. + (new_inferior): Adjust comment. + (inferior_pid): Delete. + (linux_add_process): New. + (handle_extended_wait): Adjust. + (add_lwp): Change unsigned long to ptid. + (linux_create_inferior): Add process to processes table. Adjust + to use ptids. Don't set new_inferior here. + (linux_attach_lwp): Rename to ... + (linux_attach_lwp_1): ... this. Add `initial' argument. Handle + it. Adjust to use ptids. + (linux_attach_lwp): New. + (linux_attach): Add process to processes table. Don't set + new_inferior here. + (struct counter): New. + (second_thread_of_pid_p, last_thread_of_process_p): New. + (linux_kill_one_lwp): Add `args' parameter. Handle it. Adjust to + multiple processes. + (linux_kill): Add `pid' argument. Handle it. Adjust to multiple + processes. Remove process from process table. + (linux_detach_one_lwp): Add `args' parameter. Handle it. Adjust + to multiple processes. + (any_thread_of): New. + (linux_detach): Add `pid' argument, and handle it. Remove process + from processes table. + (linux_join): Add `pid' argument. Handle it. + (linux_thread_alive): Change unsighed long argument to ptid_t. + Consider dead lwps as not being alive. + (status_pending_p): Rename `dummy' argument to `arg'. Filter out + threads we're not interested in. + (same_lwp, find_lwp_pid): New. + (linux_wait_for_lwp): Change `pid' argument's type from int to + ptid_t. Adjust. + (linux_wait_for_event): Rename to ... + (linux_wait_for_event_1): ... this. Change `pid' argument's type + from int to ptid_t. Adjust. + (linux_wait_for_event): New. + (linux_wait_1): Add `ptid' argument. Change return type to + ptid_t. Adjust. Use last_thread_of_process_p. Remove processes + that exit from the process table. + (linux_wait): Add `ptid' argument. Change return type to ptid_t. + Adjust. + (mark_lwp_dead): New. + (wait_for_sigstop): Adjust to use ptids. If a process exits while + stopping all threads, mark its main lwp as dead. + (linux_set_resume_request, linux_resume_one_thread): Adjust to use + ptids. + (fetch_register, usr_store_inferior_registers) + (regsets_fetch_inferior_registers) + (regsets_store_inferior_registers, linux_read_memory) + (linux_write_memory): Inline `inferior_pid'. + (linux_look_up_symbols): Adjust to use per-process + `thread_db_active'. + (linux_request_interrupt): Adjust to use ptids. + (linux_read_auxv): Inline `inferior_pid'. + (initialize_low): Don't reference thread_db_active. + * gdb_proc_service.h (struct ps_prochandle) : Remove. + * proc-service.c (ps_lgetregs): Use find_lwp_pid. + (ps_getpid): Return the pid of the current inferior. + * thread-db.c (proc_handle, thread_agent): Delete. + (thread_db_create_event, thread_db_enable_reporting): Adjust to + per-process data. + (find_one_thread): Change argument type to ptid_t. Adjust to + per-process data. + (maybe_attach_thread): Adjust to per-process data and ptids. + (thread_db_find_new_threads): Ditto. + (thread_db_init): Ditto. + * spu-low.c (spu_create_inferior, spu_attach): Add process to + processes table. Adjust to use ptids. + (spu_kill, spu_detach): Adjust interface. Remove process from + processes table. + (spu_join, spu_thread_alive): Adjust interface. + (spu_wait): Adjust interface. Remove process from processes + table. Adjust to use ptids. + * win32-low.c (current_inferior_tid): Delete. + (current_inferior_ptid): New. + (debug_event_ptid): New. + (thread_rec): Take a ptid. Adjust. + (child_add_thread): Add `pid' argument. Adjust to use ptids. + (child_delete_thread): Ditto. + (do_initial_child_stuff): Add `attached' argument. Add process to + processes table. + (child_fetch_inferior_registers, child_store_inferior_registers): + Adjust. + (win32_create_inferior): Pass 0 to do_initial_child_stuff. + (win32_attach): Pass 1 to do_initial_child_stuff. + (win32_kill): Adjust interface. Remove process from processes + table. + (win32_detach): Ditto. + (win32_join): Adjust interface. + (win32_thread_alive): Take a ptid. + (win32_resume): Adjust to use ptids. + (get_child_debug_event): Ditto. + (win32_wait): Adjust interface. Remove exiting process from + processes table. + 2009-04-01 Pedro Alves Non-stop mode support. diff --git a/gdb/gdbserver/gdb_proc_service.h b/gdb/gdbserver/gdb_proc_service.h index fc29f4135d4..4d153e6a189 100644 --- a/gdb/gdbserver/gdb_proc_service.h +++ b/gdb/gdbserver/gdb_proc_service.h @@ -66,8 +66,8 @@ typedef elf_gregset_t prgregset_t; /* Structure that identifies the target process. */ struct ps_prochandle { - /* The process id is all we need. */ - pid_t pid; + /* We don't need to track anything. All context is served from the + current inferior. */ }; #endif /* gdb_proc_service.h */ diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 8ad64fa8de7..2d26b6ab4f4 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -30,12 +30,88 @@ struct thread_info unsigned int gdb_id; }; +struct inferior_list all_processes; struct inferior_list all_threads; struct inferior_list all_dlls; int dlls_changed; struct thread_info *current_inferior; + +/* Oft used ptids */ +ptid_t null_ptid; +ptid_t minus_one_ptid; + +/* Create a ptid given the necessary PID, LWP, and TID components. */ + +ptid_t +ptid_build (int pid, long lwp, long tid) +{ + ptid_t ptid; + + ptid.pid = pid; + ptid.lwp = lwp; + ptid.tid = tid; + return ptid; +} + +/* Create a ptid from just a pid. */ + +ptid_t +pid_to_ptid (int pid) +{ + return ptid_build (pid, 0, 0); +} + +/* Fetch the pid (process id) component from a ptid. */ + +int +ptid_get_pid (ptid_t ptid) +{ + return ptid.pid; +} + +/* Fetch the lwp (lightweight process) component from a ptid. */ + +long +ptid_get_lwp (ptid_t ptid) +{ + return ptid.lwp; +} + +/* Fetch the tid (thread id) component from a ptid. */ + +long +ptid_get_tid (ptid_t ptid) +{ + return ptid.tid; +} + +/* ptid_equal() is used to test equality of two ptids. */ + +int +ptid_equal (ptid_t ptid1, ptid_t ptid2) +{ + return (ptid1.pid == ptid2.pid + && ptid1.lwp == ptid2.lwp + && ptid1.tid == ptid2.tid); +} + +/* Return true if this ptid represents a process. */ + +int +ptid_is_pid (ptid_t ptid) +{ + if (ptid_equal (minus_one_ptid, ptid)) + return 0; + if (ptid_equal (null_ptid, ptid)) + return 0; + + return (ptid_get_pid (ptid) != 0 + && ptid_get_lwp (ptid) == 0 + && ptid_get_tid (ptid) == 0); +} + #define get_thread(inf) ((struct thread_info *)(inf)) #define get_dll(inf) ((struct dll_info *)(inf)) @@ -93,7 +169,7 @@ remove_inferior (struct inferior_list *list, } void -add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id) +add_thread (ptid_t thread_id, void *target_data) { struct thread_info *new_thread = xmalloc (sizeof (*new_thread)); @@ -108,40 +184,38 @@ add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id) new_thread->target_data = target_data; set_inferior_regcache_data (new_thread, new_register_cache ()); - new_thread->gdb_id = gdb_id; } -unsigned int -thread_id_to_gdb_id (unsigned long thread_id) +ptid_t +thread_id_to_gdb_id (ptid_t thread_id) { struct inferior_list_entry *inf = all_threads.head; while (inf != NULL) { - struct thread_info *thread = get_thread (inf); - if (inf->id == thread_id) - return thread->gdb_id; + if (ptid_equal (inf->id, thread_id)) + return thread_id; inf = inf->next; } - return 0; + return null_ptid; } -unsigned int +ptid_t thread_to_gdb_id (struct thread_info *thread) { - return thread->gdb_id; + return thread->entry.id; } struct thread_info * -gdb_id_to_thread (unsigned int gdb_id) +find_thread_pid (ptid_t ptid) { struct inferior_list_entry *inf = all_threads.head; while (inf != NULL) { struct thread_info *thread = get_thread (inf); - if (thread->gdb_id == gdb_id) + if (ptid_equal (thread->entry.id, ptid)) return thread; inf = inf->next; } @@ -149,12 +223,12 @@ gdb_id_to_thread (unsigned int gdb_id) return NULL; } -unsigned long -gdb_id_to_thread_id (unsigned int gdb_id) +ptid_t +gdb_id_to_thread_id (ptid_t gdb_id) { - struct thread_info *thread = gdb_id_to_thread (gdb_id); + struct thread_info *thread = find_thread_pid (gdb_id); - return thread ? thread->entry.id : 0; + return thread ? thread->entry.id : null_ptid; } static void @@ -192,13 +266,13 @@ find_inferior (struct inferior_list *list, } struct inferior_list_entry * -find_inferior_id (struct inferior_list *list, unsigned long id) +find_inferior_id (struct inferior_list *list, ptid_t id) { struct inferior_list_entry *inf = list->head; while (inf != NULL) { - if (inf->id == id) + if (ptid_equal (inf->id, id)) return inf; inf = inf->next; } @@ -267,7 +341,7 @@ loaded_dll (const char *name, CORE_ADDR base_addr) struct dll_info *new_dll = xmalloc (sizeof (*new_dll)); memset (new_dll, 0, sizeof (*new_dll)); - new_dll->entry.id = -1; + new_dll->entry.id = minus_one_ptid; new_dll->name = xstrdup (name); new_dll->base_addr = base_addr; @@ -318,7 +392,7 @@ add_pid_to_list (struct inferior_list *list, unsigned long pid) struct inferior_list_entry *new_entry; new_entry = xmalloc (sizeof (struct inferior_list_entry)); - new_entry->id = pid; + new_entry->id = pid_to_ptid (pid); add_inferior_to_list (list, new_entry); } @@ -327,7 +401,7 @@ pull_pid_from_list (struct inferior_list *list, unsigned long pid) { struct inferior_list_entry *new_entry; - new_entry = find_inferior_id (list, pid); + new_entry = find_inferior_id (list, pid_to_ptid (pid)); if (new_entry == NULL) return 0; else @@ -337,3 +411,56 @@ pull_pid_from_list (struct inferior_list *list, unsigned long pid) return 1; } } + +struct process_info * +add_process (int pid, int attached) +{ + struct process_info *process; + + process = xcalloc (1, sizeof (*process)); + + process->head.id = pid_to_ptid (pid); + process->attached = attached; + + add_inferior_to_list (&all_processes, &process->head); + + return process; +} + +void +remove_process (struct process_info *process) +{ + clear_symbol_cache (&process->symbol_cache); + free_all_breakpoints (process); + remove_inferior (&all_processes, &process->head); +} + +struct process_info * +find_process_pid (int pid) +{ + return (struct process_info *) + find_inferior_id (&all_processes, pid_to_ptid (pid)); +} + +static struct process_info * +get_thread_process (struct thread_info *thread) +{ + int pid = ptid_get_pid (thread->entry.id); + return find_process_pid (pid); +} + +struct process_info * +current_process (void) +{ + if (current_inferior == NULL) + fatal ("Current inferior requested, but current_inferior is NULL\n"); + + return get_thread_process (current_inferior); +} + +void +initialize_inferiors (void) +{ + null_ptid = ptid_build (0, 0, 0); + minus_one_ptid = ptid_build (-1, 0, 0); +} diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index ba1d7b46bb9..eccc2e1a81f 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -90,7 +90,10 @@ representation of the thread ID. ``all_lwps'' is keyed by the process ID - which on Linux is (presently) - the same as the LWP ID. */ + the same as the LWP ID. + + ``all_processes'' is keyed by the "overall process ID", which + GNU/Linux calls tgid, "thread group ID". */ struct inferior_list all_lwps; @@ -105,24 +108,28 @@ int stopping_threads; /* FIXME make into a target method? */ int using_threads = 1; -static int thread_db_active; static int must_set_ptrace_flags; -/* This flag is true iff we've just created or attached to a new inferior - but it has not stopped yet. As soon as it does, we need to call the - low target's arch_setup callback. */ +/* This flag is true iff we've just created or attached to our first + inferior but it has not stopped yet. As soon as it does, we need + to call the low target's arch_setup callback. Doing this only on + the first inferior avoids reinializing the architecture on every + inferior, and avoids messing with the register caches of the + already running inferiors. NOTE: this assumes all inferiors under + control of gdbserver have the same architecture. */ static int new_inferior; static void linux_resume_one_lwp (struct inferior_list_entry *entry, int step, int signal, siginfo_t *info); static void linux_resume (struct thread_resume *resume_info, size_t n); static void stop_all_lwps (void); -static int linux_wait_for_event (int pid, int *wstat, int options); +static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); static int check_removed_breakpoint (struct lwp_info *event_child); -static void *add_lwp (unsigned long pid); +static void *add_lwp (ptid_t ptid); static int my_waitpid (int pid, int *status, int flags); static int linux_stopped_by_watchpoint (void); +static void mark_lwp_dead (struct lwp_info *lwp, int wstat); struct pending_signals { @@ -139,9 +146,6 @@ static char *disabled_regsets; static int num_regsets; #endif -/* FIXME: Delete eventually. */ -#define inferior_pid (lwpid_of (get_thread_lwp (current_inferior))) - /* The read/write ends of the pipe registered as waitable file in the event loop. */ static int linux_event_pipe[2] = { -1, -1 }; @@ -160,6 +164,24 @@ delete_lwp (struct lwp_info *lwp) free (lwp); } +/* Add a process to the common process list, and set its private + data. */ + +static struct process_info * +linux_add_process (int pid, int attached) +{ + struct process_info *proc; + + /* Is this the first process? If so, then set the arch. */ + if (all_processes.head == NULL) + new_inferior = 1; + + proc = add_process (pid, attached); + proc->private = xcalloc (1, sizeof (*proc->private)); + + return proc; +} + /* Handle a GNU/Linux extended wait response. If we see a clone event, we need to add the new LWP to our list (and not report the trap to higher layers). */ @@ -172,6 +194,7 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) if (event == PTRACE_EVENT_CLONE) { + ptid_t ptid; unsigned long new_pid; int ret, status = W_STOPCODE (SIGSTOP); @@ -195,9 +218,9 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) ptrace (PTRACE_SETOPTIONS, new_pid, 0, PTRACE_O_TRACECLONE); - new_lwp = (struct lwp_info *) add_lwp (new_pid); - add_thread (new_pid, new_lwp, new_pid); - new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp))); + ptid = ptid_build (pid_of (event_child), new_pid, 0); + new_lwp = (struct lwp_info *) add_lwp (ptid); + add_thread (ptid, new_lwp); /* Normally we will get the pending SIGSTOP. But in some cases we might get another signal delivered to the group first. @@ -266,14 +289,14 @@ get_stop_pc (void) } static void * -add_lwp (unsigned long pid) +add_lwp (ptid_t ptid) { struct lwp_info *lwp; lwp = (struct lwp_info *) xmalloc (sizeof (*lwp)); memset (lwp, 0, sizeof (*lwp)); - lwp->head.id = pid; + lwp->head.id = ptid; add_inferior_to_list (&all_lwps, &lwp->head); @@ -288,6 +311,7 @@ linux_create_inferior (char *program, char **allargs) { void *new_lwp; int pid; + ptid_t ptid; #if defined(__UCLIBC__) && defined(HAS_NOMMU) pid = vfork (); @@ -315,44 +339,58 @@ linux_create_inferior (char *program, char **allargs) _exit (0177); } - new_lwp = add_lwp (pid); - add_thread (pid, new_lwp, pid); + linux_add_process (pid, 0); + + ptid = ptid_build (pid, pid, 0); + new_lwp = add_lwp (ptid); + add_thread (ptid, new_lwp); must_set_ptrace_flags = 1; - new_inferior = 1; return pid; } /* Attach to an inferior process. */ -void -linux_attach_lwp (unsigned long pid) +static void +linux_attach_lwp_1 (unsigned long lwpid, int initial) { + ptid_t ptid; struct lwp_info *new_lwp; - if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0) + if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0) { - if (all_threads.head != NULL) + if (!initial) { /* If we fail to attach to an LWP, just warn. */ - fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", pid, + fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", lwpid, strerror (errno), errno); fflush (stderr); return; } else /* If we fail to attach to a process, report an error. */ - error ("Cannot attach to lwp %ld: %s (%d)\n", pid, + error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid, strerror (errno), errno); } /* FIXME: This intermittently fails. We need to wait for SIGSTOP first. */ - ptrace (PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE); + ptrace (PTRACE_SETOPTIONS, lwpid, 0, PTRACE_O_TRACECLONE); + + if (initial) + /* NOTE/FIXME: This lwp might have not been the tgid. */ + ptid = ptid_build (lwpid, lwpid, 0); + else + { + /* Note that extracting the pid from the current inferior is + safe, since we're always called in the context of the same + process as this new thread. */ + int pid = pid_of (get_thread_lwp (current_inferior)); + ptid = ptid_build (pid, lwpid, 0); + } - new_lwp = (struct lwp_info *) add_lwp (pid); - add_thread (pid, new_lwp, pid); - new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp))); + new_lwp = (struct lwp_info *) add_lwp (ptid); + add_thread (ptid, new_lwp); /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH brings it to a halt. @@ -389,42 +427,89 @@ linux_attach_lwp (unsigned long pid) new_lwp->stop_expected = 1; } +void +linux_attach_lwp (unsigned long lwpid) +{ + linux_attach_lwp_1 (lwpid, 0); +} + int linux_attach (unsigned long pid) { struct lwp_info *lwp; - linux_attach_lwp (pid); + linux_attach_lwp_1 (pid, 1); + + linux_add_process (pid, 1); if (!non_stop) { /* Don't ignore the initial SIGSTOP if we just attached to this process. It will be collected by wait shortly. */ - lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid); + lwp = (struct lwp_info *) find_inferior_id (&all_lwps, + ptid_build (pid, pid, 0)); lwp->stop_expected = 0; } - new_inferior = 1; + return 0; +} + +struct counter +{ + int pid; + int count; +}; + +static int +second_thread_of_pid_p (struct inferior_list_entry *entry, void *args) +{ + struct counter *counter = args; + + if (ptid_get_pid (entry->id) == counter->pid) + { + if (++counter->count > 1) + return 1; + } return 0; } -/* Kill the inferior process. Make us have no inferior. */ +static int +last_thread_of_process_p (struct thread_info *thread) +{ + ptid_t ptid = ((struct inferior_list_entry *)thread)->id; + int pid = ptid_get_pid (ptid); + struct counter counter = { pid , 0 }; -static void -linux_kill_one_lwp (struct inferior_list_entry *entry) + return (find_inferior (&all_threads, + second_thread_of_pid_p, &counter) == NULL); +} + +/* Kill the inferior lwp. */ + +static int +linux_kill_one_lwp (struct inferior_list_entry *entry, void *args) { struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); - int pid; int wstat; + int pid = * (int *) args; + + if (ptid_get_pid (entry->id) != pid) + return 0; /* We avoid killing the first thread here, because of a Linux kernel (at least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before the children get a chance to be reaped, it will remain a zombie forever. */ - if (entry == all_threads.head) - return; + + if (last_thread_of_process_p (thread)) + { + if (debug_threads) + fprintf (stderr, "lkop: is last of process %s\n", + target_pid_to_str (entry->id)); + return 0; + } /* If we're killing a running inferior, make sure it is stopped first, as PTRACE_KILL will not work otherwise. */ @@ -436,29 +521,35 @@ linux_kill_one_lwp (struct inferior_list_entry *entry) ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ - pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL); + pid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); } while (pid > 0 && WIFSTOPPED (wstat)); + + return 0; } -static void -linux_kill (void) +static int +linux_kill (int pid) { - struct thread_info *thread = (struct thread_info *) all_threads.head; + struct process_info *process; struct lwp_info *lwp; + struct thread_info *thread; int wstat; - int pid; + int lwpid; - if (thread == NULL) - return; + process = find_process_pid (pid); + if (process == NULL) + return -1; - for_each_inferior (&all_threads, linux_kill_one_lwp); + find_inferior (&all_threads, linux_kill_one_lwp, &pid); /* See the comment in linux_kill_one_lwp. We did not kill the first thread in the list, so do so now. */ - lwp = get_thread_lwp (thread); + lwp = find_lwp_pid (pid_to_ptid (pid)); + thread = get_lwp_thread (lwp); if (debug_threads) - fprintf (stderr, "lk_1: killing lwp %ld\n", lwpid_of (lwp)); + fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n", + lwpid_of (lwp), pid); /* If we're killing a running inferior, make sure it is stopped first, as PTRACE_KILL will not work otherwise. */ @@ -470,24 +561,29 @@ linux_kill (void) ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ - pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL); - } while (pid > 0 && WIFSTOPPED (wstat)); + lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); + } while (lwpid > 0 && WIFSTOPPED (wstat)); delete_lwp (lwp); - clear_inferiors (); + remove_process (process); + return 0; } -static void -linux_detach_one_lwp (struct inferior_list_entry *entry) +static int +linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) { struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); + int pid = * (int *) args; + + if (ptid_get_pid (entry->id) != pid) + return 0; /* If we're detaching from a running inferior, make sure it is stopped first, as PTRACE_DETACH will not work otherwise. */ if (!lwp->stopped) { - int pid = lwpid_of (lwp); + int lwpid = lwpid_of (lwp); stopping_threads = 1; send_sigstop (&lwp->head); @@ -500,9 +596,9 @@ linux_detach_one_lwp (struct inferior_list_entry *entry) /* If LWP exits while we're trying to stop it, there's nothing left to do. */ - lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid); + lwp = find_lwp_pid (pid_to_ptid (lwpid)); if (lwp == NULL) - return; + return 0; } /* Make sure the process isn't stopped at a breakpoint that's @@ -519,7 +615,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry) lwp->stop_expected = 0; if (lwp->stopped) linux_resume_one_lwp (&lwp->head, 0, 0, NULL); - linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL); + linux_wait_for_event (lwp->head.id, &wstat, __WALL); } /* Flush any pending changes to the process's registers. */ @@ -530,29 +626,50 @@ linux_detach_one_lwp (struct inferior_list_entry *entry) ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0); delete_lwp (lwp); + return 0; } static int -linux_detach (void) +any_thread_of (struct inferior_list_entry *entry, void *args) { + int *pid_p = args; + + if (ptid_get_pid (entry->id) == *pid_p) + return 1; + + return 0; +} + +static int +linux_detach (int pid) +{ + struct process_info *process; + + process = find_process_pid (pid); + if (process == NULL) + return -1; + + current_inferior = + (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid); + delete_all_breakpoints (); - for_each_inferior (&all_threads, linux_detach_one_lwp); - clear_inferiors (); + find_inferior (&all_threads, linux_detach_one_lwp, &pid); + remove_process (process); return 0; } static void -linux_join (void) +linux_join (int pid) { int status, ret; - struct thread_info *thread; - struct lwp_info *lwp; + struct process_info *process; - thread = (struct thread_info *) all_threads.head; - lwp = get_thread_lwp (thread); + process = find_process_pid (pid); + if (process == NULL) + return; do { - ret = my_waitpid (lwpid_of (lwp), &status, 0); + ret = my_waitpid (pid, &status, 0); if (WIFEXITED (status) || WIFSIGNALED (status)) break; } while (ret != -1 || errno != ECHILD); @@ -560,10 +677,15 @@ linux_join (void) /* Return nonzero if the given thread is still alive. */ static int -linux_thread_alive (unsigned long lwpid) +linux_thread_alive (ptid_t ptid) { - if (find_inferior_id (&all_threads, lwpid) != NULL) - return 1; + struct lwp_info *lwp = find_lwp_pid (ptid); + + /* We assume we always know if a thread exits. If a whole process + exited but we still haven't been able to report it to GDB, we'll + hold on to the last lwp of the dead process. */ + if (lwp != NULL) + return !lwp->dead; else return 0; } @@ -633,9 +755,16 @@ check_removed_breakpoint (struct lwp_info *event_child) /* Return 1 if this lwp has an interesting status pending. This function may silently resume an inferior lwp. */ static int -status_pending_p (struct inferior_list_entry *entry, void *dummy) +status_pending_p (struct inferior_list_entry *entry, void *arg) { struct lwp_info *lwp = (struct lwp_info *) entry; + ptid_t ptid = * (ptid_t *) arg; + + /* Check if we're only interested in events from a specific process + or its lwps. */ + if (!ptid_equal (minus_one_ptid, ptid) + && ptid_get_pid (ptid) != ptid_get_pid (lwp->head.id)) + return 0; if (lwp->status_pending_p && !lwp->suspended) if (check_removed_breakpoint (lwp)) @@ -653,15 +782,43 @@ status_pending_p (struct inferior_list_entry *entry, void *dummy) return (lwp->status_pending_p && !lwp->suspended); } +static int +same_lwp (struct inferior_list_entry *entry, void *data) +{ + ptid_t ptid = *(ptid_t *) data; + int lwp; + + if (ptid_get_lwp (ptid) != 0) + lwp = ptid_get_lwp (ptid); + else + lwp = ptid_get_pid (ptid); + + if (ptid_get_lwp (entry->id) == lwp) + return 1; + + return 0; +} + +struct lwp_info * +find_lwp_pid (ptid_t ptid) +{ + return (struct lwp_info*) find_inferior (&all_lwps, same_lwp, &ptid); +} + static struct lwp_info * -linux_wait_for_lwp (int pid, int *wstatp, int options) +linux_wait_for_lwp (ptid_t ptid, int *wstatp, int options) { int ret; - int to_wait_for = pid; + int to_wait_for = -1; struct lwp_info *child = NULL; if (debug_threads) - fprintf (stderr, "linux_wait_for_lwp: %d\n", pid); + fprintf (stderr, "linux_wait_for_lwp: %s\n", target_pid_to_str (ptid)); + + if (ptid_equal (ptid, minus_one_ptid)) + to_wait_for = -1; /* any child */ + else + to_wait_for = ptid_get_lwp (ptid); /* this lwp only */ options |= __WALL; @@ -679,7 +836,7 @@ retry: && WSTOPSIG (*wstatp) != 33))) fprintf (stderr, "Got an event from %d (%x)\n", ret, *wstatp); - child = (struct lwp_info *) find_inferior_id (&all_lwps, ret); + child = find_lwp_pid (pid_to_ptid (ret)); /* If we didn't find a process, one of two things presumably happened: - A process we started and then detached from has exited. Ignore it. @@ -716,7 +873,7 @@ retry: { struct thread_info *saved_inferior = current_inferior; current_inferior = (struct thread_info *) - find_inferior_id (&all_threads, lwpid_of (child)); + find_inferior_id (&all_threads, child->head.id); /* For testing only; i386_stop_pc prints out a diagnostic. */ if (the_low_target.get_pc != NULL) get_stop_pc (); @@ -733,29 +890,29 @@ retry: the stopped child otherwise. */ static int -linux_wait_for_event (int pid, int *wstat, int options) +linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) { CORE_ADDR stop_pc; struct lwp_info *event_child = NULL; int bp_status; struct lwp_info *requested_child = NULL; - /* Check for a process with a pending status. */ + /* Check for a lwp with a pending status. */ /* It is possible that the user changed the pending task's registers since it stopped. We correctly handle the change of PC if we hit a breakpoint (in check_removed_breakpoint); signals should be reported anyway. */ - if (pid == -1) + if (ptid_equal (ptid, minus_one_ptid) + || ptid_equal (pid_to_ptid (ptid_get_pid (ptid)), ptid)) { event_child = (struct lwp_info *) - find_inferior (&all_lwps, status_pending_p, NULL); + find_inferior (&all_lwps, status_pending_p, &ptid); if (debug_threads && event_child) fprintf (stderr, "Got a pending child %ld\n", lwpid_of (event_child)); } else { - requested_child = (struct lwp_info *) - find_inferior_id (&all_lwps, pid); + requested_child = find_lwp_pid (ptid); if (requested_child->status_pending_p && !check_removed_breakpoint (requested_child)) event_child = requested_child; @@ -779,7 +936,7 @@ linux_wait_for_event (int pid, int *wstat, int options) events. */ while (1) { - event_child = linux_wait_for_lwp (pid, wstat, options); + event_child = linux_wait_for_lwp (ptid, wstat, options); if ((options & WNOHANG) && event_child == NULL) return 0; @@ -792,19 +949,18 @@ linux_wait_for_event (int pid, int *wstat, int options) /* Check for thread exit. */ if (! WIFSTOPPED (*wstat)) { - int lwpid = lwpid_of (event_child); if (debug_threads) - fprintf (stderr, "LWP %d exiting\n", lwpid); + fprintf (stderr, "LWP %ld exiting\n", lwpid_of (event_child)); /* If the last thread is exiting, just return. */ - if (all_threads.head == all_threads.tail) + if (last_thread_of_process_p (current_inferior)) { if (debug_threads) - fprintf (stderr, "LWP %d is last lwp of process\n", lwpid); + fprintf (stderr, "LWP %ld is last lwp of process\n", + lwpid_of (event_child)); return lwpid_of (event_child); } - dead_thread_notify (thread_id_to_gdb_id (lwpid_of (event_child))); delete_lwp (event_child); if (!non_stop) @@ -824,7 +980,7 @@ linux_wait_for_event (int pid, int *wstat, int options) /* If we were waiting for this particular child to do something... well, it did something. */ if (requested_child != NULL) - return lwpid; + return lwpid_of (event_child); /* Wait for a more interesting event. */ continue; @@ -862,7 +1018,7 @@ linux_wait_for_event (int pid, int *wstat, int options) && !event_child->stepping && ( #ifdef USE_THREAD_DB - (thread_db_active + (current_process ()->private->thread_db_active && (WSTOPSIG (*wstat) == __SIGRTMIN || WSTOPSIG (*wstat) == __SIGRTMIN + 1)) || @@ -1000,16 +1156,56 @@ linux_wait_for_event (int pid, int *wstat, int options) return 0; } +static int +linux_wait_for_event (ptid_t ptid, int *wstat, int options) +{ + ptid_t wait_ptid; + + if (ptid_is_pid (ptid)) + { + /* A request to wait for a specific tgid. This is not possible + with waitpid, so instead, we wait for any child, and leave + children we're not interested in right now with a pending + status to report later. */ + wait_ptid = minus_one_ptid; + } + else + wait_ptid = ptid; + + while (1) + { + int event_pid; + + event_pid = linux_wait_for_event_1 (wait_ptid, wstat, options); + + if (event_pid > 0 + && ptid_is_pid (ptid) && ptid_get_pid (ptid) != event_pid) + { + struct lwp_info *event_child = find_lwp_pid (pid_to_ptid (event_pid)); + + if (! WIFSTOPPED (*wstat)) + mark_lwp_dead (event_child, *wstat); + else + { + event_child->status_pending_p = 1; + event_child->status_pending = *wstat; + } + } + else + return event_pid; + } +} + /* Wait for process, returns status. */ -static unsigned long -linux_wait_1 (struct target_waitstatus *ourstatus, int target_options) +static ptid_t +linux_wait_1 (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) { int w; struct thread_info *thread = NULL; struct lwp_info *lwp = NULL; int options; - int wait_pid = -1; int pid; /* Translate generic target options into linux options. */ @@ -1026,7 +1222,9 @@ retry: then we need to make sure we restart the other threads. We could pick a thread at random or restart all; restarting all is less arbitrary. */ - if (!non_stop && cont_thread != 0 && cont_thread != -1) + if (!non_stop + && !ptid_equal (cont_thread, null_ptid) + && !ptid_equal (cont_thread, minus_one_ptid)) { thread = (struct thread_info *) find_inferior_id (&all_threads, cont_thread); @@ -1035,18 +1233,18 @@ retry: if (thread == NULL) { struct thread_resume resume_info; - resume_info.thread = -1; + resume_info.thread = minus_one_ptid; resume_info.kind = resume_continue; resume_info.sig = 0; linux_resume (&resume_info, 1); } else - wait_pid = cont_thread; + ptid = cont_thread; } - pid = linux_wait_for_event (wait_pid, &w, options); + pid = linux_wait_for_event (ptid, &w, options); if (pid == 0) /* only if TARGET_WNOHANG */ - return pid; + return null_ptid; lwp = get_thread_lwp (current_inferior); @@ -1067,16 +1265,15 @@ retry: Report the exit status of the last thread to exit. This matches LinuxThreads' behavior. */ - if (all_threads.head == all_threads.tail) + if (last_thread_of_process_p (current_inferior)) { if (WIFEXITED (w) || WIFSIGNALED (w)) { - int pid; - - pid = pid_of (lwp); + int pid = pid_of (lwp); + struct process_info *process = find_process_pid (pid); delete_lwp (lwp); - clear_inferiors (); + remove_process (process); current_inferior = NULL; @@ -1098,7 +1295,7 @@ retry: } - return pid; + return pid_to_ptid (pid); } } else @@ -1135,12 +1332,12 @@ retry: } if (debug_threads) - fprintf (stderr, "linux_wait ret = %ld, %d, %d\n", - lwpid_of (lwp), + fprintf (stderr, "linux_wait ret = %s, %d, %d\n", + target_pid_to_str (lwp->head.id), ourstatus->kind, ourstatus->value.sig); - return lwpid_of (lwp); + return lwp->head.id; } /* Get rid of any pending event in the pipe. */ @@ -1171,25 +1368,26 @@ async_file_mark (void) be awakened anyway. */ } -static unsigned long -linux_wait (struct target_waitstatus *ourstatus, int target_options) +static ptid_t +linux_wait (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) { - unsigned long event_ptid; + ptid_t event_ptid; if (debug_threads) - fprintf (stderr, "linux_wait\n"); + fprintf (stderr, "linux_wait: [%s]\n", target_pid_to_str (ptid)); /* Flush the async file first. */ if (target_is_async_p ()) async_file_flush (); - event_ptid = linux_wait_1 (ourstatus, target_options); + event_ptid = linux_wait_1 (ptid, ourstatus, target_options); /* If at least one stop was reported, there may be more. A single SIGCHLD can signal more than one child stop. */ if (target_is_async_p () && (target_options & TARGET_WNOHANG) != 0 - && event_ptid != 0) + && !ptid_equal (event_ptid, null_ptid)) async_file_mark (); return event_ptid; @@ -1250,14 +1448,35 @@ send_sigstop (struct inferior_list_entry *entry) kill_lwp (pid, SIGSTOP); } +static void +mark_lwp_dead (struct lwp_info *lwp, int wstat) +{ + /* It's dead, really. */ + lwp->dead = 1; + + /* Store the exit status for later. */ + lwp->status_pending_p = 1; + lwp->status_pending = wstat; + + /* So that check_removed_breakpoint doesn't try to figure out if + this is stopped at a breakpoint. */ + lwp->pending_is_breakpoint = 0; + + /* Prevent trying to stop it. */ + lwp->stopped = 1; + + /* No further stops are expected from a dead lwp. */ + lwp->stop_expected = 0; +} + static void wait_for_sigstop (struct inferior_list_entry *entry) { struct lwp_info *lwp = (struct lwp_info *) entry; struct thread_info *saved_inferior; int wstat; - unsigned long saved_tid; - unsigned long ptid; + ptid_t saved_tid; + ptid_t ptid; if (lwp->stopped) return; @@ -1266,9 +1485,9 @@ wait_for_sigstop (struct inferior_list_entry *entry) if (saved_inferior != NULL) saved_tid = ((struct inferior_list_entry *) saved_inferior)->id; else - saved_tid = 0; /* avoid bogus unused warning */ + saved_tid = null_ptid; /* avoid bogus unused warning */ - ptid = lwpid_of (lwp); + ptid = lwp->head.id; linux_wait_for_event (ptid, &wstat, __WALL); @@ -1301,6 +1520,18 @@ wait_for_sigstop (struct inferior_list_entry *entry) } lwp->stop_expected = 1; } + else if (!WIFSTOPPED (wstat)) + { + if (debug_threads) + fprintf (stderr, "Process %ld exited while stopping LWPs\n", + lwpid_of (lwp)); + + /* Leave this status pending for the next time we're able to + report it. In the mean time, we'll report this lwp as dead + to GDB, so GDB doesn't try to read registers and memory from + it. */ + mark_lwp_dead (lwp, wstat); + } if (saved_inferior == NULL || linux_thread_alive (saved_tid)) current_inferior = saved_inferior; @@ -1474,11 +1705,19 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg) r = arg; for (ndx = 0; ndx < r->n; ndx++) - if (r->resume[ndx].thread == -1 || r->resume[ndx].thread == entry->id) - { - lwp->resume = &r->resume[ndx]; - return 0; - } + { + ptid_t ptid = r->resume[ndx].thread; + if (ptid_equal (ptid, minus_one_ptid) + || ptid_equal (ptid, entry->id) + || (ptid_is_pid (ptid) + && (ptid_get_pid (ptid) == pid_of (lwp))) + || (ptid_get_lwp (ptid) == -1 + && (ptid_get_pid (ptid) == pid_of (lwp)))) + { + lwp->resume = &r->resume[ndx]; + return 0; + } + } /* No resume action for this thread. */ lwp->resume = NULL; @@ -1550,7 +1789,7 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg) if (!lwp->stopped) { if (debug_threads) - fprintf (stderr, "running -> suspending %ld\n", lwpid_of (lwp)); + fprintf (stderr, "running -> suspending LWP %ld\n", lwpid_of (lwp)); lwp->suspended = 1; send_sigstop (&lwp->head); @@ -1596,7 +1835,7 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg) if (debug_threads) fprintf (stderr, "resuming LWP %ld\n", lwpid_of (lwp)); - if (lwp->resume->thread == -1 + if (ptid_equal (lwp->resume->thread, minus_one_ptid) && lwp->stepping && lwp->pending_is_breakpoint) step = 1; @@ -1685,6 +1924,7 @@ fetch_register (int regno) CORE_ADDR regaddr; int i, size; char *buf; + int pid; if (regno >= the_low_target.num_regs) return; @@ -1694,6 +1934,8 @@ fetch_register (int regno) regaddr = register_addr (regno); if (regaddr == -1) return; + + pid = lwpid_of (get_thread_lwp (current_inferior)); size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) & - sizeof (PTRACE_XFER_TYPE)); buf = alloca (size); @@ -1701,7 +1943,7 @@ fetch_register (int regno) { errno = 0; *(PTRACE_XFER_TYPE *) (buf + i) = - ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0); + ptrace (PTRACE_PEEKUSER, pid, (PTRACE_ARG3_TYPE) regaddr, 0); regaddr += sizeof (PTRACE_XFER_TYPE); if (errno != 0) { @@ -1766,10 +2008,11 @@ usr_store_inferior_registers (int regno) else collect_register (regno, buf); + pid = lwpid_of (get_thread_lwp (current_inferior)); for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + ptrace (PTRACE_POKEUSER, pid, (PTRACE_ARG3_TYPE) regaddr, *(PTRACE_XFER_TYPE *) (buf + i)); if (errno != 0) { @@ -1808,9 +2051,11 @@ regsets_fetch_inferior_registers () { struct regset_info *regset; int saw_general_regs = 0; + int pid; regset = target_regsets; + pid = lwpid_of (get_thread_lwp (current_inferior)); while (regset->size >= 0) { void *buf; @@ -1824,9 +2069,9 @@ regsets_fetch_inferior_registers () buf = xmalloc (regset->size); #ifndef __sparc__ - res = ptrace (regset->get_request, inferior_pid, 0, buf); + res = ptrace (regset->get_request, pid, 0, buf); #else - res = ptrace (regset->get_request, inferior_pid, buf, 0); + res = ptrace (regset->get_request, pid, buf, 0); #endif if (res < 0) { @@ -1840,8 +2085,8 @@ regsets_fetch_inferior_registers () else { char s[256]; - sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%ld", - inferior_pid); + sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d", + pid); perror (s); } } @@ -1861,9 +2106,11 @@ regsets_store_inferior_registers () { struct regset_info *regset; int saw_general_regs = 0; + int pid; regset = target_regsets; + pid = lwpid_of (get_thread_lwp (current_inferior)); while (regset->size >= 0) { void *buf; @@ -1881,9 +2128,9 @@ regsets_store_inferior_registers () in case there are any items in the kernel's regset that are not in gdbserver's regcache. */ #ifndef __sparc__ - res = ptrace (regset->get_request, inferior_pid, 0, buf); + res = ptrace (regset->get_request, pid, 0, buf); #else - res = ptrace (regset->get_request, inferior_pid, buf, 0); + res = ptrace (regset->get_request, pid, buf, 0); #endif if (res == 0) @@ -1893,9 +2140,9 @@ regsets_store_inferior_registers () /* Only now do we write the register set. */ #ifndef __sparc__ - res = ptrace (regset->set_request, inferior_pid, 0, buf); + res = ptrace (regset->set_request, pid, 0, buf); #else - res = ptrace (regset->set_request, inferior_pid, buf, 0); + res = ptrace (regset->set_request, pid, buf, 0); #endif } @@ -1979,13 +2226,14 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); int fd; char filename[64]; + int pid = lwpid_of (get_thread_lwp (current_inferior)); /* Try using /proc. Don't bother for one word. */ if (len >= 3 * sizeof (long)) { /* We could keep this file open and cache it - possibly one per thread. That requires some juggling, but is even faster. */ - sprintf (filename, "/proc/%ld/mem", inferior_pid); + sprintf (filename, "/proc/%d/mem", pid); fd = open (filename, O_RDONLY | O_LARGEFILE); if (fd == -1) goto no_proc; @@ -2013,8 +2261,7 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, - (PTRACE_ARG3_TYPE) addr, 0); + buffer[i] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0); if (errno) return errno; } @@ -2043,6 +2290,7 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + int pid = lwpid_of (get_thread_lwp (current_inferior)); if (debug_threads) { @@ -2051,13 +2299,12 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) /* Fill start and end extra bytes of buffer with existing memory data. */ - buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid, - (PTRACE_ARG3_TYPE) addr, 0); + buffer[0] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0); if (count > 1) { buffer[count - 1] - = ptrace (PTRACE_PEEKTEXT, inferior_pid, + = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE)), 0); @@ -2072,7 +2319,7 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); + ptrace (PTRACE_POKETEXT, pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); if (errno) return errno; } @@ -2278,10 +2525,13 @@ static void linux_look_up_symbols (void) { #ifdef USE_THREAD_DB - if (thread_db_active) + struct process_info *proc = current_process (); + + if (proc->private->thread_db_active) return; - thread_db_active = thread_db_init (!linux_supports_tracefork_flag); + proc->private->thread_db_active + = thread_db_init (!linux_supports_tracefork_flag); #endif } @@ -2290,7 +2540,8 @@ linux_request_interrupt (void) { extern unsigned long signal_pid; - if (cont_thread != 0 && cont_thread != -1) + if (!ptid_equal (cont_thread, null_ptid) + && !ptid_equal (cont_thread, minus_one_ptid)) { struct lwp_info *lwp; int lwpid; @@ -2311,8 +2562,9 @@ linux_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len) { char filename[PATH_MAX]; int fd, n; + int pid = lwpid_of (get_thread_lwp (current_inferior)); - snprintf (filename, sizeof filename, "/proc/%ld/auxv", inferior_pid); + snprintf (filename, sizeof filename, "/proc/%d/auxv", pid); fd = open (filename, O_RDONLY); if (fd < 0) @@ -2685,7 +2937,6 @@ initialize_low (void) { struct sigaction sigchld_action; memset (&sigchld_action, 0, sizeof (sigchld_action)); - thread_db_active = 0; set_target_ops (&linux_target_ops); set_breakpoint_data (the_low_target.breakpoint, the_low_target.breakpoint_len); diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 781845244da..b076c5d87e1 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -21,6 +21,8 @@ #include #endif +#include "gdb_proc_service.h" + #ifdef HAVE_LINUX_REGSETS typedef void (*regset_fill_func) (void *); typedef void (*regset_store_func) (const void *); @@ -41,6 +43,19 @@ struct regset_info extern struct regset_info target_regsets[]; #endif +struct process_info_private +{ + /* True if this process has loaded thread_db, and it is active. */ + int thread_db_active; + + /* Structure that identifies the child process for the + interface. */ + struct ps_prochandle proc_handle; + + /* Connection to the libthread_db library. */ + td_thragent_t *thread_agent; +}; + struct linux_target_ops { /* Architecture-specific setup. */ @@ -78,14 +93,14 @@ struct linux_target_ops extern struct linux_target_ops the_low_target; -#define pid_of(proc) ((proc)->head.id) -#define lwpid_of(proc) ((proc)->head.id) +#define pid_of(proc) ptid_get_pid ((proc)->head.id) +#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id) #define get_lwp(inf) ((struct lwp_info *)(inf)) #define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr))) #define get_lwp_thread(proc) ((struct thread_info *) \ find_inferior_id (&all_threads, \ - lwpid_of (get_lwp (proc)))) + get_lwp (proc)->head.id)) struct lwp_info { @@ -106,6 +121,11 @@ struct lwp_info event already received in a wait()). */ int stopped; + /* If this flag is set, the lwp is known to be dead already (exit + event already received in a wait(), and is cached in + status_pending). */ + int dead; + /* When stopped is set, the last wait status recorded for this lwp. */ int last_status; @@ -150,3 +170,5 @@ void linux_attach_lwp (unsigned long pid); int thread_db_init (int use_events); int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, CORE_ADDR load_module, CORE_ADDR *address); + +struct lwp_info *find_lwp_pid (ptid_t ptid); diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c index 8c0c05a7460..9d89326b06c 100644 --- a/gdb/gdbserver/mem-break.c +++ b/gdb/gdbserver/mem-break.c @@ -46,11 +46,10 @@ struct breakpoint int (*handler) (CORE_ADDR); }; -struct breakpoint *breakpoints; - void set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) { + struct process_info *proc = current_process (); struct breakpoint *bp; if (breakpoint_data == NULL) @@ -67,24 +66,25 @@ set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) bp->pc = where; bp->handler = handler; - bp->next = breakpoints; - breakpoints = bp; + bp->next = proc->breakpoints; + proc->breakpoints = bp; } static void delete_breakpoint (struct breakpoint *bp) { + struct process_info *proc = current_process (); struct breakpoint *cur; - if (breakpoints == bp) + if (proc->breakpoints == bp) { - breakpoints = bp->next; + proc->breakpoints = bp->next; (*the_target->write_memory) (bp->pc, bp->old_data, breakpoint_len); free (bp); return; } - cur = breakpoints; + cur = proc->breakpoints; while (cur->next) { if (cur->next == bp) @@ -102,7 +102,8 @@ delete_breakpoint (struct breakpoint *bp) static struct breakpoint * find_breakpoint_at (CORE_ADDR where) { - struct breakpoint *bp = breakpoints; + struct process_info *proc = current_process (); + struct breakpoint *bp = proc->breakpoints; while (bp != NULL) { @@ -225,7 +226,8 @@ set_breakpoint_data (const unsigned char *bp_data, int bp_len) void check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) { - struct breakpoint *bp = breakpoints; + struct process_info *proc = current_process (); + struct breakpoint *bp = proc->breakpoints; CORE_ADDR mem_end = mem_addr + mem_len; for (; bp != NULL; bp = bp->next) @@ -258,7 +260,8 @@ check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) void check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) { - struct breakpoint *bp = breakpoints; + struct process_info *proc = current_process (); + struct breakpoint *bp = proc->breakpoints; CORE_ADDR mem_end = mem_addr + mem_len; for (; bp != NULL; bp = bp->next) @@ -290,11 +293,29 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) } } -/* Delete all breakpoints. */ +/* Delete all breakpoints, and un-insert them from the inferior. */ void delete_all_breakpoints (void) { - while (breakpoints) - delete_breakpoint (breakpoints); + struct process_info *proc = current_process (); + + while (proc->breakpoints) + delete_breakpoint (proc->breakpoints); +} + +/* Release all breakpoints, but do not try to un-insert them from the + inferior. */ + +void +free_all_breakpoints (struct process_info *proc) +{ + struct breakpoint *bp; + + while (proc->breakpoints) + { + bp = proc->breakpoints; + proc->breakpoints = bp->next; + free (bp); + } } diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h index e7272a1fa62..87afe3dbcae 100644 --- a/gdb/gdbserver/mem-break.h +++ b/gdb/gdbserver/mem-break.h @@ -75,4 +75,9 @@ void set_breakpoint_data (const unsigned char *bp_data, int bp_len); void delete_all_breakpoints (void); +/* Delete all breakpoints, but do not try to un-insert them from the + inferior. */ + +void free_all_breakpoints (struct process_info *proc); + #endif /* MEM_BREAK_H */ diff --git a/gdb/gdbserver/proc-service.c b/gdb/gdbserver/proc-service.c index 053fba391f6..7999f4ad96a 100644 --- a/gdb/gdbserver/proc-service.c +++ b/gdb/gdbserver/proc-service.c @@ -102,8 +102,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset) struct lwp_info *lwp; struct thread_info *reg_inferior, *save_inferior; - lwp = (struct lwp_info *) find_inferior_id (&all_lwps, - lwpid); + lwp = find_lwp_pid (pid_to_ptid (lwpid)); if (lwp == NULL) return PS_ERR; @@ -157,5 +156,5 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, void *fpregset) pid_t ps_getpid (gdb_ps_prochandle_t ph) { - return ph->pid; + return pid_of (get_thread_lwp (current_inferior)); } diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index c506bf5eeb2..103bcc76eaa 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -79,18 +79,11 @@ typedef int socklen_t; /* A cache entry for a successfully looked-up symbol. */ struct sym_cache { - const char *name; + char *name; CORE_ADDR addr; struct sym_cache *next; }; -/* The symbol cache. */ -static struct sym_cache *symbol_cache; - -/* If this flag has been set, assume cache misses are - failures. */ -int all_symbols_looked_up; - int remote_debug = 0; struct ui_file *gdb_stdlog; @@ -317,6 +310,29 @@ fromhex (int a) return 0; } +static const char hexchars[] = "0123456789abcdef"; + +static int +ishex (int ch, int *val) +{ + if ((ch >= 'a') && (ch <= 'f')) + { + *val = ch - 'a' + 10; + return 1; + } + if ((ch >= 'A') && (ch <= 'F')) + { + *val = ch - 'A' + 10; + return 1; + } + if ((ch >= '0') && (ch <= '9')) + { + *val = ch - '0'; + return 1; + } + return 0; +} + int unhexify (char *bin, const char *hex, int count) { @@ -523,6 +539,103 @@ try_rle (char *buf, int remaining, unsigned char *csum, char **p) return n + 1; } +char * +unpack_varlen_hex (char *buff, /* packet to parse */ + ULONGEST *result) +{ + int nibble; + ULONGEST retval = 0; + + while (ishex (*buff, &nibble)) + { + buff++; + retval = retval << 4; + retval |= nibble & 0x0f; + } + *result = retval; + return buff; +} + +/* Write a PTID to BUF. Returns BUF+CHARACTERS_WRITTEN. */ + +char * +write_ptid (char *buf, ptid_t ptid) +{ + int pid, tid; + + if (multi_process) + { + pid = ptid_get_pid (ptid); + if (pid < 0) + buf += sprintf (buf, "p-%x.", -pid); + else + buf += sprintf (buf, "p%x.", pid); + } + tid = ptid_get_lwp (ptid); + if (tid < 0) + buf += sprintf (buf, "-%x", -tid); + else + buf += sprintf (buf, "%x", tid); + + return buf; +} + +ULONGEST +hex_or_minus_one (char *buf, char **obuf) +{ + ULONGEST ret; + + if (strncmp (buf, "-1", 2) == 0) + { + ret = (ULONGEST) -1; + buf += 2; + } + else + buf = unpack_varlen_hex (buf, &ret); + + if (obuf) + *obuf = buf; + + return ret; +} + +/* Extract a PTID from BUF. If non-null, OBUF is set to the to one + passed the last parsed char. Returns null_ptid on error. */ +ptid_t +read_ptid (char *buf, char **obuf) +{ + char *p = buf; + char *pp; + ULONGEST pid = 0, tid = 0; + + if (*p == 'p') + { + /* Multi-process ptid. */ + pp = unpack_varlen_hex (p + 1, &pid); + if (*pp != '.') + error ("invalid remote ptid: %s\n", p); + + p = pp + 1; + + tid = hex_or_minus_one (p, &pp); + + if (obuf) + *obuf = pp; + return ptid_build (pid, tid, 0); + } + + /* No multi-process. Just a tid. */ + tid = hex_or_minus_one (p, &pp); + + /* Since the stub is not sending a process id, then default to + what's in the current inferior. */ + pid = ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id); + + if (obuf) + *obuf = pp; + return ptid_build (pid, tid, 0); +} + /* Send a packet to the remote machine, with error checking. The data of the packet is in BUF, and the length of the packet is in CNT. Returns >= 0 on success, -1 otherwise. */ @@ -957,12 +1070,12 @@ dead_thread_notify (int id) } void -prepare_resume_reply (char *buf, unsigned long ptid, +prepare_resume_reply (char *buf, ptid_t ptid, struct target_waitstatus *status) { if (debug_threads) - fprintf (stderr, "Writing resume reply for %lu:%d\n\n", - ptid, status->kind); + fprintf (stderr, "Writing resume reply for %s:%d\n\n", + target_pid_to_str (ptid), status->kind); switch (status->kind) { @@ -978,7 +1091,7 @@ prepare_resume_reply (char *buf, unsigned long ptid, saved_inferior = current_inferior; - current_inferior = gdb_id_to_thread (ptid); + current_inferior = find_thread_pid (ptid); if (the_target->stopped_by_watchpoint != NULL && (*the_target->stopped_by_watchpoint) ()) @@ -1021,13 +1134,16 @@ prepare_resume_reply (char *buf, unsigned long ptid, in GDB will claim this event belongs to inferior_ptid if we do not specify a thread, and there's no way for gdbserver to know what inferior_ptid is. */ - if (1 || general_thread != ptid) + if (1 || !ptid_equal (general_thread, ptid)) { /* In non-stop, don't change the general thread behind GDB's back. */ if (!non_stop) general_thread = ptid; - sprintf (buf, "thread:%lx;", ptid); + sprintf (buf, "thread:"); + buf += strlen (buf); + buf = write_ptid (buf, ptid); + strcat (buf, ";"); buf += strlen (buf); } } @@ -1043,10 +1159,18 @@ prepare_resume_reply (char *buf, unsigned long ptid, } break; case TARGET_WAITKIND_EXITED: - sprintf (buf, "W%02x", status->value.integer); + if (multi_process) + sprintf (buf, "W%x;process:%x", + status->value.integer, ptid_get_pid (ptid)); + else + sprintf (buf, "W%02x", status->value.integer); break; case TARGET_WAITKIND_SIGNALLED: - sprintf (buf, "X%02x", status->value.sig); + if (multi_process) + sprintf (buf, "X%x;process:%x", + status->value.sig, ptid_get_pid (ptid)); + else + sprintf (buf, "X%02x", status->value.sig); break; default: error ("unhandled waitkind"); @@ -1174,6 +1298,31 @@ decode_search_memory_packet (const char *buf, int packet_len, return 0; } +static void +free_sym_cache (struct sym_cache *sym) +{ + if (sym != NULL) + { + free (sym->name); + free (sym); + } +} + +void +clear_symbol_cache (struct sym_cache **symcache_p) +{ + struct sym_cache *sym, *next; + + /* Check the cache first. */ + for (sym = *symcache_p; sym; sym = next) + { + next = sym->next; + free_sym_cache (sym); + } + + *symcache_p = NULL; +} + /* Ask GDB for the address of NAME, and return it in ADDRP if found. Returns 1 if the symbol is found, 0 if it is not, -1 on error. */ @@ -1183,9 +1332,12 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp) char own_buf[266], *p, *q; int len; struct sym_cache *sym; + struct process_info *proc; + + proc = current_process (); /* Check the cache first. */ - for (sym = symbol_cache; sym; sym = sym->next) + for (sym = proc->symbol_cache; sym; sym = sym->next) if (strcmp (name, sym->name) == 0) { *addrp = sym->addr; @@ -1197,7 +1349,7 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp) in any libraries loaded after that point, only in symbols in libpthread.so. It might not be an appropriate time to look up a symbol, e.g. while we're trying to fetch registers. */ - if (all_symbols_looked_up) + if (proc->all_symbols_looked_up) return 0; /* Send the request. */ @@ -1257,8 +1409,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp) sym = xmalloc (sizeof (*sym)); sym->name = xstrdup (name); sym->addr = *addrp; - sym->next = symbol_cache; - symbol_cache = sym; + sym->next = proc->symbol_cache; + proc->symbol_cache = sym; return 1; } diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 81efecc6940..998fd0ce9a3 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -32,17 +32,17 @@ #include #endif -unsigned long cont_thread; -unsigned long general_thread; -unsigned long step_thread; +ptid_t cont_thread; +ptid_t general_thread; +ptid_t step_thread; int server_waiting; static int extended_protocol; -static int attached; static int response_needed; static int exit_requested; +int multi_process; int non_stop; static char **program_argv, **wrapper_argv; @@ -90,7 +90,7 @@ int disable_packet_qfThreadInfo; /* Last status reported to GDB. */ static struct target_waitstatus last_status; -static unsigned long last_ptid; +static ptid_t last_ptid; static char *own_buf; static unsigned char *mem_buf; @@ -104,7 +104,7 @@ struct vstop_notif struct vstop_notif *next; /* Thread or process that got the event. */ - unsigned long ptid; + ptid_t ptid; /* Event info. */ struct target_waitstatus status; @@ -116,7 +116,7 @@ static struct vstop_notif *notif_queue = NULL; /* Put a stop reply to the stop reply queue. */ static void -queue_stop_reply (unsigned long ptid, struct target_waitstatus *status) +queue_stop_reply (ptid_t ptid, struct target_waitstatus *status) { struct vstop_notif *new_notif; @@ -153,7 +153,7 @@ queue_stop_reply (unsigned long ptid, struct target_waitstatus *status) we aren't sending one yet. */ void -push_event (unsigned long ptid, struct target_waitstatus *status) +push_event (ptid_t ptid, struct target_waitstatus *status) { queue_stop_reply (ptid, status); @@ -170,19 +170,30 @@ push_event (unsigned long ptid, struct target_waitstatus *status) } } -/* Get rid of the currently pending stop replies. */ +/* Get rid of the currently pending stop replies for PID. If PID is + -1, then apply to all processes. */ static void -discard_queued_stop_replies (void) +discard_queued_stop_replies (int pid) { - struct vstop_notif *next; + struct vstop_notif *prev = NULL, *reply, *next; - while (notif_queue) + for (reply = notif_queue; reply; reply = next) { - next = notif_queue->next; - notif_queue = next; + next = reply->next; + + if (pid == -1 + || ptid_get_pid (reply->ptid) == pid) + { + if (reply == notif_queue) + notif_queue = next; + else + prev->next = reply->next; - free (next); + free (reply); + } + else + prev = reply; } } @@ -209,7 +220,6 @@ static int start_inferior (char **argv) { char **new_argv = argv; - attached = 0; if (wrapper_argv != NULL) { @@ -253,13 +263,13 @@ start_inferior (char **argv) if (wrapper_argv != NULL) { struct thread_resume resume_info; - unsigned long ptid; + ptid_t ptid; - resume_info.thread = -1; + resume_info.thread = pid_to_ptid (signal_pid); resume_info.kind = resume_continue; resume_info.sig = 0; - ptid = mywait (&last_status, 0, 0); + ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); if (last_status.kind != TARGET_WAITKIND_STOPPED) return signal_pid; @@ -268,7 +278,7 @@ start_inferior (char **argv) { (*the_target->resume) (&resume_info, 1); - mywait (&last_status, 0, 0); + mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); if (last_status.kind != TARGET_WAITKIND_STOPPED) return signal_pid; } @@ -279,7 +289,7 @@ start_inferior (char **argv) /* Wait till we are at 1st instruction in program, return new pid (assuming success). */ - last_ptid = mywait (&last_status, 0, 0); + last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); return signal_pid; } @@ -293,8 +303,6 @@ attach_inferior (int pid) if (myattach (pid) != 0) return -1; - attached = 1; - fprintf (stderr, "Attached; pid = %d\n", pid); fflush (stderr); @@ -305,7 +313,7 @@ attach_inferior (int pid) if (!non_stop) { - last_ptid = mywait (&last_status, 0, 0); + last_ptid = mywait (pid_to_ptid (pid), &last_status, 0, 0); /* GDB knows to ignore the first SIGSTOP after attaching to a running process using the "attach" command, but this is different; it's @@ -656,10 +664,11 @@ 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) { - unsigned long gdb_id; + ptid_t gdb_id; require_running (own_buf); - if (general_thread != 0 && general_thread != -1) + if (!ptid_equal (general_thread, null_ptid) + && !ptid_equal (general_thread, minus_one_ptid)) gdb_id = general_thread; else { @@ -667,7 +676,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); } - sprintf (own_buf, "QC%lx", gdb_id); + sprintf (own_buf, "QC"); + own_buf += 2; + own_buf = write_ptid (own_buf, gdb_id); return; } @@ -684,21 +695,28 @@ 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); thread_ptr = all_threads.head; - sprintf (own_buf, "m%x", - thread_to_gdb_id ((struct thread_info *)thread_ptr)); + + *own_buf++ = 'm'; + gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); + write_ptid (own_buf, gdb_id); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", own_buf) == 0) { + ptid_t gdb_id; + require_running (own_buf); if (thread_ptr != NULL) { - sprintf (own_buf, "m%x", - thread_to_gdb_id ((struct thread_info *)thread_ptr)); + *own_buf++ = 'm'; + gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); + write_ptid (own_buf, gdb_id); thread_ptr = thread_ptr->next; return; } @@ -1046,6 +1064,21 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) { + char *p = &own_buf[10]; + + /* Process each feature being provided by GDB. The first + feature will follow a ':', and latter features will follow + ';'. */ + if (*p == ':') + for (p = strtok (p + 1, ";"); + p != NULL; + p = strtok (NULL, ";")) + { + /* Record if GDB knows about multiprocess support. */ + if (strcmp (p, "multiprocess+") == 0) + multi_process = 1; + } + sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1); /* We do not have any hook to indicate whether the target backend @@ -1073,6 +1106,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (the_target->qxfer_osdata != NULL) strcat (own_buf, ";qXfer:osdata:read+"); + strcat (own_buf, ";multiprocess+"); + if (target_supports_non_stop ()) strcat (own_buf, ";QNonStop+"); @@ -1086,7 +1121,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) char *p = own_buf + 12; CORE_ADDR parts[2], address = 0; int i, err; - unsigned long ptid = 0; + ptid_t ptid = null_ptid; require_running (own_buf); @@ -1111,7 +1146,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) } if (i == 0) - ptid = strtoul (p, NULL, 16); + ptid = read_ptid (p, NULL); else decode_address (&parts[i - 1], p, len); p = p2; @@ -1121,7 +1156,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) err = 1; else { - struct thread_info *thread = gdb_id_to_thread (ptid); + struct thread_info *thread = find_thread_pid (ptid); if (thread == NULL) err = 2; @@ -1208,10 +1243,30 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } - if (strcmp (own_buf, "qAttached") == 0) + if (strcmp (own_buf, "qAttached") == 0 + || strncmp (own_buf, "qAttached:", sizeof ("qAttached:") - 1) == 0) { - require_running (own_buf); - strcpy (own_buf, attached ? "1" : "0"); + struct process_info *process; + + if (own_buf[sizeof ("qAttached") - 1]) + { + int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16); + process = (struct process_info *) + find_inferior_id (&all_processes, pid_to_ptid (pid)); + } + else + { + require_running (own_buf); + process = current_process (); + } + + if (process == NULL) + { + write_enn (own_buf); + return; + } + + strcpy (own_buf, process->attached ? "1" : "0"); return; } @@ -1227,7 +1282,7 @@ handle_v_cont (char *own_buf) char *p, *q; int n = 0, i = 0; struct thread_resume *resume_info; - struct thread_resume default_action = {0}; + struct thread_resume default_action = {{0}}; /* Count the number of semicolons in the packet. There should be one for every action. */ @@ -1277,7 +1332,7 @@ handle_v_cont (char *own_buf) if (p[0] == 0) { - resume_info[i].thread = -1; + resume_info[i].thread = minus_one_ptid; default_action = resume_info[i]; /* Note: we don't increment i here, we'll overwrite this entry @@ -1285,8 +1340,7 @@ handle_v_cont (char *own_buf) } else if (p[0] == ':') { - unsigned int gdb_id = strtoul (p + 1, &q, 16); - unsigned long thread_id; + ptid_t ptid = read_ptid (p + 1, &q); if (p == q) goto err; @@ -1294,11 +1348,7 @@ handle_v_cont (char *own_buf) if (p[0] != ';' && p[0] != 0) goto err; - thread_id = gdb_id_to_thread_id (gdb_id); - if (thread_id) - resume_info[i].thread = thread_id; - else - goto err; + resume_info[i].thread = ptid; i++; } @@ -1309,11 +1359,11 @@ handle_v_cont (char *own_buf) /* Still used in occasional places in the backend. */ if (n == 1 - && resume_info[0].thread != -1 + && !ptid_equal (resume_info[0].thread, minus_one_ptid) && resume_info[0].kind != resume_stop) cont_thread = resume_info[0].thread; else - cont_thread = -1; + cont_thread = minus_one_ptid; set_desired_inferior (0); if (!non_stop) @@ -1327,7 +1377,7 @@ handle_v_cont (char *own_buf) write_ok (own_buf); else { - last_ptid = mywait (&last_status, 0, 1); + last_ptid = mywait (minus_one_ptid, &last_status, 0, 1); prepare_resume_reply (own_buf, last_ptid, &last_status); disable_async_io (); } @@ -1462,6 +1512,30 @@ handle_v_run (char *own_buf) } } +/* Kill process. Return 1 if successful, 0 if failure. */ +int +handle_v_kill (char *own_buf) +{ + int pid; + char *p = &own_buf[6]; + + pid = strtol (p, NULL, 16); + if (pid != 0 && kill_inferior (pid) == 0) + { + last_status.kind = TARGET_WAITKIND_SIGNALLED; + last_status.value.sig = TARGET_SIGNAL_KILL; + last_ptid = pid_to_ptid (pid); + discard_queued_stop_replies (pid); + write_ok (own_buf); + return 1; + } + else + { + write_enn (own_buf); + return 0; + } +} + /* Handle a 'vStopped' packet. */ static void handle_v_stopped (char *own_buf) @@ -1473,7 +1547,8 @@ handle_v_stopped (char *own_buf) struct vstop_notif *head; if (remote_debug) - fprintf (stderr, "vStopped: acking %ld\n", notif_queue->ptid); + fprintf (stderr, "vStopped: acking %s\n", + target_pid_to_str (notif_queue->ptid)); head = notif_queue; notif_queue = notif_queue->next; @@ -1510,7 +1585,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) if (strncmp (own_buf, "vAttach;", 8) == 0) { - if (target_running ()) + if (!multi_process && target_running ()) { fprintf (stderr, "Already debugging a process\n"); write_enn (own_buf); @@ -1522,7 +1597,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) if (strncmp (own_buf, "vRun;", 5) == 0) { - if (target_running ()) + if (!multi_process && target_running ()) { fprintf (stderr, "Already debugging a process\n"); write_enn (own_buf); @@ -1532,6 +1607,18 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) return; } + if (strncmp (own_buf, "vKill;", 6) == 0) + { + if (!target_running ()) + { + fprintf (stderr, "No process to kill\n"); + write_enn (own_buf); + return; + } + handle_v_kill (own_buf); + return; + } + if (strncmp (own_buf, "vStopped", 8) == 0) { handle_v_stopped (own_buf); @@ -1556,7 +1643,8 @@ myresume (char *own_buf, int step, int sig) set_desired_inferior (0); - valid_cont_thread = (cont_thread != 0 && cont_thread != -1); + valid_cont_thread = (!ptid_equal (cont_thread, null_ptid) + && !ptid_equal (cont_thread, minus_one_ptid)); if (step || sig || valid_cont_thread) { @@ -1572,7 +1660,7 @@ myresume (char *own_buf, int step, int sig) if (!valid_cont_thread) { - resume_info[n].thread = -1; + resume_info[n].thread = minus_one_ptid; resume_info[n].kind = resume_continue; resume_info[n].sig = 0; n++; @@ -1587,7 +1675,7 @@ myresume (char *own_buf, int step, int sig) write_ok (own_buf); else { - last_ptid = mywait (&last_status, 0, 1); + last_ptid = mywait (minus_one_ptid, &last_status, 0, 1); prepare_resume_reply (own_buf, last_ptid, &last_status); disable_async_io (); } @@ -1596,16 +1684,24 @@ myresume (char *own_buf, int step, int sig) /* Callback for for_each_inferior. Make a new stop reply for each stopped thread. */ -static void -queue_stop_reply_callback (struct inferior_list_entry *entry) +static int +queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) { - struct target_waitstatus status; + int pid = * (int *) arg; - status.kind = TARGET_WAITKIND_STOPPED; - status.value.sig = TARGET_SIGNAL_TRAP; + if (pid == -1 + || ptid_get_pid (entry->id) == pid) + { + struct target_waitstatus status; + + status.kind = TARGET_WAITKIND_STOPPED; + status.value.sig = TARGET_SIGNAL_TRAP; - /* Pass the last stop reply back to GDB, but don't notify. */ - queue_stop_reply (entry->id, &status); + /* Pass the last stop reply back to GDB, but don't notify. */ + queue_stop_reply (entry->id, &status); + } + + return 0; } /* Status handler for the '?' packet. */ @@ -1623,8 +1719,9 @@ handle_status (char *own_buf) if (non_stop) { - discard_queued_stop_replies (); - for_each_inferior (&all_threads, queue_stop_reply_callback); + int pid = -1; + discard_queued_stop_replies (pid); + find_inferior (&all_threads, queue_stop_reply_callback, &pid); /* The first is sent immediatly. OK is sent if there is no stopped thread, which is the same handling of the vStopped @@ -1690,6 +1787,52 @@ gdbserver_show_disableable (FILE *stream) 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) +{ + struct process_info *process = (struct process_info *) entry; + int pid = ptid_get_pid (process->head.id); + + kill_inferior (pid); + discard_queued_stop_replies (pid); +} + +static void +detach_or_kill_inferior_callback (struct inferior_list_entry *entry) +{ + struct process_info *process = (struct process_info *) entry; + int pid = ptid_get_pid (process->head.id); + + if (process->attached) + detach_inferior (pid); + else + kill_inferior (pid); + + discard_queued_stop_replies (pid); +} + +static void +join_inferiors_callback (struct inferior_list_entry *entry) +{ + struct process_info *process = (struct process_info *) entry; + + /* If we are attached, then we can exit. Otherwise, we need to hang + around doing nothing, until the child is gone. */ + if (!process->attached) + join_inferior (ptid_get_pid (process->head.id)); +} + int main (int argc, char *argv[]) { @@ -1827,6 +1970,7 @@ main (int argc, char *argv[]) exit (1); } + initialize_inferiors (); initialize_async_io (); initialize_low (); @@ -1861,7 +2005,7 @@ main (int argc, char *argv[]) { last_status.kind = TARGET_WAITKIND_EXITED; last_status.value.integer = 0; - last_ptid = -1; + last_ptid = minus_one_ptid; } /* Don't report shared library events on the initial connection, @@ -1871,8 +2015,9 @@ main (int argc, char *argv[]) if (setjmp (toplevel)) { - fprintf (stderr, "Killing inferior\n"); - kill_inferior (); + fprintf (stderr, "Killing all inferiors\n"); + for_each_inferior (&all_processes, + kill_inferior_callback); exit (1); } @@ -1891,6 +2036,7 @@ main (int argc, char *argv[]) while (1) { noack_mode = 0; + multi_process = 0; non_stop = 0; remote_open (port); @@ -1916,10 +2062,8 @@ main (int argc, char *argv[]) if (exit_requested) { - if (attached) - detach_inferior (); - else - kill_inferior (); + for_each_inferior (&all_processes, + detach_or_kill_inferior_callback); exit (0); } else @@ -1941,6 +2085,7 @@ process_serial_event (void) int signal; unsigned int len; CORE_ADDR mem_addr; + int pid; unsigned char sig; int packet_len; int new_packet_len = -1; @@ -1976,12 +2121,22 @@ process_serial_event (void) break; case 'D': require_running (own_buf); - fprintf (stderr, "Detaching from inferior\n"); - if (detach_inferior () != 0) + + if (multi_process) + { + i++; /* skip ';' */ + pid = strtol (&own_buf[i], NULL, 16); + } + else + pid = + ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id); + + fprintf (stderr, "Detaching from process %d\n", pid); + if (detach_inferior (pid) != 0) write_enn (own_buf); else { - discard_queued_stop_replies (); + discard_queued_stop_replies (pid); write_ok (own_buf); if (extended_protocol) @@ -1989,7 +2144,7 @@ process_serial_event (void) /* Treat this like a normal program exit. */ last_status.kind = TARGET_WAITKIND_EXITED; last_status.value.integer = 0; - last_ptid = signal_pid; + last_ptid = pid_to_ptid (pid); current_inferior = NULL; } @@ -2001,9 +2156,8 @@ process_serial_event (void) /* If we are attached, then we can exit. Otherwise, we need to hang around doing nothing, until the child is gone. */ - if (!attached) - join_inferior (); - + for_each_inferior (&all_processes, + join_inferiors_callback); exit (0); } } @@ -2018,16 +2172,38 @@ process_serial_event (void) case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { - unsigned long gdb_id, thread_id; + ptid_t gdb_id, thread_id; + int pid; require_running (own_buf); - gdb_id = strtoul (&own_buf[2], NULL, 16); - if (gdb_id == 0 || gdb_id == -1) - thread_id = gdb_id; + + gdb_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)) + thread_id = null_ptid; + else if (pid != 0 + && ptid_equal (pid_to_ptid (pid), + gdb_id)) + { + struct thread_info *thread = + (struct thread_info *) find_inferior (&all_threads, + first_thread_of, + &pid); + if (!thread) + { + write_enn (own_buf); + break; + } + + thread_id = ((struct inferior_list_entry *)thread)->id; + } else { thread_id = gdb_id_to_thread_id (gdb_id); - if (thread_id == 0) + if (ptid_equal (thread_id, null_ptid)) { write_enn (own_buf); break; @@ -2036,7 +2212,7 @@ process_serial_event (void) if (own_buf[1] == 'g') { - if (thread_id == 0) + if (ptid_equal (thread_id, null_ptid)) { /* GDB is telling us to choose any thread. Check if the currently selected thread is still valid. If @@ -2194,13 +2370,12 @@ process_serial_event (void) case 'k': response_needed = 0; if (!target_running ()) - /* The packet we received doesn't make sense - but we - can't reply to it, either. */ + /* The packet we received doesn't make sense - but we can't + reply to it, either. */ return; - fprintf (stderr, "Killing inferior\n"); - kill_inferior (); - discard_queued_stop_replies (); + fprintf (stderr, "Killing all inferiors\n"); + for_each_inferior (&all_processes, kill_inferior_callback); /* When using the extended protocol, we wait with no program running. The traditional protocol will exit instead. */ @@ -2217,12 +2392,13 @@ process_serial_event (void) } case 'T': { - unsigned long gdb_id, thread_id; + ptid_t gdb_id, thread_id; require_running (own_buf); - gdb_id = strtoul (&own_buf[1], NULL, 16); + + gdb_id = read_ptid (&own_buf[1], NULL); thread_id = gdb_id_to_thread_id (gdb_id); - if (thread_id == 0) + if (ptid_equal (thread_id, null_ptid)) { write_enn (own_buf); break; @@ -2242,10 +2418,8 @@ process_serial_event (void) if (extended_protocol) { if (target_running ()) - { - kill_inferior (); - discard_queued_stop_replies (); - } + for_each_inferior (&all_processes, + kill_inferior_callback); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ @@ -2323,7 +2497,8 @@ handle_target_event (int err, gdb_client_data client_data) if (debug_threads) fprintf (stderr, "handling possible target event\n"); - last_ptid = mywait (&last_status, TARGET_WNOHANG, 1); + last_ptid = mywait (minus_one_ptid, &last_status, + TARGET_WNOHANG, 1); if (last_status.kind != TARGET_WAITKIND_IGNORE) { diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 12fef0feb3f..1af5313396a 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -85,6 +85,70 @@ typedef unsigned char gdb_byte; least the size of a (void *). */ typedef long long CORE_ADDR; +typedef unsigned long long ULONGEST; + +/* The ptid struct is a collection of the various "ids" necessary + for identifying the inferior. This consists of the process id + (pid), thread id (tid), and other fields necessary for uniquely + identifying the inferior process/thread being debugged. When + manipulating ptids, the constructors, accessors, and predicate + declared in server.h should be used. These are as follows: + + ptid_build - Make a new ptid from a pid, lwp, and tid. + pid_to_ptid - Make a new ptid from just a pid. + ptid_get_pid - Fetch the pid component of a ptid. + ptid_get_lwp - Fetch the lwp component of a ptid. + ptid_get_tid - Fetch the tid component of a ptid. + ptid_equal - Test to see if two ptids are equal. + + Please do NOT access the struct ptid members directly (except, of + course, in the implementation of the above ptid manipulation + functions). */ + +struct ptid + { + /* Process id */ + int pid; + + /* Lightweight process id */ + long lwp; + + /* Thread id */ + long tid; + }; + +typedef struct ptid ptid_t; + +/* The -1 ptid, often used to indicate either an error condition or a + "don't care" condition, i.e, "run all threads". */ +extern ptid_t minus_one_ptid; + +/* The null or zero ptid, often used to indicate no process. */ +extern ptid_t null_ptid; + +/* Attempt to find and return an existing ptid with the given PID, + LWP, and TID components. If none exists, create a new one and + return that. */ +ptid_t ptid_build (int pid, long lwp, long tid); + +/* Create a ptid from just a pid. */ +ptid_t pid_to_ptid (int pid); + +/* Fetch the pid (process id) component from a ptid. */ +int ptid_get_pid (ptid_t ptid); + +/* Fetch the lwp (lightweight process) component from a ptid. */ +long ptid_get_lwp (ptid_t ptid); + +/* Fetch the tid (thread id) component from a ptid. */ +long ptid_get_tid (ptid_t ptid); + +/* Compare two ptids to see if they are equal. */ +extern int ptid_equal (ptid_t p1, ptid_t p2); + +/* Return true if this ptid represents a process id. */ +extern int ptid_is_pid (ptid_t ptid); + /* Generic information for tracking a list of ``inferiors'' - threads, processes, etc. */ struct inferior_list @@ -94,7 +158,7 @@ struct inferior_list }; struct inferior_list_entry { - unsigned long id; + ptid_t id; struct inferior_list_entry *next; }; @@ -108,6 +172,36 @@ struct dll_info CORE_ADDR base_addr; }; +struct sym_cache; +struct breakpoint; +struct process_info_private; + +struct process_info +{ + struct inferior_list_entry head; + + int attached; + + /* The symbol cache. */ + struct sym_cache *symbol_cache; + + /* If this flag has been set, assume symbol cache misses are + failures. */ + int all_symbols_looked_up; + + /* The list of memory breakpoints. */ + struct breakpoint *breakpoints; + + /* Private target data. */ + struct process_info_private *private; +}; + +/* Return a pointer to the process that corresponds to the current + thread (current_inferior). It is an error to call this if there is + no current thread selected. */ + +struct process_info *current_process (void); + #include "regcache.h" #include "gdb/signals.h" #include "gdb_signals.h" @@ -120,22 +214,33 @@ void initialize_low (); /* From inferiors.c. */ +extern struct inferior_list all_processes; extern struct inferior_list all_threads; extern struct inferior_list all_dlls; extern int dlls_changed; +void initialize_inferiors (void); + void add_inferior_to_list (struct inferior_list *list, struct inferior_list_entry *new_inferior); void for_each_inferior (struct inferior_list *list, void (*action) (struct inferior_list_entry *)); + extern struct thread_info *current_inferior; void remove_inferior (struct inferior_list *list, struct inferior_list_entry *entry); void remove_thread (struct thread_info *thread); -void add_thread (unsigned long thread_id, void *target_data, unsigned int); -unsigned int thread_id_to_gdb_id (unsigned long); -unsigned int thread_to_gdb_id (struct thread_info *); -unsigned long gdb_id_to_thread_id (unsigned int); +void add_thread (ptid_t ptid, void *target_data); + +struct process_info *add_process (int pid, int attached); +void remove_process (struct process_info *process); +struct process_info *find_process_pid (int pid); + +struct thread_info *find_thread_pid (ptid_t ptid); + +ptid_t thread_id_to_gdb_id (ptid_t); +ptid_t thread_to_gdb_id (struct thread_info *); +ptid_t gdb_id_to_thread_id (ptid_t); struct thread_info *gdb_id_to_thread (unsigned int); void clear_inferiors (void); struct inferior_list_entry *find_inferior @@ -144,7 +249,7 @@ struct inferior_list_entry *find_inferior void *), void *arg); struct inferior_list_entry *find_inferior_id (struct inferior_list *list, - unsigned long id); + ptid_t id); void *inferior_target_data (struct thread_info *); void set_inferior_target_data (struct thread_info *, void *); void *inferior_regcache_data (struct thread_info *); @@ -157,9 +262,9 @@ void unloaded_dll (const char *name, CORE_ADDR base_addr); /* Public variables in server.c */ -extern unsigned long cont_thread; -extern unsigned long general_thread; -extern unsigned long step_thread; +extern ptid_t cont_thread; +extern ptid_t general_thread; +extern ptid_t step_thread; extern int server_waiting; extern int debug_threads; @@ -172,6 +277,7 @@ extern int disable_packet_Tthread; extern int disable_packet_qC; extern int disable_packet_qfThreadInfo; +extern int multi_process; extern int non_stop; /* Functions from event-loop.c. */ @@ -188,7 +294,7 @@ extern void start_event_loop (void); extern void handle_serial_event (int err, gdb_client_data client_data); extern void handle_target_event (int err, gdb_client_data client_data); -extern void push_event (unsigned long ptid, struct target_waitstatus *status); +extern void push_event (ptid_t ptid, struct target_waitstatus *status); /* Functions from hostio.c. */ extern int handle_vFile (char *, int, int *); @@ -203,6 +309,9 @@ extern int all_symbols_looked_up; extern int noack_mode; extern int transport_is_reliable; +ptid_t read_ptid (char *buf, char **obuf); +char *write_ptid (char *buf, ptid_t ptid); + int putpkt (char *buf); int putpkt_binary (char *buf, int len); int putpkt_notif (char *buf); @@ -219,7 +328,7 @@ void convert_ascii_to_int (char *from, unsigned char *to, int n); void convert_int_to_ascii (unsigned char *from, char *to, int n); void new_thread_notify (int id); void dead_thread_notify (int id); -void prepare_resume_reply (char *buf, unsigned long thread_id, +void prepare_resume_reply (char *buf, ptid_t ptid, struct target_waitstatus *status); const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start); @@ -244,6 +353,7 @@ int remote_escape_output (const gdb_byte *buffer, int len, gdb_byte *out_buf, int *out_len, int out_maxlen); +void clear_symbol_cache (struct sym_cache **symcache_p); int look_up_one_symbol (const char *name, CORE_ADDR *addrp); void monitor_output (const char *msg); diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index ba27beb5d48..eb984101a06 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -268,6 +268,7 @@ static int spu_create_inferior (char *program, char **allargs) { int pid; + ptid_t ptid; pid = fork (); if (pid < 0) @@ -289,7 +290,10 @@ spu_create_inferior (char *program, char **allargs) _exit (0177); } - add_thread (pid, NULL, pid); + add_process (pid, 0); + + ptid = ptid_build (pid, pid, 0); + add_thread (ptid, NULL); return pid; } @@ -297,6 +301,8 @@ spu_create_inferior (char *program, char **allargs) int spu_attach (unsigned long pid) { + ptid_t ptid; + if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0) { fprintf (stderr, "Cannot attach to process %ld: %s (%d)\n", pid, @@ -305,27 +311,32 @@ spu_attach (unsigned long pid) _exit (0177); } - add_thread (pid, NULL, pid); + add_process (pid, 1); + ptid = ptid_build (pid, pid, 0); + add_thread (ptid, NULL); return 0; } /* Kill the inferior process. */ -static void -spu_kill (void) +static int +spu_kill (int) { ptrace (PTRACE_KILL, current_tid, 0, 0); + remove_process (pid); + return 0; } /* Detach from inferior process. */ static int -spu_detach (void) +spu_detach (int pid) { ptrace (PTRACE_DETACH, current_tid, 0, 0); + remove_process (pid); return 0; } static void -spu_join (void) +spu_join (int pid) { int status, ret; @@ -338,9 +349,9 @@ spu_join (void) /* Return nonzero if the given thread is still alive. */ static int -spu_thread_alive (unsigned long tid) +spu_thread_alive (ptid_t ptid) { - return tid == current_tid; + return ptid_get_lwp (ptid) == current_tid; } /* Resume process. */ @@ -350,8 +361,8 @@ spu_resume (struct thread_resume *resume_info, size_t n) size_t i; for (i = 0; i < n; i++) - if (resume_info[i].thread == -1 - || resume_info[i].thread == current_tid) + if (ptid_equal (resume_info[i].thread, minus_one_ptid) + || ptid_get_lwp (resume_info[i].thread) == current_tid) break; if (i == n) @@ -371,8 +382,8 @@ spu_resume (struct thread_resume *resume_info, size_t n) } /* Wait for process, returns status. */ -static unsigned long -spu_wait (struct target_waitstatus *ourstatus, int options) +static ptid_t +spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) { int tid = current_tid; int w; @@ -415,7 +426,8 @@ spu_wait (struct target_waitstatus *ourstatus, int options) ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = WEXITSTATUS (w); clear_inferiors (); - return ret; + remove_process (ret); + return pid_to_ptid (ret); } else if (!WIFSTOPPED (w)) { @@ -423,7 +435,8 @@ spu_wait (struct target_waitstatus *ourstatus, int options) ourstatus->kind = TARGET_WAITKIND_SIGNALLED; ourstatus->value.sig = target_signal_from_host (WTERMSIG (w)); clear_inferiors (); - return ret; + remove_process (ret); + return pid_to_ptid (ret); } /* After attach, we may have received a SIGSTOP. Do not return this @@ -432,12 +445,12 @@ spu_wait (struct target_waitstatus *ourstatus, int options) { ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = TARGET_SIGNAL_0; - return ret; + return ptid_build (ret, ret, 0); } ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = target_signal_from_host (WSTOPSIG (w)); - return ret; + return ptid_build (ret, ret, 0); } /* Fetch inferior registers. */ diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c index b570b6c6886..bbfb5fd660e 100644 --- a/gdb/gdbserver/target.c +++ b/gdb/gdbserver/target.c @@ -29,10 +29,7 @@ set_desired_inferior (int use_general) struct thread_info *found; if (use_general == 1) - { - found = (struct thread_info *) find_inferior_id (&all_threads, - general_thread); - } + found = find_thread_pid (general_thread); else { found = NULL; @@ -40,14 +37,14 @@ set_desired_inferior (int use_general) /* If we are continuing any (all) thread(s), use step_thread to decide which thread to step and/or send the specified signal to. */ - if ((step_thread != 0 && step_thread != -1) - && (cont_thread == 0 || cont_thread == -1)) - found = (struct thread_info *) find_inferior_id (&all_threads, - step_thread); + if ((!ptid_equal (step_thread, null_ptid) + && !ptid_equal (step_thread, minus_one_ptid)) + && (ptid_equal (cont_thread, null_ptid) + || ptid_equal (cont_thread, minus_one_ptid))) + found = find_thread_pid (step_thread); if (found == NULL) - found = (struct thread_info *) find_inferior_id (&all_threads, - cont_thread); + found = find_thread_pid (cont_thread); } if (found == NULL) @@ -88,28 +85,24 @@ write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, return res; } -unsigned long -mywait (struct target_waitstatus *ourstatus, int options, +ptid_t +mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, int connected_wait) { - unsigned long ret; + ptid_t ret; if (connected_wait) server_waiting = 1; - ret = (*the_target->wait) (ourstatus, options); + ret = (*the_target->wait) (ptid, ourstatus, options); - if (ourstatus->kind == TARGET_WAITKIND_EXITED - || ourstatus->kind == TARGET_WAITKIND_SIGNALLED) - { - if (ourstatus->kind == TARGET_WAITKIND_EXITED) - fprintf (stderr, - "\nChild exited with status %d\n", ourstatus->value.sig); - if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) - fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", - target_signal_to_host (ourstatus->value.sig), - target_signal_to_name (ourstatus->value.sig)); - } + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + fprintf (stderr, + "\nChild exited with status %d\n", ourstatus->value.sig); + else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) + fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", + target_signal_to_host (ourstatus->value.sig), + target_signal_to_name (ourstatus->value.sig)); if (connected_wait) server_waiting = 0; @@ -137,3 +130,27 @@ set_target_ops (struct target_ops *target) the_target = (struct target_ops *) xmalloc (sizeof (*the_target)); memcpy (the_target, target, sizeof (*the_target)); } + +/* Convert pid to printable format. */ + +const char * +target_pid_to_str (ptid_t ptid) +{ + static char buf[80]; + + if (ptid_equal (ptid, minus_one_ptid)) + snprintf (buf, sizeof (buf), ""); + else if (ptid_equal (ptid, null_ptid)) + snprintf (buf, sizeof (buf), ""); + else if (ptid_get_tid (ptid) != 0) + snprintf (buf, sizeof (buf), "Thread %d.0x%lx", + ptid_get_pid (ptid), ptid_get_tid (ptid)); + else if (ptid_get_lwp (ptid) != 0) + snprintf (buf, sizeof (buf), "LWP %d.%ld", + ptid_get_pid (ptid), ptid_get_lwp (ptid)); + else + snprintf (buf, sizeof (buf), "Process %d", + ptid_get_pid (ptid)); + + return buf; +} diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index b7156fdd34d..7ff38493ea3 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -43,7 +43,7 @@ enum resume_kind struct thread_resume { - unsigned long thread; + ptid_t thread; /* How to "resume". */ enum resume_kind kind; @@ -96,7 +96,7 @@ struct target_waitstatus { int integer; enum target_signal sig; - unsigned long related_pid; + ptid_t related_pid; char *execd_pathname; } value; @@ -129,31 +129,38 @@ struct target_ops int (*attach) (unsigned long pid); - /* Kill all inferiors. */ + /* Kill inferior PID. Return -1 on failure, and 0 on success. */ - void (*kill) (void); + int (*kill) (int pid); - /* Detach from all inferiors. - Return -1 on failure, and 0 on success. */ + /* Detach from inferior PID. Return -1 on failure, and 0 on + success. */ - int (*detach) (void); + int (*detach) (int pid); - /* Wait for inferiors to end. */ - - void (*join) (void); + /* Wait for inferior PID to exit. */ + void (*join) (int pid); /* Return 1 iff the thread with process ID PID is alive. */ - int (*thread_alive) (unsigned long pid); + int (*thread_alive) (ptid_t pid); /* Resume the inferior process. */ void (*resume) (struct thread_resume *resume_info, size_t n); /* Wait for the inferior process or thread to change state. Store - status through argument pointer STATUS. */ + status through argument pointer STATUS. + + PTID = -1 to wait for any pid to do something, PTID(pid,0,0) to + wait for any thread of process pid to do something. Return ptid + of child, or -1 in case of error; store status through argument + pointer STATUS. OPTIONS is a bit set of options defined as + TARGET_W* above. If options contains TARGET_WNOHANG and there's + no child stop to report, return is + null_ptid/TARGET_WAITKIND_IGNORE. */ - unsigned long (*wait) (struct target_waitstatus *status, int options); + ptid_t (*wait) (ptid_t ptid, struct target_waitstatus *status, int options); /* Fetch registers from the inferior process. @@ -280,11 +287,11 @@ void set_target_ops (struct target_ops *); #define myattach(pid) \ (*the_target->attach) (pid) -#define kill_inferior() \ - (*the_target->kill) () +#define kill_inferior(pid) \ + (*the_target->kill) (pid) -#define detach_inferior() \ - (*the_target->detach) () +#define detach_inferior(pid) \ + (*the_target->detach) (pid) #define mythread_alive(pid) \ (*the_target->thread_alive) (pid) @@ -295,8 +302,8 @@ void set_target_ops (struct target_ops *); #define store_inferior_registers(regno) \ (*the_target->store_registers) (regno) -#define join_inferior() \ - (*the_target->join) () +#define join_inferior(pid) \ + (*the_target->join) (pid) #define target_supports_non_stop() \ (the_target->supports_non_stop ? (*the_target->supports_non_stop ) () : 0) @@ -308,8 +315,8 @@ void set_target_ops (struct target_ops *); int start_non_stop (int nonstop); -unsigned long mywait (struct target_waitstatus *ourstatus, int options, - int connected_wait); +ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, + int connected_wait); int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); @@ -318,4 +325,6 @@ int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, void set_desired_inferior (int id); +const char *target_pid_to_str (ptid_t); + #endif /* TARGET_H */ diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index adafb2cb5dd..936bb0f942b 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -35,14 +35,7 @@ static int thread_db_use_events; #include -/* Structure that identifies the child process for the - interface. */ -static struct ps_prochandle proc_handle; - -/* Connection to the libthread_db library. */ -static td_thragent_t *thread_agent; - -static int find_one_thread (int); +static int find_one_thread (ptid_t); static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); static const char * @@ -137,6 +130,7 @@ thread_db_create_event (CORE_ADDR where) td_event_msg_t msg; td_err_e err; struct lwp_info *lwp; + struct process_info_private *proc = current_process()->private; if (debug_threads) fprintf (stderr, "Thread creation event.\n"); @@ -145,7 +139,7 @@ thread_db_create_event (CORE_ADDR where) In the LinuxThreads implementation, this is safe, because all events come from the manager thread (except for its own creation, of course). */ - err = td_ta_event_getmsg (thread_agent, &msg); + err = td_ta_event_getmsg (proc->thread_agent, &msg); if (err != TD_OK) fprintf (stderr, "thread getmsg err: %s\n", thread_db_err_str (err)); @@ -155,7 +149,7 @@ thread_db_create_event (CORE_ADDR where) created threads. */ lwp = get_thread_lwp (current_inferior); if (lwp->thread_known == 0) - find_one_thread (lwpid_of (lwp)); + find_one_thread (lwp->head.id); /* msg.event == TD_EVENT_CREATE */ @@ -181,6 +175,7 @@ thread_db_enable_reporting () td_thr_events_t events; td_notify_t notify; td_err_e err; + struct process_info_private *proc = current_process()->private; /* Set the process wide mask saying which events we're interested in. */ td_event_emptyset (&events); @@ -192,7 +187,7 @@ thread_db_enable_reporting () td_event_addset (&events, TD_DEATH); #endif - err = td_ta_set_event (thread_agent, &events); + err = td_ta_set_event (proc->thread_agent, &events); if (err != TD_OK) { warning ("Unable to set global thread event mask: %s", @@ -201,7 +196,7 @@ thread_db_enable_reporting () } /* Get address for thread creation breakpoint. */ - err = td_ta_event_addr (thread_agent, TD_CREATE, ¬ify); + err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify); if (err != TD_OK) { warning ("Unable to get location for thread creation breakpoint: %s", @@ -216,7 +211,7 @@ thread_db_enable_reporting () with actual thread deaths (via wait). */ /* Get address for thread death breakpoint. */ - err = td_ta_event_addr (thread_agent, TD_DEATH, ¬ify); + err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify); if (err != TD_OK) { warning ("Unable to get location for thread death breakpoint: %s", @@ -231,21 +226,23 @@ thread_db_enable_reporting () } static int -find_one_thread (int lwpid) +find_one_thread (ptid_t ptid) { td_thrhandle_t th; td_thrinfo_t ti; td_err_e err; struct thread_info *inferior; struct lwp_info *lwp; + struct process_info_private *proc = current_process()->private; + int lwpid = ptid_get_lwp (ptid); - inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid); + inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid); lwp = get_thread_lwp (inferior); if (lwp->thread_known) return 1; /* Get information about this thread. */ - err = td_ta_map_lwp2thr (thread_agent, lwpid_of (lwp), &th); + err = td_ta_map_lwp2thr (proc->thread_agent, lwpid, &th); if (err != TD_OK) error ("Cannot get thread handle for LWP %d: %s", lwpid, thread_db_err_str (err)); @@ -259,10 +256,10 @@ find_one_thread (int lwpid) fprintf (stderr, "Found thread %ld (LWP %d)\n", ti.ti_tid, ti.ti_lid); - if (lwpid_of (lwp) != ti.ti_lid) + if (lwpid != ti.ti_lid) { warning ("PID mismatch! Expected %ld, got %ld", - (long) lwpid_of (lwp), (long) ti.ti_lid); + (long) lwpid, (long) ti.ti_lid); return 0; } @@ -289,29 +286,24 @@ static void maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) { td_err_e err; - struct thread_info *inferior; struct lwp_info *lwp; - inferior = (struct thread_info *) find_inferior_id (&all_threads, - ti_p->ti_lid); - if (inferior != NULL) + lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid)); + if (lwp != NULL) return; if (debug_threads) fprintf (stderr, "Attaching to thread %ld (LWP %d)\n", ti_p->ti_tid, ti_p->ti_lid); linux_attach_lwp (ti_p->ti_lid); - inferior = (struct thread_info *) find_inferior_id (&all_threads, - ti_p->ti_lid); - if (inferior == NULL) + lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid)); + if (lwp == NULL) { warning ("Could not attach to thread %ld (LWP %d)\n", ti_p->ti_tid, ti_p->ti_lid); return; } - lwp = inferior_target_data (inferior); - lwp->thread_known = 1; lwp->th = *th_p; @@ -347,15 +339,18 @@ static void thread_db_find_new_threads (void) { td_err_e err; + ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id; + struct process_info_private *proc = current_process()->private; /* This function is only called when we first initialize thread_db. First locate the initial thread. If it is not ready for debugging yet, then stop. */ - if (find_one_thread (all_threads.head->id) == 0) + if (find_one_thread (ptid) == 0) return; /* Iterate over all user-space threads to discover new threads. */ - err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL, + err = td_ta_thr_iter (proc->thread_agent, + find_new_threads_callback, NULL, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); if (err != TD_OK) @@ -385,18 +380,22 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, psaddr_t addr; td_err_e err; struct lwp_info *lwp; + struct thread_info *saved_inferior; lwp = get_thread_lwp (thread); if (!lwp->thread_known) - find_one_thread (lwpid_of (lwp)); + find_one_thread (lwp->head.id); if (!lwp->thread_known) return TD_NOTHR; + saved_inferior = current_inferior; + current_inferior = thread; /* Note the cast through uintptr_t: this interface only works if a target address fits in a psaddr_t, which is a host pointer. So a 32-bit debugger can not access 64-bit TLS through this. */ err = td_thr_tls_get_addr (&lwp->th, (psaddr_t) (uintptr_t) load_module, offset, &addr); + current_inferior = saved_inferior; if (err == TD_OK) { *address = (CORE_ADDR) (uintptr_t) addr; @@ -413,6 +412,8 @@ int thread_db_init (int use_events) { int err; + struct process_info *proc = current_process (); + struct process_info_private *priv = proc->private; /* FIXME drow/2004-10-16: This is the "overall process ID", which GNU/Linux calls tgid, "thread group ID". When we support @@ -424,14 +425,10 @@ thread_db_init (int use_events) This isn't the only place in gdbserver that assumes that the first process in the list is the thread group leader. */ - proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id; - - /* Allow new symbol lookups. */ - all_symbols_looked_up = 0; thread_db_use_events = use_events; - err = td_ta_new (&proc_handle, &thread_agent); + err = td_ta_new (&priv->proc_handle, &priv->thread_agent); switch (err) { case TD_NOLIBTHREAD: @@ -445,7 +442,7 @@ thread_db_init (int use_events) return 0; thread_db_find_new_threads (); thread_db_look_up_symbols (); - all_symbols_looked_up = 1; + proc->all_symbols_looked_up = 1; return 1; default: diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 1d7c2034683..f3943abfd90 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -94,11 +94,17 @@ static void win32_resume (struct thread_resume *resume_info, size_t n); /* Get the thread ID from the current selected inferior (the current thread). */ -static DWORD -current_inferior_tid (void) +static ptid_t +current_inferior_ptid (void) { - win32_thread_info *th = inferior_target_data (current_inferior); - return th->tid; + return ((struct inferior_list_entry*) current_inferior)->id; +} + +/* The current debug event from WaitForDebugEvent. */ +static ptid_t +debug_event_ptid (DEBUG_EVENT *event) +{ + return ptid_build (event->dwProcessId, event->dwThreadId, 0); } /* Get the thread context of the thread associated with TH. */ @@ -137,12 +143,12 @@ win32_set_thread_context (win32_thread_info *th) /* Find a thread record given a thread id. If GET_CONTEXT is set then also retrieve the context for this thread. */ static win32_thread_info * -thread_rec (DWORD id, int get_context) +thread_rec (ptid_t ptid, int get_context) { struct thread_info *thread; win32_thread_info *th; - thread = (struct thread_info *) find_inferior_id (&all_threads, id); + thread = (struct thread_info *) find_inferior_id (&all_threads, ptid); if (thread == NULL) return NULL; @@ -169,20 +175,21 @@ thread_rec (DWORD id, int get_context) /* Add a thread to the thread list. */ static win32_thread_info * -child_add_thread (DWORD tid, HANDLE h) +child_add_thread (DWORD pid, DWORD tid, HANDLE h) { win32_thread_info *th; + ptid_t ptid = ptid_build (pid, tid, 0); - if ((th = thread_rec (tid, FALSE))) + if ((th = thread_rec (ptid, FALSE))) return th; th = xcalloc (1, sizeof (*th)); th->tid = tid; th->h = h; - add_thread (tid, th, (unsigned int) tid); + add_thread (ptid, th); set_inferior_regcache_data ((struct thread_info *) - find_inferior_id (&all_threads, tid), + find_inferior_id (&all_threads, ptid), new_register_cache ()); if (the_low_target.thread_added != NULL) @@ -204,15 +211,17 @@ delete_thread_info (struct inferior_list_entry *thread) /* Delete a thread from the list of threads. */ static void -child_delete_thread (DWORD id) +child_delete_thread (DWORD pid, DWORD tid) { struct inferior_list_entry *thread; + ptid_t ptid; /* If the last thread is exiting, just return. */ if (all_threads.head == all_threads.tail) return; - thread = find_inferior_id (&all_threads, id); + ptid = ptid_build (pid, tid, 0); + thread = find_inferior_id (&all_threads, ptid); if (thread == NULL) return; @@ -250,7 +259,7 @@ child_init_thread_list (void) } static void -do_initial_child_stuff (HANDLE proch, DWORD pid) +do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) { last_sig = TARGET_SIGNAL_0; @@ -263,6 +272,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid) memset (¤t_event, 0, sizeof (current_event)); + add_process (pid, attached); child_init_thread_list (); if (the_low_target.initial_stuff != NULL) @@ -320,7 +330,7 @@ static void child_fetch_inferior_registers (int r) { int regno; - win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE); + win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE); if (r == -1 || r == 0 || r > NUM_REGS) child_fetch_inferior_registers (NUM_REGS); else @@ -334,7 +344,7 @@ static void child_store_inferior_registers (int r) { int regno; - win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE); + win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE); if (r == -1 || r == 0 || r > NUM_REGS) child_store_inferior_registers (NUM_REGS); else @@ -540,7 +550,7 @@ win32_create_inferior (char *program, char **program_args) CloseHandle (pi.hThread); #endif - do_initial_child_stuff (pi.hProcess, pi.dwProcessId); + do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0); return current_process_id; } @@ -571,7 +581,7 @@ win32_attach (unsigned long pid) /* win32_wait needs to know we're attaching. */ attaching = 1; - do_initial_child_stuff (h, pid); + do_initial_child_stuff (h, pid, 1); return 0; } @@ -639,11 +649,13 @@ win32_clear_inferiors (void) } /* Kill all inferiors. */ -static void -win32_kill (void) +static int +win32_kill (int pid) { + struct process_info *process; + if (current_process_handle == NULL) - return; + return -1; TerminateProcess (current_process_handle, 0); for (;;) @@ -662,12 +674,17 @@ win32_kill (void) } win32_clear_inferiors (); + + process = find_process_pid (pid); + remove_process (process); + return 0; } -/* Detach from all inferiors. */ +/* Detach from inferior PID. */ static int -win32_detach (void) +win32_detach (int pid) { + struct process_info *process; winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL; winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; #ifdef _WIN32_WCE @@ -684,7 +701,7 @@ win32_detach (void) { struct thread_resume resume; - resume.thread = -1; + resume.thread = minus_one_ptid; resume.kind = resume_continue; resume.sig = 0; win32_resume (&resume, 1); @@ -694,6 +711,8 @@ win32_detach (void) return -1; DebugSetProcessKillOnExit (FALSE); + process = find_process_pid (pid); + remove_process (process); win32_clear_inferiors (); return 0; @@ -701,11 +720,9 @@ win32_detach (void) /* Wait for inferiors to end. */ static void -win32_join (void) +win32_join (int pid) { - extern unsigned long signal_pid; - - HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid); + HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); if (h != NULL) { WaitForSingleObject (h, INFINITE); @@ -715,13 +732,13 @@ win32_join (void) /* Return 1 iff the thread with thread ID TID is alive. */ static int -win32_thread_alive (unsigned long tid) +win32_thread_alive (ptid_t ptid) { int res; /* Our thread list is reliable; don't bother to poll target threads. */ - if (find_inferior_id (&all_threads, tid) != NULL) + if (find_inferior_id (&all_threads, ptid) != NULL) res = 1; else res = 0; @@ -738,11 +755,12 @@ win32_resume (struct thread_resume *resume_info, size_t n) int step; win32_thread_info *th; DWORD continue_status = DBG_CONTINUE; + ptid_t ptid; /* This handles the very limited set of resume packets that GDB can currently produce. */ - if (n == 1 && resume_info[0].thread == -1) + if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid)) tid = -1; else if (n > 1) tid = -1; @@ -751,7 +769,7 @@ win32_resume (struct thread_resume *resume_info, size_t n) the Windows resume code do the right thing for thread switching. */ tid = current_event.dwThreadId; - if (resume_info[0].thread != -1) + if (!ptid_equal (resume_info[0].thread, minus_one_ptid)) { sig = resume_info[0].sig; step = resume_info[0].kind == resume_step; @@ -777,7 +795,8 @@ win32_resume (struct thread_resume *resume_info, size_t n) last_sig = TARGET_SIGNAL_0; /* Get context for the currently selected thread. */ - th = thread_rec (current_event.dwThreadId, FALSE); + ptid = debug_event_ptid (¤t_event); + th = thread_rec (ptid, FALSE); if (th) { if (th->context.ContextFlags) @@ -1295,6 +1314,8 @@ auto_delete_breakpoint (CORE_ADDR stop_pc) static int get_child_debug_event (struct target_waitstatus *ourstatus) { + ptid_t ptid; + last_sig = TARGET_SIGNAL_0; ourstatus->kind = TARGET_WAITKIND_SPURIOUS; @@ -1349,9 +1370,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus) gotevent: + ptid = debug_event_ptid (¤t_event); current_inferior = - (struct thread_info *) find_inferior_id (&all_threads, - current_event.dwThreadId); + (struct thread_info *) find_inferior_id (&all_threads, ptid); switch (current_event.dwDebugEventCode) { @@ -1362,8 +1383,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus) (unsigned) current_event.dwThreadId)); /* Record the existence of this thread. */ - child_add_thread (current_event.dwThreadId, - current_event.u.CreateThread.hThread); + child_add_thread (current_event.dwProcessId, + current_event.dwThreadId, + current_event.u.CreateThread.hThread); break; case EXIT_THREAD_DEBUG_EVENT: @@ -1371,7 +1393,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus) "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); - child_delete_thread (current_event.dwThreadId); + child_delete_thread (current_event.dwProcessId, + current_event.dwThreadId); break; case CREATE_PROCESS_DEBUG_EVENT: @@ -1388,10 +1411,11 @@ get_child_debug_event (struct target_waitstatus *ourstatus) ourstatus->value.execd_pathname = "Main executable"; /* Add the main thread. */ - child_add_thread (main_thread_id, + child_add_thread (current_event.dwProcessId, + main_thread_id, current_event.u.CreateProcessInfo.hThread); - ourstatus->value.related_pid = current_event.dwThreadId; + ourstatus->value.related_pid = debug_event_ptid (¤t_event); #ifdef _WIN32_WCE if (!attaching) { @@ -1467,17 +1491,18 @@ get_child_debug_event (struct target_waitstatus *ourstatus) } current_inferior = - (struct thread_info *) find_inferior_id (&all_threads, - current_event.dwThreadId); + (struct thread_info *) find_inferior_id (&all_threads, ptid); return 1; } /* Wait for the inferior process to change state. STATUS will be filled in with a response code to send to GDB. Returns the signal which caused the process to stop. */ -static unsigned long -win32_wait (struct target_waitstatus *ourstatus, int options) +static ptid_t +win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) { + struct process_info *process; + while (1) { if (!get_child_debug_event (ourstatus)) @@ -1489,8 +1514,10 @@ win32_wait (struct target_waitstatus *ourstatus, int options) OUTMSG2 (("Child exited with retcode = %x\n", ourstatus->value.integer)); + process = find_process_pid (current_process_id); + remove_process (process); win32_clear_inferiors (); - return current_event.dwProcessId; + return pid_to_ptid (current_event.dwProcessId); case TARGET_WAITKIND_STOPPED: case TARGET_WAITKIND_LOADED: OUTMSG2 (("Child Stopped with signal = %d \n", @@ -1512,7 +1539,7 @@ win32_wait (struct target_waitstatus *ourstatus, int options) if (ourstatus->kind == TARGET_WAITKIND_LOADED) ourstatus->kind = TARGET_WAITKIND_STOPPED; - return current_event.dwThreadId; + return debug_event_ptid (¤t_event); default: OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind)); /* fall-through */ -- 2.30.2