aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2009-06-19 14:30:30 +0000
committerTristan Gingold <gingold@adacore.com>2009-06-19 14:30:30 +0000
commitbb00b29d7802d6b28c24bd269bb170ac66aa932a (patch)
tree9cdf1ab73fe805fe46708f9d1d6fbff778fc701d /gdb
parentcf8fd78b3890f7c0a8050f7dc6cefaa8918374f9 (diff)
downloadgdb-bb00b29d7802d6b28c24bd269bb170ac66aa932a.zip
gdb-bb00b29d7802d6b28c24bd269bb170ac66aa932a.tar.gz
gdb-bb00b29d7802d6b28c24bd269bb170ac66aa932a.tar.bz2
2009-06-19 Tristan Gingold <gingold@adacore.com>
* machoread.c (macho_symtab_read): Adjust for bfd changes. * darwin-nat.h (struct darwin_exception_msg): New type to describe a mach exception. (struct private_thread_info): New type to describe the state of the thread. (DEF_VEC_I thread_t): Removed, replaced by ... (DEF_VEC_O darwin_thread_t): ... this new type. (struct darwin_inferior): Renamed to ... (struct private_inferior): ... this type. Fields added. (darwin_not_port): Moved into the private inferior structure. * darwin-nat.c: Add includes, improve comments. Rewrite to handle multiple threads and processes. (darwin_resume_to): New function and protype. (darwin_resume, darwin_wait_to, darwin_wait): Ditto. (darwin_kill_inferior): Add ops argument. (darwin_pid_to_str): New function. (darwin_thread_alive): Ditto. (darwin_inf, darwin_not_port): Removed. (darwin_inf_fake_stop): New variable. (msgin, msgout, msg_state, exc_msg): Removed. (mach_check_error): Use warning instead of error. (darwin_ptrace): Adjust debug level. (cmp_thread_t): Fix names (typo). (darwin_check_new_threads): Argument is now an inferior, adjust for new structures, add no change check, ignore dead ports, handle first thread case. (find_inferior_task_it): New function. (find_inferior_notify_it): Ditto. (darwin_find_inferior_by_task): Ditto. (darwin_find_inferior_by_notify): Ditto. (darwin_find_thread): Ditto. (darwin_suspend_inferior): Ditto. (darwin_resume_inferior): Ditto. (catch_exception_raise_state): Removed. (catch_exception_raise_state_identity): Removed. (darwin_suspend_inferior_it): New function. (darwin_resume_inferior_it): Ditto. (darwin_dump_message): New function, extracted from darwin_wait. (darwin_decode_exception_message): New function. (darwin_encode_reply): New function. (catch_exception_raise): Removed. (darwin_send_reply): New function, extracted from darwin_resume. (darwin_resume_thread): New function, extracted from darwin_resume. (struct resume_inferior_threads_param): New type. (darwin_resume_inferior_threads_it): New function. (darwin_resume_inferior_threads): New function. (darwin_suspend_inferior_threads): New function. (darwin_resume): Mostly rewritten to handle multiple threads and some corner cases. (darwin_decode_message): New function extracted from darwin_wait. (cancel_breakpoint): New function. (darwin_wait): Mostly rewritten. Handle multiple threads. (darwin_mourn_inferior): Adjust for per process structures. (darwin_reply_to_all_pending_messages): New function. (darwin_stop_inferior): Adjust for per inferior structures. (darwin_attach_pid): Ditto. (darwin_init_thread_list): Ditto. (darwin_attach): Ditto. (darwin_detach): Ditto. (darwin_files_info): Now empty. (darwin_pid_to_str): Adjust returns string to match one expected by the testsuite. (darwin_read_write_inferior): Rename err variable to match other uses. Adjust debug message. Handle submaps. (darwin_xfer_memory): Adjust for per inferior structures. (set_enable_mach_exceptions): Ditto. (darwin_pid_to_exec_file): New function. (darwin_get_ada_task_ptid): Ditto. (darwin_supports_multi_process): Ditto. (_initialize_darwin_inferior): Remove useless assertion, adjust for per inferior structures. Add new target operations.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog74
-rw-r--r--gdb/darwin-nat-info.c152
-rw-r--r--gdb/darwin-nat.c1613
-rw-r--r--gdb/darwin-nat.h79
-rw-r--r--gdb/machoread.c8
5 files changed, 1379 insertions, 547 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3c4748c..2dd7915 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,77 @@
+2009-06-19 Tristan Gingold <gingold@adacore.com>
+
+ * machoread.c (macho_symtab_read): Adjust for bfd changes.
+ * darwin-nat.h (struct darwin_exception_msg): New type to describe
+ a mach exception.
+ (struct private_thread_info): New type to describe the state of the
+ thread.
+ (DEF_VEC_I thread_t): Removed, replaced by ...
+ (DEF_VEC_O darwin_thread_t): ... this new type.
+ (struct darwin_inferior): Renamed to ...
+ (struct private_inferior): ... this type. Fields added.
+ (darwin_not_port): Moved into the private inferior structure.
+ * darwin-nat.c: Add includes, improve comments.
+ Rewrite to handle multiple threads and processes.
+ (darwin_resume_to): New function and protype.
+ (darwin_resume, darwin_wait_to, darwin_wait): Ditto.
+ (darwin_kill_inferior): Add ops argument.
+ (darwin_pid_to_str): New function.
+ (darwin_thread_alive): Ditto.
+ (darwin_inf, darwin_not_port): Removed.
+ (darwin_inf_fake_stop): New variable.
+ (msgin, msgout, msg_state, exc_msg): Removed.
+ (mach_check_error): Use warning instead of error.
+ (darwin_ptrace): Adjust debug level.
+ (cmp_thread_t): Fix names (typo).
+ (darwin_check_new_threads): Argument is now an inferior,
+ adjust for new structures, add no change check, ignore dead ports,
+ handle first thread case.
+ (find_inferior_task_it): New function.
+ (find_inferior_notify_it): Ditto.
+ (darwin_find_inferior_by_task): Ditto.
+ (darwin_find_inferior_by_notify): Ditto.
+ (darwin_find_thread): Ditto.
+ (darwin_suspend_inferior): Ditto.
+ (darwin_resume_inferior): Ditto.
+ (catch_exception_raise_state): Removed.
+ (catch_exception_raise_state_identity): Removed.
+ (darwin_suspend_inferior_it): New function.
+ (darwin_resume_inferior_it): Ditto.
+ (darwin_dump_message): New function, extracted from darwin_wait.
+ (darwin_decode_exception_message): New function.
+ (darwin_encode_reply): New function.
+ (catch_exception_raise): Removed.
+ (darwin_send_reply): New function, extracted from darwin_resume.
+ (darwin_resume_thread): New function, extracted from darwin_resume.
+ (struct resume_inferior_threads_param): New type.
+ (darwin_resume_inferior_threads_it): New function.
+ (darwin_resume_inferior_threads): New function.
+ (darwin_suspend_inferior_threads): New function.
+ (darwin_resume): Mostly rewritten to handle multiple threads and
+ some corner cases.
+ (darwin_decode_message): New function extracted from darwin_wait.
+ (cancel_breakpoint): New function.
+ (darwin_wait): Mostly rewritten. Handle multiple threads.
+ (darwin_mourn_inferior): Adjust for per process structures.
+ (darwin_reply_to_all_pending_messages): New function.
+ (darwin_stop_inferior): Adjust for per inferior structures.
+ (darwin_attach_pid): Ditto.
+ (darwin_init_thread_list): Ditto.
+ (darwin_attach): Ditto.
+ (darwin_detach): Ditto.
+ (darwin_files_info): Now empty.
+ (darwin_pid_to_str): Adjust returns string to match one expected by
+ the testsuite.
+ (darwin_read_write_inferior): Rename err variable to match other uses.
+ Adjust debug message. Handle submaps.
+ (darwin_xfer_memory): Adjust for per inferior structures.
+ (set_enable_mach_exceptions): Ditto.
+ (darwin_pid_to_exec_file): New function.
+ (darwin_get_ada_task_ptid): Ditto.
+ (darwin_supports_multi_process): Ditto.
+ (_initialize_darwin_inferior): Remove useless assertion, adjust for
+ per inferior structures. Add new target operations.
+
2009-06-18 Hui Zhu <teawater@gmail.com>
Michael Snyder <msnyder@vmware.com>
diff --git a/gdb/darwin-nat-info.c b/gdb/darwin-nat-info.c
index c48d2fe..3b14006 100644
--- a/gdb/darwin-nat-info.c
+++ b/gdb/darwin-nat-info.c
@@ -1,5 +1,5 @@
/* Darwin support for GDB, the GNU debugger.
- Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2008, 2009
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2008
Free Software Foundation, Inc.
Contributed by Apple Computer, Inc.
@@ -8,7 +8,7 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
+ the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -17,7 +17,9 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
/* The name of the ppc_thread_state structure, and the names of its
members, have been changed for Unix conformance reasons. The easiest
@@ -118,9 +120,9 @@ get_task_from_args (char *args)
if (args == NULL || *args == 0)
{
- if (darwin_inf->task == TASK_NULL)
+ if (ptid_equal (inferior_ptid, null_ptid))
printf_unfiltered (_("No inferior running\n"));
- return darwin_inf->task;
+ return current_inferior ()->private->task;
}
if (strcmp (args, "gdb") == 0)
return mach_task_self ();
@@ -252,25 +254,44 @@ info_mach_ports_command (char *args, int from_tty)
printf_unfiltered (_(" gdb-task"));
else if (port == darwin_host_self)
printf_unfiltered (_(" host-self"));
- else if (port == darwin_not_port)
- printf_unfiltered (_(" gdb-notifier"));
else if (port == darwin_ex_port)
printf_unfiltered (_(" gdb-exception"));
else if (port == darwin_port_set)
printf_unfiltered (_(" gdb-port_set"));
- else if (darwin_inf && port == darwin_inf->task)
- printf_unfiltered (_(" inferior-task"));
- else if (darwin_inf && darwin_inf->threads)
+ else if (!ptid_equal (inferior_ptid, null_ptid))
{
- int k;
- thread_t t;
- for (k = 0; VEC_iterate(thread_t, darwin_inf->threads, k, t); k++)
- if (port == t)
- {
- printf_unfiltered (_(" inferior-thread for 0x%x"),
- darwin_inf->task);
- break;
- }
+ struct inferior *inf = current_inferior ();
+
+ if (port == inf->private->task)
+ printf_unfiltered (_(" inferior-task"));
+ else if (port == inf->private->notify_port)
+ printf_unfiltered (_(" inferior-notify"));
+ else
+ {
+ int k;
+ darwin_thread_t *t;
+
+ for (k = 0; k < inf->private->exception_info.count; k++)
+ if (port == inf->private->exception_info.ports[k])
+ {
+ printf_unfiltered (_(" inferior-excp-port"));
+ break;
+ }
+
+ if (inf->private->threads)
+ {
+ for (k = 0;
+ VEC_iterate(darwin_thread_t,
+ inf->private->threads, k, t);
+ k++)
+ if (port == t->gdb_port)
+ {
+ printf_unfiltered (_(" inferior-thread for 0x%x"),
+ inf->private->task);
+ break;
+ }
+ }
+ }
}
}
printf_unfiltered (_("\n"));
@@ -600,12 +621,36 @@ darwin_debug_regions_recurse (task_t task)
vm_region_submap_short_info_data_64_t r_info;
kern_return_t kret;
int ret;
+ struct cleanup *table_chain;
+
+ table_chain = make_cleanup_ui_out_table_begin_end (uiout, 9, -1, "regions");
+
+ if (gdbarch_addr_bit (current_gdbarch) <= 32)
+ {
+ ui_out_table_header (uiout, 10, ui_left, "start", "Start");
+ ui_out_table_header (uiout, 10, ui_left, "end", "End");
+ }
+ else
+ {
+ ui_out_table_header (uiout, 18, ui_left, "start", "Start");
+ ui_out_table_header (uiout, 18, ui_left, "end", "End");
+ }
+ ui_out_table_header (uiout, 3, ui_left, "min-prot", "Min");
+ ui_out_table_header (uiout, 3, ui_left, "max-prot", "Max");
+ ui_out_table_header (uiout, 5, ui_left, "inheritence", "Inh");
+ ui_out_table_header (uiout, 9, ui_left, "share-mode", "Shr");
+ ui_out_table_header (uiout, 1, ui_left, "depth", "D");
+ ui_out_table_header (uiout, 3, ui_left, "submap", "Sm");
+ ui_out_table_header (uiout, 0, ui_noalign, "tag", "Tag");
+
+ ui_out_table_body (uiout);
r_start = 0;
r_depth = 0;
while (1)
{
const char *tag;
+ struct cleanup *row_chain;
r_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
r_size = -1;
@@ -614,25 +659,39 @@ darwin_debug_regions_recurse (task_t task)
&r_info_size);
if (kret != KERN_SUCCESS)
break;
- printf_filtered (_("%s-%s %s/%s %-5s %-10s %2d %s"),
- paddr(r_start),
- paddr(r_start + r_size),
- unparse_protection (r_info.protection),
- unparse_protection (r_info.max_protection),
- unparse_inheritance (r_info.inheritance),
- unparse_share_mode (r_info.share_mode),
- r_depth,
- r_info.is_submap ? _("sm ") : _("obj"));
+ row_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "regions-row");
+
+ ui_out_field_core_addr (uiout, "start", r_start);
+ ui_out_field_core_addr (uiout, "end", r_start + r_size);
+ ui_out_field_string (uiout, "min-prot",
+ unparse_protection (r_info.protection));
+ ui_out_field_string (uiout, "max-prot",
+ unparse_protection (r_info.max_protection));
+ ui_out_field_string (uiout, "inheritence",
+ unparse_inheritance (r_info.inheritance));
+ ui_out_field_string (uiout, "share-mode",
+ unparse_share_mode (r_info.share_mode));
+ ui_out_field_int (uiout, "depth", r_depth);
+ ui_out_field_string (uiout, "submap",
+ r_info.is_submap ? _("sm ") : _("obj"));
tag = unparse_user_tag (r_info.user_tag);
if (tag)
- printf_unfiltered (_(" %s\n"), tag);
+ ui_out_field_string (uiout, "tag", tag);
else
- printf_unfiltered (_(" %u\n"), r_info.user_tag);
+ ui_out_field_int (uiout, "tag", r_info.user_tag);
+
+ do_cleanups (row_chain);
+
+ if (!ui_out_is_mi_like_p (uiout))
+ ui_out_text (uiout, "\n");
+
if (r_info.is_submap)
r_depth++;
else
r_start += r_size;
}
+ do_cleanups (table_chain);
+
}
@@ -672,6 +731,7 @@ info_mach_region_command (char *exp, int from_tty)
struct expression *expr;
struct value *val;
mach_vm_address_t address;
+ struct inferior *inf;
expr = parse_expression (exp);
val = evaluate_expression (expr);
@@ -679,22 +739,13 @@ info_mach_region_command (char *exp, int from_tty)
{
val = value_ind (val);
}
- /* In rvalue contexts, such as this, functions are coerced into
- pointers to functions. */
- if (TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC
- && VALUE_LVAL (val) == lval_memory)
- {
- address = value_address (val);
- }
- else
- {
- address = value_as_address (val);
- }
+ address = value_as_address (val);
- if ((!darwin_inf) || (darwin_inf->task == TASK_NULL))
+ if (ptid_equal (inferior_ptid, null_ptid))
error (_("Inferior not available"));
- darwin_debug_region (darwin_inf->task, address);
+ inf = current_inferior ();
+ darwin_debug_region (inf->private->task, address);
}
static void
@@ -761,9 +812,9 @@ info_mach_exceptions_command (char *args, int from_tty)
{
if (strcmp (args, "saved") == 0)
{
- if (darwin_inf->task == TASK_NULL)
- error (_("No inferior running\n"));
- disp_exception (&darwin_inf->exception_info);
+ if (ptid_equal (inferior_ptid, null_ptid))
+ printf_unfiltered (_("No inferior running\n"));
+ disp_exception (&current_inferior ()->private->exception_info);
return;
}
else if (strcmp (args, "host") == 0)
@@ -780,11 +831,14 @@ info_mach_exceptions_command (char *args, int from_tty)
}
else
{
- if (darwin_inf->task == TASK_NULL)
- error (_("No inferior running\n"));
+ struct inferior *inf;
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ printf_unfiltered (_("No inferior running\n"));
+ inf = current_inferior ();
kret = task_get_exception_ports
- (darwin_inf->task, EXC_MASK_ALL, info.masks,
+ (inf->private->task, EXC_MASK_ALL, info.masks,
&info.count, info.ports, info.behaviors, info.flavors);
MACH_CHECK_ERROR (kret);
disp_exception (&info);
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 3246881..2b45689 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -51,6 +51,8 @@
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
+#include <libproc.h>
+#include <sys/syscall.h>
#include <mach/mach_error.h>
#include <mach/mach_vm.h>
@@ -86,6 +88,15 @@ extern boolean_t exc_server (mach_msg_header_t *in, mach_msg_header_t *out);
static void darwin_stop (ptid_t);
+static void darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
+ enum target_signal signal);
+static void darwin_resume (ptid_t ptid, int step,
+ enum target_signal signal);
+
+static ptid_t darwin_wait_to (struct target_ops *ops, ptid_t ptid,
+ struct target_waitstatus *status, int options);
+static ptid_t darwin_wait (ptid_t ptid, struct target_waitstatus *status);
+
static void darwin_mourn_inferior (struct target_ops *ops);
static int darwin_lookup_task (char *args, task_t * ptask, int *ppid);
@@ -101,8 +112,9 @@ static void darwin_create_inferior (struct target_ops *ops, char *exec_file,
static void darwin_files_info (struct target_ops *ops);
-/* Current inferior. */
-darwin_inferior *darwin_inf = NULL;
+static char *darwin_pid_to_str (struct target_ops *ops, ptid_t tpid);
+
+static int darwin_thread_alive (struct target_ops *ops, ptid_t tpid);
/* Target operations for Darwin. */
static struct target_ops *darwin_ops;
@@ -116,9 +128,6 @@ mach_port_t darwin_host_self;
/* Exception port. */
mach_port_t darwin_ex_port;
-/* Notification port. */
-mach_port_t darwin_not_port;
-
/* Port set. */
mach_port_t darwin_port_set;
@@ -129,47 +138,13 @@ static vm_size_t mach_page_size;
by the kernel). */
static int enable_mach_exceptions;
+/* Inferior that should report a fake stop event. */
+static struct inferior *darwin_inf_fake_stop;
+
#define PAGE_TRUNC(x) ((x) & ~(mach_page_size - 1))
#define PAGE_ROUND(x) PAGE_TRUNC((x) + mach_page_size - 1)
-/* Buffer containing received message and to be sent message. */
-static union
-{
- mach_msg_header_t hdr;
- char data[1024];
-} msgin, msgout;
-
-/* Current message state.
- If the kernel has sent a message it expects a reply and the inferior
- can't be killed before. */
-static enum msg_state { NO_MESSAGE, GOT_MESSAGE, REPLY_SENT } msg_state;
-
-/* Unmarshalled received message. */
-static struct exc_msg
-{
- /* Receive port. */
- mach_port_t port;
-
- /* Thread and task taking the exception. */
- mach_port_t thread_port;
- mach_port_t task_port;
-
- /* Type of the exception. */
- exception_type_t ex_type;
-
- /* Machine dependent details. */
- mach_msg_type_number_t data_count;
- integer_t ex_data[4];
-} exc_msg;
-
-
-/* This controls output of inferior debugging.
- 1 = basic exception handling
- 2 = task management
- 3 = thread management
- 4 = pending_event_handler
- 6 = most chatty level. */
-
+/* This controls output of inferior debugging. */
static int darwin_debug_flag = 0;
static void
@@ -194,9 +169,9 @@ mach_check_error (kern_return_t ret, const char *file,
return;
if (func == NULL)
func = _("[UNKNOWN]");
-
- error (_("error on line %u of \"%s\" in function \"%s\": %s (0x%lx)\n"),
- line, file, func, mach_error_string (ret), (unsigned long) ret);
+
+ warning (_("Mach error at \"%s:%u\" in function \"%s\": %s (0x%lx)\n"),
+ file, line, func, mach_error_string (ret), (unsigned long) ret);
}
static const char *
@@ -240,7 +215,7 @@ darwin_ptrace (const char *name,
ret = ptrace (request, pid, (caddr_t) arg3, arg4);
- inferior_debug (2, _("ptrace (%s, %d, 0x%x, %d): %d (%s)\n"),
+ inferior_debug (4, _("ptrace (%s, %d, 0x%x, %d): %d (%s)\n"),
name, pid, arg3, arg4, ret,
(ret != 0) ? safe_strerror (errno) : _("no error"));
return ret;
@@ -249,13 +224,13 @@ darwin_ptrace (const char *name,
static int
cmp_thread_t (const void *l, const void *r)
{
- thread_t lt = *(const thread_t *)l;
- thread_t lr = *(const thread_t *)r;
- return (int)(lr - lt);
+ thread_t tl = *(const thread_t *)l;
+ thread_t tr = *(const thread_t *)r;
+ return (int)(tl - tr);
}
static void
-darwin_check_new_threads (darwin_inferior *inf)
+darwin_check_new_threads (struct inferior *inf)
{
kern_return_t kret;
unsigned int i;
@@ -263,35 +238,58 @@ darwin_check_new_threads (darwin_inferior *inf)
unsigned int new_nbr;
unsigned int old_nbr;
unsigned int new_ix, old_ix;
- VEC (thread_t) *thread_vec;
+ darwin_inferior *darwin_inf = inf->private;
+ VEC (darwin_thread_t) *thread_vec;
/* Get list of threads. */
- kret = task_threads (inf->task, &thread_list, &new_nbr);
+ kret = task_threads (darwin_inf->task, &thread_list, &new_nbr);
MACH_CHECK_ERROR (kret);
if (kret != KERN_SUCCESS)
return;
+ /* Sort the list. */
if (new_nbr > 1)
qsort (thread_list, new_nbr, sizeof (thread_t), cmp_thread_t);
- thread_vec = VEC_alloc (thread_t, new_nbr);
-
- if (inf->threads)
- old_nbr = VEC_length (thread_t, inf->threads);
+ if (darwin_inf->threads)
+ old_nbr = VEC_length (darwin_thread_t, darwin_inf->threads);
else
old_nbr = 0;
+ /* Quick check for no changes. */
+ if (old_nbr == new_nbr)
+ {
+ for (i = 0; i < new_nbr; i++)
+ if (thread_list[i]
+ != VEC_index (darwin_thread_t, darwin_inf->threads, i)->gdb_port)
+ break;
+ if (i == new_nbr)
+ {
+ kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
+ new_nbr * sizeof (int));
+ MACH_CHECK_ERROR (kret);
+ return;
+ }
+ }
+
+ thread_vec = VEC_alloc (darwin_thread_t, new_nbr);
+
for (new_ix = 0, old_ix = 0; new_ix < new_nbr || old_ix < old_nbr;)
{
thread_t new_id = (new_ix < new_nbr) ?
thread_list[new_ix] : THREAD_NULL;
- thread_t old_id = (old_ix < old_nbr) ?
- VEC_index (thread_t, inf->threads, old_ix) : THREAD_NULL;
+ darwin_thread_t *old = (old_ix < old_nbr) ?
+ VEC_index (darwin_thread_t, darwin_inf->threads, old_ix) : NULL;
+ thread_t old_id = old ? old->gdb_port : THREAD_NULL;
+
+ inferior_debug
+ (12, _(" new_ix:%d/%d, old_ix:%d/%d, new_id:%x old_id:%x\n"),
+ new_ix, new_nbr, old_ix, old_nbr, new_id, old_id);
if (old_id == new_id)
{
/* Thread still exist. */
- VEC_safe_push (thread_t, thread_vec, old_id);
+ VEC_safe_push (darwin_thread_t, thread_vec, old);
new_ix++;
old_ix++;
@@ -299,251 +297,559 @@ darwin_check_new_threads (darwin_inferior *inf)
MACH_CHECK_ERROR (kret);
continue;
}
- if (new_id < old_id || old_ix == old_nbr)
+ if (new_ix < new_nbr && new_id == MACH_PORT_DEAD)
+ {
+ /* Ignore dead ports.
+ In some weird cases, we might get dead ports. They should
+ correspond to dead thread so they could safely be ignored. */
+ new_ix++;
+ continue;
+ }
+ if (new_ix < new_nbr && (old_ix == old_nbr || new_id < old_id))
{
/* A thread was created. */
struct thread_info *tp;
+ struct private_thread_info *pti;
- tp = add_thread (ptid_build (inf->pid, 0, new_id));
- VEC_safe_push (thread_t, thread_vec, new_id);
+ pti = XZALLOC (struct private_thread_info);
+ pti->gdb_port = new_id;
+ pti->msg_state = DARWIN_RUNNING;
+
+ /* Add a new thread unless this is the first one ever met. */
+ if (!(old_nbr == 0 && new_ix == 0))
+ tp = add_thread_with_info (ptid_build (inf->pid, 0, new_id), pti);
+ else
+ {
+ tp = find_thread_ptid (ptid_build (inf->pid, 0, 0));
+ gdb_assert (tp);
+ tp->private = pti;
+ }
+ VEC_safe_push (darwin_thread_t, thread_vec, pti);
new_ix++;
continue;
}
- if (new_id > old_id || new_ix == new_nbr)
+ if (old_ix < old_nbr && (new_ix == new_nbr || new_id > old_id))
{
/* A thread was removed. */
delete_thread (ptid_build (inf->pid, 0, old_id));
kret = mach_port_deallocate (gdb_task, old_id);
MACH_CHECK_ERROR (kret);
old_ix++;
+ continue;
}
+ gdb_assert (0);
}
- if (inf->threads)
- VEC_free (thread_t, inf->threads);
- inf->threads = thread_vec;
+ if (darwin_inf->threads)
+ VEC_free (darwin_thread_t, darwin_inf->threads);
+ darwin_inf->threads = thread_vec;
kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
new_nbr * sizeof (int));
MACH_CHECK_ERROR (kret);
}
-static void
-darwin_stop (ptid_t t)
+static int
+find_inferior_task_it (struct inferior *inf, void *port_ptr)
{
- int ret;
+ return inf->private->task == *(task_t*)port_ptr;
+}
- ret = kill (ptid_get_pid (inferior_ptid), SIGINT);
+static int
+find_inferior_notify_it (struct inferior *inf, void *port_ptr)
+{
+ return inf->private->notify_port == *(task_t*)port_ptr;
}
-static void
-darwin_resume (struct target_ops *ops,
- ptid_t ptid, int step, enum target_signal signal)
+/* Return an inferior by task port. */
+static struct inferior *
+darwin_find_inferior_by_task (task_t port)
{
- struct target_waitstatus status;
- int pid;
- thread_t thread;
- kern_return_t kret;
- int res;
+ return iterate_over_inferiors (&find_inferior_task_it, &port);
+}
- /* minus_one_ptid is RESUME_ALL. */
- if (ptid_equal (ptid, minus_one_ptid))
- ptid = inferior_ptid;
+/* Return an inferior by notification port. */
+static struct inferior *
+darwin_find_inferior_by_notify (mach_port_t port)
+{
+ return iterate_over_inferiors (&find_inferior_notify_it, &port);
+}
- pid = ptid_get_pid (ptid);
- thread = ptid_get_tid (ptid);
+/* Return a thread by port. */
+static darwin_thread_t *
+darwin_find_thread (struct inferior *inf, thread_t thread)
+{
+ darwin_thread_t *t;
+ int k;
+
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ k++)
+ if (t->gdb_port == thread)
+ return t;
+ return NULL;
+}
- inferior_debug
- (2, _("darwin_resume: state=%d, thread=0x%x, step=%d signal=%d\n"),
- msg_state, thread, step, signal);
+/* Suspend (ie stop) an inferior at Mach level. */
- switch (msg_state)
+static void
+darwin_suspend_inferior (struct inferior *inf)
+{
+ if (!inf->private->suspended)
{
- case GOT_MESSAGE:
- switch (exc_msg.ex_type)
- {
- case EXC_SOFTWARE:
- if (exc_msg.ex_data[0] == EXC_SOFT_SIGNAL)
- {
- int nsignal = target_signal_to_host (signal);
- res = PTRACE (PT_THUPDATE, pid,
- (void *)(uintptr_t)exc_msg.thread_port, nsignal);
- if (res < 0)
- printf_unfiltered (_("ptrace THUP: res=%d\n"), res);
- }
- break;
+ kern_return_t kret;
- default:
- break;
- }
-
- if (thread != 0)
- {
- inferior_debug (2, _("darwin_set_sstep (thread=%x, enable=%d)\n"),
- thread, step);
- darwin_set_sstep (thread, step);
- }
+ kret = task_suspend (inf->private->task);
+ MACH_CHECK_ERROR (kret);
- kret = mach_msg (&msgout.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
- msgout.hdr.msgh_size, 0,
- MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
- if (kret != 0)
- printf_unfiltered (_("mach_msg (reply) ret=%d\n"), kret);
+ inf->private->suspended = 1;
+ }
+}
- msg_state = REPLY_SENT;
- break;
+/* Resume an inferior at Mach level. */
- case NO_MESSAGE:
- if (step)
- res = PTRACE (PT_STEP, pid, (caddr_t)1, 0);
- else
- res = PTRACE (PT_CONTINUE, pid, (caddr_t)1, 0);
- break;
+static void
+darwin_resume_inferior (struct inferior *inf)
+{
+ if (inf->private->suspended)
+ {
+ kern_return_t kret;
- default:
- gdb_assert (0);
+ kret = task_resume (inf->private->task);
+ MACH_CHECK_ERROR (kret);
+
+ inf->private->suspended = 0;
}
}
-kern_return_t
-catch_exception_raise_state
- (mach_port_t port,
- exception_type_t exception_type, mach_exception_data_t exception_data,
- mach_msg_type_number_t data_count, thread_state_flavor_t * state_flavor,
- thread_state_t in_state, mach_msg_type_number_t in_state_count,
- thread_state_t out_state, mach_msg_type_number_t out_state_count)
+/* Iterator functions. */
+
+static int
+darwin_suspend_inferior_it (struct inferior *inf, void *arg)
+{
+ darwin_suspend_inferior (inf);
+ darwin_check_new_threads (inf);
+ return 0;
+}
+
+static int
+darwin_resume_inferior_it (struct inferior *inf, void *arg)
+{
+ darwin_resume_inferior (inf);
+ return 0;
+}
+
+static void
+darwin_dump_message (mach_msg_header_t *hdr, int disp_body)
{
- return KERN_FAILURE;
+ printf_unfiltered (_("message header:\n"));
+ printf_unfiltered (_(" bits: 0x%x\n"), hdr->msgh_bits);
+ printf_unfiltered (_(" size: 0x%x\n"), hdr->msgh_size);
+ printf_unfiltered (_(" remote-port: 0x%x\n"), hdr->msgh_remote_port);
+ printf_unfiltered (_(" local-port: 0x%x\n"), hdr->msgh_local_port);
+ printf_unfiltered (_(" reserved: 0x%x\n"), hdr->msgh_reserved);
+ printf_unfiltered (_(" id: 0x%x\n"), hdr->msgh_id);
+
+ if (disp_body)
+ {
+ const unsigned char *data;
+ const unsigned long *ldata;
+ int size;
+ int i;
+
+ data = (unsigned char *)(hdr + 1);
+ size = hdr->msgh_size - sizeof (mach_msg_header_t);
+
+ if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ {
+ mach_msg_body_t *bod = (mach_msg_body_t*)data;
+ mach_msg_port_descriptor_t *desc =
+ (mach_msg_port_descriptor_t *)(bod + 1);
+ int k;
+ NDR_record_t *ndr;
+ printf_unfiltered (_("body: descriptor_count=%u\n"),
+ bod->msgh_descriptor_count);
+ data += sizeof (mach_msg_body_t);
+ size -= sizeof (mach_msg_body_t);
+ for (k = 0; k < bod->msgh_descriptor_count; k++)
+ switch (desc[k].type)
+ {
+ case MACH_MSG_PORT_DESCRIPTOR:
+ printf_unfiltered
+ (_(" descr %d: type=%u (port) name=0x%x, dispo=%d\n"),
+ k, desc[k].type, desc[k].name, desc[k].disposition);
+ break;
+ default:
+ printf_unfiltered (_(" descr %d: type=%u\n"),
+ k, desc[k].type);
+ break;
+ }
+ data += bod->msgh_descriptor_count
+ * sizeof (mach_msg_port_descriptor_t);
+ size -= bod->msgh_descriptor_count
+ * sizeof (mach_msg_port_descriptor_t);
+ ndr = (NDR_record_t *)(desc + bod->msgh_descriptor_count);
+ printf_unfiltered
+ (_("NDR: mig=%02x if=%02x encod=%02x "
+ "int=%02x char=%02x float=%02x\n"),
+ ndr->mig_vers, ndr->if_vers, ndr->mig_encoding,
+ ndr->int_rep, ndr->char_rep, ndr->float_rep);
+ data += sizeof (NDR_record_t);
+ size -= sizeof (NDR_record_t);
+ }
+
+ printf_unfiltered (_(" data:"));
+ ldata = (const unsigned long *)data;
+ for (i = 0; i < size / sizeof (unsigned long); i++)
+ printf_unfiltered (" %08lx", ldata[i]);
+ printf_unfiltered (_("\n"));
+ }
}
-kern_return_t
-catch_exception_raise_state_identity
- (mach_port_t port, mach_port_t thread_port, mach_port_t task_port,
- exception_type_t exception_type, mach_exception_data_t exception_data,
- mach_msg_type_number_t data_count, thread_state_flavor_t * state_flavor,
- thread_state_t in_state, mach_msg_type_number_t in_state_count,
- thread_state_t out_state, mach_msg_type_number_t out_state_count)
+static int
+darwin_decode_exception_message (mach_msg_header_t *hdr,
+ struct inferior **pinf,
+ darwin_thread_t **pthread)
{
+ mach_msg_body_t *bod = (mach_msg_body_t*)(hdr + 1);
+ mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1);
+ NDR_record_t *ndr;
+ integer_t *data;
+ struct inferior *inf;
+ darwin_thread_t *thread;
+ task_t task_port;
+ thread_t thread_port;
kern_return_t kret;
+ int i;
+
+ /* Check message identifier. 2401 is exc. */
+ if (hdr->msgh_id != 2401)
+ return -1;
+
+ /* Check message header. */
+ if (!(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX))
+ return -1;
+
+ /* Check descriptors. */
+ if (hdr->msgh_size < (sizeof (*hdr) + sizeof (*bod) + 2 * sizeof (*desc)
+ + sizeof (*ndr) + 2 * sizeof (integer_t))
+ || bod->msgh_descriptor_count != 2
+ || desc[0].type != MACH_MSG_PORT_DESCRIPTOR
+ || desc[0].disposition != MACH_MSG_TYPE_MOVE_SEND
+ || desc[1].type != MACH_MSG_PORT_DESCRIPTOR
+ || desc[1].disposition != MACH_MSG_TYPE_MOVE_SEND)
+ return -1;
+
+ /* Check data representation. */
+ ndr = (NDR_record_t *)(desc + 2);
+ if (ndr->mig_vers != NDR_PROTOCOL_2_0
+ || ndr->if_vers != NDR_PROTOCOL_2_0
+ || ndr->mig_encoding != NDR_record.mig_encoding
+ || ndr->int_rep != NDR_record.int_rep
+ || ndr->char_rep != NDR_record.char_rep
+ || ndr->float_rep != NDR_record.float_rep)
+ return -1;
+
+ /* Ok, the hard work. */
+ data = (integer_t *)(ndr + 1);
+ /* Find process by port. */
+ task_port = desc[1].name;
+ thread_port = desc[0].name;
+ inf = darwin_find_inferior_by_task (task_port);
+ if (inf == NULL)
+ return -1;
+ *pinf = inf;
+
+ /* Find thread by port. */
+ /* Check for new threads. Do it early so that the port in the exception
+ message can be deallocated. */
+ darwin_check_new_threads (inf);
+
+ /* We got new rights to the task and the thread. Get rid of them. */
kret = mach_port_deallocate (mach_task_self (), task_port);
MACH_CHECK_ERROR (kret);
kret = mach_port_deallocate (mach_task_self (), thread_port);
MACH_CHECK_ERROR (kret);
- return KERN_FAILURE;
+ thread = darwin_find_thread (inf, thread_port);
+ if (thread == NULL)
+ return -1;
+ *pthread = thread;
+
+ /* Finish decoding. */
+ gdb_assert (thread->msg_state == DARWIN_RUNNING);
+ thread->event.header = *hdr;
+ thread->event.thread_port = thread_port;
+ thread->event.task_port = task_port;
+ thread->event.ex_type = data[0];
+ thread->event.data_count = data[1];
+
+ if (hdr->msgh_size < (sizeof (*hdr) + sizeof (*bod) + 2 * sizeof (*desc)
+ + sizeof (*ndr) + 2 * sizeof (integer_t)
+ + data[1] * sizeof (integer_t)))
+ return -1;
+ for (i = 0; i < data[1]; i++)
+ thread->event.ex_data[i] = data[2 + i];
+
+ thread->msg_state = DARWIN_MESSAGE;
+
+ return 0;
+}
+
+static void
+darwin_encode_reply (mig_reply_error_t *reply, mach_msg_header_t *hdr,
+ integer_t code)
+{
+ mach_msg_header_t *rh = &reply->Head;
+ rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr->msgh_bits), 0);
+ rh->msgh_remote_port = hdr->msgh_remote_port;
+ rh->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
+ rh->msgh_local_port = MACH_PORT_NULL;
+ rh->msgh_id = hdr->msgh_id + 100;
+
+ reply->NDR = NDR_record;
+ reply->RetCode = code;
}
-kern_return_t
-catch_exception_raise (mach_port_t port,
- mach_port_t thread_port,
- mach_port_t task_port,
- exception_type_t exception_type,
- exception_data_t exception_data,
- mach_msg_type_number_t data_count)
+static void
+darwin_send_reply (struct inferior *inf, darwin_thread_t *thread)
{
kern_return_t kret;
- int i;
- int res;
+ mig_reply_error_t reply;
- /* We got new rights to the task. Get rid of it. */
- kret = mach_port_deallocate (mach_task_self (), task_port);
+ darwin_encode_reply (&reply, &thread->event.header, KERN_SUCCESS);
+
+ kret = mach_msg (&reply.Head, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply.Head.msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
MACH_CHECK_ERROR (kret);
+ inf->private->pending_messages--;
+}
+
+static void
+darwin_resume_thread (struct inferior *inf, darwin_thread_t *thread,
+ int step, int nsignal)
+{
+ kern_return_t kret;
+ int res;
+
inferior_debug
- (7, _("catch_exception_raise: exception_type=%d, data_count=%d\n"),
- exception_type, data_count);
- if (darwin_debug_flag > 7)
+ (3, _("darwin_resume_thread: state=%d, thread=0x%x, step=%d nsignal=%d\n"),
+ thread->msg_state, thread->gdb_port, step, nsignal);
+
+ switch (thread->msg_state)
{
- for (i = 0; i < data_count; i++)
- printf_unfiltered (" %08x", exception_data[i]);
- printf_unfiltered ("\n");
+ case DARWIN_MESSAGE:
+ if (thread->event.ex_type == EXC_SOFTWARE
+ && thread->event.ex_data[0] == EXC_SOFT_SIGNAL)
+ {
+ /* Either deliver a new signal or cancel the signal received. */
+ res = PTRACE (PT_THUPDATE, inf->pid,
+ (void *)(uintptr_t)thread->gdb_port, nsignal);
+ if (res < 0)
+ inferior_debug (1, _("ptrace THUP: res=%d\n"), res);
+ }
+ else if (nsignal)
+ {
+ /* Note: ptrace is allowed only if the process is stopped.
+ Directly send the signal to the thread. */
+ res = syscall (SYS___pthread_kill, thread->gdb_port, nsignal);
+ inferior_debug (4, _("darwin_resume_thread: kill 0x%x %d: %d\n"),
+ thread->gdb_port, nsignal, res);
+ thread->signaled = 1;
+ }
+
+ /* Set single step. */
+ inferior_debug (4, _("darwin_set_sstep (thread=%x, enable=%d)\n"),
+ thread->gdb_port, step);
+ darwin_set_sstep (thread->gdb_port, step);
+ thread->single_step = step;
+
+ darwin_send_reply (inf, thread);
+ thread->msg_state = DARWIN_RUNNING;
+ break;
+
+ case DARWIN_RUNNING:
+ break;
+
+ case DARWIN_STOPPED:
+ kret = thread_resume (thread->gdb_port);
+ MACH_CHECK_ERROR (kret);
+
+ thread->msg_state = DARWIN_RUNNING;
+ break;
}
+}
- /* Save the message.
- FIXME: this should be in a per-thread variable. */
- exc_msg.port = port;
- exc_msg.thread_port = thread_port;
- exc_msg.task_port = task_port;
- exc_msg.ex_type = exception_type;
- exc_msg.data_count = data_count;
- for (i = 0; i < data_count && i < 4; i++)
- exc_msg.ex_data[i] = exception_data[i];
+/* Resume all threads of the inferior. */
- return KERN_SUCCESS;
+static void
+darwin_resume_inferior_threads (struct inferior *inf, int step, int nsignal)
+{
+ darwin_thread_t *thread;
+ int k;
+
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, thread);
+ k++)
+ darwin_resume_thread (inf, thread, step, nsignal);
}
-static ptid_t
-darwin_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status, int options)
+struct resume_inferior_threads_param
+{
+ int step;
+ int nsignal;
+};
+
+static int
+darwin_resume_inferior_threads_it (struct inferior *inf, void *param)
+{
+ int step = ((struct resume_inferior_threads_param *)param)->step;
+ int nsignal = ((struct resume_inferior_threads_param *)param)->nsignal;
+
+ darwin_resume_inferior_threads (inf, step, nsignal);
+
+ return 0;
+}
+
+/* Suspend all threads of INF. */
+
+static void
+darwin_suspend_inferior_threads (struct inferior *inf)
{
+ darwin_thread_t *thread;
kern_return_t kret;
- mach_msg_header_t *hdr = &msgin.hdr;
- pid_t pid = ptid_get_pid (inferior_ptid); /* FIXME. */
+ int k;
+
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, thread);
+ k++)
+ switch (thread->msg_state)
+ {
+ case DARWIN_STOPPED:
+ case DARWIN_MESSAGE:
+ break;
+ case DARWIN_RUNNING:
+ kret = thread_suspend (thread->gdb_port);
+ MACH_CHECK_ERROR (kret);
+ thread->msg_state = DARWIN_STOPPED;
+ break;
+ }
+}
- gdb_assert (msg_state != GOT_MESSAGE);
+static void
+darwin_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+ struct target_waitstatus status;
+ int pid;
- inferior_debug (6, _("darwin_wait: waiting for a message\n"));
+ kern_return_t kret;
+ int res;
+ int nsignal;
+ struct inferior *inf;
+
+ inferior_debug
+ (2, _("darwin_resume: pid=%d, tid=0x%x, step=%d, signal=%d\n"),
+ ptid_get_pid (ptid), ptid_get_tid (ptid), step, signal);
- /* Wait for a message. */
- kret = mach_msg (&msgin.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0,
- sizeof (msgin.data), darwin_port_set, 0, MACH_PORT_NULL);
+ if (signal == TARGET_SIGNAL_0)
+ nsignal = 0;
+ else
+ nsignal = target_signal_to_host (signal);
+
+ /* Don't try to single step all threads. */
+ if (step)
+ ptid = inferior_ptid;
- if (kret == MACH_RCV_INTERRUPTED)
+ /* minus_one_ptid is RESUME_ALL. */
+ if (ptid_equal (ptid, minus_one_ptid))
{
- status->kind = TARGET_WAITKIND_IGNORE;
- return minus_one_ptid;
- }
+ struct resume_inferior_threads_param param;
- if (kret != MACH_MSG_SUCCESS)
+ param.nsignal = nsignal;
+ param.step = step;
+
+ /* Resume threads. */
+ iterate_over_inferiors (darwin_resume_inferior_threads_it, &param);
+ /* Resume tasks. */
+ iterate_over_inferiors (darwin_resume_inferior_it, NULL);
+ }
+ else
{
- inferior_debug (1, _("mach_msg: ret=%x\n"), kret);
- status->kind = TARGET_WAITKIND_SPURIOUS;
- return minus_one_ptid;
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
+ long tid = ptid_get_tid (ptid);
+
+ /* Stop the inferior (should be useless). */
+ darwin_suspend_inferior (inf);
+
+ if (tid == 0)
+ darwin_resume_inferior_threads (inf, step, nsignal);
+ else
+ {
+ darwin_thread_t *thread;
+
+ /* Suspend threads of the task. */
+ darwin_suspend_inferior_threads (inf);
+
+ /* Resume the selected thread. */
+ thread = darwin_find_thread (inf, tid);
+ gdb_assert (thread);
+ darwin_resume_thread (inf, thread, step, nsignal);
+ }
+
+ /* Resume the task. */
+ darwin_resume_inferior (inf);
}
+}
- /* Debug: display message. */
- if (darwin_debug_flag > 10)
- {
- const unsigned long *buf = (unsigned long *) hdr;
- unsigned int i;
-
- printf_unfiltered (_(" bits: 0x%x"), hdr->msgh_bits);
- printf_unfiltered (_(", size: 0x%x"), hdr->msgh_size);
- printf_unfiltered (_(", remote-port: 0x%x"), hdr->msgh_remote_port);
- printf_unfiltered (_(", local-port: 0x%x"), hdr->msgh_local_port);
- printf_unfiltered (_(", reserved: 0x%x"), hdr->msgh_reserved);
- printf_unfiltered (_(", id: 0x%x\n"), hdr->msgh_id);
-
- if (darwin_debug_flag > 11)
- {
- printf_unfiltered (_(" data:"));
- for (i = 0; i < hdr->msgh_size; i++)
- printf_unfiltered (" %08lx", buf[i]);
- printf_unfiltered (_("\n"));
- }
- }
+static void
+darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
+ enum target_signal signal)
+{
+ return darwin_resume (ptid, step, signal);
+}
+
+static ptid_t
+darwin_decode_message (mach_msg_header_t *hdr,
+ darwin_thread_t **pthread,
+ struct inferior **pinf,
+ struct target_waitstatus *status)
+{
+ darwin_thread_t *thread;
+ struct inferior *inf;
/* Exception message. */
if (hdr->msgh_local_port == darwin_ex_port)
{
- /* Handle it via the exception server. */
- if (!exc_server (&msgin.hdr, &msgout.hdr))
+ int res;
+
+ /* Decode message. */
+ res = darwin_decode_exception_message (hdr, &inf, &thread);
+
+ if (res < 0)
{
- printf_unfiltered (_("exc_server: unknown message (id=%x)\n"),
+ /* Should not happen... */
+ printf_unfiltered (_("darwin_wait: ill-formatted message (id=%x)\n"),
hdr->msgh_id);
+ /* FIXME: send a failure reply? */
status->kind = TARGET_WAITKIND_SPURIOUS;
return minus_one_ptid;
}
+ *pinf = inf;
+ *pthread = thread;
+ inf->private->pending_messages++;
status->kind = TARGET_WAITKIND_STOPPED;
+ thread->msg_state = DARWIN_MESSAGE;
- inferior_debug (2, _("darwin_wait: thread=%x, got %s\n"),
- exc_msg.thread_port,
- unparse_exception_type (exc_msg.ex_type));
-
- switch (exc_msg.ex_type)
+ inferior_debug (4, _("darwin_wait: thread=%x, got %s\n"),
+ thread->gdb_port,
+ unparse_exception_type (thread->event.ex_type));
+
+ switch (thread->event.ex_type)
{
case EXC_BAD_ACCESS:
status->value.sig = TARGET_EXC_BAD_ACCESS;
@@ -558,15 +864,26 @@ darwin_wait (struct target_ops *ops,
status->value.sig = TARGET_EXC_EMULATION;
break;
case EXC_SOFTWARE:
- if (exc_msg.ex_data[0] == EXC_SOFT_SIGNAL)
+ if (thread->event.ex_data[0] == EXC_SOFT_SIGNAL)
{
- status->value.sig = target_signal_from_host (exc_msg.ex_data[1]);
- inferior_debug (2, _(" (signal %d: %s)\n"),
- exc_msg.ex_data[1],
+ status->value.sig =
+ target_signal_from_host (thread->event.ex_data[1]);
+ inferior_debug (5, _(" (signal %d: %s)\n"),
+ thread->event.ex_data[1],
target_signal_to_name (status->value.sig));
+
+ /* If the thread is stopped because it has received a signal
+ that gdb has just sent, continue. */
+ if (thread->signaled)
+ {
+ thread->signaled = 0;
+ darwin_send_reply (inf, thread);
+ thread->msg_state = DARWIN_RUNNING;
+ status->kind = TARGET_WAITKIND_IGNORE;
+ }
}
else
- status->value.sig = TARGET_EXC_SOFTWARE;
+ status->value.sig = TARGET_EXC_SOFTWARE;
break;
case EXC_BREAKPOINT:
/* Many internal GDB routines expect breakpoints to be reported
@@ -579,38 +896,216 @@ darwin_wait (struct target_ops *ops,
break;
}
- msg_state = GOT_MESSAGE;
+ return ptid_build (inf->pid, 0, thread->gdb_port);
+ }
+
+ *pinf = NULL;
+ *pthread = NULL;
+
+ inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
+ if (inf != NULL)
+ {
+ if (!inf->private->no_ptrace)
+ {
+ pid_t res;
+ int wstatus;
+
+ res = wait4 (inf->pid, &wstatus, 0, NULL);
+ if (res < 0 || res != inf->pid)
+ {
+ printf_unfiltered (_("wait4: res=%d: %s\n"),
+ res, safe_strerror (errno));
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return minus_one_ptid;
+ }
+ if (WIFEXITED (wstatus))
+ {
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = WEXITSTATUS (wstatus);
+ }
+ else
+ {
+ status->kind = TARGET_WAITKIND_SIGNALLED;
+ status->value.sig = WTERMSIG (wstatus);
+ }
+
+ inferior_debug (4, _("darwin_wait: pid=%d exit, status=%x\n"),
+ res, wstatus);
+
+ /* Looks necessary on Leopard and harmless... */
+ wait4 (inf->pid, &wstatus, 0, NULL);
+
+ return ptid_build (inf->pid, 0, 0);
+ }
+ else
+ {
+ inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid);
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0; /* Don't know. */
+ return ptid_build (inf->pid, 0, 0);
+ }
+ }
+
+ printf_unfiltered (_("Bad local-port: %x\n"), hdr->msgh_local_port);
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return minus_one_ptid;
+}
+
+static int
+cancel_breakpoint (ptid_t ptid)
+{
+ /* Arrange for a breakpoint to be hit again later. We will handle
+ the current event, eventually we will resume this thread, and this
+ breakpoint will trap again.
+
+ If we do not do this, then we run the risk that the user will
+ delete or disable the breakpoint, but the thread will have already
+ tripped on it. */
- return ptid_build (pid, 0, exc_msg.thread_port);
+ struct regcache *regcache = get_thread_regcache (ptid);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ CORE_ADDR pc;
+
+ pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch);
+ if (breakpoint_inserted_here_p (pc))
+ {
+ inferior_debug (4, "cancel_breakpoint for thread %x\n",
+ ptid_get_tid (ptid));
+
+ /* Back up the PC if necessary. */
+ if (gdbarch_decr_pc_after_break (gdbarch))
+ regcache_write_pc (regcache, pc);
+
+ return 1;
}
- else if (hdr->msgh_local_port == darwin_not_port)
+ return 0;
+}
+
+static ptid_t
+darwin_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ kern_return_t kret;
+ union
+ {
+ mach_msg_header_t hdr;
+ char data[0x100];
+ } msgin;
+ mach_msg_header_t *hdr = &msgin.hdr;
+ ptid_t res;
+ darwin_thread_t *thread;
+ struct inferior *inf;
+
+ inferior_debug
+ (2, _("darwin_wait: waiting for a message pid=%d thread=%lx\n"),
+ ptid_get_pid (ptid), ptid_get_tid (ptid));
+
+ /* Handle fake stop events at first. */
+ if (darwin_inf_fake_stop != NULL)
{
- pid_t res;
- int wstatus;
+ inf = darwin_inf_fake_stop;
+ darwin_inf_fake_stop = NULL;
- /* FIXME: translate task port to pid. */
- res = wait4 (pid, &wstatus, 0, NULL);
- if (res != pid)
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ thread = VEC_index (darwin_thread_t, inf->private->threads, 0);
+ thread->msg_state = DARWIN_STOPPED;
+ return ptid_build (inf->pid, 0, thread->gdb_port);
+ }
+
+ do
+ {
+ /* set_sigint_trap (); */
+
+ /* Wait for a message. */
+ kret = mach_msg (&msgin.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0,
+ sizeof (msgin.data), darwin_port_set, 0, MACH_PORT_NULL);
+
+ /* clear_sigint_trap (); */
+
+ if (kret == MACH_RCV_INTERRUPTED)
+ {
+ status->kind = TARGET_WAITKIND_IGNORE;
+ return minus_one_ptid;
+ }
+
+ if (kret != MACH_MSG_SUCCESS)
{
- printf_unfiltered (_("wait4: res=%x\n"), res);
- wstatus = 0;
+ inferior_debug (5, _("mach_msg: ret=%x\n"), kret);
+ status->kind = TARGET_WAITKIND_SPURIOUS;
+ return minus_one_ptid;
}
- status->kind = TARGET_WAITKIND_EXITED;
- status->value.integer = WEXITSTATUS (wstatus);
- inferior_debug (2, _("darwin_wait: pid=%d exit, status=%x\n"),
- pid, wstatus);
+ /* Debug: display message. */
+ if (darwin_debug_flag > 10)
+ darwin_dump_message (hdr, darwin_debug_flag > 11);
- msg_state = NO_MESSAGE;
+ res = darwin_decode_message (hdr, &thread, &inf, status);
- return ptid;
+ if (inf == NULL)
+ return res;
}
- else
+ while (status->kind == TARGET_WAITKIND_IGNORE);
+
+ /* Stop all tasks. */
+ iterate_over_inferiors (darwin_suspend_inferior_it, NULL);
+
+ /* Read pending messages. */
+ while (1)
{
- printf_unfiltered (_("Bad local-port: %x\n"), hdr->msgh_local_port);
- status->kind = TARGET_WAITKIND_SPURIOUS;
- return minus_one_ptid;
+ struct target_waitstatus status2;
+ ptid_t ptid2;
+
+ kret = mach_msg (&msgin.hdr,
+ MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
+ sizeof (msgin.data), darwin_port_set, 1, MACH_PORT_NULL);
+
+ if (kret == MACH_RCV_TIMED_OUT)
+ break;
+ if (kret != MACH_MSG_SUCCESS)
+ {
+ inferior_debug
+ (5, _("darwin_wait: mach_msg(pending) ret=%x\n"), kret);
+ break;
+ }
+
+ ptid2 = darwin_decode_message (hdr, &thread, &inf, &status2);
+
+ if (inf != NULL && thread != NULL
+ && thread->event.ex_type == EXC_BREAKPOINT)
+ {
+ if (thread->single_step
+ || cancel_breakpoint (ptid_build (inf->pid, 0, thread->gdb_port)))
+ {
+ gdb_assert (thread->msg_state == DARWIN_MESSAGE);
+ darwin_send_reply (inf, thread);
+ thread->msg_state = DARWIN_RUNNING;
+ }
+ else
+ inferior_debug
+ (3, _("darwin_wait: thread %x hit a non-gdb breakpoint\n"),
+ thread->gdb_port);
+ }
+ else
+ inferior_debug (3, _("darwin_wait: unhandled pending message\n"));
}
+ return res;
+}
+
+static ptid_t
+darwin_wait_to (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status, int options)
+{
+ return darwin_wait (ptid, status);
+}
+
+static void
+darwin_stop (ptid_t t)
+{
+ struct inferior *inf = current_inferior ();
+
+ /* FIXME: handle in no_ptrace mode. */
+ gdb_assert (!inf->private->no_ptrace);
+ kill (inf->pid, SIGINT);
}
static void
@@ -624,76 +1119,79 @@ darwin_mourn_inferior (struct target_ops *ops)
unpush_target (darwin_ops);
/* Deallocate threads. */
- if (darwin_inf->threads)
+ if (inf->private->threads)
{
int k;
- thread_t t;
- for (k = 0; VEC_iterate (thread_t, darwin_inf->threads, k, t); k++)
+ darwin_thread_t *t;
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ k++)
{
- kret = mach_port_deallocate (gdb_task, t);
+ kret = mach_port_deallocate (gdb_task, t->gdb_port);
MACH_CHECK_ERROR (kret);
}
- VEC_free (thread_t, darwin_inf->threads);
- darwin_inf->threads = NULL;
+ VEC_free (darwin_thread_t, inf->private->threads);
+ inf->private->threads = NULL;
}
- kret = mach_port_request_notification (gdb_task, darwin_inf->task,
+ kret = mach_port_move_member (gdb_task,
+ inf->private->notify_port, MACH_PORT_NULL);
+ gdb_assert (kret == KERN_SUCCESS);
+
+ kret = mach_port_request_notification (gdb_task, inf->private->task,
MACH_NOTIFY_DEAD_NAME, 0,
- darwin_inf->prev_not_port,
+ MACH_PORT_NULL,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&prev);
/* This can fail if the task is dead. */
+ inferior_debug (4, "task=%x, prev=%x, notify_port=%x\n",
+ inf->private->task, prev, inf->private->notify_port);
+
if (kret == KERN_SUCCESS)
{
kret = mach_port_deallocate (gdb_task, prev);
MACH_CHECK_ERROR (kret);
}
+ kret = mach_port_destroy (gdb_task, inf->private->notify_port);
+ MACH_CHECK_ERROR (kret);
+
+
/* Deallocate saved exception ports. */
- for (i = 0; i < darwin_inf->exception_info.count; i++)
+ for (i = 0; i < inf->private->exception_info.count; i++)
{
kret = mach_port_deallocate
- (gdb_task, darwin_inf->exception_info.ports[i]);
+ (gdb_task, inf->private->exception_info.ports[i]);
MACH_CHECK_ERROR (kret);
}
- darwin_inf->exception_info.count = 0;
+ inf->private->exception_info.count = 0;
- kret = mach_port_deallocate (gdb_task, darwin_inf->task);
+ kret = mach_port_deallocate (gdb_task, inf->private->task);
MACH_CHECK_ERROR (kret);
- darwin_inf->task = 0;
- darwin_inf->pid = 0;
+ xfree (inf->private);
+ inf->private = NULL;
generic_mourn_inferior ();
}
static void
-darwin_stop_inferior (struct target_ops *ops, darwin_inferior *inf)
+darwin_reply_to_all_pending_messages (struct inferior *inf)
{
- struct target_waitstatus wstatus;
- ptid_t ptid;
- kern_return_t kret;
- int status;
- int res;
-
- gdb_assert (inf != NULL);
+ int k;
+ darwin_thread_t *t;
- kret = task_suspend (inf->task);
- MACH_CHECK_ERROR (kret);
-
- if (msg_state == GOT_MESSAGE)
- darwin_resume (darwin_ops, inferior_ptid, 0, 0);
-
- res = kill (inf->pid, SIGSTOP);
- if (res != 0)
- warning (_("cannot kill: %s\n"), safe_strerror (errno));
-
- ptid = darwin_wait (ops, inferior_ptid, &wstatus, 0);
- gdb_assert (wstatus.kind = TARGET_WAITKIND_STOPPED);
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ k++)
+ {
+ if (t->msg_state == DARWIN_MESSAGE)
+ darwin_resume_thread (inf, t, 0, 0);
+ }
}
static void
-darwin_kill_inferior (struct target_ops *ops)
+darwin_stop_inferior (struct inferior *inf)
{
struct target_waitstatus wstatus;
ptid_t ptid;
@@ -701,74 +1199,26 @@ darwin_kill_inferior (struct target_ops *ops)
int status;
int res;
- gdb_assert (darwin_inf != NULL);
-
- if (ptid_equal (inferior_ptid, null_ptid))
- return;
-
- darwin_stop_inferior (ops, darwin_inf);
-
- res = PTRACE (PT_KILL, darwin_inf->pid, 0, 0);
- gdb_assert (res == 0);
-
- if (msg_state == GOT_MESSAGE)
- {
- exc_msg.ex_type = 0;
- darwin_resume (ops, inferior_ptid, 0, 0);
- }
-
- kret = task_resume (darwin_inf->task);
- MACH_CHECK_ERROR (kret);
-
- ptid = darwin_wait (ops, inferior_ptid, &wstatus, 0);
-
- /* This double wait seems required... */
- res = waitpid (darwin_inf->pid, &status, 0);
- gdb_assert (res == darwin_inf->pid);
-
- msg_state = NO_MESSAGE;
-
- target_mourn_inferior ();
-}
-
-/* The child must synchronize with gdb: gdb must set the exception port
- before the child call PTRACE_SIGEXC. We use a pipe to achieve this.
- FIXME: is there a lighter way ? */
-static int ptrace_fds[2];
-
-static void
-darwin_ptrace_me (void)
-{
- int res;
- char c;
-
- /* Close write end point. */
- close (ptrace_fds[1]);
+ gdb_assert (inf != NULL);
- /* Wait until gdb is ready. */
- res = read (ptrace_fds[0], &c, 1);
- gdb_assert (res == 0);
- close (ptrace_fds[0]);
+ darwin_suspend_inferior (inf);
- /* Get rid of privileges. */
- setegid (getgid ());
+ darwin_reply_to_all_pending_messages (inf);
- /* Set TRACEME. */
- PTRACE (PT_TRACE_ME, 0, 0, 0);
+ if (inf->private->no_ptrace)
+ return;
- /* Redirect signals to exception port. */
- PTRACE (PT_SIGEXC, 0, 0, 0);
-}
+ res = kill (inf->pid, SIGSTOP);
+ if (res != 0)
+ warning (_("cannot kill: %s\n"), safe_strerror (errno));
-/* Dummy function to be sure fork_inferior uses fork(2) and not vfork(2). */
-static void
-darwin_pre_ptrace (void)
-{
- if (pipe (ptrace_fds) != 0)
+ /* Wait until the process is really stopped. */
+ while (1)
{
- ptrace_fds[0] = -1;
- ptrace_fds[1] = -1;
- error (_("unable to create a pipe: %s"), safe_strerror (errno));
+ ptid = darwin_wait (inferior_ptid, &wstatus);
+ if (wstatus.kind == TARGET_WAITKIND_STOPPED
+ && wstatus.value.sig == TARGET_SIGNAL_STOP)
+ break;
}
}
@@ -806,32 +1256,79 @@ darwin_restore_exception_ports (darwin_inferior *inf)
}
static void
-darwin_attach_pid (int pid)
+darwin_kill_inferior (struct target_ops *ops)
+{
+ struct inferior *inf = current_inferior ();
+ struct target_waitstatus wstatus;
+ ptid_t ptid;
+ kern_return_t kret;
+ int status;
+ int res;
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return;
+
+ gdb_assert (inf != NULL);
+
+ if (!inf->private->no_ptrace)
+ {
+ darwin_stop_inferior (inf);
+
+ res = PTRACE (PT_KILL, inf->pid, 0, 0);
+ gdb_assert (res == 0);
+
+ darwin_reply_to_all_pending_messages (inf);
+
+ darwin_resume_inferior (inf);
+
+ ptid = darwin_wait (inferior_ptid, &wstatus);
+ }
+ else
+ {
+ kret = darwin_restore_exception_ports (inf->private);
+ MACH_CHECK_ERROR (kret);
+
+ darwin_reply_to_all_pending_messages (inf);
+
+ darwin_resume_inferior (inf);
+
+ res = kill (inf->pid, 9);
+
+ ptid = darwin_wait (inferior_ptid, &wstatus);
+ }
+
+ target_mourn_inferior ();
+}
+
+static void
+darwin_attach_pid (struct inferior *inf)
{
- task_t itask;
kern_return_t kret;
mach_port_t prev_port;
int traps_expected;
+ mach_port_t prev_not;
exception_mask_t mask;
- kret = task_for_pid (gdb_task, pid, &itask);
+ inf->private = XZALLOC (darwin_inferior);
+
+ kret = task_for_pid (gdb_task, inf->pid, &inf->private->task);
if (kret != KERN_SUCCESS)
{
int status;
- struct inferior *inf = current_inferior ();
if (!inf->attach_flag)
{
- kill (pid, 9);
- waitpid (pid, &status, 0);
+ kill (inf->pid, 9);
+ waitpid (inf->pid, &status, 0);
}
error (_("Unable to find Mach task port for process-id %d: %s (0x%lx).\n"
" (please check gdb is setgid procmod)"),
- pid, mach_error_string (kret), (unsigned long) kret);
+ inf->pid, mach_error_string (kret), (unsigned long) kret);
}
- inferior_debug (2, _("inferior task: 0x%08x, pid: %d\n"), itask, pid);
+ inferior_debug (2, _("inferior task: 0x%x, pid: %d\n"),
+ inf->private->task, inf->pid);
if (darwin_ex_port == MACH_PORT_NULL)
{
@@ -851,55 +1348,98 @@ darwin_attach_pid (int pid)
kret = mach_port_move_member (gdb_task, darwin_ex_port, darwin_port_set);
gdb_assert (kret == KERN_SUCCESS);
+ }
- /* Create a port to be notified when the child task terminates. */
- kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_RECEIVE,
- &darwin_not_port);
- gdb_assert (kret == KERN_SUCCESS);
-
- kret = mach_port_insert_right (gdb_task, darwin_not_port, darwin_not_port,
- MACH_MSG_TYPE_MAKE_SEND);
- gdb_assert (kret == KERN_SUCCESS);
+ /* Create a port to be notified when the child task terminates. */
+ kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_RECEIVE,
+ &inf->private->notify_port);
+ gdb_assert (kret == KERN_SUCCESS);
- kret = mach_port_move_member (gdb_task, darwin_not_port, darwin_port_set);
- gdb_assert (kret == KERN_SUCCESS);
- }
+ kret = mach_port_move_member (gdb_task,
+ inf->private->notify_port, darwin_port_set);
+ gdb_assert (kret == KERN_SUCCESS);
- kret = mach_port_request_notification (gdb_task, itask,
+ kret = mach_port_request_notification (gdb_task, inf->private->task,
MACH_NOTIFY_DEAD_NAME, 0,
- darwin_not_port,
+ inf->private->notify_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &darwin_inf->prev_not_port);
+ &prev_not);
gdb_assert (kret == KERN_SUCCESS);
+ gdb_assert (prev_not == MACH_PORT_NULL);
- darwin_inf->task = itask;
- darwin_inf->pid = pid;
-
- kret = darwin_save_exception_ports (darwin_inf);
+ kret = darwin_save_exception_ports (inf->private);
gdb_assert (kret == KERN_SUCCESS);
/* Set exception port. */
if (enable_mach_exceptions)
mask = EXC_MASK_ALL;
else
- mask = EXC_MASK_SOFTWARE;
- kret = task_set_exception_ports
- (itask, mask, darwin_ex_port, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
+ mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
+ kret = task_set_exception_ports (inf->private->task, mask, darwin_ex_port,
+ EXCEPTION_DEFAULT, THREAD_STATE_NONE);
gdb_assert (kret == KERN_SUCCESS);
push_target (darwin_ops);
}
static void
-darwin_init_thread_list (darwin_inferior *inf)
+darwin_init_thread_list (struct inferior *inf)
{
- thread_t thread;
+ darwin_thread_t *thread;
+ ptid_t new_ptid;
darwin_check_new_threads (inf);
- gdb_assert (inf->threads && VEC_length (thread_t, inf->threads) > 0);
- thread = VEC_index (thread_t, inf->threads, 0);
- inferior_ptid = ptid_build (inf->pid, 0, thread);
+ gdb_assert (inf->private->threads
+ && VEC_length (darwin_thread_t, inf->private->threads) > 0);
+ thread = VEC_index (darwin_thread_t, inf->private->threads, 0);
+
+ /* Note: fork_inferior automatically add a thead but it uses a wrong ptid.
+ Fix up. */
+ new_ptid = ptid_build (inf->pid, 0, thread->gdb_port);
+ thread_change_ptid (inferior_ptid, new_ptid);
+ inferior_ptid = new_ptid;
+}
+
+/* The child must synchronize with gdb: gdb must set the exception port
+ before the child call PTRACE_SIGEXC. We use a pipe to achieve this.
+ FIXME: is there a lighter way ? */
+static int ptrace_fds[2];
+
+static void
+darwin_ptrace_me (void)
+{
+ int res;
+ char c;
+
+ /* Close write end point. */
+ close (ptrace_fds[1]);
+
+ /* Wait until gdb is ready. */
+ res = read (ptrace_fds[0], &c, 1);
+ gdb_assert (res == 0);
+ close (ptrace_fds[0]);
+
+ /* Get rid of privileges. */
+ setegid (getgid ());
+
+ /* Set TRACEME. */
+ PTRACE (PT_TRACE_ME, 0, 0, 0);
+
+ /* Redirect signals to exception port. */
+ PTRACE (PT_SIGEXC, 0, 0, 0);
+}
+
+/* Dummy function to be sure fork_inferior uses fork(2) and not vfork(2). */
+static void
+darwin_pre_ptrace (void)
+{
+ if (pipe (ptrace_fds) != 0)
+ {
+ ptrace_fds[0] = -1;
+ ptrace_fds[1] = -1;
+ error (_("unable to create a pipe: %s"), safe_strerror (errno));
+ }
}
static void
@@ -909,17 +1449,16 @@ darwin_ptrace_him (int pid)
kern_return_t kret;
mach_port_t prev_port;
int traps_expected;
+ struct inferior *inf = current_inferior ();
- darwin_attach_pid (pid);
+ darwin_attach_pid (inf);
/* Let's the child run. */
close (ptrace_fds[0]);
close (ptrace_fds[1]);
- /* fork_inferior automatically add a thread - but it uses a wrong tid. */
- delete_thread_silent (inferior_ptid);
- darwin_init_thread_list (darwin_inf);
-
+ darwin_init_thread_list (inf);
+
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
}
@@ -930,7 +1469,7 @@ darwin_create_inferior (struct target_ops *ops, char *exec_file,
/* Do the hard work. */
fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
darwin_pre_ptrace, NULL);
-
+
/* Return now in case of error. */
if (ptid_equal (inferior_ptid, null_ptid))
return;
@@ -947,8 +1486,7 @@ darwin_attach (struct target_ops *ops, char *args, int from_tty)
int wstatus;
int res;
struct inferior *inf;
-
- gdb_assert (msg_state == NO_MESSAGE);
+ kern_return_t kret;
if (!args)
error_no_arg (_("process-id to attach"));
@@ -959,33 +1497,40 @@ darwin_attach (struct target_ops *ops, char *args, int from_tty)
error (_("I refuse to debug myself!"));
if (from_tty)
- printf_unfiltered (_("Attaching to pid %d\n"), pid);
+ {
+ char *exec_file = get_exec_file (0);
- res = PTRACE (PT_ATTACHEXC, pid, 0, 0);
- if (res != 0)
- error (_("Unable to attach to process-id %d: %s (%d)"),
- pid, safe_strerror (errno), errno);
+ if (exec_file)
+ printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
+ target_pid_to_str (pid_to_ptid (pid)));
+ else
+ printf_unfiltered (_("Attaching to %s\n"),
+ target_pid_to_str (pid_to_ptid (pid)));
+ gdb_flush (gdb_stdout);
+ }
+
+ if (pid == 0 || kill (pid, 0) < 0)
+ error (_("Can't attach to process %d: %s (%d)"),
+ pid, safe_strerror (errno), errno);
+
+ inferior_ptid = pid_to_ptid (pid);
inf = add_inferior (pid);
inf->attach_flag = 1;
+ /* Always add a main thread. */
+ add_thread_silent (inferior_ptid);
- darwin_attach_pid (pid);
+ darwin_attach_pid (inf);
- pid2 = wait4 (pid, &wstatus, WUNTRACED, NULL);
- gdb_assert (pid2 == pid);
- inferior_debug (1, _("darwin_attach: wait4 pid=%d, status=0x%x\n"),
- pid2, wstatus);
+ darwin_suspend_inferior (inf);
-
- darwin_init_thread_list (darwin_inf);
+ darwin_init_thread_list (inf);
- darwin_check_osabi (darwin_inf, ptid_get_tid (inferior_ptid));
+ darwin_check_osabi (inf->private, ptid_get_tid (inferior_ptid));
- /* Looks strange, but the kernel doesn't stop the process...
- (Bug in Leopard ?)
- Do it manually. */
- /* FIXME: doesn't look to work with multi-threads!! */
- kill (pid, SIGSTOP);
+ gdb_assert (darwin_inf_fake_stop == NULL);
+ darwin_inf_fake_stop = inf;
+ inf->private->no_ptrace = 1;
}
/* Take a program previously attached to and detaches it.
@@ -998,39 +1543,40 @@ darwin_attach (struct target_ops *ops, char *args, int from_tty)
static void
darwin_detach (struct target_ops *ops, char *args, int from_tty)
{
+ pid_t pid = ptid_get_pid (inferior_ptid);
+ struct inferior *inf = current_inferior ();
kern_return_t kret;
int res;
+ /* Display message. */
if (from_tty)
{
char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
- printf_unfiltered (_("Detaching from program: %s, %d\n"), exec_file,
- ptid_get_pid (inferior_ptid));
+ printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
+ target_pid_to_str (pid_to_ptid (pid)));
gdb_flush (gdb_stdout);
}
- darwin_stop_inferior (ops, darwin_inf);
+ /* If ptrace() is in use, stop the process. */
+ if (!inf->private->no_ptrace)
+ darwin_stop_inferior (inf);
- kret = darwin_restore_exception_ports (darwin_inf);
+ kret = darwin_restore_exception_ports (inf->private);
MACH_CHECK_ERROR (kret);
- if (msg_state == GOT_MESSAGE)
+ if (!inf->private->no_ptrace)
{
- exc_msg.ex_type = 0;
- darwin_resume (ops, inferior_ptid, 0, 0);
+ res = PTRACE (PT_DETACH, inf->pid, 0, 0);
+ if (res != 0)
+ printf_unfiltered (_("Unable to detach from process-id %d: %s (%d)"),
+ inf->pid, safe_strerror (errno), errno);
}
- kret = task_resume (darwin_inf->task);
- gdb_assert (kret == KERN_SUCCESS);
+ darwin_reply_to_all_pending_messages (inf);
- res = PTRACE (PT_DETACH, darwin_inf->pid, 0, 0);
- if (res != 0)
- printf_unfiltered (_("Unable to detach from process-id %d: %s (%d)"),
- darwin_inf->pid, safe_strerror (errno), errno);
-
- msg_state = NO_MESSAGE;
+ darwin_resume_inferior (inf);
darwin_mourn_inferior (ops);
}
@@ -1038,19 +1584,22 @@ darwin_detach (struct target_ops *ops, char *args, int from_tty)
static void
darwin_files_info (struct target_ops *ops)
{
- gdb_assert (darwin_inf != NULL);
}
static char *
darwin_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
- static char buf[128];
+ static char buf[80];
+ long tid = ptid_get_tid (ptid);
+
+ if (tid != 0)
+ {
+ snprintf (buf, sizeof (buf), _("Thread 0x%lx of process %u"),
+ tid, ptid_get_pid (ptid));
+ return buf;
+ }
- snprintf (buf, sizeof (buf),
- _("process %d gdb-thread 0x%lx"),
- (unsigned) ptid_get_pid (ptid),
- (unsigned long) ptid_get_tid (ptid));
- return buf;
+ return normal_pid_to_str (ptid);
}
static int
@@ -1068,7 +1617,7 @@ static int
darwin_read_write_inferior (task_t task, CORE_ADDR addr,
char *rdaddr, const char *wraddr, int length)
{
- kern_return_t err;
+ kern_return_t kret;
mach_vm_address_t offset = addr & (mach_page_size - 1);
mach_vm_address_t low_address = (mach_vm_address_t) (addr - offset);
mach_vm_size_t aligned_length = (mach_vm_size_t) PAGE_ROUND (offset + length);
@@ -1078,16 +1627,17 @@ darwin_read_write_inferior (task_t task, CORE_ADDR addr,
mach_vm_address_t region_address;
mach_vm_size_t region_length;
- inferior_debug (8, _("darwin_read_write_inferior(%s, len=%d)\n"),
- core_addr_to_string (addr), length);
-
+ inferior_debug (8, _("darwin_read_write_inferior(task=%x, %s, len=%d)\n"),
+ task, core_addr_to_string (addr), length);
+
/* Get memory from inferior with page aligned addresses */
- err = mach_vm_read (task, low_address, aligned_length,
+ kret = mach_vm_read (task, low_address, aligned_length,
&copied, &copy_count);
- if (err != KERN_SUCCESS)
+ if (kret != KERN_SUCCESS)
{
- warning (_("darwin_read_write_inferior: vm_read failed: %s"),
- mach_error_string (err));
+ inferior_debug
+ (1, _("darwin_read_write_inferior: mach_vm_read failed at %s: %s"),
+ core_addr_to_string (addr), mach_error_string (kret));
return 0;
}
@@ -1105,64 +1655,85 @@ darwin_read_write_inferior (task_t task, CORE_ADDR addr,
region_address < low_address + aligned_length;
region_address += region_length, remaining_length -= region_length)
{
- vm_region_basic_info_data_64_t info;
- mach_port_t object_name;
- mach_vm_address_t old_address = region_address;
+ vm_region_submap_short_info_data_64_t info;
+ mach_vm_address_t region_start = region_address;
mach_msg_type_number_t count;
-
- region_length = remaining_length;
- count = VM_REGION_BASIC_INFO_COUNT_64;
- err = mach_vm_region (task, &region_address, &region_length,
- VM_REGION_BASIC_INFO_64,
- (vm_region_info_t) &info, &count, &object_name);
-
- if (err != KERN_SUCCESS)
+ natural_t region_depth;
+
+ region_depth = 100000;
+ count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
+ kret = mach_vm_region_recurse
+ (task, &region_start, &region_length, &region_depth,
+ (vm_region_recurse_info_t) &info, &count);
+
+ if (kret != KERN_SUCCESS)
{
- warning (_("darwin_write_inferior: mach_vm_region failed: %s"),
- mach_error_string (err));
+ inferior_debug (1, _("darwin_read_write_inferior: "
+ "mach_vm_region_recurse failed at %s: %s\n"),
+ core_addr_to_string (region_address),
+ mach_error_string (kret));
goto out;
}
+ inferior_debug
+ (9, _("darwin_read_write_inferior: "
+ "mach_vm_region_recurse addr=%s, start=%s, len=%s\n"),
+ core_addr_to_string (region_address),
+ core_addr_to_string (region_start),
+ core_addr_to_string (region_length));
+
/* Check for holes in memory */
- if (region_address > old_address)
+ if (region_start > region_address)
{
warning (_("No memory at %s (vs %s+0x%x). Nothing written"),
- core_addr_to_string (old_address),
core_addr_to_string (region_address),
+ core_addr_to_string (region_start),
(unsigned)region_length);
length = 0;
goto out;
}
+ /* Adjust the length. */
+ region_length -= (region_address - region_start);
+
if (!(info.max_protection & VM_PROT_WRITE))
{
- warning (_("Memory at address %s is unwritable. Nothing written"),
- core_addr_to_string (old_address));
- length = 0;
- goto out;
+ kret = mach_vm_protect
+ (task, region_address, region_length,
+ TRUE, info.max_protection | VM_PROT_WRITE | VM_PROT_COPY);
+ if (kret != KERN_SUCCESS)
+ {
+ warning (_("darwin_read_write_inf: "
+ "mach_vm_protect max failed at %s: %s"),
+ core_addr_to_string (region_address),
+ mach_error_string (kret));
+ length = 0;
+ goto out;
+ }
}
if (!(info.protection & VM_PROT_WRITE))
{
- err = mach_vm_protect (task, old_address, region_length,
+ kret = mach_vm_protect (task, region_address, region_length,
FALSE, info.protection | VM_PROT_WRITE);
- if (err != KERN_SUCCESS)
+ if (kret != KERN_SUCCESS)
{
- warning
- (_("darwin_read_write_inferior: mach_vm_protect failed: %s"),
- mach_error_string (err));
+ warning (_("darwin_read_write_inf: "
+ "mach_vm_protect failed at %s (len=0x%lx): %s"),
+ core_addr_to_string (region_address),
+ (unsigned long)region_length, mach_error_string (kret));
length = 0;
goto out;
}
}
}
- err = mach_vm_write (task, low_address, copied, aligned_length);
+ kret = mach_vm_write (task, low_address, copied, aligned_length);
- if (err != KERN_SUCCESS)
+ if (kret != KERN_SUCCESS)
{
warning (_("darwin_read_write_inferior: mach_vm_write failed: %s"),
- mach_error_string (err));
+ mach_error_string (kret));
length = 0;
}
out:
@@ -1177,7 +1748,8 @@ static int
darwin_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
struct mem_attrib *attrib, struct target_ops *target)
{
- task_t task = darwin_inf->task;
+ struct inferior *inf = current_inferior ();
+ task_t task = inf->private->task;
if (task == MACH_PORT_NULL)
return 0;
@@ -1197,15 +1769,16 @@ darwin_xfer_partial (struct target_ops *ops,
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len)
{
- inferior_debug (8, _("darwin_xfer_partial(%s, %d, rbuf=%s, wbuf=%s)\n"),
- core_addr_to_string (offset), (int)len,
- host_address_to_string (readbuf),
- host_address_to_string (writebuf));
+ struct inferior *inf = current_inferior ();
+
+ inferior_debug
+ (8, _("darwin_xfer_partial(%s, %d, rbuf=%p, wbuf=%p) pid=%u\n"),
+ core_addr_to_string (offset), (int)len, readbuf, writebuf, inf->pid);
if (object != TARGET_OBJECT_MEMORY)
return -1;
- return darwin_read_write_inferior (darwin_inf->task, offset,
+ return darwin_read_write_inferior (inf->private->task, offset,
readbuf, writebuf, len);
}
@@ -1213,8 +1786,9 @@ static void
set_enable_mach_exceptions (char *args, int from_tty,
struct cmd_list_element *c)
{
- if (darwin_inf && darwin_inf->task != TASK_NULL)
+ if (!ptid_equal (inferior_ptid, null_ptid))
{
+ struct inferior *inf = current_inferior ();
exception_mask_t mask;
kern_return_t kret;
@@ -1222,22 +1796,109 @@ set_enable_mach_exceptions (char *args, int from_tty,
mask = EXC_MASK_ALL;
else
{
- darwin_restore_exception_ports (darwin_inf);
- mask = EXC_MASK_SOFTWARE;
+ darwin_restore_exception_ports (inf->private);
+ mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
}
- kret = task_set_exception_ports (darwin_inf->task, mask, darwin_ex_port,
+ kret = task_set_exception_ports (inf->private->task, mask, darwin_ex_port,
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
MACH_CHECK_ERROR (kret);
}
}
+static char *
+darwin_pid_to_exec_file (int pid)
+{
+ char *path;
+ int res;
+
+ path = xmalloc (MAXPATHLEN);
+ make_cleanup (xfree, path);
+
+ res = proc_pidinfo (pid, PROC_PIDPATHINFO, 0, path, MAXPATHLEN);
+ if (res >= 0)
+ return path;
+ else
+ return NULL;
+}
+
+static ptid_t
+darwin_get_ada_task_ptid (long lwp, long thread)
+{
+ int i;
+ darwin_thread_t *t;
+ int k;
+ struct inferior *inf = current_inferior ();
+ kern_return_t kret;
+ mach_port_name_array_t names;
+ mach_msg_type_number_t names_count;
+ mach_port_type_array_t types;
+ mach_msg_type_number_t types_count;
+ long res = 0;
+
+ /* First linear search. */
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ k++)
+ if (t->inf_port == lwp)
+ return ptid_build (ptid_get_pid (inferior_ptid), 0, t->gdb_port);
+
+ /* Maybe the port was never extract. Do it now. */
+
+ /* First get inferior port names. */
+ kret = mach_port_names (inf->private->task, &names, &names_count, &types,
+ &types_count);
+ MACH_CHECK_ERROR (kret);
+ if (kret != KERN_SUCCESS)
+ return null_ptid;
+
+ /* For each name, copy the right in the gdb space and then compare with
+ our view of the inferior threads. We don't forget to deallocate the
+ right. */
+ for (i = 0; i < names_count; i++)
+ {
+ mach_port_t local_name;
+ mach_msg_type_name_t local_type;
+
+ /* We just need to know the corresponding name in gdb name space.
+ So extract and deallocate the right. */
+ kret = mach_port_extract_right (inf->private->task, names[i],
+ MACH_MSG_TYPE_COPY_SEND,
+ &local_name, &local_type);
+ if (kret != KERN_SUCCESS)
+ continue;
+ mach_port_deallocate (gdb_task, local_name);
+
+ for (k = 0;
+ VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ k++)
+ if (t->gdb_port == local_name)
+ {
+ t->inf_port = names[i];
+ if (names[i] == lwp)
+ res = t->gdb_port;
+ }
+ }
+
+ vm_deallocate (gdb_task, (vm_address_t) names,
+ names_count * sizeof (mach_port_t));
+
+ if (res)
+ return ptid_build (ptid_get_pid (inferior_ptid), 0, res);
+ else
+ return null_ptid;
+}
+
+static int
+darwin_supports_multi_process (void)
+{
+ return 1;
+}
+
void
-_initialize_darwin_inferior ()
+_initialize_darwin_inferior (void)
{
kern_return_t kret;
- gdb_assert (darwin_inf == NULL);
-
gdb_task = mach_task_self ();
darwin_host_self = mach_host_self ();
@@ -1249,11 +1910,6 @@ _initialize_darwin_inferior ()
MACH_CHECK_ERROR (kret);
}
- darwin_inf = (struct darwin_inferior *)
- xmalloc (sizeof (struct darwin_inferior));
-
- memset (darwin_inf, 0, sizeof (*darwin_inf));
-
darwin_ops = inf_child_target ();
darwin_ops->to_shortname = "darwin-child";
@@ -1265,17 +1921,20 @@ _initialize_darwin_inferior ()
darwin_ops->to_attach_no_wait = 0;
darwin_ops->to_detach = darwin_detach;
darwin_ops->to_files_info = darwin_files_info;
- darwin_ops->to_wait = darwin_wait;
+ darwin_ops->to_wait = darwin_wait_to;
darwin_ops->to_mourn_inferior = darwin_mourn_inferior;
darwin_ops->to_kill = darwin_kill_inferior;
darwin_ops->to_stop = darwin_stop;
- darwin_ops->to_resume = darwin_resume;
+ darwin_ops->to_resume = darwin_resume_to;
darwin_ops->to_thread_alive = darwin_thread_alive;
darwin_ops->to_pid_to_str = darwin_pid_to_str;
+ darwin_ops->to_pid_to_exec_file = darwin_pid_to_exec_file;
darwin_ops->to_load = NULL;
darwin_ops->deprecated_xfer_memory = darwin_xfer_memory;
darwin_ops->to_xfer_partial = darwin_xfer_partial;
- darwin_ops->to_has_thread_control = tc_schedlock /*| tc_switch */;
+ darwin_ops->to_supports_multi_process = darwin_supports_multi_process;
+ darwin_ops->to_get_ada_task_ptid = darwin_get_ada_task_ptid;
+ /* darwin_ops->to_has_thread_control = tc_schedlock | tc_switch */;
darwin_complete_target (darwin_ops);
diff --git a/gdb/darwin-nat.h b/gdb/darwin-nat.h
index 43a1522..3d216cc 100644
--- a/gdb/darwin-nat.h
+++ b/gdb/darwin-nat.h
@@ -22,9 +22,6 @@
#include <mach/mach.h>
#include "gdb_assert.h"
-/* Define the threads vector type. */
-DEF_VEC_I (thread_t);
-
/* Describe the mach exception handling state for a task. This state is saved
before being changed and restored when a process is detached.
For more information on these fields see task_get_exception_ports manual
@@ -48,35 +45,83 @@ struct darwin_exception_info
};
typedef struct darwin_exception_info darwin_exception_info;
-/* Describe an inferior. */
-struct darwin_inferior
+struct darwin_exception_msg
{
- /* Inferior PID. */
- int pid;
+ mach_msg_header_t header;
+
+ /* Thread and task taking the exception. */
+ mach_port_t thread_port;
+ mach_port_t task_port;
+
+ /* Type of the exception. */
+ exception_type_t ex_type;
+
+ /* Machine dependent details. */
+ mach_msg_type_number_t data_count;
+ integer_t ex_data[2];
+};
+
+enum darwin_msg_state { DARWIN_RUNNING, DARWIN_STOPPED, DARWIN_MESSAGE };
+
+struct private_thread_info
+{
+ /* The thread port from a GDB point of view. */
+ thread_t gdb_port;
+
+ /* The thread port from the inferior point of view. Not to be used inside
+ gdb except for get_ada_task_ptid. */
+ thread_t inf_port;
+
+ /* Current message state.
+ If the kernel has sent a message it expects a reply and the inferior
+ can't be killed before. */
+ enum darwin_msg_state msg_state;
+
+ /* True if this thread is single-stepped. */
+ unsigned char single_step;
+ /* True if a signal was manually sent to the thread. */
+ unsigned char signaled;
+
+ /* The last exception received. */
+ struct darwin_exception_msg event;
+};
+typedef struct private_thread_info darwin_thread_t;
+
+/* Define the threads vector type. */
+DEF_VEC_O (darwin_thread_t);
+
+
+/* Describe an inferior. */
+struct private_inferior
+{
/* Corresponding task port. */
task_t task;
- /* Previous port for request notification on task. */
- mach_port_t prev_not_port;
+ /* Port which will receive the dead-name notification for the task port.
+ This is used to detect the death of the task. */
+ mach_port_t notify_port;
/* Initial exception handling. */
darwin_exception_info exception_info;
+ /* Number of messages that have been received but not yet replied. */
+ unsigned int pending_messages;
+
+ /* Set if inferior is not controlled by ptrace(2) but through Mach. */
+ unsigned char no_ptrace;
+
+ /* True if this task is suspended. */
+ unsigned char suspended;
+
/* Sorted vector of known threads. */
- VEC(thread_t) *threads;
+ VEC(darwin_thread_t) *threads;
};
-typedef struct darwin_inferior darwin_inferior;
-
-/* Current inferior. */
-extern darwin_inferior *darwin_inf;
+typedef struct private_inferior darwin_inferior;
/* Exception port. */
extern mach_port_t darwin_ex_port;
-/* Notification port. */
-extern mach_port_t darwin_not_port;
-
/* Port set. */
extern mach_port_t darwin_port_set;
diff --git a/gdb/machoread.c b/gdb/machoread.c
index 78daa75..5f9a0fe 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -103,7 +103,6 @@ macho_symtab_read (struct objfile *objfile,
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
long storage_needed;
- asymbol *sym;
long i, j;
CORE_ADDR offset;
enum minimal_symbol_type ms_type;
@@ -114,15 +113,16 @@ macho_symtab_read (struct objfile *objfile,
for (i = 0; i < number_of_symbols; i++)
{
- sym = symbol_table[i];
+ asymbol *sym = symbol_table[i];
+ bfd_mach_o_asymbol *mach_o_sym = (bfd_mach_o_asymbol *)sym;
+
offset = ANOFFSET (objfile->section_offsets, sym->section->index);
if (sym->flags & BSF_DEBUGGING)
{
- unsigned char type = BFD_MACH_O_SYM_NTYPE(sym);
bfd_vma addr;
- switch (type)
+ switch (mach_o_sym->n_type)
{
case N_SO:
if ((sym->name == NULL || sym->name[0] == 0)