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) |
---|
-
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); 114 114 static void darwin_encode_reply (mig_reply_error_t *reply, 115 115 mach_msg_header_t *hdr, integer_t code); 116 116 117 static void darwin_setup_request_notification (struct inferior *inf); 118 static void darwin_deallocate_exception_ports (darwin_inferior *inf); 119 static void darwin_setup_exceptions (struct inferior *inf); 120 static void darwin_deallocate_threads (struct inferior *inf); 121 117 122 /* Target operations for Darwin. */ 118 123 static struct target_ops *darwin_ops; 119 124 … … darwin_check_new_threads (struct inferior *inf) 320 325 } 321 326 } 322 327 328 /* Full handling: detect new threads, remove dead threads. */ 323 329 thread_vec = VEC_alloc (darwin_thread_t, new_nbr); 324 330 325 331 for (new_ix = 0, old_ix = 0; new_ix < new_nbr || old_ix < old_nbr;) … … darwin_check_new_threads (struct inferior *inf) 365 371 pti->gdb_port = new_id; 366 372 pti->msg_state = DARWIN_RUNNING; 367 373 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) 372 375 { 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 (). */ 373 379 tp = find_thread_ptid (ptid_build (inf->pid, 0, 0)); 374 380 gdb_assert (tp); 381 gdb_assert (tp->priv == NULL); 375 382 tp->priv = pti; 376 383 } 384 else 385 { 386 /* Add the new thread. */ 387 tp = add_thread_with_info 388 (ptid_build (inf->pid, 0, new_id), pti); 389 } 377 390 VEC_safe_push (darwin_thread_t, thread_vec, pti); 378 391 new_ix++; 379 392 continue; … … darwin_check_new_threads (struct inferior *inf) 403 416 static int 404 417 find_inferior_task_it (struct inferior *inf, void *port_ptr) 405 418 { 406 return inf->priv->task == *(task_t *)port_ptr;419 return inf->priv->task == *(task_t *)port_ptr; 407 420 } 408 421 409 422 static int 410 find_inferior_ notify_it (struct inferior *inf, void *port_ptr)423 find_inferior_pid_it (struct inferior *inf, void *pid_ptr) 411 424 { 412 return inf->p riv->notify_port == *(task_t*)port_ptr;425 return inf->pid == *(int *)pid_ptr; 413 426 } 414 427 415 428 /* Return an inferior by task port. */ … … darwin_find_inferior_by_task (task_t port) 419 432 return iterate_over_inferiors (&find_inferior_task_it, &port); 420 433 } 421 434 422 /* Return an inferior by notificationport. */435 /* Return an inferior by pid port. */ 423 436 static struct inferior * 424 darwin_find_inferior_by_ notify (mach_port_t port)437 darwin_find_inferior_by_pid (int pid) 425 438 { 426 return iterate_over_inferiors (&find_inferior_ notify_it, &port);439 return iterate_over_inferiors (&find_inferior_pid_it, &pid); 427 440 } 428 441 429 442 /* Return a thread by port. */ … … darwin_dump_message (mach_msg_header_t *hdr, int disp_body) 557 570 } 558 571 } 559 572 573 /* Adjust inferior data when a new task was created. */ 574 575 static struct inferior * 576 darwin_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 621 static int 622 darwin_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 560 636 static int 561 637 darwin_decode_exception_message (mach_msg_header_t *hdr, 562 638 struct inferior **pinf, … … darwin_decode_exception_message (mach_msg_header_t *hdr, 593 669 594 670 /* Check data representation. */ 595 671 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) 602 673 return -1; 603 674 604 675 /* Ok, the hard work. */ … … darwin_decode_exception_message (mach_msg_header_t *hdr, 607 678 task_port = desc[1].name; 608 679 thread_port = desc[0].name; 609 680 610 /* We got new rights to the task, get rid of it. Do not get rid of thread611 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 615 681 /* Find process by port. */ 616 682 inf = darwin_find_inferior_by_task (task_port); 617 683 *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 618 708 if (inf == NULL) 619 709 { 620 710 /* Not a known inferior. This could happen if the child fork, as … … darwin_decode_exception_message (mach_msg_header_t *hdr, 623 713 kern_return_t kret; 624 714 mig_reply_error_t reply; 625 715 716 inferior_debug 717 (4, _("darwin_decode_exception_message: unknown task 0x%x\n"), 718 task_port); 719 626 720 /* Free thread port (we don't know it). */ 627 721 kret = mach_port_deallocate (mach_task_self (), thread_port); 628 722 MACH_CHECK_ERROR (kret); … … darwin_decode_exception_message (mach_msg_header_t *hdr, 676 770 return 0; 677 771 } 678 772 773 /* Decode dead_name notify message. */ 774 775 static int 776 darwin_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 679 812 static void 680 813 darwin_encode_reply (mig_reply_error_t *reply, mach_msg_header_t *hdr, 681 814 integer_t code) … … darwin_decode_message (mach_msg_header_t *hdr, 986 1119 else if (hdr->msgh_id == 0x48) 987 1120 { 988 1121 /* 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 989 1134 *pinf = NULL; 990 1135 *pthread = NULL; 991 1136 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 993 1143 if (inf != NULL) 994 1144 { 995 1145 if (!inf->priv->no_ptrace) … … darwin_decode_message (mach_msg_header_t *hdr, 1022 1172 /* Looks necessary on Leopard and harmless... */ 1023 1173 wait4 (inf->pid, &wstatus, 0, NULL); 1024 1174 1025 return ptid_build (inf->pid, 0, 0); 1175 inferior_ptid = ptid_build (inf->pid, 0, 0); 1176 return inferior_ptid; 1026 1177 } 1027 1178 else 1028 1179 { … … darwin_interrupt (struct target_ops *self, ptid_t t) 1204 1355 kill (inf->pid, SIGINT); 1205 1356 } 1206 1357 1358 /* Deallocate threads port and vector. */ 1359 1207 1360 static void 1208 darwin_ mourn_inferior (struct target_ops *ops)1361 darwin_deallocate_threads (struct inferior *inf) 1209 1362 { 1210 struct inferior *inf = current_inferior ();1211 kern_return_t kret;1212 mach_port_t prev;1213 int i;1214 1215 /* Deallocate threads. */1216 1363 if (inf->priv->threads) 1217 1364 { 1365 kern_return_t kret; 1218 1366 int k; 1219 1367 darwin_thread_t *t; 1220 1368 for (k = 0; … … darwin_mourn_inferior (struct target_ops *ops) 1227 1375 VEC_free (darwin_thread_t, inf->priv->threads); 1228 1376 inf->priv->threads = NULL; 1229 1377 } 1378 } 1230 1379 1380 static void 1381 darwin_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. */ 1231 1392 kret = mach_port_move_member (gdb_task, 1232 1393 inf->priv->notify_port, MACH_PORT_NULL); 1233 1394 MACH_CHECK_ERROR (kret); 1234 1395 1396 /* Remove task port dead_name notification. */ 1235 1397 kret = mach_port_request_notification (gdb_task, inf->priv->task, 1236 1398 MACH_NOTIFY_DEAD_NAME, 0, 1237 1399 MACH_PORT_NULL, … … darwin_mourn_inferior (struct target_ops *ops) 1247 1409 MACH_CHECK_ERROR (kret); 1248 1410 } 1249 1411 1412 /* Destroy notify_port. */ 1250 1413 kret = mach_port_destroy (gdb_task, inf->priv->notify_port); 1251 1414 MACH_CHECK_ERROR (kret); 1252 1415 1253 1254 1416 /* 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); 1262 1418 1419 /* Deallocate task port. */ 1263 1420 kret = mach_port_deallocate (gdb_task, inf->priv->task); 1264 1421 MACH_CHECK_ERROR (kret); 1265 1422 … … darwin_restore_exception_ports (darwin_inferior *inf) 1349 1506 return KERN_SUCCESS; 1350 1507 } 1351 1508 1509 /* Deallocate saved exception ports. */ 1510 1511 static void 1512 darwin_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 1525 static void 1526 darwin_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 1352 1551 static void 1353 1552 darwin_kill_inferior (struct target_ops *ops) 1354 1553 { … … darwin_kill_inferior (struct target_ops *ops) 1385 1584 } 1386 1585 1387 1586 static void 1587 darwin_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 (_("\ 1608 A task termination request was registered before the debugger registered\n\ 1609 its own. This is unexpected, but should otherwise not have any actual\n\ 1610 impact on the debugging session.")); 1611 } 1612 } 1613 1614 static void 1388 1615 darwin_attach_pid (struct inferior *inf) 1389 1616 { 1390 1617 kern_return_t kret; … … darwin_attach_pid (struct inferior *inf) 1463 1690 "returned: %d"), 1464 1691 kret); 1465 1692 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); 1486 1694 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); 1504 1696 1505 1697 if (!target_is_pushed (darwin_ops)) 1506 1698 push_target (darwin_ops);