Ticket #54217: patch-gdb-darwin-nat.c.diff

File patch-gdb-darwin-nat.c.diff, 16.5 KB (added by plinss (Peter Linss), 7 years ago)

Patch to gdb (slight edit to correct path)

  • gdb/darwin-nat.c

    From d94e8653463e33dd3e10ce4001217e5d929d0883 Mon Sep 17 00:00:00 2001
    From: Tristan Gingold <gingold@adacore.com>
    Date: Wed, 9 Nov 2016 10:25:00 +0100
    Subject: [PATCH 1/1] darwin-nat.c: handle Darwin 16 (aka Sierra).
    
    Support message from new task and dead name notification on task of an
    existing process.
    With Sierra, exec(2) terminate the current task and creates a new one.
    'set startup-with-shell off' must still be used on Darwin 16.
    
    2016-11-09  Tristan Gingold  <gingold@adacore.com>
    
    	* darwin-nat.c (find_inferior_task_it): Fix indentation.
    	(find_inferior_notify_it): Remove.
    	(find_inferior_pid_it): New function.
    	(darwin_find_inferior_by_notify): Remove.
    	(darwin_find_inferior_by_pid): New function.
    	(darwin_find_new_inferior): New function.
    	(darwin_check_message_ndr): New function from
    	darwin_decode_exception_message.
    	(darwin_decode_exception_message): Call darwin_check_message_ndr.
    	Handle SIGTRAP addressed to an unknown task (when a task spawned).
    	(darwin_decode_notify_message): New function.
    	(darwin_decode_message): Handle unknown task.
    	(darwin_deallocate_threads): New function from darwin_mourn_inferior.
    	(darwin_mourn_inferior): Use darwin_deallocate_threads and
    	darwin_deallocate_exception_ports.
    	(darwin_deallocate_exception_ports): New function from
    	darwin_mourn_inferior.
    	(darwin_setup_exceptions): New function from darwin_attach_pid.
    	(darwin_setup_request_notification): Likewise.
    	(darwin_attach_pid): Call darwin_setup_request_notification and
    	darwin_setup_request_notification.
    ---
     gdb/darwin-nat.c | 342 +++++++++++++++++++++++++++++++++++++++++++------------
     1 file changed, 267 insertions(+), 75 deletions(-)
    
    diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
    index 590c2ad..4fc1685 100644
    static int darwin_thread_alive (struct target_ops *ops, ptid_t tpid); 
    114114static void darwin_encode_reply (mig_reply_error_t *reply,
    115115                                 mach_msg_header_t *hdr, integer_t code);
    116116
     117static void darwin_setup_request_notification (struct inferior *inf);
     118static void darwin_deallocate_exception_ports (darwin_inferior *inf);
     119static void darwin_setup_exceptions (struct inferior *inf);
     120static void darwin_deallocate_threads (struct inferior *inf);
     121
    117122/* Target operations for Darwin.  */
    118123static struct target_ops *darwin_ops;
    119124
    darwin_check_new_threads (struct inferior *inf) 
    320325        }
    321326    }
    322327
     328  /* Full handling: detect new threads, remove dead threads.  */
    323329  thread_vec = VEC_alloc (darwin_thread_t, new_nbr);
    324330
    325331  for (new_ix = 0, old_ix = 0; new_ix < new_nbr || old_ix < old_nbr;)
    darwin_check_new_threads (struct inferior *inf) 
    365371          pti->gdb_port = new_id;
    366372          pti->msg_state = DARWIN_RUNNING;
    367373
    368           /* Add a new thread unless this is the first one ever met.  */
    369           if (!(old_nbr == 0 && new_ix == 0))
    370             tp = add_thread_with_info (ptid_build (inf->pid, 0, new_id), pti);
    371           else
     374          if (old_nbr == 0 && new_ix == 0)
    372375            {
     376              /* A ptid is create when the inferior is started (see
     377                 fork-child.c) with lwp=tid=0.  This ptid will be renamed
     378                 later by darwin_init_thread_list ().  */
    373379              tp = find_thread_ptid (ptid_build (inf->pid, 0, 0));
    374380              gdb_assert (tp);
     381              gdb_assert (tp->priv == NULL);
    375382              tp->priv = pti;
    376383            }
     384          else
     385            {
     386              /* Add the new thread.  */
     387              tp = add_thread_with_info
     388                (ptid_build (inf->pid, 0, new_id), pti);
     389            }
    377390          VEC_safe_push (darwin_thread_t, thread_vec, pti);
    378391          new_ix++;
    379392          continue;
    darwin_check_new_threads (struct inferior *inf) 
    403416static int
    404417find_inferior_task_it (struct inferior *inf, void *port_ptr)
    405418{
    406   return inf->priv->task == *(task_t*)port_ptr;
     419  return inf->priv->task == *(task_t *)port_ptr;
    407420}
    408421
    409422static int
    410 find_inferior_notify_it (struct inferior *inf, void *port_ptr)
     423find_inferior_pid_it (struct inferior *inf, void *pid_ptr)
    411424{
    412   return inf->priv->notify_port == *(task_t*)port_ptr;
     425  return inf->pid == *(int *)pid_ptr;
    413426}
    414427
    415428/* Return an inferior by task port.  */
    darwin_find_inferior_by_task (task_t port) 
    419432  return iterate_over_inferiors (&find_inferior_task_it, &port);
    420433}
    421434
    422 /* Return an inferior by notification port.  */
     435/* Return an inferior by pid port.  */
    423436static struct inferior *
    424 darwin_find_inferior_by_notify (mach_port_t port)
     437darwin_find_inferior_by_pid (int pid)
    425438{
    426   return iterate_over_inferiors (&find_inferior_notify_it, &port);
     439  return iterate_over_inferiors (&find_inferior_pid_it, &pid);
    427440}
    428441
    429442/* Return a thread by port.  */
    darwin_dump_message (mach_msg_header_t *hdr, int disp_body) 
    557570    }
    558571}
    559572
     573/* Adjust inferior data when a new task was created.  */
     574
     575static struct inferior *
     576darwin_find_new_inferior (task_t task_port, thread_t thread_port)
     577{
     578  int task_pid;
     579  struct inferior *inf;
     580  kern_return_t kret;
     581  mach_port_t prev;
     582
     583  /* Find the corresponding pid.  */
     584  kret = pid_for_task (task_port, &task_pid);
     585  if (kret != KERN_SUCCESS)
     586    {
     587      MACH_CHECK_ERROR (kret);
     588      return NULL;
     589    }
     590
     591  /* Find the inferior for this pid.  */
     592  inf = darwin_find_inferior_by_pid (task_pid);
     593  if (inf == NULL)
     594    return NULL;
     595
     596  /* Deallocate saved exception ports.  */
     597  darwin_deallocate_exception_ports (inf->priv);
     598
     599  /* No need to remove dead_name notification, but still...  */
     600  kret = mach_port_request_notification (gdb_task, inf->priv->task,
     601                                         MACH_NOTIFY_DEAD_NAME, 0,
     602                                         MACH_PORT_NULL,
     603                                         MACH_MSG_TYPE_MAKE_SEND_ONCE,
     604                                         &prev);
     605  if (kret != KERN_INVALID_ARGUMENT)
     606    MACH_CHECK_ERROR (kret);
     607
     608  /* Replace old task port.  */
     609  kret = mach_port_deallocate (gdb_task, inf->priv->task);
     610  MACH_CHECK_ERROR (kret);
     611  inf->priv->task = task_port;
     612
     613  darwin_setup_request_notification (inf);
     614  darwin_setup_exceptions (inf);
     615
     616  return inf;
     617}
     618
     619/* Check data representation.  */
     620
     621static int
     622darwin_check_message_ndr (NDR_record_t *ndr)
     623{
     624  if (ndr->mig_vers != NDR_PROTOCOL_2_0
     625      || ndr->if_vers != NDR_PROTOCOL_2_0
     626      || ndr->mig_encoding != NDR_record.mig_encoding
     627      || ndr->int_rep != NDR_record.int_rep
     628      || ndr->char_rep != NDR_record.char_rep
     629      || ndr->float_rep != NDR_record.float_rep)
     630    return -1;
     631  return 0;
     632}
     633
     634/* Decode an exception message.  */
     635
    560636static int
    561637darwin_decode_exception_message (mach_msg_header_t *hdr,
    562638                                 struct inferior **pinf,
    darwin_decode_exception_message (mach_msg_header_t *hdr, 
    593669
    594670  /* Check data representation.  */
    595671  ndr = (NDR_record_t *)(desc + 2);
    596   if (ndr->mig_vers != NDR_PROTOCOL_2_0
    597       || ndr->if_vers != NDR_PROTOCOL_2_0
    598       || ndr->mig_encoding != NDR_record.mig_encoding
    599       || ndr->int_rep != NDR_record.int_rep
    600       || ndr->char_rep != NDR_record.char_rep
    601       || ndr->float_rep != NDR_record.float_rep)
     672  if (darwin_check_message_ndr (ndr) != 0)
    602673    return -1;
    603674
    604675  /* Ok, the hard work.  */
    darwin_decode_exception_message (mach_msg_header_t *hdr, 
    607678  task_port = desc[1].name;
    608679  thread_port = desc[0].name;
    609680
    610   /* We got new rights to the task, get rid of it.  Do not get rid of thread
    611      right, as we will need it to find the thread.  */
    612   kret = mach_port_deallocate (mach_task_self (), task_port);
    613   MACH_CHECK_ERROR (kret);
    614 
    615681  /* Find process by port.  */
    616682  inf = darwin_find_inferior_by_task (task_port);
    617683  *pinf = inf;
     684
     685  if (inf == NULL && data[0] == EXC_SOFTWARE && data[1] == 2
     686      && data[2] == EXC_SOFT_SIGNAL && data[3] == SIGTRAP)
     687    {
     688      /* Not a known inferior, but a sigtrap.  This happens on darwin 16.1.0,
     689         as a new Mach task is created when a process exec.  */
     690      inf = darwin_find_new_inferior (task_port, thread_port);
     691      *pinf = inf;
     692
     693      if (inf == NULL)
     694        {
     695          /* Deallocate task_port, unless it was saved.  */
     696          kret = mach_port_deallocate (mach_task_self (), task_port);
     697          MACH_CHECK_ERROR (kret);
     698        }
     699    }
     700  else
     701    {
     702      /* We got new rights to the task, get rid of it.  Do not get rid of
     703         thread right, as we will need it to find the thread.  */
     704      kret = mach_port_deallocate (mach_task_self (), task_port);
     705      MACH_CHECK_ERROR (kret);
     706    }
     707
    618708  if (inf == NULL)
    619709    {
    620710      /* Not a known inferior.  This could happen if the child fork, as
    darwin_decode_exception_message (mach_msg_header_t *hdr, 
    623713      kern_return_t kret;
    624714      mig_reply_error_t reply;
    625715
     716      inferior_debug
     717        (4, _("darwin_decode_exception_message: unknown task 0x%x\n"),
     718         task_port);
     719
    626720      /* Free thread port (we don't know it).  */
    627721      kret = mach_port_deallocate (mach_task_self (), thread_port);
    628722      MACH_CHECK_ERROR (kret);
    darwin_decode_exception_message (mach_msg_header_t *hdr, 
    676770  return 0;
    677771}
    678772
     773/* Decode dead_name notify message.  */
     774
     775static int
     776darwin_decode_notify_message (mach_msg_header_t *hdr, struct inferior **pinf)
     777{
     778  NDR_record_t *ndr = (NDR_record_t *)(hdr + 1);
     779  integer_t *data = (integer_t *)(ndr + 1);
     780  struct inferior *inf;
     781  darwin_thread_t *thread;
     782  task_t task_port;
     783  thread_t thread_port;
     784  kern_return_t kret;
     785  int i;
     786
     787  /* Check message header.  */
     788  if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
     789    return -1;
     790
     791  /* Check descriptors.  */
     792  if (hdr->msgh_size < (sizeof (*hdr) + sizeof (*ndr) + sizeof (integer_t)))
     793    return -2;
     794
     795  /* Check data representation.  */
     796  if (darwin_check_message_ndr (ndr) != 0)
     797    return -3;
     798
     799  task_port = data[0];
     800
     801  /* Find process by port.  */
     802  inf = darwin_find_inferior_by_task (task_port);
     803  *pinf = inf;
     804
     805  /* Check message destination.  */
     806  if (inf != NULL && hdr->msgh_local_port != inf->priv->notify_port)
     807    return -4;
     808
     809  return 0;
     810}
     811
    679812static void
    680813darwin_encode_reply (mig_reply_error_t *reply, mach_msg_header_t *hdr,
    681814                     integer_t code)
    darwin_decode_message (mach_msg_header_t *hdr, 
    9861119  else if (hdr->msgh_id == 0x48)
    9871120    {
    9881121      /* MACH_NOTIFY_DEAD_NAME: notification for exit.  */
     1122      int res;
     1123
     1124      res = darwin_decode_notify_message (hdr, &inf);
     1125
     1126      if (res < 0)
     1127        {
     1128          /* Should not happen...  */
     1129          printf_unfiltered
     1130            (_("darwin_wait: ill-formatted message (id=0x%x, res=%d)\n"),
     1131             hdr->msgh_id, res);
     1132        }
     1133
    9891134      *pinf = NULL;
    9901135      *pthread = NULL;
    9911136
    992       inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
     1137      if (res < 0 || inf == NULL)
     1138        {
     1139          status->kind = TARGET_WAITKIND_IGNORE;
     1140          return minus_one_ptid;
     1141        }
     1142
    9931143      if (inf != NULL)
    9941144        {
    9951145          if (!inf->priv->no_ptrace)
    darwin_decode_message (mach_msg_header_t *hdr, 
    10221172              /* Looks necessary on Leopard and harmless...  */
    10231173              wait4 (inf->pid, &wstatus, 0, NULL);
    10241174
    1025               return ptid_build (inf->pid, 0, 0);
     1175              inferior_ptid = ptid_build (inf->pid, 0, 0);
     1176              return inferior_ptid;
    10261177            }
    10271178          else
    10281179            {
    darwin_interrupt (struct target_ops *self, ptid_t t) 
    12041355  kill (inf->pid, SIGINT);
    12051356}
    12061357
     1358/* Deallocate threads port and vector.  */
     1359
    12071360static void
    1208 darwin_mourn_inferior (struct target_ops *ops)
     1361darwin_deallocate_threads (struct inferior *inf)
    12091362{
    1210   struct inferior *inf = current_inferior ();
    1211   kern_return_t kret;
    1212   mach_port_t prev;
    1213   int i;
    1214 
    1215   /* Deallocate threads.  */
    12161363  if (inf->priv->threads)
    12171364    {
     1365      kern_return_t kret;
    12181366      int k;
    12191367      darwin_thread_t *t;
    12201368      for (k = 0;
    darwin_mourn_inferior (struct target_ops *ops) 
    12271375      VEC_free (darwin_thread_t, inf->priv->threads);
    12281376      inf->priv->threads = NULL;
    12291377    }
     1378}
    12301379
     1380static void
     1381darwin_mourn_inferior (struct target_ops *ops)
     1382{
     1383  struct inferior *inf = current_inferior ();
     1384  kern_return_t kret;
     1385  mach_port_t prev;
     1386  int i;
     1387
     1388  /* Deallocate threads.  */
     1389  darwin_deallocate_threads (inf);
     1390
     1391  /* Remove notify_port from darwin_port_set.  */
    12311392  kret = mach_port_move_member (gdb_task,
    12321393                                inf->priv->notify_port, MACH_PORT_NULL);
    12331394  MACH_CHECK_ERROR (kret);
    12341395
     1396  /* Remove task port dead_name notification.  */
    12351397  kret = mach_port_request_notification (gdb_task, inf->priv->task,
    12361398                                         MACH_NOTIFY_DEAD_NAME, 0,
    12371399                                         MACH_PORT_NULL,
    darwin_mourn_inferior (struct target_ops *ops) 
    12471409      MACH_CHECK_ERROR (kret);
    12481410    }
    12491411
     1412  /* Destroy notify_port.  */
    12501413  kret = mach_port_destroy (gdb_task, inf->priv->notify_port);
    12511414  MACH_CHECK_ERROR (kret);
    12521415
    1253 
    12541416  /* Deallocate saved exception ports.  */
    1255   for (i = 0; i < inf->priv->exception_info.count; i++)
    1256     {
    1257       kret = mach_port_deallocate
    1258         (gdb_task, inf->priv->exception_info.ports[i]);
    1259       MACH_CHECK_ERROR (kret);
    1260     }
    1261   inf->priv->exception_info.count = 0;
     1417  darwin_deallocate_exception_ports (inf->priv);
    12621418
     1419  /* Deallocate task port.  */
    12631420  kret = mach_port_deallocate (gdb_task, inf->priv->task);
    12641421  MACH_CHECK_ERROR (kret);
    12651422
    darwin_restore_exception_ports (darwin_inferior *inf) 
    13491506  return KERN_SUCCESS;
    13501507}
    13511508
     1509/* Deallocate saved exception ports.  */
     1510
     1511static void
     1512darwin_deallocate_exception_ports (darwin_inferior *inf)
     1513{
     1514  int i;
     1515  kern_return_t kret;
     1516
     1517  for (i = 0; i < inf->exception_info.count; i++)
     1518    {
     1519      kret = mach_port_deallocate (gdb_task, inf->exception_info.ports[i]);
     1520      MACH_CHECK_ERROR (kret);
     1521    }
     1522  inf->exception_info.count = 0;
     1523}
     1524
     1525static void
     1526darwin_setup_exceptions (struct inferior *inf)
     1527{
     1528  kern_return_t kret;
     1529  int traps_expected;
     1530  exception_mask_t mask;
     1531
     1532  kret = darwin_save_exception_ports (inf->priv);
     1533  if (kret != KERN_SUCCESS)
     1534    error (_("Unable to save exception ports, task_get_exception_ports"
     1535             "returned: %d"),
     1536           kret);
     1537
     1538  /* Set exception port.  */
     1539  if (enable_mach_exceptions)
     1540    mask = EXC_MASK_ALL;
     1541  else
     1542    mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
     1543  kret = task_set_exception_ports (inf->priv->task, mask, darwin_ex_port,
     1544                                   EXCEPTION_DEFAULT, THREAD_STATE_NONE);
     1545  if (kret != KERN_SUCCESS)
     1546    error (_("Unable to set exception ports, task_set_exception_ports"
     1547             "returned: %d"),
     1548           kret);
     1549}
     1550
    13521551static void
    13531552darwin_kill_inferior (struct target_ops *ops)
    13541553{
    darwin_kill_inferior (struct target_ops *ops) 
    13851584}
    13861585
    13871586static void
     1587darwin_setup_request_notification (struct inferior *inf)
     1588{
     1589  kern_return_t kret;
     1590  mach_port_t prev_not;
     1591
     1592  kret = mach_port_request_notification (gdb_task, inf->priv->task,
     1593                                         MACH_NOTIFY_DEAD_NAME, 0,
     1594                                         inf->priv->notify_port,
     1595                                         MACH_MSG_TYPE_MAKE_SEND_ONCE,
     1596                                         &prev_not);
     1597  if (kret != KERN_SUCCESS)
     1598    error (_("Termination notification request failed, "
     1599             "mach_port_request_notification\n"
     1600             "returned: %d"),
     1601           kret);
     1602  if (prev_not != MACH_PORT_NULL)
     1603    {
     1604      /* This is unexpected, as there should not be any previously
     1605         registered notification request.  But this is not a fatal
     1606         issue, so just emit a warning.  */
     1607      warning (_("\
     1608A task termination request was registered before the debugger registered\n\
     1609its own.  This is unexpected, but should otherwise not have any actual\n\
     1610impact on the debugging session."));
     1611    }
     1612}
     1613
     1614static void
    13881615darwin_attach_pid (struct inferior *inf)
    13891616{
    13901617  kern_return_t kret;
    darwin_attach_pid (struct inferior *inf) 
    14631690             "returned: %d"),
    14641691           kret);
    14651692
    1466   kret = mach_port_request_notification (gdb_task, inf->priv->task,
    1467                                          MACH_NOTIFY_DEAD_NAME, 0,
    1468                                          inf->priv->notify_port,
    1469                                          MACH_MSG_TYPE_MAKE_SEND_ONCE,
    1470                                          &prev_not);
    1471   if (kret != KERN_SUCCESS)
    1472     error (_("Termination notification request failed, "
    1473              "mach_port_request_notification\n"
    1474              "returned: %d"),
    1475            kret);
    1476   if (prev_not != MACH_PORT_NULL)
    1477     {
    1478       /* This is unexpected, as there should not be any previously
    1479          registered notification request.  But this is not a fatal
    1480          issue, so just emit a warning.  */
    1481       warning (_("\
    1482 A task termination request was registered before the debugger registered\n\
    1483 its own.  This is unexpected, but should otherwise not have any actual\n\
    1484 impact on the debugging session."));
    1485     }
     1693  darwin_setup_request_notification (inf);
    14861694
    1487   kret = darwin_save_exception_ports (inf->priv);
    1488   if (kret != KERN_SUCCESS)
    1489     error (_("Unable to save exception ports, task_get_exception_ports"
    1490              "returned: %d"),
    1491            kret);
    1492 
    1493   /* Set exception port.  */
    1494   if (enable_mach_exceptions)
    1495     mask = EXC_MASK_ALL;
    1496   else
    1497     mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
    1498   kret = task_set_exception_ports (inf->priv->task, mask, darwin_ex_port,
    1499                                    EXCEPTION_DEFAULT, THREAD_STATE_NONE);
    1500   if (kret != KERN_SUCCESS)
    1501     error (_("Unable to set exception ports, task_set_exception_ports"
    1502              "returned: %d"),
    1503            kret);
     1695  darwin_setup_exceptions (inf);
    15041696
    15051697  if (!target_is_pushed (darwin_ops))
    15061698    push_target (darwin_ops);